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 test.dwarfclassview;
043:
044: import com.sun.org.apache.xml.internal.serialize.OutputFormat;
045: import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
046: import java.io.File;
047: import java.io.FileNotFoundException;
048: import java.io.IOException;
049: import java.io.PrintStream;
050: import java.util.ArrayList;
051: import java.util.List;
052: import javax.xml.parsers.ParserConfigurationException;
053: import modelutils.Config;
054: import org.netbeans.modules.cnd.dwarfdump.CompilationUnit;
055: import org.netbeans.modules.cnd.dwarfdump.dwarf.DwarfEntry;
056: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.SECTIONS;
057: import org.netbeans.modules.cnd.dwarfdump.dwarfconsts.TAG;
058: import org.netbeans.modules.cnd.dwarfdump.exception.WrongFileFormatException;
059: import org.netbeans.modules.cnd.dwarfdump.reader.DwarfReader;
060: import org.netbeans.modules.cnd.dwarfdump.section.DwarfDebugInfoSection;
061: import org.w3c.dom.Element;
062: import org.w3c.dom.NamedNodeMap;
063: import org.w3c.dom.Node;
064: import org.w3c.dom.NodeList;
065: import test.dwarfclassview.consts.KIND;
066: import test.dwarfclassview.consts.NodeATTR;
067: import test.dwarfclassview.kindresolver.KindResolver;
068:
069: public class ClassViewDumper {
070: DwarfReader reader = null;
071: ClassViewDocument dom;
072: ClassViewElement rootElement;
073: ArrayList<String> projectDirs = null;
074: static boolean verbose = false;
075: static boolean addXSLInstruction = false;
076: static boolean dumpDWARF = false;
077:
078: public ClassViewDumper(ArrayList<String> files,
079: ArrayList<String> projectDirs, String projectName)
080: throws FileNotFoundException, IOException,
081: ParserConfigurationException {
082: this .projectDirs = projectDirs;
083:
084: dom = new ClassViewDocument();
085:
086: if (addXSLInstruction) {
087: dom
088: .appendChild(dom
089: .createProcessingInstruction(
090: "xml-stylesheet",
091: "type=\"text/xsl\" href=\"allTree.xsl\" encoding=\"UTF-8\"")); // NOI18N
092: }
093:
094: rootElement = createNode();
095: rootElement.setAttribute(NodeATTR.DISPLNAME, projectName);
096: rootElement.setName(projectName);
097: rootElement.setKind(KIND.PROJECT);
098:
099: dom.appendChild(rootElement);
100:
101: for (String objFileName : files) {
102: try {
103: reader = new DwarfReader(objFileName);
104:
105: if (verbose) {
106: System.out.println("Processing file: "
107: + objFileName); // NOI18N
108: }
109:
110: PrintStream dwarfFile = null;
111:
112: if (dumpDWARF) {
113: dwarfFile = new PrintStream(new File(objFileName
114: + ".dwarf")); // NOI18N
115: }
116:
117: for (CompilationUnit cu : getCompilationUnits()) {
118:
119: if (verbose) {
120: System.out.println("\tCU: "
121: + cu.getSourceFileFullName()); // NOI18N
122: }
123:
124: if (dumpDWARF) {
125: cu.dump(dwarfFile); // NOI18N
126: }
127:
128: for (DwarfEntry child : cu.getEntries()) {
129: addDeclarationElement(null, child, false);
130: }
131: }
132: } catch (WrongFileFormatException e) {
133: System.out.println("Skip file " + objFileName); // NOI18N
134: }
135: }
136:
137: // Remove unused namespaces???
138:
139: removeEmptyNS(dom.getDocumentElement());
140:
141: }
142:
143: public List<CompilationUnit> getCompilationUnits() {
144: List<CompilationUnit> result = null;
145:
146: try {
147: DwarfDebugInfoSection debugInfo = (DwarfDebugInfoSection) reader
148: .getSection(SECTIONS.DEBUG_INFO);
149: if (debugInfo != null) {
150: result = debugInfo.getCompilationUnits();
151: }
152: } catch (IOException ex) {
153: ex.printStackTrace();
154: }
155:
156: return (result == null) ? new ArrayList<CompilationUnit>()
157: : result;
158: }
159:
160: private void dumpClassView(PrintStream out) {
161:
162: OutputFormat format = new OutputFormat(dom);
163: format.setIndenting(true);
164:
165: XMLSerializer serializer = new XMLSerializer(out, format);
166:
167: try {
168: serializer.serialize(dom);
169: } catch (IOException ex) {
170: ex.printStackTrace();
171: }
172: }
173:
174: private void addDeclarationElement(String pqname,
175: DwarfEntry declaration, boolean uncondAdd) {
176: // If this is artifitial entry - just skip it
177: if (declaration.isArtifitial()) {
178: return;
179: }
180:
181: boolean isNamespace = declaration.isNamespace();
182:
183: DwarfEntry definition = declaration.getDefinition();
184:
185: if (definition == null) {
186: definition = declaration;
187: }
188:
189: // Check that this entry was defined in a file that we a tracking...
190: String declFilePath = definition.getDeclarationFilePath();
191:
192: if (!uncondAdd
193: && !isNamespace
194: && (declFilePath == null || !isFileInDir(declFilePath,
195: projectDirs))) {
196: return;
197: }
198:
199: // We should skip some kinds of entries - they are not displayed in ClassView
200: TAG dwarfKind = declaration.getKind();
201:
202: switch (dwarfKind) {
203: case DW_TAG_inheritance:
204: case DW_TAG_lexical_block:
205: case DW_TAG_inlined_subroutine:
206: case DW_TAG_imported_module:
207: case DW_TAG_template_type_param:
208: case DW_TAG_SUN_virtual_inheritance:
209: case DW_TAG_friend:
210: case DW_TAG_template_value_param:
211: // TODO: just skip SUN templates-related stuff for now...
212: case DW_TAG_SUN_class_template:
213: case DW_TAG_SUN_function_template:
214: case DW_TAG_SUN_struct_template:
215: return;
216: }
217:
218: String name = declaration.getName();
219: String qname = declaration.getQualifiedName();
220: String displ_name = name;
221: String params = null;
222: KIND type = null;
223:
224: if (qname == null) {
225: if (pqname == null) {
226: qname = name;
227: } else {
228: qname = pqname + "::" + name; // NOI18N
229: }
230: }
231:
232: qname = reduceTemplates(qname);
233: displ_name = reduceTemplates(displ_name);
234:
235: if (qname.startsWith("_GLOBAL_")) { // NOI18N
236: return;
237: }
238:
239: if (dwarfKind.equals(TAG.DW_TAG_SUN_class_template)
240: || dwarfKind.equals(TAG.DW_TAG_SUN_function_template)
241: || dwarfKind.equals(TAG.DW_TAG_SUN_struct_template)) {
242: displ_name += "<>"; // NOI18N
243: qname += "<>"; // NOI18N
244: }
245:
246: ClassViewElement element = createNode();
247:
248: type = KindResolver.resolveKind(declaration);
249:
250: // If entry is a function - add parameters string to display name.
251: if (KindResolver.kindSupposeParams(type)) {
252: displ_name += declaration.getParametersString(true); // with names, if this info exists
253: params = declaration.getParametersString(false); // without names
254: if (params != null) {
255: element.setAttribute(NodeATTR.PARAMS, params);
256: }
257: }
258:
259: element.setName(name);
260: element.setKind(type);
261: element.setAttribute(NodeATTR.QNAME, qname);
262: element.setAttribute(NodeATTR.DISPLNAME, displ_name);
263: element.setAttribute(NodeATTR.FILE, declFilePath);
264: element.setAttribute(NodeATTR.LINE, "" + declaration.getLine()); // NOI18N
265:
266: if (verbose) {
267: element.setAttribute(NodeATTR.DWARFINFO, " - "
268: + type.value() + " " + qname + " ("
269: + reader.getFileName() + " (0x"
270: + Long.toHexString(declaration.getRefference())
271: + ")) " + declFilePath + ":"
272: + declaration.getLine()); // NOI18N
273: }
274:
275: if (declaration.hasChildren()
276: && !KindResolver.kindSupposeParams(type)) {
277: for (DwarfEntry child : declaration.getChildren()) {
278: addDeclarationElement(qname, child, !isNamespace);
279: }
280: }
281:
282: ClassViewElement parent = getParentFor(qname, declaration);
283: appendChild(parent, element);
284: }
285:
286: private void appendChild(ClassViewElement parent,
287: ClassViewElement newChild) {
288: NodeList children = parent.getChildNodes();
289:
290: for (int i = 0; i < children.getLength(); i++) {
291: ClassViewElement child = (ClassViewElement) children
292: .item(i);
293: if (child.equals(newChild)) {
294: if (KindResolver.kindSupposeParams(KIND.get(newChild
295: .getAttribute(NodeATTR.TYPE)))) {
296: if (newChild.getAttribute(NodeATTR.DISPLNAME)
297: .length() <= child.getAttribute(
298: NodeATTR.DISPLNAME).length()) {
299: return;
300: }
301: }
302:
303: NamedNodeMap attrs = newChild.getAttributes();
304: for (int j = 0; j < attrs.getLength(); j++) {
305: Node attr = attrs.item(j);
306: child.setAttribute(attr.getNodeName(), attr
307: .getNodeValue());
308: }
309: return;
310: }
311: }
312:
313: parent.appendChild(newChild);
314: }
315:
316: static private String reduceTemplates(String name) {
317:
318: char[] chars = name.toCharArray();
319: boolean stopparsing = false;
320: StringBuffer result = new StringBuffer();
321:
322: for (int i = chars.length - 1; i >= 0; i--) {
323: result.insert(0, chars[i]);
324:
325: if (!stopparsing && chars[i] == '>') {
326: // look for matching '<'
327: int idx = i - 1;
328: int nesting = 1;
329:
330: while (idx > 0 && nesting != 0) {
331: idx--;
332: if (chars[idx] == '<') {
333: nesting--;
334: } else if (chars[idx] == '>') {
335: nesting++;
336: }
337: }
338:
339: if (idx == 0) { // i.e. matched '<' have not been found
340: stopparsing = true;
341: } else {
342: i = idx + 1;
343: }
344: }
345:
346: }
347:
348: return result.toString();
349: }
350:
351: /**
352: * @param args the command line arguments
353: */
354:
355: public static void main(String[] args) {
356: try {
357: Config config = new Config("hvxgd:c:o:p:", args); // NOI18N
358: String dumpFile = config.getParameterFor("-o"); // NOI18N
359: PrintStream dumpStream = null;
360:
361: if (config.flagSet("-h")) { // NOI18N
362: usage();
363: System.exit(0);
364: }
365:
366: if (dumpFile != null) {
367: System.err.println("Dumping ClassView XML to "
368: + dumpFile); // NOI18N
369: dumpStream = new PrintStream(dumpFile);
370: } else {
371: dumpStream = System.out;
372: }
373:
374: ArrayList<String> filesToAnalyze = null;
375: String configFileName = null;
376: ArrayList<String> projectDirs = null;
377: String projectName = config
378: .getParameterFor("-p", "Project"); // NOI18N
379:
380: if ((configFileName = config.getParameterFor("-c")) == null) { // NOI18N
381: filesToAnalyze = new ArrayList<String>();
382: filesToAnalyze.add(config.getArgument());
383:
384: projectDirs = config.getParametersFor("-d"); // NOI18N
385:
386: if (projectDirs == null) {
387: projectDirs = new ArrayList<String>();
388: projectDirs.add("."); // NOI18N
389: }
390:
391: } else {
392: ConfigFile configFile = new ConfigFile(configFileName);
393: filesToAnalyze = configFile.getFilesToAnalyze();
394: projectDirs = configFile.getProjectDirs();
395: }
396:
397: verbose = config.flagSet("-v"); // NOI18N
398: addXSLInstruction = config.flagSet("-x"); // NOI18N
399: dumpDWARF = config.flagSet("-g"); // NOI18N
400:
401: ClassViewDumper dumper = new ClassViewDumper(
402: filesToAnalyze, projectDirs, projectName);
403: dumper.dumpClassView(dumpStream);
404: } catch (FileNotFoundException ex) {
405: ex.printStackTrace();
406: } catch (IOException ex) {
407: ex.printStackTrace();
408: } catch (ParserConfigurationException ex) {
409: ex.printStackTrace();
410: }
411: }
412:
413: private static void usage() {
414: String myName = ClassViewDumper.class.getName();
415: System.out.println("TODO"); // NOI18N
416: }
417:
418: private boolean isFileInDir(String fname,
419: ArrayList<String> projectDirs) {
420: for (String dir : projectDirs) {
421: if (fname.startsWith(dir)) {
422: return true;
423: }
424: }
425:
426: return false;
427: }
428:
429: private ClassViewElement searchTree(ClassViewElement parent,
430: String qname) {
431: String pqname = parent.getAttribute(NodeATTR.QNAME);
432:
433: if (pqname.equals(qname)) {
434: return parent;
435: }
436:
437: NodeList children = parent.getChildNodes();
438: for (int i = 0; i < children.getLength(); i++) {
439: ClassViewElement twin = searchTree(
440: (ClassViewElement) children.item(i), qname);
441: if (twin != null) {
442: return twin;
443: }
444: }
445:
446: return null;
447: }
448:
449: private ClassViewElement getParentFor(String qname,
450: DwarfEntry dwarfEntry) {
451: if (qname.indexOf(' ') != -1) {
452: // Example: name is 'operator std::string()'
453: qname = qname.substring(0, qname.indexOf(' '));
454: }
455:
456: if (qname.indexOf("::") == -1) { // NOI18N
457: return rootElement;
458: }
459:
460: String pqname = qname.substring(0, qname.lastIndexOf("::")); // NOI18N
461:
462: int idx = pqname.lastIndexOf("::"); // NOI18N
463:
464: String pname = (idx == -1) ? pqname : pqname.substring(idx + 2);
465:
466: ClassViewElement parent = searchTree(rootElement, pqname);
467:
468: if (parent == null) {
469: DwarfEntry dwarfEntryParent = null;
470:
471: if (dwarfEntry != null) {
472: DwarfEntry spec = dwarfEntry.getSpecification();
473: if (spec != null) {
474: dwarfEntry = spec;
475: }
476: dwarfEntryParent = dwarfEntry.getParent();
477: }
478:
479: parent = getParentFor(pqname, dwarfEntryParent);
480: ClassViewElement element = createNode();
481: element.setAttribute(NodeATTR.QNAME, pqname);
482: element.setAttribute(NodeATTR.DISPLNAME, pname);
483: element.setKind(KindResolver.resolveKind(dwarfEntryParent));
484: parent.appendChild(element);
485: return element;
486: }
487:
488: return parent;
489: }
490:
491: private boolean removeEmptyNS(Element element) {
492: if (KIND.NAMESPACE.equals(KIND.get(element
493: .getAttribute(NodeATTR.TYPE.value())))) {
494: if (element.getChildNodes().getLength() == 0) {
495: element.getParentNode().removeChild(element);
496: return true;
497: }
498:
499: return false;
500: }
501:
502: NodeList children = element.getChildNodes();
503: for (int i = 0; i < children.getLength(); i++) {
504: if (removeEmptyNS((Element) children.item(i))) {
505: i--;
506: }
507: ;
508: }
509:
510: return false;
511: }
512:
513: private ClassViewElement createNode() {
514: return new ClassViewElement(dom);
515: }
516: }
|