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.cnd.modelimpl.debug;
043:
044: import antlr.RecognitionException;
045: import java.io.*;
046: import java.util.ArrayList;
047: import java.util.Collections;
048: import java.util.Comparator;
049: import java.util.HashMap;
050: import java.util.HashSet;
051: import java.util.Iterator;
052: import java.util.List;
053: import java.util.Map;
054: import java.util.Set;
055: import org.netbeans.modules.cnd.api.model.CsmFile;
056: import org.netbeans.modules.cnd.modelimpl.parser.generated.CPPParser;
057: import org.openide.util.Exceptions;
058:
059: /**
060: * Debugging output, collect file statistics
061: *
062: * Usecase from test harness:
063: * if (Diagnostic.getStatisticsLevel() == 0) {
064: * // need to set the default level
065: * Diagnostic.setStatisticsLevel(DEFAULT_TRACEMODEL_STATISTICS_LEVEL);
066: * }
067: * Diagnostic.initFileStatistics(file.getAbsolutePath());
068: * ...
069: * Diagnostic.dumpFileStatistics(dumpFile);
070: *
071: * @author Vladimir Kvashin, Vladimir Voskresensky
072: */
073: public class Diagnostic {
074:
075: private static int STATISTICS_LEVEL = Integer.getInteger(
076: "cnd.modelimpl.stat.level", 0).intValue(); // NOI18N
077:
078: private static DiagnosticUnresolved diagnosticUnresolved = null;
079:
080: public static class StopWatch {
081:
082: private long time;
083: private long lastStart;
084: private boolean running;
085:
086: public StopWatch() {
087: this (true);
088: }
089:
090: public StopWatch(boolean start) {
091: time = 0;
092: if (start) {
093: start();
094: }
095: }
096:
097: public void start() {
098: running = true;
099: lastStart = System.currentTimeMillis();
100: }
101:
102: public void stop() {
103: running = false;
104: time += System.currentTimeMillis() - lastStart;
105: }
106:
107: public void stopAndReport(String text) {
108: stop();
109: report(text);
110: }
111:
112: public void report(String text) {
113: System.err.println(' ' + text + ' ' + time + " ms");
114: }
115:
116: public boolean isRunning() {
117: return running;
118: }
119:
120: public long getTime() {
121: return time;
122: }
123:
124: }
125:
126: public static int getStatisticsLevel() {
127: return STATISTICS_LEVEL;
128: }
129:
130: public static void setStatisticsLevel(int level) {
131: Diagnostic.STATISTICS_LEVEL = level;
132: }
133:
134: public static boolean needStatistics() {
135: return STATISTICS_LEVEL > 0;
136: }
137:
138: private static final int step = 4;
139:
140: private static StringBuilder indentBuffer = new StringBuilder();
141:
142: public static void indent() {
143: setupIndentBuffer(indentBuffer.length() + step);
144: }
145:
146: public static void unindent() {
147: setupIndentBuffer(indentBuffer.length() - step);
148: }
149:
150: private static void setupIndentBuffer(int len) {
151: if (len <= 0) {
152: indentBuffer.setLength(0);
153: } else {
154: indentBuffer.setLength(len);
155: for (int i = 0; i < len; i++) {
156: indentBuffer.setCharAt(i, ' ');
157: }
158: }
159: }
160:
161: public static void trace(PrintStream out, Object arg) {
162: if (TraceFlags.DEBUG | needStatistics()) {
163: out.println(indentBuffer.toString() + arg);
164: }
165: }
166:
167: public static void trace(Object arg) {
168: trace(System.err, arg);
169: }
170:
171: public static void traceStack(String message) {
172: if (TraceFlags.DEBUG) {
173: trace(message);
174: StringWriter wr = new StringWriter();
175: new Exception(message).printStackTrace(new PrintWriter(wr));
176: //StringReader sr = new StringReader(wr.getBuffer().toString());
177: BufferedReader br = new BufferedReader(new StringReader(wr
178: .getBuffer().toString()));
179: try {
180: br.readLine();
181: br.readLine();
182: for (String s = br.readLine(); s != null; s = br
183: .readLine()) {
184: trace(s);
185: }
186: } catch (IOException e) {
187: e.printStackTrace(System.err);
188: }
189: }
190: }
191:
192: public static void printlnStack(String message, int depth) {
193: StringBuilder buf = new StringBuilder(message);
194: buf.append('\n');
195: StringWriter wr = new StringWriter();
196: new Exception(message).printStackTrace(new PrintWriter(wr));
197: BufferedReader br = new BufferedReader(new StringReader(wr
198: .getBuffer().toString()));
199: try {
200: br.readLine();
201: br.readLine();
202: int i = 0;
203: for (String s = br.readLine(); s != null; s = br.readLine()) {
204: if (i == 0) {
205: buf.append(" in thread "
206: + Thread.currentThread().getName()); // NOI18N
207: buf.append('\n');
208: }
209: buf.append(s);
210: buf.append('\n');
211: if (i > depth - 1) {
212: break;
213: }
214: i++;
215: }
216: } catch (IOException e) {
217: e.printStackTrace(System.err);
218: }
219: System.out.println(buf.toString());
220: }
221:
222: public static synchronized void printToFile(String fileName,
223: String format, Object... args) {
224: try {
225: FileOutputStream fos = new FileOutputStream(fileName, true);
226: PrintStream ps = new PrintStream(fos);
227: ps.printf(format, args);
228: } catch (FileNotFoundException ex) {
229: Exceptions.printStackTrace(ex);
230: }
231: }
232:
233: public static void traceThreads(String message) {
234: if (TraceFlags.DEBUG) {
235: trace(message);
236: trace("Threads are:"); // NOI18N
237: int cnt = Thread.activeCount();
238: Thread[] threads = new Thread[cnt];
239: Thread.enumerate(threads);
240: for (int i = 0; i < cnt; i++) {
241: String s = threads[i].getName() + " "
242: + threads[i].getPriority(); // NOI18N
243: if (threads[i] == Thread.currentThread()) {
244: s += " (current)"; // NOI18N
245: }
246: trace(s);
247: }
248: trace("");
249: }
250: }
251:
252: /// handle problems
253:
254: private static FileStatistics curFileHandler = new FileStatistics(
255: null);
256:
257: public static void initFileStatistics(String file) {
258: // TODO: we can store old data in map, if we are interested in them
259: // but for now just delete old data
260: curFileHandler.dispose();
261: curFileHandler = null;
262: curFileHandler = new FileStatistics(file);
263: }
264:
265: public static void dumpFileStatistics(String dumpFile)
266: throws FileNotFoundException {
267: dumpFileStatistics(dumpFile, false);
268: }
269:
270: public static void dumpFileStatistics(String dumpFile,
271: boolean append) throws FileNotFoundException {
272: PrintStream dump = new PrintStream(new FileOutputStream(
273: dumpFile, append), true);
274: try {
275: curFileHandler.dump(dump);
276: } finally {
277: dump.close();
278: }
279: }
280:
281: public static void onUnresolvedError(CharSequence[] nameTokens,
282: CsmFile file, int offset) {
283: if (STATISTICS_LEVEL > 0) {
284: getDiagnosticUnresolved().onUnresolved(nameTokens, file,
285: offset);
286: }
287: }
288:
289: public static void dumpUnresolvedStatistics(String dumpFile,
290: boolean append) throws FileNotFoundException {
291: getDiagnosticUnresolved().dumpStatictics(dumpFile, append);
292: }
293:
294: private static DiagnosticUnresolved getDiagnosticUnresolved() {
295: if (diagnosticUnresolved == null) {
296: diagnosticUnresolved = new DiagnosticUnresolved(
297: STATISTICS_LEVEL);
298: }
299: return diagnosticUnresolved;
300: }
301:
302: public static void onLexerError(RecognitionException e) {
303: curFileHandler.handleLexerError(e);
304: }
305:
306: public static void onParserError(RecognitionException e) {
307: curFileHandler.handleParserError(e);
308: }
309:
310: /**
311: * Used when type of error is not important, but there is error to report about.
312: */
313: public static void onError(Exception e, String source) {
314: curFileHandler.handleOtherError(e, source);
315: }
316:
317: public static void onInclude(String include,
318: String absBaseFilePath, String resolvedIncludePath) {
319: curFileHandler.handleInclude(include, absBaseFilePath,
320: resolvedIncludePath, false);
321: }
322:
323: public static void onRecurseInclude(String resolvedIncludePath,
324: String absBaseFilePath) {
325: curFileHandler.handleInclude(null, absBaseFilePath,
326: resolvedIncludePath, true);
327: }
328:
329: /**
330: * Collection of file statistics
331: *
332: */
333: private static class FileStatistics {
334: private Map/*<ExceptionWrapper, ExceptionWrapper>*/lexerProblems = new HashMap();
335: private Map/*<ExceptionWrapper, ExceptionWrapper>*/parserProblems = new HashMap();
336: private Map/*<ExceptionWrapper, ExceptionWrapper>*/otherProblems = new HashMap();
337: private Map/*<String, IncludeInfo>*/includes = new HashMap();
338:
339: /** first and last errors could be interesting */
340: private ExceptionWrapper lastError = null;
341: private ExceptionWrapper firstError = null;
342: private String lastErrorMsg = null;
343:
344: private String handledFile;
345:
346: public FileStatistics(String file) {
347: this .handledFile = file;
348: }
349:
350: public void handleLexerError(RecognitionException e) {
351: handleError(lexerProblems, new LexerExceptionWrapper(e),
352: true);
353: }
354:
355: public void handleParserError(RecognitionException e) {
356: handleError(parserProblems, new ParserExceptionWrapper(e),
357: true);
358: }
359:
360: public void handleOtherError(Exception e, String source) {
361: handleError(otherProblems, new ExceptionWrapper(e, source),
362: false);
363: }
364:
365: public void handleInclude(String include,
366: String absBaseFilePath, String resolvedIncludePath,
367: boolean recursion) {
368: // if resolvedIncludePath is valid => include path resolving was OK
369: String key = (resolvedIncludePath == null) ? include
370: : resolvedIncludePath;
371: assert (key != null) : "at least 'include' or 'resolvedIncludePath' must be specified";
372: IncludeInfo info = (IncludeInfo) includes.get(key);
373: if (info == null) {
374: info = new IncludeInfo(key, resolvedIncludePath == null);
375: includes.put(key, info);
376: }
377: info.add(absBaseFilePath, recursion);
378: }
379:
380: public void dispose() {
381: this .handledFile = null;
382: this .lastError = null;
383: this .firstError = null;
384: this .lastErrorMsg = null;
385: this .lexerProblems.clear();
386: this .parserProblems.clear();
387: this .otherProblems.clear();
388: this .includes.clear();
389: }
390:
391: private boolean hasStatistics() {
392: if (Diagnostic.getStatisticsLevel() == 1) {
393: // for the first level need to inform only about real problems
394: return hasLexerProblems() || hasParserProblems()
395: || hasOtherProblems() || hasIncludeProblems();
396:
397: }
398: // for other levels need detailed statistics
399: return true;
400: }
401:
402: private boolean hasLexerProblems() {
403: return lexerProblems.size() > 0;
404: }
405:
406: private boolean hasParserProblems() {
407: return parserProblems.size() > 0;
408: }
409:
410: private boolean hasOtherProblems() {
411: return otherProblems.size() > 0;
412: }
413:
414: private boolean hasIncludeProblems() {
415: for (Iterator it = includes.values().iterator(); it
416: .hasNext();) {
417: IncludeInfo elem = (IncludeInfo) it.next();
418: if (elem.hasErrors()) {
419: return true;
420: }
421: }
422: return false;
423: }
424:
425: public void dump(PrintStream dumpFile) {
426: if (lexerProblems.isEmpty() && parserProblems.isEmpty()
427: && includes.isEmpty()) {
428: trace(dumpFile, "*** No errors found in file "
429: + handledFile); // NOI18N
430: } else {
431: trace(dumpFile, "*** Statistics of file " + handledFile); // NOI18N
432: if (lastError != null) {
433: trace(dumpFile,
434: "****** First and last lexer/parser errors ******"); // NOI18N
435: indent();
436: trace(dumpFile, "[FIRST ERROR MSG]: ("
437: + firstError.getSourceName() + ")"); // NOI18N
438: trace(dumpFile, firstError.e.toString());
439: trace(dumpFile, "[LAST ERROR MSG]: ("
440: + lastError.getSourceName() + ")"); // NOI18N
441: trace(dumpFile, lastErrorMsg);
442: if (Diagnostic.getStatisticsLevel() > 1) {
443: trace(dumpFile, "+++ More details +++ "); // NOI18N
444: if (lastError != firstError) {
445: trace(dumpFile, "[FIRST ERROR] "
446: + firstError); // NOI18N
447: trace(dumpFile, "[LAST ERROR] " + lastError); // NOI18N
448: } else {
449: trace(dumpFile, "[ERROR] " + lastError); // NOI18N
450: }
451: }
452: unindent();
453: }
454: if (hasOtherProblems()) {
455: trace(dumpFile,
456: "****** All unclassified errors ******"); // NOI18N
457: indent();
458: dumpExceptions(dumpFile, otherProblems);
459: unindent();
460: }
461: if (hasLexerProblems()) {
462: trace(dumpFile, "****** All Lexer errors ******"); // NOI18N
463: indent();
464: dumpExceptions(dumpFile, lexerProblems);
465: unindent();
466: }
467: if (hasParserProblems()) {
468: trace(dumpFile, "****** All Parser errors ******"); // NOI18N
469: indent();
470: dumpExceptions(dumpFile, parserProblems);
471: unindent();
472: }
473: if ((Diagnostic.getStatisticsLevel() > 1)
474: || hasIncludeProblems()) {
475: trace(dumpFile, "****** Inclusions ******"); // NOI18N
476: indent();
477: dumpIncludes(dumpFile, includes);
478: unindent();
479: }
480: trace(dumpFile, "*** End of statistics for "
481: + handledFile + '\n'); // NOI18N
482: }
483: }
484:
485: private void handleError(
486: Map/*<ExceptionWrapper, ExceptionWrapper>*/errors,
487: ExceptionWrapper error, boolean updateFirstLastError) {
488: assert (error != null);
489: assert (error.getException() != null);
490: ExceptionWrapper wrap = (ExceptionWrapper) errors
491: .get(error);
492: if (wrap == null) {
493: wrap = error;
494: errors.put(wrap, wrap);
495: }
496: wrap.add(error.getException());
497: if (updateFirstLastError) {
498: lastError = wrap;
499: lastErrorMsg = error.e.toString();
500: if (firstError == null) {
501: firstError = lastError;
502: }
503: }
504: }
505:
506: private void dumpExceptions(PrintStream dumpFile,
507: Map/*<ExceptionWrapper, ExceptionWrapper>*/errors) {
508: // sort errors
509: List values = new ArrayList(errors.keySet());
510: Collections.sort(values, ExceptionWrapper.COMPARATOR);
511: for (Iterator it = values.iterator(); it.hasNext();) {
512: ExceptionWrapper elem = (ExceptionWrapper) it.next();
513: trace(dumpFile, elem);
514: }
515: }
516:
517: private void dumpIncludes(PrintStream dumpFile, Map includes) {
518: List values = new ArrayList(includes.values());
519: // sort to have failed first
520: Collections.sort(values, IncludeInfo.COMPARATOR);
521: for (Iterator it = values.iterator(); it.hasNext();) {
522: IncludeInfo elem = (IncludeInfo) it.next();
523: if ((Diagnostic.getStatisticsLevel() == 1)
524: && !elem.hasErrors()) {
525: // includes are sorted to have failed in the head of list
526: // don't need to trace not failed inclusions
527: // for the first level of statistics
528: break;
529: }
530: trace(dumpFile, elem);
531: }
532: }
533:
534: private static class IncludeInfo {
535: /**
536: * absolute path of included file, if include string was correctly resolved
537: * otherwise the inclusion string ("myIncl.h" or <sys/types.h>)
538: */
539: private String include;
540:
541: /** success of inclusion */
542: private boolean failedInclusion;
543: /** amount of includes from all places*/
544: private int counter = 0;
545: /** set of files from which was this include */
546: private Map includedFrom = new HashMap();
547: /** set of files from which was recursion include */
548: private Set recursionFrom = new HashSet();
549:
550: /** comparator */
551: static final Comparator COMPARATOR = new Comparator() {
552: public int compare(Object o1, Object o2) {
553: if (o1 == o2) {
554: return 0;
555: }
556: IncludeInfo i1 = (IncludeInfo) o1;
557: IncludeInfo i2 = (IncludeInfo) o2;
558: // failed inclusion has priority
559: if (i1.failedInclusion != i2.failedInclusion) {
560: return i1.failedInclusion ? -1 : 1;
561: }
562: // then recurse inclusion has priority
563: if (i1.recursionFrom.size() != i2.recursionFrom
564: .size()) {
565: return (i1.recursionFrom.size() > i2.recursionFrom
566: .size()) ? -1 : 1;
567: }
568: // then counter has priority
569: if (i1.counter != i2.counter) {
570: return (i1.counter > i2.counter) ? -1 : 1;
571: }
572: // then name of include
573: return i1.include.compareTo(i2.include);
574: }
575:
576: public boolean equals(Object obj) {
577: return super .equals(obj);
578: }
579:
580: public int hashCode() {
581: return 11; // any dummy value
582: }
583: };
584:
585: IncludeInfo(String include, boolean failedInclusion) {
586: this .include = include;
587: this .failedInclusion = failedInclusion;
588: }
589:
590: void add(String absBaseFilePath, boolean recursion) {
591: counter++;
592: Integer fileCounter = includedFrom
593: .containsKey(absBaseFilePath) ? (Integer) includedFrom
594: .get(absBaseFilePath)
595: : new Integer(0);
596: includedFrom.put(absBaseFilePath, new Integer(
597: fileCounter.intValue() + 1));
598: if (recursion) {
599: recursionFrom.add(absBaseFilePath);
600: }
601: }
602:
603: public boolean equals(Object obj) {
604: if (this == obj) {
605: return true;
606: }
607: if (!(obj instanceof IncludeInfo)) {
608: return false;
609: }
610: // info is equal for the same include files
611: IncludeInfo other = (IncludeInfo) obj;
612: boolean retValue = (this .isFailedInclude() == other
613: .isFailedInclude());
614: retValue &= this .include.equals(other.include);
615: return retValue;
616: }
617:
618: public int hashCode() {
619: // hash code by code of include file
620: int retValue = include.hashCode() + 17
621: * (isFailedInclude() ? 0 : 1);
622: return retValue;
623: }
624:
625: public String toString() {
626: StringBuilder retValue = new StringBuilder();
627:
628: retValue.append("===> ").append(include); // NOI18N
629: if (this .isFailedInclude()) {
630: retValue.append(" (FAILED)"); // NOI18N
631: } else if (this .hasRecursionInclude()) {
632: retValue.append(" (HAS RECURSION)"); // NOI18N
633: }
634: retValue.append(" included "); // NOI18N
635: retValue.append(counter).append(" time(s)"); // NOI18N
636: if (Diagnostic.getStatisticsLevel() == 1) {
637: // only first include is interested for failed or recursive inclusion
638: // and no any info except above counter for good inclusions
639: if (this .isFailedInclude()
640: || this .hasRecursionInclude()) {
641: retValue.append("\n").append(
642: indentBuffer.toString()).append(
643: indentBuffer.toString()); // NOI18N
644: String from;
645: if (hasRecursionInclude()) {
646: assert (recursionFrom.size() > 0);
647: assert (recursionFrom.iterator().hasNext());
648: from = (String) recursionFrom.iterator()
649: .next();
650: retValue.append(" [RECURSION] "); // NOI18N
651: } else {
652: assert (includedFrom.size() > 0);
653: assert (includedFrom.keySet().iterator()
654: .hasNext());
655: from = (String) includedFrom.keySet()
656: .iterator().next();
657: retValue.append(" where [").append(
658: includedFrom.get(from)).append(
659: "] time(s) "); // NOI18N
660: }
661: retValue.append("from ").append(from); // NOI18N
662: }
663: } else {
664: // sort "from" files
665: List files = new ArrayList(this .includedFrom
666: .keySet());
667: Collections.sort(files);
668: for (Iterator it = files.iterator(); it.hasNext();) {
669: String from = (String) it.next();
670: retValue.append("\n").append(
671: indentBuffer.toString()); // NOI18N
672: retValue.append(indentBuffer.toString());
673: if (recursionFrom.contains(from)) {
674: retValue.append(" [RECURSION] "); // NOI18N
675: } else {
676: retValue.append(" [").append(
677: includedFrom.get(from))
678: .append("] "); // NOI18N
679: }
680: retValue.append("from ").append(from); // NOI18N
681: }
682: }
683: return retValue.toString();
684: }
685:
686: public boolean isFailedInclude() {
687: return failedInclusion;
688: }
689:
690: public boolean hasRecursionInclude() {
691: return !recursionFrom.isEmpty();
692: }
693:
694: public boolean hasErrors() {
695: return isFailedInclude() || hasRecursionInclude();
696: }
697: }
698:
699: private static class ExceptionWrapper {
700:
701: private static final int CKHECKED_STACK_DEPTH = 15;
702: // the first recognition exception of the same types
703: private Exception e;
704: // collection of error messages
705: private Set/*<String>*/errorMessages = new HashSet();
706: private int counter = 0;
707: private String source;
708:
709: /** comparator */
710: static final Comparator COMPARATOR = new Comparator() {
711:
712: public int compare(Object o1, Object o2) {
713: if (o1 == o2) {
714: return 0;
715: }
716: ExceptionWrapper w1 = (ExceptionWrapper) o1;
717: ExceptionWrapper w2 = (ExceptionWrapper) o2;
718: // then order by number of errors
719: if (w1.counter > w2.counter) {
720: return -1;
721: } else if (w1.counter < w2.counter) {
722: return 1;
723: }
724: String msg1 = w1.e.toString();
725: String msg2 = w2.e.toString();
726: return msg1.compareTo(msg2);
727: }
728:
729: public boolean equals(Object obj) {
730: return super .equals(obj);
731: }
732:
733: public int hashCode() {
734: return 7; // any dummy value
735: }
736: };
737:
738: ExceptionWrapper(Exception e, String source) {
739: this .e = e;
740: this .source = source;
741: }
742:
743: public Exception getException() {
744: return e;
745: }
746:
747: public boolean equals(Object obj) {
748: if (this == obj) {
749: return true;
750: }
751: if (!(obj instanceof ExceptionWrapper)) {
752: return false;
753: }
754: ExceptionWrapper check = (ExceptionWrapper) obj;
755: // check that the same exceptions classes
756: if (!check.e.getClass().equals(e.getClass())) {
757: return false;
758: }
759: // check stack traces with CKHECKED_STACK_DEPTH depth elements, not more
760: StackTraceElement[] stack = e.getStackTrace();
761: StackTraceElement[] checkStack = check.e
762: .getStackTrace();
763: if (stack != null) {
764: int length = Math.min(CKHECKED_STACK_DEPTH, Math
765: .min(stack.length, checkStack.length));
766: for (int i = 0; i < length; i++) {
767: StackTraceElement curElem = stack[i];
768: StackTraceElement checkedElem = checkStack[i];
769: // check if we already can stop checking
770: if (isStopElement(curElem)
771: || check.isStopElement(checkedElem)) {
772: // all before was the same, one of current stack elements
773: // is out of interested stack => equal wrappers
774: return true;
775: } else if (!equals(curElem, checkedElem)) {
776: return false;
777: }
778: }
779: return true;
780: }
781: return false;
782: }
783:
784: protected String getSourceName() {
785: return this .source;
786: }
787:
788: public String toString() {
789: StringBuilder retValue = new StringBuilder();
790: retValue.append("===> [").append(counter).append(
791: "] similar "); // NOI18N
792: retValue.append(getSourceName()).append(
793: " error(s) with the first :\n"); // NOI18N
794: retValue.append(indentBuffer.toString()).append(
795: e.toString());
796: if (getStatisticsLevel() > 2) {
797: String indent = indentBuffer.toString()
798: + indentBuffer.toString()
799: + indentBuffer.toString();
800: StackTraceElement[] stack = e.getStackTrace();
801: for (int i = 0; i < stack.length; i++) {
802: retValue.append("\n").append(indent); // NOI18N
803: retValue.append("at ").append(stack[i]); // NOI18N
804: }
805: }
806: if (getStatisticsLevel() > 1) {
807: // trace all error messages if more than one
808: if (errorMessages.size() > 1) {
809: String indent = indentBuffer.toString()
810: + indentBuffer.toString();
811: retValue.append("\n").append(indent); // NOI18N
812: retValue.append("+++ all error messages:"); // NOI18N
813: List values = new ArrayList(errorMessages);
814: Collections.sort(values);
815: for (Iterator it = values.iterator(); it
816: .hasNext();) {
817: String elem = (String) it.next();
818: retValue.append('\n').append(indent)
819: .append(elem);
820: }
821: }
822: }
823: return retValue.toString();
824: }
825:
826: public int hashCode() {
827: int retValue;
828: StackTraceElement[] stack = e.getStackTrace();
829: // as hash code try to use the first stack trace element
830: retValue = (stack != null && stack.length > 0) ? stack[0]
831: .hashCode()
832: : e.hashCode();
833: return retValue;
834: }
835:
836: protected boolean isStopElement(StackTraceElement curElem) {
837: return false;
838: }
839:
840: private boolean equals(StackTraceElement elem1,
841: StackTraceElement elem2) {
842: assert (elem1 != null);
843: assert (elem2 != null);
844: return elem1.equals(elem2);
845: }
846:
847: public void add(Exception e) {
848: counter++;
849: errorMessages.add(e.toString());
850: }
851: }
852:
853: private static class LexerExceptionWrapper extends
854: ExceptionWrapper {
855: LexerExceptionWrapper(RecognitionException e) {
856: super (e, "Lexer"); //NOI18N
857: }
858:
859: protected boolean isStopElement(StackTraceElement curElem) {
860: // stop if not in lexer's method
861: // we are not interested in stack before lexer call
862: if (!curElem
863: .getClassName()
864: .equals(
865: "org.netbeans.modules.cnd.apt.impl.support.generated.APTLexer")) { // NOI18N
866: return true;
867: } else if (curElem.getMethodName().equals("nextToken")) { // NOI18N
868: // also we stop on nextToken()
869: return true;
870: }
871: return false;
872: }
873: }
874:
875: private static class ParserExceptionWrapper extends
876: ExceptionWrapper {
877: ParserExceptionWrapper(RecognitionException e) {
878: super (e, "Parser");//NOI18N
879: }
880:
881: protected boolean isStopElement(StackTraceElement curElem) {
882: // stop if not in parser's method
883: // we are not interested in stack before parser call
884: if (!curElem.getClassName().equals(
885: CPPParser.class.getName())) {
886: return true;
887: } else if (curElem.getMethodName().equals(
888: "translation_unit")) { // NOI18N
889: // aslo we stop on translation_unit()
890: return true;
891: }
892: return false;
893: }
894: }
895: }
896:
897: }
|