@NotNull
  public static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
      @NotNull ResolveSession resolveSession,
      @NotNull FqName fqName,
      boolean includeObjectDeclarations) {
    if (fqName.isRoot()) {
      return Collections.emptyList();
    }

    Collection<ClassDescriptor> classDescriptors = Lists.newArrayList();

    FqName packageFqName = fqName.parent();
    while (true) {
      NamespaceDescriptor packageDescriptor =
          resolveSession.getPackageDescriptorByFqName(packageFqName);
      if (packageDescriptor != null) {
        FqName classInPackagePath = new FqName(QualifiedNamesUtil.tail(packageFqName, fqName));
        Collection<ClassDescriptor> descriptors =
            getClassOrObjectDescriptorsByFqName(
                packageDescriptor, classInPackagePath, includeObjectDeclarations);
        classDescriptors.addAll(descriptors);
      }

      if (packageFqName.isRoot()) {
        break;
      } else {
        packageFqName = packageFqName.parent();
      }
    }

    return classDescriptors;
  }
 private static void functionAdditionalResolve(
     ResolveSession resolveSession,
     JetNamedFunction namedFunction,
     DelegatingBindingTrace trace,
     JetFile file) {
   BodyResolver bodyResolver =
       createBodyResolverWithEmptyContext(trace, file, resolveSession.getModuleConfiguration());
   JetScope scope =
       resolveSession
           .getInjector()
           .getScopeProvider()
           .getResolutionScopeForDeclaration(namedFunction);
   FunctionDescriptor functionDescriptor =
       (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction);
   bodyResolver.resolveFunctionBody(trace, namedFunction, functionDescriptor, scope);
 }
  private static boolean initializerAdditionalResolve(
      ResolveSession resolveSession,
      JetClassInitializer classInitializer,
      DelegatingBindingTrace trace,
      JetFile file) {
    BodyResolver bodyResolver =
        createBodyResolverWithEmptyContext(trace, file, resolveSession.getModuleConfiguration());
    JetClassOrObject classOrObject =
        PsiTreeUtil.getParentOfType(classInitializer, JetClassOrObject.class);
    LazyClassDescriptor classOrObjectDescriptor =
        (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject);
    bodyResolver.resolveAnonymousInitializers(
        classOrObject,
        classOrObjectDescriptor.getUnsubstitutedPrimaryConstructor(),
        classOrObjectDescriptor.getScopeForPropertyInitializerResolution());

    return true;
  }
 @Override
 public List<AnnotationDescriptor> getAnnotations() {
   if (annotations == null) {
     JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
     JetModifierList modifierList = classInfo.getModifierList();
     if (modifierList != null) {
       AnnotationResolver annotationResolver =
           resolveSession.getInjector().getAnnotationResolver();
       annotations =
           annotationResolver.resolveAnnotations(
               resolveSession.getResolutionScope(classInfo.getScopeAnchor()),
               modifierList,
               resolveSession.getTrace());
     } else {
       annotations = Collections.emptyList();
     }
   }
   return annotations;
 }
 private static JetScope getExpressionResolutionScope(
     @NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
   ScopeProvider provider = resolveSession.getInjector().getScopeProvider();
   JetDeclaration parentDeclaration =
       PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
   if (parentDeclaration == null) {
     return provider.getFileScopeWithAllImported((JetFile) expression.getContainingFile());
   }
   return provider.getResolutionScopeForDeclaration(parentDeclaration);
 }
  public static @NotNull BindingContext resolveToExpression(
      @NotNull final ResolveSession resolveSession, @NotNull JetExpression expression) {
    final DelegatingBindingTrace trace =
        new DelegatingBindingTrace(
            resolveSession.getBindingContext(), "trace to resolve expression", expression);
    JetFile file = (JetFile) expression.getContainingFile();

    @SuppressWarnings("unchecked")
    PsiElement topmostCandidateForAdditionalResolve =
        JetPsiUtil.getTopmostParentOfTypes(
            expression,
            JetNamedFunction.class,
            JetClassInitializer.class,
            JetProperty.class,
            JetDelegationSpecifierList.class);

    if (topmostCandidateForAdditionalResolve != null) {
      if (topmostCandidateForAdditionalResolve instanceof JetNamedFunction) {
        functionAdditionalResolve(
            resolveSession, (JetNamedFunction) topmostCandidateForAdditionalResolve, trace, file);
      } else if (topmostCandidateForAdditionalResolve instanceof JetClassInitializer) {
        initializerAdditionalResolve(
            resolveSession,
            (JetClassInitializer) topmostCandidateForAdditionalResolve,
            trace,
            file);
      } else if (topmostCandidateForAdditionalResolve instanceof JetProperty) {
        propertyAdditionalResolve(
            resolveSession, (JetProperty) topmostCandidateForAdditionalResolve, trace, file);
      } else if (topmostCandidateForAdditionalResolve instanceof JetDelegationSpecifierList) {
        delegationSpecifierAdditionalResolve(
            resolveSession,
            (JetDelegationSpecifierList) topmostCandidateForAdditionalResolve,
            trace,
            file);
      } else {
        assert false : "Invalid type of the topmost parent";
      }

      return trace.getBindingContext();
    }

    // Setup resolution scope explicitly
    if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, expression) == null) {
      JetScope scope = getExpressionMemberScope(resolveSession, expression);
      if (scope != null) {
        trace.record(BindingContext.RESOLUTION_SCOPE, expression, scope);
      }
    }

    return trace.getBindingContext();
  }
  private static void delegationSpecifierAdditionalResolve(
      final ResolveSession resolveSession,
      final JetDelegationSpecifierList specifier,
      DelegatingBindingTrace trace,
      JetFile file) {
    BodyResolver bodyResolver =
        createBodyResolverWithEmptyContext(trace, file, resolveSession.getModuleConfiguration());

    JetClassOrObject classOrObject = (JetClassOrObject) specifier.getParent();
    LazyClassDescriptor descriptor =
        (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject);

    // Activate resolving of supertypes
    descriptor.getTypeConstructor().getSupertypes();

    bodyResolver.resolveDelegationSpecifierList(
        classOrObject,
        descriptor,
        descriptor.getUnsubstitutedPrimaryConstructor(),
        descriptor.getScopeForClassHeaderResolution(),
        descriptor.getScopeForMemberDeclarationResolution());
  }
  private static void propertyAdditionalResolve(
      final ResolveSession resolveSession,
      final JetProperty jetProperty,
      DelegatingBindingTrace trace,
      JetFile file) {
    final JetScope propertyResolutionScope =
        resolveSession
            .getInjector()
            .getScopeProvider()
            .getResolutionScopeForDeclaration(jetProperty);

    BodyResolveContextForLazy bodyResolveContext =
        new BodyResolveContextForLazy(
            new Function<JetDeclaration, JetScope>() {
              @Override
              public JetScope apply(JetDeclaration declaration) {
                assert declaration.getParent() == jetProperty
                    : "Must be called only for property accessors, but called for " + declaration;
                return propertyResolutionScope;
              }
            });
    BodyResolver bodyResolver =
        createBodyResolver(
            trace, file, bodyResolveContext, resolveSession.getModuleConfiguration());
    PropertyDescriptor descriptor =
        (PropertyDescriptor) resolveSession.resolveToDescriptor(jetProperty);

    JetExpression propertyInitializer = jetProperty.getInitializer();

    if (propertyInitializer != null) {
      bodyResolver.resolvePropertyInitializer(
          jetProperty, descriptor, propertyInitializer, propertyResolutionScope);
    }

    bodyResolver.resolvePropertyAccessors(jetProperty, descriptor);
  }
  public LazyClassDescriptor(
      @NotNull ResolveSession resolveSession,
      @NotNull DeclarationDescriptor containingDeclaration,
      @NotNull Name name,
      @NotNull JetClassLikeInfo classLikeInfo) {
    this.resolveSession = resolveSession;
    this.name = name;

    if (classLikeInfo.getCorrespondingClassOrObject() != null) {
      this.resolveSession
          .getTrace()
          .record(BindingContext.CLASS, classLikeInfo.getCorrespondingClassOrObject(), this);
    }

    this.originalClassInfo = classLikeInfo;
    JetClassLikeInfo classLikeInfoForMembers =
        classLikeInfo.getClassKind() != ClassKind.ENUM_CLASS
            ? classLikeInfo
            : noEnumEntries(classLikeInfo);
    this.declarationProvider =
        resolveSession
            .getDeclarationProviderFactory()
            .getClassMemberDeclarationProvider(classLikeInfoForMembers);
    this.containingDeclaration = containingDeclaration;
    this.unsubstitutedMemberScope =
        new LazyClassMemberScope(resolveSession, declarationProvider, this);
    this.unsubstitutedInnerClassesScope = new InnerClassesScopeWrapper(unsubstitutedMemberScope);

    this.typeConstructor = new LazyClassTypeConstructor();

    this.kind = classLikeInfo.getClassKind();
    if (kind == ClassKind.OBJECT) {
      this.modality = Modality.FINAL;
    } else {
      Modality defaultModality = kind == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL;
      JetModifierList modifierList = classLikeInfo.getModifierList();
      this.modality = ModifiersChecker.resolveModalityFromModifiers(modifierList, defaultModality);
    }
    JetModifierList modifierList = classLikeInfo.getModifierList();
    this.visibility =
        ModifiersChecker.resolveVisibilityFromModifiers(modifierList, Visibilities.INTERNAL);
  }
  @NotNull
  public JetScope getScopeForClassHeaderResolution() {
    if (scopeForClassHeaderResolution == null) {
      WritableScopeImpl scope =
          new WritableScopeImpl(
              JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Class Header Resolution");
      for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
        scope.addClassifierDescriptor(typeParameterDescriptor);
      }
      scope.changeLockLevel(WritableScope.LockLevel.READING);

      scopeForClassHeaderResolution =
          new ChainedScope(
              this,
              scope,
              resolveSession.getResolutionScope(
                  declarationProvider.getOwnerInfo().getScopeAnchor()));
    }
    return scopeForClassHeaderResolution;
  }
  public static JetScope getExpressionMemberScope(
      @NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
    DelegatingBindingTrace trace =
        new DelegatingBindingTrace(
            resolveSession.getBindingContext(),
            "trace to resolve a member scope of expression",
            expression);

    if (expression instanceof JetReferenceExpression) {
      QualifiedExpressionResolver qualifiedExpressionResolver =
          resolveSession.getInjector().getQualifiedExpressionResolver();

      // In some type declaration
      if (expression.getParent() instanceof JetUserType) {
        JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier();
        if (qualifier != null) {
          Collection<? extends DeclarationDescriptor> descriptors =
              qualifiedExpressionResolver.lookupDescriptorsForUserType(
                  qualifier, getExpressionResolutionScope(resolveSession, expression), trace);

          for (DeclarationDescriptor descriptor : descriptors) {
            if (descriptor instanceof LazyPackageDescriptor) {
              return ((LazyPackageDescriptor) descriptor).getMemberScope();
            }
          }
        }
      }

      // Inside import
      if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class, false) != null) {
        NamespaceDescriptor rootPackage = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
        assert rootPackage != null;

        if (expression.getParent() instanceof JetDotQualifiedExpression) {
          JetExpression element =
              ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression();
          String name = ((JetFile) expression.getContainingFile()).getPackageName();

          NamespaceDescriptor filePackage =
              name != null
                  ? resolveSession.getPackageDescriptorByFqName(new FqName(name))
                  : rootPackage;
          assert filePackage != null : "File package should be already resolved and be found";

          JetScope scope = filePackage.getMemberScope();
          Collection<? extends DeclarationDescriptor> descriptors;

          if (element instanceof JetDotQualifiedExpression) {
            descriptors =
                qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression(
                    (JetDotQualifiedExpression) element,
                    rootPackage.getMemberScope(),
                    scope,
                    trace,
                    false,
                    false);
          } else {
            descriptors =
                qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference(
                    (JetSimpleNameExpression) element,
                    rootPackage.getMemberScope(),
                    scope,
                    trace,
                    false,
                    false,
                    false);
          }

          for (DeclarationDescriptor descriptor : descriptors) {
            if (descriptor instanceof NamespaceDescriptor) {
              return ((NamespaceDescriptor) descriptor).getMemberScope();
            }
          }
        } else {
          return rootPackage.getMemberScope();
        }
      }

      // Inside package declaration
      JetNamespaceHeader namespaceHeader =
          PsiTreeUtil.getParentOfType(expression, JetNamespaceHeader.class, false);
      if (namespaceHeader != null) {
        NamespaceDescriptor packageDescriptor =
            resolveSession.getPackageDescriptorByFqName(
                namespaceHeader.getParentFqName((JetReferenceExpression) expression));
        if (packageDescriptor != null) {
          return packageDescriptor.getMemberScope();
        }
      }
    }

    return null;
  }