@Override
    public void visitJetFile(@NotNull JetFile file) {
      MutablePackageFragmentDescriptor packageFragment = getOrCreatePackageFragmentForFile(file);
      c.getPackageFragments().put(file, packageFragment);
      c.addFile(file);

      PackageViewDescriptor packageView =
          packageFragment.getContainingDeclaration().getPackage(packageFragment.getFqName());
      ChainedScope rootPlusPackageScope =
          new ChainedScope(
              packageView, "Root scope for " + file, packageView.getMemberScope(), outerScope);
      WriteThroughScope packageScope =
          new WriteThroughScope(
              rootPlusPackageScope,
              packageFragment.getMemberScope(),
              new TraceBasedRedeclarationHandler(trace),
              "package in file " + file.getName());
      packageScope.changeLockLevel(WritableScope.LockLevel.BOTH);
      c.getFileScopes().put(file, packageScope);

      if (file.isScript()) {
        scriptHeaderResolver.processScriptHierarchy(c, file.getScript(), packageScope);
      }

      prepareForDeferredCall(packageScope, packageFragment, file);
    }
    @NotNull
    private MutableClassDescriptor createClassDescriptorForClass(
        @NotNull JetClass klass, @NotNull DeclarationDescriptor containingDeclaration) {
      ClassKind kind = getClassKind(klass);
      // Kind check is needed in order to not consider enums as inner in any case
      // (otherwise it would be impossible to create a class object in the enum)
      boolean isInner = kind == ClassKind.CLASS && klass.isInner();
      MutableClassDescriptor mutableClassDescriptor =
          new MutableClassDescriptor(
              containingDeclaration,
              outerScope,
              kind,
              isInner,
              JetPsiUtil.safeName(klass.getName()));
      c.getClasses().put(klass, mutableClassDescriptor);
      trace.record(
          FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getUnsafeFQName(klass), mutableClassDescriptor);

      createClassObjectForEnumClass(mutableClassDescriptor);

      JetScope classScope = mutableClassDescriptor.getScopeForMemberDeclarationResolution();

      prepareForDeferredCall(classScope, mutableClassDescriptor, klass);

      return mutableClassDescriptor;
    }
    @Override
    public void visitClassObject(@NotNull JetClassObject classObject) {
      JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();

      DeclarationDescriptor container = owner.getOwnerForChildren();

      MutableClassDescriptor classObjectDescriptor =
          createClassDescriptorForSingleton(
              objectDeclaration, getClassObjectName(container.getName()), ClassKind.CLASS_OBJECT);

      PackageLikeBuilder.ClassObjectStatus status =
          isEnumEntry(container)
                  || isObject(container)
                  || c.getTopDownAnalysisParameters().isDeclaredLocally()
              ? PackageLikeBuilder.ClassObjectStatus.NOT_ALLOWED
              : owner.setClassObjectDescriptor(classObjectDescriptor);

      switch (status) {
        case DUPLICATE:
          trace.report(MANY_CLASS_OBJECTS.on(classObject));
          break;
        case NOT_ALLOWED:
          trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
          break;
        case OK:
          // Everything is OK so no errors to trace.
          break;
      }
    }
  private void detectAndDisconnectLoops(@NotNull TopDownAnalysisContext c) {
    // Loop detection and disconnection
    List<Runnable> tasks = new ArrayList<Runnable>();
    for (final MutableClassDescriptorLite klass : c.getClassesTopologicalOrder()) {
      for (final JetType supertype : klass.getSupertypes()) {
        ClassifierDescriptor supertypeDescriptor =
            supertype.getConstructor().getDeclarationDescriptor();
        if (supertypeDescriptor instanceof MutableClassDescriptorLite) {
          MutableClassDescriptorLite superclass = (MutableClassDescriptorLite) supertypeDescriptor;
          if (isReachable(superclass, klass, new HashSet<ClassDescriptor>())) {
            tasks.add(
                new Runnable() {
                  @Override
                  public void run() {
                    klass.getSupertypes().remove(supertype);
                  }
                });
            reportCyclicInheritanceHierarchyError(trace, klass, superclass);
          }
        }
      }
    }

    for (Runnable task : tasks) {
      task.run();
    }
  }
 private List<MutableClassDescriptorLite> topologicallySortClassesAndObjects(
     @NotNull TopDownAnalysisContext c) {
   // A topsort is needed only for better diagnostics:
   //    edges that get removed to disconnect loops are more reasonable in this case
   //noinspection unchecked
   return DFS.topologicalOrder(
       (Iterable) c.getClasses().values(),
       new DFS.Neighbors<MutableClassDescriptorLite>() {
         @NotNull
         @Override
         public Iterable<MutableClassDescriptorLite> getNeighbors(
             MutableClassDescriptorLite current) {
           List<MutableClassDescriptorLite> result = Lists.newArrayList();
           for (JetType supertype : current.getSupertypes()) {
             DeclarationDescriptor declarationDescriptor =
                 supertype.getConstructor().getDeclarationDescriptor();
             if (declarationDescriptor instanceof MutableClassDescriptorLite) {
               MutableClassDescriptorLite classDescriptor =
                   (MutableClassDescriptorLite) declarationDescriptor;
               result.add(classDescriptor);
             }
           }
           return result;
         }
       });
 }
  public void process(
      @NotNull TopDownAnalysisContext c,
      @NotNull JetScope outerScope,
      @NotNull PackageLikeBuilder owner,
      @NotNull Collection<? extends PsiElement> declarations) {

    {
      // TODO: Very temp code - main goal is to remove recursion from
      // collectPackageFragmentsAndClassifiers
      Queue<JetDeclarationContainer> forDeferredResolve = new LinkedList<JetDeclarationContainer>();
      forDeferredResolve.addAll(
          collectPackageFragmentsAndClassifiers(c, outerScope, owner, declarations));

      while (!forDeferredResolve.isEmpty()) {
        JetDeclarationContainer declarationContainer = forDeferredResolve.poll();
        assert declarationContainer != null;

        DeclarationDescriptor descriptorForDeferredResolve =
            c.forDeferredResolver.get(declarationContainer);
        JetScope scope = c.normalScope.get(declarationContainer);

        // Even more temp code
        if (descriptorForDeferredResolve instanceof MutableClassDescriptorLite) {
          forDeferredResolve.addAll(
              collectPackageFragmentsAndClassifiers(
                  c,
                  scope,
                  ((MutableClassDescriptorLite) descriptorForDeferredResolve).getBuilder(),
                  declarationContainer.getDeclarations()));
        } else if (descriptorForDeferredResolve instanceof MutablePackageFragmentDescriptor) {
          forDeferredResolve.addAll(
              collectPackageFragmentsAndClassifiers(
                  c,
                  scope,
                  ((MutablePackageFragmentDescriptor) descriptorForDeferredResolve).getBuilder(),
                  declarationContainer.getDeclarations()));
        } else {
          assert false;
        }
      }
    }

    importsResolver.processTypeImports(c);

    createTypeConstructors(
        c); // create type constructors for classes and generic parameters, supertypes are not
            // filled in
    resolveTypesInClassHeaders(
        c); // Generic bounds and types in supertype lists (no expressions or constructor
            // resolution)

    c.setClassesTopologicalOrder(topologicallySortClassesAndObjects(c));

    // Detect and disconnect all loops in the hierarchy
    detectAndDisconnectLoops(c);
  }
  private void resolveTypesInClassHeaders(@NotNull TopDownAnalysisContext c) {
    for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry :
        c.getClasses().entrySet()) {
      JetClassOrObject classOrObject = entry.getKey();
      if (classOrObject instanceof JetClass) {
        ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
        //noinspection unchecked
        descriptorResolver.resolveGenericBounds(
            (JetClass) classOrObject,
            descriptor,
            descriptor.getScopeForClassHeaderResolution(),
            (List) descriptor.getTypeConstructor().getParameters(),
            trace);
      }
    }

    for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry :
        c.getClasses().entrySet()) {
      descriptorResolver.resolveSupertypesForMutableClassDescriptor(
          entry.getKey(), (MutableClassDescriptor) entry.getValue(), trace);
    }
  }
    @NotNull
    private MutableClassDescriptor createClassDescriptorForSingleton(
        @NotNull JetClassOrObject declaration, @NotNull Name name, @NotNull ClassKind kind) {
      MutableClassDescriptor descriptor =
          new MutableClassDescriptor(owner.getOwnerForChildren(), outerScope, kind, false, name);

      prepareForDeferredCall(
          descriptor.getScopeForMemberDeclarationResolution(), descriptor, declaration);

      createPrimaryConstructorForObject(declaration, descriptor);
      trace.record(BindingContext.CLASS, declaration, descriptor);

      c.getClasses().put(declaration, descriptor);

      return descriptor;
    }
  private void createTypeConstructors(@NotNull TopDownAnalysisContext c) {
    for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry :
        c.getClasses().entrySet()) {
      JetClassOrObject classOrObject = entry.getKey();
      MutableClassDescriptor descriptor = (MutableClassDescriptor) entry.getValue();
      if (classOrObject instanceof JetClass) {
        descriptorResolver.resolveMutableClassDescriptor(
            (JetClass) classOrObject, descriptor, trace);
      } else if (classOrObject instanceof JetObjectDeclaration) {
        descriptor.setModality(Modality.FINAL);
        descriptor.setVisibility(
            resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor)));
        descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
      }

      descriptor.createTypeConstructor();

      ClassKind kind = descriptor.getKind();
      if (kind == ClassKind.ENUM_ENTRY
          || kind == ClassKind.OBJECT
          || kind == ClassKind.ENUM_CLASS) {
        MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor();
        assert classObject != null
            : "Enum entries and named objects should have class objects: "
                + classOrObject.getText();

        JetType supertype;
        if (kind == ClassKind.ENUM_CLASS) {
          supertype = KotlinBuiltIns.getInstance().getAnyType();
        } else {
          // This is a clever hack: each enum entry and object declaration (i.e. singleton) has a
          // synthetic class object.
          // We make this class object inherit from the singleton here, thus allowing to use the
          // singleton's class object where
          // the instance of the singleton is applicable. Effectively all members of the singleton
          // would be present in its class
          // object as fake overrides, so you can access them via standard class object notation:
          // ObjectName.memberName()
          supertype = descriptor.getDefaultType();
        }
        classObject.setSupertypes(Collections.singleton(supertype));
        classObject.createTypeConstructor();
      }
    }
  }