예제 #1
0
  /**
   * Adds arcs between the dot node for this piece of abstract syntax and those representing [@link
   * {@link #returnType}, {@link #name}, {@link #formals} and {@link #body}.
   *
   * @param where the file where the dot representation must be written
   */
  @Override
  protected void toDotAux(FileWriter where) throws java.io.IOException {
    linkToNode("returnType", returnType.toDot(where), where);
    linkToNode("name", toDot(name, where), where);

    if (getFormals() != null) linkToNode("formals", getFormals().toDot(where), where);

    linkToNode("body", getBody().toDot(where), where);
  }
예제 #2
0
  /**
   * Adds the signature of this method declaration to the given class.
   *
   * @param clazz the class where the signature of this method declaration must be added
   */
  @Override
  protected void addTo(ClassType clazz) {
    Type rt = returnType.toType();
    TypeList pars = getFormals() != null ? getFormals().toType() : TypeList.EMPTY;
    MethodSignature mSig = new MethodSignature(clazz, rt, pars, name, this);

    clazz.addMethod(name, mSig);

    // we record the signature of this method inside this abstract syntax
    setSignature(mSig);
  }
예제 #3
0
  /**
   * Type-checks this method declaration. It first checks that if this method overrides a method of
   * a superclass then the return type is a subtype of that of the overridden method. Then it builds
   * a type-checker whose only variable in scope is {@code this} of type {@code clazz} and the
   * parameters of the method, and where return instructions of type {@code returnType} are allowed.
   * It then type-checks the body of the method in that type-checker. It finally checks that if this
   * method does not return {@code void}, then every execution path ends with a {@code return}
   * command.
   *
   * @param clazz the semantical type of the class where this method occurs
   */
  @Override
  protected void typeCheckAux(ClassType clazz) {
    TypeChecker checker;
    ClassType superclass;
    MethodSignature overridden;
    Type rt = returnType.typeCheck();

    // we build a type-checker which signals errors for the source code
    // of the class where this method is defined,
    // whose only variables in scope is this of type
    // clazz and the parameters of the method, and
    // where return instructions of type returnType are allowed
    checker = new TypeChecker(rt, clazz.getErrorMsg());

    // the main method is the only <i>static</i> method, where there is no this variable
    if (!getSignature().getName().equals("main")) checker = checker.putVar("this", clazz);

    // we enrich the type-checker with the formal parameters
    checker = getFormals() != null ? getFormals().typeCheck(checker) : checker;

    TypeList pars = getFormals() != null ? getFormals().typeCheck() : null;

    // we check if this method overrides a method of some superclass
    superclass = clazz.getSuperclass();
    if (superclass != null) {
      overridden = superclass.methodLookup(name, pars);

      if (overridden != null)
        // it does override a method of a superclass. We check
        // that its return type has been refined. We use the
        // canBeAssignedToSpecial method so that
        // void can be overridden into void
        if (!rt.canBeAssignedToSpecial(overridden.getReturnType()))
          error(
              checker,
              "illegal return type for overriding method \""
                  + name
                  + "\". Was "
                  + overridden.getReturnType());
    }

    // we type-check the body of the method in the resulting type-checker
    getBody().typeCheck(checker);

    // we check that there is no dead-code in the body of the method
    boolean stopping = getBody().checkForDeadcode();

    // we check that if the method does not return void then
    // every syntactical execution path in the method ends with
    // a return command (continue and break are forbidden in this position)
    if (rt != VoidType.INSTANCE && !stopping) error(checker, "missing return statement");
  }
  public SignatureFacade createConstructorFacade(InstanceCreationExpression exp) throws Exception {
    List<TypeExpression> arguments = new ArrayList<TypeExpression>();
    Map<String, TypeExpression> argumentsMap = new HashMap<String, TypeExpression>();

    if (exp.getTuple().getInstanceCreationTupleElement() != null) {
      for (InstanceCreationTupleElement tupleElement :
          exp.getTuple().getInstanceCreationTupleElement()) {
        TypeExpression typeOfArgument =
            new TypeUtils().getTypeOfExpression(tupleElement.getObject());
        if (typeOfArgument.getTypeFacade() instanceof ErrorTypeFacade)
          throw new TypeInferenceException(typeOfArgument);
        arguments.add(typeOfArgument);
        argumentsMap.put(tupleElement.getRole(), typeOfArgument);
      }
    }

    // first try to determine if the expression directly refers to a Class or a DataType
    TypeFacade cddClassifier = TypeFacadeFactory.eInstance.createVoidFacade(exp.getConstructor());
    boolean errorInResolutionOfClassifier = false;
    if (cddClassifier instanceof ErrorTypeFacade) {
      errorInResolutionOfClassifier = true;
    } else {
      Classifier referencedType = cddClassifier.extractActualType();
      if (referencedType instanceof PrimitiveType) {
        throw new Exception("Constructor invocations do not apply to primitive types");
      }
      if (referencedType instanceof Enumeration) {
        throw new Exception("Constructor invocations do not apply to enumerations");
      }
      if (referencedType.isAbstract()) {
        throw new Exception("Abstract classifiers cannot be instantiated");
      }

      // The classifier has been resolved. Must determine if arguments match with possible
      // constructors
      if (referencedType instanceof org.eclipse.uml2.uml.Class) {
        List<EObject> visibleConstructor =
            AlfScopeProvider.scopingTool
                .getVisibleOperationsOrBehaviors(referencedType)
                .resolveByName(referencedType.getName());
        if (visibleConstructor.size() > 1) {
          // try to match with arguments
          // if does not match, raise an exception
          List<SignatureFacade> visibleConstructorSignatures = new ArrayList<SignatureFacade>();
          for (EObject cddConstructor : visibleConstructor) {
            SignatureFacade cddConstructorSignature =
                SignatureFacadeFactory.eInstance.createSignatureFacade(cddConstructor);
            if (cddConstructorSignature.isAConstructor())
              visibleConstructorSignatures.add(cddConstructorSignature);
          }
          List<SignatureFacade> matchingSignatures =
              SignatureFacade.findNearestSignature(arguments, visibleConstructorSignatures);
          if (matchingSignatures.size() > 1) {
            String errorMessage = referencedType.getName() + "(";
            boolean first = true;
            for (TypeExpression arg : arguments) {
              if (first) first = false;
              else errorMessage += ", ";
              errorMessage += arg.getLabel();
            }
            errorMessage += ") resolves to multiple constructors";
            throw new Exception(errorMessage);
          } else if (matchingSignatures.size() == 0) {
            String errorMessage = "Constructor " + referencedType.getName() + "(";
            boolean first = true;
            for (TypeExpression arg : arguments) {
              if (first) first = false;
              else errorMessage += ", ";
              errorMessage += arg.getLabel();
            }
            errorMessage += ") is undefined";
            throw new Exception(errorMessage);
          } else { // exactly one match
            return matchingSignatures.get(0);
          }
        } else if (visibleConstructor.size() == 0) {
          if (arguments.size() > 0) {
            // Throw an exception
            String errorMessage = "Constructor " + referencedType.getName() + "(";
            boolean first = true;
            for (TypeExpression t : arguments) {
              if (first) first = false;
              else errorMessage += ", ";
              errorMessage += t.getLabel();
            }
            errorMessage += ") is undefined";
            throw new Exception(errorMessage);
          }
          return new DefaultConstructorFacade((Class) referencedType);
        } else { // exactly one constructor found
          // Tries to determine if arguments match
          SignatureFacade constructor = createSignatureFacade(visibleConstructor.get(0));
          if (!constructor.isAConstructor()) {
            // Throw an exception
            String errorMessage = "Constructor " + referencedType.getName() + "(";
            boolean first = true;
            for (TypeExpression t : arguments) {
              if (first) first = false;
              else errorMessage += ", ";
              errorMessage += t.getLabel();
            }
            errorMessage += ") is undefined";
            throw new Exception(errorMessage);
          }
          String potentialErrorMessage = constructor.isCompatibleWithMe(argumentsMap);
          if (potentialErrorMessage.length() == 0) return constructor;
          else throw new Exception(potentialErrorMessage);
        }
      } else if (referencedType instanceof DataType) { // This is a data type.
        // must match arguments with visible properties of the data type
        SignatureFacade defaultDataTypeConstructor =
            new DefaultConstructorFacade((DataType) referencedType);
        String errorMessage = defaultDataTypeConstructor.isCompatibleWithMe(argumentsMap);
        if (!(errorMessage.length() == 0)) throw new Exception(errorMessage);
        else return defaultDataTypeConstructor;
      }
    }

    if (errorInResolutionOfClassifier) {
      // We can try again, but considering that:
      // - the last element in the qualified name as the name of a constructor
      // - the element before the last element is a class name

      if (exp.getConstructor().getRemaining() == null)
        throw new Exception("Constructor " + exp.getConstructor().getId() + " is undefined");

      QualifiedNameWithBinding remaining = exp.getConstructor();
      QualifiedNameWithBinding cddClassName = exp.getConstructor();
      QualifiedNameWithBinding cddConstructorName = exp.getConstructor();
      EObject previousPackage = null;

      while (cddConstructorName.getRemaining() != null) {
        cddClassName = cddConstructorName;
        cddConstructorName = cddConstructorName.getRemaining();
      }

      if (remaining != cddClassName) {
        List<EObject> visiblePackages =
            AlfScopeProvider.scopingTool.getVisiblePackages(exp).resolveByName(remaining.getId());
        if (visiblePackages.isEmpty()) {
          throw new Exception("Could not resolve package " + remaining.getId());
        } else if (visiblePackages.size() > 1) {
          throw new Exception(remaining.getId() + " resolves to multiple packages");
        } else {
          List<EObject> nestedVisiblePackages;
          previousPackage = visiblePackages.get(0);
          remaining = remaining.getRemaining();
          while (remaining != cddClassName) {
            nestedVisiblePackages =
                AlfScopeProvider.scopingTool
                    .getVisiblePackages(previousPackage)
                    .resolveByName(remaining.getId());
            if (nestedVisiblePackages.isEmpty()) {
              throw new Exception("Could not resolve package " + remaining.getId());
            } else if (nestedVisiblePackages.size() > 1) {
              throw new Exception(remaining.getId() + " resolves to multiple packages");
            }
            previousPackage = nestedVisiblePackages.get(0);
            remaining = remaining.getRemaining();
          }
        }
      }

      // At this point, the (potential) path has been validated
      // cddClassName should resolve to a classifier
      List<EObject> visibleClassifiers = null;
      EObject resolvedClassifier = null;
      if (previousPackage != null)
        visibleClassifiers =
            AlfScopeProvider.scopingTool
                .getVisibleClassifiers(previousPackage)
                .resolveByName(cddClassName.getId());
      else
        visibleClassifiers =
            AlfScopeProvider.scopingTool
                .getVisibleClassifiers(exp)
                .resolveByName(cddClassName.getId());
      if (visibleClassifiers.isEmpty()) {
        throw new Exception("Could not resolve classifier " + cddClassName.getId());
      } else if (visibleClassifiers.size() > 1) {
        throw new Exception(remaining.getId() + " resolves to multiple classifiers.");
      } else {
        resolvedClassifier = visibleClassifiers.get(0);
      }
      List<EObject> visibleConstructor =
          AlfScopeProvider.scopingTool
              .getVisibleOperationsOrBehaviors(resolvedClassifier)
              .resolveByName(cddConstructorName.getId());
      if (visibleConstructor.size() > 1) {
        // try to match with arguments
        // if does not match, raise an exception
        List<SignatureFacade> visibleConstructorSignatures = new ArrayList<SignatureFacade>();
        for (EObject cddConstructor : visibleConstructor) {
          SignatureFacade cddConstructorSignature =
              SignatureFacadeFactory.eInstance.createSignatureFacade(cddConstructor);
          if (cddConstructorSignature.isAConstructor())
            visibleConstructorSignatures.add(cddConstructorSignature);
        }
        List<SignatureFacade> matchingSignatures =
            SignatureFacade.findNearestSignature(arguments, visibleConstructorSignatures);
        if (matchingSignatures.size() > 1) {
          String errorMessage = cddConstructorName.getId() + "(";
          boolean first = true;
          for (TypeExpression arg : arguments) {
            if (first) first = false;
            else errorMessage += ", ";
            errorMessage += arg.getLabel();
          }
          errorMessage += ") resolves to multiple constructors";
          throw new Exception(errorMessage);
        } else if (matchingSignatures.size() == 0) {
          String errorMessage = "Constructor " + cddConstructorName.getId() + "(";
          boolean first = true;
          for (TypeExpression arg : arguments) {
            if (first) first = false;
            else errorMessage += ", ";
            errorMessage += arg.getLabel();
          }
          errorMessage += ") is undefined";
          throw new Exception(errorMessage);
        } else { // exactly one match
          return matchingSignatures.get(0);
        }
      } else if (visibleConstructor.size() == 0) {
        String errorMessage = "Constructor " + cddConstructorName.getId() + "(";
        boolean first = true;
        for (TypeExpression arg : arguments) {
          if (first) first = false;
          else errorMessage += ", ";
          errorMessage += arg.getLabel();
        }
        errorMessage += ") is undefined";
        throw new Exception(errorMessage);
      } else { // exactly one constructor
        // Tries to determine if arguments match
        SignatureFacade constructor = createSignatureFacade(visibleConstructor.get(0));
        if (!constructor.isAConstructor()) {
          // Throw an exception
          String errorMessage = "Constructor " + cddConstructorName.getId() + "(";
          boolean first = true;
          for (TypeExpression t : arguments) {
            if (first) first = false;
            else errorMessage += ", ";
            errorMessage += t.getLabel();
          }
          errorMessage += ") is undefined";
          throw new Exception(errorMessage);
        }
        String potentialErrorMessage = constructor.isCompatibleWithMe(arguments, true);
        if (potentialErrorMessage.length() == 0) return constructor;
        else throw new Exception(potentialErrorMessage);
      }
    }

    throw new Exception("Not supported case");
  }