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