@Nullable public static PsiFile resolveFile(XmlAttribute location, PsiFile baseFile) { if (location == null) return null; final XmlAttributeValue valueElement = location.getValueElement(); if (valueElement == null) return null; // prefer direct relative path final String value = valueElement.getValue(); final PsiFile file = resolveFile(value, baseFile); if (file != baseFile && file instanceof XmlFile) { return file; } final PsiReference[] references = valueElement.getReferences(); for (PsiReference reference : references) { final PsiElement target = reference.resolve(); if (target == null && reference instanceof PsiPolyVariantReference) { final ResolveResult[] results = ((PsiPolyVariantReference) reference).multiResolve(false); for (ResolveResult result : results) { if (result.isValidResult()) { // TODO: how to weigh/prioritize the results? final PsiElement element = result.getElement(); if (element != baseFile && element instanceof XmlFile) { return (PsiFile) target; } } } } else if (target != baseFile && target instanceof XmlFile) { return (PsiFile) target; } } return null; }
private Collection<JSQualifiedNamedElement> getCandidates(Editor editor, PsiFile file) { final Collection<JSQualifiedNamedElement> candidates; if (myReference instanceof JSReferenceExpression && ((JSReferenceExpression) myReference).getQualifier() == null) { Collection<JSQualifiedNamedElement> c = getCandidates(editor, file, myReference.getCanonicalText()); filterCandidates(c); candidates = new THashSet<>(c, JSPsiImplUtils.QUALIFIED_NAME_HASHING_STRATEGY); } else { JSQualifiedNamedElement invalidResult = null; for (ResolveResult r : myReference.multiResolve(false)) { PsiElement element = r.getElement(); if (element instanceof JSQualifiedNamedElement) { invalidResult = (JSQualifiedNamedElement) element; } } if (invalidResult != null) { if (myReference.getElement().getParent() instanceof JSNewExpression && invalidResult instanceof JSFunction && ((JSFunction) invalidResult).isConstructor()) { invalidResult = (JSClass) invalidResult.getParent(); } candidates = new SmartList<>(); candidates.add(invalidResult); } else { candidates = Collections.emptyList(); } } return candidates; }
@NotNull private Set<PsiPackage> getContext() { if (myIndex == 0) return myReferenceSet.getInitialContext(); Set<PsiPackage> psiPackages = new HashSet<>(); for (ResolveResult resolveResult : myReferenceSet.getReference(myIndex - 1).doMultiResolve()) { PsiElement psiElement = resolveResult.getElement(); if (psiElement instanceof PsiPackage) { psiPackages.add((PsiPackage) psiElement); } } return psiPackages; }
@NotNull public QualifiedResolveResult followAssignmentsChain(PyResolveContext resolveContext) { PyReferenceExpression seeker = this; QualifiedResolveResult ret = null; List<PyExpression> qualifiers = new ArrayList<PyExpression>(); PyExpression qualifier = seeker.getQualifier(); if (qualifier != null) { qualifiers.add(qualifier); } Set<PsiElement> visited = new HashSet<PsiElement>(); visited.add(this); SEARCH: while (ret == null) { ResolveResult[] targets = seeker.getReference(resolveContext).multiResolve(false); for (ResolveResult target : targets) { PsiElement elt = target.getElement(); if (elt instanceof PyTargetExpression) { PsiElement assigned_from = null; final PyTargetExpression expr = (PyTargetExpression) elt; final TypeEvalContext context = resolveContext.getTypeEvalContext(); if (context.maySwitchToAST(expr) || expr.getStub() == null) { assigned_from = expr.findAssignedValue(); } // TODO: Maybe findAssignedValueByStub() should become a part of the PyTargetExpression // interface else if (elt instanceof PyTargetExpressionImpl) { assigned_from = ((PyTargetExpressionImpl) elt).findAssignedValueByStub(context); } if (assigned_from instanceof PyReferenceExpression) { if (visited.contains(assigned_from)) { break; } visited.add(assigned_from); seeker = (PyReferenceExpression) assigned_from; if (seeker.getQualifier() != null) { qualifiers.add(seeker.getQualifier()); } continue SEARCH; } else if (assigned_from != null) ret = new QualifiedResolveResultImpl(assigned_from, qualifiers, false); } else if (ret == null && elt instanceof PyElement && target.isValidResult()) { // remember this result, but a further reference may be the next resolve result ret = new QualifiedResolveResultImpl( elt, qualifiers, target instanceof ImplicitResolveResult); } } // all resolve results checked, reassignment not detected, nothing more to do break; } if (ret == null) ret = EMPTY_RESULT; return ret; }
@Deprecated public static PsiElement[] getClassInterfacePsiElements( Project project, String FQNClassOrInterfaceName) { // convert ResolveResult to PsiElement List<PsiElement> results = new ArrayList<PsiElement>(); for (ResolveResult result : getClassInterfaceResolveResult(project, FQNClassOrInterfaceName)) { results.add(result.getElement()); } return results.toArray(new PsiElement[results.size()]); }
public void testOnClickNavigation() throws Throwable { copyOnClickClasses(); final VirtualFile file = copyFileToProject(getTestName(true) + ".xml"); myFixture.configureFromExistingVirtualFile(file); final PsiReference reference = TargetElementUtil.findReference(myFixture.getEditor(), myFixture.getCaretOffset()); assertNotNull(reference); assertInstanceOf(reference, PsiPolyVariantReference.class); final ResolveResult[] results = ((PsiPolyVariantReference) reference).multiResolve(false); assertEquals(2, results.length); for (ResolveResult result : results) { assertInstanceOf(result.getElement(), PsiMethod.class); } }
public boolean isAvailable( @NotNull final Project project, final Editor editor, final PsiFile file) { if (!myReference.getElement().isValid()) return false; final long modL = myReference.getElement().getManager().getModificationTracker().getModificationCount(); if (!isAvailableCalculated || modL != modificationCount) { final ResolveResult[] results = myReference.multiResolve(false); boolean hasValidResult = false; for (ResolveResult r : results) { if (r.isValidResult()) { hasValidResult = true; break; } } if (!hasValidResult) { final Collection<JSQualifiedNamedElement> candidates = getCandidates(editor, file); isAvailableCalculated = true; isAvailable = candidates.size() > 0; String text; if (isAvailable) { final JSQualifiedNamedElement element = candidates.iterator().next(); text = element.getQualifiedName() + "?"; if (candidates.size() > 1) text += " (multiple choices...)"; if (!ApplicationManager.getApplication().isHeadlessEnvironment()) { text += " Alt+Enter"; } } else { text = ""; } myText = text; } else { isAvailableCalculated = true; isAvailable = false; myText = ""; } modificationCount = modL; } return isAvailable; }
private static List<PsiElement> resolve(final PsiReference ref) { // IDEA-56727 try resolve first as in GotoDeclarationAction PsiElement resolvedElement = ref.resolve(); if (resolvedElement == null && ref instanceof PsiPolyVariantReference) { List<PsiElement> result = new ArrayList<PsiElement>(); final ResolveResult[] psiElements = ((PsiPolyVariantReference) ref).multiResolve(false); for (ResolveResult resolveResult : psiElements) { if (resolveResult.getElement() != null) { result.add(resolveResult.getElement()); } } return result; } return resolvedElement == null ? Collections.<PsiElement>emptyList() : Collections.singletonList(resolvedElement); }
@NotNull @Override public ResolveResult[] resolve( @NotNull CSharpReferenceExpressionImpl ref, boolean incompleteCode, boolean resolveFromParent) { if (!incompleteCode) { return ref.multiResolveImpl(ref.kind(), resolveFromParent); } else { ResolveResult[] resolveResults = ref.multiResolve(false, resolveFromParent); List<ResolveResult> filter = new SmartList<ResolveResult>(); for (ResolveResult resolveResult : resolveResults) { if (resolveResult.isValidResult()) { filter.add(resolveResult); } } return ContainerUtil.toArray(filter, ResolveResult.EMPTY_ARRAY); } }
/** * Returns number of different parameters in i18n message. For example, for string <i>Class {0} * info: Class {0} extends class {1} and implements interface {2}</i> number of parameters is 3. * * @param expression i18n literal * @return number of parameters */ public static int getPropertyValueParamsMaxCount(final PsiLiteralExpression expression) { int maxCount = -1; for (PsiReference reference : expression.getReferences()) { if (reference instanceof PsiPolyVariantReference) { for (ResolveResult result : ((PsiPolyVariantReference) reference).multiResolve(false)) { if (result.isValidResult() && result.getElement() instanceof IProperty) { String value = ((IProperty) result.getElement()).getValue(); MessageFormat format; try { format = new MessageFormat(value); } catch (Exception e) { continue; // ignore syntax error } try { int count = format.getFormatsByArgumentIndex().length; maxCount = Math.max(maxCount, count); } catch (IllegalArgumentException ignored) { } } } } } return maxCount; }
@Override public void visitXmlAttributeValue(XmlAttributeValue value) { for (PsiReference reference : value.getReferences()) { if (!(reference instanceof OnClickConverter.MyReference)) { continue; } final OnClickConverter.MyReference ref = (OnClickConverter.MyReference) reference; final String methodName = ref.getValue(); if (methodName.isEmpty()) { continue; } final ResolveResult[] results = ref.multiResolve(false); final Set<PsiClass> resolvedClasses = new HashSet<PsiClass>(); final Set<PsiClass> resolvedClassesWithMistake = new HashSet<PsiClass>(); for (ResolveResult result : results) { if (result instanceof OnClickConverter.MyResolveResult) { final PsiElement element = result.getElement(); if (element != null) { final PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); if (aClass != null) { resolvedClasses.add(aClass); if (!((OnClickConverter.MyResolveResult) result).hasCorrectSignature()) { resolvedClassesWithMistake.add(aClass); } } } } } PsiClass activity = null; for (PsiClass relatedActivity : myRelatedActivities) { if (!containsOrExtends(resolvedClasses, relatedActivity)) { activity = relatedActivity; break; } else if (activity == null && containsOrExtends(resolvedClassesWithMistake, relatedActivity)) { activity = relatedActivity; } } if (activity != null) { reportMissingOnClickProblem( ref, activity, methodName, resolvedClassesWithMistake.contains(activity)); } else if (results.length == 0) { myResult.add( myInspectionManager.createProblemDescriptor( value, reference.getRangeInElement(), ProblemsHolder.unresolvedReferenceMessage(reference), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myOnTheFly)); } else if (resolvedClassesWithMistake.size() > 0) { reportMissingOnClickProblem( ref, resolvedClassesWithMistake.iterator().next(), methodName, true); } } }
@Override public void doCollectInformation(@NotNull final ProgressIndicator progress) { @SuppressWarnings("unchecked") HighlightUsagesHandlerBase<PsiElement> handler = HighlightUsagesHandler.createCustomHandler(myEditor, myFile); if (handler != null) { List<PsiElement> targets = handler.getTargets(); handler.computeUsages(targets); final List<TextRange> readUsages = handler.getReadUsages(); for (TextRange readUsage : readUsages) { LOG.assertTrue(readUsage != null, "null text range from " + handler); } myReadAccessRanges.addAll(readUsages); final List<TextRange> writeUsages = handler.getWriteUsages(); for (TextRange writeUsage : writeUsages) { LOG.assertTrue(writeUsage != null, "null text range from " + handler); } myWriteAccessRanges.addAll(writeUsages); if (!handler.highlightReferences()) return; } int flags = TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED; PsiElement myTarget; try { myTarget = TargetElementUtil.getInstance().findTargetElement(myEditor, flags, myCaretOffset); } catch (IndexNotReadyException e) { return; } if (myTarget == null) { if (!PsiDocumentManager.getInstance(myProject).isUncommited(myEditor.getDocument())) { // when document is committed, try to check injected stuff - it's fast Editor injectedEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit( myEditor, myFile, myCaretOffset); myTarget = TargetElementUtil.getInstance() .findTargetElement( injectedEditor, flags, injectedEditor.getCaretModel().getOffset()); } } if (myTarget != null) { highlightTargetUsages(myTarget); } else { PsiReference ref = TargetElementUtil.findReference(myEditor); if (ref instanceof PsiPolyVariantReference) { if (!ref.getElement().isValid()) { throw new PsiInvalidElementAccessException( ref.getElement(), "Invalid element in " + ref + " of " + ref.getClass() + "; editor=" + myEditor); } ResolveResult[] results = ((PsiPolyVariantReference) ref).multiResolve(false); if (results.length > 0) { for (ResolveResult result : results) { PsiElement target = result.getElement(); if (target != null) { if (!target.isValid()) { throw new PsiInvalidElementAccessException( target, "Invalid element returned from " + ref + " of " + ref.getClass() + "; editor=" + myEditor); } highlightTargetUsages(target); } } } } } }
@Override protected boolean acceptsForMembersVisibility( @NotNull JSPsiElementBase element, @NotNull SinkResolveProcessor resolveProcessor) { if (!(element instanceof JSAttributeListOwner)) return true; final JSAttributeList attributeList = ((JSAttributeListOwner) element).getAttributeList(); if (JSResolveUtil.getClassOfContext(place) != JSResolveUtil.getClassOfContext(element)) { if (!acceptPrivateMembers) { if (attributeList != null && attributeList.getAccessType() == JSAttributeList.AccessType.PRIVATE) { resolveProcessor.addPossibleCandidateResult( element, JSResolveResult.PRIVATE_MEMBER_IS_NOT_ACCESSIBLE); return false; } } if (!acceptProtectedMembers) { if (attributeList != null && attributeList.getAccessType() == JSAttributeList.AccessType.PROTECTED) { // we are resolving in context of the class or element within context of the class if ((myClassScopeTypeName != null || isParentClassContext(element))) { resolveProcessor.addPossibleCandidateResult( element, JSResolveResult.PROTECTED_MEMBER_IS_NOT_ACCESSIBLE); return false; } // if element / context out of class then protected element is ok due to includes } } } PsiElement elt = JSResolveUtil.findParent(element); if (processStatics) { if ((attributeList == null || !attributeList.hasModifier(JSAttributeList.ModifierType.STATIC))) { if (JSResolveUtil.PROTOTYPE_FIELD_NAME.equals(resolveProcessor.getName())) return true; resolveProcessor.addPossibleCandidateResult( element, JSResolveResult.INSTANCE_MEMBER_INACCESSIBLE); return false; } if (myTypeName != null && elt instanceof JSClass && !myTypeName.equals(((JSClass) elt).getQualifiedName())) { // static members are inherited in TypeScript classes resolveProcessor.addPossibleCandidateResult( element, JSResolveResult.STATIC_MEMBER_INACCESSIBLE); return false; } } else if (myClassDeclarationStarted && !allowUnqualifiedStaticsFromInstance) { // ActionScript only? if (attributeList != null && attributeList.hasModifier(JSAttributeList.ModifierType.STATIC)) { boolean referencingClass = false; if (place instanceof JSReferenceExpression) { JSExpression qualifier = ((JSReferenceExpression) place).getQualifier(); if (qualifier instanceof JSReferenceExpression) { List<JSElement> expressions = JSSymbolUtil.calcRefExprValues((JSReferenceExpression) qualifier); expressions: for (JSElement expression : expressions) { if (expression instanceof JSReferenceExpression) { for (ResolveResult r : ((JSReferenceExpression) expression).multiResolve(false)) { PsiElement rElement = r.getElement(); if (rElement instanceof JSClass) { referencingClass = true; break expressions; } } } } } } if (!referencingClass) { resolveProcessor.addPossibleCandidateResult( element, JSResolveResult.STATIC_MEMBER_INACCESSIBLE); return false; } } } if (processActionScriptNotAllowedNsAttributes(element, resolveProcessor, attributeList)) return false; return true; }