aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-05-29 12:04:03 -0700
committerTor Norbye <tnorbye@google.com>2012-05-30 16:41:32 -0700
commit4ae3297a857c6a0c84511b4c5e727360f6958c89 (patch)
treef8fb584f24a956df9f1ba8cb39659c101fc47192 /eclipse
parenta65182c586d3e33e77ca424b684ca2f40729c77c (diff)
downloadsdk-4ae3297a857c6a0c84511b4c5e727360f6958c89.zip
sdk-4ae3297a857c6a0c84511b4c5e727360f6958c89.tar.gz
sdk-4ae3297a857c6a0c84511b4c5e727360f6958c89.tar.bz2
Lint infrastructure fixes
This changeset contains various unrelated fixes to the lint infrastructure: (1) Tweak the way the classpaths are computed in the default lint client method such that rather than reading and parsing the .classpath file 3 times, once for each of source-path, output-path and library-path, it's now processing it once and storing the results for all 3. (2) Override the lookup-classpath method in Eclipse to directly query the Eclipse APIs for obtaining the classpath info. (3) Add in user libraries found in libs/, since these don't necessarily show up in the .classpath file. (4) Fix a couple of bugs related to checking .class files: First, when locating the project for a .class file, lint would search upwards for the surrounding project, which meant looking for the nearest parent containing an AndroidManifest.xml file. However, in the case of .class files, it will first encounter the bin/ directory, which can contain a manifest file, so it would compute a project for the bin/ folder rather than its parent, which meant the source paths would be wrong. Second, the list of class entries to be processed by lint must be sorted prior to processing; the code dealing with innerclasses depends on that. (5) Some minor code cleanup: Move some generic utility code and some string literals out of specific detectors and into the generic utility and constant classes. (6) Cache results of the lint-project to eclipse-project lookup method since that method is called repeatedly with the same (current) project. Change-Id: I33603eed8381ca54314202620cb1bb033e70f775
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java17
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java137
2 files changed, 151 insertions, 3 deletions
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 09092e7..47e650d 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
@@ -444,6 +444,23 @@ public class AdtUtils {
}
/**
+ * Converts a workspace-relative path to an absolute file path
+ *
+ * @param path the workspace-relative path to convert
+ * @return the corresponding absolute file in the file system
+ */
+ @NonNull
+ public static File workspacePathToFile(@NonNull IPath path) {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IResource res = root.findMember(path);
+ if (res != null) {
+ return res.getLocation().toFile();
+ }
+
+ return path.toFile();
+ }
+
+ /**
* Converts a {@link File} to an {@link IFile}, if possible.
*
* @param file a file to be converted
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 703be80..b5810a4 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
@@ -15,8 +15,11 @@
*/
package com.android.ide.eclipse.adt.internal.lint;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_JAR;
import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML;
import static com.android.ide.eclipse.adt.AdtConstants.MARKER_LINT;
+import static com.android.ide.eclipse.adt.AdtUtils.workspacePathToFile;
+import static com.android.sdklib.SdkConstants.FD_NATIVE_LIBS;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
@@ -45,6 +48,7 @@ import com.android.tools.lint.detector.api.Project;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.XmlContext;
import com.android.util.Pair;
+import com.google.common.collect.Maps;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
@@ -52,7 +56,9 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
@@ -85,6 +91,7 @@ import org.w3c.dom.Node;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -233,19 +240,38 @@ public class EclipseLintClient extends LintClient implements IDomParser {
return null;
}
+ // Cache for {@link getProject}
+ private IProject mLastEclipseProject;
+ private Project mLastLintProject;
+
private IProject getProject(Project project) {
+ if (project == mLastLintProject) {
+ return mLastEclipseProject;
+ }
+
+ mLastLintProject = project;
+ mLastEclipseProject = null;
+
if (mResources != null) {
if (mResources.size() == 1) {
- return mResources.get(0).getProject();
+ IProject p = mResources.get(0).getProject();
+ mLastEclipseProject = p;
+ return p;
}
+ IProject last = null;
for (IResource resource : mResources) {
IProject p = resource.getProject();
- if (project.getDir().equals(AdtUtils.getAbsolutePath(p).toFile())) {
- return p;
+ if (p != last) {
+ if (project.getDir().equals(AdtUtils.getAbsolutePath(p).toFile())) {
+ mLastEclipseProject = p;
+ return p;
+ }
+ last = p;
}
}
}
+
return null;
}
@@ -669,6 +695,111 @@ public class EclipseLintClient extends LintClient implements IDomParser {
return new LazyLocation(context.file, model.getStructuredDocument(), (IndexedRegion) node);
}
+ private Map<Project, ClassPathInfo> mProjectInfo;
+
+ @Override
+ @NonNull
+ protected ClassPathInfo getClassPath(@NonNull Project project) {
+ ClassPathInfo info;
+ if (mProjectInfo == null) {
+ mProjectInfo = Maps.newHashMap();
+ info = null;
+ } else {
+ info = mProjectInfo.get(project);
+ }
+
+ if (info == null) {
+ List<File> sources = null;
+ List<File> classes = null;
+ List<File> libraries = null;
+
+ IProject p = getProject(project);
+ if (p != null) {
+ try {
+ IJavaProject javaProject = BaseProjectHelper.getJavaProject(p);
+
+ // Output path
+ File file = workspacePathToFile(javaProject.getOutputLocation());
+ classes = Collections.singletonList(file);
+
+ // Source path
+ IClasspathEntry[] entries = javaProject.getRawClasspath();
+ sources = new ArrayList<File>(entries.length);
+ libraries = new ArrayList<File>(entries.length);
+ for (int i = 0; i < entries.length; i++) {
+ IClasspathEntry entry = entries[i];
+ int kind = entry.getEntryKind();
+
+ if (kind == IClasspathEntry.CPE_VARIABLE) {
+ entry = JavaCore.getResolvedClasspathEntry(entry);
+ kind = entry.getEntryKind();
+ }
+
+ if (kind == IClasspathEntry.CPE_SOURCE) {
+ sources.add(workspacePathToFile(entry.getPath()));
+ } else if (kind == IClasspathEntry.CPE_LIBRARY) {
+ libraries.add(entry.getPath().toFile());
+ }
+ // Note that we ignore IClasspathEntry.CPE_CONTAINER:
+ // Normal Android Eclipse projects supply both
+ // AdtConstants.CONTAINER_FRAMEWORK
+ // and
+ // AdtConstants.CONTAINER_LIBRARIES
+ // here. We ignore the framework classes for obvious reasons,
+ // but we also ignore the library container because lint will
+ // process the libraries differently. When Eclipse builds a
+ // project, it gets the .jar output of the library projects
+ // from this container, which means it doesn't have to process
+ // the library sources. Lint on the other hand wants to process
+ // the source code, so instead it actually looks at the
+ // project.properties file to find the libraries, and then it
+ // iterates over all the library projects in turn and analyzes
+ // those separately (but passing the main project for context,
+ // such that the including project's manifest declarations
+ // are used for data like minSdkVersion level).
+ //
+ // Note that this container will also contain *other*
+ // libraries (Java libraries, not library projects) that we
+ // *should* include. However, we can't distinguish these
+ // class path entries from the library project jars,
+ // so instead of looking at these, we simply listFiles() in
+ // the libs/ folder after processing the classpath info
+ }
+
+ // Add in libraries
+ File libs = new File(project.getDir(), FD_NATIVE_LIBS);
+ if (libs.isDirectory()) {
+ File[] jars = libs.listFiles();
+ if (jars != null) {
+ for (File jar : jars) {
+ if (AdtUtils.endsWith(jar.getPath(), DOT_JAR)) {
+ libraries.add(jar);
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+
+ if (sources == null) {
+ sources = super.getClassPath(project).getSourceFolders();
+ }
+ if (classes == null) {
+ classes = super.getClassPath(project).getClassFolders();
+ }
+ if (libraries == null) {
+ libraries = super.getClassPath(project).getLibraries();
+ }
+
+ info = new ClassPathInfo(sources, classes, libraries);
+ mProjectInfo.put(project, info);
+ }
+
+ return info;
+ }
+
/**
* Returns the registry of issues to check from within Eclipse.
*