aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-08-01 15:04:31 -0700
committerandroid code review <noreply-gerritcodereview@google.com>2012-08-01 15:04:31 -0700
commitaf58169996f268a5e6fd4905c50b4858382c3f0f (patch)
treef8f4af2c8d1fde403997212ddabfe89c59e4dcab
parent2de64c74ebc0976a2954cde07bb205069bd36bb6 (diff)
parent8dcd0726088eee54368e032e7dc6b31a450b4ee1 (diff)
downloadsdk-af58169996f268a5e6fd4905c50b4858382c3f0f.zip
sdk-af58169996f268a5e6fd4905c50b4858382c3f0f.tar.gz
sdk-af58169996f268a5e6fd4905c50b4858382c3f0f.tar.bz2
Merge "Fix lint-on-save for .class file detectors in Java files"
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java14
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java20
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintDeltaProcessor.java97
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java15
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java8
-rw-r--r--lint/cli/src/com/android/tools/lint/Main.java2
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java17
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java40
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java28
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java9
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java3
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java4
18 files changed, 245 insertions, 45 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index 83812b2..a2afc89 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -34,6 +34,7 @@ import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder;
+import com.android.ide.eclipse.adt.internal.lint.LintDeltaProcessor;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;
@@ -1479,6 +1480,7 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger, ISdkLog {
try {
setupDefaultEditor(mResourceMonitor);
ResourceManager.setup(mResourceMonitor);
+ LintDeltaProcessor.startListening(mResourceMonitor);
} catch (Throwable t) {
log(t, "ResourceManager.setup failed"); //$NON-NLS-1$
}
@@ -1500,6 +1502,8 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger, ISdkLog {
IconFactory.getInstance().dispose();
+ LintDeltaProcessor.stopListening(mResourceMonitor);
+
// Remove the resource listener that handles compiled resources.
IWorkspace ws = ResourcesPlugin.getWorkspace();
GlobalProjectMonitor.stopMonitoring(ws);
@@ -1555,8 +1559,14 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger, ISdkLog {
* @see IFileListener#fileChanged
*/
@Override
- public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
- if (AdtConstants.EXT_XML.equals(file.getFileExtension())) {
+ public void fileChanged(@NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas,
+ int kind, @Nullable String extension, int flags) {
+ if (flags == IResourceDelta.MARKERS) {
+ // ONLY the markers changed: not relevant to this listener
+ return;
+ }
+
+ if (AdtConstants.EXT_XML.equals(extension)) {
// The resources files must have a file path similar to
// project/res/.../*.xml
// There is no support for sub folders, so the segment count must be 4
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
index a3ae46b..4cf4a00 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
@@ -449,7 +449,8 @@ public class AdtUtils {
* @param resource the resource to look up a path for
* @return an absolute file system path to the resource
*/
- public static IPath getAbsolutePath(IResource resource) {
+ @NonNull
+ public static IPath getAbsolutePath(@NonNull IResource resource) {
IPath location = resource.getRawLocation();
if (location != null) {
return location.makeAbsolute();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java
index ea3a325..9467702 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java
@@ -27,12 +27,14 @@ import com.android.ide.eclipse.adt.internal.build.BuildHelper.ResourceMarker;
import com.android.ide.eclipse.adt.internal.build.DexException;
import com.android.ide.eclipse.adt.internal.build.Messages;
import com.android.ide.eclipse.adt.internal.build.NativeLibInJarException;
+import com.android.ide.eclipse.adt.internal.lint.LintDeltaProcessor;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
import com.android.ide.eclipse.adt.internal.project.ApkInstallManager;
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
import com.android.ide.eclipse.adt.internal.project.LibraryClasspathContainerInitializer;
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
+import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.adt.io.IFileWrapper;
@@ -248,6 +250,12 @@ public class PostCompilerBuilder extends BaseBuilder {
mConvertToDex = true;
mBuildFinalPackage = true;
} else {
+
+ if (ResourceManager.isAutoBuilding() && AdtPrefs.getPrefs().isLintOnSave()) {
+ // Check for errors on save/build, if enabled
+ LintDeltaProcessor.create().process(delta);
+ }
+
PatternBasedDeltaVisitor dv = new PatternBasedDeltaVisitor(
project, project,
"POST:Main");
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
index 18459d2..afc8fa7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
@@ -24,7 +24,6 @@ import com.android.ide.eclipse.adt.internal.build.Messages;
import com.android.ide.eclipse.adt.internal.build.RenderScriptProcessor;
import com.android.ide.eclipse.adt.internal.build.SourceProcessor;
import com.android.ide.eclipse.adt.internal.lint.EclipseLintClient;
-import com.android.ide.eclipse.adt.internal.lint.LintDeltaProcessor;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
@@ -310,11 +309,6 @@ public class PreCompilerBuilder extends BaseBuilder {
dv = new PreCompilerDeltaVisitor(this, sourceFolderPathList, mProcessors);
delta.accept(dv);
- // Check for errors on save/build, if enabled
- if (AdtPrefs.getPrefs().isLintOnSave()) {
- LintDeltaProcessor.create().process(delta);
- }
-
// Check to see if Manifest.xml, Manifest.java, or R.java have changed:
mMustCompileResources |= dv.getCompileResources();
mMustMergeManifest |= dv.hasManifestChanged();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java
index 1ee497e..0d4bd20 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java
@@ -16,6 +16,8 @@
package com.android.ide.eclipse.adt.internal.editors.layout;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.resources.ResourceFile;
import com.android.ide.common.resources.ResourceFolder;
import com.android.ide.eclipse.adt.AdtConstants;
@@ -172,7 +174,15 @@ public final class LayoutReloadMonitor {
* This records the changes for each project, but does not notify listeners.
*/
@Override
- public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
+ public void fileChanged(@NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas,
+ int kind, @Nullable String extension, int flags) {
+ // This listener only cares about .class files and AndroidManifest.xml files
+ if (!(AdtConstants.EXT_CLASS.equals(extension)
+ || AdtConstants.EXT_XML.equals(extension)
+ && SdkConstants.FN_ANDROID_MANIFEST_XML.equals(file.getName()))) {
+ return;
+ }
+
// get the file's project
IProject project = file.getProject();
@@ -187,7 +197,7 @@ public final class LayoutReloadMonitor {
if (hasAndroidNature) {
// project is an Android project, it's the one being affected
// directly by its own file change.
- processFileChanged(file, project);
+ processFileChanged(file, project, extension);
} else {
// check the projects depending on it, if they are Android project, update them.
IProject[] referencingProjects = project.getReferencingProjects();
@@ -203,7 +213,7 @@ public final class LayoutReloadMonitor {
if (hasAndroidNature) {
// the changed project is a dependency on an Android project,
// update the main project.
- processFileChanged(file, p);
+ processFileChanged(file, p, extension);
}
}
}
@@ -214,7 +224,7 @@ public final class LayoutReloadMonitor {
* @param file the changed file
* @param project the project impacted by the file change.
*/
- private void processFileChanged(IFile file, IProject project) {
+ private void processFileChanged(IFile file, IProject project, String extension) {
// if this project has already been marked as modified, we do nothing.
ChangeFlags changeFlags = mProjectFlags.get(project);
if (changeFlags != null && changeFlags.isAllTrue()) {
@@ -223,7 +233,7 @@ public final class LayoutReloadMonitor {
// here we only care about code change (so change for .class files).
// Resource changes is handled by the IResourceListener.
- if (AdtConstants.EXT_CLASS.equals(file.getFileExtension())) {
+ if (AdtConstants.EXT_CLASS.equals(extension)) {
if (file.getName().matches("R[\\$\\.](.*)")) {
// this is a R change!
if (changeFlags == null) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java
index cf210d1..7cfd6c4 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java
@@ -21,6 +21,7 @@ import static com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.
import static com.android.util.XmlUtils.ANDROID_URI;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
@@ -292,7 +293,8 @@ public final class ManifestEditor extends AndroidXmlEditor {
mMarkerMonitor = new IFileListener() {
@Override
- public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
+ public void fileChanged(@NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas,
+ int kind, @Nullable String extension, int flags) {
if (file.equals(inputFile)) {
processMarkerChanges(markerDeltas);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java
index 0ec26fe..4d1030c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java
@@ -690,7 +690,7 @@ public class EclipseLintClient extends LintClient implements IDomParser {
private String readPlainFile(File file) {
try {
- return LintUtils.getEncodedString(file);
+ return LintUtils.getEncodedString(this, file);
} catch (IOException e) {
return ""; //$NON-NLS-1$
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintDeltaProcessor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintDeltaProcessor.java
index 7847262..6b94232 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintDeltaProcessor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintDeltaProcessor.java
@@ -17,17 +17,25 @@ package com.android.ide.eclipse.adt.internal.lint;
import static com.android.ide.eclipse.adt.AdtConstants.DOT_CLASS;
import static com.android.ide.eclipse.adt.AdtConstants.DOT_JAVA;
+import static com.android.ide.eclipse.adt.AdtConstants.EXT_JAVA;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
+import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
+import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor;
+import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener;
+import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.swt.widgets.Display;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -39,6 +47,16 @@ public class LintDeltaProcessor implements Runnable {
private IFile mActiveFile;
private LintDeltaProcessor() {
+ // Get the active editor file, if any
+ Display display = AdtPlugin.getDisplay();
+ if (display == null || display.isDisposed()) {
+ return;
+ }
+ if (display.getThread() != Thread.currentThread()) {
+ display.syncExec(this);
+ } else {
+ run();
+ }
}
/**
@@ -57,17 +75,6 @@ public class LintDeltaProcessor implements Runnable {
* @param delta the delta describing recently changed files
*/
public void process(@NonNull IResourceDelta delta) {
- // Get the active editor file, if any
- Display display = AdtPlugin.getDisplay();
- if (display == null || display.isDisposed()) {
- return;
- }
- if (display.getThread() != Thread.currentThread()) {
- display.syncExec(this);
- } else {
- run();
- }
-
if (mActiveFile == null || !mActiveFile.getName().endsWith(DOT_JAVA)) {
return;
}
@@ -82,6 +89,24 @@ public class LintDeltaProcessor implements Runnable {
}
/**
+ * Process edits in the given file: update lint on the Java source provided
+ * it's the active file.
+ *
+ * @param file the file that was changed
+ */
+ public void process(@NonNull IFile file) {
+ if (mActiveFile == null || !mActiveFile.getName().endsWith(DOT_JAVA)) {
+ return;
+ }
+
+ if (file.equals(mActiveFile)) {
+ mFiles = Collections.<IResource>singletonList(file);
+ EclipseLintRunner.startLint(mFiles, mActiveFile, null,
+ false /*fatalOnly*/, false /*show*/);
+ }
+ }
+
+ /**
* Collect .java and .class files to be run in lint. Only collects files
* that match the active editor.
*/
@@ -122,4 +147,54 @@ public class LintDeltaProcessor implements Runnable {
// Get the active file: this must be run on the GUI thread
mActiveFile = AdtUtils.getActiveFile();
}
+
+ /**
+ * Start listening to the resource monitor
+ *
+ * @param resourceMonitor the resource monitor
+ */
+ public static void startListening(@NonNull GlobalProjectMonitor resourceMonitor) {
+ // Add a file listener which finds out when files have changed. This is listening
+ // specifically for saves of Java files, in order to run incremental lint on them.
+ // Note that the {@link PostCompilerBuilder} already handles incremental lint files
+ // on Java files - and runs it for both the .java and .class files.
+ //
+ // However, if Project > Build Automatically is turned off, then the PostCompilerBuilder
+ // isn't run after a save. THAT's what the below is for: it will run and *only*
+ // run lint incrementally if build automatically is off.
+ assert sListener == null; // Should only be called once on plugin activation
+ sListener = new IFileListener() {
+ @Override
+ public void fileChanged(@NonNull IFile file,
+ @NonNull IMarkerDelta[] markerDeltas,
+ int kind, @Nullable String extension, int flags) {
+ if (flags == IResourceDelta.MARKERS) {
+ // ONLY the markers changed. Ignore these since they happen
+ // when we add markers for lint errors found in the current file,
+ // which would cause us to repeatedly enter this method over and over
+ // again.
+ return;
+ }
+ if (EXT_JAVA.equals(extension)
+ && !ResourceManager.isAutoBuilding()
+ && AdtPrefs.getPrefs().isLintOnSave()) {
+ LintDeltaProcessor.create().process(file);
+ }
+ }
+ };
+ resourceMonitor.addFileListener(sListener, IResourceDelta.ADDED | IResourceDelta.CHANGED);
+ }
+
+ /**
+ * Stop listening to the resource monitor
+ *
+ * @param resourceMonitor the resource monitor
+ */
+ public static void stopListening(@NonNull GlobalProjectMonitor resourceMonitor) {
+ assert sListener != null;
+ resourceMonitor.removeFileListener(sListener);
+ sListener = null;
+ }
+
+ private static IFileListener sListener;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
index fd6e174..31207e5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
@@ -16,6 +16,8 @@
package com.android.ide.eclipse.adt.internal.resources.manager;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.resources.IntArrayWrapper;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
@@ -80,7 +82,13 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
* @see IFileListener#fileChanged
*/
@Override
- public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
+ public void fileChanged(@NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas,
+ int kind, @Nullable String extension, int flags) {
+ if (flags == IResourceDelta.MARKERS) {
+ // Only the markers changed: not relevant
+ return;
+ }
+
IProject project = file.getProject();
if (file.getName().equals(AdtConstants.FN_COMPILED_RESOURCE_CLASS)) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java
index ea14a5c..b623cec 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java
@@ -16,6 +16,8 @@
package com.android.ide.eclipse.adt.internal.resources.manager;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.resources.ResourceFile;
import com.android.ide.common.resources.ResourceFolder;
import com.android.ide.eclipse.adt.AdtPlugin;
@@ -65,12 +67,18 @@ public final class GlobalProjectMonitor {
public interface IFileListener {
/**
* Sent when a file changed.
+ *
* @param file The file that changed.
* @param markerDeltas The marker deltas for the file.
* @param kind The change kind. This is equivalent to
- * {@link IResourceDelta#accept(IResourceDeltaVisitor)}
+ * {@link IResourceDelta#accept(IResourceDeltaVisitor)}
+ * @param extension the extension of the file or null if the file does
+ * not have an extension
+ * @param flags the {@link IResourceDelta#getFlags()} value with details
+ * on what changed in the file
*/
- public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind);
+ public void fileChanged(@NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas,
+ int kind, @Nullable String extension, int flags);
}
/**
@@ -217,7 +225,8 @@ public final class GlobalProjectMonitor {
if (bundle.kindMask == ListenerBundle.MASK_NONE
|| (bundle.kindMask & kind) != 0) {
try {
- bundle.listener.fileChanged((IFile)r, delta.getMarkerDeltas(), kind);
+ bundle.listener.fileChanged((IFile)r, delta.getMarkerDeltas(), kind,
+ r.getFileExtension(), delta.getFlags());
} catch (Throwable t) {
AdtPlugin.log(t,"Failed to call IFileListener.fileChanged");
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
index 6b45f09..aa5f473 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
@@ -17,9 +17,11 @@
package com.android.ide.eclipse.adt.internal.sdk;
import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML;
+import static com.android.ide.eclipse.adt.AdtConstants.EXT_JAR;
import static com.android.sdklib.SdkConstants.FD_RES;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ddmlib.IDevice;
import com.android.ide.common.rendering.LayoutLibrary;
import com.android.ide.common.sdk.LoadStatus;
@@ -1014,7 +1016,8 @@ public final class Sdk {
*/
private IFileListener mFileListener = new IFileListener() {
@Override
- public void fileChanged(final IFile file, IMarkerDelta[] markerDeltas, int kind) {
+ public void fileChanged(final @NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas,
+ int kind, @Nullable String extension, int flags) {
if (SdkConstants.FN_PROJECT_PROPERTIES.equals(file.getName()) &&
file.getParent() == file.getProject()) {
try {
@@ -1075,7 +1078,8 @@ public final class Sdk {
}
} else if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
// check if it's an add/remove on a jar files inside libs
- if (file.getProjectRelativePath().segmentCount() == 2 &&
+ if (EXT_JAR.equals(extension) &&
+ file.getProjectRelativePath().segmentCount() == 2 &&
file.getParent().getName().equals(SdkConstants.FD_NATIVE_LIBS)) {
// need to update the project and whatever depend on it.
diff --git a/lint/cli/src/com/android/tools/lint/Main.java b/lint/cli/src/com/android/tools/lint/Main.java
index 5e51106..fbb0b16 100644
--- a/lint/cli/src/com/android/tools/lint/Main.java
+++ b/lint/cli/src/com/android/tools/lint/Main.java
@@ -1112,7 +1112,7 @@ public class Main extends LintClient {
@Override
public @NonNull String readFile(@NonNull File file) {
try {
- return LintUtils.getEncodedString(file);
+ return LintUtils.getEncodedString(this, file);
} catch (IOException e) {
return ""; //$NON-NLS-1$
}
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 93e311e..4cca31c 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
@@ -33,6 +33,7 @@ import com.android.tools.lint.detector.api.Project;
import com.android.tools.lint.detector.api.Severity;
import com.google.common.annotations.Beta;
import com.google.common.collect.Maps;
+import com.google.common.io.Files;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -177,6 +178,22 @@ public abstract class LintClient {
public abstract String readFile(@NonNull File file);
/**
+ * Reads the given binary file and returns the content as a byte array.
+ * By default this method will read the bytes from the file directly,
+ * but this can be customized by a client if for example I/O could be
+ * held in memory and not flushed to disk yet.
+ *
+ * @param file the file to read
+ * @return the bytes in the file, never null
+ * @throws IOException if the file does not exist, or if the file cannot be
+ * read for some reason
+ */
+ @NonNull
+ public byte[] readBytes(@NonNull File file) throws IOException {
+ return Files.toByteArray(file);
+ }
+
+ /**
* Returns the list of source folders for Java source files
*
* @param project the project to look up Java source file locations 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 270ffa4..d91b155 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
@@ -55,7 +55,6 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
-import com.google.common.io.Files;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
@@ -1023,7 +1022,7 @@ public class LintDriver {
String path = file.getPath();
if (file.isFile() && path.endsWith(DOT_CLASS)) {
try {
- byte[] bytes = Files.toByteArray(file);
+ byte[] bytes = mClient.readBytes(file);
if (bytes != null) {
for (File dir : classFolders) {
if (path.startsWith(dir.getPath())) {
@@ -1068,6 +1067,8 @@ public class LintDriver {
if (classDetectors != null && classDetectors.size() > 0 && entries.size() > 0) {
AsmVisitor visitor = new AsmVisitor(mClient, classDetectors);
+ String sourceContents = null;
+ String sourceName = "";
mOuterClasses = new ArrayDeque<ClassNode>();
for (ClassEntry entry : entries) {
ClassReader reader;
@@ -1097,9 +1098,31 @@ public class LintDriver {
continue;
}
+ if (sourceContents != null) {
+ // Attempt to reuse the source buffer if initialized
+ // This means making sure that the source files
+ // foo/bar/MyClass and foo/bar/MyClass$Bar
+ // and foo/bar/MyClass$3 and foo/bar/MyClass$3$1 have the same prefix.
+ String newName = classNode.name;
+ int newRootLength = newName.indexOf('$');
+ if (newRootLength == -1) {
+ newRootLength = newName.length();
+ }
+ int oldRootLength = sourceName.indexOf('$');
+ if (oldRootLength == -1) {
+ oldRootLength = sourceName.length();
+ }
+ if (newRootLength != oldRootLength ||
+ !sourceName.regionMatches(0, newName, 0, newRootLength)) {
+ sourceContents = null;
+ }
+ }
+
ClassContext context = new ClassContext(this, project, main,
entry.file, entry.jarFile, entry.binDir, entry.bytes,
- classNode, scope == Scope.JAVA_LIBRARIES /*fromLibrary*/);
+ classNode, scope == Scope.JAVA_LIBRARIES /*fromLibrary*/,
+ sourceContents);
+
try {
visitor.runClassDetectors(context);
} catch (Exception e) {
@@ -1109,6 +1132,9 @@ public class LintDriver {
if (mCanceled) {
return;
}
+
+ sourceContents = context.getSourceContents(false/*read*/);
+ sourceName = classNode.name;
}
mOuterClasses = null;
@@ -1229,7 +1255,7 @@ public class LintDriver {
for (File file : classFiles) {
try {
- byte[] bytes = Files.toByteArray(file);
+ byte[] bytes = mClient.readBytes(file);
if (bytes != null) {
entries.add(new ClassEntry(file, null /* jarFile*/, binDir, bytes));
}
@@ -1568,6 +1594,12 @@ public class LintDriver {
@Override
@NonNull
+ public byte[] readBytes(@NonNull File file) throws IOException {
+ return mDelegate.readBytes(file);
+ }
+
+ @Override
+ @NonNull
public List<File> getJavaSourceFolders(@NonNull Project project) {
return mDelegate.getJavaSourceFolders(project);
}
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 4aa21d4..5f8cac9 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
@@ -82,6 +82,8 @@ public class ClassContext extends Context {
* @param classNode the bytecode object model
* @param fromLibrary whether this class is from a library rather than part
* of this project
+ * @param sourceContents initial contents of the Java source, if known, or
+ * null
*/
public ClassContext(
@NonNull LintDriver driver,
@@ -92,13 +94,15 @@ public class ClassContext extends Context {
@NonNull File binDir,
@NonNull byte[] bytes,
@NonNull ClassNode classNode,
- boolean fromLibrary) {
+ boolean fromLibrary,
+ @Nullable String sourceContents) {
super(driver, project, main, file);
mJarFile = jarFile;
mBinDir = binDir;
mBytes = bytes;
mClassNode = classNode;
mFromLibrary = fromLibrary;
+ mSourceContents = sourceContents;
}
/**
@@ -217,6 +221,28 @@ public class ClassContext extends Context {
}
/**
+ * Returns the contents of the source file for this class file, if found. If
+ * {@code read} is false, do not read the source contents if it has not
+ * already been read. (This is primarily intended for the lint
+ * infrastructure; most client code would call {@link #getSourceContents()}
+ * .)
+ *
+ * @param read whether to read the source contents if it has not already
+ * been initialized
+ * @return the source contents, which will never be null if {@code read} is
+ * true, or null if {@code read} is false and the source contents
+ * hasn't already been read.
+ */
+ @Nullable
+ public String getSourceContents(boolean read) {
+ if (read) {
+ return getSourceContents();
+ } else {
+ return mSourceContents;
+ }
+ }
+
+ /**
* Returns a location for the given source line number in this class file's
* source file, if available.
*
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
index 9bfb7cc..ce64fe3 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
@@ -27,9 +27,9 @@ import com.android.annotations.Nullable;
import com.android.resources.FolderTypeRelationship;
import com.android.resources.ResourceFolderType;
import com.android.resources.ResourceType;
+import com.android.tools.lint.client.api.LintClient;
import com.android.util.PositionXmlParser;
import com.google.common.annotations.Beta;
-import com.google.common.io.Files;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
@@ -394,13 +394,16 @@ public class LintUtils {
* same as {@code Files.toString(file, Charsets.UTF8}, but if there's a UTF byte order mark
* (for UTF8, UTF_16 or UTF_16LE), use that instead.
*
+ * @param client the client to use for I/O operations
* @param file the file to read from
* @return the string
* @throws IOException if the file cannot be read properly
*/
@NonNull
- public static String getEncodedString(@NonNull File file) throws IOException {
- byte[] bytes = Files.toByteArray(file);
+ public static String getEncodedString(
+ @NonNull LintClient client,
+ @NonNull File file) throws IOException {
+ byte[] bytes = client.readBytes(file);
if (endsWith(file.getName(), DOT_XML)) {
return PositionXmlParser.getXmlString(bytes);
}
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java
index adee77d..da27cc9 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java
@@ -45,7 +45,6 @@ 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.io.Files;
import org.w3c.dom.Element;
@@ -422,7 +421,7 @@ public class IconDetector extends Detector implements Detector.XmlScanner {
byte[] bits = fileContents.get(file);
if (bits == null) {
try {
- bits = Files.toByteArray(file);
+ bits = context.getClient().readBytes(file);
fileContents.put(file, bits);
} catch (IOException e) {
context.log(e, null);
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java
index 67d2dfa..4765f41 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LintUtilsTest.java
@@ -16,6 +16,8 @@
package com.android.tools.lint.detector.api;
+import com.android.tools.lint.Main;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -210,7 +212,7 @@ public class LintUtilsTest extends TestCase {
writer.write(sb.toString());
writer.close();
- String s = LintUtils.getEncodedString(file);
+ String s = LintUtils.getEncodedString(new Main(), file);
assertEquals(expected, s);
}