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; }