@NotNull
  private static FunctionDescriptor standardFunction(
      ClassDescriptor classDescriptor, String name, Project project, KotlinType... parameterTypes) {
    ModuleDescriptorImpl emptyModule = KotlinTestUtils.createEmptyModule();
    ContainerForTests container = InjectionKt.createContainerForTests(project, emptyModule);
    emptyModule.setDependencies(emptyModule);
    emptyModule.initialize(PackageFragmentProvider.Empty.INSTANCE);

    LexicalScopeImpl lexicalScope =
        new LexicalScopeImpl(
            ImportingScope.Empty.INSTANCE,
            classDescriptor,
            false,
            classDescriptor.getThisAsReceiverParameter(),
            LexicalScopeKind.SYNTHETIC);

    ExpressionTypingContext context =
        ExpressionTypingContext.newContext(
            new BindingTraceContext(),
            lexicalScope,
            DataFlowInfoFactory.EMPTY,
            TypeUtils.NO_EXPECTED_TYPE);

    OverloadResolutionResults<FunctionDescriptor> functions =
        container
            .getFakeCallResolver()
            .resolveFakeCall(
                context,
                null,
                Name.identifier(name),
                null,
                null,
                FakeCallKind.OTHER,
                parameterTypes);

    for (ResolvedCall<? extends FunctionDescriptor> resolvedCall : functions.getResultingCalls()) {
      List<ValueParameterDescriptor> unsubstitutedValueParameters =
          resolvedCall.getResultingDescriptor().getValueParameters();
      for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size();
          i < unsubstitutedValueParametersSize;
          i++) {
        ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
        if (unsubstitutedValueParameter.getType().equals(parameterTypes[i])) {
          return resolvedCall.getResultingDescriptor();
        }
      }
    }
    throw new IllegalArgumentException(
        "Not found: kotlin::"
            + classDescriptor.getName()
            + "."
            + name
            + "("
            + Arrays.toString(parameterTypes)
            + ")");
  }
  private void appendDescriptor(DeclarationDescriptor descriptor, String indent) {
    int startOffset = myBuilder.length();
    myBuilder.append(DescriptorRenderer.COMPACT.render(descriptor));
    int endOffset = myBuilder.length();

    if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) {
      if (((CallableMemberDescriptor) descriptor).getModality() != Modality.ABSTRACT) {
        if (descriptor instanceof FunctionDescriptor) {
          myBuilder.append(" { ").append(DECOMPILED_COMMENT).append(" }");
          endOffset = myBuilder.length();
        } else { // descriptor instanceof PropertyDescriptor
          if (((PropertyDescriptor) descriptor).getModality() != Modality.ABSTRACT) {
            myBuilder.append(" ").append(DECOMPILED_COMMENT);
          }
        }
      }
    } else if (descriptor instanceof ClassDescriptor) {
      myBuilder.append(" {\n");
      ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
      boolean firstPassed = false;
      String subindent = indent + "    ";
      if (classDescriptor.getClassObjectDescriptor() != null) {
        firstPassed = true;
        myBuilder.append(subindent).append("class ");
        appendDescriptor(classDescriptor.getClassObjectDescriptor(), subindent);
      }
      for (DeclarationDescriptor member :
          sortDeclarations(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) {
        if (member.getContainingDeclaration() == descriptor) {
          if (firstPassed) {
            myBuilder.append("\n");
          } else {
            firstPassed = true;
          }
          myBuilder.append(subindent);
          appendDescriptor(member, subindent);
        }
      }
      myBuilder.append(indent).append("}");
      endOffset = myBuilder.length();
    }

    myBuilder.append("\n");
    PsiElement clsMember =
        myBindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
    if (clsMember != null) {
      myClsMembersToRanges.put(clsMember, new TextRange(startOffset, endOffset));
    }
  }
  @NotNull
  private static Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>>
      getSuperclassToFunctionsMultimap(
          @NotNull PsiMethodWrapper method,
          @NotNull BindingContext bindingContext,
          @NotNull ClassDescriptor containingClass) {
    Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>> result = HashMultimap.create();

    Name functionName = Name.identifier(method.getName());
    int parameterCount = method.getParameters().size();

    for (JetType supertype : TypeUtils.getAllSupertypes(containingClass.getDefaultType())) {
      ClassifierDescriptor klass = supertype.getConstructor().getDeclarationDescriptor();
      assert klass != null;
      FqName fqName = DescriptorUtils.getFQName(klass).toSafe();

      for (FunctionDescriptor fun :
          klass.getDefaultType().getMemberScope().getFunctions(functionName)) {
        if (fun.getKind().isReal() && fun.getValueParameters().size() == parameterCount) {
          PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, fun);
          if (declaration instanceof PsiMethod) {
            result.put(fqName, Pair.create(fun, (PsiMethod) declaration));
          } // else declaration is null or JetNamedFunction: both cases are processed later
        }
      }
    }
    return result;
  }
  // Returns list with type arguments info from supertypes
  // Example:
  //     - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
  //     - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
  //     - output[0] = [String, CharSequence], output[1] = []
  private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
      @NotNull ClassDescriptor klass, @NotNull Collection<TypeAndVariance> typesFromSuper) {
    // For each superclass of klass and its parameters, hold their mapping to klass' parameters
    // #0 of Bar ->  A
    // #1 of Bar ->  List<B>
    // #0 of Baz ->  Boolean
    // #1 of Baz ->  A
    // #0 of Foo ->  A (mapped to itself)
    // #1 of Foo ->  B (mapped to itself)
    Multimap<TypeConstructor, TypeProjection> substitution =
        SubstitutionUtils.buildDeepSubstitutionMultimap(
            TypeUtils.makeUnsubstitutedType(klass, JetScope.EMPTY));

    // for each parameter of klass, hold arguments in corresponding supertypes
    List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
    for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
      parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
    }

    // Enumerate all types from super and all its parameters
    for (TypeAndVariance typeFromSuper : typesFromSuper) {
      for (TypeParameterDescriptor parameter :
          typeFromSuper.type.getConstructor().getParameters()) {
        TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());

        // for given example, this block is executed four times:
        // 1. typeFromSuper = Bar<String, List<Int>>,      parameter = "#0 of Bar",  argument =
        // String
        // 2. typeFromSuper = Bar<String, List<Int>>,      parameter = "#1 of Bar",  argument =
        // List<Int>
        // 3. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#0 of Baz",  argument =
        // Boolean
        // 4. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#1 of Baz",  argument =
        // CharSequence

        // if it is mapped to klass' parameter, then store it into map
        for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) {
          // 1. projection = A
          // 2. projection = List<B>
          // 3. projection = Boolean
          // 4. projection = A
          ClassifierDescriptor classifier =
              projection.getType().getConstructor().getDeclarationDescriptor();

          // this condition is true for 1 and 4, false for 2 and 3
          if (classifier instanceof TypeParameterDescriptor
              && classifier.getContainingDeclaration() == klass) {
            int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
            Variance effectiveVariance =
                parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
            parameterToArgumentsFromSuper
                .get(parameterIndex)
                .add(new TypeProjectionAndVariance(argument, effectiveVariance));
          }
        }
      }
    }
    return parameterToArgumentsFromSuper;
  }
 private static Map<ClassDescriptor, JetType> getSuperclassToSupertypeMap(
     ClassDescriptor containingClass) {
   Map<ClassDescriptor, JetType> superclassToSupertype = Maps.newHashMap();
   for (JetType supertype : TypeUtils.getAllSupertypes(containingClass.getDefaultType())) {
     ClassifierDescriptor superclass = supertype.getConstructor().getDeclarationDescriptor();
     assert superclass instanceof ClassDescriptor;
     superclassToSupertype.put((ClassDescriptor) superclass, supertype);
   }
   return superclassToSupertype;
 }
  @Nullable
  private CompileTimeConstant<?> getCompileTimeConstFromReferenceExpression(
      PsiReferenceExpression value, PostponedTasks taskList) {
    PsiElement resolveElement = value.resolve();
    if (resolveElement instanceof PsiEnumConstant) {
      PsiElement psiElement = resolveElement.getParent();
      if (psiElement instanceof PsiClass) {
        PsiClass psiClass = (PsiClass) psiElement;
        String fqName = psiClass.getQualifiedName();
        if (fqName == null) {
          return null;
        }

        JetScope scope;
        ClassDescriptor classDescriptor =
            classResolver.resolveClass(
                new FqName(fqName), DescriptorSearchRule.INCLUDE_KOTLIN, taskList);
        if (classDescriptor == null) {
          return null;
        }
        ClassDescriptor classObjectDescriptor = classDescriptor.getClassObjectDescriptor();
        if (classObjectDescriptor == null) {
          return null;
        }
        scope = classObjectDescriptor.getMemberScope(Lists.<TypeProjection>newArrayList());

        Name identifier = Name.identifier(((PsiEnumConstant) resolveElement).getName());
        Collection<VariableDescriptor> properties = scope.getProperties(identifier);
        for (VariableDescriptor variableDescriptor : properties) {
          if (variableDescriptor.getReceiverParameter() == null) {
            return new EnumValue((PropertyDescriptor) variableDescriptor);
          }
        }
        return null;
      }
    }
    return null;
  }