aboutsummaryrefslogtreecommitdiffstats
path: root/lint
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-02-21 09:00:44 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-02-21 09:00:44 -0800
commit556b907792f0658a6c3f676e23469b83175e3431 (patch)
tree498d4772977266614d802a46296301bc163cfb1f /lint
parentf9a57e464104e29c045939d84e8d3fb5d9becf7d (diff)
parent247b1d7186a2f64a38417a3172fa07de35681a5f (diff)
downloadsdk-556b907792f0658a6c3f676e23469b83175e3431.tar.gz
sdk-556b907792f0658a6c3f676e23469b83175e3431.tar.bz2
sdk-556b907792f0658a6c3f676e23469b83175e3431.zip
Merge "Lint rule checking that activities and services are registered"
Diffstat (limited to 'lint')
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java29
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java2
-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/RegistrationDetector.java246
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/RegistrationDetectorTest.java76
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/AbstractActivity.java.txt6
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.class.databin0 -> 295 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.java.txt6
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AndroidManifestWrongRegs.xml21
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.class.databin0 -> 1401 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.java.txt40
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.class.databin0 -> 287 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.java.txt4
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver$1.class.databin0 -> 748 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.class.databin0 -> 726 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.java.txt21
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.class.databin0 -> 441 bytes
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.java.txt14
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ClassContextTest.java35
19 files changed, 501 insertions, 2 deletions
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 08da20c66..9de6dc806 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
@@ -355,7 +355,8 @@ public class ClassContext extends Context {
/**
* Computes a user-readable type signature from the given class owner, name
- * and description
+ * and description. For example, for owner="foo/bar/Foo$Baz", name="foo",
+ * description="(I)V", it returns "void foo.bar.Foo.Bar#foo(int)".
*
* @param owner the class name
* @param name the method name
@@ -406,4 +407,30 @@ public class ClassContext extends Context {
return s;
}
+
+ /**
+ * Computes the internal class name of the given fully qualified class name.
+ * For example, it converts foo.bar.Foo.Bar into foo/bar/Foo$Bar
+ *
+ * @param fqcn the fully qualified class name
+ * @return the internal class name
+ */
+ public static String getInternalName(String fqcn) {
+ String[] parts = fqcn.split("\\."); //$NON-NLS-1$
+ StringBuilder sb = new StringBuilder();
+ String prev = null;
+ for (String part : parts) {
+ if (prev != null) {
+ if (Character.isUpperCase(prev.charAt(0))) {
+ sb.append('$');
+ } else {
+ sb.append('/');
+ }
+ }
+ sb.append(part);
+ prev = part;
+ }
+
+ return sb.toString();
+ }
}
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 371046f27..7d2c35aaa 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
@@ -44,6 +44,8 @@ public class LintConstants {
public static final String TAG_INTENT_FILTER = "intent-filter"; //$NON-NLS-1$
public static final String TAG_USES_SDK = "uses-sdk"; //$NON-NLS-1$
public static final String TAG_ACTIVITY = "activity"; //$NON-NLS-1$
+ public static final String TAG_RECEIVER = "receiver"; //$NON-NLS-1$
+ public static final String TAG_PROVIDER = "provider"; //$NON-NLS-1$
public static final String TAG_GRANT_PERMISSION = "grant-uri-permission"; //$NON-NLS-1$
// Tags: Resources
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 6df3defac..cdb4c125d 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 = 78;
+ final int initialCapacity = 79;
List<Issue> issues = new ArrayList<Issue>(initialCapacity);
issues.add(AccessibilityDetector.ISSUE);
@@ -84,6 +84,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(TooManyViewsDetector.TOO_DEEP);
issues.add(GridLayoutDetector.ISSUE);
issues.add(OnClickDetector.ISSUE);
+ issues.add(RegistrationDetector.ISSUE);
issues.add(TranslationDetector.EXTRA);
issues.add(TranslationDetector.MISSING);
issues.add(HardcodedValuesDetector.ISSUE);
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/RegistrationDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/RegistrationDetector.java
new file mode 100644
index 000000000..59bac6256
--- /dev/null
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/RegistrationDetector.java
@@ -0,0 +1,246 @@
+/*
+ * 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 static com.android.tools.lint.detector.api.LintConstants.ATTR_NAME;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_PACKAGE;
+import static com.android.tools.lint.detector.api.LintConstants.TAG_ACTIVITY;
+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 com.android.tools.lint.detector.api.Category;
+import com.android.tools.lint.detector.api.ClassContext;
+import com.android.tools.lint.detector.api.Context;
+import com.android.tools.lint.detector.api.Detector.ClassScanner;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.LayoutDetector;
+import com.android.tools.lint.detector.api.Location;
+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 com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.ClassNode;
+import org.w3c.dom.Element;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Map.Entry;
+
+/**
+ * Checks for missing manifest registrations for activities, services etc
+ * and also makes sure that they are registered with the correct tag
+ */
+public class RegistrationDetector extends LayoutDetector implements ClassScanner {
+ private static final String ANDROID_APP_ACTIVITY = "android/app/Activity"; //$NON-NLS-1$
+ private static final String ANDROID_APP_SERVICE = "android/app/Service"; //$NON-NLS-1$
+ private static final String ANDROID_CONTENT_CONTENT_PROVIDER =
+ "android/content/ContentProvider"; //$NON-NLS-1$
+ private static final String ANDROID_CONTENT_BROADCAST_RECEIVER =
+ "android/content/BroadcastReceiver"; //$NON-NLS-1$
+
+ /** Unregistered activities and services */
+ public static final Issue ISSUE = Issue.create(
+ "Registered", //$NON-NLS-1$
+ "Ensures that Activities, Services and Content Providers are registered in the manifest",
+
+ "Activities, services and content providers should be registered in the " +
+ "AndroidManifext.xml file using <activity>, <service> and <provider> tags.\n" +
+ "\n" +
+ "If your activity is simply a parent class intended to be subclassed by other " +
+ "\"real\" activities, make it an abstract class.",
+
+ Category.CORRECTNESS,
+ 6,
+ Severity.WARNING,
+ RegistrationDetector.class,
+ EnumSet.of(Scope.MANIFEST, Scope.CLASS_FILE)).setMoreInfo(
+ "http://developer.android.com/guide/topics/manifest/manifest-intro.html"); //$NON-NLS-1$
+
+ private Multimap<String, String> mManifestRegistrations;
+
+ /** Constructs a new {@link RegistrationDetector} */
+ public RegistrationDetector() {
+ }
+
+ @Override
+ public Speed getSpeed() {
+ return Speed.FAST;
+ }
+
+ @Override
+ public boolean appliesTo(Context context, File file) {
+ return true;
+ }
+
+ // ---- Implements XmlScanner ----
+
+ @Override
+ public Collection<String> getApplicableElements() {
+ return Arrays.asList(sTags);
+ }
+
+ @Override
+ public void visitElement(XmlContext context, Element element) {
+ String fqcn = getFqcn(element);
+ String tag = element.getTagName();
+ String frameworkClass = tagToClass(tag);
+ if (frameworkClass != null) {
+ String signature = ClassContext.getInternalName(fqcn);
+ if (mManifestRegistrations == null) {
+ mManifestRegistrations = ArrayListMultimap.create(4, 8);
+ }
+ mManifestRegistrations.put(frameworkClass, signature);
+ }
+ }
+
+ private static String getFqcn(Element element) {
+ StringBuilder sb = new StringBuilder();
+ Element root = element.getOwnerDocument().getDocumentElement();
+ String pkg = root.getAttribute(ATTR_PACKAGE);
+ String className = element.getAttributeNS(ANDROID_URI, ATTR_NAME);
+ if (className.startsWith(".")) { //$NON-NLS-1$
+ sb.append(pkg);
+ } else if (className.indexOf('.') == -1) {
+ // According to the <activity> manifest element documentation, this is not
+ // valid ( http://developer.android.com/guide/topics/manifest/activity-element.html )
+ // but it appears in manifest files and appears to be supported by the runtime
+ // so handle this in code as well:
+ sb.append(pkg);
+ sb.append('.');
+ } // else: the class name is already a fully qualified class name
+ sb.append(className);
+ return sb.toString();
+ }
+
+ // ---- Implements ClassScanner ----
+
+ @Override
+ public void checkClass(ClassContext context, ClassNode classNode) {
+ // Abstract classes do not need to be registered
+ if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {
+ return;
+ }
+ String curr = classNode.name;
+
+ int lastIndex = curr.lastIndexOf('$');
+ if (lastIndex != -1 && lastIndex < curr.length() - 1) {
+ if (Character.isDigit(curr.charAt(lastIndex+1))) {
+ // Anonymous inner class, doesn't need to be registered
+ return;
+ }
+ }
+
+ while (curr != null) {
+ for (String s : sClasses) {
+ if (curr.equals(s)) {
+ Collection<String> registered = mManifestRegistrations != null ?
+ mManifestRegistrations.get(curr) : null;
+ if (registered == null || !registered.contains(classNode.name)) {
+ report(context, classNode, curr);
+ }
+
+ }
+ }
+
+ curr = context.getDriver().getSuperClass(curr);
+ }
+ }
+
+ private void report(ClassContext context, ClassNode classNode, String curr) {
+ String tag = classToTag(curr);
+ String className = ClassContext.createSignature(classNode.name, null, null);
+
+ String wrongClass = null; // The framework class this class actually extends
+ if (mManifestRegistrations != null) {
+ Collection<Entry<String,String>> entries =
+ mManifestRegistrations.entries();
+ for (Entry<String,String> entry : entries) {
+ if (entry.getValue().equals(classNode.name)) {
+ wrongClass = entry.getKey();
+ break;
+ }
+ }
+ }
+ if (wrongClass != null) {
+ Location location = context.getLocationForLine(-1, className, null);
+ context.report(
+ ISSUE,
+ location,
+ String.format(
+ "%1$s is a <%2$s> but is registered in the manifest as a <%3$s>",
+ className, tag, classToTag(wrongClass)),
+ null);
+ } else if (!tag.equals(TAG_RECEIVER)) { // don't need to be registered
+ Location location = context.getLocationForLine(-1, className, null);
+ context.report(
+ ISSUE,
+ location,
+ String.format(
+ "The <%1$s> %2$s is not registered in the manifest",
+ tag, className),
+ null);
+ }
+ }
+
+ /** The manifest tags we care about */
+ private static final String[] sTags = new String[] {
+ TAG_ACTIVITY,
+ TAG_SERVICE,
+ TAG_RECEIVER,
+ TAG_PROVIDER
+ // Keep synchronized with {@link #sClasses}
+ };
+
+ /** The corresponding framework classes that the tags in {@link #sTags} should extend */
+ private static final String[] sClasses = new String[] {
+ ANDROID_APP_ACTIVITY,
+ ANDROID_APP_SERVICE,
+ ANDROID_CONTENT_BROADCAST_RECEIVER,
+ ANDROID_CONTENT_CONTENT_PROVIDER
+ // Keep synchronized with {@link #sTags}
+ };
+
+ /** Looks up the corresponding framework class a given manifest tag's class should extend */
+ private static final String tagToClass(String tag) {
+ for (int i = 0, n = sTags.length; i < n; i++) {
+ if (sTags[i].equals(tag)) {
+ return sClasses[i];
+ }
+ }
+
+ return null;
+ }
+
+ /** Looks up the manifest tag a given framework class should be registered with */
+ private static final String classToTag(String className) {
+ for (int i = 0, n = sClasses.length; i < n; i++) {
+ if (sClasses[i].equals(className)) {
+ return sTags[i];
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/RegistrationDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/RegistrationDetectorTest.java
new file mode 100644
index 000000000..cb79bf2d8
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/RegistrationDetectorTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 RegistrationDetectorTest extends AbstractCheckTest {
+ @Override
+ protected Detector getDetector() {
+ return new RegistrationDetector();
+ }
+
+ public void testRegistered() throws Exception {
+ assertEquals(
+ "OnClickActivity.java: Warning: The <activity> test.pkg.OnClickActivity is not registered in the manifest\n" +
+ "TestProvider.java: Warning: The <provider> test.pkg.TestProvider is not registered in the manifest\n" +
+ "TestProvider2.java: Warning: The <provider> test.pkg.TestProvider2 is not registered in the manifest\n" +
+ "TestService.java: Warning: The <service> test.pkg.TestService is not registered in the manifest",
+
+ lintProject(
+ "bytecode/.classpath=>.classpath",
+ "bytecode/OnClickActivity.java.txt=>src/test/pkg/OnClickActivity.java",
+ "bytecode/OnClickActivity.class.data=>bin/classes/test/pkg/OnClickActivity.class",
+ "bytecode/TestService.java.txt=>src/test/pkg/TestService.java",
+ "bytecode/TestService.class.data=>bin/classes/test/pkg/TestService.class",
+ "bytecode/TestProvider.java.txt=>src/test/pkg/TestProvider.java",
+ "bytecode/TestProvider.class.data=>bin/classes/test/pkg/TestProvider.class",
+ "bytecode/TestProvider2.java.txt=>src/test/pkg/TestProvider2.java",
+ "bytecode/TestProvider2.class.data=>bin/classes/test/pkg/TestProvider2.class",
+ "bytecode/TestReceiver.java.txt=>src/test/pkg/TestReceiver.java",
+ "bytecode/TestReceiver.class.data=>bin/classes/test/pkg/TestReceiver.class"
+ ));
+ }
+
+ public void testWrongRegistrations() throws Exception {
+ assertEquals(
+ "OnClickActivity.java: Warning: test.pkg.OnClickActivity is a <activity> but is registered in the manifest as a <receiver>\n" +
+ "TestProvider.java: Warning: test.pkg.TestProvider is a <provider> but is registered in the manifest as a <activity>\n" +
+ "TestProvider2.java: Warning: test.pkg.TestProvider2 is a <provider> but is registered in the manifest as a <service>\n" +
+ "TestReceiver.java: Warning: test.pkg.TestReceiver is a <receiver> but is registered in the manifest as a <service>\n" +
+ "TestService.java: Warning: test.pkg.TestService is a <service> but is registered in the manifest as a <provider>",
+
+ lintProject(
+ "bytecode/.classpath=>.classpath",
+ "bytecode/AndroidManifestWrongRegs.xml=>AndroidManifest.xml",
+ "bytecode/OnClickActivity.java.txt=>src/test/pkg/OnClickActivity.java",
+ "bytecode/OnClickActivity.class.data=>bin/classes/test/pkg/OnClickActivity.class",
+ "bytecode/AbstractActivity.java.txt=>src/test/pkg/AbstractActivity.java",
+ "bytecode/AbstractActivity.class.data=>bin/classes/test/pkg/AbstractActivity.class",
+ "bytecode/TestService.java.txt=>src/test/pkg/TestService.java",
+ "bytecode/TestService.class.data=>bin/classes/test/pkg/TestService.class",
+ "bytecode/TestProvider.java.txt=>src/test/pkg/TestProvider.java",
+ "bytecode/TestProvider.class.data=>bin/classes/test/pkg/TestProvider.class",
+ "bytecode/TestProvider2.java.txt=>src/test/pkg/TestProvider2.java",
+ "bytecode/TestProvider2.class.data=>bin/classes/test/pkg/TestProvider2.class",
+ "bytecode/TestReceiver.java.txt=>src/test/pkg/TestReceiver.java",
+ "bytecode/TestReceiver.class.data=>bin/classes/test/pkg/TestReceiver.class",
+ "bytecode/TestReceiver$1.class.data=>bin/classes/test/pkg/TestReceiver$1.class"
+ ));
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/AbstractActivity.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/AbstractActivity.java.txt
new file mode 100644
index 000000000..a9e04005c
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/AbstractActivity.java.txt
@@ -0,0 +1,6 @@
+package test.pkg;
+
+import android.app.Activity;
+
+public abstract class AbstractActivity extends Activity {
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.class.data
new file mode 100644
index 000000000..85ebb7838
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.java.txt
new file mode 100644
index 000000000..a9e04005c
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AbstractActivity.java.txt
@@ -0,0 +1,6 @@
+package test.pkg;
+
+import android.app.Activity;
+
+public abstract class AbstractActivity extends Activity {
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AndroidManifestWrongRegs.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AndroidManifestWrongRegs.xml
new file mode 100644
index 000000000..efe721315
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/AndroidManifestWrongRegs.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="test.pkg"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="10" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <!-- These registrations are bogus (wrong type) -->
+ <activity android:name=".TestProvider" />
+ <service android:name="test.pkg.TestProvider2" />
+ <provider android:name=".TestService" />
+ <receiver android:name="OnClickActivity" />
+ <service android:name="TestReceiver" />
+
+ </application>
+
+</manifest>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.class.data
new file mode 100644
index 000000000..945742fee
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.java.txt
new file mode 100644
index 000000000..2bf1bb847
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider.java.txt
@@ -0,0 +1,40 @@
+package test.pkg;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestProvider extends ContentProvider {
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.class.data
new file mode 100644
index 000000000..0973dbea3
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.java.txt
new file mode 100644
index 000000000..881975dc3
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestProvider2.java.txt
@@ -0,0 +1,4 @@
+package test.pkg;
+
+public class TestProvider2 extends TestProvider {
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver$1.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver$1.class.data
new file mode 100644
index 000000000..7ede85a69
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver$1.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.class.data
new file mode 100644
index 000000000..6180e4070
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.java.txt
new file mode 100644
index 000000000..90893c88d
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestReceiver.java.txt
@@ -0,0 +1,21 @@
+package test.pkg;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class TestReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ }
+
+ // Anonymous classes should NOT be counted as a must-register
+ private BroadcastReceiver dummy() {
+ return new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ }
+ };
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.class.data
new file mode 100644
index 000000000..a98f7aa60
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.class.data
Binary files differ
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.java.txt
new file mode 100644
index 000000000..d3f128a63
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/TestService.java.txt
@@ -0,0 +1,14 @@
+package test.pkg;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class TestService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ClassContextTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ClassContextTest.java
new file mode 100644
index 000000000..528a53c39
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ClassContextTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.detector.api;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class ClassContextTest extends TestCase {
+ public void testCreateSignature() {
+ assertEquals("foo.bar.Foo.Bar",
+ ClassContext.createSignature("foo/bar/Foo$Bar", null, null));
+ assertEquals("void foo.bar.Foo.Bar#name(int)",
+ ClassContext.createSignature("foo/bar/Foo$Bar", "name", "(I)V"));
+ assertEquals("void foo.bar.Foo.Bar#name(Integer)",
+ ClassContext.createSignature("foo/bar/Foo$Bar", "name", "(Ljava/lang/Integer;)V"));
+ }
+
+ public void testGetInternalName() {
+ assertEquals("foo/bar/Foo$Bar",
+ ClassContext.getInternalName("foo.bar.Foo.Bar"));
+ }
+}