/** 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 verifyVariableModifiers(VariableNode v) {
    ModifiersSet modifiersSet = v.getModifiers();
    if (modifiersSet == null) return;

    ASModifier[] modifiers = modifiersSet.getAllModifiers();
    IExpressionNode site = v.getNameExpressionNode();
    for (ASModifier modifier : modifiers) {
      if (modifier == ASModifier.NATIVE) {
        classScope.addProblem(new NativeVariableProblem(site));
      } else if (modifier == ASModifier.DYNAMIC) {
        classScope.addProblem(new DynamicNotOnClassProblem(site));
      } else if (modifier == ASModifier.FINAL) {
        classScope.addProblem(new FinalOutsideClassProblem(site));
      } else if (modifier == ASModifier.OVERRIDE) {
        classScope.addProblem(new InvalidOverrideProblem(site));
      } else if (modifier == ASModifier.VIRTUAL) {
        classScope.addProblem(new VirtualOutsideClassProblem(site));
      }
    }
    classScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(v);
  }
  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;
  }