### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java,v retrieving revision 1.158 diff -u -r1.158 SelectionEngine.java --- codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java 7 Apr 2010 17:22:33 -0000 1.158 +++ codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java 22 Feb 2011 12:35:51 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,12 +10,18 @@ *******************************************************************************/ package org.eclipse.jdt.internal.codeassist; +import java.util.ArrayList; +import java.util.Iterator; import java.util.Locale; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IOpenable; +import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; @@ -1106,7 +1112,7 @@ } this.acceptedAnswer = true; } else if (binding instanceof MethodBinding) { - MethodBinding methodBinding = (MethodBinding) binding; + MethodBinding methodBinding = getCorrectMethodBinding((MethodBinding) binding); this.noProposal = false; boolean isValuesOrValueOf = false; @@ -1608,4 +1614,192 @@ return false; } + + /* + * Returns the correct method binding according to whether the selection is on the method declaration + * or on the inheritDoc tag in its javadoc. + */ + private MethodBinding getCorrectMethodBinding(MethodBinding binding) { + if (this.parser.javadocParser instanceof SelectionJavadocParser) { + if (((SelectionJavadocParser)this.parser.javadocParser).inheritDocTagSelected){ + try { + Object res = findMethodWithAttachedDocInHierarchy(binding); + if (res instanceof MethodBinding) { + return (MethodBinding) res; + } + } catch (JavaModelException e) { + return null; + } + } + } + return binding; + } + + protected MethodBinding findOverriddenMethodInType(ReferenceBinding overriddenType, MethodBinding overriding) throws JavaModelException { + if (overriddenType == null) + return null; + MethodBinding[] overriddenMethods= overriddenType.availableMethods(); + LookupEnvironment lookupEnv = this.lookupEnvironment; + if (lookupEnv != null && overriddenMethods != null) { + for (int i= 0; i < overriddenMethods.length; i++) { + if (lookupEnv.methodVerifier().isMethodSubsignature(overriding, overriddenMethods[i])) { + return overriddenMethods[i]; + } + } + } + return null; + } + + private Object findMethodWithAttachedDocInHierarchy(final MethodBinding method) throws JavaModelException { + ReferenceBinding type= method.declaringClass; + final SelectionRequestor requestor1 = (SelectionRequestor) this.requestor; + return new InheritDocVisitor() { + public Object visit(ReferenceBinding currType) throws JavaModelException { + MethodBinding overridden = findOverriddenMethodInType(currType, method); + if (overridden == null) + return InheritDocVisitor.CONTINUE; + TypeBinding args[] = overridden.parameters; + String names[] = new String[args.length]; + for (int i = 0; i < args.length; i++) { + names[i] = Signature.createTypeSignature(args[i].sourceName(), false); + } + IMember member = (IMember) requestor1.findMethodFromBinding(overridden, names, overridden.declaringClass); + if (member == null) + return InheritDocVisitor.CONTINUE; + if (member.getAttachedJavadoc(null) != null ) { + // for binary methods with attached javadoc and no source attached + return overridden; + } + IOpenable openable = member.getOpenable(); + if (openable == null) + return InheritDocVisitor.CONTINUE; + IBuffer buf= openable.getBuffer(); + if (buf == null) { + // no source attachment found. This method maybe the one. Stop. + return InheritDocVisitor.STOP_BRANCH; + } + + ISourceRange javadocRange= member.getJavadocRange(); + if (javadocRange == null) + return InheritDocVisitor.CONTINUE; // this method doesn't have javadoc, continue to look. + String rawJavadoc= buf.getText(javadocRange.getOffset(), javadocRange.getLength()); + if (rawJavadoc != null) { + return overridden; + } + return InheritDocVisitor.CONTINUE; + } + }.visitInheritDoc(type); + } + + /** + * Implements the "Algorithm for Inheriting Method Comments" as specified for + * 1.4.2, + * 1.5, and + * 1.6. + * + *
+ * Unfortunately, the implementation is broken in Javadoc implementations since 1.5, see + * Sun's bug. + *
+ * + *+ * We adhere to the spec. + *
+ */ + private static abstract class InheritDocVisitor { + public static final Object STOP_BRANCH= new Object() { + public String toString() { return "STOP_BRANCH"; } //$NON-NLS-1$ + }; + public static final Object CONTINUE= new Object() { + public String toString() { return "CONTINUE"; } //$NON-NLS-1$ + }; + + /** + * Visits a type and decides how the visitor should proceed. + * + * @param currType the current type + * @returnnull
, to indicate that visiting should be
+ * cancelled immediately. The returned value is the result of
+ * {@link #visitInheritDoc(ReferenceBinding)}currentType
.
+ *
+ * @param currentType the starting type
+ * @return the result from a call to {@link #visit(ReferenceBinding)}, or null
if none of
+ * the calls returned a result
+ * @throws JavaModelException unexpected problem
+ */
+ public Object visitInheritDoc(ReferenceBinding currentType) throws JavaModelException {
+ ArrayList visited= new ArrayList();
+ visited.add(currentType);
+ Object result= visitInheritDocInterfaces(visited, currentType);
+ if (result != InheritDocVisitor.CONTINUE)
+ return result;
+
+ ReferenceBinding superClass= currentType.superclass();
+
+ while (superClass != null && ! visited.contains(superClass)) {
+ result= visit(superClass);
+ if (result == InheritDocVisitor.STOP_BRANCH) {
+ return null;
+ } else if (result == InheritDocVisitor.CONTINUE) {
+ visited.add(superClass);
+ result= visitInheritDocInterfaces(visited, superClass);
+ if (result != InheritDocVisitor.CONTINUE)
+ return result;
+ else
+ superClass= superClass.superclass();
+ } else {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Visits the super interfaces of the given type in the given hierarchy, thereby skipping already visited types.
+ *
+ * @param visited set of visited types
+ * @param currentType type whose super interfaces should be visited
+ * @return the result, or {@link #CONTINUE} if no result has been found
+ * @throws JavaModelException unexpected problem
+ */
+ private Object visitInheritDocInterfaces(ArrayList visited, ReferenceBinding currentType) throws JavaModelException {
+ ArrayList toVisitChildren= new ArrayList();
+ ReferenceBinding[] superInterfaces= currentType.superInterfaces();
+ for (int i= 0; i < superInterfaces.length; i++) {
+ ReferenceBinding superInterface= superInterfaces[i];
+ if (visited.contains(superInterface))
+ continue;
+ visited.add(superInterface);
+ Object result= visit(superInterface);
+ if (result == InheritDocVisitor.STOP_BRANCH) {
+ //skip
+ } else if (result == InheritDocVisitor.CONTINUE) {
+ toVisitChildren.add(superInterface);
+ } else {
+ return result;
+ }
+ }
+ for (Iterator iter= toVisitChildren.iterator(); iter.hasNext(); ) {
+ ReferenceBinding child= (ReferenceBinding) iter.next();
+ Object result= visitInheritDocInterfaces(visited, child);
+ if (result != InheritDocVisitor.CONTINUE)
+ return result;
+ }
+ return InheritDocVisitor.CONTINUE;
+ }
+ }
}
Index: codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java,v
retrieving revision 1.7
diff -u -r1.7 SelectionJavadoc.java
--- codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java 7 Mar 2009 01:08:06 -0000 1.7
+++ codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java 22 Feb 2011 12:35:51 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
package org.eclipse.jdt.internal.codeassist.select;
import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.*;
/**
@@ -19,9 +20,11 @@
public class SelectionJavadoc extends Javadoc {
Expression selectedNode;
+ boolean inheritDocSelected;
public SelectionJavadoc(int sourceStart, int sourceEnd) {
super(sourceStart, sourceEnd);
+ this.inheritDocSelected = false;
}
/* (non-Javadoc)
@@ -106,6 +109,11 @@
binding = this.selectedNode.resolvedType;
}
throw new SelectionNodeFound(binding);
+ } else if (this.inheritDocSelected) {
+ ReferenceContext referenceContext = scope.referenceContext();
+ if (referenceContext instanceof MethodDeclaration) {
+ throw new SelectionNodeFound(((MethodDeclaration) referenceContext).binding);
+ }
}
}
Index: codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java,v
retrieving revision 1.9
diff -u -r1.9 SelectionJavadocParser.java
--- codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java 7 Mar 2009 01:08:06 -0000 1.9
+++ codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java 22 Feb 2011 12:35:51 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -25,12 +25,14 @@
int selectionStart;
int selectionEnd;
ASTNode selectedNode;
+ public boolean inheritDocTagSelected;
public SelectionJavadocParser(SelectionParser sourceParser) {
super(sourceParser);
this.shouldReportProblems = false;
this.reportProblems = false;
this.kind = SELECTION_PARSER | TEXT_PARSE;
+ this.inheritDocTagSelected = false;
}
/*
@@ -186,6 +188,16 @@
protected void updateDocComment() {
if (this.selectedNode instanceof Expression) {
((SelectionJavadoc) this.docComment).selectedNode = (Expression) this.selectedNode;
+ } else if (this.inheritDocTagSelected) {
+ ((SelectionJavadoc) this.docComment).inheritDocSelected = true;
}
}
+
+ /*
+ * Sets a flag to denote that selection has taken place on an inheritDoc tag
+ */
+ protected void parseInheritDocTag() {
+ if (this.tagSourceStart == this.selectionStart && this.tagSourceEnd == this.selectionEnd)
+ this.inheritDocTagSelected = true;
+ }
}
Index: compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java,v
retrieving revision 1.80
diff -u -r1.80 JavadocParser.java
--- compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java 8 Feb 2011 05:16:20 -0000 1.80
+++ compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java 22 Feb 2011 12:35:51 -0000
@@ -568,6 +568,10 @@
if (this.reportProblems) {
recordInheritedPosition((((long) this.tagSourceStart) << 32) + this.tagSourceEnd);
}
+ if (this.inlineTagStarted) {
+ // parse a 'valid' inheritDoc tag
+ parseInheritDocTag();
+ }
break;
default:
valid = false;
@@ -692,6 +696,10 @@
return valid;
}
+ protected void parseInheritDocTag() {
+ // do nothing
+ }
+
/*
* Parse @param tag declaration and flag missing description if corresponding option is enabled
*/
Index: model/org/eclipse/jdt/internal/core/SelectionRequestor.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java,v
retrieving revision 1.79
diff -u -r1.79 SelectionRequestor.java
--- model/org/eclipse/jdt/internal/core/SelectionRequestor.java 7 Sep 2010 19:14:26 -0000 1.79
+++ model/org/eclipse/jdt/internal/core/SelectionRequestor.java 22 Feb 2011 12:35:51 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -34,6 +34,7 @@
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
@@ -842,6 +843,60 @@
}
return res;
}
+// TODO(Ayush): This can be an API in IType
+private IMethod findMethod(IType type, char[] selector, String[] paramTypeNames) throws JavaModelException {
+ IMethod method = null;
+ int startingIndex = 0;
+ String[] args;
+ IType enclosingType = type.getDeclaringType();
+ // If the method is a constructor of a non-static inner type, add the enclosing type as an
+ // additional parameter to the constructor
+ if (enclosingType != null
+ && CharOperation.equals(type.getElementName().toCharArray(), selector)
+ && !Flags.isStatic(type.getFlags())) {
+ args = new String[paramTypeNames.length+1];
+ startingIndex = 1;
+ args[0] = Signature.createTypeSignature(enclosingType.getFullyQualifiedName(), true);
+ } else {
+ args = new String[paramTypeNames.length];
+ }
+ int length = args.length;
+ for(int i = startingIndex; i< length ; i++){
+ args[i] = new String(paramTypeNames[i-startingIndex]);
+ }
+ method = type.getMethod(new String(selector), args);
+
+ IMethod[] methods = type.findMethods(method);
+ if (methods != null && methods.length > 0) {
+ method = methods[0];
+ }
+ return method;
+}
+
+/**
+ * This method returns an IMethod element from the given binding. However,
+ * unlike {@link #findMethod(IType, char[], String[])}, this does not require an IType to get
+ * the IMethod element.
+ * @param method the given method binding
+ * @param signatures the type signatures of the method arguments
+ * @param declaringClass the binding of the method's declaring class
+ * @return an IMethod corresponding to the method binding given, or null if none is found.
+ */
+public IJavaElement findMethodFromBinding(MethodBinding method, String[] signatures, ReferenceBinding declaringClass) {
+ IType foundType = this.resolveType(declaringClass.qualifiedPackageName(), declaringClass.qualifiedSourceName(), NameLookup.ACCEPT_CLASSES & NameLookup.ACCEPT_INTERFACES);
+ if (foundType != null) {
+ if (foundType instanceof BinaryType) {
+ try {
+ return this.findMethod(foundType, method.selector, signatures);
+ } catch (JavaModelException e) {
+ return null;
+ }
+ } else {
+ return foundType.getMethod(new String(method.selector), signatures);
+ }
+ }
+ return null;
+}
/**
* Returns the resolved elements.
*/
#P org.eclipse.jdt.core.tests.model
Index: src/org/eclipse/jdt/core/tests/model/SelectionJavadocModelTests.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SelectionJavadocModelTests.java,v
retrieving revision 1.16
diff -u -r1.16 SelectionJavadocModelTests.java
--- src/org/eclipse/jdt/core/tests/model/SelectionJavadocModelTests.java 27 Jun 2008 16:02:40 -0000 1.16
+++ src/org/eclipse/jdt/core/tests/model/SelectionJavadocModelTests.java 22 Feb 2011 12:35:59 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -1311,4 +1311,174 @@
elements
);
}
+
+ public void testBug171019() throws CoreException {
+ this.wcOwner = new WorkingCopyOwner() {};
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy("/Tests/b171019/X.java",
+ "package b171019;\n" +
+ "interface X {\n" +
+ " /**\n" +
+ " * Main desc of foo..\n" +
+ " */\n" +
+ " void foo(int x);\n" +
+ "}\n" +
+ "interface Y extends X {\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" + // should navigate to X.foo(int)
+ " */\n" +
+ " void foo(int x);\n\n" +
+ " /**\n" +
+ " * {@inheritDoc}\n" + // should navigate to Y.foo(String)
+ " */\n" +
+ " void foo(String s);\n" +
+ "}\n"
+ );
+ IJavaElement[] elements = new IJavaElement[2];
+ elements[0] = selectMethod(this.workingCopies[0], "@inheritDoc", 1);
+ elements[1] = selectMethod(this.workingCopies[0], "@inheritDoc", 2);
+ assertElementsEqual("Invalid selection(s)",
+ "foo(int) [in X [in [Working copy] X.java [in b171019 [in