001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd;
004:
005: import java.util.ArrayList;
006: import java.util.Comparator;
007: import java.util.List;
008:
009: import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
010: import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
011: import net.sourceforge.pmd.ast.ASTFieldDeclaration;
012: import net.sourceforge.pmd.ast.ASTFormalParameter;
013: import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
014: import net.sourceforge.pmd.ast.ASTMethodDeclaration;
015: import net.sourceforge.pmd.ast.ASTTypeDeclaration;
016: import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
017: import net.sourceforge.pmd.ast.CanSuppressWarnings;
018: import net.sourceforge.pmd.ast.SimpleNode;
019:
020: public class RuleViolation implements IRuleViolation {
021:
022: public static class RuleViolationComparator implements
023: Comparator<IRuleViolation> {
024: //
025: // Changed logic of Comparator so that rules in the same file
026: // get grouped together in the output report.
027: // DDP 7/11/2002
028: //
029: public int compare(IRuleViolation r1, IRuleViolation r2) {
030: if (!r1.getFilename().equals(r2.getFilename())) {
031: return r1.getFilename().compareTo(r2.getFilename());
032: }
033:
034: if (r1.getBeginLine() != r2.getBeginLine())
035: return r1.getBeginLine() - r2.getBeginLine();
036:
037: if (r1.getDescription() != null
038: && r2.getDescription() != null
039: && !r1.getDescription().equals(r2.getDescription())) {
040: return r1.getDescription().compareTo(
041: r2.getDescription());
042: }
043:
044: if (r1.getBeginLine() == r2.getBeginLine()) {
045: return 1;
046: }
047:
048: // line number diff maps nicely to compare()
049: return r1.getBeginLine() - r2.getBeginLine();
050: }
051: }
052:
053: private Rule rule;
054: private String description;
055: private String filename;
056:
057: private String className;
058: private String methodName;
059: private String variableName;
060: private String packageName;
061: private int beginLine;
062: private int endLine;
063:
064: private int beginColumn;
065: private int endColumn;
066: private boolean isSuppressed;
067:
068: public RuleViolation(Rule rule, RuleContext ctx, SimpleNode node) {
069: this (rule, ctx, node, rule.getMessage());
070: }
071:
072: public RuleViolation(Rule rule, RuleContext ctx, SimpleNode node,
073: String specificMsg) {
074: this .rule = rule;
075: this .filename = ctx.getSourceCodeFilename();
076: this .description = specificMsg;
077:
078: if (node != null) {
079: if (node
080: .getFirstParentOfType(ASTClassOrInterfaceDeclaration.class) == null) {
081: // This takes care of nodes which are outside a class definition - i.e., import declarations
082: className = "";
083: } else {
084: // default to symbol table lookup
085: className = node.getScope().getEnclosingClassScope()
086: .getClassName() == null ? "" : node.getScope()
087: .getEnclosingClassScope().getClassName();
088: }
089: // default to symbol table lookup
090: String qualifiedName = null;
091: List<ASTClassOrInterfaceDeclaration> parents = node
092: .getParentsOfType(ASTClassOrInterfaceDeclaration.class);
093: for (ASTClassOrInterfaceDeclaration parent : parents) {
094: if (qualifiedName == null) {
095: qualifiedName = parent.getScope()
096: .getEnclosingClassScope().getClassName();
097: } else {
098: qualifiedName = parent.getScope()
099: .getEnclosingClassScope().getClassName()
100: + "$" + qualifiedName;
101: }
102: }
103: // Sourcefile does not have an enclosing class scope...
104: if (!"net.sourceforge.pmd.symboltable.SourceFileScope"
105: .equals(node.getScope().getClass().getName())) {
106: className = node.getScope().getEnclosingClassScope()
107: .getClassName() == null ? "" : qualifiedName;
108: }
109: setVariableNameIfExists(node);
110:
111: methodName = node
112: .getFirstParentOfType(ASTMethodDeclaration.class) == null ? ""
113: : node.getScope().getEnclosingMethodScope()
114: .getName();
115:
116: packageName = node.getScope().getEnclosingSourceFileScope()
117: .getPackageName() == null ? "" : node.getScope()
118: .getEnclosingSourceFileScope().getPackageName();
119:
120: beginLine = node.getBeginLine();
121: endLine = node.getEndLine();
122: beginColumn = node.getBeginColumn();
123: endColumn = node.getEndColumn();
124:
125: // TODO combine this duplicated code
126: // TODO same for duplicated code in ASTTypeDeclaration && ASTClassOrInterfaceBodyDeclaration
127: List<SimpleNode> parentTypes = new ArrayList<SimpleNode>(
128: node.getParentsOfType(ASTTypeDeclaration.class));
129: if (node instanceof ASTTypeDeclaration) {
130: parentTypes.add(node);
131: }
132: parentTypes
133: .addAll(node
134: .getParentsOfType(ASTClassOrInterfaceBodyDeclaration.class));
135: if (node instanceof ASTClassOrInterfaceBodyDeclaration) {
136: parentTypes.add(node);
137: }
138: parentTypes.addAll(node
139: .getParentsOfType(ASTFormalParameter.class));
140: if (node instanceof ASTFormalParameter) {
141: parentTypes.add(node);
142: }
143: parentTypes
144: .addAll(node
145: .getParentsOfType(ASTLocalVariableDeclaration.class));
146: if (node instanceof ASTLocalVariableDeclaration) {
147: parentTypes.add(node);
148: }
149: for (SimpleNode parentType : parentTypes) {
150: CanSuppressWarnings t = (CanSuppressWarnings) parentType;
151: if (t.hasSuppressWarningsAnnotationFor(getRule())) {
152: isSuppressed = true;
153: }
154: }
155: } else {
156: className = "";
157: methodName = "";
158: packageName = "";
159: filename = "";
160: }
161: }
162:
163: private void setVariableNameIfExists(SimpleNode node) {
164: variableName = (node.getClass()
165: .equals(ASTFieldDeclaration.class)) ? ((ASTFieldDeclaration) node)
166: .getVariableName()
167: : "";
168: if ("".equals(variableName)) {
169: variableName = (node.getClass()
170: .equals(ASTLocalVariableDeclaration.class)) ? ((ASTLocalVariableDeclaration) node)
171: .getVariableName()
172: : "";
173: }
174: if ("".equals(variableName)) {
175: variableName = (node.getClass()
176: .equals(ASTVariableDeclaratorId.class)) ? node
177: .getImage() : "";
178: }
179: }
180:
181: public Rule getRule() {
182: return rule;
183: }
184:
185: public boolean isSuppressed() {
186: return this .isSuppressed;
187: }
188:
189: public int getBeginColumn() {
190: return beginColumn;
191: }
192:
193: public int getEndColumn() {
194: return endColumn;
195: }
196:
197: public String getDescription() {
198: return description;
199: }
200:
201: public String getFilename() {
202: return filename;
203: }
204:
205: public String getClassName() {
206: return className;
207: }
208:
209: public String getMethodName() {
210: return methodName;
211: }
212:
213: public String getPackageName() {
214: return packageName;
215: }
216:
217: public int getBeginLine() {
218: return beginLine;
219: }
220:
221: public int getEndLine() {
222: return endLine;
223: }
224:
225: public String getVariableName() {
226: return variableName;
227: }
228:
229: public String toString() {
230: return getFilename() + ":" + getRule() + ":" + getDescription()
231: + ":" + beginLine;
232: }
233:
234: }
|