Issue #3741: Fix false negative when import is from java.lang package

This commit is contained in:
Andrei Selkin 2017-01-22 18:30:32 +03:00 committed by rnveach
parent 3065df7eee
commit e3686ca404
3 changed files with 84 additions and 7 deletions

View File

@ -58,15 +58,19 @@ public class UnusedImportsCheck extends AbstractCheck {
public static final String MSG_KEY = "import.unused";
/** Regex to match class names. */
private static final Pattern CLASS_NAME = Pattern.compile(
private static final Pattern CLASS_NAME = CommonUtils.createPattern(
"((:?[\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*)");
/** Regex to match the first class name. */
private static final Pattern FIRST_CLASS_NAME = Pattern.compile(
private static final Pattern FIRST_CLASS_NAME = CommonUtils.createPattern(
"^" + CLASS_NAME);
/** Regex to match argument names. */
private static final Pattern ARGUMENT_NAME = Pattern.compile(
private static final Pattern ARGUMENT_NAME = CommonUtils.createPattern(
"[(,]\\s*" + CLASS_NAME.pattern());
/** Regexp pattern to match java.lang package. */
private static final Pattern JAVA_LANG_PACKAGE_PATTERN =
CommonUtils.createPattern("^java\\.lang\\.[a-zA-Z]+$");
/** Suffix for the star import. */
private static final String STAR_IMPORT_SUFFIX = ".*";
@ -101,10 +105,10 @@ public class UnusedImportsCheck extends AbstractCheck {
public void finishTree(DetailAST rootAST) {
// loop over all the imports to see if referenced.
imports.stream()
.filter(imp -> !referenced.contains(CommonUtils.baseClassName(imp.getText())))
.forEach(imp -> log(imp.getLineNo(),
imp.getColumnNo(),
MSG_KEY, imp.getText()));
.filter(imprt -> isUnusedImport(imprt.getText()))
.forEach(imprt -> log(imprt.getLineNo(),
imprt.getColumnNo(),
MSG_KEY, imprt.getText()));
}
@Override
@ -173,6 +177,17 @@ public class UnusedImportsCheck extends AbstractCheck {
}
}
/**
* Checks whether an import is unused.
* @param imprt an import.
* @return true if an import is unused.
*/
private boolean isUnusedImport(String imprt) {
final Matcher javaLangPackageMatcher = JAVA_LANG_PACKAGE_PATTERN.matcher(imprt);
return !referenced.contains(CommonUtils.baseClassName(imprt))
|| javaLangPackageMatcher.matches();
}
/**
* Collects references made by IDENT.
* @param ast the IDENT node to process

View File

@ -186,4 +186,22 @@ public class UnusedImportsCheckTest extends BaseCheckTestSupport {
expected);
}
@Test
public void testImportsFromJavaLang() throws Exception {
final DefaultConfiguration checkConfig = createCheckConfig(UnusedImportsCheck.class);
final String[] expected = {
"3:8: " + getCheckMessage(MSG_KEY, "java.lang.String"),
"4:8: " + getCheckMessage(MSG_KEY, "java.lang.Math"),
"5:8: " + getCheckMessage(MSG_KEY, "java.lang.Class"),
"6:8: " + getCheckMessage(MSG_KEY, "java.lang.Exception"),
"7:8: " + getCheckMessage(MSG_KEY, "java.lang.Runnable"),
"8:8: " + getCheckMessage(MSG_KEY, "java.lang.RuntimeException"),
"9:8: " + getCheckMessage(MSG_KEY, "java.lang.ProcessBuilder"),
"10:8: " + getCheckMessage(MSG_KEY, "java.lang.Double"),
"11:8: " + getCheckMessage(MSG_KEY, "java.lang.Integer"),
"12:8: " + getCheckMessage(MSG_KEY, "java.lang.Float"),
"13:8: " + getCheckMessage(MSG_KEY, "java.lang.Short"),
};
verify(checkConfig, getPath("InputUnusedImportFromJavaLang.java"), expected);
}
}

View File

@ -0,0 +1,44 @@
package com.puppycrawl.tools.checkstyle.checks.imports;
import java.lang.String; // VIOLATION
import java.lang.Math; // VIOLATION
import java.lang.Class; // VIOLATION
import java.lang.Exception; // VIOLATION
import java.lang.Runnable; // VIOLATION
import java.lang.RuntimeException; // VIOLATION
import java.lang.ProcessBuilder; // VIOLATION
import java.lang.Double; // VIOLATION
import java.lang.Integer; // VIOLATION
import java.lang.Float; // VIOLATION
import java.lang.Short; // VIOLATION
import java.lang.annotation.Annotation; // OK
import java.lang.reflect.Modifier; // OK
import java.lang.reflect.Field; // OK
import java.lang.*; // OK
public class InputUnusedImportFromJavaLang {
private static final String SOMETHING = "a string";
private static final double PI = Math.PI;
private Class clazz = this.getClass();
private Exception ex = new RuntimeException();
private Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
private ProcessBuilder processBuilder = new ProcessBuilder();
private Modifier modifier = new Modifier();
private Field field;
private Annotation annotation;
public static void main(String[] args) {
Double d = new Double(0.0d);
Float f = new Float(0.1f);
Integer i = new Integer(1);
Short s = Short.MIN_VALUE;
}
}