自定义CheckStyle规则

CheckStyle基于antlr对源码进行处理

  • antlr对AST解析
  • 使用Visitor模式

主要是通过:

1
public int[] getDefaultTokens()

指定要访问的节点类型。

1
public void visitToken(DetailAST assignAST)

指定如何处理节点,并进行规则校验。

参数不可在方法内重新赋值

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
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

import java.util.ArrayList;
import java.util.List;

/**
* Date: 13-8-26
* Time: 下午4:34
* checks the Method Parameter should not assign.
*
* @author shenyanchao
*/
public class ParameterNoAssignCheck extends Check {

private int[] assignTokenTypes = {
TokenTypes.ASSIGN,
TokenTypes.PLUS_ASSIGN,
TokenTypes.MINUS_ASSIGN,
TokenTypes.STAR_ASSIGN,
TokenTypes.DIV_ASSIGN,
TokenTypes.MOD_ASSIGN,
TokenTypes.SR_ASSIGN,
TokenTypes.BSR_ASSIGN,
TokenTypes.SL_ASSIGN,
TokenTypes.BAND_ASSIGN,
TokenTypes.BXOR_ASSIGN,
TokenTypes.BOR_ASSIGN
};

@Override
public int[] getDefaultTokens() {
return assignTokenTypes;
}

@Override
public void visitToken(DetailAST assignAST) {
if (null == assignAST) {
return;
}
DetailAST leftVarAST = assignAST.findFirstToken(TokenTypes.IDENT);
if (null == leftVarAST) {
return;
}
String leftVar = leftVarAST.getText();
DetailAST methodDefAST = findParentMethodDefBy(assignAST);
if (null != methodDefAST) {
List<String> parameters = findMethodParameterNames(methodDefAST);
if (parameters.contains(leftVar)) {
log(leftVarAST.getLineNo(), "Method parameter [" + leftVar + "] should not assign!");
}
}
}
private List<String> findMethodParameterNames(DetailAST methodDefAST) {
List<String> parameters = new ArrayList<String>();
if (null != methodDefAST) {
DetailAST parametersAST = methodDefAST.findFirstToken(TokenTypes.PARAMETERS);
if (null != parametersAST) {
DetailAST parameterDefAST = parametersAST.getFirstChild();
while (null != parameterDefAST) {
if (parameterDefAST.getType() == TokenTypes.PARAMETER_DEF) {
String parameterName = parameterDefAST.findFirstToken(TokenTypes.IDENT).getText();
parameters.add(parameterName);
}
parameterDefAST = parameterDefAST.getNextSibling();
}
}
}
return parameters;
}

/**
* @param aAST aAST
* @return ancestor METHOD_DEF or null
*/
private DetailAST findParentMethodDefBy(DetailAST aAST) {
if (null == aAST || aAST.getType() == TokenTypes.METHOD_DEF) {
return aAST;
} else {
return findParentMethodDefBy(aAST.getParent());
}
}

}

控制使用String连+的数量

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
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

/**
* Date: 13-8-26
* Time: 下午1:29
*
* @author shenyanchao
*/
public class ConcatStringCheck extends Check {

private static final int DEFAULT_MAX = 10;
private int max = DEFAULT_MAX;

@Override
public int[] getDefaultTokens() {
return new int[]{TokenTypes.EXPR};
}

@Override
public void visitToken(DetailAST ast) {
int plusCount = findAllSubNodeIn(ast, TokenTypes.PLUS);
if (plusCount > max - 1) {
log(ast.getLineNo(), "more than " + (max) + " string concat,please use StringBuffer or StringBuilder " +
"instead");
}
}
public void setMax(int limit) {
max = limit;
}

private int findAllSubNodeIn(DetailAST ast, int tokenTypes) {
if (ast.getChildCount() == 0) {
return 0;
} else {
int count = 0;
count += ast.getChildCount(tokenTypes);
DetailAST childAST = ast.getFirstChild();
while (null != childAST) {
count += findAllSubNodeIn(childAST, tokenTypes);
childAST = childAST.getNextSibling();
}
return count;
}
}

}