private static List<FunctionDescriptor> getSuperFunctionsForMethod(
      @NotNull PsiMethodWrapper method,
      @NotNull BindingTrace trace,
      @NotNull ClassDescriptor containingClass) {
    List<FunctionDescriptor> superFunctions = Lists.newArrayList();

    Map<ClassDescriptor, JetType> superclassToSupertype =
        getSuperclassToSupertypeMap(containingClass);

    Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>> superclassToFunctions =
        getSuperclassToFunctionsMultimap(method, trace.getBindingContext(), containingClass);

    for (HierarchicalMethodSignature superSignature :
        method.getPsiMethod().getHierarchicalMethodSignature().getSuperSignatures()) {
      PsiMethod superMethod = superSignature.getMethod();

      PsiClass psiClass = superMethod.getContainingClass();
      assert psiClass != null;
      String classFqNameString = psiClass.getQualifiedName();
      assert classFqNameString != null;
      FqName classFqName = new FqName(classFqNameString);

      if (!JavaToKotlinClassMap.getInstance().mapPlatformClass(classFqName).isEmpty()) {
        for (FunctionDescriptor superFun :
            JavaToKotlinMethodMap.INSTANCE.getFunctions(superMethod, containingClass)) {
          superFunctions.add(substituteSuperFunction(superclassToSupertype, superFun));
        }
        continue;
      }

      DeclarationDescriptor superFun =
          superMethod instanceof JetClsMethod
              ? trace.get(
                  BindingContext.DECLARATION_TO_DESCRIPTOR,
                  ((JetClsMethod) superMethod).getOrigin())
              : findSuperFunction(superclassToFunctions.get(classFqName), superMethod);
      if (superFun == null) {
        reportCantFindSuperFunction(method);
        continue;
      }

      assert superFun instanceof FunctionDescriptor : superFun.getClass().getName();

      superFunctions.add(
          substituteSuperFunction(superclassToSupertype, (FunctionDescriptor) superFun));
    }

    // sorting for diagnostic stability
    Collections.sort(
        superFunctions,
        new Comparator<FunctionDescriptor>() {
          @Override
          public int compare(FunctionDescriptor fun1, FunctionDescriptor fun2) {
            FqNameUnsafe fqName1 = getFQName(fun1.getContainingDeclaration());
            FqNameUnsafe fqName2 = getFQName(fun2.getContainingDeclaration());
            return fqName1.getFqName().compareTo(fqName2.getFqName());
          }
        });
    return superFunctions;
  }
  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
  public static LookupElement createLookupElement(
      @NotNull KotlinCodeAnalyzer analyzer,
      @NotNull DeclarationDescriptor descriptor,
      @Nullable PsiElement declaration) {
    if (declaration != null) {
      MutableLookupElement javaLookupElement = createJavaLookupElementIfPossible(declaration);
      if (javaLookupElement != null) {
        InsertHandler<LookupElement> customHandler = getInsertHandler(descriptor);
        if (customHandler != null) {
          return javaLookupElement.setInsertHandler(getInsertHandler(descriptor));
        } else {
          return javaLookupElement;
        }
      }
    }

    LookupElementBuilder element =
        LookupElementBuilder.create(
            new JetLookupObject(descriptor, analyzer, declaration), descriptor.getName().getName());

    String presentableText = descriptor.getName().getName();
    String typeText = "";
    String tailText = "";
    boolean tailTextGrayed = true;

    if (descriptor instanceof FunctionDescriptor) {
      FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
      JetType returnType = functionDescriptor.getReturnType();
      typeText = DescriptorRenderer.TEXT.renderType(returnType);
      presentableText += DescriptorRenderer.TEXT.renderFunctionParameters(functionDescriptor);

      boolean extensionFunction = functionDescriptor.getReceiverParameter() != null;
      DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
      if (containingDeclaration != null && extensionFunction) {
        tailText +=
            " for "
                + DescriptorRenderer.TEXT.renderType(
                    functionDescriptor.getReceiverParameter().getType());
        tailText += " in " + DescriptorUtils.getFQName(containingDeclaration);
      }
    } else if (descriptor instanceof VariableDescriptor) {
      JetType outType = ((VariableDescriptor) descriptor).getType();
      typeText = DescriptorRenderer.TEXT.renderType(outType);
    } else if (descriptor instanceof ClassDescriptor) {
      DeclarationDescriptor declaredIn = descriptor.getContainingDeclaration();
      assert declaredIn != null;
      tailText = " (" + DescriptorUtils.getFQName(declaredIn) + ")";
      tailTextGrayed = true;
    } else {
      typeText = DescriptorRenderer.TEXT.render(descriptor);
    }

    element = element.withInsertHandler(getInsertHandler(descriptor));
    element =
        element
            .withTailText(tailText, tailTextGrayed)
            .withTypeText(typeText)
            .withPresentableText(presentableText);
    element =
        element.withIcon(
            JetDescriptorIconProvider.getIcon(descriptor, Iconable.ICON_FLAG_VISIBILITY));
    element = element.withStrikeoutness(KotlinBuiltIns.getInstance().isDeprecated(descriptor));
    return element;
  }