aboutsummaryrefslogtreecommitdiffstats
path: root/lint/libs
diff options
context:
space:
mode:
Diffstat (limited to 'lint/libs')
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java82
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java27
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java2
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ApiDetectorTest.java20
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$1.class.databin0 -> 674 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1$InnerInnerClass1.class.databin0 -> 762 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1.class.databin0 -> 824 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass2.class.databin0 -> 638 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.class.databin0 -> 854 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.java.txt41
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/LintDriverTest.java51
11 files changed, 221 insertions, 2 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
index a749ace..d328ab8 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
@@ -31,6 +31,7 @@ import static org.objectweb.asm.Opcodes.ASM4;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.annotations.VisibleForTesting;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.client.api.LintListener.EventType;
import com.android.tools.lint.detector.api.Category;
@@ -66,10 +67,12 @@ import org.w3c.dom.Element;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Deque;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -860,6 +863,7 @@ public class LintDriver {
if (libraries.size() > 0) {
libraryEntries = new ArrayList<ClassEntry>(64);
findClasses(libraryEntries, libraries);
+ Collections.sort(libraryEntries);
} else {
libraryEntries = Collections.emptyList();
}
@@ -877,6 +881,7 @@ public class LintDriver {
} else {
classEntries = new ArrayList<ClassEntry>(64);
findClasses(classEntries, classFolders);
+ Collections.sort(classEntries);
}
if (getPhase() == 1) {
@@ -894,15 +899,35 @@ public class LintDriver {
runClassDetectors(Scope.CLASS_FILE, classEntries, project, main);
}
+ /**
+ * Stack of {@link ClassNode} nodes for outer classes of the currently
+ * processed class, including that class itself. Populated by
+ * {@link #runClassDetectors(Scope, List, Project, Project)} and used by
+ * {@link #getOuterClassNode(ClassNode)}
+ */
+ private Deque<ClassNode> mOuterClasses;
+
private void runClassDetectors(Scope scope, List<ClassEntry> entries,
Project project, Project main) {
if (mScope.contains(scope)) {
List<Detector> classDetectors = mScopeDetectors.get(scope);
if (classDetectors != null && classDetectors.size() > 0 && entries.size() > 0) {
+ mOuterClasses = new ArrayDeque<ClassNode>();
for (ClassEntry entry : entries) {
ClassReader reader = new ClassReader(entry.bytes);
ClassNode classNode = new ClassNode();
reader.accept(classNode, 0 /* flags */);
+
+ ClassNode peek;
+ while ((peek = mOuterClasses.peek()) != null) {
+ if (classNode.name.startsWith(peek.name)) {
+ break;
+ } else {
+ mOuterClasses.pop();
+ }
+ }
+ mOuterClasses.push(classNode);
+
if (isSuppressed(null, classNode)) {
// Class was annotated with suppress all -- no need to look any further
continue;
@@ -917,8 +942,31 @@ public class LintDriver {
return;
}
}
+
+ mOuterClasses = null;
+ }
+ }
+ }
+
+ /** Returns the outer class node of the given class node
+ * @param classNode the inner class node
+ * @return the outer class node */
+ public ClassNode getOuterClassNode(@NonNull ClassNode classNode) {
+ String outerName = classNode.outerClass;
+
+ Iterator<ClassNode> iterator = mOuterClasses.iterator();
+ while (iterator.hasNext()) {
+ ClassNode node = iterator.next();
+ if (outerName != null) {
+ if (node.name.equals(outerName)) {
+ return node;
+ }
+ } else if (node == classNode) {
+ return iterator.hasNext() ? iterator.next() : null;
}
}
+
+ return null;
}
private Map<String, String> getSuperMap(List<ClassEntry> libraryEntries,
@@ -1665,7 +1713,8 @@ public class LintDriver {
}
/** A pending class to be analyzed by {@link #checkClasses} */
- private static class ClassEntry {
+ @VisibleForTesting
+ static class ClassEntry implements Comparable<ClassEntry> {
public final File file;
public final File jarFile;
public final File binDir;
@@ -1678,5 +1727,36 @@ public class LintDriver {
this.binDir = binDir;
this.bytes = bytes;
}
+
+ @Override
+ public int compareTo(ClassEntry other) {
+ String p1 = file.getPath();
+ String p2 = other.file.getPath();
+ int m1 = p1.length();
+ int m2 = p2.length();
+ int m = Math.min(m1, m2);
+
+ for (int i = 0; i < m; i++) {
+ char c1 = p1.charAt(i);
+ char c2 = p2.charAt(i);
+ if (c1 != c2) {
+ // Sort Foo$Bar.class *after* Foo.class, even though $ < .
+ if (c1 == '.' && c2 == '$') {
+ return -1;
+ }
+ if (c1 == '$' && c2 == '.') {
+ return 1;
+ }
+ return c1 - c2;
+ }
+ }
+
+ return (m == m1) ? -1 : 1;
+ }
+
+ @Override
+ public String toString() {
+ return file.getPath();
+ }
}
}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java
index 9de6dc8..ff05270 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java
@@ -257,6 +257,33 @@ public class ClassContext extends Context {
if (mDriver.isSuppressed(issue, mClassNode)) {
return;
}
+ ClassNode curr = mClassNode;
+ while (curr != null) {
+ curr = mDriver.getOuterClassNode(curr);
+ if (curr != null) {
+ if (mClassNode.outerMethod != null) {
+ @SuppressWarnings("rawtypes") // ASM API
+ List methods = curr.methods;
+ for (Object m : methods) {
+ MethodNode method = (MethodNode) m;
+ if (method.name.equals(mClassNode.outerMethod)
+ && method.desc.equals(mClassNode.outerMethodDesc)) {
+ // Found the outer method for this anonymous class; continue
+ // reporting on it (which will also work its way up the parent
+ // class hierarchy)
+ if (method != null && mDriver.isSuppressed(issue, method)) {
+ return;
+ }
+ break;
+ }
+ }
+ }
+ if (mDriver.isSuppressed(issue, curr)) {
+ return;
+ }
+ }
+ }
+
super.report(issue, location, message, data);
}
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java
index 0c3aaee..5f9a1e3 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java
@@ -76,7 +76,7 @@ public class ApiLookup {
private static final int BINARY_FORMAT_VERSION = 1;
private static final boolean DEBUG_FORCE_REGENERATE_BINARY = false;
private static final boolean DEBUG_SEARCH = false;
- private static final boolean WRITE_STATS = LintUtils.assertionsEnabled();
+ private static final boolean WRITE_STATS = false;
/** Default size to reserve for each API entry when creating byte buffer to build up data */
private static final int BYTES_PER_ENTRY = 40;
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ApiDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ApiDetectorTest.java
index 797059c..eb35e1d 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ApiDetectorTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ApiDetectorTest.java
@@ -236,6 +236,26 @@ public class ApiDetectorTest extends AbstractCheckTest {
));
}
+ public void testSuppressInnerClasses() throws Exception {
+ assertEquals(
+ // These errors are correctly -not- suppressed because they
+ // appear outside the middle inner class suppressing its own errors
+ // and its child's errors
+ "ApiCallTest4.java:38: Error: Call requires API level 14 (current min is 1): android.widget.GridLayout#<init>\n" +
+ "ApiCallTest4.java:9: Error: Call requires API level 14 (current min is 1): android.widget.GridLayout#<init>",
+
+ lintProject(
+ "apicheck/classpath=>.classpath",
+ "apicheck/minsdk1.xml=>AndroidManifest.xml",
+ "apicheck/ApiCallTest4.java.txt=>src/test/pkg/ApiCallTest4.java",
+ "apicheck/ApiCallTest4.class.data=>bin/classes/test/pkg/ApiCallTest4.class",
+ "apicheck/ApiCallTest4$1.class.data=>bin/classes/test/pkg/ApiCallTest4$1.class",
+ "apicheck/ApiCallTest4$InnerClass1.class.data=>bin/classes/test/pkg/ApiCallTest4$InnerClass1.class",
+ "apicheck/ApiCallTest4$InnerClass2.class.data=>bin/classes/test/pkg/ApiCallTest4$InnerClass2.class",
+ "apicheck/ApiCallTest4$InnerClass1$InnerInnerClass1.class.data=>bin/classes/test/pkg/ApiCallTest4$InnerClass1$InnerInnerClass1.class"
+ ));
+ }
+
public void testApiTargetAnnotation() throws Exception {
assertEquals(
"ApiTargetTest.java:13: Error: Class requires API level 8 (current min is 1): org.w3c.dom.DOMErrorHandler\n" +
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$1.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$1.class.data
new file mode 100644
index 0000000..8d3fbf7
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$1.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1$InnerInnerClass1.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1$InnerInnerClass1.class.data
new file mode 100644
index 0000000..940b83d
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1$InnerInnerClass1.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1.class.data
new file mode 100644
index 0000000..4da3d3b
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass1.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass2.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass2.class.data
new file mode 100644
index 0000000..c8e914b
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4$InnerClass2.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.class.data
new file mode 100644
index 0000000..b51d04a
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.java.txt
new file mode 100644
index 0000000..de6be04
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/apicheck/ApiCallTest4.java.txt
@@ -0,0 +1,41 @@
+package test.pkg;
+
+import android.annotation.SuppressLint;
+import android.widget.GridLayout;
+
+@SuppressWarnings("unused")
+public class ApiCallTest4 {
+ public void foo() {
+ new GridLayout(null, null, 0);
+ }
+
+ @SuppressLint("NewApi")
+ void foo2() {
+ // Inner class suppressed via a method in outer class
+ new Runnable() {
+ @Override
+ public void run() {
+ new GridLayout(null, null, 0);
+ }
+ };
+ }
+
+ @SuppressLint("NewApi")
+ private class InnerClass1 {
+ void foo() {
+ new GridLayout(null, null, 0);
+ }
+
+ private class InnerInnerClass1 {
+ public void foo() {
+ new GridLayout(null, null, 0);
+ }
+ }
+ }
+
+ private class InnerClass2 {
+ public void foo() {
+ new GridLayout(null, null, 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/LintDriverTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/LintDriverTest.java
new file mode 100644
index 0000000..0fbc221
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/LintDriverTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tools.lint.client.api;
+
+import com.android.tools.lint.client.api.LintDriver.ClassEntry;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class LintDriverTest extends TestCase {
+ public void testClassEntryCompare() throws Exception {
+ ClassEntry c0 = new ClassEntry(new File("/a1/Foo.class"), null, null, null);
+ ClassEntry c1 = new ClassEntry(new File("/a1/Foo.clazz"), null, null, null);
+ ClassEntry c2 = new ClassEntry(new File("/a1/Foo$Inner1.class"), null, null, null);
+ ClassEntry c3 = new ClassEntry(new File("/a1/Foo$Inner1$Inner.class"), null, null, null);
+ ClassEntry c4 = new ClassEntry(new File("/a2/Foo$Inner2.clas"), null, null, null);
+ ClassEntry c5 = new ClassEntry(new File("/a2/Foo$Inner2.class"), null, null, null);
+
+ List<ClassEntry> expected = Arrays.asList(c0, c1, c2, c3, c4, c5);
+ List<ClassEntry> list = new ArrayList<ClassEntry>(expected);
+ Collections.sort(list);
+ assertEquals(list, list);
+
+ List<ClassEntry> list2 = Arrays.asList(c5, c4, c3, c2, c1, c0);
+ Collections.sort(list2);
+ assertEquals(expected, list2);
+
+ List<ClassEntry> list3 = Arrays.asList(c3, c0, c1, c5, c2, c4);
+ Collections.sort(list3);
+ assertEquals(expected, list3);
+ }
+}