-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
FieldNamingConventionsRule.java
129 lines (106 loc) · 5.1 KB
/
FieldNamingConventionsRule.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.codestyle;
import static net.sourceforge.pmd.lang.java.ast.JModifier.FINAL;
import static net.sourceforge.pmd.lang.java.ast.JModifier.STATIC;
import static net.sourceforge.pmd.lang.java.ast.ModifierOwner.Visibility.V_PUBLIC;
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTVariableId;
import net.sourceforge.pmd.lang.java.ast.internal.JavaAstUtils;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
/**
* Configurable naming conventions for field declarations.
*
* @author Clément Fournier
* @since 6.7.0
*/
public class FieldNamingConventionsRule extends AbstractNamingConventionRule<ASTVariableId> {
// TODO we need a more powerful scheme to match some fields, e.g. include modifiers/type
// We could define a new property, but specifying property values as a single string doesn't scale
private static final PropertyDescriptor<List<String>> EXCLUDED_NAMES =
PropertyFactory.stringListProperty("exclusions")
.desc("Names of fields to whitelist.")
.defaultValues("serialVersionUID", "serialPersistentFields")
.build();
private static final Set<String> MAKE_FIELD_STATIC_CLASS_ANNOT =
setOf(
"lombok.experimental.UtilityClass"
);
private final PropertyDescriptor<Pattern> publicConstantFieldRegex = defaultProp("public constant").defaultValue("[A-Z][A-Z_0-9]*").build();
private final PropertyDescriptor<Pattern> constantFieldRegex = defaultProp("constant").desc("Regex which applies to non-public static final field names").defaultValue("[A-Z][A-Z_0-9]*").build();
private final PropertyDescriptor<Pattern> enumConstantRegex = defaultProp("enum constant").defaultValue("[A-Z][A-Z_0-9]*").build();
private final PropertyDescriptor<Pattern> finalFieldRegex = defaultProp("final field").build();
private final PropertyDescriptor<Pattern> staticFieldRegex = defaultProp("static field").build();
private final PropertyDescriptor<Pattern> defaultFieldRegex = defaultProp("defaultField", "field").build();
public FieldNamingConventionsRule() {
super(ASTFieldDeclaration.class, ASTEnumConstant.class);
definePropertyDescriptor(publicConstantFieldRegex);
definePropertyDescriptor(constantFieldRegex);
definePropertyDescriptor(enumConstantRegex);
definePropertyDescriptor(finalFieldRegex);
definePropertyDescriptor(staticFieldRegex);
definePropertyDescriptor(defaultFieldRegex);
definePropertyDescriptor(EXCLUDED_NAMES);
}
@Override
public Object visit(ASTFieldDeclaration node, Object data) {
for (ASTVariableId id : node) {
if (getProperty(EXCLUDED_NAMES).contains(id.getName())) {
continue;
}
ASTTypeDeclaration enclosingType = node.getEnclosingType();
boolean isFinal = node.hasModifiers(FINAL);
boolean isStatic = node.hasModifiers(STATIC) || JavaAstUtils.hasAnyAnnotation(enclosingType, MAKE_FIELD_STATIC_CLASS_ANNOT);
if (isFinal && isStatic) {
checkMatches(id, node.getVisibility() == V_PUBLIC ? publicConstantFieldRegex : constantFieldRegex, data);
} else if (isFinal) {
checkMatches(id, finalFieldRegex, data);
} else if (isStatic) {
checkMatches(id, staticFieldRegex, data);
} else {
checkMatches(id, defaultFieldRegex, data);
}
}
return data;
}
@Override
public Object visit(ASTEnumConstant node, Object data) {
// This inlines checkMatches because there's no variable declarator id
if (!getProperty(enumConstantRegex).matcher(node.getImage()).matches()) {
asCtx(data).addViolation(node, "enum constant",
node.getImage(),
getProperty(enumConstantRegex).toString());
}
return data;
}
@Override
String defaultConvention() {
return CAMEL_CASE;
}
@Override
String nameExtractor(ASTVariableId node) {
return node.getName();
}
@Override
String kindDisplayName(ASTVariableId node, PropertyDescriptor<Pattern> descriptor) {
boolean isFinal = node.hasModifiers(FINAL);
boolean isStatic = node.hasModifiers(STATIC);
if (isFinal && isStatic) {
return node.getVisibility() == V_PUBLIC ? "public constant" : "constant";
} else if (isFinal) {
return "final field";
} else if (isStatic) {
return "static field";
} else {
return "field";
}
}
}