/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.rule.comments; import java.util.Arrays; import net.sourceforge.pmd.PropertySource; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode; import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty; /** * @author Brian Remedios */ public class CommentRequiredRule extends AbstractCommentRule { enum CommentRequirement { Required("Required"), Ignored("Ignored"), Unwanted("Unwanted"); private final String label; CommentRequirement(String theLabel) { label = theLabel; } public static String[] labels() { String[] labels = new String[values().length]; int i = 0; for (CommentRequirement requirement : values()) { labels[i++] = requirement.label; } return labels; } } public static final EnumeratedProperty<CommentRequirement> HEADER_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>( "headerCommentRequirement", "Header comments. Possible values: " + Arrays.toString(CommentRequirement.values()), CommentRequirement.labels(), CommentRequirement.values(), 0, 1.0f); public static final EnumeratedProperty<CommentRequirement> FIELD_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>( "fieldCommentRequirement", "Field comments. Possible values: " + Arrays.toString(CommentRequirement.values()), CommentRequirement.labels(), CommentRequirement.values(), 0, 2.0f); public static final EnumeratedProperty<CommentRequirement> PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>( "publicMethodCommentRequirement", "Public method and constructor comments. Possible values: " + Arrays.toString(CommentRequirement.values()), CommentRequirement.labels(), CommentRequirement.values(), 0, 3.0f); public static final EnumeratedProperty<CommentRequirement> PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>( "protectedMethodCommentRequirement", "Protected method constructor comments. Possible values: " + Arrays.toString(CommentRequirement.values()), CommentRequirement.labels(), CommentRequirement.values(), 0, 4.0f); public static final EnumeratedProperty<CommentRequirement> ENUM_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<>( "enumCommentRequirement", "Enum comments. Possible values: " + Arrays.toString(CommentRequirement.values()), CommentRequirement.labels(), CommentRequirement.values(), 0, 5.0f); public static final EnumeratedProperty<CommentRequirement> SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR = new EnumeratedProperty<CommentRequirement>( "serialVersionUIDCommentRequired", "serial version UID commts. Possible values: " + Arrays.toString(CommentRequirement.values()), CommentRequirement.labels(), CommentRequirement.values(), 1, 6.0f); public CommentRequiredRule() { definePropertyDescriptor(HEADER_CMT_REQUIREMENT_DESCRIPTOR); definePropertyDescriptor(FIELD_CMT_REQUIREMENT_DESCRIPTOR); definePropertyDescriptor(PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR); definePropertyDescriptor(PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR); definePropertyDescriptor(ENUM_CMT_REQUIREMENT_DESCRIPTOR); definePropertyDescriptor(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR); } private CommentRequirement getCommentRequirement(String label) { if (CommentRequirement.Ignored.label.equals(label)) { return CommentRequirement.Ignored; } else if (CommentRequirement.Required.label.equals(label)) { return CommentRequirement.Required; } else if (CommentRequirement.Unwanted.label.equals(label)) { return CommentRequirement.Unwanted; } else { return null; } } @Override public Object visit(ASTClassOrInterfaceDeclaration decl, Object data) { CommentRequirement headerRequirement = getCommentRequirement( getProperty(HEADER_CMT_REQUIREMENT_DESCRIPTOR).toString()); if (headerRequirement != CommentRequirement.Ignored) { if (headerRequirement == CommentRequirement.Required) { if (decl.comment() == null) { addViolationWithMessage(data, decl, HEADER_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Required, decl.getBeginLine(), decl.getEndLine()); } } else { if (decl.comment() != null) { addViolationWithMessage(data, decl, HEADER_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Unwanted, decl.getBeginLine(), decl.getEndLine()); } } } return super.visit(decl, data); } @Override public Object visit(ASTConstructorDeclaration decl, Object data) { checkComment(decl, data); return super.visit(decl, data); } @Override public Object visit(ASTMethodDeclaration decl, Object data) { checkComment(decl, data); return super.visit(decl, data); } private void checkComment(AbstractJavaAccessNode decl, Object data) { CommentRequirement pubMethodRequirement = getCommentRequirement( getProperty(PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR).toString()); CommentRequirement protMethodRequirement = getCommentRequirement( getProperty(PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR).toString()); if (decl.isPublic()) { if (pubMethodRequirement != CommentRequirement.Ignored) { if (pubMethodRequirement == CommentRequirement.Required) { if (decl.comment() == null) { addViolationWithMessage(data, decl, PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Required, decl.getBeginLine(), decl.getEndLine()); } } else { if (decl.comment() != null) { addViolationWithMessage(data, decl, PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Unwanted, decl.getBeginLine(), decl.getEndLine()); } } } } else if (decl.isProtected()) { if (protMethodRequirement != CommentRequirement.Ignored) { if (protMethodRequirement == CommentRequirement.Required) { if (decl.comment() == null) { addViolationWithMessage(data, decl, PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Required, decl.getBeginLine(), decl.getEndLine()); } } else { if (decl.comment() != null) { addViolationWithMessage(data, decl, PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Unwanted, decl.getBeginLine(), decl.getEndLine()); } } } } } @Override public Object visit(ASTFieldDeclaration decl, Object data) { CommentRequirement fieldRequirement = getCommentRequirement( getProperty(FIELD_CMT_REQUIREMENT_DESCRIPTOR).toString()); if (fieldRequirement != CommentRequirement.Ignored) { if (isSerialVersionUID(decl)) { checkSerialVersionUID(decl, data, fieldRequirement); } else if (fieldRequirement == CommentRequirement.Required) { if (decl.comment() == null) { addViolationWithMessage(data, decl, FIELD_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Required, decl.getBeginLine(), decl.getEndLine()); } } else { if (decl.comment() != null) { addViolationWithMessage(data, decl, FIELD_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Unwanted, decl.getBeginLine(), decl.getEndLine()); } } } return super.visit(decl, data); } private void checkSerialVersionUID(ASTFieldDeclaration decl, Object data, CommentRequirement fieldRequirement) { CommentRequirement serialVersionUIDReq = getCommentRequirement( getProperty(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR).toString()); if (serialVersionUIDReq != CommentRequirement.Ignored) { if (fieldRequirement == CommentRequirement.Required) { if (decl.comment() == null) { addViolationWithMessage(data, decl, SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Required, decl.getBeginLine(), decl.getEndLine()); } } else { if (decl.comment() != null) { addViolationWithMessage(data, decl, SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Unwanted, decl.getBeginLine(), decl.getEndLine()); } } } } private boolean isSerialVersionUID(ASTFieldDeclaration field) { if ("serialVersionUID".equals(field.getVariableName()) && field.isStatic() && field.isFinal() && field.getType() == long.class) { return true; } return false; } @Override public Object visit(ASTEnumDeclaration decl, Object data) { CommentRequirement enumRequirement = getCommentRequirement( getProperty(ENUM_CMT_REQUIREMENT_DESCRIPTOR).toString()); if (enumRequirement != CommentRequirement.Ignored) { if (enumRequirement == CommentRequirement.Required) { if (decl.comment() == null) { addViolationWithMessage(data, decl, ENUM_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Required, decl.getBeginLine(), decl.getEndLine()); } } else { if (decl.comment() != null) { addViolationWithMessage(data, decl, ENUM_CMT_REQUIREMENT_DESCRIPTOR.name() + " " + CommentRequirement.Unwanted, decl.getBeginLine(), decl.getEndLine()); } } } return super.visit(decl, data); } @Override public Object visit(ASTCompilationUnit cUnit, Object data) { assignCommentsToDeclarations(cUnit); return super.visit(cUnit, data); } public boolean allCommentsAreIgnored() { return getProperty(HEADER_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored && getProperty(FIELD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored && getProperty(PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored && getProperty(PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored && getProperty(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored; } /** * @see PropertySource#dysfunctionReason() */ @Override public String dysfunctionReason() { return allCommentsAreIgnored() ? "All comment types are ignored" : null; } }