From e3686ca4043ac7151512e51cba3e1dcfa44b4352 Mon Sep 17 00:00:00 2001 From: Andrei Selkin Date: Sun, 22 Jan 2017 18:30:32 +0300 Subject: [PATCH] Issue #3741: Fix false negative when import is from java.lang package --- .../checks/imports/UnusedImportsCheck.java | 29 +++++++++--- .../imports/UnusedImportsCheckTest.java | 18 ++++++++ .../InputUnusedImportFromJavaLang.java | 44 +++++++++++++++++++ 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/checks/imports/InputUnusedImportFromJavaLang.java diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java index 7559961fa..326459301 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java @@ -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 diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheckTest.java index e8c6c4d1a..e0029468f 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheckTest.java @@ -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); + } } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/imports/InputUnusedImportFromJavaLang.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/imports/InputUnusedImportFromJavaLang.java new file mode 100644 index 000000000..0fcded4e9 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/imports/InputUnusedImportFromJavaLang.java @@ -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; + } +}