aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java23
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java1
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java3
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java56
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java23
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ViewTypeDetectorTest.java10
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/broken-manifest2.xml28
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/casts2.xml23
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/WrongCastActivity2.java.txt15
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/DefaultSdkInfoTest.java4
10 files changed, 179 insertions, 7 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
index f8d6cd9..29c3da6 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
@@ -77,6 +77,8 @@ class DefaultSdkInfo extends SdkInfo {
@Override
@Nullable
public String getParentViewName(@NonNull String name) {
+ name = getRawType(name);
+
return PARENTS.get(name);
}
@@ -102,6 +104,9 @@ class DefaultSdkInfo extends SdkInfo {
@Override
public boolean isSubViewOf(@NonNull String parent, @NonNull String child) {
+ parent = getRawType(parent);
+ child = getRawType(child);
+
// Do analysis just on non-fqcn paths
if (parent.indexOf('.') != -1) {
parent = parent.substring(parent.lastIndexOf('.') + 1);
@@ -128,13 +133,25 @@ class DefaultSdkInfo extends SdkInfo {
return false;
}
+ // Strip off type parameters, e.g. AdapterView<?> => AdapterView
+ private static String getRawType(String type) {
+ if (type != null) {
+ int index = type.indexOf('<');
+ if (index != -1) {
+ type = type.substring(0, index);
+ }
+ }
+
+ return type;
+ }
+
private static final int CLASS_COUNT = 59;
@NonNull
private static final Map<String, String> PARENTS = new HashMap<String, String>(CLASS_COUNT);
static {
- PARENTS.put(COMPOUND_BUTTON, VIEW);
+ PARENTS.put(COMPOUND_BUTTON, BUTTON);
PARENTS.put(ABS_SPINNER, ADAPTER_VIEW);
PARENTS.put(ABS_LIST_VIEW, ADAPTER_VIEW);
PARENTS.put(ABS_SEEK_BAR, ADAPTER_VIEW);
@@ -201,9 +218,7 @@ class DefaultSdkInfo extends SdkInfo {
/*
// Check that all widgets lead to the root view
- boolean assertionsEnabled = false;
- assert assertionsEnabled = true; // Intentional side-effect
- if (assertionsEnabled) {
+ if (LintUtils.assertionsEnabled()) {
for (String key : PARENTS.keySet()) {
String parent = PARENTS.get(key);
if (!parent.equals(VIEW)) {
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java
index fb8e134..a2757cb 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java
@@ -48,6 +48,7 @@ public class LintConstants {
// Tags: Manifest
public static final String TAG_SERVICE = "service"; //$NON-NLS-1$
public static final String TAG_USES_PERMISSION = "uses-permission";//$NON-NLS-1$
+ public static final String TAG_USES_LIBRARY = "uses-library"; //$NON-NLS-1$
public static final String TAG_APPLICATION = "application"; //$NON-NLS-1$
public static final String TAG_INTENT_FILTER = "intent-filter"; //$NON-NLS-1$
public static final String TAG_USES_SDK = "uses-sdk"; //$NON-NLS-1$
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
index 0232245..74ddd8a 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
@@ -53,7 +53,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
private static final List<Issue> sIssues;
static {
- final int initialCapacity = 85;
+ final int initialCapacity = 86;
List<Issue> issues = new ArrayList<Issue>(initialCapacity);
issues.add(AccessibilityDetector.ISSUE);
@@ -103,6 +103,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(ManifestOrderDetector.ORDER);
issues.add(ManifestOrderDetector.USES_SDK);
issues.add(ManifestOrderDetector.MULTIPLE_USES_SDK);
+ issues.add(ManifestOrderDetector.WRONG_PARENT);
issues.add(SecurityDetector.EXPORTED_SERVICE);
issues.add(SecurityDetector.OPEN_PROVIDER);
issues.add(SecurityDetector.WORLD_READABLE);
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java
index 95ca8b9..856bd26 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java
@@ -20,7 +20,12 @@ import static com.android.tools.lint.detector.api.LintConstants.ANDROID_MANIFEST
import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI;
import static com.android.tools.lint.detector.api.LintConstants.ATTR_MIN_SDK_VERSION;
import static com.android.tools.lint.detector.api.LintConstants.ATTR_TARGET_SDK_VERSION;
+import static com.android.tools.lint.detector.api.LintConstants.TAG_ACTIVITY;
import static com.android.tools.lint.detector.api.LintConstants.TAG_APPLICATION;
+import static com.android.tools.lint.detector.api.LintConstants.TAG_PROVIDER;
+import static com.android.tools.lint.detector.api.LintConstants.TAG_RECEIVER;
+import static com.android.tools.lint.detector.api.LintConstants.TAG_SERVICE;
+import static com.android.tools.lint.detector.api.LintConstants.TAG_USES_LIBRARY;
import static com.android.tools.lint.detector.api.LintConstants.TAG_USES_PERMISSION;
import static com.android.tools.lint.detector.api.LintConstants.TAG_USES_SDK;
@@ -35,6 +40,7 @@ import com.android.tools.lint.detector.api.Speed;
import com.android.tools.lint.detector.api.XmlContext;
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.File;
@@ -93,11 +99,29 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
Category.CORRECTNESS,
6,
- Severity.ERROR,
+ Severity.FATAL,
ManifestOrderDetector.class,
EnumSet.of(Scope.MANIFEST)).setMoreInfo(
"http://developer.android.com/guide/topics/manifest/uses-sdk-element.html"); //$NON-NLS-1$
+ /** Missing a {@code <uses-sdk>} element */
+ public static final Issue WRONG_PARENT = Issue.create(
+ "WrongManifestParent", //$NON-NLS-1$
+ "Checks that various manifest elements are declared in the right place",
+
+ "The <uses-library> element should be defined as a direct child of the " +
+ "<application> tag, not the <manifest> tag or an <activity> tag. Similarly, " +
+ "a <uses-sdk> tag much be declared at the root level, and so on. This check " +
+ "looks for incorrect declaration locations in the manifest, and complains " +
+ "if an element is found in the wrong place.",
+
+ Category.CORRECTNESS,
+ 6,
+ Severity.FATAL,
+ ManifestOrderDetector.class,
+ EnumSet.of(Scope.MANIFEST)).setMoreInfo(
+ "http://developer.android.com/guide/topics/manifest/manifest-intro.html"); //$NON-NLS-1$
+
/** Constructs a new {@link ManifestOrderDetector} check */
public ManifestOrderDetector() {
}
@@ -148,13 +172,41 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
"uses-feature", //$NON-NLS-1$
"supports-screens", //$NON-NLS-1$
"compatible-screens", //$NON-NLS-1$
- "supports-gl-texture" //$NON-NLS-1$
+ "supports-gl-texture", //$NON-NLS-1$
+ TAG_USES_LIBRARY,
+ TAG_ACTIVITY,
+ TAG_SERVICE,
+ TAG_PROVIDER,
+ TAG_RECEIVER
);
}
@Override
public void visitElement(XmlContext context, Element element) {
String tag = element.getTagName();
+ Node parentNode = element.getParentNode();
+
+ if (tag.equals(TAG_USES_LIBRARY) || tag.equals(TAG_ACTIVITY) || tag.equals(TAG_SERVICE)
+ || tag.equals(TAG_PROVIDER) || tag.equals(TAG_RECEIVER)) {
+ if (!TAG_APPLICATION.equals(parentNode.getNodeName())
+ && context.isEnabled(WRONG_PARENT)) {
+ context.report(WRONG_PARENT, element, context.getLocation(element),
+ String.format(
+ "The <%1$s> element must be a direct child of the <application> element",
+ tag), null);
+ }
+
+ return;
+ }
+
+ if (parentNode != element.getOwnerDocument().getDocumentElement()
+ && context.isEnabled(WRONG_PARENT)) {
+ context.report(WRONG_PARENT, element, context.getLocation(element),
+ String.format(
+ "The <%1$s> element must be a direct child of the " +
+ "<manifest> root element", tag), null);
+ }
+
if (tag.equals(TAG_USES_SDK)) {
mSeenUsesSdk++;
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
index 8ecee91..9553d78 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
@@ -77,4 +77,27 @@ public class ManifestOrderDetectorTest extends AbstractCheckTest {
"multiplesdk.xml=>AndroidManifest.xml",
"res/values/strings.xml"));
}
+
+ public void testWrongLocation() throws Exception {
+ assertEquals(
+ "AndroidManifest.xml:10: Error: The <permission> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:11: Error: The <permission-tree> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:12: Error: The <permission-group> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:14: Error: The <uses-sdk> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:15: Error: The <uses-configuration> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:16: Error: The <uses-feature> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:17: Error: The <supports-screens> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:18: Error: The <compatible-screens> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:19: Error: The <supports-gl-texture> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:24: Error: The <uses-library> element must be a direct child of the <application> element\n" +
+ "AndroidManifest.xml:25: Error: The <activity> element must be a direct child of the <application> element\n" +
+ "AndroidManifest.xml:8: Error: The <uses-sdk> element must be a direct child of the <manifest> root element\n" +
+ "AndroidManifest.xml:8: Warning: <uses-sdk> tag appears after <application> tag\n" +
+ "AndroidManifest.xml:8: Warning: <uses-sdk> tag should specify a target API level (the highest verified version; when running on later versions, compatibility behaviors may be enabled) with android:targetSdkVersion=\"?\"\n" +
+ "AndroidManifest.xml:9: Error: The <uses-permission> element must be a direct child of the <manifest> root element\n" +
+ "ManifestOrderDetectorTest_testWrongLocation/AndroidManifest.xml:14: Error: There should only be a single <uses-sdk> element in the manifest: merge these together\n" +
+ "=> ManifestOrderDetectorTest_testWrongLocation/AndroidManifest.xml:8: Also appears here",
+
+ lintProject("broken-manifest2.xml=>AndroidManifest.xml"));
+ }
}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ViewTypeDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ViewTypeDetectorTest.java
index f1f8492..2ea876f 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ViewTypeDetectorTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ViewTypeDetectorTest.java
@@ -34,4 +34,14 @@ public class ViewTypeDetectorTest extends AbstractCheckTest {
"src/test/pkg/WrongCastActivity.java.txt=>src/test/pkg/WrongCastActivity.java"
));
}
+
+ public void test27441() throws Exception {
+ assertEquals(
+ "No warnings.",
+
+ lintProject(
+ "res/layout/casts2.xml",
+ "src/test/pkg/WrongCastActivity2.java.txt=>src/test/pkg/WrongCastActivity2.java"
+ ));
+ }
}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/broken-manifest2.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/broken-manifest2.xml
new file mode 100644
index 0000000..307046b
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/broken-manifest2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.helloworld"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:icon="@drawable/icon" android:label="@string/app_name">
+ <!-- Wrong declaration locations -->
+ <uses-sdk android:minSdkVersion="Froyo" />
+ <uses-permission />
+ <permission />
+ <permission-tree />
+ <permission-group />
+ <instrumentation />
+ <uses-sdk />
+ <uses-configuration />
+ <uses-feature />
+ <supports-screens />
+ <compatible-screens />
+ <supports-gl-texture />
+
+ </application>
+
+ <!-- Wrong declaration locations -->
+ <uses-library />
+ <activity android:name=".HelloWorld"
+ android:label="@string/app_name" />
+
+</manifest>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/casts2.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/casts2.xml
new file mode 100644
index 0000000..249c02f
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/casts2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- unit test from issue 27441 -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <RadioGroup
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <RadioButton
+ android:id="@+id/additional"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <Spinner
+ android:id="@+id/reminder_lead"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </RadioGroup>
+
+</ScrollView>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/WrongCastActivity2.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/WrongCastActivity2.java.txt
new file mode 100644
index 0000000..7cd422a
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/src/test/pkg/WrongCastActivity2.java.txt
@@ -0,0 +1,15 @@
+package test.pkg;
+
+import android.app.*;
+import android.view.*;
+import android.widget.*;
+
+public class WrongCastActivity2 extends Activity {
+ private TextView additionalButton;
+
+ private void configureAdditionalButton(View bodyView) {
+ this.additionalButton = (TextView) bodyView
+ .findViewById(R.id.additional);
+ Object x = (AdapterView<?>) bodyView.findViewById(R.id.reminder_lead);
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/DefaultSdkInfoTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/DefaultSdkInfoTest.java
index 2ce41e4..afdc985 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/DefaultSdkInfoTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/client/api/DefaultSdkInfoTest.java
@@ -42,6 +42,9 @@ public class DefaultSdkInfoTest extends TestCase {
DefaultSdkInfo info = new DefaultSdkInfo();
assertTrue(info.isSubViewOf("Button", "Button"));
assertTrue(info.isSubViewOf("TextView", "Button"));
+ assertTrue(info.isSubViewOf("TextView", "RadioButton"));
+ assertTrue(info.isSubViewOf("AdapterView", "Spinner"));
+ assertTrue(info.isSubViewOf("AdapterView<?>", "Spinner"));
assertFalse(info.isSubViewOf("Button", "TextView"));
assertFalse(info.isSubViewOf("CheckBox", "ToggleButton"));
assertFalse(info.isSubViewOf("ToggleButton", "CheckBox"));
@@ -52,5 +55,6 @@ public class DefaultSdkInfoTest extends TestCase {
assertFalse(info.isSubViewOf("EditText", "TextView"));
assertTrue(info.isSubViewOf("View", "TextView"));
assertFalse(info.isSubViewOf("TextView", "View"));
+ assertFalse(info.isSubViewOf("Spinner", "AdapterView<?>"));
}
}