Line 0
Link Here
|
|
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright 2009 Sun Microsystems, Inc. All rights reserved. |
5 |
* |
6 |
* The contents of this file are subject to the terms of either the GNU |
7 |
* General Public License Version 2 only ("GPL") or the Common |
8 |
* Development and Distribution License("CDDL") (collectively, the |
9 |
* "License"). You may not use this file except in compliance with the |
10 |
* License. You can obtain a copy of the License at |
11 |
* http://www.netbeans.org/cddl-gplv2.html |
12 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
13 |
* specific language governing permissions and limitations under the |
14 |
* License. When distributing the software, include this License Header |
15 |
* Notice in each file and include the License file at |
16 |
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this |
17 |
* particular file as subject to the "Classpath" exception as provided |
18 |
* by Sun in the GPL Version 2 section of the License file that |
19 |
* accompanied this code. If applicable, add the following below the |
20 |
* License Header, with the fields enclosed by brackets [] replaced by |
21 |
* your own identifying information: |
22 |
* "Portions Copyrighted [year] [name of copyright owner]" |
23 |
* |
24 |
* If you wish your version of this file to be governed by only the CDDL |
25 |
* or only the GPL Version 2, indicate your decision by adding |
26 |
* "[Contributor] elects to include this software in this distribution |
27 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a |
28 |
* single choice of license, a recipient has the option to distribute |
29 |
* your version of this file under either the CDDL, the GPL Version 2 or |
30 |
* to extend the choice of license to its licensees as provided above. |
31 |
* However, if you add GPL Version 2 code and therefore, elected the GPL |
32 |
* Version 2 license, then the option applies only if the new code is |
33 |
* made subject to such option by the copyright holder. |
34 |
* |
35 |
* Contributor(s): |
36 |
* |
37 |
* Portions Copyrighted 2009 Sun Microsystems, Inc. |
38 |
*/ |
39 |
|
40 |
package org.netbeans.modules.java.editor.overridden; |
41 |
|
42 |
import java.awt.Point; |
43 |
import java.lang.reflect.InvocationTargetException; |
44 |
import java.lang.reflect.Method; |
45 |
import java.net.URL; |
46 |
import java.util.ArrayList; |
47 |
import java.util.Collections; |
48 |
import java.util.EnumSet; |
49 |
import java.util.HashMap; |
50 |
import java.util.HashSet; |
51 |
import java.util.LinkedHashMap; |
52 |
import java.util.LinkedList; |
53 |
import java.util.List; |
54 |
import java.util.Map; |
55 |
import java.util.Set; |
56 |
import java.util.concurrent.atomic.AtomicBoolean; |
57 |
import java.util.logging.Level; |
58 |
import java.util.logging.Logger; |
59 |
import javax.lang.model.element.Element; |
60 |
import javax.lang.model.element.ExecutableElement; |
61 |
import javax.lang.model.element.TypeElement; |
62 |
import javax.lang.model.util.ElementFilter; |
63 |
import javax.lang.model.util.Types; |
64 |
import org.netbeans.api.java.classpath.ClassPath; |
65 |
import org.netbeans.api.java.queries.SourceForBinaryQuery; |
66 |
import org.netbeans.api.java.source.ClassIndex; |
67 |
import org.netbeans.api.java.source.ClassIndex.SearchKind; |
68 |
import org.netbeans.api.java.source.ClassIndex.SearchScope; |
69 |
import org.netbeans.api.java.source.ClasspathInfo; |
70 |
import org.netbeans.api.java.source.CompilationController; |
71 |
import org.netbeans.api.java.source.CompilationInfo; |
72 |
import org.netbeans.api.java.source.ElementHandle; |
73 |
import org.netbeans.api.java.source.JavaSource; |
74 |
import org.netbeans.api.java.source.SourceUtils; |
75 |
import org.netbeans.api.java.source.Task; |
76 |
import org.netbeans.spi.java.classpath.support.ClassPathSupport; |
77 |
import org.openide.DialogDisplayer; |
78 |
import org.openide.NotifyDescriptor; |
79 |
import org.openide.filesystems.FileObject; |
80 |
import org.openide.filesystems.FileStateInvalidException; |
81 |
import org.openide.filesystems.URLMapper; |
82 |
import org.openide.util.Exceptions; |
83 |
import org.openide.util.Lookup; |
84 |
import org.openide.util.NbBundle; |
85 |
import org.openide.util.TopologicalSortException; |
86 |
import org.openide.util.Utilities; |
87 |
|
88 |
/** |
89 |
* |
90 |
* @author Jan Lahoda |
91 |
*/ |
92 |
public class ComputeOverriders { |
93 |
|
94 |
private static final Logger LOG = Logger.getLogger(ComputeOverriders.class.getName()); |
95 |
|
96 |
private final AtomicBoolean cancel; |
97 |
|
98 |
public ComputeOverriders(AtomicBoolean cancel) { |
99 |
this.cancel = cancel; |
100 |
} |
101 |
|
102 |
private static Set<URL> findReverseSourceRoots(final URL thisSourceRoot, Map<URL, List<URL>> sourceDeps, final FileObject thisFile) { |
103 |
long startTime = System.currentTimeMillis(); |
104 |
|
105 |
try { |
106 |
//TODO: from SourceUtils (which filters out source roots that do not belong to open projects): |
107 |
//Create inverse dependencies |
108 |
final Map<URL, List<URL>> inverseDeps = new HashMap<URL, List<URL>> (); |
109 |
for (Map.Entry<URL,List<URL>> entry : sourceDeps.entrySet()) { |
110 |
final URL u1 = entry.getKey(); |
111 |
final List<URL> l1 = entry.getValue(); |
112 |
for (URL u2 : l1) { |
113 |
List<URL> l2 = inverseDeps.get(u2); |
114 |
if (l2 == null) { |
115 |
l2 = new ArrayList<URL>(); |
116 |
inverseDeps.put (u2,l2); |
117 |
} |
118 |
l2.add (u1); |
119 |
} |
120 |
} |
121 |
//Collect dependencies |
122 |
final Set<URL> result = new HashSet<URL>(); |
123 |
final LinkedList<URL> todo = new LinkedList<URL> (); |
124 |
todo.add (thisSourceRoot); |
125 |
while (!todo.isEmpty()) { |
126 |
final URL u = todo.removeFirst(); |
127 |
if (!result.contains(u)) { |
128 |
result.add (u); |
129 |
final List<URL> ideps = inverseDeps.get(u); |
130 |
if (ideps != null) { |
131 |
todo.addAll (ideps); |
132 |
} |
133 |
} |
134 |
} |
135 |
return result; |
136 |
} finally { |
137 |
long endTime = System.currentTimeMillis(); |
138 |
|
139 |
Logger.getLogger("TIMER").log(Level.FINE, "Find Reverse Source Roots", //NOI18N |
140 |
new Object[]{thisFile, endTime - startTime}); |
141 |
} |
142 |
} |
143 |
|
144 |
private static FileObject findSourceRoot(FileObject file) { |
145 |
final ClassPath cp = ClassPath.getClassPath(file, ClassPath.SOURCE); |
146 |
if (cp != null) { |
147 |
return cp.findOwnerRoot(file); |
148 |
} |
149 |
//Null is a valid value for files which have no source path (default filesystem). |
150 |
return null; |
151 |
} |
152 |
|
153 |
private Set<URL> findBinaryRootsForSourceRoot(FileObject sourceRoot, Map<URL, List<URL>> binaryDeps) { |
154 |
// BinaryForSourceQuery.findBinaryRoots(thisSourceRoot).getRoots(); |
155 |
Set<URL> result = new HashSet<URL>(); |
156 |
|
157 |
for (URL bin : binaryDeps.keySet()) { |
158 |
if (cancel.get()) return Collections.emptySet(); |
159 |
for (FileObject s : SourceForBinaryQuery.findSourceRoots(bin).getRoots()) { |
160 |
if (s == sourceRoot) { |
161 |
result.add(bin); |
162 |
} |
163 |
} |
164 |
} |
165 |
|
166 |
return result; |
167 |
} |
168 |
|
169 |
Map<ElementHandle<? extends Element>, List<ElementDescription>> process(CompilationInfo info, TypeElement te, ExecutableElement ee, boolean interactive) { |
170 |
long startTime = System.currentTimeMillis(); |
171 |
|
172 |
try { |
173 |
return processImpl(info, te, ee, interactive); |
174 |
} finally { |
175 |
Logger.getLogger("TIMER").log(Level.FINE, "Overridden - Total", //NOI18N |
176 |
new Object[] {info.getFileObject(), System.currentTimeMillis() - startTime}); |
177 |
} |
178 |
} |
179 |
|
180 |
private Map<ElementHandle<? extends Element>, List<ElementDescription>> processImpl(CompilationInfo info, TypeElement te, ExecutableElement ee, boolean interactive) { |
181 |
FileObject file = info.getFileObject(); |
182 |
FileObject thisSourceRoot = findSourceRoot(file); |
183 |
|
184 |
if (thisSourceRoot == null) { |
185 |
return null; |
186 |
} |
187 |
|
188 |
|
189 |
//XXX: special case "this" source root (no need to create a new JS and load the classes again for it): |
190 |
// reverseSourceRoots.add(thisSourceRoot); |
191 |
|
192 |
// LOG.log(Level.FINE, "reverseSourceRoots: {0}", reverseSourceRoots); //NOI18N |
193 |
|
194 |
// if (LOG.isLoggable(Level.FINE)) { |
195 |
// LOG.log(Level.FINE, "method: {0}", ee.toString()); //NOI18N |
196 |
// } |
197 |
|
198 |
|
199 |
final Map<ElementHandle<TypeElement>, List<ElementHandle<ExecutableElement>>> methods = new HashMap<ElementHandle<TypeElement>, List<ElementHandle<ExecutableElement>>>(); |
200 |
|
201 |
if (ee == null) { |
202 |
if (te == null) { |
203 |
fillInMethods(info.getTopLevelElements(), methods); |
204 |
} else { |
205 |
methods.put(ElementHandle.create(te), Collections.<ElementHandle<ExecutableElement>>emptyList()); |
206 |
} |
207 |
} else { |
208 |
TypeElement owner = (TypeElement) ee.getEnclosingElement(); |
209 |
|
210 |
methods.put(ElementHandle.create(owner), Collections.singletonList(ElementHandle.create(ee))); |
211 |
} |
212 |
|
213 |
final Map<ElementHandle<? extends Element>, List<ElementDescription>> overriding = new HashMap<ElementHandle<? extends Element>, List<ElementDescription>>(); |
214 |
|
215 |
long startTime = System.currentTimeMillis(); |
216 |
long[] classIndexTime = new long[1]; |
217 |
final Map<URL, Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>>> users = computeUsers(info, thisSourceRoot, methods.keySet(), classIndexTime, interactive); |
218 |
long endTime = System.currentTimeMillis(); |
219 |
|
220 |
if (users == null) { |
221 |
return null; |
222 |
} |
223 |
|
224 |
Logger.getLogger("TIMER").log(Level.FINE, "Overridden Candidates - Class Index", //NOI18N |
225 |
new Object[] {file, classIndexTime[0]}); |
226 |
Logger.getLogger("TIMER").log(Level.FINE, "Overridden Candidates - Total", //NOI18N |
227 |
new Object[] {file, endTime - startTime}); |
228 |
|
229 |
for (Map.Entry<URL, Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>>> data : users.entrySet()) { |
230 |
for (Map.Entry<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>> deps : data.getValue().entrySet()) { |
231 |
if (cancel.get()) return null; |
232 |
findOverriddenAnnotations(data.getKey(), deps.getValue(), deps.getKey(), methods.get(deps.getKey()), overriding); |
233 |
} |
234 |
} |
235 |
|
236 |
return overriding; |
237 |
} |
238 |
private static final ClassPath EMPTY = ClassPathSupport.createClassPath(new URL[0]); |
239 |
|
240 |
private static void fillInMethods(Iterable<? extends TypeElement> types, Map<ElementHandle<TypeElement>, List<ElementHandle<ExecutableElement>>> methods) { |
241 |
for (TypeElement te : types) { |
242 |
List<ElementHandle<ExecutableElement>> l = new LinkedList<ElementHandle<ExecutableElement>>(); |
243 |
|
244 |
for (ExecutableElement ee : ElementFilter.methodsIn(te.getEnclosedElements())) { |
245 |
l.add(ElementHandle.create(ee)); |
246 |
} |
247 |
|
248 |
methods.put(ElementHandle.create(te), l); |
249 |
|
250 |
fillInMethods(ElementFilter.typesIn(te.getEnclosedElements()), methods); |
251 |
} |
252 |
} |
253 |
private Set<ElementHandle<TypeElement>> computeUsers(URL source, Set<ElementHandle<TypeElement>> base, long[] classIndexCumulative) { |
254 |
ClasspathInfo cpinfo = ClasspathInfo.create(EMPTY, EMPTY, ClassPathSupport.createClassPath(source)); |
255 |
|
256 |
return computeUsers(cpinfo, ClassIndex.SearchScope.SOURCE, base, classIndexCumulative); |
257 |
} |
258 |
|
259 |
private Set<ElementHandle<TypeElement>> computeUsers(ClasspathInfo cpinfo, SearchScope scope, Set<ElementHandle<TypeElement>> base, long[] classIndexCumulative) { |
260 |
long startTime = System.currentTimeMillis(); |
261 |
|
262 |
try { |
263 |
List<ElementHandle<TypeElement>> l = new LinkedList<ElementHandle<TypeElement>>(base); |
264 |
Set<ElementHandle<TypeElement>> result = new HashSet<ElementHandle<TypeElement>>(); |
265 |
|
266 |
while (!l.isEmpty()) { |
267 |
if (cancel.get()) return null; |
268 |
|
269 |
ElementHandle<TypeElement> eh = l.remove(0); |
270 |
|
271 |
result.add(eh); |
272 |
Set<ElementHandle<TypeElement>> typeElements = cpinfo.getClassIndex().getElements(eh, Collections.singleton(SearchKind.IMPLEMENTORS), EnumSet.of(scope)); |
273 |
//XXX: Canceling |
274 |
if (typeElements != null) { |
275 |
l.addAll(typeElements); |
276 |
} |
277 |
} |
278 |
return result; |
279 |
} finally { |
280 |
classIndexCumulative[0] += (System.currentTimeMillis() - startTime); |
281 |
} |
282 |
} |
283 |
|
284 |
static List<URL> reverseSourceRootsInOrderOverride; |
285 |
|
286 |
private List<URL> reverseSourceRootsInOrder(CompilationInfo info, URL thisSourceRoot, FileObject thisSourceRootFO, Map<URL, List<URL>> sourceDeps, Map<URL, List<URL>> binaryDeps, boolean interactive) { |
287 |
if (reverseSourceRootsInOrderOverride != null) { |
288 |
return reverseSourceRootsInOrderOverride; |
289 |
} |
290 |
|
291 |
Set<URL> sourceRootsSet; |
292 |
|
293 |
if (sourceDeps.containsKey(thisSourceRoot)) { |
294 |
sourceRootsSet = findReverseSourceRoots(thisSourceRoot, sourceDeps, info.getFileObject()); |
295 |
} else { |
296 |
sourceRootsSet = new HashSet<URL>(); |
297 |
|
298 |
for (URL binary : findBinaryRootsForSourceRoot(thisSourceRootFO, binaryDeps)) { |
299 |
List<URL> deps = binaryDeps.get(binary); |
300 |
|
301 |
if (deps != null) { |
302 |
sourceRootsSet.addAll(deps); |
303 |
} |
304 |
} |
305 |
} |
306 |
|
307 |
List<URL> sourceRoots; |
308 |
try { |
309 |
sourceRoots = new LinkedList<URL>(Utilities.topologicalSort(sourceDeps.keySet(), sourceDeps)); |
310 |
} catch (TopologicalSortException ex) { |
311 |
if (interactive) { |
312 |
Exceptions.attachLocalizedMessage(ex,NbBundle.getMessage(GoToImplementation.class, "ERR_CycleInDependencies")); |
313 |
Exceptions.printStackTrace(ex); |
314 |
} else { |
315 |
LOG.log(Level.FINE, null, ex); |
316 |
} |
317 |
return null; |
318 |
} |
319 |
|
320 |
sourceRoots.retainAll(sourceRootsSet); |
321 |
|
322 |
Collections.reverse(sourceRoots); |
323 |
|
324 |
return sourceRoots; |
325 |
} |
326 |
|
327 |
private Map<URL, Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>>> computeUsers(CompilationInfo info, FileObject thisSourceRoot, Set<ElementHandle<TypeElement>> baseHandles, long[] classIndexCumulative, boolean interactive) { |
328 |
Map<URL, List<URL>> sourceDeps = getDependencies(false); |
329 |
Map<URL, List<URL>> binaryDeps = getDependencies(true); |
330 |
|
331 |
if (sourceDeps == null || binaryDeps == null) { |
332 |
if (interactive) { |
333 |
NotifyDescriptor nd = new NotifyDescriptor.Message(NbBundle.getMessage(GoToImplementation.class, "ERR_NoDependencies"), NotifyDescriptor.ERROR_MESSAGE); |
334 |
|
335 |
DialogDisplayer.getDefault().notifyLater(nd); |
336 |
} else { |
337 |
LOG.log(Level.FINE, NbBundle.getMessage(GoToImplementation.class, "ERR_NoDependencies")); |
338 |
} |
339 |
|
340 |
return null; |
341 |
} |
342 |
|
343 |
URL thisSourceRootURL; |
344 |
|
345 |
try { |
346 |
thisSourceRootURL = thisSourceRoot.getURL(); |
347 |
} catch (FileStateInvalidException ex) { |
348 |
Exceptions.printStackTrace(ex); |
349 |
return null; |
350 |
} |
351 |
|
352 |
List<URL> sourceRoots = reverseSourceRootsInOrder(info, thisSourceRootURL, thisSourceRoot, sourceDeps, binaryDeps, interactive); |
353 |
|
354 |
if (sourceRoots == null) { |
355 |
return null; |
356 |
} |
357 |
|
358 |
Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>> auxHandles = new HashMap<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>>(); |
359 |
|
360 |
if (!sourceDeps.containsKey(thisSourceRootURL)) { |
361 |
Set<URL> binaryRoots = new HashSet<URL>(); |
362 |
|
363 |
for (URL sr : sourceRoots) { |
364 |
List<URL> deps = sourceDeps.get(sr); |
365 |
|
366 |
if (deps != null) { |
367 |
binaryRoots.addAll(deps); |
368 |
} |
369 |
} |
370 |
|
371 |
binaryRoots.retainAll(binaryDeps.keySet()); |
372 |
|
373 |
for (ElementHandle<TypeElement> handle : baseHandles) { |
374 |
Set<ElementHandle<TypeElement>> types = computeUsers(ClasspathInfo.create(EMPTY, ClassPathSupport.createClassPath(binaryRoots.toArray(new URL[0])), EMPTY), SearchScope.DEPENDENCIES, Collections.singleton(handle), classIndexCumulative); |
375 |
|
376 |
if (types == null/*canceled*/ || cancel.get()) { |
377 |
return null; |
378 |
} |
379 |
|
380 |
auxHandles.put(handle, types); |
381 |
} |
382 |
} |
383 |
|
384 |
Map<URL, Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>>> result = new LinkedHashMap<URL, Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>>>(); |
385 |
|
386 |
for (URL file : sourceRoots) { |
387 |
for (ElementHandle<TypeElement> base : baseHandles) { |
388 |
if (cancel.get()) return null; |
389 |
|
390 |
Set<ElementHandle<TypeElement>> baseTypes = new HashSet<ElementHandle<TypeElement>>(); |
391 |
|
392 |
baseTypes.add(base); |
393 |
|
394 |
Set<ElementHandle<TypeElement>> aux = auxHandles.get(base); |
395 |
|
396 |
if (aux != null) { |
397 |
baseTypes.addAll(aux); |
398 |
} |
399 |
|
400 |
for (URL dep : sourceDeps.get(file)) { |
401 |
Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>> depTypesMulti = result.get(dep); |
402 |
Set<ElementHandle<TypeElement>> depTypes = depTypesMulti != null ? depTypesMulti.get(base) : null; |
403 |
|
404 |
if (depTypes != null) { |
405 |
baseTypes.addAll(depTypes); |
406 |
} |
407 |
} |
408 |
|
409 |
Set<ElementHandle<TypeElement>> types = computeUsers(file, baseTypes, classIndexCumulative); |
410 |
|
411 |
if (types == null/*canceled*/ || cancel.get()) { |
412 |
return null; |
413 |
} |
414 |
|
415 |
types.removeAll(baseTypes); |
416 |
|
417 |
Map<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>> currentUsers = result.get(file); |
418 |
|
419 |
if (currentUsers == null) { |
420 |
result.put(file, currentUsers = new LinkedHashMap<ElementHandle<TypeElement>, Set<ElementHandle<TypeElement>>>()); |
421 |
} |
422 |
|
423 |
currentUsers.put(base, types); |
424 |
} |
425 |
} |
426 |
|
427 |
return result; |
428 |
} |
429 |
|
430 |
private void findOverriddenAnnotations( |
431 |
URL sourceRoot, |
432 |
final Set<ElementHandle<TypeElement>> users, |
433 |
final ElementHandle<TypeElement> originalType, |
434 |
final List<ElementHandle<ExecutableElement>> methods, |
435 |
final Map<ElementHandle<? extends Element>, List<ElementDescription>> overriding) { |
436 |
if (!users.isEmpty()) { |
437 |
FileObject sourceRootFile = URLMapper.findFileObject(sourceRoot); |
438 |
ClasspathInfo cpinfo = ClasspathInfo.create(sourceRootFile); |
439 |
|
440 |
JavaSource js = JavaSource.create(cpinfo); |
441 |
|
442 |
try { |
443 |
js.runUserActionTask(new Task<CompilationController>() { |
444 |
public void run(CompilationController controller) throws Exception { |
445 |
Set<Element> seenElements = new HashSet<Element>(); |
446 |
Element resolvedOriginalType = originalType.resolve(controller); |
447 |
|
448 |
if (resolvedOriginalType == null) { |
449 |
return ; |
450 |
} |
451 |
|
452 |
for (ElementHandle<TypeElement> typeHandle : users) { |
453 |
if (cancel.get()) return ; |
454 |
TypeElement type = typeHandle.resolve(controller); |
455 |
|
456 |
if (type == null || !seenElements.add(type)) { |
457 |
continue; |
458 |
} |
459 |
|
460 |
Types types = controller.getTypes(); |
461 |
|
462 |
if (types.isSubtype(types.erasure(type.asType()), types.erasure(resolvedOriginalType.asType()))) { |
463 |
List<ElementDescription> classOverriders = overriding.get(originalType); |
464 |
|
465 |
if (classOverriders == null) { |
466 |
overriding.put(originalType, classOverriders = new LinkedList<ElementDescription>()); |
467 |
} |
468 |
|
469 |
classOverriders.add(new ElementDescription(controller, type, true)); |
470 |
|
471 |
for (ElementHandle<ExecutableElement> originalMethodHandle : methods) { |
472 |
ExecutableElement originalMethod = originalMethodHandle.resolve(controller); |
473 |
|
474 |
if (originalMethod != null) { |
475 |
ExecutableElement overrider = getImplementationOf(controller, originalMethod, type); |
476 |
|
477 |
if (overrider == null) { |
478 |
continue; |
479 |
} |
480 |
|
481 |
List<ElementDescription> overriddingMethods = overriding.get(originalMethodHandle); |
482 |
|
483 |
if (overriddingMethods == null) { |
484 |
overriding.put(originalMethodHandle, overriddingMethods = new ArrayList<ElementDescription>()); |
485 |
} |
486 |
|
487 |
overriddingMethods.add(new ElementDescription(controller, overrider, true)); |
488 |
} else { |
489 |
Logger.getLogger("global").log(Level.SEVERE, "IsOverriddenAnnotationHandler: originalMethod == null!"); //NOI18N |
490 |
} |
491 |
} |
492 |
} |
493 |
} |
494 |
} |
495 |
}, true); |
496 |
} catch (Exception e) { |
497 |
Exceptions.printStackTrace(e); |
498 |
} |
499 |
} |
500 |
} |
501 |
|
502 |
private static ExecutableElement getImplementationOf(CompilationInfo info, ExecutableElement overridee, TypeElement implementor) { |
503 |
for (ExecutableElement overrider : ElementFilter.methodsIn(implementor.getEnclosedElements())) { |
504 |
if (info.getElements().overrides(overrider, overridee, implementor)) { |
505 |
return overrider; |
506 |
} |
507 |
} |
508 |
|
509 |
return null; |
510 |
} |
511 |
|
512 |
static void performGoToAction(List<ElementDescription> declarations, Point position) { |
513 |
String caption = NbBundle.getMessage(GoToImplementation.class, "LBL_ImplementorsOverriders"); |
514 |
|
515 |
PopupUtil.showPopup(new IsOverriddenPopup(caption, declarations), caption, position.x, position.y, true, 0); |
516 |
} |
517 |
|
518 |
static Map<URL, List<URL>> dependenciesOverride; |
519 |
|
520 |
private static Map<URL, List<URL>> getDependencies(boolean binary) { |
521 |
if (dependenciesOverride != null) { |
522 |
return dependenciesOverride; |
523 |
} |
524 |
|
525 |
ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class); |
526 |
|
527 |
if (l == null) { |
528 |
return null; |
529 |
} |
530 |
|
531 |
Class clazz = null; |
532 |
String method = null; |
533 |
|
534 |
try { |
535 |
clazz = l.loadClass("org.netbeans.modules.parsing.impl.indexing.friendapi.IndexingController"); |
536 |
method = binary ? "getBinaryRootDependencies" : "getRootDependencies"; |
537 |
} catch (ClassNotFoundException ex) { |
538 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex); |
539 |
try { |
540 |
clazz = l.loadClass("org.netbeans.modules.parsing.impl.indexing.RepositoryUpdater"); |
541 |
method = binary ? "getDependencies" : "doesnotexist"; |
542 |
} catch (ClassNotFoundException inner) { |
543 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, inner); |
544 |
return null; |
545 |
} |
546 |
} |
547 |
|
548 |
try { |
549 |
Method getDefault = clazz.getDeclaredMethod("getDefault"); |
550 |
Object instance = getDefault.invoke(null); |
551 |
Method dependenciesMethod = clazz.getDeclaredMethod(method); |
552 |
|
553 |
return (Map<URL, List<URL>>) dependenciesMethod.invoke(instance); |
554 |
} catch (IllegalAccessException ex) { |
555 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex); |
556 |
return null; |
557 |
} catch (IllegalArgumentException ex) { |
558 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex); |
559 |
return null; |
560 |
} catch (InvocationTargetException ex) { |
561 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex); |
562 |
return null; |
563 |
} catch (NoSuchMethodException ex) { |
564 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex); |
565 |
return null; |
566 |
} catch (SecurityException ex) { |
567 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex); |
568 |
return null; |
569 |
} catch (ClassCastException ex) { |
570 |
Logger.getLogger(GoToImplementation.class.getName()).log(Level.FINE, null, ex); |
571 |
return null; |
572 |
} |
573 |
} |
574 |
|
575 |
} |