@Override
  public Object[] getFileReferenceCompletionVariants(final FileReference reference) {
    final String s = reference.getText();
    if (s != null && s.equals("/")) {
      return ArrayUtil.EMPTY_OBJECT_ARRAY;
    }

    final CommonProcessors.CollectUniquesProcessor<PsiFileSystemItem> collector =
        new CommonProcessors.CollectUniquesProcessor<PsiFileSystemItem>();
    final PsiElementProcessor<PsiFileSystemItem> processor =
        new PsiElementProcessor<PsiFileSystemItem>() {
          @Override
          public boolean execute(@NotNull PsiFileSystemItem fileSystemItem) {
            return new FilteringProcessor<PsiFileSystemItem>(
                    reference.getFileReferenceSet().getReferenceCompletionFilter(), collector)
                .process(FileReference.getOriginalFile(fileSystemItem));
          }
        };

    List<Object> additionalItems = ContainerUtil.newArrayList();
    for (PsiFileSystemItem context : reference.getContexts()) {
      for (final PsiElement child : context.getChildren()) {
        if (child instanceof PsiFileSystemItem) {
          processor.execute((PsiFileSystemItem) child);
        }
      }
      if (context instanceof FileReferenceResolver) {
        additionalItems.addAll(((FileReferenceResolver) context).getVariants(reference));
      }
    }

    final FileType[] types = reference.getFileReferenceSet().getSuitableFileTypes();
    final THashSet<PsiElement> set =
        new THashSet<PsiElement>(collector.getResults(), VARIANTS_HASHING_STRATEGY);
    final PsiElement[] candidates = PsiUtilCore.toPsiElementArray(set);

    final Object[] variants = new Object[candidates.length + additionalItems.size()];
    for (int i = 0; i < candidates.length; i++) {
      PsiElement candidate = candidates[i];
      Object item = reference.createLookupItem(candidate);
      if (item == null) {
        item = FileInfoManager.getFileLookupItem(candidate);
      }
      if (candidate instanceof PsiFile
          && item instanceof LookupElement
          && types.length > 0
          && ArrayUtil.contains(((PsiFile) candidate).getFileType(), types)) {
        item = PrioritizedLookupElement.withPriority((LookupElement) item, Double.MAX_VALUE);
      }
      variants[i] = item;
    }

    for (int i = 0; i < additionalItems.size(); i++) {
      variants[i + candidates.length] = additionalItems.get(i);
    }
    if (!reference.getFileReferenceSet().isUrlEncoded()) {
      return variants;
    }
    List<Object> encodedVariants = new ArrayList<Object>(variants.length + additionalItems.size());
    for (int i = 0; i < candidates.length; i++) {
      final PsiElement element = candidates[i];
      if (element instanceof PsiNamedElement) {
        final PsiNamedElement psiElement = (PsiNamedElement) element;
        String name = psiElement.getName();
        final String encoded = reference.encode(name, psiElement);
        if (encoded == null) continue;
        if (!encoded.equals(name)) {
          final Icon icon =
              psiElement.getIcon(Iconable.ICON_FLAG_READ_STATUS | Iconable.ICON_FLAG_VISIBILITY);
          LookupElementBuilder item =
              FileInfoManager.getFileLookupItem(candidates[i], encoded, icon);
          encodedVariants.add(item.withTailText(" (" + name + ")"));
        } else {
          encodedVariants.add(variants[i]);
        }
      }
    }
    encodedVariants.addAll(additionalItems);
    return ArrayUtil.toObjectArray(encodedVariants);
  }
  @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;
  }
  private static void completeAnnotationAttributeName(
      CompletionResultSet result, PsiElement insertedElement, CompletionParameters parameters) {
    PsiNameValuePair pair = PsiTreeUtil.getParentOfType(insertedElement, PsiNameValuePair.class);
    PsiAnnotationParameterList parameterList = (PsiAnnotationParameterList) pair.getParent();
    PsiAnnotation anno = (PsiAnnotation) parameterList.getParent();
    boolean showClasses = psiElement().afterLeaf("(").accepts(insertedElement);
    PsiClass annoClass = null;
    final PsiJavaCodeReferenceElement referenceElement = anno.getNameReferenceElement();
    if (referenceElement != null) {
      final PsiElement element = referenceElement.resolve();
      if (element instanceof PsiClass) {
        annoClass = (PsiClass) element;
        if (annoClass.findMethodsByName("value", false).length == 0) {
          showClasses = false;
        }
      }
    }

    if (showClasses && insertedElement.getParent() instanceof PsiReferenceExpression) {
      final Set<LookupElement> set =
          JavaCompletionUtil.processJavaReference(
              insertedElement,
              (PsiJavaReference) insertedElement.getParent(),
              new ElementExtractorFilter(createAnnotationFilter(insertedElement)),
              JavaCompletionProcessor.Options.DEFAULT_OPTIONS,
              result.getPrefixMatcher(),
              parameters);
      for (final LookupElement element : set) {
        result.addElement(element);
      }
      addAllClasses(parameters, result, new InheritorsHolder(insertedElement, result));
    }

    if (annoClass != null) {
      final PsiNameValuePair[] existingPairs = parameterList.getAttributes();

      methods:
      for (PsiMethod method : annoClass.getMethods()) {
        if (!(method instanceof PsiAnnotationMethod)) continue;

        final String attrName = method.getName();
        for (PsiNameValuePair existingAttr : existingPairs) {
          if (PsiTreeUtil.isAncestor(existingAttr, insertedElement, false)) break;
          if (Comparing.equal(existingAttr.getName(), attrName)
              || PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(attrName)
                  && existingAttr.getName() == null) continue methods;
        }
        LookupElementBuilder element =
            LookupElementBuilder.createWithIcon(method)
                .withInsertHandler(
                    new InsertHandler<LookupElement>() {
                      @Override
                      public void handleInsert(InsertionContext context, LookupElement item) {
                        final Editor editor = context.getEditor();
                        TailType.EQ.processTail(editor, editor.getCaretModel().getOffset());
                        context.setAddCompletionChar(false);

                        context.commitDocument();
                        PsiAnnotationParameterList paramList =
                            PsiTreeUtil.findElementOfClassAtOffset(
                                context.getFile(),
                                context.getStartOffset(),
                                PsiAnnotationParameterList.class,
                                false);
                        if (paramList != null
                            && paramList.getAttributes().length > 0
                            && paramList.getAttributes()[0].getName() == null) {
                          int valueOffset =
                              paramList.getAttributes()[0].getTextRange().getStartOffset();
                          context
                              .getDocument()
                              .insertString(
                                  valueOffset, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME);
                          TailType.EQ.processTail(
                              editor,
                              valueOffset + PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.length());
                        }
                      }
                    });

        PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod) method).getDefaultValue();
        if (defaultValue != null) {
          Object constant =
              JavaPsiFacade.getInstance(method.getProject())
                  .getConstantEvaluationHelper()
                  .computeConstantExpression(defaultValue);
          if (constant != null) {
            element =
                element.withTailText(
                    " default " + (constant instanceof String ? "\"" + constant + "\"" : constant),
                    true);
          }
        }

        result.addElement(element);
      }
    }
  }