@Override
  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
    if (!super.isAvailable(project, editor, file) || !(file instanceof JetFile)) {
      return false;
    }

    // When running single test 'isAvailable()' is invoked multiple times, so we need to clear
    // lists.
    overriddenNonOverridableMembers.clear();
    containingDeclarationsNames.clear();

    DeclarationDescriptor descriptor = ResolvePackage.resolveToDescriptor(element);
    if (!(descriptor instanceof CallableMemberDescriptor)) return false;

    for (CallableMemberDescriptor overriddenDescriptor :
        getAllDeclaredNonOverridableOverriddenDescriptors((CallableMemberDescriptor) descriptor)) {
      assert overriddenDescriptor.getKind() == DECLARATION : "Can only be applied to declarations.";
      PsiElement overriddenMember = descriptorToDeclaration(overriddenDescriptor);
      if (overriddenMember == null
          || !QuickFixUtil.canModifyElement(overriddenMember)
          || !(overriddenMember instanceof JetCallableDeclaration)) {
        return false;
      }
      String containingDeclarationName =
          overriddenDescriptor.getContainingDeclaration().getName().asString();
      overriddenNonOverridableMembers.add((JetCallableDeclaration) overriddenMember);
      containingDeclarationsNames.add(containingDeclarationName);
    }
    return overriddenNonOverridableMembers.size() > 0;
  }
  @Nullable
  public final FunctionDescriptor getCurrentFunctionDescriptor() {
    if (currentFunctionDescriptor == null) {
      PsiElement element = getDeclaration();

      if (element instanceof JetFunction) {
        currentFunctionDescriptor =
            (FunctionDescriptor) ResolvePackage.resolveToDescriptor((JetFunction) element);
      } else if (element instanceof JetClass) {
        currentFunctionDescriptor =
            ((ClassDescriptor) ResolvePackage.resolveToDescriptor((JetClass) element))
                .getUnsubstitutedPrimaryConstructor();
      } else if (element instanceof PsiMethod) {
        currentFunctionDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) element);
      }
    }
    return currentFunctionDescriptor;
  }
  private static boolean checkIfHasExpectedType(
      @NotNull FunctionDescriptor functionDescriptor, boolean isInherited) {
    if (!(functionDescriptor instanceof AnonymousFunctionDescriptor && isInherited)) return false;

    JetFunctionLiteral functionLiteral =
        (JetFunctionLiteral) DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
    assert functionLiteral != null : "No declaration found for " + functionDescriptor;

    PsiElement parent = functionLiteral.getParent();
    if (!(parent instanceof JetFunctionLiteralExpression)) return false;

    JetFunctionLiteralExpression expression = (JetFunctionLiteralExpression) parent;
    return ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL)
            .get(BindingContext.EXPECTED_EXPRESSION_TYPE, expression)
        != null;
  }
  private static List<FunctionDescriptor> generateFunctionsToAdd(JetNamedFunction functionElement) {
    FunctionDescriptor functionDescriptor =
        (FunctionDescriptor) ResolvePackage.resolveToDescriptor(functionElement);

    DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
    if (!(containingDeclaration instanceof ClassDescriptor)) return Collections.emptyList();

    List<FunctionDescriptor> functions = Lists.newArrayList();
    ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
    // TODO: filter out impossible supertypes (for example when argument's type isn't visible in a
    // superclass).
    for (ClassDescriptor supertypeDescriptor : getSupertypes(classDescriptor)) {
      if (KotlinBuiltIns.isAnyOrNullableAny(supertypeDescriptor.getDefaultType())) continue;
      functions.add(generateFunctionSignatureForType(functionDescriptor, supertypeDescriptor));
    }
    return functions;
  }
  private static JetValueArgumentList findCall(CreateParameterInfoContext context) {
    // todo: calls to this constructors, when we will have auxiliary constructors
    PsiFile file = context.getFile();
    if (!(file instanceof JetFile)) {
      return null;
    }

    JetValueArgumentList argumentList =
        PsiTreeUtil.getParentOfType(
            file.findElementAt(context.getOffset()), JetValueArgumentList.class);
    if (argumentList == null) {
      return null;
    }

    final JetSimpleNameExpression callNameExpression = getCallSimpleNameExpression(argumentList);
    if (callNameExpression == null) {
      return null;
    }

    PsiReference[] references = callNameExpression.getReferences();
    if (references.length == 0) {
      return null;
    }

    ResolutionFacade resolutionFacade =
        ResolvePackage.getResolutionFacade(callNameExpression.getContainingJetFile());
    final BindingContext bindingContext =
        resolutionFacade.analyze(callNameExpression, BodyResolveMode.FULL);
    ModuleDescriptor moduleDescriptor = resolutionFacade.findModuleDescriptor(callNameExpression);

    JetScope scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, callNameExpression);
    final DeclarationDescriptor placeDescriptor;
    if (scope != null) {
      placeDescriptor = scope.getContainingDeclaration();
    } else {
      placeDescriptor = null;
    }
    Function1<DeclarationDescriptor, Boolean> visibilityFilter =
        new Function1<DeclarationDescriptor, Boolean>() {
          @Override
          public Boolean invoke(DeclarationDescriptor descriptor) {
            if (placeDescriptor == null) return true;
            if (!(descriptor instanceof DeclarationDescriptorWithVisibility)) return true;
            return CorePackage.isVisible(
                (DeclarationDescriptorWithVisibility) descriptor,
                placeDescriptor,
                bindingContext,
                callNameExpression);
          }
        };

    final Name refName = callNameExpression.getReferencedNameAsName();

    Function1<Name, Boolean> nameFilter =
        new Function1<Name, Boolean>() {
          @Override
          public Boolean invoke(Name name) {
            return name.equals(refName);
          }
        };
    Collection<DeclarationDescriptor> variants =
        new ReferenceVariantsHelper(
                bindingContext, moduleDescriptor, file.getProject(), visibilityFilter)
            .getReferenceVariants(
                callNameExpression,
                new DescriptorKindFilter(
                    DescriptorKindFilter.FUNCTIONS_MASK | DescriptorKindFilter.CLASSIFIERS_MASK,
                    Collections.<DescriptorKindExclude>emptyList()),
                nameFilter,
                false,
                false);

    Collection<Pair<? extends DeclarationDescriptor, ResolutionFacade>> itemsToShow =
        new ArrayList<Pair<? extends DeclarationDescriptor, ResolutionFacade>>();
    for (DeclarationDescriptor variant : variants) {
      if (variant instanceof FunctionDescriptor) {
        // todo: renamed functions?
        itemsToShow.add(Pair.create((FunctionDescriptor) variant, resolutionFacade));
      } else if (variant instanceof ClassDescriptor) {
        // todo: renamed classes?
        for (ConstructorDescriptor constructorDescriptor :
            ((ClassDescriptor) variant).getConstructors()) {
          itemsToShow.add(Pair.create(constructorDescriptor, resolutionFacade));
        }
      }
    }

    context.setItemsToShow(ArrayUtil.toObjectArray(itemsToShow));
    return argumentList;
  }