Example #1
0
  public boolean isVisibleTo(RubyContext context, LexicalScope lexicalScope, RubyModule module) {
    CompilerAsserts.neverPartOfCompilation();
    assert lexicalScope == null || lexicalScope.getLiveModule() == module;

    if (!isPrivate) {
      return true;
    }

    // Look in lexical scope
    if (lexicalScope != null) {
      while (lexicalScope != context.getRootLexicalScope()) {
        if (lexicalScope.getLiveModule() == declaringModule) {
          return true;
        }
        lexicalScope = lexicalScope.getParent();
      }
    }

    // Look in ancestors
    if (module instanceof RubyClass) {
      for (RubyModule included : module.parentAncestors()) {
        if (included == declaringModule) {
          return true;
        }
      }
    }

    // Allow Object constants if looking with lexical scope.
    if (lexicalScope != null && context.getCoreLibrary().getObjectClass() == declaringModule) {
      return true;
    }

    return false;
  }
  protected void generateBindableImpl() {
    if (classDefinition.needsEventDispatcher(classScope.getProject())) {
      // Generate a EventDispatcher member, equivalent to:
      //   private var _bindingEventDispatcher : flash.events.EventDispatcher;
      //
      // Note that it is in a separate private namespace, so it won't conflict with user defined
      // private members

      // Add init code for the _bindingEventDispatcher to the ctor
      // this is the equivalent of:
      //   _bindingEventDispatcher = new flash.events.EventDispatcher(this);

      iinitInsns.addAll(BindableHelper.generateBindingEventDispatcherInit(itraits, false));
      BindableHelper.generateAddEventListener(classScope);
      BindableHelper.generateDispatchEvent(classScope);
      BindableHelper.generateHasEventListener(classScope);
      BindableHelper.generateRemoveEventListener(classScope);
      BindableHelper.generateWillTrigger(classScope);
    }

    if (classDefinition.needsStaticEventDispatcher(classScope.getProject())) {
      cinitInsns.addAll(BindableHelper.generateBindingEventDispatcherInit(ctraits, true));
      BindableHelper.generateStaticEventDispatcherGetter(classStaticScope);
    }
  }
  ITraitVisitor declareVariable(
      VariableNode varNode,
      DefinitionBase varDef,
      boolean is_static,
      boolean is_const,
      Object initializer) {
    final ICompilerProject project = this.classScope.getProject();
    Name var_name = varDef.getMName(project);

    TypeDefinitionBase typeDef = varDef.resolveType(project);
    Name var_type = typeDef != null ? typeDef.getMName(project) : null;

    int trait_kind = is_const ? TRAIT_Const : TRAIT_Var;

    LexicalScope ls = is_static ? this.classStaticScope : this.classScope;

    ls.declareVariableName(var_name);

    ITraitVisitor tv =
        ls.traitsVisitor.visitSlotTrait(
            trait_kind, var_name, ITraitsVisitor.RUNTIME_SLOT, var_type, initializer);

    if (!is_static)
      if (varDef.getNamespaceReference()
          instanceof NamespaceDefinition.IProtectedNamespaceDefinition)
        this.iinfo.flags |= ABCConstants.CLASS_FLAG_protected;

    SemanticUtils.checkScopedToDefaultNamespaceProblem(
        this.classScope, varNode, varDef, this.className.getBaseName());

    return tv;
  }
  private void addAnyEmbeddedAsset() {
    ICompilerProject project = classScope.getProject();
    if (!(project instanceof CompilerProject)) return;

    EmbedData embedData =
        classDefinition.getEmbeddedAsset((CompilerProject) project, classScope.getProblems());
    if (embedData != null) classScope.getGlobalScope().getEmbeds().add(embedData);
  }
  /**
   * Check the class definition for various errors related to implemented interfaces, such as making
   * sure that all interface methods are implemented
   *
   * @param cls the class definition to check
   */
  void implementedInterfaceSemanticChecks(ClassDefinition cls) {
    Iterator<IInterfaceDefinition> it = cls.interfaceIterator(classScope.getProject());
    while (it.hasNext()) {
      IInterfaceDefinition interf = it.next();

      if (interf instanceof InterfaceDefinition) {
        ((InterfaceDefinition) interf)
            .validateClassImplementsAllMethods(
                classScope.getProject(), cls, classScope.getProblems());
      }
    }
  }
  /**
   * Generate instructions for field initializers or static initialization statements.
   *
   * @param node - the AST at the root of the statement.
   * @param isStatic - true if the code should be generated in a static context.
   */
  private void generateInstructions(IASNode node, final boolean isStatic) {
    //  Do we need to create new information for the class'
    //  static initialization method?  Note that this may
    //  be undone if the codgen fails or doesn't produce
    //  any instructions.
    final boolean createNewCinit = isStatic && this.cinfo.cInit == null;

    if (createNewCinit) {
      //  Speculatively initialize the class' cinit
      //  (static class initializer routine)'s data
      //  structures; the code generator may need to
      //  store information in them.
      this.cinfo.cInit = new MethodInfo();
      MethodBodyInfo cinit_info = new MethodBodyInfo();
      cinit_info.setMethodInfo(this.cinfo.cInit);

      this.classStaticScope.setMethodInfo(this.cinfo.cInit);
      this.classStaticScope.methodVisitor = emitter.visitMethod(this.cinfo.cInit);
      this.classStaticScope.methodVisitor.visit();
      this.classStaticScope.methodBodyVisitor =
          this.classStaticScope.methodVisitor.visitBody(cinit_info);
      this.classStaticScope.methodBodyVisitor.visit();
    }

    InstructionList cgResult = null;

    LexicalScope ls = isStatic ? this.classStaticScope : this.classScope;

    ls.resetDebugInfo();
    cgResult = ls.getGenerator().generateInstructions(node, CmcEmitter.__statement_NT, ls);

    //  If nothing came back, revert any change made to the cinit information.
    if ((cgResult == null || cgResult.isEmpty()) && createNewCinit) {
      this.cinfo.cInit = null;
      this.classStaticScope.resetMethodInfo();
      this.classStaticScope.methodVisitor = null;
      this.classStaticScope.methodBodyVisitor = null;
    }

    //  Save the generated instructions, if present.
    if (cgResult != null) {
      if (isStatic) this.cinitInsns.addAll(cgResult);
      else this.iinitInsns.addAll(cgResult);
    }
  }
  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;
  }
  /** 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 generateRequiredContingentDefinitions() {
    List<IDefinition> definitons = classDefinition.getContingentDefinitions();
    for (IDefinition definition : definitons) {
      if (!definition.isContingentNeeded(classScope.getProject())) continue;

      assert (definition instanceof VariableDefinition)
          : "The code generator only supports contigent variable definitions";

      final IDefinitionNode node = definition.getNode();
      declareVariable(
          (VariableNode) node,
          (VariableDefinition) definition,
          definition.isStatic(),
          definition instanceof IConstantDefinition,
          LexicalScope.noInitializer);
    }
  }
  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);
  }
 /** Process an import directive. */
 @Override
 void processImportDirective(ImportNode imp) {
   // Run the BURM, but for the purpose of semantic checking not code generation.
   classScope.getGenerator().generateInstructions(imp, CmcEmitter.__statement_NT, this.classScope);
 }
  /** Declare a variable. */
  @Override
  void declareVariable(VariableNode var) {
    verifyVariableModifiers(var);

    VariableDefinition varDef = (VariableDefinition) var.getDefinition();

    boolean is_static = var.hasModifier(ASModifier.STATIC);
    boolean is_const = SemanticUtils.isConst(var, classScope.getProject());

    final ICompilerProject project = this.classScope.getProject();

    ICodeGenerator codeGenerator = classScope.getGenerator();
    IExpressionNode assignedValueNode = var.getAssignedValueNode();
    IConstantValue constantValue = codeGenerator.generateConstantValue(assignedValueNode, project);

    //  initializer is null if no constant value
    //  can be generated, and null is the correct value for "no value."
    Object initializer = constantValue != null ? constantValue.getValue() : null;

    // Reducing the constant value may have produced problems in the
    // LexicalScope used for constant reduction. Transfer them over
    // to the LexicalScope for this class.
    Collection<ICompilerProblem> problems =
        constantValue != null ? constantValue.getProblems() : null;
    if (problems != null) classScope.addProblems(problems);

    final MethodBodySemanticChecker checker =
        MethodBodySemanticCheckerFactory.getChecker(this.classScope); // CO-5148

    DefinitionBase varType = (DefinitionBase) varDef.resolveType(project);

    Object transformed_initializer = null;

    if ((initializer != null) && (varType != null)) {
      transformed_initializer =
          checker
              .checkInitialValue(
                  var,
                  new Binding(null, varType.getMName(this.classScope.getProject()), varType),
                  new PooledValue(initializer))
              .getValue();
    } else {
      transformed_initializer = initializer;
    }

    ITraitVisitor tv = declareVariable(var, varDef, is_static, is_const, transformed_initializer);
    if (is_static) this.classStaticScope.processMetadata(tv, getAllMetaTags(varDef));
    else this.classScope.processMetadata(tv, getAllMetaTags(varDef));
    tv.visitEnd();

    //  Generate variable initializers and append them to the
    //  proper initialization list.
    if (transformed_initializer == null && var.getAssignedValueNode() != null) {
      // Emit initialization instructions for non-static vars.  Static var
      // instructions will be emitted during finishClassDefinition()
      if (is_static) staticVariableInitializers.add(var);
      else generateInstructions(var, false);
    } else {
      checker.checkClassField(var, is_static);
      //  Massive kludge -- grovel over chained variable decls and add them one by one
      for (int i = 0; i < var.getChildCount(); i++) {
        IASNode candidate = var.getChild(i);

        if (candidate instanceof VariableNode) {
          declareVariable((VariableNode) candidate);
        }
      }
    }
  }
  /**
   * 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()));
      }
    }
  }
  /** Finish the class' definition. */
  void finishClassDefinition() {
    // the generation of instructions for variable initialization is delayed
    // until now, so we can add that initialization to the front of
    // the cinit instruction list.
    if (!staticVariableInitializers.isEmpty()) {
      InstructionList exisitingCinitInsns = null;
      if (!this.cinitInsns.isEmpty()) {
        exisitingCinitInsns = new InstructionList();
        exisitingCinitInsns.addAll(this.cinitInsns);
        this.cinitInsns = new InstructionList();
      }

      for (VariableNode var : staticVariableInitializers) generateInstructions(var, true);

      if (exisitingCinitInsns != null) this.cinitInsns.addAll(exisitingCinitInsns);
    }

    // add "goto_definition_help" metadata to user defined metadata.
    ITraitVisitor tv =
        classScope.getGlobalScope().traitsVisitor.visitClassTrait(TRAIT_Class, className, 0, cinfo);
    IMetaInfo[] metaTags = getAllMetaTags(classDefinition);

    // Add "goto definition help" metadata for the constructor.
    if (this.ctorFunction != null) {
      FunctionDefinition ctorDef = this.ctorFunction.getDefinition();
      MetaTag metaTag =
          MetaTag.createGotoDefinitionHelp(
              classDefinition,
              classDefinition.getContainingFilePath(),
              Integer.toString(ctorDef.getNameStart()),
              true);
      if (metaTag != null) metaTags = MetaTag.addMetaTag(metaTags, metaTag);
    }

    this.classScope.processMetadata(tv, metaTags);
    tv.visitEnd();

    // Need to do this before generating the CTOR as the generated code may result in insns that
    // need to be added to the ctor.
    generateBindableImpl();

    generateRequiredContingentDefinitions();

    addAnyEmbeddedAsset();

    // Make any vistEnd method calls
    // that were deferred.
    // callVisitEnds must be called on the same thread
    // that started code generation.  Since we don't generate
    // classes in parallel yet, we know that we are on the thread
    // that started code generation here.
    classScope.callVisitEnds();
    classStaticScope.callVisitEnds();

    //  Create the class' constructor function.
    if (this.ctorFunction != null) {
      MethodInfo mi =
          classScope
              .getGenerator()
              .generateFunction(this.ctorFunction, classScope, this.iinitInsns);

      if (mi != null) this.iinfo.iInit = mi;
    } else if (!this.iinitInsns.isEmpty()) {
      //  Synthesize a constructor.

      this.iinfo.iInit = new MethodInfo();
      MethodBodyInfo iinit = new MethodBodyInfo();
      iinit.setMethodInfo(this.iinfo.iInit);

      IMethodVisitor mv = emitter.visitMethod(this.iinfo.iInit);
      mv.visit();
      IMethodBodyVisitor mbv = mv.visitBody(iinit);
      InstructionList ctor_insns = new InstructionList();
      ctor_insns.addInstruction(OP_getlocal0);
      ctor_insns.addInstruction(OP_pushscope);

      ctor_insns.addAll(this.iinitInsns);

      //  Call the superclass' constructor after the instance
      //  init instructions; this doesn't seem like an abstractly
      //  correct sequence, but it's what ASC does.
      ctor_insns.addInstruction(OP_getlocal0);
      ctor_insns.addInstruction(OP_constructsuper, 0);

      ctor_insns.addInstruction(OP_returnvoid);
      mbv.visit();
      mbv.visitInstructionList(ctor_insns);
      mbv.visitEnd();
      mv.visitEnd();
    }

    //  If the class has static initialization
    //  logic, emit a cinit routine.
    if (!this.cinitInsns.isEmpty()) {
      InstructionList cinit_insns = new InstructionList();
      cinit_insns.addInstruction(OP_getlocal0);
      cinit_insns.addInstruction(OP_pushscope);

      //  TODO: Examine other end-of-function processing
      //  and ensure it's completed.
      this.classStaticScope.finishClassStaticInitializer(this.cinitInsns);
      cinit_insns.addAll(this.cinitInsns);

      cinit_insns.addInstruction(OP_returnvoid);

      this.classStaticScope.methodBodyVisitor.visitInstructionList(cinit_insns);
      this.classStaticScope.methodBodyVisitor.visitEnd();
      this.classStaticScope.methodVisitor.visitEnd();
    } else {
      //  Ensure nothing got dropped.
      assert (this.classStaticScope.methodBodyVisitor == null);
    }

    itraits.visitEnd();
    ctraits.visitEnd();

    cv.visitEnd();
  }
  /**
   * Constructor. Initializes the ClassDirectiveProcessor and its associated AET data structures.
   *
   * @param node - the AST that starts the class' definition in source; used for diagnostics.
   * @param class_definition - the class' definition
   * @param enclosing_scope - the immediately enclosing lexical scope.
   * @param emitter - the active ABC emitter.
   */
  ClassDirectiveProcessor(
      ICommonClassNode node,
      ClassDefinition class_definition,
      LexicalScope enclosing_scope,
      IABCVisitor emitter) {
    super(enclosing_scope.getProblems());

    this.emitter = emitter;
    this.definitionSource = node;
    assert (this.definitionSource != null) : "Class definition AST must be provided.";

    this.classScope = enclosing_scope.pushFrame();
    this.classStaticScope = enclosing_scope.pushFrame();

    if (node.getNodeID() == ASTNodeID.ClassID) {
      classScope.setInitialControlFlowRegionNode(((ClassNode) node).getScopedNode());
      classStaticScope.setInitialControlFlowRegionNode(((ClassNode) node).getScopedNode());
    }

    ICompilerProject project = classScope.getProject();

    // Set the class Name.
    this.classDefinition = class_definition;
    this.className = classDefinition.getMName(project);
    iinfo.name = className;

    // Check for a duplicate class name.
    switch (SemanticUtils.getMultiDefinitionType(this.classDefinition, project)) {
      case AMBIGUOUS:
        classScope.addProblem(
            new DuplicateClassDefinitionProblem(node, class_definition.getBaseName()));
        break;
      case NONE:
        break;
      default:
        assert false; // I don't think classes can have other type of multiple definitions
    }

    if (node instanceof BaseDefinitionNode) // test doesn't work for MXML, which is OK.
    {
      BaseDefinitionNode n = (BaseDefinitionNode) node;
      SemanticUtils.checkScopedToDefaultNamespaceProblem(classScope, n, classDefinition, null);
    }
    // Resolve the super class, checking that it exists,
    // that it is a class rather than an interface,
    // that it isn't final, and that it isn't the same as this class.
    ClassDefinition superclassDefinition =
        SemanticUtils.resolveBaseClass(node, class_definition, project, classScope.getProblems());

    // Check that the superclass isn't a forward reference, but only need to do this if both
    // definitions come from the same containing source.  getContainingFilePath() returns the file
    // from the ASFileScope, so no need to worry about included files.
    if (!classDefinition.isGeneratedEmbedClass()
        && classDefinition
            .getContainingFilePath()
            .equals(superclassDefinition.getContainingFilePath())) {
      // If the absolute offset in the class is less than the
      // offset of the super class, it must be a forward reference in the file
      int classOffset = classDefinition.getAbsoluteStart();
      int superClassOffset = superclassDefinition.getAbsoluteEnd();
      if (classOffset < superClassOffset)
        classScope.addProblem(
            new ForwardReferenceToBaseClassProblem(node, superclassDefinition.getQualifiedName()));
    }

    // Set the superclass Name.
    this.superclassName = superclassDefinition.getMName(project);
    iinfo.superName = superclassName;

    // Resolve the interfaces.
    IInterfaceDefinition[] interfaces =
        classDefinition.resolveImplementedInterfaces(project, classScope.getProblems());

    // Set the interface Names.
    int n_interfaces = interfaces.length;
    ArrayList<Name> interface_names = new ArrayList<Name>(n_interfaces);
    for (int i = 0; i < n_interfaces; i++) {
      InterfaceDefinition idef = (InterfaceDefinition) interfaces[i];
      if (idef != null) {
        Name interfaceName = ((InterfaceDefinition) interfaces[i]).getMName(project);
        interface_names.add(interfaceName);
      }
    }
    iinfo.interfaceNames = interface_names.toArray(new Name[interface_names.size()]);

    // Set the flags corresponding to 'final' and 'dynamic'.
    if (classDefinition.isFinal()) iinfo.flags |= ABCConstants.CLASS_FLAG_final;
    if (!classDefinition.isDynamic()) iinfo.flags |= ABCConstants.CLASS_FLAG_sealed;

    iinfo.protectedNs =
        ((NamespaceDefinition) classDefinition.getProtectedNamespaceReference()).getAETNamespace();

    this.cv = emitter.visitClass(iinfo, cinfo);
    cv.visit();

    this.itraits = cv.visitInstanceTraits();
    this.ctraits = cv.visitClassTraits();

    this.classScope.traitsVisitor = this.itraits;
    this.classStaticScope.traitsVisitor = this.ctraits;

    // Build an array of the names of all the ancestor classes.
    ArrayList<Name> ancestorClassNames = new ArrayList<Name>();

    // Walk the superclass chain, starting with this class
    // and (unless there are problems) ending with Object.
    // This will accomplish three things:
    // - find loops;
    // - build the array of names of ancestor classes;
    // - set the needsProtected flag if this class or any of its ancestor classes needs it.

    boolean needsProtected = false;

    //  Remember the most recently examined class in case there's a cycle in the superclass
    //  chain, in which case we'll need it to issue a diagnostic.
    ClassDefinition c = null;

    IClassDefinition.IClassIterator classIterator = classDefinition.classIterator(project, true);

    while (classIterator.hasNext()) {
      c = (ClassDefinition) classIterator.next();
      needsProtected |= c.getOwnNeedsProtected();
      if (c != classDefinition) ancestorClassNames.add(c.getMName(project));
    }

    // Report a loop in the superclass chain, such as A extends B and B extends A.
    // Note: A extends A was found previously by SemanticUtils.resolveBaseClass().
    if (classIterator.foundLoop())
      classScope.addProblem(new CircularTypeReferenceProblem(c, c.getQualifiedName()));

    // In the case of class A extends A, ancestorClassNames will be empty at this point.
    // Change it to be Object to prevent "Warning: Stack underflow" in the script init code below.
    if (ancestorClassNames.isEmpty()) {
      ClassDefinition objectDefinition =
          (ClassDefinition) project.getBuiltinType(IASLanguageConstants.BuiltinType.OBJECT);
      ancestorClassNames.add(objectDefinition.getMName(project));
    }

    // If this class or any of its ancestor classes needs the protected flag set, set it.
    if (needsProtected) iinfo.flags |= ABCConstants.CLASS_FLAG_protected;

    // Add the class initialization logic to the script init.
    // For class B extends A, where class A extends Object, this looks like
    // getscopeobject
    // findpropstrict Object
    // getproperty Object
    // pushscope
    // findpropstrict A
    // getproperty A
    // dup
    // pushscope
    // newclass
    // popscope
    // popscope
    // initproperty B
    InstructionList initInstructions = this.classScope.getInitInstructions();
    initInstructions.addInstruction(OP_getscopeobject, 0);

    // Push ancestor classes onto the scope stack.
    for (int i = ancestorClassNames.size() - 1; i >= 0; i--) {
      Name ancestorClassName = ancestorClassNames.get(i);
      initInstructions.addInstruction(OP_getlex, ancestorClassName);
      // The newclass instruction below also needs the superclass on the stack, so dup it
      if (i == 0) initInstructions.addInstruction(OP_dup);
      initInstructions.addInstruction(OP_pushscope);
    }

    initInstructions.addInstruction(OP_newclass, cinfo);

    for (int i = 0; i < ancestorClassNames.size(); i++)
      initInstructions.addInstruction(OP_popscope);

    initInstructions.addInstruction(OP_initproperty, className);

    implementedInterfaceSemanticChecks(class_definition);

    processResourceBundles(class_definition, project, classScope.getProblems());
  }
  /**
   * @param lexicalScope The surrounding LexicalScope (as in Constant), or null if it is ignored (as
   *     in Mod::Constant or ::Constant)
   * @param module The receiver of the constant lookup. Must be identical to
   *     lexicalScope.getLiveModule() if lexicalScope != null.
   */
  @TruffleBoundary
  public static RubyConstant lookupConstant(
      RubyContext context, LexicalScope lexicalScope, RubyModule module, String name) {
    CompilerAsserts.neverPartOfCompilation();
    assert lexicalScope == null || lexicalScope.getLiveModule() == module;

    RubyConstant constant;

    // Look in the current module
    constant = module.getConstants().get(name);

    if (constant != null) {
      return constant;
    }

    // Look in lexical scope
    if (lexicalScope != null) {
      if (lexicalScope != context.getRootLexicalScope()) {
        // Already looked in the top lexical scope, which is module.
        lexicalScope = lexicalScope.getParent();
      }

      while (lexicalScope != context.getRootLexicalScope()) {
        constant = lexicalScope.getLiveModule().getConstants().get(name);

        if (constant != null) {
          return constant;
        }

        lexicalScope = lexicalScope.getParent();
      }
    }

    // Look in ancestors
    for (RubyModule ancestor : module.parentAncestors()) {
      constant = ancestor.getConstants().get(name);

      if (constant != null) {
        return constant;
      }
    }

    // Look in Object and its included modules
    if (module.isOnlyAModule()) {
      final RubyClass objectClass = context.getCoreLibrary().getObjectClass();

      constant = objectClass.getConstants().get(name);
      if (constant != null) {
        return constant;
      }

      for (RubyModule ancestor : objectClass.includedModules()) {
        constant = ancestor.getConstants().get(name);

        if (constant != null) {
          return constant;
        }
      }
    }

    // Nothing found
    return null;
  }