/** * 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); }
/** * 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); }
/** * 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"); }