mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 05:51:25 +07:00
IDEA-66081 (resolve methods in javadoc by signatures)
This commit is contained in:
@@ -48,12 +48,10 @@ import java.util.*;
|
||||
|
||||
public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
|
||||
@NonNls public static final String SHORT_NAME = "JavadocReference";
|
||||
public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.javadoc.ref.display.name");
|
||||
|
||||
|
||||
private static ProblemDescriptor createDescriptor(@NotNull PsiElement element, String template, InspectionManager manager,
|
||||
boolean onTheFly) {
|
||||
return manager.createProblemDescriptor(element, template, onTheFly, (LocalQuickFix [])null, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
return manager.createProblemDescriptor(element, template, onTheFly, null, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -66,9 +64,14 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
|
||||
return checkMember(field, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(aClass, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProblemDescriptor[] checkMember(final PsiDocCommentOwner docCommentOwner, final InspectionManager manager, final boolean isOnTheFly) {
|
||||
ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
|
||||
final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
|
||||
final PsiDocComment docComment = docCommentOwner.getDocComment();
|
||||
if (docComment == null) return null;
|
||||
|
||||
@@ -77,26 +80,20 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
|
||||
for (PsiJavaCodeReferenceElement reference : references) {
|
||||
final List<PsiClass> classesToImport = new ImportClassFix(reference).getClassesToImport();
|
||||
final PsiElement referenceNameElement = reference.getReferenceNameElement();
|
||||
problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference, cannotResolveSymbolMessage("<code>" + reference.getText() + "</code>"),
|
||||
!isOnTheFly || classesToImport.isEmpty() ? null : new AddImportFix(classesToImport), ProblemHighlightType.LIKE_UNKNOWN_SYMBOL,
|
||||
isOnTheFly));
|
||||
problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference,
|
||||
cannotResolveSymbolMessage("<code>" + reference.getText() + "</code>"),
|
||||
!isOnTheFly || classesToImport.isEmpty() ? null : new AddImportFix(classesToImport),
|
||||
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, isOnTheFly));
|
||||
}
|
||||
|
||||
return problems.isEmpty()
|
||||
? null
|
||||
: problems.toArray(new ProblemDescriptor[problems.size()]);
|
||||
return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
return checkMember(aClass, manager, isOnTheFly);
|
||||
}
|
||||
|
||||
|
||||
private PsiElementVisitor getVisitor(final Set<PsiJavaCodeReferenceElement> references,
|
||||
final PsiElement context,
|
||||
final ArrayList<ProblemDescriptor> problems,
|
||||
final InspectionManager manager, final boolean onTheFly) {
|
||||
final InspectionManager manager,
|
||||
final boolean onTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
visitElement(expression);
|
||||
@@ -137,58 +134,56 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
|
||||
};
|
||||
}
|
||||
|
||||
public static void visitRefInDocTag(final PsiDocTag tag, final JavadocManager manager, final PsiElement context, ArrayList<ProblemDescriptor> problems,
|
||||
InspectionManager inspectionManager,
|
||||
boolean onTheFly) {
|
||||
public static void visitRefInDocTag(final PsiDocTag tag,
|
||||
final JavadocManager manager,
|
||||
final PsiElement context,
|
||||
final ArrayList<ProblemDescriptor> problems,
|
||||
final InspectionManager inspectionManager,
|
||||
final boolean onTheFly) {
|
||||
final String tagName = tag.getName();
|
||||
PsiDocTagValue value = tag.getValueElement();
|
||||
final PsiDocTagValue value = tag.getValueElement();
|
||||
if (value == null) return;
|
||||
final JavadocTagInfo info = manager.getTagInfo(tagName);
|
||||
if (info != null && !info.isValidInContext(context)) return;
|
||||
String message = info == null || !info.isInline() ? null : info.checkTagValue(value);
|
||||
final String message = info == null || !info.isInline() ? null : info.checkTagValue(value);
|
||||
if (message != null){
|
||||
problems.add(createDescriptor(value, message, inspectionManager, onTheFly));
|
||||
}
|
||||
|
||||
final PsiReference reference = value.getReference();
|
||||
if (reference != null) {
|
||||
PsiElement element = reference.resolve();
|
||||
if (element == null) {
|
||||
final int textOffset = value.getTextOffset();
|
||||
if (reference == null) return;
|
||||
final PsiElement element = reference.resolve();
|
||||
if (element != null) return;
|
||||
final int textOffset = value.getTextOffset();
|
||||
if (textOffset == value.getTextRange().getEndOffset()) return;
|
||||
final PsiDocTagValue valueElement = tag.getValueElement();
|
||||
if (valueElement == null) return;
|
||||
|
||||
if (textOffset != value.getTextRange().getEndOffset()) {
|
||||
final PsiDocTagValue valueElement = tag.getValueElement();
|
||||
if (valueElement != null) {
|
||||
final CharSequence paramName =
|
||||
value.getContainingFile().getViewProvider().getContents().subSequence(textOffset, value.getTextRange().getEndOffset());
|
||||
@NonNls String params = "<code>" + paramName + "</code>";
|
||||
|
||||
final List<LocalQuickFix> fixes = new ArrayList<LocalQuickFix>();
|
||||
if (onTheFly && "param".equals(tagName)) {
|
||||
final PsiDocCommentOwner commentOwner = PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class);
|
||||
if (commentOwner instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)commentOwner;
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
final PsiDocTag[] tags = tag.getContainingComment().getTags();
|
||||
final Set<String> unboundParams = new HashSet<String>();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!JavaDocLocalInspection.isFound(tags, parameter)) {
|
||||
unboundParams.add(parameter.getName());
|
||||
}
|
||||
}
|
||||
if (!unboundParams.isEmpty()) {
|
||||
fixes.add(new RenameReferenceQuickFix(unboundParams));
|
||||
}
|
||||
}
|
||||
}
|
||||
fixes.add(new RemoveTagFix(tagName, paramName, tag));
|
||||
|
||||
problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params),
|
||||
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly,
|
||||
fixes.toArray(new LocalQuickFix[fixes.size()])));
|
||||
final CharSequence paramName = value.getContainingFile().getViewProvider().getContents().subSequence(textOffset, value.getTextRange().getEndOffset());
|
||||
final String params = "<code>" + paramName + "</code>";
|
||||
final List<LocalQuickFix> fixes = new ArrayList<LocalQuickFix>();
|
||||
if (onTheFly && "param".equals(tagName)) {
|
||||
final PsiDocCommentOwner commentOwner = PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class);
|
||||
if (commentOwner instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)commentOwner;
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
final PsiDocTag[] tags = tag.getContainingComment().getTags();
|
||||
final Set<String> unboundParams = new HashSet<String>();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!JavaDocLocalInspection.isFound(tags, parameter)) {
|
||||
unboundParams.add(parameter.getName());
|
||||
}
|
||||
}
|
||||
if (!unboundParams.isEmpty()) {
|
||||
fixes.add(new RenameReferenceQuickFix(unboundParams));
|
||||
}
|
||||
}
|
||||
}
|
||||
fixes.add(new RemoveTagFix(tagName, paramName, tag));
|
||||
|
||||
problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params),
|
||||
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly,
|
||||
fixes.toArray(new LocalQuickFix[fixes.size()])));
|
||||
}
|
||||
|
||||
private static String cannotResolveSymbolMessage(String params) {
|
||||
@@ -197,7 +192,7 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
|
||||
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return DISPLAY_NAME;
|
||||
return InspectionsBundle.message("inspection.javadoc.ref.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.javadoc;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
@@ -29,9 +29,9 @@ import com.intellij.psi.javadoc.PsiDocTagValue;
|
||||
import com.intellij.psi.scope.ElementClassFilter;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.scope.processor.FilterScopeProcessor;
|
||||
import com.intellij.psi.util.MethodSignature;
|
||||
import com.intellij.psi.util.MethodSignatureUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.CharTable;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -85,8 +85,6 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
@Nullable
|
||||
private PsiReference getReferenceInScope(PsiElement scope, PsiElement element) {
|
||||
final String name = element.getText();
|
||||
|
||||
|
||||
final String[] signature = getSignature();
|
||||
|
||||
if (signature == null) {
|
||||
@@ -97,49 +95,44 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
}
|
||||
}
|
||||
|
||||
final PsiMethod[] methods = getAllMethods(scope, this);
|
||||
|
||||
nextMethod:
|
||||
for (PsiMethod method : methods) {
|
||||
if (!method.getName().equals(name)) continue;
|
||||
|
||||
if (signature == null) {
|
||||
return new MyReference(method);
|
||||
}
|
||||
else {
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (parameters.length != signature.length) continue;
|
||||
for (int j = 0; j < parameters.length; j++) {
|
||||
PsiParameter parameter = parameters[j];
|
||||
PsiType type1 = TypeConversionUtil.erasure(parameter.getType());
|
||||
String type2 = signature[j];
|
||||
if (!Comparing.strEqual(type1.getPresentableText(), type2) && !Comparing.strEqual(type1.getCanonicalText(), type2)) {
|
||||
String shortName = "";
|
||||
PsiClass psiClass = PsiUtil.resolveClassInType(type1);
|
||||
while (psiClass != null) {
|
||||
shortName = psiClass.getName() + (shortName.length() > 0 ? "." + shortName : "");
|
||||
psiClass = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class);
|
||||
}
|
||||
if (!Comparing.strEqual(shortName, type2)) {
|
||||
continue nextMethod;
|
||||
}
|
||||
}
|
||||
final MethodSignature methodSignature;
|
||||
if (signature != null) {
|
||||
final List<PsiType> types = Lists.newArrayListWithCapacity(signature.length);
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory();
|
||||
for (String s : signature) {
|
||||
try {
|
||||
types.add(elementFactory.createTypeFromText(s, scope));
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
types.add(PsiType.NULL);
|
||||
}
|
||||
|
||||
return new MyReference(method) {
|
||||
@NotNull
|
||||
public PsiElement[] getVariants() {
|
||||
final List<PsiMethod> lst = new ArrayList<PsiMethod>();
|
||||
for (PsiMethod method : methods) {
|
||||
if (name.equals(method.getName())) {
|
||||
lst.add(method);
|
||||
}
|
||||
}
|
||||
return lst.toArray(new PsiMethod[lst.size()]);
|
||||
}
|
||||
};
|
||||
}
|
||||
methodSignature = MethodSignatureUtil.createMethodSignature(name, types.toArray(new PsiType[types.size()]),
|
||||
PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
else {
|
||||
methodSignature = MethodSignatureUtil.createMethodSignature(name, PsiType.EMPTY_ARRAY,
|
||||
PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
final PsiMethod[] methods = getAllMethods(scope, this);
|
||||
for (PsiMethod method : methods) {
|
||||
if (!method.getName().equals(name) ||
|
||||
!MethodSignatureUtil.areSignaturesErasureEqual(methodSignature, method.getSignature(PsiSubstitutor.EMPTY))) continue;
|
||||
return new MyReference(method) {
|
||||
@NotNull
|
||||
public PsiElement[] getVariants() {
|
||||
final List<PsiMethod> lst = new ArrayList<PsiMethod>();
|
||||
for (PsiMethod method : methods) {
|
||||
if (name.equals(method.getName())) {
|
||||
lst.add(method);
|
||||
}
|
||||
}
|
||||
return lst.toArray(new PsiMethod[lst.size()]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -157,34 +150,30 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
|
||||
public int getTextOffset() {
|
||||
final PsiElement element = getNameElement();
|
||||
|
||||
if (element != null) {
|
||||
return element.getTextRange().getStartOffset();
|
||||
}
|
||||
|
||||
return getTextRange().getEndOffset();
|
||||
return element != null ? element.getTextRange().getStartOffset() : getTextRange().getEndOffset();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getNameElement() {
|
||||
final ASTNode sharp = findChildByType(DOC_TAG_VALUE_SHARP_TOKEN);
|
||||
if (sharp == null) return null;
|
||||
return SourceTreeToPsiMap.treeElementToPsi(sharp).getNextSibling();
|
||||
return sharp != null ? SourceTreeToPsiMap.treeToPsiNotNull(sharp).getNextSibling() : null;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public String[] getSignature() {
|
||||
PsiElement element = getNameElement().getNextSibling();
|
||||
PsiElement element = getNameElement();
|
||||
if (element == null) return null;
|
||||
|
||||
element = element.getNextSibling();
|
||||
while (element != null && !(element instanceof PsiDocTagValue)) {
|
||||
element = element.getNextSibling();
|
||||
}
|
||||
|
||||
if (element == null) return null;
|
||||
|
||||
List<String> types = new ArrayList<String>();
|
||||
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (child.getNode().getElementType() == DOC_TYPE_HOLDER) {
|
||||
final String[] typeStrings = child.getText().split("[, ]"); //avoid param types list parsing hmm mathod(paramType1, paramType2, ...) -> typeElement1, identifier2, ...
|
||||
final String[] typeStrings = child.getText().split("[, ]"); //avoid param types list parsing hmm method(paramType1, paramType2, ...) -> typeElement1, identifier2, ...
|
||||
if (typeStrings != null) {
|
||||
for (String type : typeStrings) {
|
||||
if (type.length() > 0) {
|
||||
@@ -224,14 +213,14 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
}
|
||||
|
||||
public class MyReference implements PsiJavaReference {
|
||||
private final PsiElement myReferencee;
|
||||
private final PsiElement myReferredElement;
|
||||
|
||||
public MyReference(PsiElement referencee) {
|
||||
myReferencee = referencee;
|
||||
public MyReference(PsiElement referredElement) {
|
||||
myReferredElement = referredElement;
|
||||
}
|
||||
|
||||
public PsiElement resolve() {
|
||||
return myReferencee;
|
||||
return myReferredElement;
|
||||
}
|
||||
|
||||
public void processVariants(PsiScopeProcessor processor) {
|
||||
@@ -244,12 +233,14 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
|
||||
@NotNull
|
||||
public JavaResolveResult advancedResolve(boolean incompleteCode) {
|
||||
return myReferencee == null ? JavaResolveResult.EMPTY : new CandidateInfo(myReferencee, PsiSubstitutor.EMPTY);
|
||||
return myReferredElement == null ? JavaResolveResult.EMPTY
|
||||
: new CandidateInfo(myReferredElement, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JavaResolveResult[] multiResolve(boolean incompleteCode) {
|
||||
return myReferencee == null ? JavaResolveResult.EMPTY_ARRAY : new JavaResolveResult[]{new CandidateInfo(myReferencee, PsiSubstitutor.EMPTY)};
|
||||
return myReferredElement == null ? JavaResolveResult.EMPTY_ARRAY
|
||||
: new JavaResolveResult[]{new CandidateInfo(myReferredElement, PsiSubstitutor.EMPTY)};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -269,21 +260,26 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
|
||||
@NotNull
|
||||
public String getCanonicalText() {
|
||||
return getNameElement().getText();
|
||||
final PsiElement nameElement = getNameElement();
|
||||
assert nameElement != null;
|
||||
return nameElement.getText();
|
||||
}
|
||||
|
||||
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
|
||||
final PsiElement element = getNameElement();
|
||||
final ASTNode treeElement = SourceTreeToPsiMap.psiElementToTree(element);
|
||||
final PsiElement nameElement = getNameElement();
|
||||
assert nameElement != null;
|
||||
final ASTNode treeElement = SourceTreeToPsiMap.psiToTreeNotNull(nameElement);
|
||||
final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(treeElement);
|
||||
LeafElement newToken = Factory.createSingleLeafElement(DOC_TAG_VALUE_TOKEN, newElementName, charTableByTree, getManager());
|
||||
((CompositeElement)treeElement.getTreeParent()).replaceChildInternal(SourceTreeToPsiMap.psiElementToTree(element), newToken);
|
||||
return SourceTreeToPsiMap.treeElementToPsi(newToken);
|
||||
final LeafElement newToken = Factory.createSingleLeafElement(DOC_TAG_VALUE_TOKEN, newElementName, charTableByTree, getManager());
|
||||
((CompositeElement)treeElement.getTreeParent()).replaceChildInternal(SourceTreeToPsiMap.psiToTreeNotNull(nameElement), newToken);
|
||||
return SourceTreeToPsiMap.treeToPsiNotNull(newToken);
|
||||
}
|
||||
|
||||
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
if (isReferenceTo(element)) return PsiDocMethodOrFieldRef.this;
|
||||
final String name = getNameElement().getText();
|
||||
final PsiElement nameElement = getNameElement();
|
||||
assert nameElement != null;
|
||||
final String name = nameElement.getText();
|
||||
final String newName;
|
||||
|
||||
final PsiMethod method;
|
||||
@@ -305,15 +301,16 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
|
||||
if (getFirstChild().getNode().getElementType() == ElementType.DOC_REFERENCE_HOLDER) {
|
||||
PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement) getFirstChild().getFirstChild();
|
||||
final PsiElement child = getFirstChild();
|
||||
if (containingClass != null && child != null && child.getNode().getElementType() == ElementType.DOC_REFERENCE_HOLDER) {
|
||||
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement) child.getFirstChild();
|
||||
assert referenceElement != null;
|
||||
referenceElement.bindToElement(containingClass);
|
||||
}
|
||||
else {
|
||||
if (!PsiTreeUtil.isAncestor(containingClass, PsiDocMethodOrFieldRef.this, true)) {
|
||||
final PsiReferenceExpression ref =
|
||||
JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory().createReferenceExpression(containingClass);
|
||||
if (containingClass != null && !PsiTreeUtil.isAncestor(containingClass, PsiDocMethodOrFieldRef.this, true)) {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory();
|
||||
final PsiReferenceExpression ref = elementFactory.createReferenceExpression(containingClass);
|
||||
addAfter(ref, null);
|
||||
}
|
||||
}
|
||||
@@ -352,10 +349,11 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
}
|
||||
|
||||
public PsiElement bindToText(PsiClass containingClass, StringBuffer newText) {
|
||||
PsiComment comment =
|
||||
JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory().createCommentFromText(newText.toString(), null);
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory();
|
||||
PsiComment comment = elementFactory.createCommentFromText(newText.toString(), null);
|
||||
PsiElement tag = PsiTreeUtil.getChildOfType(comment, PsiDocTag.class);
|
||||
PsiElement ref = PsiTreeUtil.getChildOfType(tag, PsiDocMethodOrFieldRef.class);
|
||||
assert ref != null : newText;
|
||||
return replace(ref);
|
||||
}
|
||||
|
||||
@@ -366,20 +364,20 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
|
||||
public TextRange getRangeInElement() {
|
||||
final ASTNode sharp = findChildByType(DOC_TAG_VALUE_SHARP_TOKEN);
|
||||
if (sharp == null) return new TextRange(0, getTextLength());
|
||||
final PsiElement nextSibling = SourceTreeToPsiMap.treeElementToPsi(sharp).getNextSibling();
|
||||
if(nextSibling != null){
|
||||
final PsiElement nextSibling = SourceTreeToPsiMap.treeToPsiNotNull(sharp).getNextSibling();
|
||||
if (nextSibling != null) {
|
||||
final int startOffset = nextSibling.getTextRange().getStartOffset() - getTextRange().getStartOffset();
|
||||
int endOffset = nextSibling.getTextRange().getEndOffset() - getTextRange().getStartOffset();
|
||||
final PsiElement nextParSibling = nextSibling.getNextSibling();
|
||||
if(nextParSibling != null && "(".equals(nextParSibling.getText())){
|
||||
endOffset ++;
|
||||
if (nextParSibling != null && "(".equals(nextParSibling.getText())) {
|
||||
endOffset++;
|
||||
PsiElement nextElement = nextParSibling.getNextSibling();
|
||||
if(nextElement != null && SourceTreeToPsiMap.psiElementToTree(nextElement).getElementType() == DOC_TAG_VALUE_TOKEN){
|
||||
if (nextElement != null && SourceTreeToPsiMap.psiToTreeNotNull(nextElement).getElementType() == DOC_TAG_VALUE_TOKEN) {
|
||||
endOffset += nextElement.getTextLength();
|
||||
nextElement = nextElement.getNextSibling();
|
||||
}
|
||||
if(nextElement != null && ")".equals(nextElement.getText())){
|
||||
endOffset ++;
|
||||
if (nextElement != null && ")".equals(nextElement.getText())) {
|
||||
endOffset++;
|
||||
}
|
||||
}
|
||||
return new TextRange(startOffset, endOffset);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package pkg;
|
||||
|
||||
/**
|
||||
* @see #method(pkg.B0.C[])
|
||||
* @see #method(B0.C[])
|
||||
* @see #method(B0.C...)
|
||||
*/
|
||||
class A0 {
|
||||
public void method(B0.C[] c) { }
|
||||
}
|
||||
|
||||
class B0 {
|
||||
class C {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package pkg;
|
||||
|
||||
/**
|
||||
* @see #<error descr="Cannot resolve symbol 'method(B1.C)'">method(B1.C)</error>
|
||||
* @see #<error descr="Cannot resolve symbol 'method(B1.C[][])'">method(B1.C[][])</error>
|
||||
* @see #<error descr="Cannot resolve symbol 'method(B1.C..)'">method(<error descr="Cannot resolve symbol 'B1.C.'">B1.C.</error>.)</error>
|
||||
* @see #<error descr="Cannot resolve symbol 'method(B1.C[)'">method(B1.C[)</error>
|
||||
*/
|
||||
class A1 {
|
||||
public void method(B1.C[] c) { }
|
||||
}
|
||||
|
||||
class B1 {
|
||||
class C {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package pkg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @see #method(java.util.List)
|
||||
* @see #method(java.util.List<String>)
|
||||
* @see #method(java.util.List<T>)
|
||||
* @see #method(java.util.List<Number>)
|
||||
*/
|
||||
class A2<T> {
|
||||
public void method(List<String> list) { }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection;
|
||||
import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection;
|
||||
|
||||
public class JavadocResolveTest extends DaemonAnalyzerTestCase {
|
||||
private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/javaDoc/resolve";
|
||||
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new JavaDocLocalInspection(), new JavaDocReferenceInspection()};
|
||||
}
|
||||
|
||||
public void testSee0() throws Exception { doTest(); }
|
||||
public void testSee1() throws Exception { doTest(); }
|
||||
public void testSee2() throws Exception { doTest(); }
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(BASE_PATH + "/pkg/" + getTestName(false) + ".java", BASE_PATH, false, false);
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,23 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
|
||||
public interface MethodSignature {
|
||||
MethodSignature[] EMPTY_ARRAY = new MethodSignature[0];
|
||||
@NotNull PsiSubstitutor getSubstitutor();
|
||||
@NotNull String getName();
|
||||
/**
|
||||
* already substituted
|
||||
*/
|
||||
@NotNull PsiType[] getParameterTypes();
|
||||
@NotNull PsiTypeParameter[] getTypeParameters();
|
||||
boolean isRaw();
|
||||
|
||||
@NotNull
|
||||
PsiSubstitutor getSubstitutor();
|
||||
|
||||
@NotNull
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* @return array of parameter types (already substituted)
|
||||
*/
|
||||
@NotNull
|
||||
PsiType[] getParameterTypes();
|
||||
|
||||
@NotNull
|
||||
PsiTypeParameter[] getTypeParameters();
|
||||
|
||||
boolean isRaw();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.util.Set;
|
||||
|
||||
|
||||
public class MethodSignatureUtil {
|
||||
private MethodSignatureUtil() { }
|
||||
|
||||
public static final TObjectHashingStrategy<MethodSignatureBackedByPsiMethod> METHOD_BASED_HASHING_STRATEGY =
|
||||
new TObjectHashingStrategy<MethodSignatureBackedByPsiMethod>() {
|
||||
public int computeHashCode(final MethodSignatureBackedByPsiMethod signature) {
|
||||
@@ -40,9 +42,6 @@ public class MethodSignatureUtil {
|
||||
}
|
||||
};
|
||||
|
||||
private MethodSignatureUtil() {
|
||||
}
|
||||
|
||||
public static MethodSignature createMethodSignature(@NonNls @NotNull String name,
|
||||
@Nullable PsiParameterList parameterTypes,
|
||||
@Nullable PsiTypeParameterList typeParameterList,
|
||||
@@ -154,10 +153,12 @@ public class MethodSignatureUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod findMethodBySignature(final PsiClass aClass, PsiMethod pattenMethod, boolean checkBases) {
|
||||
return findMethodBySignature(aClass, pattenMethod.getSignature(PsiSubstitutor.EMPTY), checkBases);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod findMethodBySignature(final PsiClass aClass, MethodSignature methodSignature, boolean checkBases) {
|
||||
List<Pair<PsiMethod, PsiSubstitutor>> pairs = aClass.findMethodsAndTheirSubstitutorsByName(methodSignature.getName(), checkBases);
|
||||
for (Pair<PsiMethod, PsiSubstitutor> pair : pairs) {
|
||||
@@ -181,13 +182,17 @@ public class MethodSignatureUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod findMethodBySuperMethod(final PsiClass aClass, PsiMethod method, final boolean checkBases) {
|
||||
List<Pair<PsiMethod, PsiSubstitutor>> pairs = aClass.findMethodsAndTheirSubstitutorsByName(method.getName(), checkBases);
|
||||
for (Pair<PsiMethod, PsiSubstitutor> pair : pairs) {
|
||||
PsiMethod candidate = pair.first;
|
||||
PsiSubstitutor substitutor = pair.second;
|
||||
MethodSignature candidateSignature = candidate.getSignature(substitutor);
|
||||
PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(method.getContainingClass(), candidate.getContainingClass(), substitutor);
|
||||
final PsiClass methodClass = method.getContainingClass();
|
||||
final PsiClass candidateClass = candidate.getContainingClass();
|
||||
if (methodClass == null || candidateClass == null) continue;
|
||||
PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(methodClass, candidateClass, substitutor);
|
||||
if (superSubstitutor == null) continue;
|
||||
MethodSignature superSignature = method.getSignature(superSubstitutor);
|
||||
if (isSubsignature(superSignature, candidateSignature)) return candidate;
|
||||
@@ -206,41 +211,47 @@ public class MethodSignatureUtil {
|
||||
}
|
||||
|
||||
public static boolean areParametersErasureEqual(PsiMethod method1, PsiMethod method2) {
|
||||
return METHOD_PARAMETERS_ERASURE_EQUALITY.equals(method1.getSignature(PsiSubstitutor.EMPTY),
|
||||
method2.getSignature(PsiSubstitutor.EMPTY));
|
||||
return areSignaturesErasureEqual(method1.getSignature(PsiSubstitutor.EMPTY), method2.getSignature(PsiSubstitutor.EMPTY));
|
||||
}
|
||||
|
||||
public static boolean areSignaturesErasureEqual(MethodSignature signature1, MethodSignature signature2) {
|
||||
return METHOD_PARAMETERS_ERASURE_EQUALITY.equals(signature1, signature2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param methodSignature
|
||||
* @param superMethodSignature
|
||||
* @param methodSignature method signature
|
||||
* @param superMethodSignature super method signature
|
||||
* @return null if signatures do not match
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiSubstitutor getSuperMethodSignatureSubstitutor(MethodSignature methodSignature, MethodSignature superMethodSignature) {
|
||||
PsiSubstitutor result = getSuperMethodSignatureSubstitutorImpl(methodSignature, superMethodSignature);
|
||||
if (result == null) return null;
|
||||
|
||||
PsiTypeParameter[] methoTypeParameters = methodSignature.getTypeParameters();
|
||||
PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters();
|
||||
PsiTypeParameter[] superTypeParameters = superMethodSignature.getTypeParameters();
|
||||
PsiSubstitutor methodSubstitutor = methodSignature.getSubstitutor();
|
||||
|
||||
//check bounds
|
||||
for (int i = 0; i < methoTypeParameters.length; i++) {
|
||||
PsiTypeParameter methoTypeParameter = methoTypeParameters[i];
|
||||
for (int i = 0; i < methodTypeParameters.length; i++) {
|
||||
PsiTypeParameter methodTypeParameter = methodTypeParameters[i];
|
||||
PsiTypeParameter superTypeParameter = superTypeParameters[i];
|
||||
final Set<PsiType> methoSupers = new HashSet<PsiType>();
|
||||
for (PsiClassType methoSuper : methoTypeParameter.getSuperTypes()) {
|
||||
methoSupers.add(methodSubstitutor.substitute(methoSuper));
|
||||
final Set<PsiType> methodSupers = new HashSet<PsiType>();
|
||||
for (PsiClassType methodSuper : methodTypeParameter.getSuperTypes()) {
|
||||
methodSupers.add(methodSubstitutor.substitute(methodSuper));
|
||||
}
|
||||
|
||||
final Set<PsiType> superSupers = new HashSet<PsiType>();
|
||||
for (PsiClassType superSuper : superTypeParameter.getSuperTypes()) {
|
||||
superSupers.add(methodSubstitutor.substitute(PsiUtil.captureToplevelWildcards(result.substitute(superSuper), methoTypeParameter)));
|
||||
superSupers.add(methodSubstitutor.substitute(PsiUtil.captureToplevelWildcards(result.substitute(superSuper), methodTypeParameter)));
|
||||
}
|
||||
if (!methoSupers.equals(superSupers)) return null;
|
||||
if (!methodSupers.equals(superSupers)) return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiSubstitutor getSuperMethodSignatureSubstitutorImpl(MethodSignature methodSignature, MethodSignature superSignature) {
|
||||
// normalize generic method declarations: correlate type parameters
|
||||
// todo: correlate type params by name?
|
||||
@@ -336,5 +347,4 @@ public class MethodSignatureUtil {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user