Correct indexing of overriding/implementing methods from interfaces.
authorJan Lahoda <jlahoda@netbeans.org>
Mon, 26 Dec 2011 19:35:24 +0100
changeset 7192b14a9a42066
parent 718 dc6026f33021
child 720 0fb4698acaaa
Correct indexing of overriding/implementing methods from interfaces.
remoting/server/indexer/usages/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImpl.java
remoting/server/indexer/usages/test/unit/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImplTest.java
     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