aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-08-27 10:11:34 -0700
committerTor Norbye <tnorbye@google.com>2012-08-27 14:50:09 -0700
commitfeadb6b4daf294c45425eb0300366675a5ce0b89 (patch)
tree4521e34be458632d93e43ba283b11de4d853873a
parent708c14a6e409a71c8dcbfe69c2ee7ed67d5e50e5 (diff)
downloadsdk-feadb6b4daf294c45425eb0300366675a5ce0b89.zip
sdk-feadb6b4daf294c45425eb0300366675a5ce0b89.tar.gz
sdk-feadb6b4daf294c45425eb0300366675a5ce0b89.tar.bz2
Issue 34322: Fix handling of import statements
Fix the commit prefs lint check such that it correctly identifies scenarios where the innerclass "Editor" is referenced without its qualifying top level class, SharedPreferences. Change-Id: I3a22738508b66ce0b3e836feff91f816b2c368e8
-rw-r--r--eclipse/dictionary.txt1
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java45
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java9
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/SharedPrefsDetectorTest.java36
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest2.java.txt19
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest3.java.txt15
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest4.java.txt15
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java73
8 files changed, 210 insertions, 3 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt
index af3d835..c4d9089 100644
--- a/eclipse/dictionary.txt
+++ b/eclipse/dictionary.txt
@@ -341,6 +341,7 @@ wakelocks
wallpaper
webtools
whilst
+wildcard
workflow
xdpi
xhdpi
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
index 514d91e..fe659cd 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
@@ -47,6 +47,8 @@ import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
+import lombok.ast.ImportDeclaration;
+
/**
* Useful utility methods related to lint.
@@ -707,4 +709,47 @@ public class LintUtils {
return locale;
}
+
+ /**
+ * Returns true if the given class (specified by a fully qualified class
+ * name) name is imported in the given compilation unit either through a fully qualified
+ * import or by a wildcard import.
+ *
+ * @param compilationUnit the compilation unit
+ * @param fullyQualifiedName the fully qualified class name
+ * @return true if the given imported name refers to the given fully
+ * qualified name
+ */
+ public static boolean isImported(
+ @NonNull lombok.ast.Node compilationUnit,
+ @NonNull String fullyQualifiedName) {
+ int dotIndex = fullyQualifiedName.lastIndexOf('.');
+ int dotLength = fullyQualifiedName.length() - dotIndex;
+
+ boolean imported = false;
+ for (lombok.ast.Node rootNode : compilationUnit.getChildren()) {
+ if (rootNode instanceof ImportDeclaration) {
+ ImportDeclaration importDeclaration = (ImportDeclaration) rootNode;
+ String fqn = importDeclaration.asFullyQualifiedName();
+ if (fqn.equals(fullyQualifiedName)) {
+ return true;
+ } else if (fullyQualifiedName.regionMatches(dotIndex, fqn,
+ fqn.length() - dotLength, dotLength)) {
+ // This import is importing the class name using some other prefix, so there
+ // fully qualified class name cannot be imported under that name
+ return false;
+ } else if (importDeclaration.astStarImport()
+ && fqn.regionMatches(0, fqn, 0, dotIndex + 1)) {
+ imported = true;
+ // but don't break -- keep searching in case there's a non-wildcard
+ // import of the specific class name, e.g. if we're looking for
+ // android.content.SharedPreferences.Editor, don't match on the following:
+ // import android.content.SharedPreferences.*;
+ // import foo.bar.Editor;
+ }
+ }
+ }
+
+ return imported;
+ }
}
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java
index 685d9cf..5db301b 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java
@@ -23,6 +23,7 @@ import com.android.tools.lint.detector.api.Context;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
+import com.android.tools.lint.detector.api.LintUtils;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
@@ -109,8 +110,12 @@ public class SharedPrefsDetector extends Detector implements Detector.JavaScanne
}
VariableDefinition definition = (VariableDefinition) node.getParent().getParent();
String type = definition.astTypeReference().toString();
- if (!type.endsWith("SharedPreferences.Editor")) { //$NON-NLS-1$
- return;
+ if (!type.endsWith("SharedPreferences.Editor")) { //$NON-NLS-1$
+ if (!type.equals("Editor") || //$NON-NLS-1$
+ !LintUtils.isImported(context.compilationUnit,
+ "android.content.SharedPreferences.Editor")) { //$NON-NLS-1$
+ return;
+ }
}
Node method = findSurroundingMethod(node.getParent());
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/SharedPrefsDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/SharedPrefsDetectorTest.java
index b77f3bd..964232c 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/SharedPrefsDetectorTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/SharedPrefsDetectorTest.java
@@ -39,4 +39,40 @@ public class SharedPrefsDetectorTest extends AbstractCheckTest {
lintProject("src/test/pkg/SharedPrefsTest.java.txt=>" +
"src/test/pkg/SharedPrefsTest.java"));
}
+
+ public void test2() throws Exception {
+ // Regression test 1 for http://code.google.com/p/android/issues/detail?id=34322
+ assertEquals(
+ "src/test/pkg/SharedPrefsTest2.java:13: Warning: SharedPreferences.edit() without a corresponding commit() or apply() call [CommitPrefEdits]\n" +
+ " SharedPreferences.Editor editor = preferences.edit();\n" +
+ " ~~~~~~~~~~~~~~~~~~\n" +
+ "src/test/pkg/SharedPrefsTest2.java:17: Warning: SharedPreferences.edit() without a corresponding commit() or apply() call [CommitPrefEdits]\n" +
+ " Editor editor = preferences.edit();\n" +
+ " ~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 2 warnings\n",
+
+ lintProject("src/test/pkg/SharedPrefsTest2.java.txt=>" +
+ "src/test/pkg/SharedPrefsTest2.java"));
+ }
+
+ public void test3() throws Exception {
+ // Regression test 2 for http://code.google.com/p/android/issues/detail?id=34322
+ assertEquals(
+ "src/test/pkg/SharedPrefsTest3.java:13: Warning: SharedPreferences.edit() without a corresponding commit() or apply() call [CommitPrefEdits]\n" +
+ " Editor editor = preferences.edit();\n" +
+ " ~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n",
+
+ lintProject("src/test/pkg/SharedPrefsTest3.java.txt=>" +
+ "src/test/pkg/SharedPrefsTest3.java"));
+ }
+
+ public void test4() throws Exception {
+ // Regression test 3 for http://code.google.com/p/android/issues/detail?id=34322
+ assertEquals(
+ "No warnings.",
+
+ lintProject("src/test/pkg/SharedPrefsTest4.java.txt=>" +
+ "src/test/pkg/SharedPrefsTest4.java"));
+ }
}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest2.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest2.java.txt
new file mode 100644
index 0000000..20c3a21
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest2.java.txt
@@ -0,0 +1,19 @@
+package test.pkg;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+@SuppressWarnings("unused")
+public class SharedPrefsTest2 extends Activity {
+ public void test1(SharedPreferences preferences) {
+ SharedPreferences.Editor editor = preferences.edit();
+ }
+
+ public void test2(SharedPreferences preferences) {
+ Editor editor = preferences.edit();
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest3.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest3.java.txt
new file mode 100644
index 0000000..e5baa00
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest3.java.txt
@@ -0,0 +1,15 @@
+package test.pkg;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.*;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+@SuppressWarnings("unused")
+public class SharedPrefsTest3 extends Activity {
+ public void test(SharedPreferences preferences) {
+ Editor editor = preferences.edit();
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest4.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest4.java.txt
new file mode 100644
index 0000000..28de959
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/SharedPrefsTest4.java.txt
@@ -0,0 +1,15 @@
+package test.pkg;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.SharedPreferences;
+import foo.bar.Editor;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+@SuppressWarnings("unused")
+public class SharedPrefsTest4 extends Activity {
+ public void test(SharedPreferences preferences) {
+ Editor editor = preferences.edit();
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java
index 0ce3815..7dfa260 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java
@@ -17,9 +17,15 @@
package com.android.tools.lint.detector.api;
import static com.android.tools.lint.detector.api.LintUtils.getLocaleAndRegion;
+import static com.android.tools.lint.detector.api.LintUtils.isImported;
import static com.android.tools.lint.detector.api.LintUtils.splitPath;
+import com.android.annotations.Nullable;
+import com.android.tools.lint.LombokParser;
import com.android.tools.lint.Main;
+import com.android.tools.lint.checks.BuiltinIssueRegistry;
+import com.android.tools.lint.client.api.IJavaParser;
+import com.android.tools.lint.client.api.LintDriver;
import com.google.common.collect.Iterables;
import java.io.BufferedOutputStream;
@@ -29,6 +35,7 @@ import java.io.OutputStreamWriter;
import java.util.Arrays;
import junit.framework.TestCase;
+import lombok.ast.Node;
@SuppressWarnings("javadoc")
public class LintUtilsTest extends TestCase {
@@ -285,4 +292,68 @@ public class LintUtilsTest extends TestCase {
assertEquals("zh-rCN", getLocaleAndRegion("values-zh-rCN-keyshidden"));
assertEquals("ms", getLocaleAndRegion("values-ms-keyshidden"));
}
-} \ No newline at end of file
+
+ public void testIsImported() throws Exception {
+ assertFalse(isImported(getCompilationUnit(
+ "package foo.bar;\n" +
+ "class Foo {\n" +
+ "}\n"),
+ "android.app.Activity"));
+
+ assertTrue(isImported(getCompilationUnit(
+ "package foo.bar;\n" +
+ "import foo.bar.*;\n" +
+ "import android.app.Activity;\n" +
+ "import foo.bar.Baz;\n" +
+ "class Foo {\n" +
+ "}\n"),
+ "android.app.Activity"));
+
+ assertTrue(isImported(getCompilationUnit(
+ "package foo.bar;\n" +
+ "import android.app.Activity;\n" +
+ "class Foo {\n" +
+ "}\n"),
+ "android.app.Activity"));
+
+ assertTrue(isImported(getCompilationUnit(
+ "package foo.bar;\n" +
+ "import android.app.*;\n" +
+ "class Foo {\n" +
+ "}\n"),
+ "android.app.Activity"));
+
+ assertFalse(isImported(getCompilationUnit(
+ "package foo.bar;\n" +
+ "import android.app.*;\n" +
+ "import foo.bar.Activity;\n" +
+ "class Foo {\n" +
+ "}\n"),
+ "android.app.Activity"));
+ }
+
+ private Node getCompilationUnit(String javaSource) {
+ IJavaParser parser = new LombokParser();
+ TestContext context = new TestContext(javaSource, new File("test"));
+ Node compilationUnit = parser.parseJava(context);
+ assertNotNull(javaSource, compilationUnit);
+ return compilationUnit;
+ }
+
+ private class TestContext extends JavaContext {
+ private final String mJavaSource;
+ public TestContext(String javaSource, File file) {
+ super(new LintDriver(new BuiltinIssueRegistry(),
+ new Main()), new Main().getProject(new File("dummy"), new File("dummy")),
+ null, file);
+
+ mJavaSource = javaSource;
+ }
+
+ @Override
+ @Nullable
+ public String getContents() {
+ return mJavaSource;
+ }
+ }
+}