001: package tide.syntaxtree;
002:
003: import japa.parser.ast.body.*;
004: import japa.parser.ast.CompilationUnit;
005: import javaparser.*;
006: import javaparser.javacc_gen.*;
007: import tide.editor.*;
008: import tide.sources.*;
009: import snow.concurrent.*;
010: import snow.utils.gui.*;
011: import snow.utils.StringUtils;
012: import java.util.*;
013: import java.io.*;
014:
015: /** Some collected functions acting on the whole tree or branches.
016: * (removing trailing spaces, parsing to see warnings...)
017: */
018: public final class TreeFunctions {
019:
020: public static boolean detectSourcesWithoutTypeOfSameName = false;
021: public static boolean detectSourcesWithoutType = false;
022:
023: private TreeFunctions() {
024: }
025:
026: /** Removes the tailing spaces at the end of the lines + trim the source.
027: * TODO: don't work on files opened in the editor ...
028: */
029: public static void removeTailingSpaces(final List<SourceFile> sfs) {
030: final ProgressModalDialog pmd = new ProgressModalDialog(
031: MainEditorFrame.instance,
032: "Removing unuseful spaces in " + sfs.size()
033: + " sources", false);
034: pmd.setProgressBounds(sfs.size());
035: pmd.start();
036:
037: Thread t = new Thread() {
038: public void run() {
039: long removed = 0;
040: try {
041: MainEditorFrame.instance.outputPanels
042: .selectToolsTab(true);
043: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
044: .appendLine("Cleaning "
045: + sfs.size()
046: + " java files: removing tailing spaces\n");
047:
048: int modifFiles = 0;
049: sfl: for (SourceFile s : sfs) {
050: pmd.incrementProgress(1);
051: pmd.setProgressComment(s.getJavaName());
052: if (pmd.getWasCancelled()) {
053: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
054: .appendError("\nCleaning cancelled by user.\n");
055: break;
056: }
057:
058: if (!s.isEditable()) // was look
059: {
060: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
061: .appendError("\nNot editable source: "
062: + s.getJavaName() + "\n");
063: continue sfl;
064: }
065:
066: try {
067: String src = s.getContent().trim();
068: String nsrc = StringUtils
069: .removeLineTailSpaces(src);
070: int diff = src.length() - nsrc.length();
071: if (diff > 0) {
072: removed += diff;
073: modifFiles++;
074:
075: if (MainEditorFrame.debug) {
076: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
077: .appendLine(s.getJavaName()
078: + ":0: removed "
079: + diff + " chars");
080: }
081:
082: s.setCaretPositionToRemember(s
083: .getCaretLinePosition(), s
084: .getCaretColumnPosition());
085: s.setContentFromEditor(nsrc, true); // allow, because we are quick, we will "win" and write our version, some millis after another.
086: s.saveContentToFile();
087: }
088: } catch (Exception e) {
089: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
090: .appendError("\nCleaner ERROR\n"
091: + s.getJavaName() + ":0: "
092: + e.getMessage() + "\n");
093: e.printStackTrace();
094: }
095: }
096: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
097: .append("" + removed
098: + " characters removed in "
099: + modifFiles + " file"
100: + (modifFiles == 1 ? "" : "s"));
101: } finally {
102: pmd.closeDialog();
103: }
104: }
105: };
106: t.setName("Removing tailing spaces");
107: t.start();
108:
109: }
110:
111: /** Parses all files, searching for syntax problems and write them.
112: * REMARK: this allow us to see that the parse tree have NO memory leak !
113: * parsing 2500 files don't leaks !
114: */
115: public static void parseAllToSearchForProblems(
116: final List<SourceFile> sfs, final boolean onlyRawParse) {
117: final ProgressModalDialog pmd = new ProgressModalDialog(
118: MainEditorFrame.instance,
119: "Parsing "
120: + sfs.size()
121: + " sources with the CC parser of Sreenivasa Viswanadha",
122: false);
123: pmd.setProgressBounds(sfs.size());
124: pmd.start();
125:
126: Thread t = new Thread() {
127: public void run() {
128: try {
129: long t0 = System.currentTimeMillis();
130:
131: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
132: .setText("Parsing " + sfs.size()
133: + " java files\n");
134: MainEditorFrame.instance.outputPanels
135: .selectToolsTab(false);
136: int w = 0;
137: int err = 0;
138: int exc = 0;
139:
140: for (SourceFile s : sfs) {
141: pmd.incrementProgress(1);
142: pmd.setProgressComment(s.getJavaName());
143: if (pmd.getWasCancelled()) {
144: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
145: .appendError("\nParsing cancelled by user.");
146: break;
147: }
148:
149: try {
150: int[] wee = parse(s, onlyRawParse); //.getContent(), s.getJavaName(), s.javaFile);
151: w += wee[0];
152: err += wee[1];
153: exc += wee[2];
154: } catch (Exception e) {
155: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
156: .appendError("\nPARSER ERROR\n"
157: + s.getJavaName() + ": "
158: + e.getMessage());
159: e.printStackTrace();
160: }
161: }
162: if (MainEditorFrame.debug) {
163: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
164: .append("\nTotal time = "
165: + (System.currentTimeMillis() - t0)
166: + " ms, ");
167: }
168: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
169: .append("\n" + w + " warnings.");
170: if (err > 0) {
171: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
172: .appendError(" " + err + " errors.");
173: }
174: if (exc > 0) {
175: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
176: .appendError(" " + exc + " exceptions.");
177: }
178:
179: } finally {
180: pmd.closeDialog();
181: }
182: }
183: };
184: t.setName("Parse debug");
185: t.start();
186:
187: }
188:
189: /** Parses all files, searching for syntax problems and write them.
190: * REMARK: this allow us to see that the parse tree have NO memory leak !
191: * parsing 2500 files don't leaks !
192: */
193: public static void parseAllToSearchForProblems2(
194: final List<SourceFile> sfs, final boolean onlyRawParse) {
195: final ProgressModalDialog pmd = new ProgressModalDialog(
196: MainEditorFrame.instance,
197: "Parsing "
198: + sfs.size()
199: + " sources with the new CC parser of Júlio Vilmar Gesser (jgesser@gmail.com)",
200: false);
201: pmd.setProgressBounds(sfs.size());
202: pmd.start();
203:
204: Thread t = new Thread() {
205: public void run() {
206: try {
207: long t0 = System.currentTimeMillis();
208:
209: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
210: .setText("Parsing " + sfs.size()
211: + " java files\n");
212: MainEditorFrame.instance.outputPanels
213: .selectToolsTab(false);
214: int w = 0, err = 0, exc = 0;
215: for (SourceFile s : sfs) {
216: pmd.incrementProgress(1);
217: pmd.setProgressComment(s.getJavaName());
218: if (pmd.getWasCancelled()) {
219: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
220: .appendError("\nParsing cancelled by user.");
221: break;
222: }
223:
224: try {
225: int[] wee = parse2(s, onlyRawParse); //.getContent(), s.getJavaName(), s.javaFile);
226: w += wee[0];
227: err += wee[1];
228: exc += wee[2];
229:
230: } catch (Exception e) {
231: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
232: .appendError("\nPARSER ERROR\n"
233: + s.getJavaName() + ": "
234: + e.getMessage());
235: e.printStackTrace();
236: }
237: }
238: //if(MainEditorFrame.debug)
239: {
240: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
241: .append("\nTotal time = "
242: + (System.currentTimeMillis() - t0)
243: + " ms, ");
244: }
245: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
246: .append("\n" + w + " warnings.");
247: if (err > 0) {
248: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
249: .appendError(" " + err + " errors.");
250: }
251: if (exc > 0) {
252: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
253: .appendError(" " + exc + " exceptions.");
254: }
255:
256: } finally {
257: pmd.closeDialog();
258: }
259: }
260: };
261: t.setName("Parse debug");
262: t.start();
263:
264: }
265:
266: /** The thread must be launched with start() after creation.
267: */
268: public static Thread createDetectDependenciesThread(
269: final List<SourceFile> sfs, final boolean writeOut) {
270: // A safe swing call
271: final ProgressModalDialog[] pmd = new ProgressModalDialog[1];
272: new SwingSafeRunnable(new Runnable() {
273: public void run() {
274: pmd[0] = new ProgressModalDialog(
275: MainEditorFrame.instance,
276: "Detecting dependencies of " + sfs.size()
277: + " sources", false);
278: }
279: }, true).run();
280:
281: MainEditorFrame.debugOut("Detecting dependentcies of "
282: + sfs.size() + " sources.");
283:
284: pmd[0].setProgressBounds(sfs.size());
285: pmd[0].start();
286:
287: Thread t = new Thread() {
288: public void run() {
289: try {
290: long t0 = System.currentTimeMillis();
291:
292: if (writeOut) {
293: MainEditorFrame.instance.outputPanels
294: .selectToolsTab(true);
295: }
296:
297: /* debug
298: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("Detecting dependencies of "+sfs.size()+" java files");
299: if(sfs.size()>0 && sfs.size()<5)
300: {
301: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine(": "+sfs);
302: }
303: else
304: {
305: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine("");
306: }*/
307:
308: for (final SourceFile s : sfs) {
309: pmd[0].incrementProgress(1);
310: pmd[0].setProgressComment(s.getJavaName());
311: if (pmd[0].getWasCancelled()) {
312: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
313: .appendErrorLine("Parsing cancelled by user.");
314: break;
315: }
316:
317: try {
318: DependenciesDetector.updateDependencies(s,
319: writeOut);
320: //MainEditorFrame.debugOut("Updated: "+s.sourceFileDependencies);
321: } catch (Exception e) {
322: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
323: .appendErrorLine("PARSER ERROR\n"
324: + s.getJavaName() + ": "
325: + e.getMessage());
326: e.printStackTrace();
327: }
328: }
329:
330: if (MainEditorFrame.debug) {
331: long dt = (System.currentTimeMillis() - t0);
332: if (dt > 1000) {
333: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
334: .appendLine("Total dependencies detecting time = "
335: + dt
336: + " ms for "
337: + sfs.size() + " files");
338: }
339: }
340: } finally {
341: pmd[0].closeDialog();
342: }
343: }
344: };
345: t.setName("Dependencies detection");
346:
347: return t;
348: }
349:
350: /** ex: japa.parser.ParseException: Encountered "(" at line 116, column 43.
351: */
352: private static int[] getLinColFromParserMess(String message) {
353: int line = 0;
354: int pos = message.indexOf("line ");
355: if (pos > 0) {
356: int posE = message.indexOf(',', pos + 5);
357: if (posE > 0) {
358: String ls = message.substring(pos + 5, posE);
359: //System.out.println("Error node: ls="+ls);
360: try {
361: line = Integer.parseInt(ls);
362: } catch (Exception ee) {
363: }
364: }
365: }
366:
367: int column = 0;
368: pos = message.indexOf("column ", pos);
369: if (pos > 0) {
370: int posE = message.indexOf('.', pos + 7);
371: if (posE > 0) {
372: String ls = message.substring(pos + 7, posE);
373: try {
374: column = Integer.parseInt(ls);
375: } catch (Exception ee) {
376: }
377: }
378: }
379: return new int[] { line, column };
380: }
381:
382: /** @return the number of warnings.
383: * AST dev trick: search in the DumpVisitor to find out where the items araises...
384: */
385: public static int[] parse2(FileItem f, boolean onlyRawParse) {
386: int w = 0;
387: int err = 0;
388: int exc = 0;
389:
390: //long t0 = System.currentTimeMillis();
391: try {
392: // special case.
393: if (f.getJavaPartName().equals("package-info"))
394: return new int[3];
395:
396: StringReader sr = new StringReader(f.getContent());
397: CompilationUnit cu = japa.parser.JavaParser.parse(sr);
398:
399: if (onlyRawParse)
400: return new int[3]; // just to see if it is parsable
401:
402: // System.out.println(""+ cu.pakage.toString());
403: String pan = cu.pakage != null ? cu.pakage.toString() : "";
404: /* if(!f.getPackageName().equals(pan))
405: {
406: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append("\n\tat "+f.getJavaName()+"("+f.getJavaPartName()+".java:"+1+")");
407: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.append(": bad package name '"+pan+"' should be '"
408: +f.getPackageName()+"'");
409: w++;
410: }*/
411:
412: List<TypeDeclaration> types = cu.types;
413:
414: //System.out.println(""+types);
415: if (types == null || types.isEmpty()) {
416: if (detectSourcesWithoutType) {
417: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
418: .append("\n\tat " + f.getJavaName() + "("
419: + f.getJavaPartName() + ".java:"
420: + 1 + ")");
421: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
422: .append(": no declared type");
423: w++;
424: }
425: } else {
426: boolean hasNamed = false;
427: for (TypeDeclaration ti : types) {
428: //System.out.println("type: "+ti.name);
429: // ti is null when classes blocks have exceding ";" at end, as in 1.6 and 1.7 src.
430: if (detectSourcesWithoutTypeOfSameName
431: && ti.name != null
432: && ti.name.equals(f.getJavaPartName())) {
433: hasNamed = true;
434: }
435: //analyse(ti);
436: }
437:
438: if (detectSourcesWithoutTypeOfSameName && !hasNamed) {
439: w++;
440: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
441: .append("\n\tat " + f.getJavaName() + "("
442: + f.getJavaPartName() + ".java:"
443: + 1 + ")");
444: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
445: .append(": no type named '"
446: + f.getJavaPartName() + "'");
447: }
448: }
449:
450: } catch (Error e) // REALLY ! Lexical error
451: {
452: int[] lc = getLinColFromParserMess(e.getMessage());
453: //MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
454: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
455: .appendErrorLine("\n\tat " + f.getJavaName() + "("
456: + f.getJavaPartName() + ".java:" + lc[0]
457: + "): ERROR "
458: + StringUtils.firstLine(e.getMessage()));
459: //e.printStackTrace();
460: err++;
461: } catch (Exception e) {
462: int[] lc = getLinColFromParserMess(e.getMessage());
463: //MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
464: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
465: .appendErrorLine("\n\tat " + f.getJavaName() + "("
466: + f.getJavaPartName() + ".java:" + lc[0]
467: + "): "
468: + StringUtils.firstLine(e.getMessage()));
469: //e.printStackTrace();
470: exc++;
471: }
472:
473: return new int[] { w, err, exc };
474: }
475:
476: @tide.annotations.Recurse
477: static void analyse(TypeDeclaration ti) {
478: System.out.println("Visiting type " + ti.name);
479:
480: JapaVisitor jv = new JapaVisitor();
481: ti.accept(jv, null); //??
482:
483: for (BodyDeclaration mi : ti.members) // fields, methods, inner class,...
484: {
485: //System.out.println("mi:"+mi);
486: mi.accept(jv, null); //??
487:
488: if (mi instanceof TypeDeclaration) {
489: analyse((TypeDeclaration) mi);
490: }
491: }
492: }
493:
494: /** @return the number of warnings.
495: */
496: public static int[] parse(FileItem f, boolean onlyRawParse) {
497: int w = 0;
498: int err = 0;
499: int exc = 0;
500: //long t0 = System.currentTimeMillis();
501: try {
502: StringReader sr = new StringReader(f.getContent());
503: JavaParser pa = new JavaParser(sr);
504: pa.disable_tracing();
505: RAWSyntaxTree st = new RAWSyntaxTree(f.getJavaName());
506: pa.parserOutputProcessor = st;
507:
508: pa.CompilationUnit();
509:
510: if (onlyRawParse)
511: return new int[3];
512:
513: //System.out.println("\nJavaParser took " + (System.currentTimeMillis()-t0) + " ms for "+f);
514: final SimplifiedSyntaxTree2 sst = new SimplifiedSyntaxTree2(
515: st.root, f.getJavaName());
516: TreeFunctions.searchForCommonProblems(sst, sst.root, f
517: .getJavaName());
518: sst.callAtEndToMakeWarningsVisible();
519:
520: w = sst.getWarningsCount();
521: if (w > 0) {
522: for (int i = 0; i < w; i++) {
523: WarningNode wn = sst.getWarningNodeAt(i);
524: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
525: .append("\n\tat " + f.getJavaName() + "("
526: + f.getJavaPartName() + ".java:"
527: + wn.getStartLinCol()[0] + "): ");
528:
529: if (wn.gravity == 1) {
530: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
531: .appendError(wn.toString());
532: } else {
533: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
534: .append(wn.toString());
535: }
536: }
537: }
538:
539: //System.out.println(""+fileName +"\t" +(System.currentTimeMillis()-t0) + "");
540: //final DefaultTreeModel tm = new DefaultTreeModel(sst.root);
541: } catch (Error e) // REALLY ! Lexical error
542: {
543: int[] lc = getLinColFromParserMess(e.getMessage());
544: //MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
545: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
546: .appendErrorLine("\n\tat " + f.getJavaName() + "("
547: + f.getJavaPartName() + ".java:" + lc[0]
548: + "): ERROR "
549: + StringUtils.firstLine(e.getMessage()));
550: //e.printStackTrace();
551: err++;
552: } catch (Exception e) {
553: int[] lc = getLinColFromParserMess(e.getMessage());
554: //MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendError("\nParseerror: "+e.getMessage());
555: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
556: .appendErrorLine("\n\tat " + f.getJavaName() + "("
557: + f.getJavaPartName() + ".java:" + lc[0]
558: + "): "
559: + StringUtils.firstLine(e.getMessage()));
560: //e.printStackTrace();
561: exc++;
562: }
563:
564: return new int[] { w, err, exc };
565: }
566:
567: /** Apply all searches for common known problems.
568: */
569: public static void searchForCommonProblems(
570: SimplifiedSyntaxTree2 sst, final ParserTreeNode root,
571: String javaName) {
572: ProblemsSearch.analyseFile(sst, javaName);
573: searchForCommonProblemsRecurse(sst, root);
574: }
575:
576: private static void searchForCommonProblemsRecurse(
577: SimplifiedSyntaxTree2 sst, final ParserTreeNode root) {
578:
579: for (int i = 0; i < root.getChildCount(); i++) {
580: final ParserTreeNode ci = root.getChildNodeAt(i);
581: if (ci instanceof ClassNode) {
582: ProblemsSearch.analyseClass(sst, (ClassNode) ci);
583: }
584: // recursively look for errors
585: searchForCommonProblemsRecurse(sst, ci);
586: }
587: }
588:
589: }
|