有沒有被Source Review折磨過?有沒有被千奇百怪的寫法折磨過?
發(fā)現(xiàn)對(duì)中國的coder來說,規(guī)范基本等于0。明明代碼規(guī)范里說不許寫但是照寫的大有人在。
用人力去Review這些代碼有時(shí)候容易遺漏,有時(shí)候沒有這么多力氣去看幾千行代碼。
所以工具必不可少。這里講一個(gè)檢查字符串相加的。
字符串相加,例如
String str1 = "abc";
String str = str1 + "123";
很多情況下是違反代碼規(guī)范的。
知道這種+號(hào)會(huì)被javac翻譯成StringBuffer.append,所以我才不能用findbugs,8過代碼規(guī)范不等于語言。
普通的做法可以檢查出""這種的字符串相加,我這里寫了一個(gè)很垃圾的能檢查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;
}
}
}
需要一點(diǎn)點(diǎn)AST方面的知識(shí)。TokenTypes.PLUS就是+號(hào),PLUS_ASSIGN就是+=,VARIABLE_DEF是定義一個(gè)變量。
當(dāng)遇到VARIABLE_DEF的時(shí)候呢,就去把它的TYPE和NAME儲(chǔ)存到vartbl里去。
stringifyNode的時(shí)候要遞歸。因?yàn)橛腥藭?huì)寫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);
}
}
整個(gè)邏輯其實(shí)就是,當(dāng)你AST看到+號(hào)的時(shí)候,看看前面,后面是不是文字類型。如果不是文字類型但是是一個(gè)標(biāo)示符的話,就看下vartbl里是不是有這個(gè)標(biāo)示符,然后看看他的類型是不是String。
代碼作用域還沒有考慮進(jìn)去-_-!。