protected void verifyFunctionModifiers(FunctionNode f) { ModifiersSet modifiersSet = f.getModifiers(); if (modifiersSet == null) return; IExpressionNode site = f.getNameExpressionNode(); if (modifiersSet.hasModifier(ASModifier.STATIC)) { if (modifiersSet.hasModifier(ASModifier.FINAL)) { classScope.addProblem(new FinalOutsideClassProblem(site)); } if (modifiersSet.hasModifier(ASModifier.OVERRIDE)) { classScope.addProblem(new StaticAndOverrideProblem(site)); } if (modifiersSet.hasModifier(ASModifier.DYNAMIC)) { classScope.addProblem(new DynamicNotOnClassProblem(site)); } if (modifiersSet.hasModifier(ASModifier.VIRTUAL)) { classScope.addProblem(new VirtualOutsideClassProblem(site)); } } classScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(f); // Functions in a class allow all modifiers return; }
/** * This method performs the semantic analysis of a function declared in a class. * * @param node the FunctionNode to semantically analyze */ void functionSemanticChecks(FunctionNode node) { verifyFunctionModifiers(node); FunctionDefinition func = node.getDefinition(); Collection<ICompilerProblem> problems = classScope.getProblems(); // code model has some peculiar ideas about what makes a function a constructor or not boolean looks_like_ctor = func.isConstructor(); looks_like_ctor |= func.getBaseName() != null && this.className != null && func.getBaseName().equals(this.className.getBaseName()); if (!looks_like_ctor && (func.getBaseName() != null)) { SemanticUtils.checkScopedToDefaultNamespaceProblem( classScope, node, func, this.classDefinition.getQualifiedName()); } if (looks_like_ctor) { // If a constructor has a namespace as part of it's declaration, it must be declared public. // It is ok to omit the namespace // We must check the AST, as CM treats all ctors as public no matter what the user typed in // so the FunctionDefinition will always be in the public namespace if (node.getActualNamespaceNode() != null && node.getActualNamespaceNode().getName() != IASKeywordConstants.PUBLIC) problems.add(new ConstructorMustBePublicProblem(node.getActualNamespaceNode())); // A constructor cannot be static if (func.isStatic()) problems.add(new ConstructorIsStaticProblem(node)); // A constructor cannot declare a return type, other than void. IExpressionNode returnTypeExpression = node.getReturnTypeNode(); if (returnTypeExpression != null) { // We cannot check whether node.resolveReturnType() returns the definition // for the void type, because the return type of a constructor is considered // to be the class of the object being constructed, rather than void. // So instead we simply check whether the type annotation was void. boolean returnTypeIsVoid = false; if (returnTypeExpression instanceof ILanguageIdentifierNode) { LanguageIdentifierKind kind = ((ILanguageIdentifierNode) returnTypeExpression).getKind(); if (kind == LanguageIdentifierKind.VOID) returnTypeIsVoid = true; } if (!returnTypeIsVoid) { ICompilerProblem problem = new ConstructorCannotHaveReturnTypeProblem(returnTypeExpression); problems.add(problem); } } // Is it a getter or setter that appears to be the constructor? if (func instanceof IAccessorDefinition) problems.add(new ConstructorIsGetterSetterProblem(node.getNameExpressionNode())); } else if (!func.isStatic()) { // We have to find the (potentially) overriden function whether we are an override or // not/ FunctionDefinition override = func.resolveOverriddenFunction(classScope.getProject()); if (func.isOverride()) { if (override == null) { // Didn't find the function we are supposed to be overriding problems.add(new OverrideNotFoundProblem(node.getNameExpressionNode())); } else { if (!func.hasCompatibleSignature(override, classScope.getProject())) { // Signatures didn't match problems.add(new IncompatibleOverrideProblem(node.getNameExpressionNode())); } if (override.isFinal()) { // overriding final problems.add(new OverrideFinalProblem(node.getNameExpressionNode())); } } } else if (override != null) { // found overriden function, but function not marked as override problems.add(new FunctionNotMarkedOverrideProblem(node.getNameExpressionNode())); } } }