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 dwarfvsmodel;
043:
044: import java.io.*;
045: import java.util.LinkedList;
046: import org.netbeans.modules.cnd.api.model.util.CsmKindUtilities;
047: import org.netbeans.modules.cnd.api.model.util.CsmTracer;
048: import org.netbeans.modules.cnd.dwarfdump.CompilationUnit;
049: import org.netbeans.modules.cnd.dwarfdump.Dwarf;
050: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.TAG;
051: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfDeclaration;
052: import java.util.List;
053: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfEntry;
054: import java.io.IOException;
055: import java.util.ArrayList;
056: import java.util.Iterator;
057: import java.io.PrintStream;
058: import modelutils.FileCodeModelDeclaration;
059:
060: import org.netbeans.modules.cnd.api.model.*;
061:
062: /**
063: * Compares declarations from model (CsmFile) and dwarf (CompilationUnit)
064: *
065: * <pre>
066: *
067: * NB: Naming conventions.
068: *
069: * areXxxxEqual methods - return boolean (true if equal otherwise false)
070: * does NOT affect counters
071: * does NOT report anything
072: * basically is atomic (don't go deep inside)
073: *
074: * compareXxxx methods - have void return type,
075: * affects counters,
076: * report differences
077: * print trace information
078: * go recursively through objects
079: * </pre>
080: *
081: * @author ak119685, vkvashin
082: */
083: public class ModelComparator {
084:
085: private CsmFile csmFile;
086: private CompilationUnit dwarfData;
087: private Dwarf dwarf;
088: private FileInfo fileInfo;
089:
090: private boolean bidirectional = false;
091:
092: private int numMatched = 0;
093: private int numTotal = 0;
094:
095: private Tracer tracer;
096:
097: private File tempDir;
098: private boolean printToScreen = false;
099: private boolean compareBodies = true;
100:
101: private PrintStream modelStream = System.out; // for dumping model
102: private PrintStream dwarfStream = System.out; // for dumping dwarf
103: //private PrintStream optionsStream = System.out; // for logging options
104: private PrintStream traceStream = System.out; // for trace
105: private PrintStream diffStream = System.out; // for printing information concerning differencies in model
106: private PrintStream resultStream = System.out; // for results
107:
108: private PrintStream modelListStream = System.out; // for dumping model list for compar
109: private PrintStream dwarfListStream = System.out; // for dumping dwarf list for compar
110:
111: // public static final int VERBOSITY_LOW = 0;
112: // public static final int VERBOSITY_MEDIUM = 1;
113: // public static final int VERBOSITY_HIGH = 2;
114: //
115: // private int verbosity = VERBOSITY_HIGH;
116:
117: public ModelComparator(CsmFile codeModel,
118: CompilationUnit dwarfData, Dwarf dwarf, FileInfo fileInfo,
119: PrintStream resultLog, PrintStream traceLog) {
120: this .csmFile = codeModel;
121: this .dwarfData = dwarfData;
122: this .dwarf = dwarf;
123: this .fileInfo = fileInfo;
124: this .resultStream = resultLog;
125: this .traceStream = traceLog;
126: this .tracer = new Tracer(traceLog);
127: }
128:
129: public void setBidirectional(boolean bidirectional) {
130: this .bidirectional = bidirectional;
131: }
132:
133: public void setTemp(File tempDir) {
134: this .tempDir = tempDir;
135: }
136:
137: public void setPrintToScreen(boolean printToScreen) {
138: this .printToScreen = printToScreen;
139: }
140:
141: public void setCompareBodies(boolean compareBodies) {
142: this .compareBodies = compareBodies;
143: }
144:
145: private void setupStreams() throws IOException {
146: modelStream = printToScreen ? System.out : DMUtils
147: .createStream(tempDir, csmFile.getName(), "model"); // NOI18N
148: dwarfStream = printToScreen ? System.out : DMUtils
149: .createStream(tempDir, csmFile.getName(), "dwarf"); // NOI18N
150: diffStream = printToScreen ? System.out : DMUtils.createStream(
151: tempDir, csmFile.getName(), "diff"); // NOI18N
152: //traceStream and resultStream are passed directly to the constructor
153: modelListStream = printToScreen ? System.out : DMUtils
154: .createStream(tempDir, csmFile.getName(), "model-list"); // NOI18N
155: dwarfListStream = printToScreen ? System.out : DMUtils
156: .createStream(tempDir, csmFile.getName(), "dwarf-list"); // NOI18N
157: }
158:
159: private void printFileInfo() {
160: modelStream.printf("Parse options:\n"); // NOI18N
161: modelStream.printf("\tDefines\n"); // NOI18N
162: for (String define : fileInfo.getDefines()) {
163: modelStream.printf("\t\t%s\n", define); // NOI18N
164: }
165: modelStream.printf("\t<> include path\n"); // NOI18N
166: for (String incPath : fileInfo.getSysIncludes()) {
167: modelStream.printf("\t\t%s\n", incPath); // NOI18N
168: }
169: modelStream.printf("\t\"\" include path\n"); // NOI18N
170: for (String incPath : fileInfo.getQuoteIncludes()) {
171: modelStream.printf("\t\t%s\n", incPath); // NOI18N
172: }
173: }
174:
175: public ComparationResult compare() throws IOException {
176:
177: setupStreams();
178:
179: diffStream.println("Differences for "
180: + csmFile.getAbsolutePath()); //NOI18N
181: diffStream.println("Object file: " + dwarf.getFileName()); // NOI18N
182: dwarfStream.println("Object file: " + dwarf.getFileName()); // NOI18N
183: dwarfData.dump(dwarfStream);
184:
185: modelStream.printf("===== Dumping model %s\n", csmFile
186: .getAbsolutePath()); // NOI18N
187: printFileInfo();
188: (new CsmTracer(modelStream)).dumpModel(csmFile, "\n"); // NOI18N
189:
190: modelStream.println();
191:
192: clearTotal();
193: tracer.println("\n======== Processing "
194: + csmFile.getAbsolutePath() + "\n"); // NOI18N
195:
196: //compare(csmFile.getDeclarations(), dwarfData.getDeclarations());
197: DwarfList dwarfList = new DwarfList(dwarfData);
198: ModelList modelList = new ModelList(csmFile);
199: dwarfList.dump(dwarfListStream, compareBodies);
200: modelList.dump(modelListStream, compareBodies);
201: compare(modelList, dwarfList);
202:
203: ComparationResult result = new ComparationResult(csmFile,
204: getTotal(), getMatched()); // NOI18N
205: result.dump(resultStream);
206: if (diffStream != resultStream) {
207: result.dump(diffStream);
208: }
209: tracer.println("\t... done.\n"); // NOI18N
210: return result;
211: }
212:
213: private void compare(ModelList modelList, DwarfList dwarfList) {
214:
215: for (DwarfEntry entry : dwarfList.getDeclarations()) {
216: if (DMFlags.TRACE_COMPARISON)
217: tracer.println("Searching for "
218: + dwarfList.getQualifiedName(entry) + ' '
219: + entry); // NOI18N
220: if (DMFlags.TRACE_ENTRIES)
221: tracer.traceRecursive(entry);
222: tracer.indent();
223: CsmDeclaration decl = find(entry, dwarfList, modelList);
224: if (DMFlags.TRACE_COMPARISON)
225: tracer.printf("Found %s \n", toString(decl)); // NOI18N
226: if (decl != null) {
227: incBoth();
228: compareDeclarations(decl, entry);
229: } else {
230: reportMoreInDwarf(entry, dwarfList
231: .getQualifiedName(entry));
232: }
233: if (DMFlags.TRACE_COMPARISON)
234: tracer.printf("\t\t%d of %d\n\n", getMatched(),
235: getTotal()); // NOI18N
236: tracer.unindent();
237: }
238: }
239:
240: /**
241: * Finds a declaration in modelList that corresponds to the given dwarf entry (from dwarfList)
242: * @param entry dwarf entry to search corresopondent CsmDeclaration in modelList
243: * @param dwarfList list this entry is taken from (to determine are there any overloads)
244: * @param modelList list in which to search for model declaration
245: **/
246: private CsmDeclaration find(DwarfEntry entry, DwarfList dwarfList,
247: ModelList modelList) {
248:
249: String qualifiedName = dwarfList.getQualifiedName(entry);
250:
251: // {
252: // String qn2 = dwarfList.qualifiedNameFromMangled(entry);
253: // System.err.printf("QN: %s MIPS: %s \n", qualifiedName, qn2);
254: // if( qn2 != null && ! qn2.equals(qualifiedName) ) {
255: // System.err.println("@@@@@ qualified names differ !!");
256: // }
257: // }
258:
259: Iterable<CsmDeclaration> declarations = modelList
260: .getDeclarations(qualifiedName);
261: if (!declarations.iterator().hasNext()) {
262: String qname2 = dwarfList.qualifiedNameFromMangled(entry);
263: if (qname2 != null && qname2.indexOf("::") >= 0) { // NOI18N
264: qualifiedName = qname2;
265: declarations = modelList.getDeclarations(qualifiedName);
266: }
267: }
268:
269: if (ComparisonUtils.isFunction(entry)) {
270: // Gather information from dwarf site
271: int paramCount = entry.getParameters().size();
272: int dwarfOverloadsCount = 0;
273: boolean noOtherOverloadWithThisParamCount = true;
274: for (DwarfEntry e : dwarfList
275: .getDeclarations(qualifiedName)) {
276: if (ComparisonUtils.isFunction(e)) {
277: dwarfOverloadsCount++;
278: int cnt = e.getParameters().size();
279: if (cnt != paramCount) {
280: noOtherOverloadWithThisParamCount = false;
281: }
282: }
283: }
284:
285: // Well, let's then gather model data
286: List<CsmFunction> modelOverloads = new ArrayList<CsmFunction>();
287: for (CsmDeclaration decl : declarations) {
288: if (CsmKindUtilities.isFunction(decl)) {
289: CsmFunction func = (CsmFunction) decl;
290: if (func.getParameters().size() == paramCount) {
291: modelOverloads.add(func);
292: }
293: }
294: }
295:
296: if (DMFlags.TRACE_COMPARISON) {
297: tracer
298: .printf(
299: "function; paramCount=%d dwarfOverloads=%d modelOverloads=%d noOtherOverloadWithThisParamCount=%b\n", // NOI18N
300: paramCount, dwarfOverloadsCount,
301: modelOverloads.size(),
302: noOtherOverloadWithThisParamCount);
303: }
304:
305: // Ok, let's look what we've got
306: if (modelOverloads.isEmpty()) {
307: return null;
308: }
309: if (noOtherOverloadWithThisParamCount
310: && modelOverloads.size() == 1) {
311: return modelOverloads.get(0);
312: }
313: // we have several overloads with same parameters either in model or in dwarf -
314: // in any case we should compare lists in detailed manner
315: for (CsmFunction funct : modelOverloads) {
316: if (areFunctionSignaturesEqual(funct, entry)) {
317: return funct;
318: }
319: }
320: if (DMFlags.TRACE_COMPARISON)
321: tracer
322: .println("Exact match not found; searching by position"); // NOI18N
323: // well, let's at last try to find just by position
324: for (CsmFunction funct : modelOverloads) {
325: if (entry.getLine() == funct.getStartPosition()
326: .getLine()) {
327: return funct;
328: }
329: }
330: } else {
331: for (CsmDeclaration decl : declarations) {
332: if (ComparisonUtils.isClass(entry)) {
333: if (CsmKindUtilities.isClass(decl)) {
334: return decl;
335: }
336: } else if (ComparisonUtils.isEnum(entry)) {
337: if (CsmKindUtilities.isEnum(decl)) {
338: return decl;
339: }
340: } else if (ComparisonUtils.isVariable(entry)) {
341: if (CsmKindUtilities.isVariable(decl)) {
342: return decl;
343: }
344: } else if (ComparisonUtils.isTypedef(entry)) {
345: if (CsmKindUtilities.isTypedef(decl)) {
346: return decl;
347: }
348: } else {
349: tracer
350: .println("High-level entry is neither class, nor enum, variable or function: "
351: + entry); // NOI18N
352: return null;
353: }
354: }
355: }
356: return null;
357: }
358:
359: private String toString(CsmDeclaration decl) {
360: if (decl == null) {
361: return "null"; // NOI18N
362: }
363: String name = CsmKindUtilities.isFunction(decl) ? ComparisonUtils
364: .getSignature((CsmFunction) decl)
365: : decl.getName();
366: StringBuilder sb = new StringBuilder(name);
367: sb.append(' ');
368: sb.append(decl.getKind().toString());
369: sb.append(' ');
370: sb.append(CsmTracer.getOffsetString((CsmOffsetable) decl));
371: return sb.toString();
372: }
373:
374: // public String toString(CsmDeclaration declaration) {
375: // String classname = declaration.getClass().toString();
376: // classname = classname.substring(classname.lastIndexOf('.') + 1);
377: // return FileCodeModelReader.getFileCodeModelDeclaration(declaration).toString() + " <" + classname + ">"; // NOI18N
378: // }
379:
380: /** Returns true if name matches. */
381: public boolean areDeclarationNamesEqual(
382: CsmDeclaration modelDeclaration, DwarfEntry dwarfDeclaration) {
383: if (dwarfDeclaration == null) {
384: reportError("DwarfEntry for parameter is null "
385: + dwarfDeclaration); // NOI18N
386: return false;
387: } else if (ComparisonUtils.getName(dwarfDeclaration) == null) {
388: reportError("DwarfEntry name is null " + dwarfDeclaration); // NOI18N
389: return false;
390: }
391: // Remove spaces from modelName (ex. "operator <<" => "operator<<")
392: String modelName = modelDeclaration.getName().replaceAll(" ",
393: ""); // NOI18N
394: String dwarfName = ComparisonUtils.getName(dwarfDeclaration); // NOI18N
395: if ("...".equals(modelName)) { // NOI18N
396: modelName = "";
397: }
398: //TODO: Global scope?
399: if (!(modelName.equals(dwarfName) || modelName.equals("::"
400: + dwarfName))) { // NOI18N
401: return false;
402: }
403: return true;
404: }
405:
406: /**
407: * Compares dwarf and model declarations that are supposed to be the same.
408: * Increments numTotal and numMatch as appropriate.
409: */
410: private void compareDeclarations(CsmDeclaration decl,
411: DwarfEntry entry) {
412:
413: if (DMFlags.TRACE_COMPARISON)
414: tracer.printf("Comparing %s and %s\n", toString(decl),
415: entry); // NOI18N
416: tracer.indent();
417:
418: if (!areDeclarationNamesEqual(decl, entry)) {
419: reportDifferent(decl, entry, "Names differ: ", decl
420: .getName(), entry.getName()); //NOI18N
421: }
422: if (CsmKindUtilities.isFunction(decl)) {
423: compareFunctions((CsmFunction) decl, entry);
424: } else if (CsmKindUtilities.isVariable(decl)) {
425: compareVariables((CsmVariable) decl, entry);
426: } else if (decl.getKind() == CsmDeclaration.Kind.USING_DIRECTIVE) {
427: //TODO: add code
428: } else if (CsmKindUtilities.isTypedef(decl)) {
429: compareTypedefs((CsmTypedef) decl, entry);
430: } else if (CsmKindUtilities.isClass(decl)) {
431: compareClasses((CsmClass) decl, entry);
432: }
433: // namespaces are nvere added to this list; just their elements are added
434: // else if(CsmKindUtilities.isNamespaceDefinition(decl)) {
435: // compareNamespaces((CsmNamespaceDefinition) decl, entry);
436: // }
437: else {
438: StringBuilder sb = new StringBuilder(
439: "Don't know how to compare "); //NOI18N
440: sb.append(decl.getKind());
441: sb.append(" (" + decl.getClass() + ") "); //NOI18N
442: sb.append(((CsmOffsetable) decl).getContainingFile()
443: .getAbsolutePath());
444: sb.append(CsmTracer.getOffsetString((CsmOffsetable) decl));
445: reportError(sb.toString());
446: }
447:
448: tracer.unindent();
449: }
450:
451: /**
452: * Compares functions.
453: * Affects counters (for what is inside, not for functions themselves).
454: * Reports differencies
455: */
456: private void compareFunctions(CsmFunction funct, DwarfEntry entry) {
457: // Compare return types
458: compareReturnTypes(funct, entry);
459: // compare parameters
460: compareFunctionParameters(funct, entry);
461: // Compare bodies
462: CsmFunctionDefinition definition = funct.getDefinition();
463: //if (funct == definition) {
464: if (definition != null) {
465: compareBodies(definition, entry);
466: }
467: }
468:
469: /**
470: * Compares return types
471: * Affects counters (for what is inside, not for functions themselves).
472: * Reports differencies
473: */
474: private void compareReturnTypes(CsmFunction funct, DwarfEntry entry) {
475: CsmType csmRetType = funct.getReturnType();
476: if (DMFlags.TRACE_COMPARISON)
477: tracer.printf("Comparing return types %s and %s\n",
478: ComparisonUtils.getText(csmRetType), entry); // NOI18N
479: if (areTypesEqual(csmRetType, entry)) {
480: incBoth();
481: } else {
482: reportDifferentType(funct, entry, "Return types differ:",
483: csmRetType); //NOI18N
484: }
485: }
486:
487: /**
488: * Compares functions signature.
489: * Prints to diff, affects counters
490: */
491: boolean compareFunctionParameters(CsmFunction modelFunction,
492: DwarfEntry dwarfFunction) {
493:
494: Iterator<CsmParameter> modelParameters = modelFunction
495: .getParameters().iterator();
496:
497: for (DwarfEntry dwarfParam : dwarfFunction.getParameters()) {
498: if (modelParameters.hasNext()) {
499: compareVariables(modelParameters.next(), dwarfParam);
500: } else {
501: reportMoreInDwarf(dwarfParam, dwarfParam.getName());
502: }
503: }
504: return true;
505: }
506:
507: /**
508: * Compares variables (and parameters as well).
509: * Prints to diff, affects counters
510: */
511: private void compareVariables(CsmVariable var, DwarfEntry entry) {
512: if (!ComparisonUtils.isVariable(entry)) {
513: reportError("Error: an entry supposed to be variable, but it is not: "
514: + entry); // NOI18N
515: return;
516: }
517: if (!areDeclarationNamesEqual(var, entry)) {
518: reportDifferent(var, entry, (CsmKindUtilities
519: .isParamVariable(var) ? "Parameter" : "Variable")
520: + " names differ", //NOI18N
521: var.getName(), entry.getName());
522: return;
523: }
524: CsmType type = var.getType();
525: if (!areTypesEqual(type, entry)) {
526: reportDifferentType(var, entry, (CsmKindUtilities
527: .isParamVariable(var) ? "Parameter" : "Variable")
528: + " types differ", type); //NOI18N
529: return;
530: }
531: incBoth();
532: }
533:
534: private void compareTypedefs(CsmTypedef typedef, DwarfEntry entry) {
535:
536: if (entry.getKind() != TAG.DW_TAG_typedef) {
537: reportError("Error: an entry supposed to be variable, but it is not: "
538: + entry); // NOI18N
539: return;
540: }
541: if (!areDeclarationNamesEqual(typedef, entry)) {
542: reportDifferent(typedef, entry, "Typedef names differ",
543: typedef.getName(), entry.getName()); // NOI18N
544: return;
545: }
546:
547: //if (!dwarfDeclaration.getType().equals(modelDeclaration.getType().getText())) {
548: CsmType type = typedef.getType();
549: if (!areTypesEqual(typedef.getType(), entry/*.getType()*/)) {
550: reportDifferentType(typedef, entry, "Typedef types differ",
551: type); //NOI18N
552: return;
553: }
554: incBoth();
555: }
556:
557: /** Compares functions signature. Does NOT print to diff, does NOT affect counters */
558: boolean areFunctionSignaturesEqual(CsmFunction modelFunction,
559: DwarfEntry dwarfFunction) {
560:
561: List<CsmParameter> modelFunctionParams = modelFunction
562: .getParameters();
563: List<DwarfEntry> dwarfFunctionParams = dwarfFunction
564: .getParameters();
565:
566: if (modelFunctionParams.size() != dwarfFunctionParams.size()) {
567: return false;
568: }
569:
570: for (int i = 0; i < modelFunctionParams.size(); i++) {
571: DwarfEntry entry = dwarfFunctionParams.get(i);
572: if (!ComparisonUtils.isParameter(entry)) {
573: return false;
574: }
575: if (!areTypesEqual(modelFunctionParams.get(i).getType(),
576: entry/*.getType()*/)) {
577: return false;
578: }
579: }
580:
581: return true;
582: }
583:
584: /**
585: * Compares two types.
586: * Does NOT print to diff, does NOT affect counters
587: */
588: private boolean areTypesEqual(CsmType csmType, DwarfEntry entry) {
589: String dwarfType = entry.getType();
590: // String typedef = entry.getTypeDef();
591: // if( typedef != null ) {
592: // tracer.println("TYPE: " + dwarfType + " TYPEDEF: " + typedef);
593: // }
594: return areTypesEqual(csmType, dwarfType);
595: }
596:
597: /** Compares two types. Does NOT print to diff, does NOT affect counters */
598: private boolean areTypesEqual(CsmType csmType, String dwarfType) {
599:
600: int leftAngle = dwarfType.indexOf('<');
601: if (leftAngle >= 0) {
602: int rightAngle = dwarfType.lastIndexOf('>');
603: if (rightAngle > leftAngle) {
604: dwarfType = dwarfType.substring(0, leftAngle)
605: + dwarfType.substring(rightAngle + 1);
606: }
607: }
608:
609: if ("void".equals(dwarfType)) { // NOI18N
610: return csmType == null
611: || ComparisonUtils.isEmpty(csmType.getText())
612: || "void".equals(csmType.getText()); // NOI18N
613: }
614: dwarfType = dwarfType.replaceAll(" ", ""); // NOI18N
615: if (csmType == null && "null".equals(dwarfType)) { // NOI18N
616: return true;
617: }
618: if (csmType != null) {
619: String modelText = ComparisonUtils.getText(csmType);
620: modelText = modelText.replaceAll(" ", ""); // NOI18N
621: return dwarfType.equals(modelText);
622:
623: }
624: return false;
625: }
626:
627: public void compareBodies(CsmFunctionDefinition modelDefinition,
628: DwarfEntry dwarfDefinition) {
629: if (compareBodies) {
630: tracer.indent();
631: compareDeclarationTrees(ModelTree
632: .createModelNode(modelDefinition), DwarfTree
633: .createDwarfNode(dwarfDefinition));
634: tracer.unindent();
635: }
636: }
637:
638: public int getWeight(DwarfEntry entry) {
639: if (ComparisonUtils.isFunction(entry)) {
640: Node<DwarfEntry> node = DwarfTree.createDwarfNode(entry);
641: if (node != null) {
642: int sum = 1; // for return type
643: for (DwarfEntry p : entry.getParameters()) {
644: sum++; // for each parameter
645: }
646: sum += node.getDeclarationsCount();
647: return sum;
648: }
649: }
650: return 0;
651: }
652:
653: public void compareDeclarationTrees(Node<CsmDeclaration> modelNode,
654: Node<DwarfEntry> dwarfNode) {
655: // if( DMFlags.TRACE_TREES ) {
656: // tracer.indent();
657: // tracer.trace(modelNode, "Model Node =========="); // NOI18N
658: // tracer.trace(dwarfNode, "Dwarf Node =========="); // NOI18N
659: // tracer.unindent();
660: // }
661: compareDeclarationLists(modelNode.getDeclarations(), dwarfNode
662: .getDeclarations());
663: compareNodeLists(modelNode.getSubnodes(), dwarfNode
664: .getSubnodes());
665: }
666:
667: private void compareDeclarationLists(
668: Iterable<CsmDeclaration> originalModelDeclarations,
669: Iterable<DwarfEntry> dwarfEntries) {
670:
671: List<CsmDeclaration> modelDeclarations = new LinkedList<CsmDeclaration>();
672: DMUtils.addAll(modelDeclarations, originalModelDeclarations);
673:
674: tracer.indent();
675:
676: //if( DMFlags.TRACE_COMPARISON ) tracer.print("DLC: dwarf --> model"); // NOI18N
677: for (DwarfEntry dwarfEntry : dwarfEntries) {
678: boolean found = false;
679: for (Iterator it = modelDeclarations.iterator(); it
680: .hasNext();) {
681: CsmDeclaration modelDecl = (CsmDeclaration) it.next();
682: if (areDeclarationNamesEqual(modelDecl, dwarfEntry)) {
683: found = true;
684: it.remove();
685: compareDeclarations(modelDecl, dwarfEntry);
686: break;
687: }
688: }
689: if (!found) {
690: reportMoreInDwarf(dwarfEntry, null);
691: }
692: }
693:
694: if (bidirectional) {
695: //if( DMFlags.TRACE_COMPARISON ) tracer.print("DLC: model --> dwarf"); // NOI18N
696: for (CsmDeclaration modelDecl : modelDeclarations) {
697: boolean found = false;
698: for (DwarfEntry dwarfEntry : dwarfEntries) {
699: if (areDeclarationNamesEqual(modelDecl, dwarfEntry)) {
700: found = true;
701: break;
702: }
703: }
704: if (!found) {
705: reportMoreInModel(modelDecl);
706: }
707: }
708: }
709:
710: tracer.unindent();
711: }
712:
713: public void compareNodeLists(
714: Iterable<Node<CsmDeclaration>> modelNodes,
715: Iterable<Node<DwarfEntry>> dwarfNodes) {
716: tracer.indent();
717: Iterator<Node<CsmDeclaration>> modelIter = modelNodes
718: .iterator();
719: Iterator<Node<DwarfEntry>> dwarfIter = dwarfNodes.iterator();
720: while (modelIter.hasNext() && dwarfIter.hasNext()) {
721: compareDeclarationTrees(modelIter.next(), dwarfIter.next());
722: }
723: if (bidirectional) {
724: while (modelIter.hasNext()) {
725: reportMoreInModel(modelIter);
726: }
727: }
728: while (dwarfIter.hasNext()) {
729: reportMoreInDwarf(dwarfIter);
730: }
731: tracer.unindent();
732: }
733:
734: private void reportMoreInModel(Iterator<Node<CsmDeclaration>> nodes) {
735: while (nodes.hasNext()) {
736: Node<CsmDeclaration> node = nodes.next();
737: for (CsmDeclaration decl : node.getDeclarations()) {
738: reportMoreInModel(decl);
739: }
740: reportMoreInModel(node.getSubnodes().iterator());
741: }
742: }
743:
744: private void reportMoreInDwarf(Iterator<Node<DwarfEntry>> nodes) {
745: while (nodes.hasNext()) {
746: Node<DwarfEntry> node = nodes.next();
747: for (DwarfEntry entry : node.getDeclarations()) {
748: reportMoreInDwarf(entry, null);
749: }
750: reportMoreInDwarf(node.getSubnodes().iterator());
751: }
752: }
753:
754: private void reportMoreInDwarf(DwarfEntry entry, String fqn) {
755: int weight = 1 + getWeight(entry);
756: addTotal(weight);
757: diffPrint("In DWARF only: "
758: + (fqn == null ? entry.getName() : fqn) + ' '
759: + entry.toString() + " +" + weight); // NOI18N
760: }
761:
762: private void reportMoreInModel(CsmDeclaration decl) {
763: incTotal();
764: diffPrint("In model only: " + toString(decl)); // NOI18N
765: }
766:
767: private void reportDifferentType(CsmDeclaration modelDecl,
768: DwarfEntry entry, String message, CsmType type) {
769: String modelTypeText = (type == null) ? "null"
770: : ComparisonUtils.getText(type); // NOI18N
771: reportDifferent(modelDecl, entry, message, modelTypeText, entry
772: .getType());
773: }
774:
775: private void reportDifferent(CsmDeclaration modelDecl,
776: DwarfEntry entry, String message, String model, String dwarf) {
777: incTotal();
778: DwarfDeclaration dwarfDecl = entry.getDeclaration();
779: // diffPrint("Declarations differ:"); // NOI18N
780: // tracer.indent();
781: // if( message != null ) {
782: // diffPrint(" " + message);
783: // }
784: // diffPrint(" Model: " + toString(modelDecl)); // NOI18N
785: // diffPrint(" Dwarf: " + dwarfDecl.toString()); // NOI18N
786: // tracer.unindent();
787: // diffPrintF("DIFFER| %s | \"%s\" |VS| \"%s\" | MODEL | %s | DWARF | %s\n", message, model, dwarf, toString(modelDecl), dwarfDecl);
788: diffPrintF(
789: "DIFFER| %s | %s |VS| %s | MODEL | %s | DWARF | %s\n",
790: message, model, dwarf, toString(modelDecl), dwarfDecl); // NOI18N
791: }
792:
793: private void diffPrint(String message) {
794: diffStream.println(message);
795: if (!printToScreen) {
796: tracer.println(message);
797: }
798: }
799:
800: private void diffPrintF(String format, Object... args) {
801: diffStream.printf(format, args);
802: if (!printToScreen) {
803: tracer.printf(format, args);
804: }
805: }
806:
807: /**
808: * Reports error (not a difference, but rather program or data logic error)
809: * Does NOT affect counters
810: */
811: private void reportError(String message) {
812: Exception e = new Exception(message);
813: e.printStackTrace(System.err);
814: e.printStackTrace(traceStream);
815: }
816:
817: private void clearTotal() {
818: numTotal = 0;
819: }
820:
821: private void clearMatched() {
822: numMatched = 0;
823: }
824:
825: private void incTotal() {
826: numTotal++;
827: if (DMFlags.TRACE_COUNTER) {
828: tracer.println("incTotal() " + numTotal); // NOI18N
829: printStackTrace(3);
830: }
831: }
832:
833: private void addTotal(int addition) {
834: numTotal += addition;
835: if (DMFlags.TRACE_COUNTER) {
836: tracer.println("addTotal() " + numTotal); // NOI18N
837: printStackTrace(3);
838: }
839: }
840:
841: private void incMatched() {
842: numMatched++;
843: if (DMFlags.TRACE_COUNTER) {
844: tracer.println("incMatched() " + numMatched); // NOI18N
845: printStackTrace(3);
846: }
847: }
848:
849: private void incBoth() {
850: numTotal++;
851: numMatched++;
852: if (DMFlags.TRACE_COUNTER) {
853: tracer
854: .println("incBoth() " + numMatched + " / "
855: + numTotal); // NOI18N
856: printStackTrace(3);
857: }
858: }
859:
860: private void printStackTrace(int deep) {
861: StackTraceElement[] stack = Thread.currentThread()
862: .getStackTrace();
863: tracer.indent();
864: for (int i = 2; i < Math.min(stack.length, deep + 2); i++) {
865: tracer.println(stack[i].toString());
866: }
867: tracer.unindent();
868: }
869:
870: private int getTotal() {
871: return numTotal;
872: }
873:
874: private int getMatched() {
875: return numMatched;
876: }
877:
878: private void compareClasses(CsmClass modelDeclaration,
879: DwarfEntry dwarfDeclaration) {
880: //compare(modelDeclaration.getMembers(), dwarfDeclaration.getMembers());
881: ModelList modelList = new ModelList(modelDeclaration);
882: DwarfList dwarfList = new DwarfList(dwarfData, dwarfDeclaration);
883: compare(modelList, dwarfList);
884: }
885:
886: private static FileCodeModelDeclaration getCodeModelDeclaration(
887: DwarfEntry entry) {
888: DwarfDeclaration decl = entry.getDeclaration();
889: FileCodeModelDeclaration result = new FileCodeModelDeclaration(
890: decl.kind, decl.declarationString,
891: decl.declarationPosition);
892:
893: if (entry.hasChildren()) {
894: ArrayList<DwarfEntry> children = entry.getChildren();
895: for (Iterator<DwarfEntry> i = children.iterator(); i
896: .hasNext();) {
897: result.addChild(getCodeModelDeclaration(i.next()));
898: }
899: }
900:
901: return result;
902: }
903: }
|