public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
    if (isReferenceTo(element)) return getElement();

    final String newName;
    if (element instanceof PsiClass) {
      PsiClass psiClass = (PsiClass) element;
      final boolean jvmFormat =
          Boolean.TRUE.equals(JavaClassReferenceProvider.JVM_FORMAT.getValue(getOptions()));
      newName = jvmFormat ? ClassUtil.getJVMClassName(psiClass) : psiClass.getQualifiedName();
    } else if (element instanceof PsiPackage) {
      PsiPackage psiPackage = (PsiPackage) element;
      newName = psiPackage.getQualifiedName();
    } else {
      throw new IncorrectOperationException("Cannot bind to " + element);
    }
    assert newName != null;

    TextRange range =
        new TextRange(
            myJavaClassReferenceSet.getReference(0).getRangeInElement().getStartOffset(),
            getRangeInElement().getEndOffset());
    final ElementManipulator<PsiElement> manipulator = getManipulator(getElement());
    if (manipulator != null) {
      final PsiElement finalElement = manipulator.handleContentChange(getElement(), range, newName);
      range = new TextRange(range.getStartOffset(), range.getStartOffset() + newName.length());
      myJavaClassReferenceSet.reparse(finalElement, range);
      return finalElement;
    }
    return element;
  }
 public JavaClassReference[] getAllReferences() {
   JavaClassReference[] result = myReferences;
   if (myNestedGenericParameterReferences != null) {
     for (JavaClassReferenceSet set : myNestedGenericParameterReferences) {
       result = ArrayUtil.mergeArrays(result, set.getAllReferences(), JavaClassReference.class);
     }
   }
   return result;
 }
 @Override
 public void duringCompletion(@NotNull CompletionInitializationContext context) {
   JavaClassReference reference =
       findJavaClassReference(context.getFile(), context.getStartOffset());
   if (reference != null && reference.getExtendClassNames() != null) {
     JavaClassReferenceSet set = reference.getJavaClassReferenceSet();
     context.setReplacementOffset(
         set.getRangeInElement().getEndOffset()
             + set.getElement().getTextRange().getStartOffset());
   }
 }
 public JavaClassReference(
     final JavaClassReferenceSet referenceSet,
     TextRange range,
     int index,
     String text,
     final boolean staticImport) {
   super(referenceSet.getProvider());
   myInStaticImport = staticImport;
   LOG.assertTrue(range.getEndOffset() <= referenceSet.getElement().getTextLength());
   myIndex = index;
   myRange = range;
   myText = text;
   myJavaClassReferenceSet = referenceSet;
 }
 private boolean isStaticClassReference(final String s, boolean strict) {
   if (myIndex == 0) {
     return false;
   }
   char c = s.charAt(getRangeInElement().getStartOffset() - 1);
   return myJavaClassReferenceSet.isStaticSeparator(c, strict);
 }
  @Override
  public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
    PsiElement position = parameters.getPosition();
    JavaClassReference reference =
        findJavaClassReference(position.getContainingFile(), parameters.getOffset());
    if (reference == null) {
      return;
    }

    String[] extendClassNames = reference.getExtendClassNames();
    PsiElement context = reference.getCompletionContext();
    if (extendClassNames != null && context instanceof PsiJavaPackage) {
      if (parameters.getCompletionType() == CompletionType.SMART) {
        JavaClassReferenceSet set = reference.getJavaClassReferenceSet();
        int setStart =
            set.getRangeInElement().getStartOffset()
                + set.getElement().getTextRange().getStartOffset();
        String fullPrefix =
            parameters
                .getPosition()
                .getContainingFile()
                .getText()
                .substring(setStart, parameters.getOffset());
        reference.processSubclassVariants(
            (PsiJavaPackage) context, extendClassNames, result.withPrefixMatcher(fullPrefix));
        return;
      }
      result.addLookupAdvertisement(
          "Press "
              + getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION)
              + " to see inheritors of "
              + StringUtil.join(extendClassNames, ", "));
    }

    if (parameters.getCompletionType() == CompletionType.SMART) {
      return;
    }

    if (parameters.isExtendedCompletion()
        || parameters.getCompletionType() == CompletionType.CLASS_NAME) {
      JavaClassNameCompletionContributor.addAllClasses(parameters, result);
    } else {
      LegacyCompletionContributor.completeReference(parameters, result);
    }
    result.stopHere();
  }
  private JavaResolveResult advancedResolveInner(final PsiElement psiElement, final String qName) {
    final PsiManager manager = psiElement.getManager();
    final GlobalSearchScope scope = getScope();
    if (myIndex == myJavaClassReferenceSet.getReferences().length - 1) {
      final PsiClass aClass =
          JavaPsiFacade.getInstance(manager.getProject()).findClass(qName, scope);
      if (aClass != null) {
        return new ClassCandidateInfo(aClass, PsiSubstitutor.EMPTY, false, psiElement);
      } else {
        if (!JavaClassReferenceProvider.ADVANCED_RESOLVE.getBooleanValue(getOptions())) {
          return JavaResolveResult.EMPTY;
        }
      }
    }
    PsiElement resolveResult = JavaPsiFacade.getInstance(manager.getProject()).findPackage(qName);
    if (resolveResult == null) {
      resolveResult = JavaPsiFacade.getInstance(manager.getProject()).findClass(qName, scope);
    }
    if (myInStaticImport && resolveResult == null) {
      resolveResult = resolveMember(qName, manager, getElement().getResolveScope());
    }
    if (resolveResult == null) {
      PsiFile containingFile = psiElement.getContainingFile();

      if (containingFile instanceof PsiJavaFile) {
        if (containingFile instanceof JspFile) {
          containingFile = containingFile.getViewProvider().getPsi(StdLanguages.JAVA);
          if (containingFile == null) return JavaResolveResult.EMPTY;
        }

        final ClassResolverProcessor processor =
            new ClassResolverProcessor(getCanonicalText(), psiElement);
        containingFile.processDeclarations(processor, ResolveState.initial(), null, psiElement);

        if (processor.getResult().length == 1) {
          final JavaResolveResult javaResolveResult = processor.getResult()[0];

          if (javaResolveResult != JavaResolveResult.EMPTY && getOptions() != null) {
            final Boolean value =
                JavaClassReferenceProvider.RESOLVE_QUALIFIED_CLASS_NAME.getValue(getOptions());
            final PsiClass psiClass = (PsiClass) javaResolveResult.getElement();
            if (value != null && value.booleanValue() && psiClass != null) {
              final String qualifiedName = psiClass.getQualifiedName();

              if (!qName.equals(qualifiedName)) {
                return JavaResolveResult.EMPTY;
              }
            }
          }

          return javaResolveResult;
        }
      }
    }
    return resolveResult != null
        ? new CandidateInfo(resolveResult, PsiSubstitutor.EMPTY, false, false, psiElement)
        : JavaResolveResult.EMPTY;
  }
 private GlobalSearchScope getScope() {
   final GlobalSearchScope scope = myJavaClassReferenceSet.getProvider().getScope();
   if (scope == null) {
     final Module module = ModuleUtil.findModuleForPsiElement(getElement());
     if (module != null) {
       return module.getModuleWithDependenciesAndLibrariesScope(true);
     }
     return GlobalSearchScope.allScope(getElement().getProject());
   }
   return scope;
 }
  private JavaResolveResult doAdvancedResolve() {
    final PsiElement psiElement = getElement();

    if (!psiElement.isValid()) return JavaResolveResult.EMPTY;

    final String elementText = psiElement.getText();

    final PsiElement context = getContext();
    if (context instanceof PsiClass) {
      if (isStaticClassReference(elementText, false)) {
        final PsiClass psiClass =
            ((PsiClass) context).findInnerClassByName(getCanonicalText(), false);
        if (psiClass != null)
          return new ClassCandidateInfo(psiClass, PsiSubstitutor.EMPTY, false, psiElement);
        PsiElement member = doResolveMember((PsiClass) context, myText);
        return member == null
            ? JavaResolveResult.EMPTY
            : new CandidateInfo(member, PsiSubstitutor.EMPTY, false, false, psiElement);
      } else if (!myInStaticImport && myJavaClassReferenceSet.isAllowDollarInNames()) {
        return JavaResolveResult.EMPTY;
      }
    }

    final int endOffset = getRangeInElement().getEndOffset();
    LOG.assertTrue(endOffset <= elementText.length(), elementText);
    final int startOffset =
        myJavaClassReferenceSet.getReference(0).getRangeInElement().getStartOffset();
    final String qName = elementText.substring(startOffset, endOffset);
    if (!qName.contains(".")) {
      final String defaultPackage =
          JavaClassReferenceProvider.DEFAULT_PACKAGE.getValue(getOptions());
      if (StringUtil.isNotEmpty(defaultPackage)) {
        final JavaResolveResult resolveResult =
            advancedResolveInner(psiElement, defaultPackage + "." + qName);
        if (resolveResult != JavaResolveResult.EMPTY) {
          return resolveResult;
        }
      }
    }
    return advancedResolveInner(psiElement, qName);
  }
  @NotNull
  private Object[] getSubclassVariants(
      @NotNull PsiPackage context, @NotNull String[] extendClasses) {
    HashSet<Object> lookups = new HashSet<Object>();
    GlobalSearchScope packageScope = PackageScope.packageScope(context, true);
    GlobalSearchScope scope = myJavaClassReferenceSet.getProvider().getScope();
    if (scope != null) {
      packageScope = packageScope.intersectWith(scope);
    }
    final GlobalSearchScope allScope = ProjectScope.getAllScope(context.getProject());
    final boolean instantiatable =
        JavaClassReferenceProvider.INSTANTIATABLE.getBooleanValue(getOptions());
    final boolean notInterface =
        JavaClassReferenceProvider.NOT_INTERFACE.getBooleanValue(getOptions());
    final boolean notEnum = JavaClassReferenceProvider.NOT_ENUM.getBooleanValue(getOptions());
    final boolean concrete = JavaClassReferenceProvider.CONCRETE.getBooleanValue(getOptions());

    final ClassKind classKind = getClassKind();

    for (String extendClassName : extendClasses) {
      final PsiClass extendClass =
          JavaPsiFacade.getInstance(context.getProject()).findClass(extendClassName, allScope);
      if (extendClass != null) {
        // add itself
        if (packageScope.contains(extendClass.getContainingFile().getVirtualFile())) {
          if (isClassAccepted(
              extendClass, classKind, instantiatable, concrete, notInterface, notEnum)) {
            ContainerUtil.addIfNotNull(createSubclassLookupValue(context, extendClass), lookups);
          }
        }
        for (final PsiClass clazz : ClassInheritorsSearch.search(extendClass, packageScope, true)) {
          if (isClassAccepted(clazz, classKind, instantiatable, concrete, notInterface, notEnum)) {
            ContainerUtil.addIfNotNull(createSubclassLookupValue(context, clazz), lookups);
          }
        }
      }
    }
    return lookups.toArray();
  }
 private boolean canReferencePackage() {
   return myJavaClassReferenceSet.canReferencePackage(myIndex);
 }
  private void reparse(
      String str, PsiElement element, final boolean isStaticImport, JavaClassReferenceSet context) {
    myElement = element;
    myContext = context;
    final List<JavaClassReference> referencesList = new ArrayList<JavaClassReference>();
    int currentDot = -1;
    int referenceIndex = 0;
    boolean allowDollarInNames = isAllowDollarInNames();
    boolean allowGenerics = false;
    boolean allowGenericsCalculated = false;
    boolean parsingClassNames = true;

    while (parsingClassNames) {
      int nextDotOrDollar = -1;
      for (int curIndex = currentDot + 1; curIndex < str.length(); ++curIndex) {
        final char ch = str.charAt(curIndex);

        if (ch == SEPARATOR || (ch == SEPARATOR2 && allowDollarInNames)) {
          nextDotOrDollar = curIndex;
          break;
        }

        if (((ch == SEPARATOR3 || ch == SEPARATOR4))) {
          if (!allowGenericsCalculated) {
            allowGenerics =
                !isStaticImport && PsiUtil.getLanguageLevel(element).hasEnumKeywordAndAutoboxing();
            allowGenericsCalculated = true;
          }

          if (allowGenerics) {
            nextDotOrDollar = curIndex;
            break;
          }
        }
      }

      if (nextDotOrDollar == -1) {
        nextDotOrDollar = currentDot + 1;
        for (int i = nextDotOrDollar;
            i < str.length() && Character.isJavaIdentifierPart(str.charAt(i));
            ++i) nextDotOrDollar++;
        parsingClassNames = false;
        int j = nextDotOrDollar;
        while (j < str.length() && Character.isWhitespace(str.charAt(j))) ++j;

        if (j < str.length()) {
          char ch = str.charAt(j);
          boolean recognized = false;

          if (ch == '[') {
            j++;
            while (j < str.length() && Character.isWhitespace(str.charAt(j))) ++j;

            if (j < str.length()) {
              ch = str.charAt(j);

              if (ch == ']') {
                j++;
                while (j < str.length() && Character.isWhitespace(str.charAt(j))) ++j;

                recognized = j == str.length();
              }
            }
          }

          final Boolean aBoolean = JavaClassReferenceProvider.JVM_FORMAT.getValue(getOptions());
          if (aBoolean == null || !aBoolean.booleanValue()) {
            if (!recognized)
              nextDotOrDollar = -1; // nonsensible characters anyway, don't do resolve
          }
        }
      }

      if (nextDotOrDollar != -1 && nextDotOrDollar < str.length()) {
        final char c = str.charAt(nextDotOrDollar);
        if (c == SEPARATOR3) {
          int end = str.lastIndexOf('>');
          if (end != -1 && end > nextDotOrDollar) {
            if (myNestedGenericParameterReferences == null)
              myNestedGenericParameterReferences = new ArrayList<JavaClassReferenceSet>(1);
            myNestedGenericParameterReferences.add(
                new JavaClassReferenceSet(
                    str.substring(nextDotOrDollar + 1, end),
                    myElement,
                    myStartInElement + nextDotOrDollar + 1,
                    isStaticImport,
                    myProvider,
                    this));
            parsingClassNames = false;
          } else {
            nextDotOrDollar = -1; // nonsensible characters anyway, don't do resolve
          }
        } else if (SEPARATOR4 == c && myContext != null) {
          if (myContext.myNestedGenericParameterReferences == null)
            myContext.myNestedGenericParameterReferences = new ArrayList<JavaClassReferenceSet>(1);
          myContext.myNestedGenericParameterReferences.add(
              new JavaClassReferenceSet(
                  str.substring(nextDotOrDollar + 1),
                  myElement,
                  myStartInElement + nextDotOrDollar + 1,
                  isStaticImport,
                  myProvider,
                  this));
          parsingClassNames = false;
        }
      }

      int beginIndex = currentDot + 1;
      while (beginIndex < nextDotOrDollar && Character.isWhitespace(str.charAt(beginIndex)))
        beginIndex++;

      final String subreferenceText =
          nextDotOrDollar > 0
              ? str.substring(beginIndex, nextDotOrDollar)
              : str.substring(beginIndex);

      TextRange textRange =
          new TextRange(
              myStartInElement + beginIndex,
              myStartInElement + (nextDotOrDollar > 0 ? nextDotOrDollar : str.length()));
      JavaClassReference currentContextRef =
          createReference(referenceIndex, subreferenceText, textRange, isStaticImport);
      referenceIndex++;
      referencesList.add(currentContextRef);
      if ((currentDot = nextDotOrDollar) < 0) {
        break;
      }
    }

    myReferences = referencesList.toArray(new JavaClassReference[referencesList.size()]);
  }
 public PsiElement getElement() {
   return myJavaClassReferenceSet.getElement();
 }
 public boolean isSoft() {
   return myJavaClassReferenceSet.isSoft();
 }
 public String getUnresolvedMessagePattern() {
   return myJavaClassReferenceSet.getUnresolvedMessagePattern(myIndex);
 }
 @Nullable
 private Map<CustomizableReferenceProvider.CustomizationKey, Object> getOptions() {
   return myJavaClassReferenceSet.getOptions();
 }
 @Nullable
 public PsiReference getContextReference() {
   return myIndex > 0 ? myJavaClassReferenceSet.getReference(myIndex - 1) : null;
 }