diff --git a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java index af46d0c795d8..77b76a3b4f26 100644 --- a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java @@ -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 problems = new ArrayList(); + final ArrayList problems = new ArrayList(); 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 classesToImport = new ImportClassFix(reference).getClassesToImport(); final PsiElement referenceNameElement = reference.getReferenceNameElement(); - problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference, cannotResolveSymbolMessage("" + reference.getText() + ""), - !isOnTheFly || classesToImport.isEmpty() ? null : new AddImportFix(classesToImport), ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, - isOnTheFly)); + problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference, + cannotResolveSymbolMessage("" + reference.getText() + ""), + !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 references, final PsiElement context, final ArrayList 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 problems, - InspectionManager inspectionManager, - boolean onTheFly) { + public static void visitRefInDocTag(final PsiDocTag tag, + final JavadocManager manager, + final PsiElement context, + final ArrayList 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 = "" + paramName + ""; - - final List fixes = new ArrayList(); - 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 unboundParams = new HashSet(); - 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 = "" + paramName + ""; + final List fixes = new ArrayList(); + 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 unboundParams = new HashSet(); + 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 diff --git a/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java b/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java index b528198bb493..e4416a428200 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java @@ -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 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 lst = new ArrayList(); - 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 lst = new ArrayList(); + 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 types = new ArrayList(); 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); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See0.java new file mode 100644 index 000000000000..5b7edc9ba85d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See0.java @@ -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 { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See1.java new file mode 100644 index 000000000000..24d1dae563da --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See1.java @@ -0,0 +1,16 @@ +package pkg; + +/** + * @see #method(B1.C) + * @see #method(B1.C[][]) + * @see #method(B1.C..) + * @see #method(B1.C[) + */ +class A1 { + public void method(B1.C[] c) { } +} + +class B1 { + class C { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See2.java new file mode 100644 index 000000000000..e3d607e09b70 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See2.java @@ -0,0 +1,13 @@ +package pkg; + +import java.util.List; + +/** + * @see #method(java.util.List) + * @see #method(java.util.List) + * @see #method(java.util.List) + * @see #method(java.util.List) + */ +class A2 { + public void method(List list) { } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocResolveTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocResolveTest.java new file mode 100644 index 000000000000..6b2be0270645 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocResolveTest.java @@ -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); + } +} diff --git a/java/openapi/src/com/intellij/psi/util/MethodSignature.java b/java/openapi/src/com/intellij/psi/util/MethodSignature.java index 8700d3ba3285..0e7496398166 100644 --- a/java/openapi/src/com/intellij/psi/util/MethodSignature.java +++ b/java/openapi/src/com/intellij/psi/util/MethodSignature.java @@ -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(); } diff --git a/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java b/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java index 73318fb601a5..5a70a6862181 100644 --- a/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java +++ b/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java @@ -29,6 +29,8 @@ import java.util.Set; public class MethodSignatureUtil { + private MethodSignatureUtil() { } + public static final TObjectHashingStrategy METHOD_BASED_HASHING_STRATEGY = new TObjectHashingStrategy() { 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> pairs = aClass.findMethodsAndTheirSubstitutorsByName(methodSignature.getName(), checkBases); for (Pair 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> pairs = aClass.findMethodsAndTheirSubstitutorsByName(method.getName(), checkBases); for (Pair 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 methoSupers = new HashSet(); - for (PsiClassType methoSuper : methoTypeParameter.getSuperTypes()) { - methoSupers.add(methodSubstitutor.substitute(methoSuper)); + final Set methodSupers = new HashSet(); + for (PsiClassType methodSuper : methodTypeParameter.getSuperTypes()) { + methodSupers.add(methodSubstitutor.substitute(methodSuper)); } final Set superSupers = new HashSet(); 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; } - }