1 package com.puppycrawl.tools.checkstyle.checks.coding; 20 21 import com.puppycrawl.tools.checkstyle.api.Check; 22 import com.puppycrawl.tools.checkstyle.api.DetailAST; 23 import com.puppycrawl.tools.checkstyle.api.ScopeUtils; 24 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 25 26 import com.puppycrawl.tools.checkstyle.checks.CheckUtils; 27 28 import java.util.Arrays ; 29 30 46 public class MagicNumberCheck extends Check 47 { 48 52 private static final int[] ALLOWED_PATH_TOKENTYPES = { 53 TokenTypes.ASSIGN, 54 TokenTypes.ARRAY_INIT, 55 TokenTypes.EXPR, 56 TokenTypes.UNARY_PLUS, 57 TokenTypes.UNARY_MINUS, 58 TokenTypes.TYPECAST, 59 TokenTypes.ELIST, 60 TokenTypes.LITERAL_NEW, 61 TokenTypes.METHOD_CALL, 62 TokenTypes.STAR, 63 }; 64 65 static { 66 Arrays.sort(ALLOWED_PATH_TOKENTYPES); 67 } 68 69 70 private double[] mIgnoreNumbers = {-1, 0, 1, 2}; 71 72 73 public int[] getDefaultTokens() 74 { 75 return new int[] { 76 TokenTypes.NUM_DOUBLE, 77 TokenTypes.NUM_FLOAT, 78 TokenTypes.NUM_INT, 79 TokenTypes.NUM_LONG, 80 }; 81 } 82 83 84 public void visitToken(DetailAST aAST) 85 { 86 if (inIgnoreList(aAST)) { 87 return; 88 } 89 90 final DetailAST constantDefAST = findContainingConstantDef(aAST); 91 92 if (constantDefAST == null) { 93 reportMagicNumber(aAST); 94 } 95 else { 96 DetailAST ast = aAST.getParent(); 97 while (ast != constantDefAST) { 98 final int type = ast.getType(); 99 if (Arrays.binarySearch(ALLOWED_PATH_TOKENTYPES, type) < 0) { 100 reportMagicNumber(aAST); 101 break; 102 } 103 104 ast = ast.getParent(); 105 } 106 } 107 } 108 109 115 private DetailAST findContainingConstantDef(DetailAST aAST) 116 { 117 DetailAST varDefAST = aAST; 118 while ((varDefAST != null) 119 && (varDefAST.getType() != TokenTypes.VARIABLE_DEF) 120 && (varDefAST.getType() != TokenTypes.ENUM_CONSTANT_DEF)) 121 { 122 varDefAST = varDefAST.getParent(); 123 } 124 125 if (varDefAST == null) { 127 return null; 128 } 129 130 if (ScopeUtils.inInterfaceOrAnnotationBlock(varDefAST) 132 || (varDefAST.getType() == TokenTypes.ENUM_CONSTANT_DEF)) 133 { 134 return varDefAST; 135 } 136 137 final DetailAST modifiersAST = 139 varDefAST.findFirstToken(TokenTypes.MODIFIERS); 140 if (modifiersAST.branchContains(TokenTypes.FINAL)) { 141 return varDefAST; 142 } 143 144 return null; 145 } 146 147 151 private void reportMagicNumber(DetailAST aAST) 152 { 153 String text = aAST.getText(); 154 final DetailAST parent = aAST.getParent(); 155 DetailAST reportAST = aAST; 156 if (parent.getType() == TokenTypes.UNARY_MINUS) { 157 reportAST = parent; 158 text = "-" + text; 159 } 160 else if (parent.getType() == TokenTypes.UNARY_PLUS) { 161 reportAST = parent; 162 text = "+" + text; 163 } 164 log(reportAST.getLineNo(), 165 reportAST.getColumnNo(), 166 "magic.number", 167 text); 168 } 169 170 177 private boolean inIgnoreList(DetailAST aAST) 178 { 179 double value = CheckUtils.parseDouble(aAST.getText(), aAST.getType()); 180 final DetailAST parent = aAST.getParent(); 181 if (parent.getType() == TokenTypes.UNARY_MINUS) { 182 value = -1 * value; 183 } 184 return (Arrays.binarySearch(mIgnoreNumbers, value) >= 0); 185 } 186 187 192 public void setIgnoreNumbers(double[] aList) 193 { 194 if ((aList == null) || (aList.length == 0)) { 195 mIgnoreNumbers = new double[0]; 196 } 197 else { 198 mIgnoreNumbers = new double[aList.length]; 199 System.arraycopy(aList, 0, mIgnoreNumbers, 0, aList.length); 200 Arrays.sort(mIgnoreNumbers); 201 } 202 } 203 } 204 | Popular Tags |