001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd.typeresolution;
004:
005: import java.util.ArrayList;
006: import java.util.Collections;
007: import java.util.HashMap;
008: import java.util.List;
009: import java.util.Map;
010: import java.util.logging.Level;
011: import java.util.logging.Logger;
012:
013: import net.sourceforge.pmd.ast.ASTAdditiveExpression;
014: import net.sourceforge.pmd.ast.ASTAllocationExpression;
015: import net.sourceforge.pmd.ast.ASTAndExpression;
016: import net.sourceforge.pmd.ast.ASTAnnotationTypeDeclaration;
017: import net.sourceforge.pmd.ast.ASTArrayDimsAndInits;
018: import net.sourceforge.pmd.ast.ASTBooleanLiteral;
019: import net.sourceforge.pmd.ast.ASTCastExpression;
020: import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
021: import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
022: import net.sourceforge.pmd.ast.ASTCompilationUnit;
023: import net.sourceforge.pmd.ast.ASTConditionalAndExpression;
024: import net.sourceforge.pmd.ast.ASTConditionalExpression;
025: import net.sourceforge.pmd.ast.ASTConditionalOrExpression;
026: import net.sourceforge.pmd.ast.ASTEnumDeclaration;
027: import net.sourceforge.pmd.ast.ASTEqualityExpression;
028: import net.sourceforge.pmd.ast.ASTExclusiveOrExpression;
029: import net.sourceforge.pmd.ast.ASTExpression;
030: import net.sourceforge.pmd.ast.ASTFieldDeclaration;
031: import net.sourceforge.pmd.ast.ASTImportDeclaration;
032: import net.sourceforge.pmd.ast.ASTInclusiveOrExpression;
033: import net.sourceforge.pmd.ast.ASTInstanceOfExpression;
034: import net.sourceforge.pmd.ast.ASTLiteral;
035: import net.sourceforge.pmd.ast.ASTMultiplicativeExpression;
036: import net.sourceforge.pmd.ast.ASTName;
037: import net.sourceforge.pmd.ast.ASTNullLiteral;
038: import net.sourceforge.pmd.ast.ASTPackageDeclaration;
039: import net.sourceforge.pmd.ast.ASTPostfixExpression;
040: import net.sourceforge.pmd.ast.ASTPreDecrementExpression;
041: import net.sourceforge.pmd.ast.ASTPreIncrementExpression;
042: import net.sourceforge.pmd.ast.ASTPrimaryExpression;
043: import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
044: import net.sourceforge.pmd.ast.ASTPrimarySuffix;
045: import net.sourceforge.pmd.ast.ASTPrimitiveType;
046: import net.sourceforge.pmd.ast.ASTReferenceType;
047: import net.sourceforge.pmd.ast.ASTRelationalExpression;
048: import net.sourceforge.pmd.ast.ASTShiftExpression;
049: import net.sourceforge.pmd.ast.ASTStatementExpression;
050: import net.sourceforge.pmd.ast.ASTType;
051: import net.sourceforge.pmd.ast.ASTTypeDeclaration;
052: import net.sourceforge.pmd.ast.ASTUnaryExpression;
053: import net.sourceforge.pmd.ast.ASTUnaryExpressionNotPlusMinus;
054: import net.sourceforge.pmd.ast.ASTVariableDeclarator;
055: import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
056: import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
057: import net.sourceforge.pmd.ast.Node;
058: import net.sourceforge.pmd.ast.SimpleNode;
059: import net.sourceforge.pmd.ast.TypeNode;
060:
061: //
062: // Helpful reading:
063: // http://www.janeg.ca/scjp/oper/promotions.html
064: // http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html
065: //
066:
067: public class ClassTypeResolver extends JavaParserVisitorAdapter {
068:
069: private static final Logger LOG = Logger
070: .getLogger(ClassTypeResolver.class.getName());
071:
072: private static final Map<String, Class<?>> myPrimitiveTypes;
073: private static final Map<String, String> myJavaLang;
074:
075: static {
076: // Note: Assumption here that primitives come from same parent ClassLoader regardless of what ClassLoader we are passed
077: Map<String, Class<?>> thePrimitiveTypes = new HashMap<String, Class<?>>();
078: thePrimitiveTypes.put("void", Void.TYPE);
079: thePrimitiveTypes.put("boolean", Boolean.TYPE);
080: thePrimitiveTypes.put("byte", Byte.TYPE);
081: thePrimitiveTypes.put("char", Character.TYPE);
082: thePrimitiveTypes.put("short", Short.TYPE);
083: thePrimitiveTypes.put("int", Integer.TYPE);
084: thePrimitiveTypes.put("long", Long.TYPE);
085: thePrimitiveTypes.put("float", Float.TYPE);
086: thePrimitiveTypes.put("double", Double.TYPE);
087: myPrimitiveTypes = Collections
088: .unmodifiableMap(thePrimitiveTypes);
089:
090: Map<String, String> theJavaLang = new HashMap<String, String>();
091: theJavaLang.put("Boolean", "java.lang.Boolean");
092: theJavaLang.put("Byte", "java.lang.Byte");
093: theJavaLang.put("Character", "java.lang.Character");
094: theJavaLang.put("CharSequence", "java.lang.CharSequence");
095: theJavaLang.put("Class", "java.lang.Class");
096: theJavaLang.put("ClassLoader", "java.lang.ClassLoader");
097: theJavaLang.put("Cloneable", "java.lang.Cloneable");
098: theJavaLang.put("Comparable", "java.lang.Comparable");
099: theJavaLang.put("Compiler", "java.lang.Compiler");
100: theJavaLang.put("Double", "java.lang.Double");
101: theJavaLang.put("Float", "java.lang.Float");
102: theJavaLang.put("InheritableThreadLocal",
103: "java.lang.InheritableThreadLocal");
104: theJavaLang.put("Integer", "java.lang.Integer");
105: theJavaLang.put("Long", "java.lang.Long");
106: theJavaLang.put("Math", "java.lang.Math");
107: theJavaLang.put("Number", "java.lang.Number");
108: theJavaLang.put("Object", "java.lang.Object");
109: theJavaLang.put("Package", "java.lang.Package");
110: theJavaLang.put("Process", "java.lang.Process");
111: theJavaLang.put("Runnable", "java.lang.Runnable");
112: theJavaLang.put("Runtime", "java.lang.Runtime");
113: theJavaLang.put("RuntimePermission",
114: "java.lang.RuntimePermission");
115: theJavaLang.put("SecurityManager", "java.lang.SecurityManager");
116: theJavaLang.put("Short", "java.lang.Short");
117: theJavaLang.put("StackTraceElement",
118: "java.lang.StackTraceElement");
119: theJavaLang.put("StrictMath", "java.lang.StrictMath");
120: theJavaLang.put("String", "java.lang.String");
121: theJavaLang.put("StringBuffer", "java.lang.StringBuffer");
122: theJavaLang.put("System", "java.lang.System");
123: theJavaLang.put("Thread", "java.lang.Thread");
124: theJavaLang.put("ThreadGroup", "java.lang.ThreadGroup");
125: theJavaLang.put("ThreadLocal", "java.lang.ThreadLocal");
126: theJavaLang.put("Throwable", "java.lang.Throwable");
127: theJavaLang.put("Void", "java.lang.Void");
128: myJavaLang = Collections.unmodifiableMap(theJavaLang);
129: }
130:
131: private final PMDASMClassLoader pmdClassLoader;
132: private Map<String, String> importedClasses;
133: private List<String> importedOnDemand;
134:
135: public ClassTypeResolver() {
136: this (ClassTypeResolver.class.getClassLoader());
137: }
138:
139: public ClassTypeResolver(ClassLoader classLoader) {
140: pmdClassLoader = new PMDASMClassLoader(classLoader);
141: }
142:
143: // FUTURE ASTCompilationUnit should not be a TypeNode. Clean this up accordingly.
144: public Object visit(ASTCompilationUnit node, Object data) {
145: String className = null;
146: try {
147: importedOnDemand = new ArrayList<String>();
148: className = getClassName(node);
149: if (className != null) {
150: populateClassName(node, className);
151: }
152: } catch (ClassNotFoundException e) {
153: LOG.log(Level.FINE, "Could not find class " + className);
154: } catch (NoClassDefFoundError e) {
155: LOG.log(Level.WARNING, "Could not find class " + className);
156: } finally {
157: populateImports(node);
158: }
159: return super .visit(node, data);
160: }
161:
162: public Object visit(ASTImportDeclaration node, Object data) {
163: ASTName importedType = (ASTName) node.jjtGetChild(0);
164: if (importedType.getType() != null) {
165: node.setType(importedType.getType());
166: } else {
167: populateType(node, importedType.getImage());
168: }
169:
170: if (node.getType() != null) {
171: node.setPackage(node.getType().getPackage());
172: }
173: return data;
174: }
175:
176: public Object visit(ASTTypeDeclaration node, Object data) {
177: super .visit(node, data);
178: rollupTypeUnary(node);
179: return data;
180: }
181:
182: public Object visit(ASTClassOrInterfaceType node, Object data) {
183: populateType(node, node.getImage());
184: return data;
185: }
186:
187: public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
188: populateType(node, node.getImage());
189: return super .visit(node, data);
190: }
191:
192: public Object visit(ASTEnumDeclaration node, Object data) {
193: populateType(node, node.getImage());
194: return super .visit(node, data);
195: }
196:
197: public Object visit(ASTAnnotationTypeDeclaration node, Object data) {
198: populateType(node, node.getImage());
199: return super .visit(node, data);
200: }
201:
202: public Object visit(ASTName node, Object data) {
203: /*
204: * Only doing this for nodes where getNameDeclaration is null this means
205: * it's not a named node, i.e. Static reference or Annotation Doing this
206: * for memory - TODO: Investigate if there is a valid memory concern or
207: * not
208: */
209: if (node.getNameDeclaration() == null) {
210: // Skip these scenarios as there is no type to populate in these cases:
211: // 1) Parent is a PackageDeclaration, which is not a type
212: // 2) Parent is a ImportDeclaration, this is handled elsewhere.
213: if (!(node.jjtGetParent() instanceof ASTPackageDeclaration || node
214: .jjtGetParent() instanceof ASTImportDeclaration)) {
215: String name = node.getImage();
216: if (name.indexOf('.') != -1) {
217: name = name.substring(0, name.indexOf('.'));
218: }
219: populateType(node, name);
220: }
221: } else {
222: // Carry over the type from the declaration
223: if (node.getNameDeclaration().getNode() instanceof TypeNode) {
224: node.setType(((TypeNode) node.getNameDeclaration()
225: .getNode()).getType());
226: }
227: }
228: return super .visit(node, data);
229: }
230:
231: public Object visit(ASTFieldDeclaration node, Object data) {
232: super .visit(node, data);
233: rollupTypeUnary(node);
234: return data;
235: }
236:
237: public Object visit(ASTVariableDeclarator node, Object data) {
238: super .visit(node, data);
239: rollupTypeUnary(node);
240: return data;
241: }
242:
243: public Object visit(ASTVariableDeclaratorId node, Object data) {
244: if (node == null || node.getNameDeclaration() == null) {
245: return super .visit(node, data);
246: }
247: String name = node.getNameDeclaration().getTypeImage();
248: if (name.indexOf('.') != -1) {
249: name = name.substring(0, name.indexOf('.'));
250: }
251: populateType(node, name);
252: return super .visit(node, data);
253: }
254:
255: public Object visit(ASTType node, Object data) {
256: super .visit(node, data);
257: rollupTypeUnary(node);
258: return data;
259: }
260:
261: public Object visit(ASTReferenceType node, Object data) {
262: super .visit(node, data);
263: rollupTypeUnary(node);
264: return data;
265: }
266:
267: public Object visit(ASTPrimitiveType node, Object data) {
268: populateType(node, node.getImage());
269: return super .visit(node, data);
270: }
271:
272: public Object visit(ASTExpression node, Object data) {
273: super .visit(node, data);
274: rollupTypeUnary(node);
275: return data;
276: }
277:
278: public Object visit(ASTConditionalExpression node, Object data) {
279: super .visit(node, data);
280: if (node.isTernary()) {
281: // TODO Rules for Ternary are complex
282: } else {
283: rollupTypeUnary(node);
284: }
285: return data;
286: }
287:
288: public Object visit(ASTConditionalOrExpression node, Object data) {
289: populateType(node, "boolean");
290: return super .visit(node, data);
291: }
292:
293: public Object visit(ASTConditionalAndExpression node, Object data) {
294: populateType(node, "boolean");
295: return super .visit(node, data);
296: }
297:
298: public Object visit(ASTInclusiveOrExpression node, Object data) {
299: super .visit(node, data);
300: rollupTypeBinaryNumericPromotion(node);
301: return data;
302: }
303:
304: public Object visit(ASTExclusiveOrExpression node, Object data) {
305: super .visit(node, data);
306: rollupTypeBinaryNumericPromotion(node);
307: return data;
308: }
309:
310: public Object visit(ASTAndExpression node, Object data) {
311: super .visit(node, data);
312: rollupTypeBinaryNumericPromotion(node);
313: return data;
314: }
315:
316: public Object visit(ASTEqualityExpression node, Object data) {
317: populateType(node, "boolean");
318: return super .visit(node, data);
319: }
320:
321: public Object visit(ASTInstanceOfExpression node, Object data) {
322: populateType(node, "boolean");
323: return super .visit(node, data);
324: }
325:
326: public Object visit(ASTRelationalExpression node, Object data) {
327: populateType(node, "boolean");
328: return super .visit(node, data);
329: }
330:
331: public Object visit(ASTShiftExpression node, Object data) {
332: super .visit(node, data);
333: // Unary promotion on LHS is type of a shift operation
334: rollupTypeUnaryNumericPromotion(node);
335: return data;
336: }
337:
338: public Object visit(ASTAdditiveExpression node, Object data) {
339: super .visit(node, data);
340: rollupTypeBinaryNumericPromotion(node);
341: return data;
342: }
343:
344: public Object visit(ASTMultiplicativeExpression node, Object data) {
345: super .visit(node, data);
346: rollupTypeBinaryNumericPromotion(node);
347: return data;
348: }
349:
350: public Object visit(ASTUnaryExpression node, Object data) {
351: super .visit(node, data);
352: rollupTypeUnaryNumericPromotion(node);
353: return data;
354: }
355:
356: public Object visit(ASTPreIncrementExpression node, Object data) {
357: super .visit(node, data);
358: rollupTypeUnary(node);
359: return data;
360: }
361:
362: public Object visit(ASTPreDecrementExpression node, Object data) {
363: super .visit(node, data);
364: rollupTypeUnary(node);
365: return data;
366: }
367:
368: public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) {
369: super .visit(node, data);
370: if ("!".equals(node.getImage())) {
371: populateType(node, "boolean");
372: } else {
373: rollupTypeUnary(node);
374: }
375: return data;
376: }
377:
378: public Object visit(ASTPostfixExpression node, Object data) {
379: super .visit(node, data);
380: rollupTypeUnary(node);
381: return data;
382: }
383:
384: public Object visit(ASTCastExpression node, Object data) {
385: super .visit(node, data);
386: rollupTypeUnary(node);
387: return data;
388: }
389:
390: public Object visit(ASTPrimaryExpression node, Object data) {
391: super .visit(node, data);
392: if (node.jjtGetNumChildren() == 1) {
393: rollupTypeUnary(node);
394: } else {
395: // TODO OMG, this is complicated. PrimaryExpression, PrimaryPrefix and PrimarySuffix are all related.
396: }
397: return data;
398: }
399:
400: public Object visit(ASTPrimaryPrefix node, Object data) {
401: super .visit(node, data);
402: if (node.getImage() == null) {
403: rollupTypeUnary(node);
404: } else {
405: // TODO OMG, this is complicated. PrimaryExpression, PrimaryPrefix and PrimarySuffix are all related.
406: }
407: return data;
408: }
409:
410: public Object visit(ASTPrimarySuffix node, Object data) {
411: super .visit(node, data);
412: // TODO OMG, this is complicated. PrimaryExpression, PrimaryPrefix and PrimarySuffix are all related.
413: return data;
414: }
415:
416: public Object visit(ASTNullLiteral node, Object data) {
417: // No explicit type
418: return super .visit(node, data);
419: }
420:
421: public Object visit(ASTBooleanLiteral node, Object data) {
422: populateType(node, "boolean");
423: return super .visit(node, data);
424: }
425:
426: public Object visit(ASTLiteral node, Object data) {
427: super .visit(node, data);
428: if (node.jjtGetNumChildren() != 0) {
429: rollupTypeUnary(node);
430: } else {
431: if (node.isIntLiteral()) {
432: String image = node.getImage();
433: if (image.endsWith("l") || image.endsWith("L")) {
434: populateType(node, "long");
435: } else {
436: try {
437: Integer.decode(image);
438: populateType(node, "int");
439: } catch (NumberFormatException e) {
440: // Bad literal, 'long' requires use of 'l' or 'L' suffix.
441: }
442: }
443: } else if (node.isFloatLiteral()) {
444: String image = node.getImage();
445: if (image.endsWith("f") || image.endsWith("F")) {
446: populateType(node, "float");
447: } else if (image.endsWith("d") || image.endsWith("D")) {
448: populateType(node, "double");
449: } else {
450: try {
451: Double.parseDouble(image);
452: populateType(node, "double");
453: } catch (NumberFormatException e) {
454: // Bad literal, 'float' requires use of 'f' or 'F' suffix.
455: }
456: }
457: } else if (node.isCharLiteral()) {
458: populateType(node, "char");
459: } else if (node.isStringLiteral()) {
460: populateType(node, "java.lang.String");
461: } else {
462: throw new IllegalStateException(
463: "PMD error, unknown literal type!");
464: }
465: }
466: return data;
467: }
468:
469: public Object visit(ASTAllocationExpression node, Object data) {
470: super .visit(node, data);
471:
472: if ((node.jjtGetNumChildren() >= 2 && node.jjtGetChild(1) instanceof ASTArrayDimsAndInits)
473: || (node.jjtGetNumChildren() >= 3 && node
474: .jjtGetChild(2) instanceof ASTArrayDimsAndInits)) {
475: //
476: // Classes for Array types cannot be found directly using reflection.
477: // As far as I can tell you have to create an array instance of the necessary
478: // dimensionality, and then ask for the type from the instance. OMFG that's ugly.
479: //
480:
481: // TODO Need to create utility method to allow array type creation which will use
482: // caching to avoid repeated object creation.
483: // TODO Modify Parser to tell us array dimensions count.
484: // TODO Parser seems to do some work to handle arrays in certain case already.
485: // Examine those to figure out what's going on, make sure _all_ array scenarios
486: // are ultimately covered. Appears to use a Dimensionable interface to handle
487: // only a part of the APIs (not bump), but is implemented several times, so
488: // look at refactoring to eliminate duplication. Dimensionable is also used
489: // on AccessNodes for some scenarios, need to account for that. Might be
490: // missing some TypeNode candidates we can add to the AST and have to deal
491: // with here (e.g. FormalParameter)? Plus some existing usages may be
492: // incorrect.
493: } else {
494: rollupTypeUnary(node);
495: }
496: return data;
497: }
498:
499: public Object visit(ASTStatementExpression node, Object data) {
500: super .visit(node, data);
501: rollupTypeUnary(node);
502: return data;
503: }
504:
505: // Roll up the type based on type of the first child node.
506: private void rollupTypeUnary(TypeNode typeNode) {
507: if (typeNode instanceof SimpleNode) {
508: SimpleNode simpleNode = (SimpleNode) typeNode;
509: if (simpleNode.jjtGetNumChildren() >= 1) {
510: Node child = simpleNode.jjtGetChild(0);
511: if (child instanceof TypeNode) {
512: typeNode.setType(((TypeNode) child).getType());
513: }
514: }
515: }
516: }
517:
518: // Roll up the type based on type of the first child node using Unary Numeric Promotion per JLS 5.6.1
519: private void rollupTypeUnaryNumericPromotion(TypeNode typeNode) {
520: if (typeNode instanceof SimpleNode) {
521: SimpleNode simpleNode = (SimpleNode) typeNode;
522: if (simpleNode.jjtGetNumChildren() >= 1) {
523: Node child = simpleNode.jjtGetChild(0);
524: if (child instanceof TypeNode) {
525: Class<?> type = ((TypeNode) child).getType();
526: if (type != null) {
527: if ("byte".equals(type.getName())
528: || "short".equals(type.getName())
529: || "char".equals(type.getName())) {
530: populateType(typeNode, "int");
531: } else {
532: typeNode.setType(((TypeNode) child)
533: .getType());
534: }
535: }
536: }
537: }
538: }
539: }
540:
541: // Roll up the type based on type of the first and second child nodes using Binary Numeric Promotion per JLS 5.6.2
542: private void rollupTypeBinaryNumericPromotion(TypeNode typeNode) {
543: if (typeNode instanceof SimpleNode) {
544: SimpleNode simpleNode = (SimpleNode) typeNode;
545: if (simpleNode.jjtGetNumChildren() >= 2) {
546: Node child1 = simpleNode.jjtGetChild(0);
547: Node child2 = simpleNode.jjtGetChild(1);
548: if (child1 instanceof TypeNode
549: && child2 instanceof TypeNode) {
550: Class<?> type1 = ((TypeNode) child1).getType();
551: Class<?> type2 = ((TypeNode) child2).getType();
552: if (type1 != null && type2 != null) {
553: // Yeah, String is not numeric, but easiest place to handle it, only affects ASTAdditiveExpression
554: if ("java.lang.String".equals(type1.getName())
555: || "java.lang.String".equals(type2
556: .getName())) {
557: populateType(typeNode, "java.lang.String");
558: } else if ("boolean".equals(type1.getName())
559: || "boolean".equals(type2.getName())) {
560: populateType(typeNode, "boolean");
561: } else if ("double".equals(type1.getName())
562: || "double".equals(type2.getName())) {
563: populateType(typeNode, "double");
564: } else if ("float".equals(type1.getName())
565: || "float".equals(type2.getName())) {
566: populateType(typeNode, "float");
567: } else if ("long".equals(type1.getName())
568: || "long".equals(type2.getName())) {
569: populateType(typeNode, "long");
570: } else {
571: populateType(typeNode, "int");
572: }
573: } else if (type1 != null || type2 != null) {
574: // If one side is known to be a String, then the result is a String
575: // Yeah, String is not numeric, but easiest place to handle it, only affects ASTAdditiveExpression
576: if ((type1 != null && "java.lang.String"
577: .equals(type1.getName()))
578: || (type2 != null && "java.lang.String"
579: .equals(type2.getName()))) {
580: populateType(typeNode, "java.lang.String");
581: }
582: }
583: }
584: }
585: }
586: }
587:
588: private void populateType(TypeNode node, String className) {
589:
590: String qualifiedName = className;
591: Class<?> myType = myPrimitiveTypes.get(className);
592: if (myType == null && importedClasses != null) {
593: if (importedClasses.containsKey(className)) {
594: qualifiedName = importedClasses.get(className);
595: } else if (importedClasses.containsValue(className)) {
596: qualifiedName = className;
597: }
598: if (qualifiedName != null) {
599: try {
600: /*
601: * TODO - the map right now contains just class names. if we
602: * use a map of classname/class then we don't have to hit
603: * the class loader for every type - much faster
604: */
605: myType = pmdClassLoader.loadClass(qualifiedName);
606: } catch (ClassNotFoundException e) {
607: myType = processOnDemand(qualifiedName);
608: } catch (NoClassDefFoundError e) {
609: myType = processOnDemand(qualifiedName);
610: }
611: }
612: }
613: if (myType != null) {
614: node.setType(myType);
615: }
616: }
617:
618: /**
619: * Check whether the supplied class name exists.
620: */
621: public boolean classNameExists(String fullyQualifiedClassName) {
622: try {
623: pmdClassLoader.loadClass(fullyQualifiedClassName);
624: return true; //Class found
625: } catch (ClassNotFoundException e) {
626: return false;
627: }
628: }
629:
630: private Class<?> processOnDemand(String qualifiedName) {
631: for (String entry : importedOnDemand) {
632: try {
633: return pmdClassLoader.loadClass(entry + "."
634: + qualifiedName);
635: } catch (Throwable e) {
636: }
637: }
638: return null;
639: }
640:
641: private String getClassName(ASTCompilationUnit node) {
642: ASTClassOrInterfaceDeclaration classDecl = node
643: .getFirstChildOfType(ASTClassOrInterfaceDeclaration.class);
644: if (classDecl == null) {
645: return null; // Happens if this compilation unit only contains an enum
646: }
647: if (node.declarationsAreInDefaultPackage()) {
648: return classDecl.getImage();
649: }
650: ASTPackageDeclaration pkgDecl = node.getPackageDeclaration();
651: importedOnDemand.add(pkgDecl.getPackageNameImage());
652: return pkgDecl.getPackageNameImage() + "."
653: + classDecl.getImage();
654: }
655:
656: /**
657: * If the outer class wasn't found then we'll get in here
658: *
659: * @param node
660: */
661: private void populateImports(ASTCompilationUnit node) {
662: List<ASTImportDeclaration> theImportDeclarations = node
663: .findChildrenOfType(ASTImportDeclaration.class);
664: importedClasses = new HashMap<String, String>();
665:
666: // go through the imports
667: for (ASTImportDeclaration anImportDeclaration : theImportDeclarations) {
668: String strPackage = anImportDeclaration.getPackageName();
669: if (anImportDeclaration.isImportOnDemand()) {
670: importedOnDemand.add(strPackage);
671: } else if (!anImportDeclaration.isImportOnDemand()) {
672: String strName = anImportDeclaration.getImportedName();
673: importedClasses.put(strName, strName);
674: importedClasses.put(strName.substring(strPackage
675: .length() + 1), strName);
676: }
677: }
678:
679: importedClasses.putAll(myJavaLang);
680: }
681:
682: private void populateClassName(ASTCompilationUnit node,
683: String className) throws ClassNotFoundException {
684: node.setType(pmdClassLoader.loadClass(className));
685: importedClasses = pmdClassLoader.getImportedClasses(className);
686: }
687:
688: }
|