Correct indexing of overriding/implementing methods from interfaces.
1.1 --- a/remoting/server/indexer/usages/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImpl.java Mon Dec 26 15:34:00 2011 +0100
1.2 +++ b/remoting/server/indexer/usages/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImpl.java Mon Dec 26 19:35:24 2011 +0100
1.3 @@ -52,6 +52,7 @@
1.4 import com.sun.source.util.Trees;
1.5 import java.io.IOException;
1.6 import java.net.URL;
1.7 +import java.util.ArrayList;
1.8 import java.util.Arrays;
1.9 import java.util.Collection;
1.10 import java.util.HashSet;
1.11 @@ -72,7 +73,9 @@
1.12 import javax.lang.model.type.TypeMirror;
1.13 import javax.lang.model.type.TypeVariable;
1.14 import javax.lang.model.type.WildcardType;
1.15 +import javax.lang.model.util.ElementFilter;
1.16 import javax.lang.model.util.Elements;
1.17 +import javax.lang.model.util.Types;
1.18 import org.apache.lucene.document.Document;
1.19 import org.apache.lucene.document.Field;
1.20 import org.apache.lucene.document.Field.Index;
1.21 @@ -80,7 +83,6 @@
1.22 import org.apache.lucene.index.CorruptIndexException;
1.23 import org.netbeans.api.editor.mimelookup.MimeRegistration;
1.24 import org.netbeans.api.java.source.ElementHandle;
1.25 -import org.netbeans.api.java.source.ElementUtilities;
1.26 import org.netbeans.modules.jackpot30.backend.impl.spi.IndexAccessor;
1.27 import org.netbeans.modules.java.preprocessorbridge.spi.JavaIndexerPlugin;
1.28 import org.netbeans.modules.java.source.usages.ClassFileUtil;
1.29 @@ -109,7 +111,7 @@
1.30 final String file = IndexAccessor.getCurrent().getPath(indexable.getURL());
1.31 final Trees trees = services.lookup(Trees.class);
1.32 final Elements elements = services.lookup(Elements.class);
1.33 - final ElementUtilities eu = services.lookup(ElementUtilities.class);
1.34 + final Types types = services.lookup(Types.class);
1.35 final Document usages = new Document();
1.36
1.37 usages.add(new Field("file", file, Store.YES, Index.NO));
1.38 @@ -139,7 +141,7 @@
1.39 }
1.40
1.41 if (el.getKind() == ElementKind.METHOD) {
1.42 - for (ExecutableElement e : overrides(eu, (ExecutableElement) el)) {
1.43 + for (ExecutableElement e : overrides(types, elements, (ExecutableElement) el)) {
1.44 serialized = Common.serialize(ElementHandle.create(e));
1.45
1.46 if (SEEN_SIGNATURES.add(serialized)) {
1.47 @@ -230,7 +232,7 @@
1.48 currentFeatureDocument.add(new Field("featureSignature", featureSignature, Store.YES, Index.NO));
1.49 currentFeatureDocument.add(new Field("featureVMSignature", ClassFileUtil.createExecutableDescriptor((ExecutableElement) el)[2], Store.YES, Index.NO));
1.50
1.51 - for (ExecutableElement e : overrides(eu, (ExecutableElement) el)) {
1.52 + for (ExecutableElement e : overrides(types, elements, (ExecutableElement) el)) {
1.53 currentFeatureDocument.add(new Field("featureOverrides", Common.serialize(ElementHandle.create(e)), Store.YES, Index.NOT_ANALYZED));
1.54 }
1.55 }
1.56 @@ -253,12 +255,28 @@
1.57 }
1.58 }
1.59
1.60 - private static Iterable<? extends ExecutableElement> overrides(ElementUtilities eu, ExecutableElement method) {
1.61 + static Collection<? extends ExecutableElement> overrides(Types types, Elements elements, ExecutableElement method) {
1.62 + TypeElement enclosing = (TypeElement) method.getEnclosingElement();
1.63 + List<TypeMirror> todo = new LinkedList<TypeMirror>(types.directSupertypes(enclosing.asType()));
1.64 + List<TypeMirror> seen = new ArrayList<TypeMirror>();
1.65 List<ExecutableElement> result = new LinkedList<ExecutableElement>();
1.66
1.67 - //XXX: one method may override+implement more than one method
1.68 - while ((method = eu.getOverriddenMethod(method)) != null) {
1.69 - result.add(method);
1.70 + OUTER: while (!todo.isEmpty()) {
1.71 + TypeMirror type = todo.remove(0);
1.72 +
1.73 + if (type.getKind() != TypeKind.DECLARED) continue;
1.74 +
1.75 + for (TypeMirror s : seen) {
1.76 + if (types.isSameType(s, type)) continue OUTER;
1.77 + }
1.78 +
1.79 + TypeElement te = (TypeElement) ((DeclaredType) type).asElement();
1.80 +
1.81 + for (ExecutableElement m : ElementFilter.methodsIn(te.getEnclosedElements())) {
1.82 + if (elements.overrides(method, m, enclosing))
1.83 + result.add(m);
1.84 + }
1.85 +
1.86 }
1.87
1.88 return result;
2.1 --- a/remoting/server/indexer/usages/test/unit/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImplTest.java Mon Dec 26 15:34:00 2011 +0100
2.2 +++ b/remoting/server/indexer/usages/test/unit/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImplTest.java Mon Dec 26 19:35:24 2011 +0100
2.3 @@ -41,15 +41,20 @@
2.4 */
2.5 package org.netbeans.modules.jackpot30.indexer.usages;
2.6
2.7 +import com.sun.source.util.TreePath;
2.8 import java.io.File;
2.9 import java.io.IOException;
2.10 import java.io.OutputStream;
2.11 +import java.util.ArrayList;
2.12 +import java.util.Arrays;
2.13 import java.util.HashSet;
2.14 +import java.util.List;
2.15 import java.util.Set;
2.16 import javax.lang.model.element.ExecutableElement;
2.17 import javax.lang.model.util.ElementFilter;
2.18 import org.netbeans.api.editor.mimelookup.MimePath;
2.19 import org.netbeans.api.java.source.CompilationController;
2.20 +import org.netbeans.api.java.source.ElementHandle;
2.21 import org.netbeans.api.java.source.JavaSource;
2.22 import org.netbeans.api.java.source.Task;
2.23 import org.netbeans.junit.NbTestCase;
2.24 @@ -128,6 +133,50 @@
2.25 assertTrue(invoked[0]);
2.26 }
2.27
2.28 + public void testOverriddenMethods() throws IOException {
2.29 + doOverriddenMethodsTest("package test; public class Test { public String toStr|ing() { return null; } }",
2.30 + "METHOD:java.lang.Object:toString:()Ljava/lang/String;");
2.31 + doOverriddenMethodsTest("package test; public class Test extends A implements B { public void t|t() { } } class A implements B { public void tt() {} } interface B { public void tt(); }",
2.32 + "METHOD:test.A:tt:()V",
2.33 + "METHOD:test.B:tt:()V");
2.34 + }
2.35 +
2.36 + protected void doOverriddenMethodsTest(String code, final String... signature) throws IOException {
2.37 + final int pos = code.indexOf('|');
2.38 +
2.39 + code = code.replace("|", "");
2.40 +
2.41 + FileObject testFile = FileUtil.createData(new File(getWorkDir(), "Test.java"));
2.42 + OutputStream out = testFile.getOutputStream();
2.43 +
2.44 + try {
2.45 + out.write(code.getBytes());
2.46 + } finally {
2.47 + out.close();
2.48 + }
2.49 +
2.50 + final boolean[] invoked = new boolean[1];
2.51 +
2.52 + JavaSource.forFileObject(testFile).runUserActionTask(new Task<CompilationController>() {
2.53 + @Override public void run(CompilationController parameter) throws Exception {
2.54 + parameter.toPhase(JavaSource.Phase.RESOLVED);
2.55 +
2.56 + TreePath selected = parameter.getTreeUtilities().pathFor(pos);
2.57 + ExecutableElement method = (ExecutableElement) parameter.getTrees().getElement(selected);
2.58 + List<String> result = new ArrayList<String>();
2.59 +
2.60 + for (ExecutableElement ee : IndexerImpl.overrides(parameter.getTypes(), parameter.getElements(), method)) {
2.61 + result.add(Common.serialize(ElementHandle.create(ee)));
2.62 + }
2.63 +
2.64 + assertEquals(Arrays.asList(signature), result);
2.65 + invoked[0] = true;
2.66 + }
2.67 + }, true);
2.68 +
2.69 + assertTrue(invoked[0]);
2.70 + }
2.71 +
2.72 @ServiceProvider(service=MimeDataProvider.class)
2.73 public static final class JavacParserProvider implements MimeDataProvider {
2.74