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.naming;
    5
    6   import net.sourceforge.pmd.PropertyDescriptor;
    7   import net.sourceforge.pmd.lang.ast.Node;
    8   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
    9   import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
    10  import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
    11  import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
    12  import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
    13  import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
    14  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
    15  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
    16  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
    17  import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
    18  import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty;
    19  import net.sourceforge.pmd.util.CollectionUtil;
    20
    21  public class VariableNamingConventionsRule extends AbstractJavaRule {
    22
    23      private boolean checkMembers;
    24      private boolean checkLocals;
    25      private boolean checkParameters;
    26      private String[] staticPrefixes;
    27      private String[] staticSuffixes;
    28      private String[] memberPrefixes;
    29      private String[] memberSuffixes;
    30      private String[] localPrefixes;
    31      private String[] localSuffixes;
    32      private String[] parameterPrefixes;
    33      private String[] parameterSuffixes;
    34
    35      private static final BooleanProperty CHECK_MEMBERS_DESCRIPTOR = new BooleanProperty("checkMembers",
    36  	    "Check member variables", true, 1.0f);
    37
    38      private static final BooleanProperty CHECK_LOCALS_DESCRIPTOR = new BooleanProperty("checkLocals",
    39  	    "Check local variables", true, 2.0f);
    40
    41      private static final BooleanProperty CHECK_PARAMETERS_DESCRIPTOR = new BooleanProperty("checkParameters",
    42  	    "Check constructor and method parameter variables", true, 3.0f);
    43
    44      private static final StringMultiProperty STATIC_PREFIXES_DESCRIPTOR = new StringMultiProperty("staticPrefix",
    45  	    "Static variable prefixes", new String[] { "" }, 4.0f, ',');
    46
    47      private static final StringMultiProperty STATIC_SUFFIXES_DESCRIPTOR = new StringMultiProperty("staticSuffix",
    48  	    "Static variable suffixes", new String[] { "" }, 5.0f, ',');
    49
    50      private static final StringMultiProperty MEMBER_PREFIXES_DESCRIPTOR = new StringMultiProperty("memberPrefix",
    51  	    "Member variable prefixes", new String[] { "" }, 6.0f, ',');
    52
    53      private static final StringMultiProperty MEMBER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("memberSuffix",
    54  	    "Member variable suffixes", new String[] { "" }, 7.0f, ',');
    55
    56      private static final StringMultiProperty LOCAL_PREFIXES_DESCRIPTOR = new StringMultiProperty("localPrefix",
    57  	    "Local variable prefixes", new String[] { "" }, 8.0f, ',');
    58
    59      private static final StringMultiProperty LOCAL_SUFFIXES_DESCRIPTOR = new StringMultiProperty("localSuffix",
    60  	    "Local variable suffixes", new String[] { "" }, 9.0f, ',');
    61
    62      private static final StringMultiProperty PARAMETER_PREFIXES_DESCRIPTOR = new StringMultiProperty("parameterPrefix",
    63  	    "Method parameter variable prefixes", new String[] { "" }, 10.0f, ',');
    64
    65      private static final StringMultiProperty PARAMETER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("parameterSuffix",
    66  	    "Method parameter variable suffixes", new String[] { "" }, 11.0f, ',');
    67
    68      public VariableNamingConventionsRule() {
    69  	definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR);
    70  	definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR);
    71  	definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR);
    72  	definePropertyDescriptor(STATIC_PREFIXES_DESCRIPTOR);
    73  	definePropertyDescriptor(STATIC_SUFFIXES_DESCRIPTOR);
    74  	definePropertyDescriptor(MEMBER_PREFIXES_DESCRIPTOR);
    75  	definePropertyDescriptor(MEMBER_SUFFIXES_DESCRIPTOR);
    76  	definePropertyDescriptor(LOCAL_PREFIXES_DESCRIPTOR);
    77  	definePropertyDescriptor(LOCAL_SUFFIXES_DESCRIPTOR);
    78  	definePropertyDescriptor(PARAMETER_PREFIXES_DESCRIPTOR);
    79  	definePropertyDescriptor(PARAMETER_SUFFIXES_DESCRIPTOR);
    80      }
    81
    82      public Object visit(ASTCompilationUnit node, Object data) {
    83  	init();
    84  	return super.visit(node, data);
    85      }
    86
    87      protected void init() {
    88  	checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR);
    89  	checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR);
    90  	checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR);
    91  	staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR);
    92  	staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR);
    93  	memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR);
    94  	memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR);
    95  	localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR);
    96  	localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR);
    97  	parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR);
    98  	parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR);
    99      }
    100
    101     public Object visit(ASTFieldDeclaration node, Object data) {
    102 	if (!checkMembers) {
    103 	    return data;
    104 	}
    105 	boolean isStatic = node.isStatic();
    106 	boolean isFinal = node.isFinal();
    107 	// Anything from an interface is necessarily static and final
    108 	if (node.jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTClassOrInterfaceDeclaration
    109 		&& ((ASTClassOrInterfaceDeclaration) node.jjtGetParent().jjtGetParent().jjtGetParent()).isInterface()) {
    110 	    isStatic = true;
    111 	    isFinal = true;
    112 	}
    113 	return checkVariableDeclarators(node.isStatic() ? staticPrefixes : memberPrefixes, isStatic ? staticSuffixes
    114 		: memberSuffixes, node, isStatic, isFinal, data);
    115     }
    116
    117     public Object visit(ASTLocalVariableDeclaration node, Object data) {
    118 	if (!checkLocals) {
    119 	    return data;
    120 	}
    121 	return checkVariableDeclarators(localPrefixes, localSuffixes, node, false, node.isFinal(), data);
    122     }
    123
    124     public Object visit(ASTFormalParameters node, Object data) {
    125 	if (!checkParameters) {
    126 	    return data;
    127 	}
    128 	for (ASTFormalParameter formalParameter : node.findChildrenOfType(ASTFormalParameter.class)) {
    129 	    for (ASTVariableDeclaratorId variableDeclaratorId : formalParameter
    130 		    .findChildrenOfType(ASTVariableDeclaratorId.class)) {
    131 		checkVariableDeclaratorId(parameterPrefixes, parameterSuffixes, node, false, formalParameter.isFinal(),
    132 			variableDeclaratorId, data);
    133 	    }
    134 	}
    135 	return data;
    136     }
    137
    138     private Object checkVariableDeclarators(String[] prefixes, String[] suffixes, Node root, boolean isStatic,
    139 	    boolean isFinal, Object data) {
    140 	for (ASTVariableDeclarator variableDeclarator : root.findChildrenOfType(ASTVariableDeclarator.class)) {
    141 	    for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclarator
    142 		    .findChildrenOfType(ASTVariableDeclaratorId.class)) {
    143 		checkVariableDeclaratorId(prefixes, suffixes, root, isStatic, isFinal, variableDeclaratorId, data);
    144 	    }
    145 	}
    146 	return data;
    147     }
    148
    149     private Object checkVariableDeclaratorId(String[] prefixes, String[] suffixes, Node root, boolean isStatic,
    150 	    boolean isFinal, ASTVariableDeclaratorId variableDeclaratorId, Object data) {
    151
    152 	// Get the variable name
    153 	String varName = variableDeclaratorId.getImage();
    154
    155 	// Skip serialVersionUID
    156 	if (varName.equals("serialVersionUID")) {
    157 	    return data;
    158 	}
    159
    160 	// Static finals should be uppercase
    161 	if (isStatic && isFinal) {
    162 	    if (!varName.equals(varName.toUpperCase())) {
    163 		addViolationWithMessage(data, variableDeclaratorId,
    164 			"Variables that are final and static should be all capitals, ''{0}'' is not all capitals.",
    165 			new Object[] { varName });
    166 	    }
    167 	    return data;
    168 	} else if (!isFinal) {
    169 	    String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes);
    170
    171 	    if (normalizedVarName.indexOf('_') >= 0) {
    172 		addViolationWithMessage(
    173 			data,
    174 			variableDeclaratorId,
    175 			"Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.",
    176 			new Object[] { varName });
    177 	    }
    178 	    if (Character.isUpperCase(varName.charAt(0))) {
    179 		addViolationWithMessage(data, variableDeclaratorId,
    180 			"Variables should start with a lowercase character, ''{0}'' starts with uppercase character.",
    181 			new Object[] { varName });
    182 	    }
    183 	}
    184 	return data;
    185     }
    186
    187     private String normalizeVariableName(String varName, String[] prefixes, String[] suffixes) {
    188 	return stripSuffix(stripPrefix(varName, prefixes), suffixes);
    189     }
    190
    191     private String stripSuffix(String varName, String[] suffixes) {
    192 	if (suffixes != null) {
    193 	    for (int i = 0; i < suffixes.length; i++) {
    194 		if (varName.endsWith(suffixes[i])) {
    195 		    varName = varName.substring(0, varName.length() - suffixes[i].length());
    196 		    break;
    197 		}
    198 	    }
    199 	}
    200 	return varName;
    201     }
    202
    203     private String stripPrefix(String varName, String[] prefixes) {
    204 	if (prefixes != null) {
    205 	    for (int i = 0; i < prefixes.length; i++) {
    206 		if (varName.startsWith(prefixes[i])) {
    207 		    return varName.substring(prefixes[i].length());
    208 		}
    209 	    }
    210 	}
    211 	return varName;
    212     }
    213
    214 	public boolean hasPrefixesOrSuffixes() {
    215
    216 		for (PropertyDescriptor<?> desc : getPropertyDescriptors()) {
    217 			if (desc instanceof StringMultiProperty) {
    218 				String[] values = getProperty((StringMultiProperty)desc);
    219 				if (CollectionUtil.isNotEmpty(values)) return true;
    220 			}
    221 		}
    222 		return false;
    223 	}
    224
    225 	public String dysfunctionReason() {
    226 		return hasPrefixesOrSuffixes() ?
    227 				null :
    228 				"No prefixes or suffixes specified";
    229 	}
    230
    231 }