diff --git a/java.editor/nbproject/project.xml b/java.editor/nbproject/project.xml
--- a/java.editor/nbproject/project.xml
+++ b/java.editor/nbproject/project.xml
@@ -203,6 +203,15 @@
+ org.netbeans.modules.java.platform
+
+
+
+ 1
+ 1.15
+
+
+
org.netbeans.modules.java.preprocessorbridge
@@ -264,6 +273,15 @@
+ org.netbeans.modules.project.libraries
+
+
+
+ 1
+ 1.23
+
+
+
org.netbeans.modules.projectapi
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/AnnotationsHolder.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/AnnotationsHolder.java
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/AnnotationsHolder.java
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/AnnotationsHolder.java
@@ -60,7 +60,8 @@
* @author Jan Lahoda
*/
public class AnnotationsHolder implements PropertyChangeListener {
-
+
+ private static final Logger LOGGER = Logger.getLogger(AnnotationsHolder.class.getName());
private static final Map file2Annotations = new HashMap();
public static synchronized AnnotationsHolder get(FileObject file) {
@@ -82,7 +83,7 @@
return a;
} catch (IOException ex) {
- IsOverriddenAnnotationHandler.LOG.log(Level.INFO, null, ex);
+ LOGGER.log(Level.INFO, null, ex);
return null;
}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/Bundle.properties b/java.editor/src/org/netbeans/modules/java/editor/overridden/Bundle.properties
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/Bundle.properties
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/Bundle.properties
@@ -23,7 +23,7 @@
# Contributor(s):
#
# The Original Software is NetBeans. The Initial Developer of the Original
-# Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+# Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
# Microsystems, Inc. All Rights Reserved.
#
# If you wish your version of this file to be governed by only the CDDL
@@ -51,3 +51,24 @@
NAME_AnonynmousInner=anonymous inner
CTL_IsOverriddenAnnotationAction=Overriden Annotation
+CTL_GoToImplementation=Go to Implementation
+goto-implementation=Go to Implementation
+
+LAB_IsOverridenAnnotation-override-is-overridden-combined=Overrides and is overridden
+TP_COMBINED-override-is-overridden-combined=Overrides and is overridden
+LAB_IsOverridenAnnotation-implements-is-overridden-combined=Implements and is overridden
+TP_COMBINED-implements-is-overridden-combined=Implements and is overridden
+#XXX: inside interfaces, but this should ideally be overrides/has implementations:
+LAB_IsOverridenAnnotation-implements-has-implementations-combined=Implements and has implementations
+TP_COMBINED-implements-has-implementations-combined=Implements and has implementations
+LAB_IsOverriddenAnnotation=Is Overridden
+LAB_OverridesAnnotation=Overrides
+LAB_ImplementsAnnotation=Implements
+LAB_HasImplementationsAnnotation=Has Implementations
+
+LBL_NoMethod=No Method or Type
+LBL_NoOverridingMethod=No overridding method found
+LBL_NoOverridingType=No overridding type found
+ERR_CycleInDependencies=Cycle in dependencies
+LBL_ImplementorsOverriders=Implementors/Overridders
+ERR_NoDependencies=Cannot detect project dependencies
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeAnnotations.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeAnnotations.java
new file mode 100644
--- /dev/null
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeAnnotations.java
@@ -0,0 +1,196 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.editor.overridden;
+
+import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.lang.model.element.Element;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Position;
+import javax.swing.text.StyledDocument;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.JavaParserResultTask;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.modules.parsing.api.Snapshot;
+import org.netbeans.modules.parsing.spi.Parser.Result;
+import org.netbeans.modules.parsing.spi.Scheduler;
+import org.netbeans.modules.parsing.spi.SchedulerEvent;
+import org.netbeans.modules.parsing.spi.SchedulerTask;
+import org.netbeans.modules.parsing.spi.TaskFactory;
+import org.openide.text.NbDocument;
+
+/**
+ *
+ * @author lahvac
+ */
+public class ComputeAnnotations extends JavaParserResultTask {
+
+ private final AtomicBoolean cancel = new AtomicBoolean();
+
+ public ComputeAnnotations() {
+ super(Phase.RESOLVED);
+ }
+
+ @Override
+ public void run(Result result, SchedulerEvent event) {
+ cancel.set(false);
+
+ CompilationInfo info = CompilationInfo.get(result);
+
+ if (info.getChangedTree() != null) {
+ //XXX: currently only method bodies are rebuilt.
+ return ;
+ }
+
+ long start = System.currentTimeMillis();
+ StyledDocument doc = (StyledDocument) result.getSnapshot().getSource().getDocument(false);
+
+ if (doc == null) {
+ return ;
+ }
+
+ List annotations = new LinkedList();
+
+ createAnnotations(info, doc, new ComputeOverriding(cancel).process(info), false, annotations);
+ createAnnotations(info, doc, new ComputeOverriders(cancel).process(info, null, null, false), true, annotations);
+
+ if (cancel.get()) return ;
+
+ AnnotationsHolder.get(info.getFileObject()).setNewAnnotations(annotations);
+
+ long end = System.currentTimeMillis();
+
+ Logger.getLogger("TIMER").log(Level.FINE, "Is Overridden Annotations", new Object[] {info.getFileObject(), end - start});
+ }
+
+ private void createAnnotations(CompilationInfo info, StyledDocument doc, Map, List> descriptions, boolean overridden, List annotations) {
+ if (descriptions != null) {
+ for (Entry, List> e : descriptions.entrySet()) {
+ Element ee = e.getKey().resolve(info);
+ Tree t = info.getTrees().getTree(ee);
+
+ if (t == null) {
+ //XXX: log
+ continue;
+ }
+
+ AnnotationType type;
+ String dn;
+
+ if (overridden) {
+ if (ee.getEnclosingElement().getKind().isInterface() || ee.getKind().isInterface()) {
+ type = AnnotationType.HAS_IMPLEMENTATION;
+ dn = "Is Implemented";
+ } else {
+ type = AnnotationType.IS_OVERRIDDEN;
+ dn = "Is Overridden";
+ }
+ } else {
+ if (ee.getEnclosingElement().getKind().isInterface() || ee.getKind().isInterface()) {
+ type = AnnotationType.IMPLEMENTS;
+ dn = "Implements";
+ } else {
+ type = AnnotationType.OVERRIDES;
+ dn = "Overrides";
+ }
+ }
+
+ Position pos = getPosition(doc, (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), t));
+
+ annotations.add(new IsOverriddenAnnotation(doc, pos, type, dn, e.getValue()));
+ }
+ }
+ }
+
+ @Override
+ public int getPriority() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public Class extends Scheduler> getSchedulerClass() {
+ return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
+ }
+
+ @Override
+ public void cancel() {
+ cancel.set(true);
+ }
+
+ private static Position getPosition(final StyledDocument doc, final int offset) {
+ class Impl implements Runnable {
+ private Position pos;
+ public void run() {
+ if (offset < 0 || offset >= doc.getLength())
+ return ;
+
+ try {
+ pos = doc.createPosition(offset - NbDocument.findLineColumn(doc, offset));
+ } catch (BadLocationException ex) {
+ //should not happen?
+ Logger.getLogger(ComputeAnnotations.class.getName()).log(Level.FINE, null, ex);
+ }
+ }
+ }
+
+ Impl i = new Impl();
+
+ doc.render(i);
+
+ return i.pos;
+ }
+
+ public static final class FactoryImpl extends TaskFactory {
+
+ @Override
+ public Collection extends SchedulerTask> create(Snapshot snapshot) {
+ return Collections.singleton(new ComputeAnnotations());
+ }
+
+ }
+}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeOverriders.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeOverriders.java
new file mode 100644
--- /dev/null
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeOverriders.java
@@ -0,0 +1,575 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.java.editor.overridden;
+
+import java.awt.Point;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Types;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.queries.SourceForBinaryQuery;
+import org.netbeans.api.java.source.ClassIndex;
+import org.netbeans.api.java.source.ClassIndex.SearchKind;
+import org.netbeans.api.java.source.ClassIndex.SearchScope;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.SourceUtils;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileStateInvalidException;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+import org.openide.util.TopologicalSortException;
+import org.openide.util.Utilities;
+
+/**
+ *
+ * @author Jan Lahoda
+ */
+public class ComputeOverriders {
+
+ private static final Logger LOG = Logger.getLogger(ComputeOverriders.class.getName());
+
+ private final AtomicBoolean cancel;
+
+ public ComputeOverriders(AtomicBoolean cancel) {
+ this.cancel = cancel;
+ }
+
+ private static Set findReverseSourceRoots(final URL thisSourceRoot, Map> sourceDeps, final FileObject thisFile) {
+ long startTime = System.currentTimeMillis();
+
+ try {
+ //TODO: from SourceUtils (which filters out source roots that do not belong to open projects):
+ //Create inverse dependencies
+ final Map> inverseDeps = new HashMap> ();
+ for (Map.Entry> entry : sourceDeps.entrySet()) {
+ final URL u1 = entry.getKey();
+ final List l1 = entry.getValue();
+ for (URL u2 : l1) {
+ List l2 = inverseDeps.get(u2);
+ if (l2 == null) {
+ l2 = new ArrayList();
+ inverseDeps.put (u2,l2);
+ }
+ l2.add (u1);
+ }
+ }
+ //Collect dependencies
+ final Set result = new HashSet();
+ final LinkedList todo = new LinkedList ();
+ todo.add (thisSourceRoot);
+ while (!todo.isEmpty()) {
+ final URL u = todo.removeFirst();
+ if (!result.contains(u)) {
+ result.add (u);
+ final List ideps = inverseDeps.get(u);
+ if (ideps != null) {
+ todo.addAll (ideps);
+ }
+ }
+ }
+ return result;
+ } finally {
+ long endTime = System.currentTimeMillis();
+
+ Logger.getLogger("TIMER").log(Level.FINE, "Find Reverse Source Roots", //NOI18N
+ new Object[]{thisFile, endTime - startTime});
+ }
+ }
+
+ private static FileObject findSourceRoot(FileObject file) {
+ final ClassPath cp = ClassPath.getClassPath(file, ClassPath.SOURCE);
+ if (cp != null) {
+ return cp.findOwnerRoot(file);
+ }
+ //Null is a valid value for files which have no source path (default filesystem).
+ return null;
+ }
+
+ private Set findBinaryRootsForSourceRoot(FileObject sourceRoot, Map> binaryDeps) {
+// BinaryForSourceQuery.findBinaryRoots(thisSourceRoot).getRoots();
+ Set result = new HashSet();
+
+ for (URL bin : binaryDeps.keySet()) {
+ if (cancel.get()) return Collections.emptySet();
+ for (FileObject s : SourceForBinaryQuery.findSourceRoots(bin).getRoots()) {
+ if (s == sourceRoot) {
+ result.add(bin);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ Map, List> process(CompilationInfo info, TypeElement te, ExecutableElement ee, boolean interactive) {
+ long startTime = System.currentTimeMillis();
+
+ try {
+ return processImpl(info, te, ee, interactive);
+ } finally {
+ Logger.getLogger("TIMER").log(Level.FINE, "Overridden - Total", //NOI18N
+ new Object[] {info.getFileObject(), System.currentTimeMillis() - startTime});
+ }
+ }
+
+ private Map, List> processImpl(CompilationInfo info, TypeElement te, ExecutableElement ee, boolean interactive) {
+ FileObject file = info.getFileObject();
+ FileObject thisSourceRoot = findSourceRoot(file);
+
+ if (thisSourceRoot == null) {
+ return null;
+ }
+
+
+ //XXX: special case "this" source root (no need to create a new JS and load the classes again for it):
+// reverseSourceRoots.add(thisSourceRoot);
+
+// LOG.log(Level.FINE, "reverseSourceRoots: {0}", reverseSourceRoots); //NOI18N
+
+// if (LOG.isLoggable(Level.FINE)) {
+// LOG.log(Level.FINE, "method: {0}", ee.toString()); //NOI18N
+// }
+
+
+ final Map, List>> methods = new HashMap, List>>();
+
+ if (ee == null) {
+ if (te == null) {
+ fillInMethods(info.getTopLevelElements(), methods);
+ } else {
+ methods.put(ElementHandle.create(te), Collections.>emptyList());
+ }
+ } else {
+ TypeElement owner = (TypeElement) ee.getEnclosingElement();
+
+ methods.put(ElementHandle.create(owner), Collections.singletonList(ElementHandle.create(ee)));
+ }
+
+ final Map, List> overriding = new HashMap, List>();
+
+ long startTime = System.currentTimeMillis();
+ long[] classIndexTime = new long[1];
+ final Map, Set>>> users = computeUsers(info, thisSourceRoot, methods.keySet(), classIndexTime, interactive);
+ long endTime = System.currentTimeMillis();
+
+ if (users == null) {
+ return null;
+ }
+
+ Logger.getLogger("TIMER").log(Level.FINE, "Overridden Candidates - Class Index", //NOI18N
+ new Object[] {file, classIndexTime[0]});
+ Logger.getLogger("TIMER").log(Level.FINE, "Overridden Candidates - Total", //NOI18N
+ new Object[] {file, endTime - startTime});
+
+ for (Map.Entry, Set>>> data : users.entrySet()) {
+ for (Map.Entry, Set>> deps : data.getValue().entrySet()) {
+ if (cancel.get()) return null;
+ findOverriddenAnnotations(data.getKey(), deps.getValue(), deps.getKey(), methods.get(deps.getKey()), overriding);
+ }
+ }
+
+ return overriding;
+ }
+ private static final ClassPath EMPTY = ClassPathSupport.createClassPath(new URL[0]);
+
+ private static void fillInMethods(Iterable extends TypeElement> types, Map, List>> methods) {
+ for (TypeElement te : types) {
+ List> l = new LinkedList>();
+
+ for (ExecutableElement ee : ElementFilter.methodsIn(te.getEnclosedElements())) {
+ l.add(ElementHandle.create(ee));
+ }
+
+ methods.put(ElementHandle.create(te), l);
+
+ fillInMethods(ElementFilter.typesIn(te.getEnclosedElements()), methods);
+ }
+ }
+ private Set> computeUsers(URL source, Set> base, long[] classIndexCumulative) {
+ ClasspathInfo cpinfo = ClasspathInfo.create(EMPTY, EMPTY, ClassPathSupport.createClassPath(source));
+
+ return computeUsers(cpinfo, ClassIndex.SearchScope.SOURCE, base, classIndexCumulative);
+ }
+
+ private Set> computeUsers(ClasspathInfo cpinfo, SearchScope scope, Set> base, long[] classIndexCumulative) {
+ long startTime = System.currentTimeMillis();
+
+ try {
+ List> l = new LinkedList>(base);
+ Set> result = new HashSet>();
+
+ while (!l.isEmpty()) {
+ if (cancel.get()) return null;
+
+ ElementHandle eh = l.remove(0);
+
+ result.add(eh);
+ Set> typeElements = cpinfo.getClassIndex().getElements(eh, Collections.singleton(SearchKind.IMPLEMENTORS), EnumSet.of(scope));
+ //XXX: Canceling
+ if (typeElements != null) {
+ l.addAll(typeElements);
+ }
+ }
+ return result;
+ } finally {
+ classIndexCumulative[0] += (System.currentTimeMillis() - startTime);
+ }
+ }
+
+ static List reverseSourceRootsInOrderOverride;
+
+ private List reverseSourceRootsInOrder(CompilationInfo info, URL thisSourceRoot, FileObject thisSourceRootFO, Map> sourceDeps, Map> binaryDeps, boolean interactive) {
+ if (reverseSourceRootsInOrderOverride != null) {
+ return reverseSourceRootsInOrderOverride;
+ }
+
+ Set sourceRootsSet;
+
+ if (sourceDeps.containsKey(thisSourceRoot)) {
+ sourceRootsSet = findReverseSourceRoots(thisSourceRoot, sourceDeps, info.getFileObject());
+ } else {
+ sourceRootsSet = new HashSet();
+
+ for (URL binary : findBinaryRootsForSourceRoot(thisSourceRootFO, binaryDeps)) {
+ List deps = binaryDeps.get(binary);
+
+ if (deps != null) {
+ sourceRootsSet.addAll(deps);
+ }
+ }
+ }
+
+ List sourceRoots;
+ try {
+ sourceRoots = new LinkedList(Utilities.topologicalSort(sourceDeps.keySet(), sourceDeps));
+ } catch (TopologicalSortException ex) {
+ if (interactive) {
+ Exceptions.attachLocalizedMessage(ex,NbBundle.getMessage(GoToImplementation.class, "ERR_CycleInDependencies"));
+ Exceptions.printStackTrace(ex);
+ } else {
+ LOG.log(Level.FINE, null, ex);
+ }
+ return null;
+ }
+
+ sourceRoots.retainAll(sourceRootsSet);
+
+ Collections.reverse(sourceRoots);
+
+ return sourceRoots;
+ }
+
+ private Map, Set>>> computeUsers(CompilationInfo info, FileObject thisSourceRoot, Set> baseHandles, long[] classIndexCumulative, boolean interactive) {
+ Map> sourceDeps = getDependencies(false);
+ Map> binaryDeps = getDependencies(true);
+
+ if (sourceDeps == null || binaryDeps == null) {
+ if (interactive) {
+ NotifyDescriptor nd = new NotifyDescriptor.Message(NbBundle.getMessage(GoToImplementation.class, "ERR_NoDependencies"), NotifyDescriptor.ERROR_MESSAGE);
+
+ DialogDisplayer.getDefault().notifyLater(nd);
+ } else {
+ LOG.log(Level.FINE, NbBundle.getMessage(GoToImplementation.class, "ERR_NoDependencies"));
+ }
+
+ return null;
+ }
+
+ URL thisSourceRootURL;
+
+ try {
+ thisSourceRootURL = thisSourceRoot.getURL();
+ } catch (FileStateInvalidException ex) {
+ Exceptions.printStackTrace(ex);
+ return null;
+ }
+
+ List sourceRoots = reverseSourceRootsInOrder(info, thisSourceRootURL, thisSourceRoot, sourceDeps, binaryDeps, interactive);
+
+ if (sourceRoots == null) {
+ return null;
+ }
+
+ Map, Set>> auxHandles = new HashMap, Set>>();
+
+ if (!sourceDeps.containsKey(thisSourceRootURL)) {
+ Set binaryRoots = new HashSet();
+
+ for (URL sr : sourceRoots) {
+ List deps = sourceDeps.get(sr);
+
+ if (deps != null) {
+ binaryRoots.addAll(deps);
+ }
+ }
+
+ binaryRoots.retainAll(binaryDeps.keySet());
+
+ for (ElementHandle handle : baseHandles) {
+ Set> types = computeUsers(ClasspathInfo.create(EMPTY, ClassPathSupport.createClassPath(binaryRoots.toArray(new URL[0])), EMPTY), SearchScope.DEPENDENCIES, Collections.singleton(handle), classIndexCumulative);
+
+ if (types == null/*canceled*/ || cancel.get()) {
+ return null;
+ }
+
+ auxHandles.put(handle, types);
+ }
+ }
+
+ Map, Set>>> result = new LinkedHashMap, Set>>>();
+
+ for (URL file : sourceRoots) {
+ for (ElementHandle base : baseHandles) {
+ if (cancel.get()) return null;
+
+ Set> baseTypes = new HashSet>();
+
+ baseTypes.add(base);
+
+ Set> aux = auxHandles.get(base);
+
+ if (aux != null) {
+ baseTypes.addAll(aux);
+ }
+
+ for (URL dep : sourceDeps.get(file)) {
+ Map, Set>> depTypesMulti = result.get(dep);
+ Set> depTypes = depTypesMulti != null ? depTypesMulti.get(base) : null;
+
+ if (depTypes != null) {
+ baseTypes.addAll(depTypes);
+ }
+ }
+
+ Set> types = computeUsers(file, baseTypes, classIndexCumulative);
+
+ if (types == null/*canceled*/ || cancel.get()) {
+ return null;
+ }
+
+ types.removeAll(baseTypes);
+
+ Map, Set>> currentUsers = result.get(file);
+
+ if (currentUsers == null) {
+ result.put(file, currentUsers = new LinkedHashMap, Set>>());
+ }
+
+ currentUsers.put(base, types);
+ }
+ }
+
+ return result;
+ }
+
+ private void findOverriddenAnnotations(
+ URL sourceRoot,
+ final Set> users,
+ final ElementHandle originalType,
+ final List> methods,
+ final Map, List> overriding) {
+ if (!users.isEmpty()) {
+ FileObject sourceRootFile = URLMapper.findFileObject(sourceRoot);
+ ClasspathInfo cpinfo = ClasspathInfo.create(sourceRootFile);
+
+ JavaSource js = JavaSource.create(cpinfo);
+
+ try {
+ js.runUserActionTask(new Task() {
+ public void run(CompilationController controller) throws Exception {
+ Set seenElements = new HashSet();
+ Element resolvedOriginalType = originalType.resolve(controller);
+
+ if (resolvedOriginalType == null) {
+ return ;
+ }
+
+ for (ElementHandle typeHandle : users) {
+ if (cancel.get()) return ;
+ TypeElement type = typeHandle.resolve(controller);
+
+ if (type == null || !seenElements.add(type)) {
+ continue;
+ }
+
+ Types types = controller.getTypes();
+
+ if (types.isSubtype(types.erasure(type.asType()), types.erasure(resolvedOriginalType.asType()))) {
+ List classOverriders = overriding.get(originalType);
+
+ if (classOverriders == null) {
+ overriding.put(originalType, classOverriders = new LinkedList());
+ }
+
+ classOverriders.add(new ElementDescription(controller, type, true));
+
+ for (ElementHandle originalMethodHandle : methods) {
+ ExecutableElement originalMethod = originalMethodHandle.resolve(controller);
+
+ if (originalMethod != null) {
+ ExecutableElement overrider = getImplementationOf(controller, originalMethod, type);
+
+ if (overrider == null) {
+ continue;
+ }
+
+ List overriddingMethods = overriding.get(originalMethodHandle);
+
+ if (overriddingMethods == null) {
+ overriding.put(originalMethodHandle, overriddingMethods = new ArrayList());
+ }
+
+ overriddingMethods.add(new ElementDescription(controller, overrider, true));
+ } else {
+ Logger.getLogger("global").log(Level.SEVERE, "IsOverriddenAnnotationHandler: originalMethod == null!"); //NOI18N
+ }
+ }
+ }
+ }
+ }
+ }, true);
+ } catch (Exception e) {
+ Exceptions.printStackTrace(e);
+ }
+ }
+ }
+
+ private static ExecutableElement getImplementationOf(CompilationInfo info, ExecutableElement overridee, TypeElement implementor) {
+ for (ExecutableElement overrider : ElementFilter.methodsIn(implementor.getEnclosedElements())) {
+ if (info.getElements().overrides(overrider, overridee, implementor)) {
+ return overrider;
+ }
+ }
+
+ return null;
+ }
+
+ static void performGoToAction(List declarations, Point position) {
+ String caption = NbBundle.getMessage(GoToImplementation.class, "LBL_ImplementorsOverriders");
+
+ PopupUtil.showPopup(new IsOverriddenPopup(caption, declarations), caption, position.x, position.y, true, 0);
+ }
+
+ static Map> dependenciesOverride;
+
+ private static Map> getDependencies(boolean binary) {
+ if (dependenciesOverride != null) {
+ return dependenciesOverride;
+ }
+
+ ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
+
+ if (l == null) {
+ return null;
+ }
+
+ Class clazz = null;
+ String method = null;
+
+ try {
+ clazz = l.loadClass("org.netbeans.modules.parsing.impl.indexing.friendapi.IndexingController");
+ method = binary ? "getBinaryRootDependencies" : "getRootDependencies";
+ } catch (ClassNotFoundException ex) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex);
+ try {
+ clazz = l.loadClass("org.netbeans.modules.parsing.impl.indexing.RepositoryUpdater");
+ method = binary ? "getDependencies" : "doesnotexist";
+ } catch (ClassNotFoundException inner) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, inner);
+ return null;
+ }
+ }
+
+ try {
+ Method getDefault = clazz.getDeclaredMethod("getDefault");
+ Object instance = getDefault.invoke(null);
+ Method dependenciesMethod = clazz.getDeclaredMethod(method);
+
+ return (Map>) dependenciesMethod.invoke(instance);
+ } catch (IllegalAccessException ex) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex);
+ return null;
+ } catch (IllegalArgumentException ex) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex);
+ return null;
+ } catch (InvocationTargetException ex) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex);
+ return null;
+ } catch (NoSuchMethodException ex) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex);
+ return null;
+ } catch (SecurityException ex) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex);
+ return null;
+ } catch (ClassCastException ex) {
+ Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex);
+ return null;
+ }
+ }
+
+}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationHandler.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeOverriding.java
rename from java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationHandler.java
rename to java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeOverriding.java
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationHandler.java
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/ComputeOverriding.java
@@ -42,19 +42,14 @@
package org.netbeans.modules.java.editor.overridden;
import com.sun.source.tree.CompilationUnitTree;
-import com.sun.source.tree.Tree;
-import java.io.IOException;
-import java.net.URL;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.Element;
@@ -66,123 +61,23 @@
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Position;
-import javax.swing.text.StyledDocument;
-import org.netbeans.api.java.classpath.ClassPath;
-import org.netbeans.api.java.classpath.ClassPath.Entry;
-import org.netbeans.api.java.queries.SourceForBinaryQuery;
-import org.netbeans.api.java.source.CancellableTask;
-import org.netbeans.api.java.source.Task;
-import org.netbeans.api.java.source.ClassIndex.SearchKind;
-import org.netbeans.api.java.source.ClasspathInfo;
-import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.ElementHandle;
-import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.SourceUtils;
-import org.netbeans.api.java.source.ClassIndex;
-import org.netbeans.spi.java.classpath.support.ClassPathSupport;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileUtil;
-import org.openide.text.NbDocument;
-import org.openide.util.Exceptions;
-import org.openide.util.NbBundle;
-import org.openide.util.RequestProcessor;
-import org.openide.util.TopologicalSortException;
-import org.openide.util.Utilities;
/**
*
* @author Jan Lahoda
*/
-public class IsOverriddenAnnotationHandler implements CancellableTask {
+public class ComputeOverriding {
- private static final boolean enableReverseLookups = Boolean.getBoolean("org.netbeans.java.editor.enableReverseLookups");
- static final Logger LOG = Logger.getLogger(IsOverriddenAnnotationHandler.class.getName());
+ static final Logger LOG = Logger.getLogger(ComputeOverriding.class.getName());
- private FileObject file;
+ private final AtomicBoolean cancel;
- public IsOverriddenAnnotationHandler(FileObject file) {
- this.file = file;
- Logger.getLogger("TIMER").log(Level.FINE, "IsOverriddenAnnotationHandler", new Object[] {file, this}); //NOI18N
- }
-
- private IsOverriddenVisitor visitor;
-
- public void run(CompilationInfo info) throws IOException {
- resume();
-
- StyledDocument doc = (StyledDocument) info.getDocument();
-
- if (doc == null) {
- LOG.log(Level.FINE, "Cannot get document!"); //NOI18N
- return ;
- }
-
- long startTime = System.currentTimeMillis();
-
- try {
- List annotations = process(info, doc);
-
- if (annotations == null) {
- //cancelled:
- return ;
- }
-
- newAnnotations(annotations);
- } finally {
- synchronized (this) {
- visitor = null;
- }
-
- Logger.getLogger("TIMER").log(Level.FINE, "Overridden in", //NOI18N
- new Object[] {file, System.currentTimeMillis() - startTime});
- }
- }
-
- private FileObject findSourceRoot() {
- final ClassPath cp = ClassPath.getClassPath(file, ClassPath.SOURCE);
- if (cp != null) {
- for (FileObject root : cp.getRoots()) {
- if (FileUtil.isParentOf(root, file))
- return root;
- }
- }
- //Null is a valid value for files which have no source path (default filesystem).
- return null;
- }
-
- //temporary hack:
- private synchronized Set findReverseSourceRoots(final FileObject thisSourceRoot, final FileObject thisFile) {
- final Object o = new Object();
- final Set reverseSourceRoots = new HashSet();
-
- RequestProcessor.getDefault().post(new Runnable() {
- public void run() {
- long startTime = System.currentTimeMillis();
- Set reverseSourceRootsInt = new HashSet(ReverseSourceRootsLookup.reverseSourceRootsLookup(thisSourceRoot));
- long endTime = System.currentTimeMillis();
-
- Logger.getLogger("TIMER").log(Level.FINE, "Find Reverse Source Roots", //NOI18N
- new Object[] {thisFile, endTime - startTime});
-
- synchronized (o) {
- reverseSourceRoots.addAll(reverseSourceRootsInt);
- }
-
- wakeUp();
- }
- });
-
- try {
- wait();
- } catch (InterruptedException ex) {
- Exceptions.printStackTrace(ex);
- }
-
- return reverseSourceRoots;
+ public ComputeOverriding(AtomicBoolean cancel) {
+ this.cancel = cancel;
}
public static AnnotationType detectOverrides(CompilationInfo info, TypeElement type, ExecutableElement ee, List result) {
@@ -201,7 +96,7 @@
for (ExecutableElement overridee : lee) {
if (info.getElements().overrides(ee, overridee, SourceUtils.getEnclosingTypeElement(ee))) {
if (seenMethods.add(overridee)) {
- result.add(new ElementDescription(info, overridee));
+ result.add(new ElementDescription(info, overridee, false));
}
}
}
@@ -219,16 +114,8 @@
return null;
}
- public List process(CompilationInfo info, final StyledDocument doc) {
- IsOverriddenVisitor v;
-
- synchronized (this) {
- if (isCanceled())
- return null;
-
- v = visitor = new IsOverriddenVisitor(doc, info);
- }
-
+ public Map, List> process(CompilationInfo info) {
+ IsOverriddenVisitor v = new IsOverriddenVisitor(info, cancel);
CompilationUnitTree unit = info.getCompilationUnit();
long startTime1 = System.currentTimeMillis();
@@ -238,27 +125,9 @@
long endTime1 = System.currentTimeMillis();
Logger.getLogger("TIMER").log(Level.FINE, "Overridden Scanner", //NOI18N
- new Object[] {file, endTime1 - startTime1});
+ new Object[] {info.getFileObject(), endTime1 - startTime1});
- Set reverseSourceRoots;
-
- if (enableReverseLookups) {
- FileObject thisSourceRoot = findSourceRoot();
- if (thisSourceRoot == null) {
- return null;
- }
-
- reverseSourceRoots = findReverseSourceRoots(thisSourceRoot, info.getFileObject());
-
- //XXX: special case "this" source root (no need to create a new JS and load the classes again for it):
- reverseSourceRoots.add(thisSourceRoot);
- } else {
- reverseSourceRoots = null;
- }
-
- LOG.log(Level.FINE, "reverseSourceRoots: {0}", reverseSourceRoots); //NOI18N
-
- List annotations = new ArrayList();
+ Map, List> result = new HashMap, List>();
for (ElementHandle td : v.type2Declaration.keySet()) {
if (isCanceled())
@@ -295,330 +164,30 @@
}
Set seenMethods = new HashSet();
- List overrides = new ArrayList();
-
+ List descriptions = new LinkedList();
+
for (ExecutableElement overridee : lee) {
if (info.getElements().overrides(ee, overridee, SourceUtils.getEnclosingTypeElement(ee))) {
if (seenMethods.add(overridee)) {
- overrides.add(new ElementDescription(info, overridee));
+ descriptions.add(new ElementDescription(info, overridee, false));
}
}
}
-
- if (!overrides.isEmpty()) {
- int position = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), v.declaration2Tree.get(methodHandle));
- Position pos = getPosition(doc, position);
-
- if (pos == null) {
- //cannot compute the position, skip
- continue;
- }
-
- StringBuffer tooltip = new StringBuffer();
- boolean wasOverrides = false;
-
- boolean newline = false;
-
- for (ElementDescription ed : overrides) {
- if (newline) {
- tooltip.append("\n"); //NOI18N
- }
-
- newline = true;
-
- if (ed.getModifiers().contains(Modifier.ABSTRACT)) {
- tooltip.append(NbBundle.getMessage(IsOverriddenAnnotationHandler.class, "TP_Implements", ed.getDisplayName()));
- } else {
- tooltip.append(NbBundle.getMessage(IsOverriddenAnnotationHandler.class, "TP_Overrides", ed.getDisplayName()));
- wasOverrides = true;
- }
- }
-
- annotations.add(new IsOverriddenAnnotation(doc, pos, wasOverrides ? AnnotationType.OVERRIDES : AnnotationType.IMPLEMENTS, tooltip.toString(), overrides));
- }
- }
-
- if (enableReverseLookups) {
- String typeOverridden = null;
- AnnotationType typeType = null;
- TypeElement resolved = td.resolve(info);
-
-
- if (resolved == null) {
- Logger.getLogger("global").log(Level.SEVERE, "IsOverriddenAnnotationHandler: resolved == null!"); //NOI18N
- continue;
- }
-
- if (resolved.getKind().isInterface()) {
- typeOverridden = NbBundle.getMessage(IsOverriddenAnnotationHandler.class, "CAP_HasImplementations");
- typeType = AnnotationType.HAS_IMPLEMENTATION;
- }
-
- if (resolved.getKind().isClass()) {
- typeOverridden = NbBundle.getMessage(IsOverriddenAnnotationHandler.class, "CAP_IsOverridden");
- typeType = AnnotationType.IS_OVERRIDDEN;
- }
-
- final Map, List> overriding = new HashMap, List>();
- final List overridingClasses = new ArrayList();
-
- long startTime = System.currentTimeMillis();
- long[] classIndexTime = new long[1];
- final Map>> users = computeUsers(reverseSourceRoots, ElementHandle.create(resolved), classIndexTime);
- long endTime = System.currentTimeMillis();
-
- if (users == null) {
- return null;
- }
-
- Logger.getLogger("TIMER").log(Level.FINE, "Overridden Users Class Index", //NOI18N
- new Object[] {file, classIndexTime[0]});
- Logger.getLogger("TIMER").log(Level.FINE, "Overridden Users", //NOI18N
- new Object[] {file, endTime - startTime});
-
- for (Map.Entry>> data : users.entrySet()) {
- if (isCanceled())
- return null;
-
- findOverriddenAnnotations(data.getKey(), data.getValue(), td, v.type2Declaration.get(td), overriding, overridingClasses);
- }
-
- if (!overridingClasses.isEmpty()) {
- Tree t = v.declaration2Class.get(td);
-
- if (t != null) {
- Position pos = getPosition(doc, (int) info.getTrees().getSourcePositions().getStartPosition(unit, t));
-
- if (pos == null) {
- //cannot compute the position, skip
- continue;
- }
-
- annotations.add(new IsOverriddenAnnotation(doc, pos, typeType, typeOverridden.toString(), overridingClasses));
- }
- }
-
- for (ElementHandle original : overriding.keySet()) {
- if (isCanceled())
- return null;
-
- Position pos = getPosition(doc, (int) info.getTrees().getSourcePositions().getStartPosition(unit, v.declaration2Tree.get(original)));
-
- if (pos == null) {
- //cannot compute the position, skip
- continue;
- }
-
- Set mods = original.resolve(info).getModifiers();
- String tooltip = null;
-
- if (mods.contains(Modifier.ABSTRACT)) {
- tooltip = NbBundle.getMessage(IsOverriddenAnnotationHandler.class, "TP_HasImplementations");
- } else {
- tooltip = NbBundle.getMessage(IsOverriddenAnnotationHandler.class, "TP_IsOverridden");
- }
-
- IsOverriddenAnnotation ann = new IsOverriddenAnnotation(doc, pos, mods.contains(Modifier.ABSTRACT) ? AnnotationType.HAS_IMPLEMENTATION : AnnotationType.IS_OVERRIDDEN, tooltip, overriding.get(original));
-
- annotations.add(ann);
- }
+
+ result.put(methodHandle, descriptions);
}
}
if (isCanceled())
return null;
else
- return annotations;
- }
-
- private static final ClassPath EMPTY = ClassPathSupport.createClassPath(new URL[0]);
-
- private Set> computeUsers(FileObject source, Set> base, long[] classIndexCumulative) {
- ClasspathInfo cpinfo = ClasspathInfo.create(/*source);/*/EMPTY, EMPTY, ClassPathSupport.createClassPath(new FileObject[] {source}));
-
- long startTime = System.currentTimeMillis();
-
- try {
- List> l = new LinkedList>(base);
- Set> result = new HashSet>();
-
- while (!l.isEmpty()) {
- ElementHandle eh = l.remove(0);
-
- result.add(eh);
- Set> typeElements = cpinfo.getClassIndex().getElements(eh, Collections.singleton(SearchKind.IMPLEMENTORS), EnumSet.of(ClassIndex.SearchScope.SOURCE));
- //XXX: Canceling
- if (typeElements != null) {
- l.addAll(typeElements);
- }
- }
return result;
- } finally {
- classIndexCumulative[0] += (System.currentTimeMillis() - startTime);
- }
- }
-
- private Map>> computeUsers(Set sources, ElementHandle base, long[] classIndexCumulative) {
- Map> edges = new HashMap>();
- Map> dependsOn = new HashMap>();
-
- for (FileObject source : sources) {
- edges.put(source, new ArrayList());
- }
-
- for (FileObject source : sources) {
- List deps = new ArrayList();
-
- dependsOn.put(source, deps);
-
- for (Entry entry : ClassPath.getClassPath(source, ClassPath.COMPILE).entries()) { //TODO: should also check BOOT?
- for (FileObject s : SourceForBinaryQuery.findSourceRoots(entry.getURL()).getRoots()) {
- Collection targets = edges.get(s);
-
- if (targets != null) {
- targets.add(source);
- }
-
- deps.add(s);
- }
- }
- }
-
- List sourceRoots = new ArrayList(sources);
-
- try {
- Utilities.topologicalSort(sourceRoots, edges);
- } catch (TopologicalSortException ex) {
- LOG.log(Level.WARNING, "internal error", ex); //NOI18N
- return null;
- }
-
- Map>> result = new HashMap>>();
-
- for (FileObject file : sourceRoots) {
- Set> baseTypes = new HashSet>();
-
- baseTypes.add(base);
-
- for (FileObject dep : dependsOn.get(file)) {
- Set> depTypes = result.get(dep);
-
- if (depTypes != null) {
- baseTypes.addAll(depTypes);
- }
- }
-
- Set> types = computeUsers(file, baseTypes, classIndexCumulative);
-
- types.removeAll(baseTypes);
-
- result.put(file, types);
- }
-
- return result;
- }
- private void findOverriddenAnnotations(
- FileObject sourceRoot,
- final Set> users,
- final ElementHandle originalType,
- final List> methods,
- final Map, List> overriding,
- final List overridingClasses) {
- ClasspathInfo cpinfo = ClasspathInfo.create(sourceRoot);
-
- if (!users.isEmpty()) {
- JavaSource js = JavaSource.create(cpinfo);
-
- try {
- js.runUserActionTask(new Task() {
-
- public void run(CompilationController controller) throws Exception {
- Set seenElements = new HashSet();
-
- for (ElementHandle typeHandle : users) {
- if (isCanceled())
- return;
- TypeElement type = typeHandle.resolve(controller);
- Element resolvedOriginalType = originalType.resolve(controller);
-
- if (!seenElements.add(resolvedOriginalType))
- continue;
-
- if (controller.getTypes().isSubtype(type.asType(), resolvedOriginalType.asType())) {
- overridingClasses.add(new ElementDescription(controller, type));
-
- for (ElementHandle originalMethodHandle : methods) {
- ExecutableElement originalMethod = originalMethodHandle.resolve(controller);
-
- if (originalMethod != null) {
- ExecutableElement overrider = getImplementationOf(controller, originalMethod, type);
-
- if (overrider == null)
- continue;
-
- List overriddingMethods = overriding.get(originalMethodHandle);
-
- if (overriddingMethods == null) {
- overriding.put(originalMethodHandle, overriddingMethods = new ArrayList());
- }
-
- overriddingMethods.add(new ElementDescription(controller, overrider));
- } else {
- Logger.getLogger("global").log(Level.SEVERE, "IsOverriddenAnnotationHandler: originalMethod == null!"); //NOI18N
- }
- }
- }
- }
- }
- },true);
- } catch (Exception e) {
- Exceptions.printStackTrace(e);
- }
- }
- }
-
- private ExecutableElement getImplementationOf(CompilationInfo info, ExecutableElement overridee, TypeElement implementor) {
- for (ExecutableElement overrider : ElementFilter.methodsIn(implementor.getEnclosedElements())) {
- if (info.getElements().overrides(overrider, overridee, implementor)) {
- return overrider;
- }
- }
-
- return null;
- }
-
- private boolean canceled;
-
- public synchronized void cancel() {
- canceled = true;
-
- if (visitor != null) {
- visitor.cancel();
- }
-
- wakeUp();
- }
-
- private synchronized void resume() {
- canceled = false;
- }
-
- private synchronized void wakeUp() {
- notifyAll();
}
private synchronized boolean isCanceled() {
- return canceled;
+ return cancel.get();
}
- private void newAnnotations(List as) {
- AnnotationsHolder a = AnnotationsHolder.get(file);
-
- if (a != null) {
- a.setNewAnnotations(as);
- }
- }
-
private static void sortOutMethods(CompilationInfo info, Map> where, Element td, boolean current) {
if (current) {
Map> newlyAdded = new HashMap>();
@@ -662,27 +231,4 @@
}
}
- private static Position getPosition(final StyledDocument doc, final int offset) {
- class Impl implements Runnable {
- private Position pos;
- public void run() {
- if (offset < 0 || offset >= doc.getLength())
- return ;
-
- try {
- pos = doc.createPosition(offset - NbDocument.findLineColumn(doc, offset));
- } catch (BadLocationException ex) {
- //should not happen?
- LOG.log(Level.FINE, null, ex);
- }
- }
- }
-
- Impl i = new Impl();
-
- doc.render(i);
-
- return i.pos;
- }
-
}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/ElementDescription.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/ElementDescription.java
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/ElementDescription.java
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/ElementDescription.java
@@ -40,6 +40,7 @@
*/
package org.netbeans.modules.java.editor.overridden;
+import java.awt.Image;
import java.util.Collection;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
@@ -57,6 +58,7 @@
import org.netbeans.api.java.source.ui.ElementIcons;
import org.netbeans.modules.editor.java.Utilities;
import org.openide.filesystems.FileObject;
+import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
/**
@@ -71,13 +73,15 @@
private ElementHandle outtermostElement;
private Collection modifiers;
private String displayName;
-
- public ElementDescription(CompilationInfo info, Element element) {
+ private final boolean overriddenFlag;
+
+ public ElementDescription(CompilationInfo info, Element element, boolean overriddenFlag) {
this.originalCPInfo = info.getClasspathInfo();
this.handle = ElementHandle.create(element);
this.outtermostElement = ElementHandle.create(SourceUtils.getOutermostEnclosingTypeElement(element));
this.modifiers = element.getModifiers();
this.displayName = element.accept(new ElementNameVisitor(), true);
+ this.overriddenFlag = overriddenFlag;
}
public FileObject getSourceFile() {
@@ -93,9 +97,19 @@
}
public Icon getIcon() {
- return ElementIcons.getElementIcon(handle.getKind(), modifiers);
+ Image badge;
+
+ if (overriddenFlag) {
+ badge = ImageUtilities.loadImage("org/netbeans/modules/java/editor/resources/is-overridden-badge.png");
+ } else {
+ badge = ImageUtilities.loadImage("org/netbeans/modules/java/editor/resources/overrides-badge.png");
+ }
+
+ Image icon = ImageUtilities.icon2Image(ElementIcons.getElementIcon(handle.getKind(), modifiers));
+
+ return ImageUtilities.image2Icon(ImageUtilities.mergeImages(icon, badge, 16, 0));
}
-
+
public String getDisplayName() {
return displayName;
}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/GoToImplementation.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/GoToImplementation.java
new file mode 100644
--- /dev/null
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/GoToImplementation.java
@@ -0,0 +1,212 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.java.editor.overridden;
+
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.swing.SwingUtilities;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.editor.EditorActionRegistration;
+import org.netbeans.api.java.lexer.JavaTokenId;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.editor.BaseAction;
+import org.netbeans.editor.ext.ExtKit;
+import org.netbeans.modules.editor.java.JavaKit;
+import org.netbeans.modules.java.editor.semantic.Utilities;
+import org.openide.awt.StatusDisplayer;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
+
+@EditorActionRegistration(
+ name = "goto-implementation",
+ mimeType = JavaKit.JAVA_MIME_TYPE,
+ popupText = "#CTL_GoToImplementation"
+)
+public final class GoToImplementation extends BaseAction {
+
+ public GoToImplementation() {
+ super(SAVE_POSITION | ABBREV_RESET);
+// putValue(SHORT_DESCRIPTION, NbBundle.getMessage(GoToImplementation.class, "CTL_GoToImplementation"));
+// String name = NbBundle.getMessage(GoToImplementation.class, "CTL_GoToImplementation_trimmed");
+// putValue(ExtKit.TRIMMED_TEXT,name);
+// putValue(POPUP_MENU_TEXT, name);
+ }
+
+ public void actionPerformed(ActionEvent e, final JTextComponent c) {
+ try {
+ JavaSource.forDocument(c.getDocument()).runUserActionTask(new Task() {
+ public void run(CompilationController parameter) throws Exception {
+ parameter.toPhase(Phase.RESOLVED);
+
+ Element el = resolveElement(parameter, c.getCaretPosition());
+
+ if (el == null) {
+ StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(GoToImplementation.class, "LBL_NoMethod"));
+ return ;
+ }
+
+ TypeElement type = el.getKind() == ElementKind.METHOD ? (TypeElement) el.getEnclosingElement() : (TypeElement) el;
+ ExecutableElement method = el.getKind() == ElementKind.METHOD ? (ExecutableElement) el : null;
+
+ Map, List> overriding = new ComputeOverriders(new AtomicBoolean()).process(parameter, type, method, true);
+
+ List overridingMethods = overriding.get(ElementHandle.create(el));
+
+ if (overridingMethods == null || overridingMethods.isEmpty()) {
+ String key = el.getKind() == ElementKind.METHOD ? "LBL_NoOverridingMethod" : "LBL_NoOverridingType";
+
+ StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(GoToImplementation.class, key));
+ return;
+ }
+
+ Point p = new Point(c.modelToView(c.getCaretPosition()).getLocation());
+
+ SwingUtilities.convertPointToScreen(p, c);
+
+ performGoToAction(overridingMethods, p);
+ }
+ }, true);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+
+ static void performGoToAction(List declarations, Point position) {
+ String caption = NbBundle.getMessage(GoToImplementation.class, "LBL_ImplementorsOverriders");
+
+ PopupUtil.showPopup(new IsOverriddenPopup(caption, declarations), caption, position.x, position.y, true, 0);
+ }
+
+ private static Set SUPPORTED_ELEMENTS = EnumSet.of(ElementKind.METHOD, ElementKind.ANNOTATION_TYPE, ElementKind.CLASS, ElementKind.ENUM, ElementKind.INTERFACE);
+
+ private static Element resolveElement(CompilationInfo info, int caret) {
+ TreePath tp = info.getTreeUtilities().pathFor(caret);
+
+ TokenSequence ts = info.getTokenHierarchy().tokenSequence(JavaTokenId.language());
+
+ ts.move(caret);
+
+ boolean isIdentifier = ts.moveNext() && ts.token().id() == JavaTokenId.IDENTIFIER;
+
+ if (!isIdentifier) {
+ ts.move(caret);
+ isIdentifier = ts.movePrevious() && ts.token().id() == JavaTokenId.IDENTIFIER;
+ }
+
+ if (isIdentifier) {
+ Element elementUnderCaret = info.getTrees().getElement(tp);
+
+ if (elementUnderCaret != null && SUPPORTED_ELEMENTS.contains(elementUnderCaret.getKind())) {
+ return (Element) elementUnderCaret;
+ }
+ }
+
+ Element el = resolveHeader(tp, info, caret);
+
+ if (el == null) {
+ tp = info.getTreeUtilities().pathFor(caret + 1);
+ el = resolveHeader(tp, info, caret);
+ }
+
+ return el;
+ }
+
+ private static Element resolveHeader(TreePath tp, CompilationInfo info, int caret) {
+ while (tp.getLeaf().getKind() != Kind.METHOD && tp.getLeaf().getKind() != Kind.CLASS && tp.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
+ tp = tp.getParentPath();
+ }
+
+ if (tp.getLeaf().getKind() == Kind.COMPILATION_UNIT) {
+ return null;
+ }
+
+ long bodyStart;
+
+ if (tp.getLeaf().getKind() == Kind.METHOD) {
+ MethodTree mt = (MethodTree) tp.getLeaf();
+ SourcePositions sp = info.getTrees().getSourcePositions();
+ BlockTree body = mt.getBody();
+ bodyStart = body != null ? sp.getStartPosition(info.getCompilationUnit(), body) : Integer.MAX_VALUE;
+ } else {
+ assert tp.getLeaf().getKind() == Kind.CLASS;
+ Document doc = info.getSnapshot().getSource().getDocument(false);
+
+ if (doc == null) {
+ return null;
+ }
+
+ bodyStart = Utilities.findBodyStart(tp.getLeaf(), info.getCompilationUnit(), info.getTrees().getSourcePositions(), doc);
+ }
+
+ if (caret >= bodyStart) {
+ return null;
+ }
+
+ Element el = info.getTrees().getElement(tp);
+
+ if (el == null || !SUPPORTED_ELEMENTS.contains(el.getKind())) {
+ return null;
+ }
+
+ return (Element) el;
+ }
+
+}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/GoToSuperTypeAction.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/GoToSuperTypeAction.java
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/GoToSuperTypeAction.java
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/GoToSuperTypeAction.java
@@ -117,7 +117,7 @@
ExecutableElement ee = (ExecutableElement) resolved;
- type[0] = IsOverriddenAnnotationHandler.detectOverrides(parameter, (TypeElement) ee.getEnclosingElement(), ee, result);
+ type[0] = ComputeOverriding.detectOverrides(parameter, (TypeElement) ee.getEnclosingElement(), ee, result);
}
}, true);
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationAction.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationAction.java
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationAction.java
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationAction.java
@@ -24,7 +24,7 @@
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
@@ -41,13 +41,28 @@
package org.netbeans.modules.java.editor.overridden;
import java.awt.Point;
+import java.awt.Toolkit;
import java.awt.event.ActionEvent;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.MissingResourceException;
+import java.util.Set;
import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
+import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
+import org.netbeans.api.java.source.ui.ElementOpen;
import org.netbeans.editor.AnnotationDesc;
import org.netbeans.editor.Annotations;
import org.netbeans.editor.BaseDocument;
@@ -57,7 +72,6 @@
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
-import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
/**
@@ -65,7 +79,7 @@
* @author Jan Lahoda
*/
public final class IsOverriddenAnnotationAction extends AbstractAction {
-
+
public IsOverriddenAnnotationAction() {
putValue(NAME, NbBundle.getMessage(IsOverriddenAnnotationAction.class,
"CTL_IsOverriddenAnnotationAction")); //NOI18N
@@ -119,7 +133,7 @@
AnnotationsHolder ah = AnnotationsHolder.get(file);
if (ah == null) {
- IsOverriddenAnnotationHandler.LOG.log(Level.INFO, "component=" + component + " does not have attached a IsOverriddenAnnotationHandler"); //NOI18N
+ Logger.getLogger(IsOverriddenAnnotationAction.class.getName()).log(Level.INFO, "component=" + component + " does not have attached a IsOverriddenAnnotationHandler"); //NOI18N
return null;
}
@@ -134,13 +148,42 @@
return null;
}
+ private List findAnnotations(JTextComponent component, int offset) {
+ FileObject file = getFile(component);
+
+ if (file == null) {
+ if (ErrorManager.getDefault().isLoggable(ErrorManager.WARNING)) {
+ ErrorManager.getDefault().log(ErrorManager.WARNING, "component=" + component + " does not have a file specified in the document."); //NOI18N
+ }
+ return null;
+ }
+
+ AnnotationsHolder ah = AnnotationsHolder.get(file);
+
+ if (ah == null) {
+ Logger.getLogger(IsOverriddenAnnotationAction.class.getName()).log(Level.INFO, "component=" + component + " does not have attached a IsOverriddenAnnotationHandler"); //NOI18N
+
+ return null;
+ }
+
+ List annotations = new LinkedList();
+
+ for(IsOverriddenAnnotation a : ah.getAnnotations()) {
+ if (a.getPosition().getOffset() == offset) {
+ annotations.add(a);
+ }
+ }
+
+ return annotations;
+ }
+
boolean invokeDefaultAction(final JTextComponent comp) {
final Document doc = comp.getDocument();
if (doc instanceof BaseDocument) {
final int currentPosition = comp.getCaretPosition();
final Annotations annotations = ((BaseDocument) doc).getAnnotations();
- final IsOverriddenAnnotation[] annotation = new IsOverriddenAnnotation[1];
+ final Map> caption2Descriptions = new LinkedHashMap>();
final Point[] p = new Point[1];
doc.render(new Runnable() {
@@ -148,26 +191,101 @@
try {
int line = Utilities.getLineOffset((BaseDocument) doc, currentPosition);
int startOffset = Utilities.getRowStartFromLineOffset((BaseDocument) doc, line);
+ p[0] = comp.modelToView(startOffset).getLocation();
AnnotationDesc desc = annotations.getActiveAnnotation(line);
- p[0] = comp.modelToView(startOffset).getLocation();
- annotation[0] = findAnnotation(comp, desc, startOffset);
+
+ if (desc == null) {
+ return ;
+ }
+
+ Collection annots;
+
+ if (COMBINED_TYPES.contains(desc.getAnnotationType())) {
+ annots = findAnnotations(comp, startOffset);
+ } else {
+ annots = Collections.singletonList(findAnnotation(comp, desc, startOffset));
+ }
+
+ for (IsOverriddenAnnotation a : annots) {
+ if (a != null) {
+ caption2Descriptions.put(computeCaption(a.getType(), a.getShortDescription()), a.getDeclarations());
+ }
+ }
} catch (BadLocationException ex) {
- Exceptions.printStackTrace(ex);
+ ErrorManager.getDefault().notify(ex);
}
}
});
- if (annotation[0] == null)
+ if (caption2Descriptions.isEmpty())
return false;
JumpList.checkAddEntry(comp, currentPosition);
-
- annotation[0].mouseClicked(comp, p[0]);
+
+ mouseClicked(caption2Descriptions, comp, p[0]);
return true;
}
return false;
}
-
+
+ private static void mouseClicked(Map> caption2Descriptions, JTextComponent c, Point p) {
+ if (caption2Descriptions.size() == 1 && caption2Descriptions.values().iterator().next().size() == 1) {
+ ElementDescription desc = caption2Descriptions.values().iterator().next().get(0);
+ FileObject file = desc.getSourceFile();
+
+ if (file != null) {
+ ElementOpen.open(file, desc.getHandle());
+ } else {
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ return ;
+ }
+
+ Point position = new Point(p);
+
+ SwingUtilities.convertPointToScreen(position, c);
+
+ StringBuilder caption = new StringBuilder();
+ List descriptions = new LinkedList();
+ boolean first = true;
+
+ for (Entry> e : caption2Descriptions.entrySet()) {
+ if (!first) {
+ caption.append("/");
+ }
+ first = false;
+ caption.append(e.getKey());
+ descriptions.addAll(e.getValue());
+ }
+
+ PopupUtil.showPopup(new IsOverriddenPopup(caption.toString(), descriptions), caption.toString(), position.x, position.y, true, 0);
+ }
+
+ private static String computeCaption(AnnotationType type, String shortDescription) throws MissingResourceException, IllegalStateException {
+ String caption;
+ switch (type) {
+ case IMPLEMENTS:
+ caption = NbBundle.getMessage(IsOverriddenAnnotation.class, "CAP_Implements");
+ break;
+ case OVERRIDES:
+ caption = NbBundle.getMessage(IsOverriddenAnnotation.class, "CAP_Overrides");
+ break;
+ case HAS_IMPLEMENTATION:
+ case IS_OVERRIDDEN:
+ caption = shortDescription;
+ break;
+ default:
+ throw new IllegalStateException("Currently not implemented: " + type); //NOI18N
+ }
+ return caption;
+ }
+
+ private static final Set COMBINED_TYPES = new HashSet(Arrays.asList(
+ "org-netbeans-modules-editor-java-implements-has-implementations-combined",
+ "org-netbeans-modules-editor-java-implements-is-overridden-combined",
+ "org-netbeans-modules-editor-java-override-is-overridden-combined"
+ ));
}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationHandlerFactory.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationHandlerFactory.java
deleted file mode 100644
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenAnnotationHandlerFactory.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * Contributor(s):
- *
- * The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
- * Microsystems, Inc. All Rights Reserved.
- *
- * If you wish your version of this file to be governed by only the CDDL
- * or only the GPL Version 2, indicate your decision by adding
- * "[Contributor] elects to include this software in this distribution
- * under the [CDDL or GPL Version 2] license." If you do not indicate a
- * single choice of license, a recipient has the option to distribute
- * your version of this file under either the CDDL, the GPL Version 2 or
- * to extend the choice of license to its licensees as provided above.
- * However, if you add GPL Version 2 code and therefore, elected the GPL
- * Version 2 license, then the option applies only if the new code is
- * made subject to such option by the copyright holder.
- */
-package org.netbeans.modules.java.editor.overridden;
-
-import org.netbeans.api.java.source.CancellableTask;
-import org.netbeans.api.java.source.CompilationInfo;
-import org.netbeans.api.java.source.JavaSource.Phase;
-import org.netbeans.api.java.source.JavaSource.Priority;
-import org.netbeans.api.java.source.support.EditorAwareJavaSourceTaskFactory;
-import org.openide.filesystems.FileObject;
-
-/**
- *
- * @author Jan Lahoda
- */
-@org.openide.util.lookup.ServiceProvider(service=org.netbeans.api.java.source.JavaSourceTaskFactory.class)
-public class IsOverriddenAnnotationHandlerFactory extends EditorAwareJavaSourceTaskFactory {
-
- /**
- * Creates a new instance of IsOverriddenAnnotationHandlerFactory
- */
- public IsOverriddenAnnotationHandlerFactory() {
- super(Phase.RESOLVED, Priority.MIN);
- }
-
- public CancellableTask createTask(FileObject file) {
- return new IsOverriddenAnnotationHandler(file);
- }
-
-}
diff --git a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenVisitor.java b/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenVisitor.java
--- a/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenVisitor.java
+++ b/java.editor/src/org/netbeans/modules/java/editor/overridden/IsOverriddenVisitor.java
@@ -47,16 +47,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
-import javax.swing.text.Document;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.api.java.source.support.CancellableTreePathScanner;
-import org.netbeans.api.java.source.ClassIndex;
/**
*
@@ -65,7 +64,6 @@
class IsOverriddenVisitor extends CancellableTreePathScanner {
private CompilationInfo info;
- private Document doc;
Map, List>> type2Declaration;
Map, MethodTree> declaration2Tree;
@@ -73,8 +71,8 @@
private Map> type2Handle;
- IsOverriddenVisitor(Document doc, CompilationInfo info) {
- this.doc = doc;
+ IsOverriddenVisitor(CompilationInfo info, AtomicBoolean cancel) {
+ super(cancel);
this.info = info;
type2Declaration = new HashMap, List>>();
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/Bundle.properties b/java.editor/src/org/netbeans/modules/java/editor/resources/Bundle.properties
--- a/java.editor/src/org/netbeans/modules/java/editor/resources/Bundle.properties
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/Bundle.properties
@@ -23,7 +23,7 @@
# Contributor(s):
#
# The Original Software is NetBeans. The Initial Developer of the Original
-# Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+# Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
# Microsystems, Inc. All Rights Reserved.
#
# If you wish your version of this file to be governed by only the CDDL
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/DefaultKeyBindings.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/DefaultKeyBindings.xml
--- a/java.editor/src/org/netbeans/modules/java/editor/resources/DefaultKeyBindings.xml
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/DefaultKeyBindings.xml
@@ -51,6 +51,7 @@
+
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/has-implementations-annotation.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/has-implementations-annotation.xml
--- a/java.editor/src/org/netbeans/modules/java/editor/resources/has-implementations-annotation.xml
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/has-implementations-annotation.xml
@@ -44,7 +44,7 @@
"-//NetBeans//DTD annotation type 1.0//EN"
"http://www.netbeans.org/dtds/annotation-type-1_0.dtd">
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/implements-annotation.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/implements-annotation.xml
--- a/java.editor/src/org/netbeans/modules/java/editor/resources/implements-annotation.xml
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/implements-annotation.xml
@@ -44,8 +44,8 @@
"-//NetBeans//DTD annotation type 1.1//EN"
"http://www.netbeans.org/dtds/annotation-type-1_1.dtd">
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/implements-has-implementations-combined.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/implements-has-implementations-combined.xml
new file mode 100644
--- /dev/null
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/implements-has-implementations-combined.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/implements-is-overridden-combined.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/implements-is-overridden-combined.xml
new file mode 100644
--- /dev/null
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/implements-is-overridden-combined.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/is-overridden-annotation.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/is-overridden-annotation.xml
--- a/java.editor/src/org/netbeans/modules/java/editor/resources/is-overridden-annotation.xml
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/is-overridden-annotation.xml
@@ -45,7 +45,7 @@
"http://www.netbeans.org/dtds/annotation-type-1_1.dtd">
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/is-overridden-badge.png b/java.editor/src/org/netbeans/modules/java/editor/resources/is-overridden-badge.png
new file mode 100644
index 0000000000000000000000000000000000000000..72adb7d54ddfd0be5ebe80b8acdd69b35014c944
GIT binary patch
literal 210
zc%17D@N?(olHy`uVBq!ia0vp^>_9BQ!3HF6HKu+5QjEnx?oJHr&dIz4a@dl*-CY>|
zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8kRc_WzOL*ySw%(EdFIWtssIW}mbgZgIOpf)
zrskC}I2WZRmZYXAlxLP?D7bt2281{Ai31hsdb&7j+ghW9_Nvb!FF3V_^84%(m6G;+PmvBZH@_pUXO@geCxbOgcCK
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/layer.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/layer.xml
--- a/java.editor/src/org/netbeans/modules/java/editor/resources/layer.xml
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/layer.xml
@@ -118,6 +118,7 @@
+
@@ -300,6 +301,9 @@
+
+
+
@@ -431,6 +435,9 @@
+
+
+
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/override-is-overridden-combined.png b/java.editor/src/org/netbeans/modules/java/editor/resources/override-is-overridden-combined.png
new file mode 100644
index 0000000000000000000000000000000000000000..339a3d24214ced8433fba3a897e74bfcdeb386bd
GIT binary patch
literal 547
zc$@(v0^I$HP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXM!
z2owMV4M8*j00E;(L_t(I%cYaSOB+!T#($Ho(Ga5*Z7mf=5f-uysF&a&9$ErI=&9&Y
zEd8enT0!vU)vE^&QZKgDs6irBv@P1wU>nS4&AR(~c`KW30jaVBnEx=uo`@=AUfN~OWfCS(I4|LuI8h{cJrN?d>L0qp9
zFMTaKA5L~CpC6%=&-kE8c09+k;R)$5;)uvCtDs5HAhmb8TYZ1Lh56W`r#D5-t#SOl
z#Kn(uUQW(4HI_91Uo$WOpAbcF_wx=TPeySXbyn8i;`ts{+9KJPV7t7@)L1qF)O5YC
zHTV^X=)
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/override-is-overridden-combined.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/override-is-overridden-combined.xml
new file mode 100644
--- /dev/null
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/override-is-overridden-combined.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/overrides-annotation.xml b/java.editor/src/org/netbeans/modules/java/editor/resources/overrides-annotation.xml
--- a/java.editor/src/org/netbeans/modules/java/editor/resources/overrides-annotation.xml
+++ b/java.editor/src/org/netbeans/modules/java/editor/resources/overrides-annotation.xml
@@ -44,7 +44,7 @@
"-//NetBeans//DTD annotation type 1.0//EN"
"http://www.netbeans.org/dtds/annotation-type-1_0.dtd">
diff --git a/java.editor/src/org/netbeans/modules/java/editor/resources/overrides-badge.png b/java.editor/src/org/netbeans/modules/java/editor/resources/overrides-badge.png
new file mode 100644
index 0000000000000000000000000000000000000000..a966cafb5a01d4a94d0fa46e4c2c7468e35aabf1
GIT binary patch
literal 240
zc%17D@N?(olHy`uVBq!ia0vp^>_E)P!3HG%MVKuHQjEnx?oJHr&dIz4a@dl*-CY>|
zgW!U_%O``>7I;J!Gca%qgD@k*tT_@OLrOe-UD^
zR&9_oS;+d@LE()~=R+SWhC>^t2G}LN>();
+ ComputeOverriders.dependenciesOverride.put(r1, Collections.emptyList());
+ ComputeOverriders.dependenciesOverride.put(r2, Collections.singletonList(r1));
+ ComputeOverriders.dependenciesOverride.put(r3, Collections.singletonList(r1));
+ ComputeOverriders.dependenciesOverride.put(r4, Arrays.asList(r1, r2));
+
+ Map, List> output = new ComputeOverriders(new AtomicBoolean()).process(info, null, null, false);
+ Map> outputStrings = new LinkedHashMap>();
+
+ for (Entry, List> e : output.entrySet()) {
+ List descs = new LinkedList();
+
+ for (ElementDescription ed : e.getValue()) {
+ descs.add(ed.getHandle().toString());
+ }
+
+ outputStrings.put(e.getKey().toString(), descs);
+ }
+
+ Map> golden = new LinkedHashMap>();
+
+ golden.put("ElementHandle[kind=CLASS; sigs=test.Test ]", Arrays.asList(
+ "ElementHandle[kind=CLASS; sigs=dep.Dep ]",
+ "ElementHandle[kind=CLASS; sigs=dep3.Dep3 ]",
+ "ElementHandle[kind=CLASS; sigs=dep4.Dep4 ]"
+ ));
+ golden.put("ElementHandle[kind=METHOD; sigs=test.Test test ()V ]", Arrays.asList(
+ "ElementHandle[kind=METHOD; sigs=dep.Dep test ()V ]",
+ "ElementHandle[kind=METHOD; sigs=dep3.Dep3 test ()V ]",
+ "ElementHandle[kind=METHOD; sigs=dep4.Dep4 test ()V ]"
+ ));
+
+ assertEquals(golden, outputStrings);
+ }
+
+
+ private Map root2ClassPath = new HashMap();
+ private Map root2BuildRoot = new HashMap();
+ private Map buildRoot2Source = new HashMap();
+
+ private FileObject sourceDirectories;
+ private FileObject buildDirectories;
+
+ private void prepareSourceRoot(String name, String... dependsOn) throws Exception {
+ FileObject src = FileUtil.createFolder(sourceDirectories, name);
+ FileObject build = FileUtil.createFolder(buildDirectories, name);
+
+ List dependencies = new LinkedList();
+
+ for(String dep : dependsOn) {
+ FileObject depFO = buildDirectories.getFileObject(dep);
+
+ assertNotNull(depFO);
+ dependencies.add(depFO);
+ }
+
+ root2ClassPath.put(src, ClassPathSupport.createClassPath(dependencies.toArray(new FileObject[0])));
+ root2BuildRoot.put(src, build);
+ buildRoot2Source.put(build, src);
+ }
+
+ private void prepareSource(String sourceRoot, String fileName, String code) throws Exception {
+ FileObject root = sourceDirectories.getFileObject(sourceRoot);
+
+ assertNotNull(root);
+
+ FileObject source = FileUtil.createData(root, fileName);
+
+ TestUtilities.copyStringToFile(source, code);
+
+ SourceUtilsTestUtil.compileRecursively(root);
+ }
+
+ public void setUp() throws Exception {
+ SourceUtilsTestUtil.setLookup(new Object[0], ComputeOverridersTest.class.getClassLoader());
+ Main.initializeURLFactory();
+
+ clearWorkDir();
+ File wd = getWorkDir();
+ assert wd.isDirectory() && wd.list().length == 0;
+ FileObject dir = FileUtil.toFileObject(wd);
+
+ assertNotNull(dir);
+
+ sourceDirectories = FileUtil.createFolder(dir, "src");
+ buildDirectories = FileUtil.createFolder(dir, "build");
+
+ FileObject cache = FileUtil.createFolder(dir, "cache");
+
+ List