View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.comments;
5   
6   import java.util.Arrays;
7   
8   import net.sourceforge.pmd.PropertySource;
9   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
10  import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
11  import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
13  import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
14  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
15  import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode;
16  import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty;
17  
18  /**
19   * @author Brian Remedios
20   */
21  public class CommentRequiredRule extends AbstractCommentRule {
22  
23  	enum CommentRequirement {
24  		Required("Required"), Ignored("Ignored"), Unwanted("Unwanted");
25  
26  		private final String label;
27  
28  		CommentRequirement(String theLabel) {
29  			label = theLabel;
30  		}
31  
32  		public static String[] labels() {
33  			String[] labels = new String[values().length];
34  			int i = 0;
35  			for (CommentRequirement requirement : values()) {
36  				labels[i++] = requirement.label;
37  			}
38  			return labels;
39  		}
40  	}
41  
42  	public static final EnumeratedProperty<CommentRequirement> HEADER_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>(
43  			"headerCommentRequirement", "Header comments. Possible values: " + Arrays.toString(CommentRequirement.values()),
44  			CommentRequirement.labels(), CommentRequirement.values(), 0, 1.0f);
45  
46  	public static final EnumeratedProperty<CommentRequirement> FIELD_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>(
47  			"fieldCommentRequirement", "Field comments. Possible values: " + Arrays.toString(CommentRequirement.values()),
48  			CommentRequirement.labels(), CommentRequirement.values(), 0, 2.0f);
49  
50  	public static final EnumeratedProperty<CommentRequirement> PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>(
51  			"publicMethodCommentRequirement", "Public method and constructor comments. Possible values: " + Arrays.toString(CommentRequirement.values()),
52  			CommentRequirement.labels(), CommentRequirement.values(), 0, 3.0f);
53  
54  	public static final EnumeratedProperty<CommentRequirement> PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>(
55  			"protectedMethodCommentRequirement", "Protected method constructor comments. Possible values: " + Arrays.toString(CommentRequirement.values()),
56  			CommentRequirement.labels(), CommentRequirement.values(), 0, 4.0f);
57  
58  	public static final EnumeratedProperty<CommentRequirement> ENUM_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>(
59  			"enumCommentRequirement", "Enum comments. Possible values: " + Arrays.toString(CommentRequirement.values()),
60  			CommentRequirement.labels(), CommentRequirement.values(), 0, 5.0f);
61  
62  	public static final EnumeratedProperty<CommentRequirement> SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<CommentRequirement>(
63  	        "serialVersionUIDCommentRequired", "serial version UID commts. Possible values: " + Arrays.toString(CommentRequirement.values()),
64  	        CommentRequirement.labels(), CommentRequirement.values(), 1, 6.0f);
65  
66  	public CommentRequiredRule() {
67  		definePropertyDescriptor(HEADER_CMT_REQUIREMENT_DESCRIPTOR);
68  		definePropertyDescriptor(FIELD_CMT_REQUIREMENT_DESCRIPTOR);
69  		definePropertyDescriptor(PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR);
70  		definePropertyDescriptor(PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR);
71  		definePropertyDescriptor(ENUM_CMT_REQUIREMENT_DESCRIPTOR);
72  		definePropertyDescriptor(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR);
73  	}
74  
75  	private CommentRequirement getCommentRequirement(String label) {
76  		if (CommentRequirement.Ignored.label.equals(label)) {
77  			return CommentRequirement.Ignored;
78  		} else if (CommentRequirement.Required.label.equals(label)) {
79  			return CommentRequirement.Required;
80  		} else if (CommentRequirement.Unwanted.label.equals(label)) {
81  			return CommentRequirement.Unwanted;
82  		} else {
83  			return null;
84  		}
85  	}
86  
87  	@Override
88  	public Object visit(ASTClassOrInterfaceDeclaration decl, Object data) {
89  		CommentRequirement headerRequirement = getCommentRequirement(getProperty(
90  				HEADER_CMT_REQUIREMENT_DESCRIPTOR).toString());
91  
92  		if (headerRequirement != CommentRequirement.Ignored) {
93  			if (headerRequirement == CommentRequirement.Required) {
94  				if (decl.comment() == null) {
95  					addViolationWithMessage(data, decl,
96  							HEADER_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
97  									+ CommentRequirement.Required,
98  							decl.getBeginLine(), decl.getEndLine());
99  				}
100 			} else {
101 				if (decl.comment() != null) {
102 					addViolationWithMessage(data, decl,
103 							HEADER_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
104 									+ CommentRequirement.Unwanted,
105 							decl.getBeginLine(), decl.getEndLine());
106 				}
107 			}
108 		}
109 
110 		return super.visit(decl, data);
111 	}
112 
113 	@Override
114 	public Object visit(ASTConstructorDeclaration decl, Object data) {
115 	    checkComment(decl, data);
116 	    return super.visit(decl, data);
117 	}
118 
119 	@Override
120 	public Object visit(ASTMethodDeclaration decl, Object data) {
121 	    checkComment(decl, data);
122 	    return super.visit(decl, data);
123 	}
124 
125 	private void checkComment(AbstractJavaAccessNode decl, Object data) {
126 		CommentRequirement pubMethodRequirement = getCommentRequirement(getProperty(
127 				PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR).toString());
128 		CommentRequirement protMethodRequirement = getCommentRequirement(getProperty(
129 				PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR).toString());
130 
131 		if (decl.isPublic()) {
132 			if (pubMethodRequirement != CommentRequirement.Ignored) {
133 				if (pubMethodRequirement == CommentRequirement.Required) {
134 					if (decl.comment() == null) {
135 						addViolationWithMessage(data, decl,
136 								PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name()
137 										+ " " + CommentRequirement.Required,
138 								decl.getBeginLine(), decl.getEndLine());
139 					}
140 				} else {
141 					if (decl.comment() != null) {
142 						addViolationWithMessage(data, decl,
143 								PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name()
144 										+ " " + CommentRequirement.Unwanted,
145 								decl.getBeginLine(), decl.getEndLine());
146 					}
147 				}
148 			}
149 		} else if (decl.isProtected()) {
150 			if (protMethodRequirement != CommentRequirement.Ignored) {
151 				if (protMethodRequirement == CommentRequirement.Required) {
152 					if (decl.comment() == null) {
153 						addViolationWithMessage(data, decl,
154 								PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name()
155 										+ " " + CommentRequirement.Required,
156 								decl.getBeginLine(), decl.getEndLine());
157 					}
158 				} else {
159 					if (decl.comment() != null) {
160 						addViolationWithMessage(data, decl,
161 								PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name()
162 										+ " " + CommentRequirement.Unwanted,
163 								decl.getBeginLine(), decl.getEndLine());
164 					}
165 				}
166 			}
167 		}
168 	}
169 
170 	@Override
171 	public Object visit(ASTFieldDeclaration decl, Object data) {
172 		CommentRequirement fieldRequirement = getCommentRequirement(getProperty(
173 				FIELD_CMT_REQUIREMENT_DESCRIPTOR).toString());
174 
175 
176 		if (fieldRequirement != CommentRequirement.Ignored) {
177 		    if (isSerialVersionUID(decl)) {
178 		        checkSerialVersionUID(decl, data, fieldRequirement);
179 		    } else
180 			if (fieldRequirement == CommentRequirement.Required) {
181 				if (decl.comment() == null) {
182 					addViolationWithMessage(data, decl,
183 							FIELD_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
184 									+ CommentRequirement.Required,
185 							decl.getBeginLine(), decl.getEndLine());
186 				}
187 			} else {
188 				if (decl.comment() != null) {
189 					addViolationWithMessage(data, decl,
190 							FIELD_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
191 									+ CommentRequirement.Unwanted,
192 							decl.getBeginLine(), decl.getEndLine());
193 				}
194 			}
195 		}
196 
197 		return super.visit(decl, data);
198 	}
199 
200     private void checkSerialVersionUID(ASTFieldDeclaration decl, Object data, CommentRequirement fieldRequirement) {
201 	    CommentRequirement serialVersionUIDReq = getCommentRequirement(getProperty(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR).toString());
202 	    if (serialVersionUIDReq != CommentRequirement.Ignored) {
203 	        if (fieldRequirement == CommentRequirement.Required) {
204 	            if (decl.comment() == null) {
205                     addViolationWithMessage(data, decl,
206                             SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
207                                     + CommentRequirement.Required,
208                             decl.getBeginLine(), decl.getEndLine());
209 	            }
210 	        } else {
211 	            if (decl.comment() != null) {
212                     addViolationWithMessage(data, decl,
213                             SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
214                                     + CommentRequirement.Unwanted,
215                             decl.getBeginLine(), decl.getEndLine());
216 	            }
217 	        }
218 	    }
219     }
220 
221 	private boolean isSerialVersionUID(ASTFieldDeclaration field) {
222 	    if ("serialVersionUID".equals(field.getVariableName())
223 	        && field.isStatic() && field.isFinal()
224 	        && field.getType() == long.class) {
225 	                return true;
226 	    }
227 	    return false;
228 	}
229 
230 	@Override
231 	public Object visit(ASTEnumDeclaration decl, Object data) {
232 		
233 		CommentRequirement enumRequirement = getCommentRequirement(getProperty(
234 				ENUM_CMT_REQUIREMENT_DESCRIPTOR).toString());
235 
236 		if (enumRequirement != CommentRequirement.Ignored) {
237 			if (enumRequirement == CommentRequirement.Required) {
238 				if (decl.comment() == null) {
239 					addViolationWithMessage(data, decl,
240 							ENUM_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
241 									+ CommentRequirement.Required,
242 							decl.getBeginLine(), decl.getEndLine());
243 				}
244 			} else {
245 				if (decl.comment() != null) {
246 					addViolationWithMessage(data, decl,
247 							ENUM_CMT_REQUIREMENT_DESCRIPTOR.name() + " "
248 									+ CommentRequirement.Unwanted,
249 							decl.getBeginLine(), decl.getEndLine());
250 				}
251 			}
252 		}
253 
254 		return super.visit(decl, data);
255 	}
256 
257 	@Override
258 	public Object visit(ASTCompilationUnit cUnit, Object data) {
259 		assignCommentsToDeclarations(cUnit);
260 
261 		return super.visit(cUnit, data);
262 	}
263 
264 	public boolean allCommentsAreIgnored() {
265 
266 		return getProperty(HEADER_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored
267 				&& getProperty(FIELD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored
268 				&& getProperty(PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored
269 				&& getProperty(PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored
270 				&& getProperty(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored;
271 	}
272 
273 	/**
274 	 * @see PropertySource#dysfunctionReason()
275 	 */
276 	@Override
277 	public String dysfunctionReason() {
278 		return allCommentsAreIgnored() ? "All comment types are ignored" : null;
279 	}
280 }