Repository navigation
Expand file tree
/
Copy pathFieldNamingConventionsRule.java
More file actions
134 lines (109 loc) · 5.21 KB
/
Copy pathFieldNamingConventionsRule.java
File metadata and controls
134 lines (109 loc) · 5.21 KB
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
130
131
132
133
134
/*
* 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;
import net.sourceforge.pmd.reporting.RuleContext;
/**
* 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) {
RuleContext ctx = (RuleContext) 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, ctx);
} else if (isFinal) {
checkMatches(id, finalFieldRegex, ctx);
} else if (isStatic) {
checkMatches(id, staticFieldRegex, ctx);
} else {
checkMatches(id, defaultFieldRegex, ctx);
}
}
return null;
}
@Override
public Object visit(ASTEnumConstant node, Object data) {
RuleContext ctx = (RuleContext) data;
// This inlines checkMatches because there's no variable declarator id
if (!getProperty(enumConstantRegex).matcher(node.getName()).matches()) {
ctx.addViolation(node, "enum constant",
node.getName(),
getProperty(enumConstantRegex).toString());
}
return null;
}
@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";
}
}
}