View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd;
5   
6   import java.util.ArrayList;
7   import java.util.Comparator;
8   import java.util.List;
9   
10  import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
11  import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
12  import net.sourceforge.pmd.ast.ASTFieldDeclaration;
13  import net.sourceforge.pmd.ast.ASTFormalParameter;
14  import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
15  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
16  import net.sourceforge.pmd.ast.ASTTypeDeclaration;
17  import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
18  import net.sourceforge.pmd.ast.CanSuppressWarnings;
19  import net.sourceforge.pmd.ast.SimpleNode;
20  
21  public class RuleViolation implements IRuleViolation {
22  
23      public static class RuleViolationComparator implements Comparator<IRuleViolation> {
24          //
25          // Changed logic of Comparator so that rules in the same file
26          // get grouped together in the output report.
27          // DDP 7/11/2002
28          //
29          public int compare(IRuleViolation r1, IRuleViolation r2) {
30              if (!r1.getFilename().equals(r2.getFilename())) {
31                  return r1.getFilename().compareTo(r2.getFilename());
32              }
33  
34              if (r1.getBeginLine() != r2.getBeginLine())
35                  return r1.getBeginLine() - r2.getBeginLine();
36  
37              if (r1.getDescription() != null && r2.getDescription() != null && !r1.getDescription().equals(r2.getDescription())) {
38                  return r1.getDescription().compareTo(r2.getDescription());
39              }
40  
41              if (r1.getBeginLine() == r2.getBeginLine()) {
42                  return 1;
43              }
44              
45              // line number diff maps nicely to compare()
46              return r1.getBeginLine() - r2.getBeginLine();
47          }
48      }
49  
50      private Rule rule;
51      private String description;
52      private String filename;
53  
54      private String className;
55      private String methodName;
56      private String variableName;
57      private String packageName;
58      private int beginLine;
59      private int endLine;
60  
61      private int beginColumn;
62      private int endColumn;
63      private boolean isSuppressed;
64  
65      public RuleViolation(Rule rule, RuleContext ctx, SimpleNode node) {
66          this(rule, ctx, node, rule.getMessage());
67      }
68  
69      public RuleViolation(Rule rule, RuleContext ctx, SimpleNode node, String specificMsg) {
70          this.rule = rule;
71          this.filename = ctx.getSourceCodeFilename();
72          this.description = specificMsg;
73  
74          if (node != null) {
75  	        if (node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class) == null) {
76  	            // This takes care of nodes which are outside a class definition - i.e., import declarations
77  	            className = "";
78  	        } else {
79  	            // default to symbol table lookup
80  	            className = node.getScope().getEnclosingClassScope().getClassName() == null ? "" : node.getScope().getEnclosingClassScope().getClassName();
81  	        }
82  	        // default to symbol table lookup
83  	        String qualifiedName = null;
84  	        List<ASTClassOrInterfaceDeclaration> parents = node.getParentsOfType(ASTClassOrInterfaceDeclaration.class);
85  	        for ( ASTClassOrInterfaceDeclaration parent : parents )
86  	        {
87  	        	if (qualifiedName == null) {
88  	        		qualifiedName = parent.getScope().getEnclosingClassScope().getClassName();
89  	            } else {
90  	            	qualifiedName = parent.getScope().getEnclosingClassScope().getClassName() + "$" + qualifiedName;
91  	            }
92  	        }
93  	        // Sourcefile does not have an enclosing class scope...
94  	        if ( ! "net.sourceforge.pmd.symboltable.SourceFileScope".equals(node.getScope().getClass().getName() ) ) {
95  	        	className = node.getScope().getEnclosingClassScope().getClassName() == null ? "" : qualifiedName;
96  	        }
97  	        setVariableNameIfExists(node);
98  
99  	        methodName = node.getFirstParentOfType(ASTMethodDeclaration.class) == null ? "" : node.getScope().getEnclosingMethodScope().getName();
100 
101 	        packageName = node.getScope().getEnclosingSourceFileScope().getPackageName() == null ? "" : node.getScope().getEnclosingSourceFileScope().getPackageName();
102 
103 	        beginLine = node.getBeginLine();
104 	        endLine = node.getEndLine();
105 	        beginColumn = node.getBeginColumn();
106 	        endColumn = node.getEndColumn();
107 
108 	        // TODO combine this duplicated code
109 	        // TODO same for duplicated code in ASTTypeDeclaration && ASTClassOrInterfaceBodyDeclaration
110 	        List<SimpleNode> parentTypes = new ArrayList<SimpleNode>(node.getParentsOfType(ASTTypeDeclaration.class));
111 	        if (node instanceof ASTTypeDeclaration) {
112 	            parentTypes.add(node);
113 	        }
114 	        parentTypes.addAll(node.getParentsOfType(ASTClassOrInterfaceBodyDeclaration.class));
115 	        if (node instanceof ASTClassOrInterfaceBodyDeclaration) {
116 	            parentTypes.add(node);
117 	        }
118 	        parentTypes.addAll(node.getParentsOfType(ASTFormalParameter.class));
119 	        if (node instanceof ASTFormalParameter) {
120 	            parentTypes.add(node);
121 	        }
122 	        parentTypes.addAll(node.getParentsOfType(ASTLocalVariableDeclaration.class));
123 	        if (node instanceof ASTLocalVariableDeclaration) {
124 	            parentTypes.add(node);
125 	        }
126 	        for (SimpleNode parentType : parentTypes) {
127 	            CanSuppressWarnings t = (CanSuppressWarnings) parentType;
128 	            if (t.hasSuppressWarningsAnnotationFor(getRule())) {
129 	                isSuppressed = true;
130 	            }
131 	        }
132         } else {
133         	className = "";
134         	methodName = "";
135         	packageName = "";
136         	filename = "";
137         }
138     }
139 
140     private void setVariableNameIfExists(SimpleNode node) {
141         variableName = (node.getClass().equals(ASTFieldDeclaration.class))
142                 ? ((ASTFieldDeclaration) node).getVariableName() : "";
143         if ("".equals(variableName)) {
144             variableName = (node.getClass().equals(ASTLocalVariableDeclaration.class))
145                     ? ((ASTLocalVariableDeclaration) node).getVariableName() : "";
146         }
147         if ("".equals(variableName)) {
148             variableName = (node.getClass().equals(ASTVariableDeclaratorId.class))
149                     ? node.getImage() : "";
150         }
151     }
152 
153     public Rule getRule() {
154         return rule;
155     }
156 
157     public boolean isSuppressed() {
158         return this.isSuppressed;
159     }
160 
161     public int getBeginColumn() {
162         return beginColumn;
163     }
164 
165     public int getEndColumn() {
166         return endColumn;
167     }
168 
169     public String getDescription() {
170         return description;
171     }
172 
173     public String getFilename() {
174         return filename;
175     }
176 
177     public String getClassName() {
178         return className;
179     }
180 
181     public String getMethodName() {
182         return methodName;
183     }
184 
185     public String getPackageName() {
186         return packageName;
187     }
188 
189     public int getBeginLine() {
190         return beginLine;
191     }
192 
193     public int getEndLine() {
194         return endLine;
195     }
196 
197     public String getVariableName() {
198         return variableName;
199     }
200 
201     public String toString() {
202         return getFilename() + ":" + getRule() + ":" + getDescription() + ":" + beginLine;
203     }
204 
205 }