Adding a warning for methods and fields that are 'remotely' unused
authorJan Lahoda <jlahoda@netbeans.org>
Wed, 08 Aug 2012 18:53:31 +0200
changeset 841d1ef140c28c4
parent 840 66aefaa70f32
child 842 045ee8d72826
Adding a warning for methods and fields that are 'remotely' unused
remoting/ide/usages/nbproject/project.xml
remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/hints/RemotelyUnused.java
     1.1 --- a/remoting/ide/usages/nbproject/project.xml	Wed Aug 08 18:39:56 2012 +0200
     1.2 +++ b/remoting/ide/usages/nbproject/project.xml	Wed Aug 08 18:53:31 2012 +0200
     1.3 @@ -7,15 +7,6 @@
     1.4              <suite-component/>
     1.5              <module-dependencies>
     1.6                  <dependency>
     1.7 -                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
     1.8 -                    <build-prerequisite/>
     1.9 -                    <compile-dependency/>
    1.10 -                    <run-dependency>
    1.11 -                        <release-version>1</release-version>
    1.12 -                        <specification-version>1.13</specification-version>
    1.13 -                    </run-dependency>
    1.14 -                </dependency>
    1.15 -                <dependency>
    1.16                      <code-name-base>org.netbeans.api.java.classpath</code-name-base>
    1.17                      <build-prerequisite/>
    1.18                      <compile-dependency/>
    1.19 @@ -33,6 +24,15 @@
    1.20                      </run-dependency>
    1.21                  </dependency>
    1.22                  <dependency>
    1.23 +                    <code-name-base>org.netbeans.libs.lucene</code-name-base>
    1.24 +                    <build-prerequisite/>
    1.25 +                    <compile-dependency/>
    1.26 +                    <run-dependency>
    1.27 +                        <release-version>3</release-version>
    1.28 +                        <specification-version>3.7</specification-version>
    1.29 +                    </run-dependency>
    1.30 +                </dependency>
    1.31 +                <dependency>
    1.32                      <code-name-base>org.netbeans.modules.editor</code-name-base>
    1.33                      <build-prerequisite/>
    1.34                      <compile-dependency/>
    1.35 @@ -84,15 +84,6 @@
    1.36                      </run-dependency>
    1.37                  </dependency>
    1.38                  <dependency>
    1.39 -                    <code-name-base>org.netbeans.modules.project.ant</code-name-base>
    1.40 -                    <build-prerequisite/>
    1.41 -                    <compile-dependency/>
    1.42 -                    <run-dependency>
    1.43 -                        <release-version>1</release-version>
    1.44 -                        <specification-version>1.43</specification-version>
    1.45 -                    </run-dependency>
    1.46 -                </dependency>
    1.47 -                <dependency>
    1.48                      <code-name-base>org.netbeans.modules.projectapi</code-name-base>
    1.49                      <build-prerequisite/>
    1.50                      <compile-dependency/>
    1.51 @@ -120,6 +111,23 @@
    1.52                      </run-dependency>
    1.53                  </dependency>
    1.54                  <dependency>
    1.55 +                    <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
    1.56 +                    <build-prerequisite/>
    1.57 +                    <compile-dependency/>
    1.58 +                    <run-dependency>
    1.59 +                        <release-version>0</release-version>
    1.60 +                        <specification-version>1.25</specification-version>
    1.61 +                    </run-dependency>
    1.62 +                </dependency>
    1.63 +                <dependency>
    1.64 +                    <code-name-base>org.netbeans.spi.java.hints</code-name-base>
    1.65 +                    <build-prerequisite/>
    1.66 +                    <compile-dependency/>
    1.67 +                    <run-dependency>
    1.68 +                        <specification-version>1.4</specification-version>
    1.69 +                    </run-dependency>
    1.70 +                </dependency>
    1.71 +                <dependency>
    1.72                      <code-name-base>org.openide.actions</code-name-base>
    1.73                      <build-prerequisite/>
    1.74                      <compile-dependency/>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/hints/RemotelyUnused.java	Wed Aug 08 18:53:31 2012 +0200
     2.3 @@ -0,0 +1,152 @@
     2.4 +/*
     2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     2.6 + *
     2.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
     2.8 + *
     2.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    2.10 + * Other names may be trademarks of their respective owners.
    2.11 + *
    2.12 + * The contents of this file are subject to the terms of either the GNU
    2.13 + * General Public License Version 2 only ("GPL") or the Common
    2.14 + * Development and Distribution License("CDDL") (collectively, the
    2.15 + * "License"). You may not use this file except in compliance with the
    2.16 + * License. You can obtain a copy of the License at
    2.17 + * http://www.netbeans.org/cddl-gplv2.html
    2.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    2.19 + * specific language governing permissions and limitations under the
    2.20 + * License.  When distributing the software, include this License Header
    2.21 + * Notice in each file and include the License file at
    2.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    2.23 + * particular file as subject to the "Classpath" exception as provided
    2.24 + * by Oracle in the GPL Version 2 section of the License file that
    2.25 + * accompanied this code. If applicable, add the following below the
    2.26 + * License Header, with the fields enclosed by brackets [] replaced by
    2.27 + * your own identifying information:
    2.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    2.29 + *
    2.30 + * If you wish your version of this file to be governed by only the CDDL
    2.31 + * or only the GPL Version 2, indicate your decision by adding
    2.32 + * "[Contributor] elects to include this software in this distribution
    2.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    2.34 + * single choice of license, a recipient has the option to distribute
    2.35 + * your version of this file under either the CDDL, the GPL Version 2 or
    2.36 + * to extend the choice of license to its licensees as provided above.
    2.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    2.38 + * Version 2 license, then the option applies only if the new code is
    2.39 + * made subject to such option by the copyright holder.
    2.40 + *
    2.41 + * Contributor(s):
    2.42 + *
    2.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
    2.44 + */
    2.45 +
    2.46 +package org.netbeans.modules.jackpot30.ide.usages.hints;
    2.47 +
    2.48 +import com.sun.source.tree.Tree.Kind;
    2.49 +import java.io.IOException;
    2.50 +import java.net.URI;
    2.51 +import java.net.URISyntaxException;
    2.52 +import java.util.BitSet;
    2.53 +import java.util.concurrent.atomic.AtomicBoolean;
    2.54 +import javax.lang.model.element.Element;
    2.55 +import javax.lang.model.element.ElementKind;
    2.56 +import javax.lang.model.element.ExecutableElement;
    2.57 +import org.apache.lucene.document.Document;
    2.58 +import org.apache.lucene.document.Field;
    2.59 +import org.apache.lucene.document.Field.Index;
    2.60 +import org.apache.lucene.document.Field.Store;
    2.61 +import org.apache.lucene.index.IndexReader;
    2.62 +import org.apache.lucene.index.IndexWriter;
    2.63 +import org.apache.lucene.index.Term;
    2.64 +import org.apache.lucene.search.Collector;
    2.65 +import org.apache.lucene.search.IndexSearcher;
    2.66 +import org.apache.lucene.search.Query;
    2.67 +import org.apache.lucene.search.Searcher;
    2.68 +import org.apache.lucene.search.TermQuery;
    2.69 +import org.netbeans.api.java.source.ElementHandle;
    2.70 +import org.netbeans.modules.jackpot30.common.api.JavaUtils;
    2.71 +import org.netbeans.modules.jackpot30.common.api.LuceneHelpers.BitSetCollector;
    2.72 +import org.netbeans.modules.jackpot30.remoting.api.LocalCache;
    2.73 +import org.netbeans.modules.jackpot30.remoting.api.LocalCache.Task;
    2.74 +import org.netbeans.modules.jackpot30.remoting.api.RemoteIndex;
    2.75 +import org.netbeans.modules.jackpot30.remoting.api.WebUtilities;
    2.76 +import org.netbeans.spi.editor.hints.ErrorDescription;
    2.77 +import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
    2.78 +import org.netbeans.spi.java.hints.Hint;
    2.79 +import org.netbeans.spi.java.hints.HintContext;
    2.80 +import org.netbeans.spi.java.hints.TriggerTreeKind;
    2.81 +import org.openide.util.NbBundle.Messages;
    2.82 +
    2.83 +/**
    2.84 + *
    2.85 + * @author lahvac
    2.86 + */
    2.87 +@Hint(displayName="DN_RemotelyUnused", description="DESC_RemotelyUnused", category="general", enabled=false)
    2.88 +@Messages({"DN_RemotelyUnused=Unused in Remote Projects",
    2.89 +           "DESC_RemotelyUnused=Not used in any known remote project",
    2.90 +           "ERR_NoUsages=No usages found in any know projects"})
    2.91 +public class RemotelyUnused {
    2.92 +
    2.93 +    private static final String VAL_UNUSED = "unused";
    2.94 +    private static final String VAL_USED = "used";
    2.95 +    private static final String VAL_UNKNOWN = "unknown";
    2.96 +
    2.97 +    @TriggerTreeKind({Kind.VARIABLE, Kind.METHOD})
    2.98 +    public static ErrorDescription hint(HintContext ctx) throws URISyntaxException, IOException {
    2.99 +        Element toSearch = ctx.getInfo().getTrees().getElement(ctx.getPath());
   2.100 +
   2.101 +        if (toSearch == null) return null;
   2.102 +        if (!toSearch.getKind().isField() && toSearch.getKind() != ElementKind.METHOD && toSearch.getKind() != ElementKind.CONSTRUCTOR) return null;
   2.103 +        if (toSearch.getKind() == ElementKind.METHOD && ctx.getInfo().getElementUtilities().overridesMethod((ExecutableElement) toSearch)) return null;
   2.104 +
   2.105 +        final String serialized = JavaUtils.serialize(ElementHandle.create(toSearch));
   2.106 +
   2.107 +        for (RemoteIndex idx : RemoteIndex.loadIndices()) {
   2.108 +            String result = LocalCache.runOverLocalCache(idx, new Task<IndexReader, String>() {
   2.109 +                @Override
   2.110 +                public String run(IndexReader reader, AtomicBoolean cancel) throws IOException {
   2.111 +                    Query query = new TermQuery(new Term("usagesSignature", serialized));
   2.112 +                    Searcher s = new IndexSearcher(reader);
   2.113 +                    BitSet matchingDocuments = new BitSet(reader.maxDoc());
   2.114 +                    Collector c = new BitSetCollector(matchingDocuments);
   2.115 +
   2.116 +                    s.search(query, c);
   2.117 +
   2.118 +                    for (int docNum = matchingDocuments.nextSetBit(0); docNum >= 0; docNum = matchingDocuments.nextSetBit(docNum + 1)) {
   2.119 +                        if (cancel.get()) return VAL_UNKNOWN;
   2.120 +
   2.121 +                        final Document doc = reader.document(docNum);
   2.122 +
   2.123 +                        return doc.get("usagesUsages");
   2.124 +                    }
   2.125 +
   2.126 +                    return VAL_UNKNOWN;
   2.127 +                }
   2.128 +            }, null, new AtomicBoolean()/*XXX*/);
   2.129 +
   2.130 +            if (result == null) {
   2.131 +                URI resolved = new URI(idx.remote.toExternalForm() + "/usages/search?path=" + WebUtilities.escapeForQuery(idx.remoteSegment) + "&signatures=" + WebUtilities.escapeForQuery(serialized));
   2.132 +                String response = WebUtilities.requestStringResponse(resolved, new AtomicBoolean());
   2.133 +
   2.134 +                if (response != null) {
   2.135 +                    result = response.trim().isEmpty() ? VAL_UNUSED : VAL_USED;
   2.136 +                } else {
   2.137 +                    result = VAL_UNKNOWN;
   2.138 +                }
   2.139 +                final String resultFin = result;
   2.140 +                LocalCache.saveToLocalCache(idx, new Task<IndexWriter, Void>() {
   2.141 +                    @Override public Void run(IndexWriter p, AtomicBoolean cancel) throws IOException {
   2.142 +                        Document doc = new Document();
   2.143 +                        doc.add(new Field("usagesSignature", serialized, Store.NO, Index.NOT_ANALYZED));
   2.144 +                        doc.add(new Field("usagesUsages", resultFin, Store.YES, Index.NO));
   2.145 +                        p.addDocument(doc);
   2.146 +                        return null;
   2.147 +                    }
   2.148 +                });
   2.149 +            }
   2.150 +            if (!VAL_UNUSED.equals(result)) return null;
   2.151 +        }
   2.152 +
   2.153 +        return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), Bundle.ERR_NoUsages());
   2.154 +    }
   2.155 +}