public String calcGenerics(@NotNull PsiElement context, InsertionContext insertionContext) {
    if (insertionContext.getCompletionChar() == '<') {
      return "";
    }

    assert context.isValid();
    if (myDiamond) {
      return "<>";
    }

    if (getObject() instanceof PsiClass) {
      PsiClass psiClass = (PsiClass) getObject();
      PsiResolveHelper resolveHelper =
          JavaPsiFacade.getInstance(psiClass.getProject()).getResolveHelper();
      PsiSubstitutor substitutor = getSubstitutor();
      StringBuilder builder = new StringBuilder();
      for (PsiTypeParameter parameter : psiClass.getTypeParameters()) {
        PsiType substitute = substitutor.substitute(parameter);
        if (substitute == null
            || (PsiUtil.resolveClassInType(substitute) == parameter
                && resolveHelper.resolveReferencedClass(parameter.getName(), context)
                    != CompletionUtil.getOriginalOrSelf(parameter))) {
          return "";
        }
        if (builder.length() > 0) {
          builder.append(", ");
        }
        builder.append(substitute.getCanonicalText());
      }
      if (builder.length() > 0) {
        return "<" + builder + ">";
      }
    }
    return "";
  }
 private static boolean isInitializedImplicitly(PsiField field) {
   field = CompletionUtil.getOriginalOrSelf(field);
   for (ImplicitUsageProvider provider : ImplicitUsageProvider.EP_NAME.getExtensions()) {
     if (provider.isImplicitWrite(field)) {
       return true;
     }
   }
   return false;
 }
 private void calculateToLift(LookupElement element) {
   for (String string : CompletionUtil.iterateLookupStrings(element)) {
     for (int len = 1; len < string.length(); len++) {
       String prefix = string.substring(0, len);
       for (LookupElement shorterElement : myElements.get(prefix)) {
         if (myCondition.shouldLift(shorterElement, element)) {
           myToLift.putValue(element, shorterElement);
           myReversedToLift.putValue(shorterElement, element);
         }
       }
     }
   }
 }
  @Override
  public void removeElement(@NotNull LookupElement element, @NotNull ProcessingContext context) {
    for (String s : CompletionUtil.iterateLookupStrings(element)) {
      myElements.remove(s, element);
      if (myElements.get(s).isEmpty()) {
        mySortedStrings.remove(s);
      }
    }

    removeFromMap(element, myToLift, myReversedToLift);
    removeFromMap(element, myReversedToLift, myToLift);

    super.removeElement(element, context);
  }
  private static void init(final AbstractFileType abstractFileType) {
    SyntaxTable table = abstractFileType.getSyntaxTable();
    CompletionUtil.registerCompletionData(abstractFileType, new SyntaxTableCompletionData(table));

    if (!isEmpty(table.getStartComment()) && !isEmpty(table.getEndComment())
        || !isEmpty(table.getLineComment())) {
      abstractFileType.setCommenter(new MyCommenter(abstractFileType));
    }

    if (table.isHasBraces() || table.isHasBrackets() || table.isHasParens()) {
      BraceMatchingUtil.registerBraceMatcher(abstractFileType, new CustomFileTypeBraceMatcher());
    }

    TypedHandler.registerQuoteHandler(abstractFileType, new CustomFileTypeQuoteHandler());
  }
  private boolean shouldQualify(PsiField field, InsertionContext context) {
    if (myHelper != null && !myHelper.willBeImported()) {
      return true;
    }

    if (getAttribute(FORCE_QUALIFY) != null) {
      return true;
    }

    PsiReference reference = context.getFile().findReferenceAt(context.getStartOffset());
    if (reference instanceof PsiReferenceExpression
        && !((PsiReferenceExpression) reference).isQualified()) {
      final PsiVariable target =
          JavaPsiFacade.getInstance(context.getProject())
              .getResolveHelper()
              .resolveReferencedVariable(field.getName(), (PsiElement) reference);
      return !field
          .getManager()
          .areElementsEquivalent(target, CompletionUtil.getOriginalOrSelf(field));
    }
    return false;
  }
  @Override
  public void addElement(@NotNull LookupElement added, @NotNull ProcessingContext context) {
    myCount++;

    for (String string : CompletionUtil.iterateLookupStrings(added)) {
      if (string.length() == 0) continue;

      myElements.putValue(string, added);
      mySortedStrings.add(string);
      final NavigableSet<String> after = mySortedStrings.tailSet(string, false);
      for (String s : after) {
        if (!s.startsWith(string)) {
          break;
        }
        for (LookupElement longer : myElements.get(s)) {
          updateLongerItem(added, longer);
        }
      }
    }
    super.addElement(added, context);

    calculateToLift(added);
  }
  @NotNull
  public Object[] getVariants() {
    final ArrayList<Object> ret = Lists.newArrayList(super.getVariants());
    PsiFile file = myElement.getContainingFile();
    final InjectedLanguageManager languageManager =
        InjectedLanguageManager.getInstance(myElement.getProject());
    final PsiLanguageInjectionHost host = languageManager.getInjectionHost(myElement);
    if (host != null) file = host.getContainingFile();

    final PsiElement originalElement = CompletionUtil.getOriginalElement(myElement);
    final PyQualifiedExpression element =
        originalElement instanceof PyQualifiedExpression
            ? (PyQualifiedExpression) originalElement
            : myElement;

    // include our own names
    final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(element);
    if (file instanceof ScopeOwner)
      PyResolveUtil.scopeCrawlUp(processor, (ScopeOwner) file, null, null);

    ret.addAll(processor.getResultList());

    return ret.toArray();
  }