Skip to content

Commit

Permalink
Issue sevntu-checkstyle#425: New option to skip fields by regexp
Browse files Browse the repository at this point in the history
  • Loading branch information
cypai committed Mar 6, 2016
1 parent 170fb86 commit 0c7f5fc
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ private enum Type {
*/
private static final int DEFAULT_MAX_BINARY_SYMBOLS_UNTIL_UNDERSCORE = 8;

/**
* Default regexp for fields to ignore for this check.
*/
private static final Pattern DEFAULT_IGNORE_FIELD_NAME_PATTERN =
Pattern.compile("serialVersionUID");

/**
* Regex for splitting a decimal literal into checkable substrings.
*/
Expand Down Expand Up @@ -247,6 +253,11 @@ private enum Type {
*/
private int maxBinarySymbolsUntilUnderscore = DEFAULT_MAX_BINARY_SYMBOLS_UNTIL_UNDERSCORE;

/**
* Regexp for fields to ignore.
*/
private Pattern ignoreFieldNamePattern = DEFAULT_IGNORE_FIELD_NAME_PATTERN;

/**
* Sets how many characters in a decimal literal there must be before it checks for an
* underscore.
Expand Down Expand Up @@ -307,6 +318,15 @@ public void setMaxBinarySymbolsUntilUnderscore(int amount) {
maxBinarySymbolsUntilUnderscore = amount;
}

/**
* Sets the regexp pattern for field names to ignore.
* @param pattern
* the regexp pattern of fields to ignore
*/
public void setIgnoreFieldNamePattern(String pattern) {
ignoreFieldNamePattern = Pattern.compile(pattern);
}

@Override
public int[] getDefaultTokens() {
return new int[] {
Expand All @@ -319,28 +339,69 @@ public int[] getDefaultTokens() {

@Override
public void visitToken(final DetailAST ast) {
if (!passesCheck(ast.getText())) {
if (!passesCheck(ast)) {
log(ast.getLineNo(), MSG_KEY);
}
}

/**
* Returns true if the numeric literal passes the check.
* @param rawLiteral
* numeric literal
* Checks if the provided token is a field.
* @param ast
* the token to check
* @return whether or not the token is a field
*/
private static boolean isField(final DetailAST ast) {
DetailAST current = ast;
while (current.getParent() != null && current.getType() != TokenTypes.VARIABLE_DEF) {
current = current.getParent();
}
return current.getType() == TokenTypes.VARIABLE_DEF
&& current.branchContains(TokenTypes.LITERAL_STATIC)
&& current.branchContains(TokenTypes.FINAL);
}

/**
* Returns the provided field's name.
* @param ast
* the field for which the function looks for a name
* @return the field's name
*/
private static String getFieldName(final DetailAST ast) {
DetailAST current = ast;
while (current.getParent() != null && current.getType() != TokenTypes.VARIABLE_DEF) {
current = current.getParent();
}
current = current.getFirstChild();
while (current.getType() != TokenTypes.IDENT) {
current = current.getNextSibling();
}
return current.getText();
}

/**
* Returns true if the ast passes the check.
* @param ast
* the numeric literal to check
* @return if the numeric literal passes the check
*/
private boolean passesCheck(String rawLiteral) {
final Type type = getNumericType(rawLiteral);
final int minCheckingLength = minSymbolsBeforeChecking(type);
final int symbolsUntilUnderscore = maxSymbolsUntilUnderscore(type);
final String[] numericSegments = getNumericSegments(rawLiteral);
boolean passing = true;
for (String numericSegment : numericSegments) {
if (!numericSegmentPassesRequirement(numericSegment,
minCheckingLength, symbolsUntilUnderscore)) {
passing = false;
break;
private boolean passesCheck(final DetailAST ast) {
boolean passing;
if (isField(ast) && ignoreFieldNamePattern.matcher(getFieldName(ast)).find()) {
passing = true;
}
else {
final String rawLiteral = ast.getText();
final Type type = getNumericType(rawLiteral);
final int minCheckingLength = minSymbolsBeforeChecking(type);
final int symbolsUntilUnderscore = maxSymbolsUntilUnderscore(type);
final String[] numericSegments = getNumericSegments(rawLiteral);
passing = true;
for (String numericSegment : numericSegments) {
if (!numericSegmentPassesRequirement(numericSegment,
minCheckingLength, symbolsUntilUnderscore)) {
passing = false;
break;
}
}
}
return passing;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static com.github.sevntu.checkstyle.checks.coding.NumericLiteralNeedsUnderscoreCheck.MSG_KEY;

import java.io.File;

import org.junit.Test;

import com.github.sevntu.checkstyle.BaseCheckTestSupport;
Expand Down Expand Up @@ -97,4 +99,54 @@ public void testWithConfig()
expected);
}

@Test
public void testIgnore() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(NumericLiteralNeedsUnderscoreCheck.class);
final String[] expected = {
"7: " + warningMessage,
"8: " + warningMessage,
"10: " + warningMessage,
"15: " + warningMessage,
"16: " + warningMessage,
"17: " + warningMessage,
"22: " + warningMessage,
"24: " + warningMessage,
"30: " + warningMessage,
"31: " + warningMessage,
"32: " + warningMessage,
"33: " + warningMessage,
"40: " + warningMessage,
};
verify(checkConfig, new File("src/test/resources-noncompilable/com/github/sevntu/checkstyle/checks/"
+ "coding/InputNumericLiteralNeedUnderscoreCheck3.java").getCanonicalPath(),
expected);
}

@Test
public void testConfiguredIgnore() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(NumericLiteralNeedsUnderscoreCheck.class);
checkConfig.addAttribute("ignoreFieldNamePattern", "RED");
checkConfig.addAttribute("minDecimalSymbolLen", "1");
final String[] expected = {
"7: " + warningMessage,
"8: " + warningMessage,
"10: " + warningMessage,
"14: " + warningMessage,
"15: " + warningMessage,
"17: " + warningMessage,
"22: " + warningMessage,
"24: " + warningMessage,
"30: " + warningMessage,
"31: " + warningMessage,
"32: " + warningMessage,
"33: " + warningMessage,
"38: " + warningMessage,
};
verify(checkConfig, new File("src/test/resources-noncompilable/com/github/sevntu/checkstyle/checks/"
+ "coding/InputNumericLiteralNeedUnderscoreCheck3.java").getCanonicalPath(),
expected);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.github.sevntu.checkstyle.checks.coding;

import java.util.function.Function;

public class InputNumericLiteralNeedUnderscoreCheck3 {

private static final float G = 6.6740831E-11f;
private static final double H = 6.626070040E-34d;

float serialVersionUID = 0x1234567F;

public void foo() {
SomeBean bean = new SomeBean() {
private static final long serialVersionUID = -35450329839532371L;
public static final long ABC = 1234567L;
public static final long RED = 0xFF0000FFL;
public static long blue = 0x0000FFFFL;

@Override
public int bar() {
Function<Integer, Integer> f = (i) -> {
return 1234567 + i;
};
return 1234567;
}
};
}

private void bar() {
float a = 0x0000FFP1F;
float b = 0x0000FFp1F;
float c = 0x0000FF;
float d = 0x0000FF00;
}

static class SomeException extends Exception {

private static final long serialVersionUID = -35450329839532371L;
private static final int CONSTANT = 1;
static final int RED = 0xF00000;

}

static abstract class SomeBean {
public abstract int bar();
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.github.sevntu.checkstyle.checks.coding;

public class InputNumericLiteralNeedUnderscoreCheck {

public void goodNumericLiterals() {
int goodInt1 = 1234;
int goodInt2 = 1_234_567;
Expand All @@ -22,7 +22,7 @@ public void goodNumericLiterals() {
double goodDouble6 = -123_456.789d;
double goodDouble7 = -123_456.123456D;
}

public void badNumericLiterals() {
int badInt = 1234567;
long badLong1 = 1234567L;
Expand All @@ -33,7 +33,7 @@ public void badNumericLiterals() {
badFloat -= 1.2345678f;
}
}

public void scientificNotation() {
float fgood1 = 123.456e2f;
float fgood2 = 123_4.123_456_7e2f;
Expand All @@ -45,7 +45,7 @@ public void scientificNotation() {
double dgood4 = 1234.123_456_7e2d;
double dgood5 = 1234.123_456_7e2D;
}

public void badScientificNotation() {
float fbad1 = 1.2345678e2f;
float fbad2 = 123_4.12_3456_7e2f;
Expand All @@ -56,7 +56,7 @@ public void badScientificNotation() {
double dbad4 = 1234.12_3456_7e2d;
double dbad5 = 1234.12_3456_7e2D;
}

public void goodHexLiterals() {
int goodInt1 = 0xFF;
int goodInt2 = 0xFFFF_FFFF;
Expand All @@ -70,7 +70,7 @@ public void goodHexLiterals() {
double goodDouble2 = 0xCA_FE_DEED.DEAD_BEEFp0d;
double goodDouble3 = 0x1.1234p0d;
}

public void badHexLiterals() {
int badInt1 = 0x11111111;
int badInt2 = 0xFFFEFFFE;
Expand All @@ -84,7 +84,7 @@ public void badHexLiterals() {
double badDouble1 = 0x12345.6p2;
double badDouble2 = 0x1.12345p2d;
}

public void goodBinaryLiterals() {
int goodInt1 = 0b00001111;
int goodInt2 = 0b00001111_00001111;
Expand All @@ -94,7 +94,7 @@ public void goodBinaryLiterals() {
long goodLong3 = 0b00001111_00001111l;
long goodLong4 = 0b00001111l;
}

public void badBinaryLiterals() {
int badInt1 = 0b000011110;
int badInt2 = 0b0000111_100001111;
Expand All @@ -103,5 +103,5 @@ public void badBinaryLiterals() {
long badLong3 = 0b000011111l;
long badLong4 = 0b00001111_00001111_000011111_0001111l;
}

}

0 comments on commit 0c7f5fc

Please sign in to comment.