001: package tide.sources;
002:
003: import japa.parser.ast.*;
004: import java.lang.reflect.Method;
005: import tide.classsyntax.SingleClassLoader;
006: import tide.editor.MainEditorFrame;
007: import tide.syntaxtree.*;
008: import javaparser.*;
009: import java.util.Locale;
010: import java.util.*;
011:
012: /** Used to search for types in the trees.
013: */
014: public final class TypeLocator {
015: private TypeLocator() {
016: }
017:
018: /** This is the best, using imports !
019: * @param originPackage is used to try to match other classes in the same package as the source where this was called.
020: */
021: public static FileItem locateUsingStaticImports(
022: final ParserResult pr, final SingleClassLoader scl,
023: final String javaName, final boolean isMethod,
024: final String originPackage) {
025: MainEditorFrame.debugOut("Locate static import2 " + javaName
026: + " from " + originPackage + ", meth=" + isMethod);
027: if (pr == null)
028: return null;
029:
030: for (final ImportDeclaration ipd : pr.compilationUnit.imports) {
031: if (!ipd.isStatic)
032: continue; // only look at static imports
033:
034: //String im = in.getImportName();
035: if (ipd.isAsterisk) {
036: String im = "" + ipd.name;
037: FileItem it = locateQuick(im);
038: // look in bytecode for public static methods and fields
039: // as sin, Pi in java.lang.Math
040: if (it != null && scl != null) {
041: try {
042: Class cl = scl.findClass(im);
043: if (cl != null) {
044: if (isMethod) {
045: for (Method m : cl.getDeclaredMethods()) {
046: if (m.getName().equals(javaName))
047: return it;
048: }
049: } else {
050: if (cl.getDeclaredField(javaName) != null) // only looks for public (?)
051: {
052: // FOUND !
053: return it;
054: }
055: }
056: }
057: } catch (Exception ex) {
058: ex.printStackTrace();
059: } catch (Error ex) {
060: ex.printStackTrace();
061: }
062: }
063: //scl;
064: } else {
065: String typeName = "" + ipd.name; // i.e. java.lang.Math.sin
066: String im = typeName;
067: int pos = typeName.lastIndexOf(".");
068: if (pos >= 0) {
069: im = im.substring(pos + 1); // sin
070: typeName = typeName.substring(0, pos); // java.lang.Math
071: }
072:
073: if (im.equals(javaName)) // sin
074: {
075: FileItem it = locateQuick(typeName);
076: if (it != null)
077: return it;
078: MainEditorFrame
079: .debugOut("Error: cannot locate static import type "
080: + typeName);
081: }
082:
083: }
084:
085: }
086: return null;
087: }
088:
089: /* This is the best, using imports !
090: * @param originPackage is used to try to match other classes in the same package as the source where this was called.
091: *
092: @Deprecated
093: public static FileItem locateUsingStaticImports(final ParserTreeNode imports, SingleClassLoader scl, String javaName, boolean isMethod, String originPackage)
094: {
095: MainEditorFrame.debugOut("Locate static import "+javaName+" from "+originPackage+", meth="+isMethod);
096: if(imports==null) return null;
097:
098: for(int i=0; i<imports.getChildCount(); i++)
099: {
100: ImportNode in = (ImportNode) imports.getChildNodeAt(i);
101: if(!in.isStatic()) continue; // only look at static imports
102:
103: String im = in.getImportName();
104: if(im.endsWith(".*"))
105: {
106: im = im.substring(0,im.length()-2);
107: FileItem it = locateQuick( im );
108: // look in bytecode for public static methods and fields
109: // as sin, Pi in java.lang.Math
110: if(it!=null && scl!=null)
111: {
112: try
113: {
114: Class cl = scl.findClass(im);
115: if(cl!=null)
116: {
117: if(isMethod)
118: {
119: for(Method m : cl.getDeclaredMethods())
120: {
121: if(m.getName().equals(javaName)) return it;
122: }
123: }
124: else
125: {
126: if(cl.getDeclaredField(javaName)!=null) // only looks for public (?)
127: {
128: // FOUND !
129: return it;
130: }
131: }
132: }
133: }
134: catch(Exception ex) {ex.printStackTrace();}
135: catch(Error ex) {ex.printStackTrace();}
136: }
137: //scl;
138: }
139: else
140: {
141: String typeName = im;
142: int pos = im.lastIndexOf(".");
143: if(pos>=0)
144: {
145: im = im.substring(pos+1); // i.e. java.lang.Math.sin
146: typeName = typeName.substring(0, pos);
147: }
148:
149: if(im.equals(javaName)) // sin
150: {
151: FileItem it = locateQuick( typeName );
152: if(it!=null) return it;
153: MainEditorFrame.debugOut("Error: cannot locate static import type "+typeName);
154: }
155:
156: }
157:
158: }
159: return null;
160: }*/
161:
162: @edu.umd.cs.findbugs.annotations.CheckForNull
163: @SuppressWarnings("deprecation")
164: public static FileItem locateUsingImports(final FileItem src,
165: final String javaName) {
166: if (src.getParserResultIfAlreadyMade() != null) {
167: return locateUsingImports(src
168: .getParserResultIfAlreadyMade(), javaName, src
169: .getPackageName());
170: } else if (src.getSimplifiedSyntaxTreeIfAlreadyMade() != null) {
171: //OLD
172: return locateUsingImports(
173: src.getSimplifiedSyntaxTreeIfAlreadyMade().importsNode,
174: javaName, src.getPackageName());
175: }
176:
177: return null;
178: }
179:
180: private static FileItem locateUsingImports(final ParserResult pr,
181: final String javaName, final String originPackage) {
182: //System.out.println("Locate "+javaName+" from "+originPackage);
183:
184: FileItem it = null;
185:
186: // 1) search in the origin package (where the analysis started !)
187: if (originPackage != null && originPackage.length() > 0) {
188: it = locateQuick(originPackage + "." + javaName);
189: if (it != null)
190: return it;
191: }
192:
193: // 2) search in java.lang
194: it = locateQuick("java.lang." + javaName);
195: if (it != null)
196: return it;
197:
198: if (pr == null || pr.compilationUnit == null) {
199: System.out.println("No comp unit");
200: return null;
201: }
202:
203: // 3) through all declared imports packages
204: if (pr.compilationUnit.imports == null) {
205: return null; // well defined, really no imports statements.
206: }
207:
208: for (final ImportDeclaration idi : pr.compilationUnit.imports) {
209: if (idi.isAsterisk) {
210: it = locateQuick("" + idi.name + "." + javaName);
211: if (it != null)
212: return it;
213: } else {
214: // [April2007]: the dot is important.
215: final String im = "" + idi.name;
216: if (im.endsWith("." + javaName)) {
217: it = locateQuick(im);
218: if (it != null)
219: return it;
220: }
221: }
222: }
223:
224: // 4) exact search "javax.swing.JFrame"
225: // made at end, to avoid importing classes from toplevel if we are not in toplevel !
226: // (TODO: we can also place this test as 0) and check for package names) (if quicker)
227: it = locateQuick(javaName);
228: if (it != null)
229: return it;
230:
231: return null;
232:
233: }
234:
235: /** This is the best, using imports !
236: * Todo: static imports too...
237: * @param originPackage is used to try to match other classes in the same package as the source where this was called.
238: */
239: private static FileItem locateUsingImports(ParserTreeNode imports,
240: String javaName, String originPackage) {
241: //System.out.println("Locate "+javaName+" from "+originPackage);
242:
243: FileItem it = null;
244:
245: // 1) search in the origin package (where the analysis started !)
246: if (originPackage != null && originPackage.length() > 0) {
247: it = locateQuick(originPackage + "." + javaName);
248:
249: if (it != null)
250: return it;
251: }
252:
253: // 2) search in java.lang
254: it = locateQuick("java.lang." + javaName);
255: if (it != null)
256: return it;
257:
258: // 3) through all declared imports packages
259: if (imports == null)
260: return null;
261:
262: for (int i = 0; i < imports.getChildCount(); i++) {
263: // also analyse static imports ???
264: ImportNode imn = (ImportNode) imports.getChildNodeAt(i);
265: String im = imn.getImportName();
266: // either "xxx.yyy.*" or "xxx.yyy.Z"
267: if (im.endsWith(".*")) {
268: it = locateQuick(im.substring(0, im.length() - 2) + "."
269: + javaName);
270: if (it != null)
271: return it;
272: } else {
273: // [April2007]: the dot is important.
274: if (im.endsWith("." + javaName)) {
275: it = locateQuick(im);
276: if (it != null)
277: return it;
278: }
279: }
280: }
281:
282: // 4) exact search "javax.swing.JFrame"
283: // made at end, to avoid importing classes from toplevel if we are not in toplevel !
284: // (TODO: we can also place this test as 0) and check for package names) (if quicker)
285: it = locateQuick(javaName);
286: if (it != null)
287: return it;
288:
289: return null;
290: }
291:
292: /** Useful to provide some help.
293: * @return only the types that are not in the imports node (as wildcard OR single type)
294: */
295: @Deprecated
296: public static List<FileItem> locateMissingImport(
297: ParserTreeNode imports, String javaSimpleName,
298: String originPackage) {
299: SourcesTreeModel sourcesTree = MainEditorFrame.instance
300: .getActualProject().sourcesTreeModel;
301: List<SourceFile> lsf = sourcesTree
302: .getAllSourceFilesContainingName(javaSimpleName, true,
303: true); // exact and case sens.
304:
305: Set<String> importPackages = new HashSet<String>();
306: importPackages.add(originPackage);
307: Set<String> importedTypes = new HashSet<String>();
308: for (int i = 0; i < imports.getChildCount(); i++) {
309: String im = ((ImportNode) imports.getChildNodeAt(i))
310: .getImportName();
311: // either "xxx.yyy.*" or "xxx.yyy.Z"
312: if (im.endsWith(".*")) {
313: importPackages.add(im.substring(0, im.length() - 2));
314: } else {
315: importedTypes.add(im);
316: }
317: }
318:
319: List<FileItem> foundMissingImportsCandidates = new ArrayList<FileItem>();
320: for (SourceFile sf : lsf) {
321: if (importPackages.contains(sf.getPackageName()))
322: continue;
323: if (importedTypes.contains(sf.getJavaName()))
324: continue;
325: // ouh, we have it !
326: // TODO: keep "shortest", "nearest", "most used" ??
327: foundMissingImportsCandidates.add(sf);
328: }
329:
330: // not found, look in the libs
331: LibrariesTreeModel libsTree = MainEditorFrame.instance
332: .getActualProject().librariesTreeModel;
333: lsf.clear();
334: List<LibFileItem> lsfl = libsTree.getAllFilesContainingName(
335: javaSimpleName, true, true, true); // exact and case sens.
336: for (LibFileItem lf : lsfl) {
337: if (importPackages.contains(lf.getPackageName()))
338: continue;
339: if (importedTypes.contains(lf.getJavaName()))
340: continue;
341: foundMissingImportsCandidates.add(lf);
342: }
343:
344: return foundMissingImportsCandidates;
345: }
346:
347: /** Useful to provide some help.
348: * @return only the types that are not in the imports node (as wildcard OR single type)
349: */
350: public static List<FileItem> locateMissingImport(
351: final ParserResult pr, final String javaSimpleName,
352: final String originPackage) {
353: SourcesTreeModel sourcesTree = MainEditorFrame.instance
354: .getActualProject().sourcesTreeModel;
355: List<SourceFile> lsf = sourcesTree
356: .getAllSourceFilesContainingName(javaSimpleName, true,
357: true); // exact and case sens.
358:
359: Set<String> importPackages = new HashSet<String>();
360: importPackages.add(originPackage);
361: Set<String> importedTypes = new HashSet<String>();
362:
363: if (pr.compilationUnit.imports != null) {
364: for (final ImportDeclaration it : pr.compilationUnit.imports) {
365: if (it.isAsterisk) {
366: importPackages.add("" + it.name); // yes
367: } else {
368: importedTypes.add("" + it.name); // yes
369: }
370: }
371: }
372:
373: List<FileItem> foundMissingImportsCandidates = new ArrayList<FileItem>();
374: for (SourceFile sf : lsf) {
375: if (importPackages.contains(sf.getPackageName()))
376: continue;
377: if (importedTypes.contains(sf.getJavaName()))
378: continue;
379: // ouh, we have it !
380: // TODO: keep "shortest", "nearest", "most used" ??
381: foundMissingImportsCandidates.add(sf);
382: //return sf;
383: }
384:
385: // not found, look in the libs
386: LibrariesTreeModel libsTree = MainEditorFrame.instance
387: .getActualProject().librariesTreeModel;
388: lsf.clear();
389: List<LibFileItem> lsfl = libsTree.getAllFilesContainingName(
390: javaSimpleName, true, true, true); // exact and case sens.
391: for (LibFileItem lf : lsfl) {
392: if (importPackages.contains(lf.getPackageName()))
393: continue;
394: if (importedTypes.contains(lf.getJavaName()))
395: continue;
396: foundMissingImportsCandidates.add(lf);
397: //return lf;
398: }
399:
400: return foundMissingImportsCandidates;
401: }
402:
403: /** case sensitive search
404: */
405: public static FileItem locateQuick(final String javaName) {
406: return locateQuick(javaName, true);
407: }
408:
409: /** uses the models hashtables to quickly locate a type
410: */
411: public static FileItem locateQuick(final String javaName,
412: final boolean caseSensitive) {
413: // 1) exact search
414: // search in sources
415: SourcesTreeModel sourcesTree = MainEditorFrame.instance
416: .getActualProject().sourcesTreeModel;
417: FileItem it = sourcesTree.quickGet(javaName, caseSensitive);
418:
419: if (it != null) {
420: //System.out.println("Found in quick cache: "+javaName);
421: return it;
422: }
423:
424: // search in libraries
425: LibrariesTreeModel libsTree = MainEditorFrame.instance
426: .getActualProject().librariesTreeModel;
427: it = libsTree.quickGet(javaName, caseSensitive);
428: if (it != null) {
429: return it;
430: }
431:
432: return null; // not found
433: }
434:
435: /** Quick. Be careful, returns the first hit, ...
436: * Be careful, several libs defines "javax" root packages...
437: */
438: public static FileItem locateFirstPackage(final String javaName) {
439: // 1) exact search
440: // search in sources
441: SourcesTreeModel sourcesTree = MainEditorFrame.instance
442: .getActualProject().sourcesTreeModel;
443: FileItem it = sourcesTree.quickPackageGet(javaName, true);
444: if (it != null)
445: return it;
446:
447: // search in libraries
448: LibrariesTreeModel libsTree = MainEditorFrame.instance
449: .getActualProject().librariesTreeModel;
450: it = libsTree.quickPackageGet(javaName, true);
451: return it; // null if not found
452: }
453:
454: /** useful to locate for example all javax packages (there is one in rt.jar, but also in some other jar !! or project)
455: */
456: public static List<FileItem> locateAllPackages(String javaName) {
457: // in the sources
458: List<FileItem> packs = new ArrayList<FileItem>();
459: SourcesTreeModel sourcesTree = MainEditorFrame.instance
460: .getActualProject().sourcesTreeModel;
461: FileItem it = sourcesTree.quickPackageGet(javaName, true);
462: if (it != null)
463: packs.add(it);
464:
465: // the libs
466: LibrariesTreeModel libsTree = MainEditorFrame.instance
467: .getActualProject().librariesTreeModel;
468: packs.addAll(libsTree.getAllPackages(javaName));
469:
470: return packs;
471: }
472:
473: /* locate the given type. BAD routine, use when the imports node not exists !
474: *
475: public static FileItem locateLazy(String name)
476: {
477: // don't search for "this", "super", "true" .... and also not for "12.3223" !
478: if(SyntaxUtils.isValidIdentifier(name)) return null;
479:
480: // exact search
481: final Vector<SourceFile> hits = MainEditorFrame.instance.sourcesTreePanel.getTreeModel().getAllSourceFilesContainingName(name, true, true);
482: final Vector<LibFileItem> hitsLib = MainEditorFrame.instance.librariesPanel.getTreeModel().getAllFilesContainingName(name, true, true);
483:
484: if(hits.isEmpty() && hitsLib.isEmpty())
485: {
486: hits.addAll( MainEditorFrame.instance.sourcesTreePanel.getTreeModel().getAllSourceFilesContainingName(name, true, false) );
487: if(hits.isEmpty())
488: {
489: hits.addAll( MainEditorFrame.instance.sourcesTreePanel.getTreeModel().getAllSourceFilesContainingName(name, false, false) );
490: }
491:
492: if(hits.isEmpty())
493: {
494: hitsLib.addAll( MainEditorFrame.instance.librariesPanel.getTreeModel().getAllFilesContainingName(name, true, false) );
495: }
496:
497: if(hitsLib.isEmpty())
498: {
499: hitsLib.addAll( MainEditorFrame.instance.librariesPanel.getTreeModel().getAllFilesContainingName(name, false, false) );
500: }
501: }
502:
503: if(hits.size()==1)
504: {
505: return hits.elementAt(0);
506: }
507: else if(hits.size()>1)
508: {
509: System.out.println("Warning: several types found with name "+name);
510: return hits.elementAt(0);
511: }
512:
513: // no src => look in libs
514: if(hitsLib.size()==1)
515: {
516: return hitsLib.get(0);
517: }
518: else if(hitsLib.size()>1)
519: {
520: System.out.println("Warning: several types found with name "+name);
521: return hitsLib.get(0);
522: }
523:
524: System.out.println("No type found for "+name);
525: return null;
526:
527: }*/
528:
529: /** finds a type (ex: snow.utils.Hello) or simply "Hello".
530: * TODO: use package names to limit search scope ?
531: */
532: public static FileItem searchTypeForName(String searchForJavaName,
533: boolean ignoreCases, boolean approximateSearchEndingWith) {
534: if (ignoreCases)
535: searchForJavaName = searchForJavaName
536: .toUpperCase(Locale.ENGLISH);
537: // search in sources
538: SourcesTreeModel sourcesTree = MainEditorFrame.instance
539: .getActualProject().sourcesTreeModel;
540: List<SourceFile> allSources = sourcesTree
541: .getAllSourceFiles(false);
542: FileItem it = searchTypeForName(allSources, searchForJavaName,
543: ignoreCases, false);
544: if (it != null)
545: return it;
546:
547: // search in libraries
548: LibrariesTreeModel libsTree = MainEditorFrame.instance
549: .getActualProject().librariesTreeModel;
550: List<LibFileItem> allLibs = libsTree.getAllFiles();
551:
552: // fill first (twice...) with the "java.lang" subfiles !
553: // LibFileItem jlf = libsTree.getPackage("java.lang");
554:
555: it = searchTypeForName(allLibs, searchForJavaName, ignoreCases,
556: false);
557: if (it != null)
558: return it;
559:
560: if (approximateSearchEndingWith) {
561: it = searchTypeForName(allSources, searchForJavaName,
562: ignoreCases, true);
563: if (it != null)
564: return it;
565: it = searchTypeForName(allLibs, searchForJavaName,
566: ignoreCases, true);
567: if (it != null)
568: return it;
569: }
570:
571: // not found !
572: return null;
573: }
574:
575: private static FileItem searchTypeForName(
576: java.util.List<? extends FileItem> items,
577: String searchForJavaName, boolean ignoreCases,
578: boolean approximateSearchEndingWith) {
579: boolean hasPoint = searchForJavaName.indexOf('.') >= 0;
580: for (FileItem s : items) {
581: String jn = s.getJavaName();
582: if (ignoreCases)
583: jn = jn.toUpperCase(Locale.ENGLISH);
584:
585: if (jn.equals(searchForJavaName)) // full match
586: {
587: return s;
588: }
589:
590: if (!hasPoint && jn.indexOf('.') >= 0) {
591: if (jn.equals("java.lang." + searchForJavaName)) {
592: return s;
593: }
594: }
595:
596: if (approximateSearchEndingWith) {
597: String namee = searchForJavaName;
598: if (!hasPoint && jn.indexOf('.') >= 0)
599: namee = "." + searchForJavaName; // so we can use endsWith() ! the special case of toplevel is treated above.
600: if (jn.endsWith(namee)) {
601: return s;
602: }
603: }
604: }
605:
606: // not found !
607: return null;
608: }
609:
610: public static List<FileItem> searchSimpleNamesStartingWith(
611: String start) {
612: List<FileItem> hits = new ArrayList<FileItem>();
613: // case sensitive & exact
614: hits.addAll(MainEditorFrame.instance.sourcesTreePanel
615: .getTreeModel().getAllSourceFilesContainingName(start,
616: true, true));
617: hits.addAll(MainEditorFrame.instance.librariesPanel
618: .getTreeModel().getAllFilesContainingName(start, true,
619: true, true));
620:
621: // inexact
622: if (hits.isEmpty()) {
623: hits
624: .addAll(MainEditorFrame.instance.sourcesTreePanel
625: .getTreeModel()
626: .getAllSourceFilesWithSimpleNameStartingWith(
627: start));
628: hits.addAll(MainEditorFrame.instance.librariesPanel
629: .getTreeModel()
630: .getAllJavaFilesWithSimpleNameStartingWith(start));
631: }
632: return hits;
633:
634: }
635:
636: }
|