/** Declare a function. TODO: static vs. instance. */ @Override void declareFunction(FunctionNode func) { func.parseFunctionBody(classScope.getProblems()); final FunctionDefinition funcDef = func.getDefinition(); final boolean is_constructor = func.isConstructor(); functionSemanticChecks(func); // Save the constructor function until // we've seen all the instance variables // that might need initialization. if (is_constructor) { if (this.ctorFunction == null) this.ctorFunction = func; else { // If we already have a ctor, must be multiply defined. Ignore it and generate problem String name = this.className.getBaseName(); classScope.addProblem(new MultipleContructorDefinitionsProblem(func, name)); } } else { LexicalScope ls = funcDef.isStatic() ? classStaticScope : classScope; MethodInfo mi = classScope.getGenerator().generateFunction(func, ls, null); if (mi != null) { Name funcName = funcDef.getMName(classScope.getProject()); ITraitVisitor tv = ls.traitsVisitor.visitMethodTrait( functionTraitKind(func, TRAIT_Method), funcName, 0, mi); if (funcName != null) classScope .getMethodBodySemanticChecker() .checkFunctionForConflictingDefinitions(func, funcDef); if (!funcDef.isStatic()) if (funcDef.getNamespaceReference() instanceof NamespaceDefinition.IProtectedNamespaceDefinition) this.iinfo.flags |= ABCConstants.CLASS_FLAG_protected; ls.processMetadata(tv, getAllMetaTags(funcDef)); if (func.hasModifier(ASModifier.FINAL)) tv.visitAttribute(Trait.TRAIT_FINAL, Boolean.TRUE); if (func.hasModifier(ASModifier.OVERRIDE)) tv.visitAttribute(Trait.TRAIT_OVERRIDE, Boolean.TRUE); tv.visitEnd(); } } }
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())); } } }