diff options
author | Tor Norbye <tnorbye@google.com> | 2012-02-21 09:00:44 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-02-21 09:00:44 -0800 |
commit | 556b907792f0658a6c3f676e23469b83175e3431 (patch) | |
tree | 498d4772977266614d802a46296301bc163cfb1f /lint | |
parent | f9a57e464104e29c045939d84e8d3fb5d9becf7d (diff) | |
parent | 247b1d7186a2f64a38417a3172fa07de35681a5f (diff) | |
download | sdk-556b907792f0658a6c3f676e23469b83175e3431.tar.gz sdk-556b907792f0658a6c3f676e23469b83175e3431.tar.bz2 sdk-556b907792f0658a6c3f676e23469b83175e3431.zip |
Merge "Lint rule checking that activities and services are registered"
Diffstat (limited to 'lint')
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 Binary files differnew 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 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 Binary files differnew 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 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 Binary files differnew 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 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 Binary files differnew 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 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 Binary files differnew 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 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 Binary files differnew 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 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")); + } +} |