aboutsummaryrefslogtreecommitdiffstats
path: root/lint
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2013-01-03 16:53:56 -0800
committerTor Norbye <tnorbye@google.com>2013-01-04 10:22:48 -0800
commit6050e51438c29d5f5f6413dd842fa2d019d954db (patch)
treea5df515ba1831f3466e16c7e661914f6f4169b2d /lint
parentcf7f3984edfb23ce6bb85ebd101c165c7c0cafa6 (diff)
downloadsdk-6050e51438c29d5f5f6413dd842fa2d019d954db.zip
sdk-6050e51438c29d5f5f6413dd842fa2d019d954db.tar.gz
sdk-6050e51438c29d5f5f6413dd842fa2d019d954db.tar.bz2
Make resource folders customizeable
Until now, lint has hardcoded where the project resources are to be found: in $project/res. With the new build system this will no longer necessarily be the case; there can be multiple resource folders, and the locations might not be just res/. Therefore, this CL generalizes lint's handling of resource folders: it is now provided by the LintClient, and the command line lint tool uses this to offer a new --resources flag which can be used to set the resource directory/directories for a project. Change-Id: I3717c6474141776ee5541d476f9bad5bb8e1a9c7
Diffstat (limited to 'lint')
-rw-r--r--lint/cli/src/main/java/com/android/tools/lint/Main.java39
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/MainTest.java78
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java14
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java14
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java14
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java4
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java4
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java14
8 files changed, 149 insertions, 32 deletions
diff --git a/lint/cli/src/main/java/com/android/tools/lint/Main.java b/lint/cli/src/main/java/com/android/tools/lint/Main.java
index 673e4d8..c53469e 100644
--- a/lint/cli/src/main/java/com/android/tools/lint/Main.java
+++ b/lint/cli/src/main/java/com/android/tools/lint/Main.java
@@ -91,6 +91,7 @@ public class Main extends LintClient {
private static final String ARG_EXITCODE = "--exitcode"; //$NON-NLS-1$
private static final String ARG_CLASSES = "--classpath"; //$NON-NLS-1$
private static final String ARG_SOURCES = "--sources"; //$NON-NLS-1$
+ private static final String ARG_RESOURCES = "--resources"; //$NON-NLS-1$
private static final String ARG_LIBRARIES = "--libraries"; //$NON-NLS-1$
private static final String ARG_NOWARN2 = "--nowarn"; //$NON-NLS-1$
@@ -128,6 +129,7 @@ public class Main extends LintClient {
protected List<File> mSources;
protected List<File> mClasses;
protected List<File> mLibraries;
+ protected List<File> mResources;
protected Configuration mDefaultConfiguration;
protected IssueRegistry mRegistry;
@@ -500,6 +502,23 @@ public class Main extends LintClient {
}
mSources.add(input);
}
+ } else if (arg.equals(ARG_RESOURCES)) {
+ if (index == args.length - 1) {
+ System.err.println("Missing resource folder name");
+ System.exit(ERRNO_INVALIDARGS);
+ }
+ String paths = args[++index];
+ for (String path : LintUtils.splitPath(paths)) {
+ File input = getInArgumentPath(path);
+ if (!input.exists()) {
+ System.err.println("Resource folder " + input + " does not exist.");
+ System.exit(ERRNO_INVALIDARGS);
+ }
+ if (mResources == null) {
+ mResources = new ArrayList<File>();
+ }
+ mResources.add(input);
+ }
} else if (arg.equals(ARG_LIBRARIES)) {
if (index == args.length - 1) {
System.err.println("Missing library folder name");
@@ -537,9 +556,11 @@ public class Main extends LintClient {
System.err.println("No files to analyze.");
System.exit(ERRNO_INVALIDARGS);
} else if (files.size() > 1
- && (mClasses != null || mSources != null || mLibraries != null)) {
- System.err.println("The " + ARG_SOURCES + ", " + ARG_CLASSES + " and "
- + ARG_LIBRARIES + " arguments can only be used with a single project");
+ && (mClasses != null || mSources != null || mLibraries != null
+ || mResources != null)) {
+ System.err.println(String.format(
+ "The %1$s, %2$s, %3$s and %4$s arguments can only be used with a single project",
+ ARG_SOURCES, ARG_CLASSES, ARG_LIBRARIES, ARG_RESOURCES));
System.exit(ERRNO_INVALIDARGS);
}
@@ -932,6 +953,8 @@ public class Main extends LintClient {
ARG_XML + " <filename>", "Create an XML report instead.",
"", "\nProject Options:",
+ ARG_RESOURCES + " <dir>", "Add the given folder (or path) as a resource directory " +
+ "for the project. Only valid when running lint on a single project.",
ARG_SOURCES + " <dir>", "Add the given folder (or path) as a source directory for " +
"the project. Only valid when running lint on a single project.",
ARG_CLASSES + " <dir>", "Add the given folder (or jar file, or path) as a class " +
@@ -1210,6 +1233,16 @@ public class Main extends LintClient {
return info;
}
+ @NonNull
+ @Override
+ public List<File> getResourceFolders(@NonNull Project project) {
+ if (mResources == null) {
+ return super.getResourceFolders(project);
+ }
+
+ return mResources;
+ }
+
/**
* Consult the lint.xml file, but override with the --enable and --disable
* flags supplied on the command line
diff --git a/lint/cli/src/test/java/com/android/tools/lint/MainTest.java b/lint/cli/src/test/java/com/android/tools/lint/MainTest.java
index 5a48a47..2ff470e 100644
--- a/lint/cli/src/test/java/com/android/tools/lint/MainTest.java
+++ b/lint/cli/src/test/java/com/android/tools/lint/MainTest.java
@@ -180,7 +180,7 @@ public class MainTest extends AbstractCheckTest {
File project = getProjectDir(null, "bytecode/classes.jar=>libs/classes.jar");
checkDriver(
"",
- "The --sources, --classpath and --libraries arguments can only be used with a single project\n",
+ "The --sources, --classpath, --libraries and --resources arguments can only be used with a single project\n",
// Args
new String[] {
@@ -194,6 +194,82 @@ public class MainTest extends AbstractCheckTest {
});
}
+ public void testCustomResourceDirs() throws Exception {
+ File project = getProjectDir(null,
+ "res/layout/accessibility.xml=>myres1/layout/accessibility1.xml",
+ "res/layout/accessibility.xml=>myres2/layout/accessibility1.xml"
+ );
+
+ checkDriver(
+ "\n"
+ + "Scanning MainTest_testCustomResourceDirs: ..\n"
+ + "myres1/layout/accessibility1.xml:4: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageView android:id=\"@+id/android_logo\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "myres2/layout/accessibility1.xml:4: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageView android:id=\"@+id/android_logo\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "myres1/layout/accessibility1.xml:5: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageButton android:importantForAccessibility=\"yes\" android:id=\"@+id/android_logo2\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "myres2/layout/accessibility1.xml:5: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageButton android:importantForAccessibility=\"yes\" android:id=\"@+id/android_logo2\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "0 errors, 4 warnings\n", // Expected output
+ "",
+
+ // Args
+ new String[] {
+ "--check",
+ "ContentDescription",
+ "--disable",
+ "LintError",
+ "--resources",
+ new File(project, "myres1").getPath(),
+ "--resources",
+ new File(project, "myres2").getPath(),
+ project.getPath(),
+ });
+ }
+
+ public void testPathList() throws Exception {
+ File project = getProjectDir(null,
+ "res/layout/accessibility.xml=>myres1/layout/accessibility1.xml",
+ "res/layout/accessibility.xml=>myres2/layout/accessibility1.xml"
+ );
+
+ checkDriver(
+ "\n"
+ + "Scanning MainTest_testPathList: ..\n"
+ + "myres1/layout/accessibility1.xml:4: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageView android:id=\"@+id/android_logo\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "myres2/layout/accessibility1.xml:4: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageView android:id=\"@+id/android_logo\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "myres1/layout/accessibility1.xml:5: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageButton android:importantForAccessibility=\"yes\" android:id=\"@+id/android_logo2\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "myres2/layout/accessibility1.xml:5: Warning: [Accessibility] Missing contentDescription attribute on image [ContentDescription]\n"
+ + " <ImageButton android:importantForAccessibility=\"yes\" android:id=\"@+id/android_logo2\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:src=\"@drawable/android_button\" android:focusable=\"false\" android:clickable=\"false\" android:layout_weight=\"1.0\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "0 errors, 4 warnings\n", // Expected output
+ "",
+
+ // Args
+ new String[] {
+ "--check",
+ "ContentDescription",
+ "--disable",
+ "LintError",
+ "--resources",
+ // Combine two paths with a single separator here
+ new File(project, "myres1").getPath()
+ + ':' + new File(project, "myres2").getPath(),
+ project.getPath(),
+ });
+ }
+
public void testClassPath() throws Exception {
File project = getProjectDir(null,
"apicheck/minsdk1.xml=>AndroidManifest.xml",
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java
index 9afef42..6c4b202 100644
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java
+++ b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java
@@ -52,6 +52,7 @@ import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -236,20 +237,19 @@ public abstract class LintClient {
}
/**
- * Returns the resource folder.
+ * Returns the resource folders.
*
* @param project the project to look up the resource folder for
- * @return a file pointing to the resource folder, or null if the project
- * does not contain any resources
+ * @return a list of files pointing to the resource folders, possibly empty
*/
- @Nullable
- public File getResourceFolder(@NonNull Project project) {
+ @NonNull
+ public List<File> getResourceFolders(@NonNull Project project) {
File res = new File(project.getDir(), RES_FOLDER);
if (res.exists()) {
- return res;
+ return Collections.singletonList(res);
}
- return null;
+ return Collections.emptyList();
}
/**
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java
index dd268a5..28168a6 100644
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java
+++ b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java
@@ -841,9 +841,11 @@ public class LintDriver {
if (files != null) {
checkIndividualResources(project, main, xmlDetectors, files);
} else {
- File res = project.getResourceFolder();
- if (res != null && !xmlDetectors.isEmpty()) {
- checkResFolder(project, main, res, xmlDetectors);
+ List<File> resourceFolders = project.getResourceFolders();
+ if (!resourceFolders.isEmpty() && !xmlDetectors.isEmpty()) {
+ for (File res : resourceFolders) {
+ checkResFolder(project, main, res, xmlDetectors);
+ }
}
}
}
@@ -1686,9 +1688,9 @@ public class LintDriver {
}
@Override
- @Nullable
- public File getResourceFolder(@NonNull Project project) {
- return mDelegate.getResourceFolder(project);
+ @NonNull
+ public List<File> getResourceFolders(@NonNull Project project) {
+ return mDelegate.getResourceFolders(project);
}
@Override
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java
index df27b2f..67c3b16 100644
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java
+++ b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java
@@ -353,20 +353,20 @@ public class Project {
* @return a file pointing to the resource folder, or null if the project
* does not contain any resources
*/
- @Nullable
- public File getResourceFolder() {
- File folder = mClient.getResourceFolder(this);
+ @NonNull
+ public List<File> getResourceFolders() {
+ List<File> folders = mClient.getResourceFolders(this);
- if (folder != null && isAospFrameworksProject(mDir)) {
+ if (folders.size() == 1 && isAospFrameworksProject(mDir)) {
// No manifest file for this project: just init the manifest values here
mMinSdk = mTargetSdk = SdkConstants.HIGHEST_KNOWN_API;
- folder = new File(folder, RES_FOLDER);
+ File folder = new File(folders.get(0), RES_FOLDER);
if (!folder.exists()) {
- folder = null;
+ folders = Collections.emptyList();
}
}
- return folder;
+ return folders;
}
/**
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java
index 4d8b3a4..7f26c96 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java
@@ -386,8 +386,8 @@ public class IconDetector extends ResourceXmlDetector implements Detector.JavaSc
}
private void checkResourceFolder(Context context, @NonNull Project project) {
- File res = project.getResourceFolder();
- if (res != null) {
+ List<File> resourceFolders = project.getResourceFolders();
+ for (File res : resourceFolders) {
File[] folders = res.listFiles();
if (folders != null) {
boolean checkFolders = context.isEnabled(ICON_DENSITIES)
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java
index b1e848b..f957331 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java
@@ -105,7 +105,9 @@ public class PrivateKeyDetector extends Detector {
Project project = context.getProject();
File projectFolder = project.getDir();
- checkFolder(context, new File(projectFolder, "res"));
+ for (File res : project.getResourceFolders()) {
+ checkFolder(context, res);
+ }
checkFolder(context, new File(projectFolder, "assets"));
for (File srcFolder : project.getJavaSourceFolders()) {
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
index 436f420..2a2d77c 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
@@ -54,6 +54,7 @@ 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.Lists;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
@@ -260,16 +261,19 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec
if (type != null && LintUtils.isFileBasedResourceType(type)) {
String name = resource.substring(secondDot + 1);
- File[] folders = null;
- File res = context.getProject().getResourceFolder();
- if (res != null) {
- folders = res.listFiles();
+ List<File> folders = Lists.newArrayList();
+ List<File> resourceFolders = context.getProject().getResourceFolders();
+ for (File res : resourceFolders) {
+ File[] f = res.listFiles();
+ if (f != null) {
+ folders.addAll(Arrays.asList(f));
+ }
}
if (folders != null) {
// Process folders in alphabetical order such that we process
// based folders first: we want the locations in base folder
// order
- Arrays.sort(folders, new Comparator<File>() {
+ Collections.sort(folders, new Comparator<File>() {
@Override
public int compare(File file1, File file2) {
return file1.getName().compareTo(file2.getName());