aboutsummaryrefslogtreecommitdiffstats
path: root/lint
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-02-13 10:21:50 -0800
committerTor Norbye <tnorbye@google.com>2012-02-13 10:27:00 -0800
commitb89f2aa44747994f8a190cf0da7c466cadb9da2b (patch)
tree005f3d06715291bb8fdee59e8c11548fca09f8ba /lint
parent71008df5a5b37666ce3142c2df69fa93391260ac (diff)
downloadsdk-b89f2aa44747994f8a190cf0da7c466cadb9da2b.zip
sdk-b89f2aa44747994f8a190cf0da7c466cadb9da2b.tar.gz
sdk-b89f2aa44747994f8a190cf0da7c466cadb9da2b.tar.bz2
Add namespace-typo detector
This changeset adds a new lint detector which looks for typos in the namespace declaration for Android. If it sees the prefix "android" it ensures that the URI matches exactly (and case-sensitively) http://schemas.android.com/apk/res/android If the prefix is "a", it also checks for the above prefix, but only warns if the difference is "close" (edit distance <= 3) such that it belives it's a typo, not some unrelated prefix bound to "a". (This was requested in http://b.android.com/25449) Change-Id: Ic6dee77a300fc048cb9bee3e455f533b858ef6bb
Diffstat (limited to 'lint')
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java6
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java1
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/TypoDetector.java95
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TypoDetectorTest.java61
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace.xml24
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace2.xml24
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace3.xml24
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace4.xml27
8 files changed, 261 insertions, 1 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java
index ec6bd6a..c76d44d 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java
@@ -181,7 +181,11 @@ class XmlVisitor {
NamedNodeMap attributes = element.getAttributes();
for (int i = 0, n = attributes.getLength(); i < n; i++) {
Attr attribute = (Attr) attributes.item(i);
- List<Detector.XmlScanner> list = mAttributeToCheck.get(attribute.getLocalName());
+ String name = attribute.getLocalName();
+ if (name == null) {
+ name = attribute.getName();
+ }
+ List<Detector.XmlScanner> list = mAttributeToCheck.get(name);
if (list != null) {
for (int j = 0, max = list.size(); j < max; j++) {
Detector.XmlScanner check = list.get(j);
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 ed5586d..67aabdb 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
@@ -125,6 +125,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(ViewTypeDetector.ISSUE);
issues.add(WrongImportDetector.ISSUE);
issues.add(ViewConstructorDetector.ISSUE);
+ issues.add(TypoDetector.ISSUE);
issues.add(AlwaysShowActionDetector.ISSUE);
addCustomIssues(issues);
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TypoDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TypoDetector.java
new file mode 100644
index 0000000..3fcbcf5
--- /dev/null
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TypoDetector.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.checks;
+
+import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI;
+
+import com.android.tools.lint.detector.api.Category;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.LintUtils;
+import com.android.tools.lint.detector.api.ResourceXmlDetector;
+import com.android.tools.lint.detector.api.Scope;
+import com.android.tools.lint.detector.api.Severity;
+import com.android.tools.lint.detector.api.Speed;
+import com.android.tools.lint.detector.api.XmlContext;
+
+import org.w3c.dom.Attr;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Check which looks for likely typos in various places.
+ */
+public class TypoDetector extends ResourceXmlDetector {
+ private static final String XMLNS_ANDROID = "xmlns:android"; //$NON-NLS-1$
+ private static final String XMLNS_A = "xmlns:a"; //$NON-NLS-1$
+
+ /** The main issue discovered by this detector */
+ public static final Issue ISSUE = Issue.create(
+ "NamespaceTypo", //$NON-NLS-1$
+ "Looks for misspellings in namespace declarations",
+
+ "Accidental misspellings in namespace declarations can lead to some very " +
+ "obscure error messages. This check looks for potential misspellings to " +
+ "help track these down.",
+ Category.CORRECTNESS,
+ 8,
+ Severity.WARNING,
+ TypoDetector.class,
+ Scope.RESOURCE_FILE_SCOPE);
+
+ /** Constructs a new {@link TypoDetector} */
+ public TypoDetector() {
+ }
+
+ @Override
+ public Speed getSpeed() {
+ return Speed.FAST;
+ }
+
+ @Override
+ public Collection<String> getApplicableAttributes() {
+ return Arrays.asList(XMLNS_ANDROID, XMLNS_A);
+ }
+
+ @Override
+ public void visitAttribute(XmlContext context, Attr attribute) {
+ String value = attribute.getValue();
+ if (!value.equals(ANDROID_URI)) {
+ if (attribute.getName().equals(XMLNS_A)) {
+ // For the "android" prefix we always assume that the namespace prefix
+ // should be our expected prefix, but for the "a" prefix we make sure
+ // that it's at least "close"; if you're bound it to something completely
+ // different, don't complain.
+ if (LintUtils.editDistance(ANDROID_URI, value) > 4) {
+ return;
+ }
+ }
+
+ if (value.equalsIgnoreCase(ANDROID_URI)) {
+ context.report(ISSUE, attribute, context.getLocation(attribute),
+ String.format("URI is case sensitive: was \"%1$s\", expected \"%2$s\"",
+ value, ANDROID_URI), null);
+ } else {
+ context.report(ISSUE, attribute, context.getLocation(attribute),
+ String.format("Unexpected namespace URI bound to the \"android\" " +
+ "prefix, was %1$s, expected %2$s", value, ANDROID_URI), null);
+ }
+ }
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TypoDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TypoDetectorTest.java
new file mode 100644
index 0000000..b9af7a2
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TypoDetectorTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.checks;
+
+import com.android.tools.lint.detector.api.Detector;
+
+@SuppressWarnings("javadoc")
+public class TypoDetectorTest extends AbstractCheckTest {
+ @Override
+ protected Detector getDetector() {
+ return new TypoDetector();
+ }
+
+ public void test() throws Exception {
+ assertEquals(
+ "wrong_namespace.xml:2: Warning: Unexpected namespace URI bound to the " +
+ "\"android\" prefix, was http://schemas.android.com/apk/res/andriod, " +
+ "expected http://schemas.android.com/apk/res/android",
+
+ lintProject("res/layout/wrong_namespace.xml"));
+ }
+
+ public void test2() throws Exception {
+ assertEquals(
+ "wrong_namespace2.xml:2: Warning: URI is case sensitive: was " +
+ "\"http://schemas.android.com/apk/res/Android\", expected " +
+ "\"http://schemas.android.com/apk/res/android\"",
+
+ lintProject("res/layout/wrong_namespace2.xml"));
+ }
+
+ public void test3() throws Exception {
+ assertEquals(
+ "wrong_namespace3.xml:2: Warning: Unexpected namespace URI bound to the " +
+ "\"android\" prefix, was http://schemas.android.com/apk/res/androi, " +
+ "expected http://schemas.android.com/apk/res/android",
+
+ lintProject("res/layout/wrong_namespace3.xml"));
+ }
+
+ public void testOk() throws Exception {
+ assertEquals(
+ "No warnings.",
+
+ lintProject("res/layout/wrong_namespace4.xml"));
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace.xml
new file mode 100644
index 0000000..c6e2143
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/andriod"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <include
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ layout="@layout/layout2" />
+
+ <Button
+ android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+ <Button
+ android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+</LinearLayout>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace2.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace2.xml
new file mode 100644
index 0000000..49dc611
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace2.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/Android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <include
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ layout="@layout/layout2" />
+
+ <Button
+ android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+ <Button
+ android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+</LinearLayout>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace3.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace3.xml
new file mode 100644
index 0000000..02252b4
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace3.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:a="http://schemas.android.com/apk/res/androi"
+ a:layout_width="match_parent"
+ a:layout_height="match_parent"
+ a:orientation="vertical" >
+
+ <include
+ a:layout_width="wrap_content"
+ a:layout_height="wrap_content"
+ layout="@layout/layout2" />
+
+ <Button
+ a:id="@+id/button1"
+ a:layout_width="wrap_content"
+ a:layout_height="wrap_content"
+ a:text="Button" />
+
+ <Button
+ a:id="@+id/button2"
+ a:layout_width="wrap_content"
+ a:layout_height="wrap_content"
+ a:text="Button" />
+
+</LinearLayout>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace4.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace4.xml
new file mode 100644
index 0000000..4142622
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/wrong_namespace4.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This file does *not* have a wrong namespace: it's testdata to make sure we don't complain when "a" is defined for something unrelated -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:a="http://something/very/different"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <include
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ layout="@layout/layout2" />
+
+ <Button
+ android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+ <Button
+ android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+</LinearLayout>