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.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 }