有没有被Source Review折磨过?有没有被千奇百怪的写法折磨过?
发现对中国的coder来说,规范基本等于0。明明代码规范里说不许写但是照写的大有人在。
用人力去Review这些代码有时候容易遗漏,有时候没有这么多力气去看几千行代码。
所以工具必不可少。这里讲一个检查字符串相加的。
字符串相加,例如
知道这种+号会被javac翻译成StringBuffer.append,所以我才不能用findbugs,8过代码规范不等于语言。
普通的做法可以检查出""这种的字符串相加,我这里写了一个很垃圾的能检查 String变量相加的情况。变量范围仅限于local变量。目前来说是够了。
需要一点点AST方面的知识。 TokenTypes.PLUS就是+号, PLUS_ASSIGN就是+=, VARIABLE_DEF是定义一个变量 。
当遇到VARIABLE_DEF的时候呢,就去把它的TYPE和NAME储存到vartbl里去。
stringifyNode的时候要递归。因为有人会写java.lang.String abc = "123";(-_-!一切皆有可能)
整个逻辑其实就是,当你AST看到+号的时候,看看前面,后面是不是文字类型。如果不是文字类型但是是一个标示符的话,就看下 vartbl里是不是有这个标示符,然后看看他的类型是不是String。
代码作用域还没有考虑进去-_-!。
发现对中国的coder来说,规范基本等于0。明明代码规范里说不许写但是照写的大有人在。
用人力去Review这些代码有时候容易遗漏,有时候没有这么多力气去看几千行代码。
所以工具必不可少。这里讲一个检查字符串相加的。
字符串相加,例如
String str1
=
"
abc
"
;
String str = str1 + " 123 " ;
很多情况下是违反代码规范的。
String str = str1 + " 123 " ;

普通的做法可以检查出""这种的字符串相加,我这里写了一个很垃圾的能检查 String变量相加的情况。变量范围仅限于local变量。目前来说是够了。
public
class
StringPlusCheck
extends
Check {
public StringPlusCheck(){
}
public int [] getDefaultTokens() {
return new int [] {TokenTypes.PLUS, TokenTypes.PLUS_ASSIGN,TokenTypes.VARIABLE_DEF};
}
public void visitToken(DetailAST aAST) {
switch (aAST.getType()) {
case TokenTypes.VARIABLE_DEF:
processVarDef(aAST);
break ;
default :
AST firstChild = aAST.getFirstChild();
AST secondChild = firstChild.getNextSibling();
if (checkType(firstChild) || checkType(secondChild)) {
log(aAST.getLineNo(), aAST.getColumnNo(), " zhu tou you wrote a string plus " , aAST.getText());
}
}
}
private void processVarDef(DetailAST aAST) {
AST child = aAST.getFirstChild();
String varName = null ;
String varType = null ;
while (child != null ) {
switch (child.getType()) {
case TokenTypes.TYPE:
varType = ASTUtils.stringifyNode(child.getFirstChild());
break ;
case TokenTypes.IDENT:
varName = child.getText();
break ;
default :
break ;
}
child = child.getNextSibling();
}
vartbl.put(varName, varType);
}
private boolean checkType(AST ast) {
switch (ast.getType()) {
case TokenTypes.STRING_LITERAL:
case TokenTypes.CHAR_LITERAL:
return true ;
case TokenTypes.IDENT:
String varName = ast.getText();
String varType = (String)vartbl.get(varName);
if (varType != null && varType.endsWith( " String " )) {
return false ;
}
default :
return false ;
}
}
}
public StringPlusCheck(){
}
public int [] getDefaultTokens() {
return new int [] {TokenTypes.PLUS, TokenTypes.PLUS_ASSIGN,TokenTypes.VARIABLE_DEF};
}
public void visitToken(DetailAST aAST) {
switch (aAST.getType()) {
case TokenTypes.VARIABLE_DEF:
processVarDef(aAST);
break ;
default :
AST firstChild = aAST.getFirstChild();
AST secondChild = firstChild.getNextSibling();
if (checkType(firstChild) || checkType(secondChild)) {
log(aAST.getLineNo(), aAST.getColumnNo(), " zhu tou you wrote a string plus " , aAST.getText());
}
}
}
private void processVarDef(DetailAST aAST) {
AST child = aAST.getFirstChild();
String varName = null ;
String varType = null ;
while (child != null ) {
switch (child.getType()) {
case TokenTypes.TYPE:
varType = ASTUtils.stringifyNode(child.getFirstChild());
break ;
case TokenTypes.IDENT:
varName = child.getText();
break ;
default :
break ;
}
child = child.getNextSibling();
}
vartbl.put(varName, varType);
}
private boolean checkType(AST ast) {
switch (ast.getType()) {
case TokenTypes.STRING_LITERAL:
case TokenTypes.CHAR_LITERAL:
return true ;
case TokenTypes.IDENT:
String varName = ast.getText();
String varType = (String)vartbl.get(varName);
if (varType != null && varType.endsWith( " String " )) {
return false ;
}
default :
return false ;
}
}
}
需要一点点AST方面的知识。 TokenTypes.PLUS就是+号, PLUS_ASSIGN就是+=, VARIABLE_DEF是定义一个变量 。
当遇到VARIABLE_DEF的时候呢,就去把它的TYPE和NAME储存到vartbl里去。
stringifyNode的时候要递归。因为有人会写java.lang.String abc = "123";(-_-!一切皆有可能)
public
static
String stringifyNode(AST ast) {
StringBuffer result = new StringBuffer();
_stringifyNode(ast, result);
return result.toString();
}
private static void _stringifyNode(AST ast, StringBuffer sbf) {
if (ast == null ) {
return ;
}
int childcnt = ast.getNumberOfChildren();
if (childcnt > 0 ) {
_stringifyNode(ast.getFirstChild(), sbf);
}
sbf.append(ast.getText());
if (childcnt > 0 ) {
_stringifyNode(ast.getFirstChild().getNextSibling(), sbf);
}
}
StringBuffer result = new StringBuffer();
_stringifyNode(ast, result);
return result.toString();
}
private static void _stringifyNode(AST ast, StringBuffer sbf) {
if (ast == null ) {
return ;
}
int childcnt = ast.getNumberOfChildren();
if (childcnt > 0 ) {
_stringifyNode(ast.getFirstChild(), sbf);
}
sbf.append(ast.getText());
if (childcnt > 0 ) {
_stringifyNode(ast.getFirstChild().getNextSibling(), sbf);
}
}
整个逻辑其实就是,当你AST看到+号的时候,看看前面,后面是不是文字类型。如果不是文字类型但是是一个标示符的话,就看下 vartbl里是不是有这个标示符,然后看看他的类型是不是String。
代码作用域还没有考虑进去-_-!。