001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.java.editor.overridden;
043:
044: import com.sun.source.tree.CompilationUnitTree;
045: import com.sun.source.tree.Tree;
046: import java.io.IOException;
047: import java.net.URL;
048: import java.util.ArrayList;
049: import java.util.Collection;
050: import java.util.Collections;
051: import java.util.HashMap;
052: import java.util.HashSet;
053: import java.util.EnumSet;
054: import java.util.LinkedList;
055: import java.util.List;
056: import java.util.Map;
057: import java.util.Set;
058: import java.util.logging.Level;
059: import java.util.logging.Logger;
060: import javax.lang.model.element.Element;
061: import javax.lang.model.element.ExecutableElement;
062: import javax.lang.model.element.Modifier;
063: import javax.lang.model.element.Name;
064: import javax.lang.model.element.TypeElement;
065: import javax.lang.model.type.DeclaredType;
066: import javax.lang.model.type.TypeKind;
067: import javax.lang.model.type.TypeMirror;
068: import javax.lang.model.util.ElementFilter;
069: import javax.swing.text.BadLocationException;
070: import javax.swing.text.Position;
071: import javax.swing.text.StyledDocument;
072: import org.netbeans.api.java.classpath.ClassPath;
073: import org.netbeans.api.java.classpath.ClassPath;
074: import org.netbeans.api.java.classpath.ClassPath.Entry;
075: import org.netbeans.api.java.queries.SourceForBinaryQuery;
076: import org.netbeans.api.java.source.CancellableTask;
077: import org.netbeans.api.java.source.Task;
078: import org.netbeans.api.java.source.ClassIndex.SearchKind;
079: import org.netbeans.api.java.source.ClasspathInfo;
080: import org.netbeans.api.java.source.CompilationController;
081: import org.netbeans.api.java.source.CompilationInfo;
082: import org.netbeans.api.java.source.ElementHandle;
083: import org.netbeans.api.java.source.JavaSource;
084: import org.netbeans.api.java.source.SourceUtils;
085: import org.netbeans.api.java.source.ClassIndex;
086: import org.netbeans.spi.java.classpath.support.ClassPathSupport;
087: import org.openide.ErrorManager;
088: import org.openide.cookies.EditorCookie;
089: import org.openide.filesystems.FileObject;
090: import org.openide.filesystems.FileUtil;
091: import org.openide.loaders.DataObject;
092: import org.openide.text.NbDocument;
093: import org.openide.util.NbBundle;
094: import org.openide.util.RequestProcessor;
095: import org.openide.util.TopologicalSortException;
096: import org.openide.util.Utilities;
097:
098: /**
099: *
100: * @author Jan Lahoda
101: */
102: public class IsOverriddenAnnotationHandler implements
103: CancellableTask<CompilationInfo> {
104:
105: private static final boolean enableReverseLookups = Boolean
106: .getBoolean("org.netbeans.java.editor.enableReverseLookups");
107: static final Logger LOG = Logger
108: .getLogger(IsOverriddenAnnotationHandler.class.getName());
109:
110: private FileObject file;
111:
112: IsOverriddenAnnotationHandler(FileObject file) {
113: this .file = file;
114: Logger.getLogger("TIMER").log(Level.FINE,
115: "IsOverriddenAnnotationHandler",
116: new Object[] { file, this }); //NOI18N
117: }
118:
119: private IsOverriddenVisitor visitor;
120:
121: public void run(CompilationInfo info) throws IOException {
122: resume();
123:
124: StyledDocument doc = (StyledDocument) info.getDocument();
125:
126: if (doc == null) {
127: LOG.log(Level.FINE, "Cannot get document!"); //NOI18N
128: return;
129: }
130:
131: long startTime = System.currentTimeMillis();
132:
133: try {
134: List<IsOverriddenAnnotation> annotations = process(info,
135: doc);
136:
137: if (annotations == null) {
138: //cancelled:
139: return;
140: }
141:
142: newAnnotations(annotations);
143: } finally {
144: synchronized (this ) {
145: visitor = null;
146: }
147:
148: Logger.getLogger("TIMER").log(Level.FINE,
149: "Overridden in", //NOI18N
150: new Object[] { file,
151: System.currentTimeMillis() - startTime });
152: }
153: }
154:
155: private FileObject findSourceRoot() {
156: final ClassPath cp = ClassPath.getClassPath(file,
157: ClassPath.SOURCE);
158: if (cp != null) {
159: for (FileObject root : cp.getRoots()) {
160: if (FileUtil.isParentOf(root, file))
161: return root;
162: }
163: }
164: //Null is a valid value for files which have no source path (default filesystem).
165: return null;
166: }
167:
168: //temporary hack:
169: private synchronized Set<FileObject> findReverseSourceRoots(
170: final FileObject this SourceRoot, final FileObject this File) {
171: final Object o = new Object();
172: final Set<FileObject> reverseSourceRoots = new HashSet<FileObject>();
173:
174: RequestProcessor.getDefault().post(new Runnable() {
175: public void run() {
176: long startTime = System.currentTimeMillis();
177: Set<FileObject> reverseSourceRootsInt = new HashSet<FileObject>(
178: ReverseSourceRootsLookup
179: .reverseSourceRootsLookup(this SourceRoot));
180: long endTime = System.currentTimeMillis();
181:
182: Logger.getLogger("TIMER").log(Level.FINE,
183: "Find Reverse Source Roots", //NOI18N
184: new Object[] { this File, endTime - startTime });
185:
186: synchronized (o) {
187: reverseSourceRoots.addAll(reverseSourceRootsInt);
188: }
189:
190: wakeUp();
191: }
192: });
193:
194: try {
195: wait();
196: } catch (InterruptedException ex) {
197: ErrorManager.getDefault().notify(ex);
198: }
199:
200: return reverseSourceRoots;
201: }
202:
203: public static AnnotationType detectOverrides(CompilationInfo info,
204: TypeElement type, ExecutableElement ee,
205: List<ElementDescription> result) {
206: final Map<Name, List<ExecutableElement>> name2Method = new HashMap<Name, List<ExecutableElement>>();
207:
208: sortOutMethods(info, name2Method, type, false);
209:
210: List<ExecutableElement> lee = name2Method.get(ee
211: .getSimpleName());
212:
213: if (lee == null || lee.isEmpty()) {
214: return null;
215: }
216:
217: Set<ExecutableElement> seenMethods = new HashSet<ExecutableElement>();
218:
219: for (ExecutableElement overridee : lee) {
220: if (info.getElements().overrides(ee, overridee,
221: SourceUtils.getEnclosingTypeElement(ee))) {
222: if (seenMethods.add(overridee)) {
223: result.add(new ElementDescription(info, overridee));
224: }
225: }
226: }
227:
228: if (!result.isEmpty()) {
229: for (ElementDescription ed : result) {
230: if (!ed.getModifiers().contains(Modifier.ABSTRACT)) {
231: return AnnotationType.OVERRIDES;
232: }
233: }
234:
235: return AnnotationType.IMPLEMENTS;
236: }
237:
238: return null;
239: }
240:
241: List<IsOverriddenAnnotation> process(CompilationInfo info,
242: final StyledDocument doc) {
243: IsOverriddenVisitor v;
244:
245: synchronized (this ) {
246: if (isCanceled())
247: return null;
248:
249: v = visitor = new IsOverriddenVisitor(doc, info);
250: }
251:
252: CompilationUnitTree unit = info.getCompilationUnit();
253:
254: long startTime1 = System.currentTimeMillis();
255:
256: v.scan(unit, null);
257:
258: long endTime1 = System.currentTimeMillis();
259:
260: Logger.getLogger("TIMER").log(Level.FINE, "Overridden Scanner", //NOI18N
261: new Object[] { file, endTime1 - startTime1 });
262:
263: Set<FileObject> reverseSourceRoots;
264:
265: if (enableReverseLookups) {
266: FileObject this SourceRoot = findSourceRoot();
267: if (this SourceRoot == null) {
268: return null;
269: }
270:
271: reverseSourceRoots = findReverseSourceRoots(this SourceRoot,
272: info.getFileObject());
273:
274: //XXX: special case "this" source root (no need to create a new JS and load the classes again for it):
275: reverseSourceRoots.add(this SourceRoot);
276: } else {
277: reverseSourceRoots = null;
278: }
279:
280: LOG.log(Level.FINE, "reverseSourceRoots: {0}",
281: reverseSourceRoots); //NOI18N
282:
283: List<IsOverriddenAnnotation> annotations = new ArrayList<IsOverriddenAnnotation>();
284:
285: for (ElementHandle<TypeElement> td : v.type2Declaration
286: .keySet()) {
287: if (isCanceled())
288: return null;
289:
290: LOG.log(Level.FINE, "type: {0}", td.getQualifiedName()); //NOI18N
291:
292: final Map<Name, List<ExecutableElement>> name2Method = new HashMap<Name, List<ExecutableElement>>();
293:
294: TypeElement resolvedType = td.resolve(info);
295:
296: if (resolvedType == null)
297: continue;
298:
299: sortOutMethods(info, name2Method, resolvedType, false);
300:
301: for (ElementHandle<ExecutableElement> methodHandle : v.type2Declaration
302: .get(td)) {
303: if (isCanceled())
304: return null;
305:
306: ExecutableElement ee = methodHandle.resolve(info);
307:
308: if (ee == null)
309: continue;
310:
311: if (LOG.isLoggable(Level.FINE)) {
312: LOG.log(Level.FINE, "method: {0}", ee.toString()); //NOI18N
313: }
314:
315: List<ExecutableElement> lee = name2Method.get(ee
316: .getSimpleName());
317:
318: if (lee == null || lee.isEmpty()) {
319: continue;
320: }
321:
322: Set<ExecutableElement> seenMethods = new HashSet<ExecutableElement>();
323: List<ElementDescription> overrides = new ArrayList<ElementDescription>();
324:
325: for (ExecutableElement overridee : lee) {
326: if (info.getElements().overrides(ee, overridee,
327: SourceUtils.getEnclosingTypeElement(ee))) {
328: if (seenMethods.add(overridee)) {
329: overrides.add(new ElementDescription(info,
330: overridee));
331: }
332: }
333: }
334:
335: if (!overrides.isEmpty()) {
336: int position = (int) info.getTrees()
337: .getSourcePositions().getStartPosition(
338: info.getCompilationUnit(),
339: v.declaration2Tree
340: .get(methodHandle));
341: Position pos = getPosition(doc, position);
342:
343: if (pos == null) {
344: //cannot compute the position, skip
345: continue;
346: }
347:
348: StringBuffer tooltip = new StringBuffer();
349: boolean wasOverrides = false;
350:
351: boolean newline = false;
352:
353: for (ElementDescription ed : overrides) {
354: if (newline) {
355: tooltip.append("\n"); //NOI18N
356: }
357:
358: newline = true;
359:
360: if (ed.getModifiers().contains(
361: Modifier.ABSTRACT)) {
362: tooltip
363: .append(NbBundle
364: .getMessage(
365: IsOverriddenAnnotationHandler.class,
366: "TP_Implements",
367: ed.getDisplayName()));
368: } else {
369: tooltip
370: .append(NbBundle
371: .getMessage(
372: IsOverriddenAnnotationHandler.class,
373: "TP_Overrides",
374: ed.getDisplayName()));
375: wasOverrides = true;
376: }
377: }
378:
379: annotations.add(new IsOverriddenAnnotation(doc,
380: pos,
381: wasOverrides ? AnnotationType.OVERRIDES
382: : AnnotationType.IMPLEMENTS,
383: tooltip.toString(), overrides));
384: }
385: }
386:
387: if (enableReverseLookups) {
388: String typeOverridden = null;
389: AnnotationType typeType = null;
390: TypeElement resolved = td.resolve(info);
391:
392: if (resolved == null) {
393: Logger
394: .getLogger("global")
395: .log(Level.SEVERE,
396: "IsOverriddenAnnotationHandler: resolved == null!"); //NOI18N
397: continue;
398: }
399:
400: if (resolved.getKind().isInterface()) {
401: typeOverridden = NbBundle.getMessage(
402: IsOverriddenAnnotationHandler.class,
403: "CAP_HasImplementations");
404: typeType = AnnotationType.HAS_IMPLEMENTATION;
405: }
406:
407: if (resolved.getKind().isClass()) {
408: typeOverridden = NbBundle.getMessage(
409: IsOverriddenAnnotationHandler.class,
410: "CAP_IsOverridden");
411: typeType = AnnotationType.IS_OVERRIDDEN;
412: }
413:
414: final Map<ElementHandle<ExecutableElement>, List<ElementDescription>> overriding = new HashMap<ElementHandle<ExecutableElement>, List<ElementDescription>>();
415: final List<ElementDescription> overridingClasses = new ArrayList<ElementDescription>();
416:
417: long startTime = System.currentTimeMillis();
418: long[] classIndexTime = new long[1];
419: final Map<FileObject, Set<ElementHandle<TypeElement>>> users = computeUsers(
420: reverseSourceRoots, ElementHandle
421: .create(resolved), classIndexTime);
422: long endTime = System.currentTimeMillis();
423:
424: if (users == null) {
425: return null;
426: }
427:
428: Logger.getLogger("TIMER").log(Level.FINE,
429: "Overridden Users Class Index", //NOI18N
430: new Object[] { file, classIndexTime[0] });
431: Logger.getLogger("TIMER").log(Level.FINE,
432: "Overridden Users", //NOI18N
433: new Object[] { file, endTime - startTime });
434:
435: for (Map.Entry<FileObject, Set<ElementHandle<TypeElement>>> data : users
436: .entrySet()) {
437: if (isCanceled())
438: return null;
439:
440: findOverriddenAnnotations(data.getKey(), data
441: .getValue(), td,
442: v.type2Declaration.get(td), overriding,
443: overridingClasses);
444: }
445:
446: if (!overridingClasses.isEmpty()) {
447: Tree t = v.declaration2Class.get(td);
448:
449: if (t != null) {
450: Position pos = getPosition(doc, (int) info
451: .getTrees().getSourcePositions()
452: .getStartPosition(unit, t));
453:
454: if (pos == null) {
455: //cannot compute the position, skip
456: continue;
457: }
458:
459: annotations
460: .add(new IsOverriddenAnnotation(doc,
461: pos, typeType, typeOverridden
462: .toString(),
463: overridingClasses));
464: }
465: }
466:
467: for (ElementHandle<ExecutableElement> original : overriding
468: .keySet()) {
469: if (isCanceled())
470: return null;
471:
472: Position pos = getPosition(doc, (int) info
473: .getTrees().getSourcePositions()
474: .getStartPosition(unit,
475: v.declaration2Tree.get(original)));
476:
477: if (pos == null) {
478: //cannot compute the position, skip
479: continue;
480: }
481:
482: Set<Modifier> mods = original.resolve(info)
483: .getModifiers();
484: String tooltip = null;
485:
486: if (mods.contains(Modifier.ABSTRACT)) {
487: tooltip = NbBundle.getMessage(
488: IsOverriddenAnnotationHandler.class,
489: "TP_HasImplementations");
490: } else {
491: tooltip = NbBundle.getMessage(
492: IsOverriddenAnnotationHandler.class,
493: "TP_IsOverridden");
494: }
495:
496: IsOverriddenAnnotation ann = new IsOverriddenAnnotation(
497: doc,
498: pos,
499: mods.contains(Modifier.ABSTRACT) ? AnnotationType.HAS_IMPLEMENTATION
500: : AnnotationType.IS_OVERRIDDEN,
501: tooltip, overriding.get(original));
502:
503: annotations.add(ann);
504: }
505: }
506: }
507:
508: if (isCanceled())
509: return null;
510: else
511: return annotations;
512: }
513:
514: private static final ClassPath EMPTY = ClassPathSupport
515: .createClassPath(new URL[0]);
516:
517: private Set<ElementHandle<TypeElement>> computeUsers(
518: FileObject source, Set<ElementHandle<TypeElement>> base,
519: long[] classIndexCumulative) {
520: ClasspathInfo cpinfo = ClasspathInfo.create(
521: /*source);/*/EMPTY, EMPTY, ClassPathSupport
522: .createClassPath(new FileObject[] { source }));
523:
524: long startTime = System.currentTimeMillis();
525:
526: try {
527: List<ElementHandle<TypeElement>> l = new LinkedList<ElementHandle<TypeElement>>(
528: base);
529: Set<ElementHandle<TypeElement>> result = new HashSet<ElementHandle<TypeElement>>();
530:
531: while (!l.isEmpty()) {
532: ElementHandle<TypeElement> eh = l.remove(0);
533:
534: result.add(eh);
535: Set<ElementHandle<TypeElement>> typeElements = cpinfo
536: .getClassIndex()
537: .getElements(
538: eh,
539: Collections
540: .singleton(SearchKind.IMPLEMENTORS),
541: EnumSet
542: .of(ClassIndex.SearchScope.SOURCE));
543: //XXX: Canceling
544: if (typeElements != null) {
545: l.addAll(typeElements);
546: }
547: }
548: return result;
549: } finally {
550: classIndexCumulative[0] += (System.currentTimeMillis() - startTime);
551: }
552: }
553:
554: private Map<FileObject, Set<ElementHandle<TypeElement>>> computeUsers(
555: Set<FileObject> sources, ElementHandle<TypeElement> base,
556: long[] classIndexCumulative) {
557: Map<FileObject, Collection<FileObject>> edges = new HashMap<FileObject, Collection<FileObject>>();
558: Map<FileObject, Collection<FileObject>> dependsOn = new HashMap<FileObject, Collection<FileObject>>();
559:
560: for (FileObject source : sources) {
561: edges.put(source, new ArrayList<FileObject>());
562: }
563:
564: for (FileObject source : sources) {
565: List<FileObject> deps = new ArrayList<FileObject>();
566:
567: dependsOn.put(source, deps);
568:
569: for (Entry entry : ClassPath.getClassPath(source,
570: ClassPath.COMPILE).entries()) { //TODO: should also check BOOT?
571: for (FileObject s : SourceForBinaryQuery
572: .findSourceRoots(entry.getURL()).getRoots()) {
573: Collection<FileObject> targets = edges.get(s);
574:
575: if (targets != null) {
576: targets.add(source);
577: }
578:
579: deps.add(s);
580: }
581: }
582: }
583:
584: List<FileObject> sourceRoots = new ArrayList<FileObject>(
585: sources);
586:
587: try {
588: Utilities.topologicalSort(sourceRoots, edges);
589: } catch (TopologicalSortException ex) {
590: LOG.log(Level.WARNING, "internal error", ex); //NOI18N
591: return null;
592: }
593:
594: Map<FileObject, Set<ElementHandle<TypeElement>>> result = new HashMap<FileObject, Set<ElementHandle<TypeElement>>>();
595:
596: for (FileObject file : sourceRoots) {
597: Set<ElementHandle<TypeElement>> baseTypes = new HashSet<ElementHandle<TypeElement>>();
598:
599: baseTypes.add(base);
600:
601: for (FileObject dep : dependsOn.get(file)) {
602: Set<ElementHandle<TypeElement>> depTypes = result
603: .get(dep);
604:
605: if (depTypes != null) {
606: baseTypes.addAll(depTypes);
607: }
608: }
609:
610: Set<ElementHandle<TypeElement>> types = computeUsers(file,
611: baseTypes, classIndexCumulative);
612:
613: types.removeAll(baseTypes);
614:
615: result.put(file, types);
616: }
617:
618: return result;
619: }
620:
621: private void findOverriddenAnnotations(
622: FileObject sourceRoot,
623: final Set<ElementHandle<TypeElement>> users,
624: final ElementHandle<TypeElement> originalType,
625: final List<ElementHandle<ExecutableElement>> methods,
626: final Map<ElementHandle<ExecutableElement>, List<ElementDescription>> overriding,
627: final List<ElementDescription> overridingClasses) {
628: ClasspathInfo cpinfo = ClasspathInfo.create(sourceRoot);
629:
630: if (!users.isEmpty()) {
631: JavaSource js = JavaSource.create(cpinfo);
632:
633: try {
634: js.runUserActionTask(new Task<CompilationController>() {
635:
636: public void run(CompilationController controller)
637: throws Exception {
638: Set<Element> seenElements = new HashSet<Element>();
639:
640: for (ElementHandle<TypeElement> typeHandle : users) {
641: if (isCanceled())
642: return;
643: TypeElement type = typeHandle
644: .resolve(controller);
645: Element resolvedOriginalType = originalType
646: .resolve(controller);
647:
648: if (!seenElements.add(resolvedOriginalType))
649: continue;
650:
651: if (controller.getTypes().isSubtype(
652: type.asType(),
653: resolvedOriginalType.asType())) {
654: overridingClasses
655: .add(new ElementDescription(
656: controller, type));
657:
658: for (ElementHandle<ExecutableElement> originalMethodHandle : methods) {
659: ExecutableElement originalMethod = originalMethodHandle
660: .resolve(controller);
661:
662: if (originalMethod != null) {
663: ExecutableElement overrider = getImplementationOf(
664: controller,
665: originalMethod, type);
666:
667: if (overrider == null)
668: continue;
669:
670: List<ElementDescription> overriddingMethods = overriding
671: .get(originalMethodHandle);
672:
673: if (overriddingMethods == null) {
674: overriding
675: .put(
676: originalMethodHandle,
677: overriddingMethods = new ArrayList<ElementDescription>());
678: }
679:
680: overriddingMethods
681: .add(new ElementDescription(
682: controller,
683: overrider));
684: } else {
685: Logger
686: .getLogger("global")
687: .log(Level.SEVERE,
688: "IsOverriddenAnnotationHandler: originalMethod == null!"); //NOI18N
689: }
690: }
691: }
692: }
693: }
694: }, true);
695: } catch (Exception e) {
696: ErrorManager.getDefault().notify(e);
697: }
698: }
699: }
700:
701: private ExecutableElement getImplementationOf(CompilationInfo info,
702: ExecutableElement overridee, TypeElement implementor) {
703: for (ExecutableElement overrider : ElementFilter
704: .methodsIn(implementor.getEnclosedElements())) {
705: if (info.getElements().overrides(overrider, overridee,
706: implementor)) {
707: return overrider;
708: }
709: }
710:
711: return null;
712: }
713:
714: private boolean canceled;
715:
716: public synchronized void cancel() {
717: canceled = true;
718:
719: if (visitor != null) {
720: visitor.cancel();
721: }
722:
723: wakeUp();
724: }
725:
726: private synchronized void resume() {
727: canceled = false;
728: }
729:
730: private synchronized void wakeUp() {
731: notifyAll();
732: }
733:
734: private synchronized boolean isCanceled() {
735: return canceled;
736: }
737:
738: private void newAnnotations(List<IsOverriddenAnnotation> as) {
739: AnnotationsHolder a = AnnotationsHolder.get(file);
740:
741: if (a != null) {
742: a.setNewAnnotations(as);
743: }
744: }
745:
746: private static void sortOutMethods(CompilationInfo info,
747: Map<Name, List<ExecutableElement>> where, Element td,
748: boolean current) {
749: if (current) {
750: Map<Name, List<ExecutableElement>> newlyAdded = new HashMap<Name, List<ExecutableElement>>();
751:
752: OUTTER: for (ExecutableElement ee : ElementFilter
753: .methodsIn(td.getEnclosedElements())) {
754: Name name = ee.getSimpleName();
755: List<ExecutableElement> alreadySeen = where.get(name);
756:
757: if (alreadySeen != null) {
758: for (ExecutableElement seen : alreadySeen) {
759: if (info.getElements().overrides(
760: seen,
761: ee,
762: (TypeElement) seen
763: .getEnclosingElement())) {
764: continue OUTTER; //a method that overrides this one was already handled, ignore
765: }
766: }
767: }
768:
769: List<ExecutableElement> lee = newlyAdded.get(name);
770:
771: if (lee == null) {
772: newlyAdded.put(name,
773: lee = new ArrayList<ExecutableElement>());
774: }
775:
776: lee.add(ee);
777: }
778:
779: for (Map.Entry<Name, List<ExecutableElement>> e : newlyAdded
780: .entrySet()) {
781: List<ExecutableElement> lee = where.get(e.getKey());
782:
783: if (lee == null) {
784: where.put(e.getKey(), e.getValue());
785: } else {
786: lee.addAll(e.getValue());
787: }
788: }
789: }
790:
791: for (TypeMirror super Type : info.getTypes().directSupertypes(
792: td.asType())) {
793: if (super Type.getKind() == TypeKind.DECLARED) {
794: sortOutMethods(info, where, ((DeclaredType) super Type)
795: .asElement(), true);
796: }
797: }
798: }
799:
800: private static Position getPosition(final StyledDocument doc,
801: final int offset) {
802: class Impl implements Runnable {
803: private Position pos;
804:
805: public void run() {
806: if (offset < 0 || offset >= doc.getLength())
807: return;
808:
809: try {
810: pos = doc.createPosition(offset
811: - NbDocument.findLineColumn(doc, offset));
812: } catch (BadLocationException ex) {
813: //should not happen?
814: LOG.log(Level.FINE, null, ex);
815: }
816: }
817: }
818:
819: Impl i = new Impl();
820:
821: doc.render(i);
822:
823: return i.pos;
824: }
825:
826: }
|