diff options
author | Tor Norbye <tnorbye@google.com> | 2012-12-17 16:55:54 -0800 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2012-12-19 09:14:40 -0800 |
commit | e4ec7999afe36cf1e68dd102253cef2a89fcc5b2 (patch) | |
tree | c8c94ea7def36effdb6db188ed76e53d549ba875 /lint/cli | |
parent | b28737ae52aa0a186587be6b1fa5f35cdf384291 (diff) | |
download | sdk-e4ec7999afe36cf1e68dd102253cef2a89fcc5b2.zip sdk-e4ec7999afe36cf1e68dd102253cef2a89fcc5b2.tar.gz sdk-e4ec7999afe36cf1e68dd102253cef2a89fcc5b2.tar.bz2 |
Lint check for valid class references
Lint already checks that classes registered in the manifest (such as
activities and services) exist and are instantiatable.
This lint check expands this check to also make sure that custom views
and fragments referenced in layouts also exist, as well as class names
registered in analytics config files (requested in issue 41567).
It also fixes the typography detector to not flag IDs as needing
em dashes.
Change-Id: Idd42be60dae6c0747324d600d15b01d6d8a3240f
Diffstat (limited to 'lint/cli')
6 files changed, 229 insertions, 10 deletions
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/MissingClassDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/MissingClassDetectorTest.java index 4edf345..27875e8 100644 --- a/lint/cli/src/test/java/com/android/tools/lint/checks/MissingClassDetectorTest.java +++ b/lint/cli/src/test/java/com/android/tools/lint/checks/MissingClassDetectorTest.java @@ -16,17 +16,29 @@ package com.android.tools.lint.checks; +import static com.android.tools.lint.checks.MissingClassDetector.INNERCLASS; +import static com.android.tools.lint.checks.MissingClassDetector.INSTANTIATABLE; +import static com.android.tools.lint.checks.MissingClassDetector.MISSING; + +import com.android.annotations.NonNull; +import com.android.tools.lint.client.api.LintClient; import com.android.tools.lint.detector.api.Detector; +import com.android.tools.lint.detector.api.Issue; +import com.android.tools.lint.detector.api.Project; import com.android.tools.lint.detector.api.Scope; +import com.google.common.collect.Sets; import java.io.File; import java.util.Arrays; import java.util.EnumSet; +import java.util.HashSet; import java.util.List; +import java.util.Set; @SuppressWarnings("javadoc") public class MissingClassDetectorTest extends AbstractCheckTest { private EnumSet<Scope> mScopes; + private Set<Issue> mEnabled = new HashSet<Issue>(); @Override protected Detector getDetector() { @@ -38,8 +50,19 @@ public class MissingClassDetectorTest extends AbstractCheckTest { return mScopes; } + @Override + protected TestConfiguration getConfiguration(LintClient client, Project project) { + return new TestConfiguration(client, project, null) { + @Override + public boolean isEnabled(@NonNull Issue issue) { + return super.isEnabled(issue) && mEnabled.contains(issue); + } + }; + } + public void test() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING); assertEquals( "AndroidManifest.xml:13: Error: Class referenced in the manifest, test.pkg.TestProvider, was not found in the project or the libraries [MissingRegistered]\n" + " <activity android:name=\".TestProvider\" />\n" + @@ -67,6 +90,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testIncrementalInManifest() throws Exception { mScopes = Scope.MANIFEST_SCOPE; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "No warnings.", @@ -78,6 +102,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testNoWarningBeforeBuild() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "No warnings.", @@ -89,11 +114,12 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testOkClasses() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "No warnings.", lintProject( - "bytecode/AndroidManifestWrongRegs.xml=>AndroidManifest.xml", + "bytecode/AndroidManifestRegs.xml=>AndroidManifest.xml", "bytecode/.classpath=>.classpath", "bytecode/OnClickActivity.java.txt=>src/test/pkg/OnClickActivity.java", "bytecode/OnClickActivity.class.data=>bin/classes/test/pkg/OnClickActivity.class", @@ -110,11 +136,12 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testOkLibraries() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "No warnings.", lintProject( - "bytecode/AndroidManifestWrongRegs.xml=>AndroidManifest.xml", + "bytecode/AndroidManifestRegs.xml=>AndroidManifest.xml", "bytecode/.classpath=>.classpath", "bytecode/classes.jar=>libs/classes.jar" )); @@ -122,10 +149,13 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testLibraryProjects() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); File master = getProjectDir("MasterProject", // Master project - "bytecode/AndroidManifestWrongRegs.xml=>AndroidManifest.xml", + "bytecode/AndroidManifestRegs.xml=>AndroidManifest.xml", "multiproject/main.properties=>project.properties", + "bytecode/TestService.java.txt=>src/test/pkg/TestService.java", + "bytecode/TestService.class.data=>bin/classes/test/pkg/TestService.class", "bytecode/.classpath=>.classpath" ); File library = getProjectDir("LibraryProject", @@ -134,25 +164,24 @@ public class MissingClassDetectorTest extends AbstractCheckTest { "multiproject/library.properties=>project.properties", "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" // Missing TestReceiver: Test should complain about just that class ); - assertEquals( - "MasterProject/AndroidManifest.xml:17: Error: Class referenced in the manifest, test.pkg.TestReceiver, was not found in the project or the libraries [MissingRegistered]\n" + - " <service android:name=\"TestReceiver\" />\n" + - " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - "1 errors, 0 warnings\n", + assertEquals("" + + "MasterProject/AndroidManifest.xml:32: Error: Class referenced in the manifest, test.pkg.TestReceiver, was not found in the project or the libraries [MissingRegistered]\n" + + " <receiver android:name=\"TestReceiver\" />\n" + + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + "1 errors, 0 warnings\n", checkLint(Arrays.asList(master, library))); } public void testInnerClassStatic() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "src/test/pkg/Foo.java:8: Warning: This inner class should be static (test.pkg.Foo.Baz) [Instantiatable]\n" + " public class Baz extends Activity {\n" + @@ -171,6 +200,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testInnerClassPublic() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "src/test/pkg/Foo/Bar.java:6: Warning: The default constructor must be public [Instantiatable]\n" + " private Bar() {\n" + @@ -187,6 +217,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testInnerClass() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "AndroidManifest.xml:14: Error: Class referenced in the manifest, test.pkg.Foo.Bar, was not found in the project or the libraries [MissingRegistered]\n" + " <activity\n" + @@ -206,6 +237,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testInnerClass2() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "AndroidManifest.xml:14: Error: Class referenced in the manifest, test.pkg.Foo.Bar, was not found in the project or the libraries [MissingRegistered]\n" + " <activity\n" + @@ -222,6 +254,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testWrongSeparator1() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "AndroidManifest.xml:14: Error: Class referenced in the manifest, test.pkg.Foo.Bar, was not found in the project or the libraries [MissingRegistered]\n" + " <activity\n" + @@ -238,6 +271,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testWrongSeparator2() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "AndroidManifest.xml:14: Error: Class referenced in the manifest, test.pkg.Foo.Bar, was not found in the project or the libraries [MissingRegistered]\n" + " <activity\n" + @@ -257,6 +291,7 @@ public class MissingClassDetectorTest extends AbstractCheckTest { public void testNoClassesWithLibraries() throws Exception { mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); assertEquals( "No warnings.", @@ -267,4 +302,75 @@ public class MissingClassDetectorTest extends AbstractCheckTest { )); } + public void testFragment() throws Exception { + mScopes = null; + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); + assertEquals("" + + "res/layout/fragment2.xml:7: Error: Class referenced in the layout file, my.app.Fragment, was not found in the project or the libraries [MissingRegistered]\n" + + " <fragment\n" + + " ^\n" + + "res/layout/fragment2.xml:12: Error: Class referenced in the layout file, my.app.MyView, was not found in the project or the libraries [MissingRegistered]\n" + + " <view\n" + + " ^\n" + + "res/layout/fragment2.xml:17: Error: Class referenced in the layout file, my.app.Fragment2, was not found in the project or the libraries [MissingRegistered]\n" + + " <fragment\n" + + " ^\n" + + "3 errors, 0 warnings\n", + + lintProject( + "bytecode/AndroidManifestRegs.xml=>AndroidManifest.xml", + "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", + "registration/Foo.java.txt=>src/test/pkg/Foo.java", + "registration/Foo.class.data=>bin/classes/test/pkg/Foo.class", + "registration/Bar.java.txt=>src/test/pkg/Foo/Bar.java", + "registration/Bar.class.data=>bin/classes/test/pkg/Foo/Bar.class", + + "res/layout/fragment2.xml" + )); + } + + public void testAnalytics() throws Exception { + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); + assertEquals("" + + "res/values/analytics.xml:13: Error: Class referenced in the analytics file, com.example.app.BaseActivity, was not found in the project or the libraries [MissingRegistered]\n" + + " <string name=\"com.example.app.BaseActivity\">Home</string>\n" + + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + "res/values/analytics.xml:14: Error: Class referenced in the analytics file, com.example.app.PrefsActivity, was not found in the project or the libraries [MissingRegistered]\n" + + " <string name=\"com.example.app.PrefsActivity\">Preferences</string>\n" + + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + "2 errors, 0 warnings\n", + + lintProject( + "bytecode/.classpath=>.classpath", + "res/values/analytics.xml", + "bytecode/OnClickActivity.java.txt=>src/test/pkg/OnClickActivity.java", + "bytecode/OnClickActivity.class.data=>bin/classes/test/pkg/OnClickActivity.class" + )); + } + + public void testCustomView() throws Exception { + mEnabled = Sets.newHashSet(MISSING, INSTANTIATABLE, INNERCLASS); + assertEquals("" + + "res/layout/customview.xml:21: Error: Class referenced in the layout file, foo.bar.Baz, was not found in the project or the libraries [MissingRegistered]\n" + + " <foo.bar.Baz\n" + + " ^\n" + + "1 errors, 0 warnings\n", + + lintProject( + "bytecode/.classpath=>.classpath", + "res/layout/customview.xml", + "bytecode/OnClickActivity.java.txt=>src/test/pkg/OnClickActivity.java", + "bytecode/OnClickActivity.class.data=>bin/classes/test/pkg/OnClickActivity.class" + )); + } } diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/TypographyDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/TypographyDetectorTest.java index 16d0107..5173011 100644 --- a/lint/cli/src/test/java/com/android/tools/lint/checks/TypographyDetectorTest.java +++ b/lint/cli/src/test/java/com/android/tools/lint/checks/TypographyDetectorTest.java @@ -86,6 +86,13 @@ public class TypographyDetectorTest extends AbstractCheckTest { lintProject("res/values/typography.xml")); } + public void testAnalytics() throws Exception { + assertEquals("" + + "No warnings.", + + lintProject("res/values/analytics.xml")); + } + public void testSingleQuotesRange() { assertTrue(SINGLE_QUOTE.matcher("Foo: 'bar'").matches()); assertTrue(SINGLE_QUOTE.matcher("'Foo': bar").matches()); diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AndroidManifestRegs.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AndroidManifestRegs.xml new file mode 100644 index 0000000..e52f73c --- /dev/null +++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/bytecode/AndroidManifestRegs.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<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" > + <provider android:name=".TestProvider" /> + <provider android:name="test.pkg.TestProvider2" /> + <service android:name=".TestService" /> + <activity android:name="OnClickActivity" /> + <receiver android:name="TestReceiver" /> + + </application> + +</manifest> diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/layout/fragment2.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/layout/fragment2.xml new file mode 100644 index 0000000..3a672d1 --- /dev/null +++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/layout/fragment2.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <fragment + class="my.app.Fragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <view + class="my.app.MyView" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <fragment + android:name="my.app.Fragment2" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <view + android:name="test.pkg.TestService" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <view + class="test.pkg.TestService" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <fragment + android:name="test.pkg.TestService" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <fragment + class="test.pkg.TestService" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <fragment + class="test.pkg.Foo$Bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <fragment + class="test.pkg.Nonexistent" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:ignore="MissingRegistered" /> + +</LinearLayout> diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/values/analytics.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/values/analytics.xml new file mode 100644 index 0000000..8ea40a8 --- /dev/null +++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/values/analytics.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8" ?> +<resources> + <!--Replace placeholder ID with your tracking ID--> + <string name="ga_trackingId">UA-12345678-1</string> + + <!--Enable Activity tracking--> + <bool name="ga_autoActivityTracking">true</bool> + + <!--Enable automatic exception tracking--> + <bool name="ga_reportUncaughtExceptions">true</bool> + + <!-- The screen names that will appear in your reporting --> + <string name="com.example.app.BaseActivity">Home</string> + <string name="com.example.app.PrefsActivity">Preferences</string> + <string name="test.pkg.OnClickActivity">Clicks</string> +</resources> diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/values/typography.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/values/typography.xml index 1dd4845..02ffb1c 100644 --- a/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/values/typography.xml +++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/res/values/typography.xml @@ -25,5 +25,6 @@ <item>Age 5 1/2</item> </string-array> <string name="ndash">X Y Z: 10 10 -1</string> + <string name="ga_trackingId">UA-0000-0</string> </resources> |