diff options
author | Tor Norbye <tnorbye@google.com> | 2012-02-10 22:18:13 -0800 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2012-02-13 10:43:47 -0800 |
commit | 3e10306ab1812b2c141e75fb36e2f5c92eeefd28 (patch) | |
tree | a248ca617a3b0563a0c58bc8d0b09dfa4dae6166 /lint | |
parent | 71008df5a5b37666ce3142c2df69fa93391260ac (diff) | |
download | sdk-3e10306ab1812b2c141e75fb36e2f5c92eeefd28.zip sdk-3e10306ab1812b2c141e75fb36e2f5c92eeefd28.tar.gz sdk-3e10306ab1812b2c141e75fb36e2f5c92eeefd28.tar.bz2 |
Make lint process Java jar dependencies
This changeset makes lint properly handle the jar dependency scope for
issues. It also tweaks the API in a few minor ways.
Change-Id: Ibd7b943c9d3ce361e091af8f1e990709bb94d183
Diffstat (limited to 'lint')
13 files changed, 218 insertions, 22 deletions
diff --git a/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java b/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java index 9ee5ee8..e777e99 100644 --- a/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java +++ b/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java @@ -16,6 +16,7 @@ package com.android.tools.lint; +import com.android.annotations.Nullable; import com.android.tools.lint.client.api.IDomParser; import com.android.tools.lint.client.api.IssueRegistry; import com.android.tools.lint.detector.api.Location; @@ -161,6 +162,7 @@ public class LintCliXmlParser extends PositionXmlParser implements IDomParser { private class LocationHandle implements Handle { private File mFile; private Node mNode; + private Object mClientData; public LocationHandle(File file, Node node) { mFile = file; @@ -176,5 +178,16 @@ public class LintCliXmlParser extends PositionXmlParser implements IDomParser { return null; } + + @Override + public void setClientData(@Nullable Object clientData) { + mClientData = clientData; + } + + @Override + @Nullable + public Object getClientData() { + return mClientData; + } } } diff --git a/lint/cli/src/com/android/tools/lint/LombokParser.java b/lint/cli/src/com/android/tools/lint/LombokParser.java index e1a3c3a..15b1073 100644 --- a/lint/cli/src/com/android/tools/lint/LombokParser.java +++ b/lint/cli/src/com/android/tools/lint/LombokParser.java @@ -16,6 +16,7 @@ package com.android.tools.lint; +import com.android.annotations.Nullable; import com.android.tools.lint.client.api.IJavaParser; import com.android.tools.lint.detector.api.JavaContext; import com.android.tools.lint.detector.api.Location; @@ -113,6 +114,7 @@ public class LombokParser implements IJavaParser { private class LocationHandle implements Handle { private File mFile; private Node mNode; + private Object mClientData; public LocationHandle(File file, Node node) { mFile = file; @@ -124,5 +126,17 @@ public class LombokParser implements IJavaParser { Position pos = mNode.getPosition(); return Location.create(mFile, null /*contents*/, pos.getStart(), pos.getEnd()); } + + + @Override + public void setClientData(@Nullable Object clientData) { + mClientData = clientData; + } + + @Override + @Nullable + public Object getClientData() { + return mClientData; + } } } diff --git a/lint/cli/src/com/android/tools/lint/Main.java b/lint/cli/src/com/android/tools/lint/Main.java index d319648..3c94f93 100644 --- a/lint/cli/src/com/android/tools/lint/Main.java +++ b/lint/cli/src/com/android/tools/lint/Main.java @@ -797,7 +797,7 @@ public class Main extends LintClient { } @Override - public void log(Throwable exception, String format, Object... args) { + public void log(Severity severity, Throwable exception, String format, Object... args) { System.out.flush(); if (!mQuiet) { // Place the error message on a line of its own since we're printing '.' etc diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java index fb62538..48e86b5 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java @@ -23,6 +23,7 @@ import com.android.tools.lint.detector.api.Detector; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.Location; import com.android.tools.lint.detector.api.Project; +import com.android.tools.lint.detector.api.Severity; import com.google.common.annotations.Beta; import org.w3c.dom.Document; @@ -92,14 +93,31 @@ public abstract class LintClient { @Nullable Object data); /** - * Send an exception to the log + * Send an exception or error message (with warning severity) to the log * * @param exception the exception, possibly null * @param format the error message using {@link String#format} syntax, possibly null * (though in that case the exception should not be null) * @param args any arguments for the format string */ + public void log( + @Nullable Throwable exception, + @Nullable String format, + @Nullable Object... args) { + log(Severity.WARNING, exception, format, args); + } + + /** + * Send an exception or error message to the log + * + * @param severity the severity of the warning + * @param exception the exception, possibly null + * @param format the error message using {@link String#format} syntax, possibly null + * (though in that case the exception should not be null) + * @param args any arguments for the format string + */ public abstract void log( + @NonNull Severity severity, @Nullable Throwable exception, @Nullable String format, @Nullable Object... args); @@ -159,6 +177,7 @@ public abstract class LintClient { /** * Returns the list of output folders for class files + * * @param project the project to look up class file locations for * @return a list of output folders to search for .class files */ @@ -168,6 +187,17 @@ public abstract class LintClient { } /** + * Returns the list of Java libraries + * + * @param project the project to look up jar dependencies for + * @return a list of jar dependencies containing .class files + */ + @NonNull + public List<File> getJavaLibraries(@NonNull Project project) { + return getEclipseClasspath(project, "lib"); //$NON-NLS-1$ + } + + /** * Returns the {@link SdkInfo} to use for the given project. * * @param project the project to look up an {@link SdkInfo} for diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java index c02d735..b30d71a 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java @@ -731,11 +731,23 @@ public class LintDriver { return; } + if (mScope.contains(Scope.JAVA_LIBRARIES)) { + List<Detector> detectors = mScopeDetectors.get(Scope.JAVA_LIBRARIES); + if (detectors != null && detectors.size() > 0) { + List<File> libraries = project.getJavaLibraries(); + checkClasses(project, main, libraries, detectors, true /* isLibrary */); + } + } + + if (mCanceled) { + return; + } + if (mScope.contains(Scope.CLASS_FILE)) { List<Detector> detectors = mScopeDetectors.get(Scope.CLASS_FILE); if (detectors != null && detectors.size() > 0) { - List<File> binFolders = project.getJavaClassFolders(); - checkClasses(project, main, binFolders, detectors); + List<File> classFolders = project.getJavaClassFolders(); + checkClasses(project, main, classFolders, detectors, false /* isLibrary */); } } @@ -789,14 +801,15 @@ public class LintDriver { private void checkClasses( @NonNull Project project, @Nullable Project main, - @NonNull List<File> binFolders, - @NonNull List<Detector> checks) { - if (binFolders.size() == 0) { + @NonNull List<File> classFolders, + @NonNull List<Detector> checks, + boolean isLibrary) { + if (classFolders.size() == 0) { //mClient.log(null, "Warning: Class-file checks are enabled, but no " + // "output folders found. Does the project need to be built first?"); } - for (File classPathEntry : binFolders) { + for (File classPathEntry : classFolders) { if (classPathEntry.getName().endsWith(DOT_JAR)) { File jarFile = classPathEntry; try { @@ -810,7 +823,7 @@ public class LintDriver { try { File file = new File(entry.getName()); checkClassFile(b, project, main, file, jarFile, jarFile, - checks); + checks, isLibrary); } catch (Exception e) { mClient.log(e, null); continue; @@ -839,7 +852,7 @@ public class LintDriver { byte[] bytes = Files.toByteArray(file); if (bytes != null) { checkClassFile(bytes, project, main, file, null /*jarFile*/, binDir, - checks); + checks, isLibrary); } } catch (IOException e) { mClient.log(e, null); @@ -860,7 +873,8 @@ public class LintDriver { @NonNull File file, @NonNull File jarFile, @NonNull File binDir, - @NonNull List<Detector> checks) { + @NonNull List<Detector> checks, + boolean fromLibrary) { ClassReader reader = new ClassReader(bytes); ClassNode classNode = new ClassNode(); reader.accept(classNode, 0 /*flags*/); @@ -871,7 +885,7 @@ public class LintDriver { } ClassContext context = new ClassContext(this, project, main, file, jarFile, - binDir, bytes, classNode); + binDir, bytes, classNode, fromLibrary); for (Detector detector : checks) { if (detector.appliesTo(context, file)) { fireEvent(EventType.SCANNING_FILE, context); @@ -1161,8 +1175,8 @@ public class LintDriver { @Override - public void log(@Nullable Throwable exception, @Nullable String format, - @Nullable Object... args) { + public void log(@NonNull Severity severity, @Nullable Throwable exception, + @Nullable String format, @Nullable Object... args) { mDelegate.log(exception, format, args); } @@ -1185,6 +1199,11 @@ public class LintDriver { } @Override + public List<File> getJavaLibraries(Project project) { + return mDelegate.getJavaLibraries(project); + } + + @Override @Nullable public IDomParser getDomParser() { return mDelegate.getDomParser(); 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 8a4fb2d..a2899d8 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 @@ -52,21 +52,27 @@ public class ClassContext extends Context { private boolean mSearchedForSource; /** If the file is a relative path within a jar file, this is the jar file, otherwise null */ private final File mJarFile; + /** Whether this class is part of a library (rather than corresponding to one of the + * source files in this project */ + private final boolean mFromLibrary; /** * Construct a new {@link ClassContext} * * @param driver the driver running through the checks * @param project the project containing the file being checked - * @param main the main project if this project is a library project, or null if this - * is not a library project. The main project is the root project of all - * library projects, not necessarily the directly including project. + * @param main the main project if this project is a library project, or + * null if this is not a library project. The main project is the + * root project of all library projects, not necessarily the + * directly including project. * @param file the file being checked - * @param jarFile If the file is a relative path within a jar file, this is the jar - * file, otherwise null + * @param jarFile If the file is a relative path within a jar file, this is + * the jar file, otherwise null * @param binDir the root binary directory containing this .class file. * @param bytes the bytecode raw data * @param classNode the bytecode object model + * @param fromLibrary whether this class is from a library rather than part + * of this project */ public ClassContext( @NonNull LintDriver driver, @@ -76,12 +82,14 @@ public class ClassContext extends Context { @Nullable File jarFile, @NonNull File binDir, @NonNull byte[] bytes, - @NonNull ClassNode classNode) { + @NonNull ClassNode classNode, + boolean fromLibrary) { super(driver, project, main, file); mJarFile = jarFile; mBinDir = binDir; mBytes = bytes; mClassNode = classNode; + mFromLibrary = fromLibrary; } /** @@ -116,6 +124,15 @@ public class ClassContext extends Context { } /** + * Returns whether this class is part of a library (not this project). + * + * @return true if this class is part of a library + */ + public boolean isFromClassLibrary() { + return mFromLibrary; + } + + /** * Returns the source file for this class file, if possible. * * @return the source file, or null diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java index d18ab71..9d61047 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java @@ -35,6 +35,7 @@ public class Location { private final Position mEnd; private String mMessage; private Location mSecondary; + private Object mClientData; /** * (Private constructor, use one of the factory methods @@ -143,6 +144,28 @@ public class Location { return mMessage; } + /** + * Sets the client data associated with this location. This is an optional + * field which can be used by the creator of the {@link Location} to store + * temporary state associated with the location. + * + * @param clientData the data to store with this location + */ + public void setClientData(@Nullable Object clientData) { + mClientData = clientData; + } + + /** + * Returns the client data associated with this location - an optional field + * which can be used by the creator of the {@link Location} to store + * temporary state associated with the location. + * + * @return the data associated with this location + */ + @Nullable + public Object getClientData() { + return mClientData; + } @Override public String toString() { @@ -352,6 +375,25 @@ public class Location { */ @NonNull Location resolve(); + + /** + * Sets the client data associated with this location. This is an optional + * field which can be used by the creator of the {@link Location} to store + * temporary state associated with the location. + * + * @param clientData the data to store with this location + */ + public void setClientData(@Nullable Object clientData); + + /** + * Returns the client data associated with this location - an optional field + * which can be used by the creator of the {@link Location} to store + * temporary state associated with the location. + * + * @return the data associated with this location + */ + @Nullable + public Object getClientData(); } /** A default {@link Handle} implementation for simple file offsets */ @@ -360,6 +402,7 @@ public class Location { private String mContents; private int mStartOffset; private int mEndOffset; + private Object mClientData; /** * Constructs a new {@link DefaultLocationHandle} @@ -380,5 +423,16 @@ public class Location { public Location resolve() { return Location.create(mFile, mContents, mStartOffset, mEndOffset); } + + @Override + public void setClientData(@Nullable Object clientData) { + mClientData = clientData; + } + + @Override + @Nullable + public Object getClientData() { + return mClientData; + } } } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java index e2795ed..5146a77 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java @@ -82,6 +82,7 @@ public class Project { private List<File> mFiles; private List<File> mJavaSourceFolders; private List<File> mJavaClassFolders; + private List<File> mJavaLibraries;; private List<Project> mDirectLibraries; private List<Project> mAllLibraries; @@ -268,6 +269,28 @@ public class Project { } /** + * Returns the list of Java libraries (typically .jar files) that this + * project depends on. Note that this refers to jar libraries, not Android + * library projects which are processed in a separate pass with their own + * source and class folders. + * + * @return a list of .jar files (or class folders) that this project depends + * on. + */ + @NonNull + public List<File> getJavaLibraries() { + if (mJavaLibraries == null) { + // AOSP builds already merge libraries and class folders into + // the single classes.jar file, so these have already been processed + // in getJavaClassFolders. + + mJavaLibraries = mClient.getJavaLibraries(this); + } + + return mJavaLibraries; + } + + /** * Returns the relative path of a given file relative to the user specified * directory (which is often the project directory but sometimes a higher up * directory when a directory tree is being scanned diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java index 9e5ed81..4b9da60 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java @@ -77,7 +77,8 @@ public enum Scope { PROGUARD_FILE, /** - * The analysis considers classes in the libraries for this project. + * The analysis considers classes in the libraries for this project. These + * will be analyzed before the classes themselves. */ JAVA_LIBRARIES; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java index 7053038..99cf76c 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java @@ -76,7 +76,7 @@ public class ApiDetector extends LayoutDetector implements Detector.ClassScanner 6, Severity.ERROR, ApiDetector.class, - EnumSet.of(Scope.CLASS_FILE, Scope.JAVA_LIBRARIES, Scope.RESOURCE_FILE)); + EnumSet.of(Scope.CLASS_FILE, Scope.RESOURCE_FILE)); private ApiLookup mApiDatabase; private int mMinApi = -1; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java index 4d1c8ae..ac3a7a3 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java @@ -149,6 +149,7 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto * defined multiple times, usually for different translations. */ private Map<String, List<Pair<Handle, String>>> mFormatStrings; + /** * List of strings that contain percents that aren't formatting strings; these * should not be passed to String.format. diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/FieldGetterDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/FieldGetterDetectorTest.java index bdb7618..ccbf26b 100644 --- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/FieldGetterDetectorTest.java +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/FieldGetterDetectorTest.java @@ -41,6 +41,21 @@ public class FieldGetterDetectorTest extends AbstractCheckTest { )); } + public void testLibraries() throws Exception { + // This tests the infrastructure: it makes sure that we *don't* run this + // check in jars that are on the jar library dependency path (testJar() checks + // that it *does* work for local jar classes) + assertEquals( + "No warnings.", + + lintProject( + "bytecode/classpath-lib=>.classpath", + "bytecode/AndroidManifest.xml=>AndroidManifest.xml", + "bytecode/GetterTest.java.txt=>src/test/bytecode/GetterTest.java", + "bytecode/GetterTest.jar.data=>libs/library.jar" + )); + } + public void testJar() throws Exception { assertEquals( "GetterTest.java:47: Warning: Calling getter method getFoo1() on self is slower than field access (mFoo1)\n" + diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/classpath-lib b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/classpath-lib new file mode 100644 index 0000000..e730df8 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/classpath-lib @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="gen"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> + <classpathentry kind="lib" path="libs/library.jar"/> + <classpathentry kind="output" path="bin/classes"/> +</classpath> |