View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.ast;
5   
6   import java.io.IOException;
7   import java.io.PrintWriter;
8   import java.io.Writer;
9   import java.util.ArrayList;
10  import java.util.List;
11  
12  public class DumpFacade extends JavaParserVisitorAdapter {
13  
14  	private PrintWriter writer;
15  	private boolean recurse;
16  
17  	public void initializeWith(Writer writer, String prefix, boolean recurse, JavaNode node) {
18  		this.writer = writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter(writer);
19  		this.recurse = recurse;
20  		this.visit(node, prefix);
21  		try {
22  			writer.flush();
23  		} catch (IOException e) {
24  			throw new RuntimeException("Problem flushing PrintWriter.", e);
25  		}
26  	}
27  
28  	@Override
29  	public Object visit(JavaNode node, Object data) {
30  		dump(node, (String) data);
31  		if (recurse) {
32  			return super.visit(node, data + " ");
33  		} else {
34  			return data;
35  		}
36  	}
37  
38  	private void dump(JavaNode node, String prefix) {
39  		//
40  		// Dump format is generally composed of the following items...
41  		//
42  
43  		// 1) Dump prefix
44  		writer.print(prefix);
45  
46  		// 2) JJT Name of the Node
47  		writer.print(node.toString());
48  
49  		//
50  		// If there are any additional details, then:
51  		// 1) A colon
52  		// 2) The Node.getImage() if it is non-empty
53  		// 3) Extras in parentheses
54  		//
55  
56  		// Standard image handling
57  		String image = node.getImage();
58  
59  		// Special image handling (e.g. Nodes with normally null images)
60  		if (node instanceof ASTBooleanLiteral) {
61  			image = String.valueOf(((ASTBooleanLiteral) node).isTrue());
62  		} else if (node instanceof ASTPrimaryPrefix) {
63  			ASTPrimaryPrefix primaryPrefix = (ASTPrimaryPrefix) node;
64  			String result = null;
65  			if (primaryPrefix.usesSuperModifier()) {
66  				result = "super";
67  			} else if (primaryPrefix.usesThisModifier()) {
68  				result = "this";
69  			}
70  			if (image != null) {
71  				result += "." + image;
72  			}
73  			image = result;
74  		} else if (node instanceof ASTPrimarySuffix) {
75  			ASTPrimarySuffix primarySuffix = (ASTPrimarySuffix) node;
76  			if (primarySuffix.isArrayDereference()) {
77  				if (image == null) {
78  					image = "[";
79  				} else {
80  					image = "[" + image;
81  				}
82  			}
83  		}
84  
85  		// Extras
86  		List<String> extras = new ArrayList<>();
87  
88  		collectModifiers(node, extras);
89  
90  		// Standard Dimensionable extras
91  		if (node instanceof Dimensionable) {
92  			Dimensionable dimensionable = (Dimensionable) node;
93  			if (dimensionable.isArray()) {
94  				StringBuilder extra = new StringBuilder("array");
95  				for (int i = 0; i < dimensionable.getArrayDepth(); i++) {
96  					extra.append('[');
97  				}
98  				extras.add(extra.toString());
99  			}
100 		}
101 
102 		// Other extras
103 		if (node instanceof ASTArguments) {
104 			extras.add(String.valueOf(((ASTArguments) node).getArgumentCount()));
105 		} else if (node instanceof ASTAssignmentOperator) {
106 			extras.add(((ASTAssignmentOperator) node).isCompound() ? "compound" : "simple");
107 		} else if (node instanceof ASTClassOrInterfaceBodyDeclaration) {
108 			if (((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) {
109 				extras.add("anonymous inner class");
110 			}
111 			if (((ASTClassOrInterfaceBodyDeclaration) node).isEnumChild()) {
112 				extras.add("enum child");
113 			}
114 		} else if (node instanceof ASTBlock) {
115 			if (((ASTBlock) node).containsComment()) {
116 				extras.add("contains comment");
117 			}
118 		} else if (node instanceof ASTClassOrInterfaceDeclaration) {
119 			extras.add(((ASTClassOrInterfaceDeclaration) node).isInterface() ? "interface" : "class");
120 			if (((ASTClassOrInterfaceDeclaration) node).isNested()) {
121 				extras.add("nested");
122 			}
123 		} else if (node instanceof ASTConditionalExpression) {
124 			if (((ASTConditionalExpression) node).isTernary()) {
125 				extras.add("ternary");
126 			}
127 		} else if (node instanceof ASTConstructorDeclaration) {
128 			extras.add(String.valueOf(((ASTConstructorDeclaration) node).getParameterCount()));
129 			if (((ASTConstructorDeclaration) node).containsComment()) {
130 				extras.add("contains comment");
131 			}
132 		} else if (node instanceof ASTExplicitConstructorInvocation) {
133 			extras.add(String.valueOf(((ASTExplicitConstructorInvocation) node).getArgumentCount()));
134 			if (((ASTExplicitConstructorInvocation) node).isThis()) {
135 				extras.add("this");
136 			}
137 			if (((ASTExplicitConstructorInvocation) node).isSuper()) {
138 				extras.add("super");
139 			}
140 		} else if (node instanceof ASTFormalParameter) {
141 			if (((ASTFormalParameter) node).isVarargs()) {
142 				extras.add("varargs");
143 			}
144 		} else if (node instanceof ASTFormalParameters) {
145 			extras.add(String.valueOf(((ASTFormalParameters) node).getParameterCount()));
146 		} else if (node instanceof ASTIfStatement) {
147 			if (((ASTIfStatement) node).hasElse()) {
148 				extras.add("has else");
149 			}
150 		} else if (node instanceof ASTImportDeclaration) {
151 			if (((ASTImportDeclaration) node).isImportOnDemand()) {
152 				extras.add("on demand");
153 			}
154 			if (((ASTImportDeclaration) node).isStatic()) {
155 				extras.add("static");
156 			}
157 		} else if (node instanceof ASTInitializer) {
158 			extras.add(((ASTInitializer) node).isStatic() ? "static" : "nonstatic");
159 		} else if (node instanceof ASTLiteral) {
160 		    ASTLiteral literal = (ASTLiteral)node;
161 			if (literal.isCharLiteral()) {
162 				extras.add("char style");
163 			}
164 			if (literal.isIntLiteral()) {
165 				extras.add("int style");
166 			}
167 			if (literal.isFloatLiteral()) {
168 				extras.add("float style");
169 			}
170 			if (literal.isStringLiteral()) {
171 				extras.add("String style");
172 			}
173 			if (literal.isDoubleLiteral()) {
174 			    extras.add("double style");
175 			}
176 			if (literal.isLongLiteral()) {
177 			    extras.add("long style");
178 			}
179 		} else if (node instanceof ASTResultType) {
180 			if (((ASTResultType) node).isVoid()) {
181 				extras.add("void");
182 			}
183 			if (((ASTResultType) node).returnsArray()) {
184 				extras.add("returns array");
185 			}
186 		} else if (node instanceof ASTSwitchLabel) {
187 			if (((ASTSwitchLabel) node).isDefault()) {
188 				extras.add("default");
189 			}
190 		} else if (node instanceof ASTTryStatement) {
191 			if (((ASTTryStatement) node).hasFinally()) {
192 				extras.add("has finally");
193 			}
194 		}
195 
196 		// Output image and extras
197 		if (image != null || !extras.isEmpty()) {
198 			writer.print(':');
199 			if (image != null) {
200 				writer.print(image);
201 			}
202 			for (String extra : extras) {
203 				writer.print('(');
204 				writer.print(extra);
205 				writer.print(')');
206 			}
207 		}
208 
209 		writer.println();
210 	}
211 
212 	private void collectModifiers(JavaNode node, List<String> extras) {
213 		// Standard AccessNode extras
214 		if (node instanceof AccessNode) {
215 			AccessNode accessNode = (AccessNode) node;
216 			if (accessNode.isPackagePrivate()) {
217 				extras.add("package private");
218 			}
219 			if (accessNode.isPrivate()) {
220 				extras.add("private");
221 			}
222 			if (accessNode.isPublic()) {
223 				extras.add("public");
224 			}
225 			if (accessNode.isProtected()) {
226 				extras.add("protected");
227 			}
228 			if (accessNode.isAbstract()) {
229 				extras.add("abstract");
230 			}
231 			if (accessNode.isStatic()) {
232 				extras.add("static");
233 			}
234 			if (accessNode.isFinal()) {
235 				extras.add("final");
236 			}
237 			if (accessNode.isSynchronized()) {
238 				extras.add("synchronized");
239 			}
240 			if (accessNode.isNative()) {
241 				extras.add("native");
242 			}
243 			if (accessNode.isStrictfp()) {
244 				extras.add("strict");
245 			}
246 			if (accessNode.isTransient()) {
247 				extras.add("transient");
248 			}
249 			if (accessNode.isDefault()) {
250 			    extras.add("default");
251 			}
252 		}
253 	}
254 }