aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintRunner.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintRunner.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintRunner.java238
1 files changed, 238 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintRunner.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintRunner.java
new file mode 100644
index 000000000..43cd48d1b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintRunner.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.
+ */
+package com.android.ide.eclipse.adt.internal.lint;
+
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.tools.lint.client.api.IssueRegistry;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.swt.widgets.Shell;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Eclipse implementation for running lint on workspace files and projects.
+ */
+public class EclipseLintRunner {
+ static final String MARKER_CHECKID_PROPERTY = "checkid"; //$NON-NLS-1$
+
+ /**
+ * Runs lint and updates the markers, and waits for the result. Returns
+ * true if fatal errors were found.
+ *
+ * @param resources the resources (project, folder or file) to be analyzed
+ * @param source if checking a single source file, the source file
+ * @param doc the associated document, if known, or null
+ * @param fatalOnly if true, only report fatal issues (severity=error)
+ * @return true if any fatal errors were encountered.
+ */
+ private static boolean runLint(
+ @NonNull List<? extends IResource> resources,
+ @Nullable IResource source,
+ @Nullable IDocument doc,
+ boolean fatalOnly) {
+ resources = addLibraries(resources);
+ LintJob job = (LintJob) startLint(resources, source, doc, fatalOnly,
+ false /*show*/);
+ try {
+ job.join();
+ boolean fatal = job.isFatal();
+
+ if (fatal) {
+ LintViewPart.show(resources);
+ }
+
+ return fatal;
+ } catch (InterruptedException e) {
+ AdtPlugin.log(e, null);
+ }
+
+ return false;
+ }
+
+ /**
+ * Runs lint and updates the markers. Does not wait for the job to finish -
+ * just returns immediately.
+ *
+ * @param resources the resources (project, folder or file) to be analyzed
+ * @param source if checking a single source file, the source file. When
+ * single checking an XML file, this is typically the same as the
+ * file passed in the list in the first parameter, but when
+ * checking the .class files of a Java file for example, the
+ * .class file and all the inner classes of the Java file are
+ * passed in the first parameter, and the corresponding .java
+ * source file is passed here.
+ * @param doc the associated document, if known, or null
+ * @param fatalOnly if true, only report fatal issues (severity=error)
+ * @param show if true, show the results in a {@link LintViewPart}
+ * @return the job running lint in the background.
+ */
+ public static Job startLint(
+ @NonNull List<? extends IResource> resources,
+ @Nullable IResource source,
+ @Nullable IDocument doc,
+ boolean fatalOnly,
+ boolean show) {
+ IssueRegistry registry = EclipseLintClient.getRegistry();
+ EclipseLintClient client = new EclipseLintClient(registry, resources, doc, fatalOnly);
+ return startLint(client, resources, source, show);
+ }
+
+ /**
+ * Runs lint and updates the markers. Does not wait for the job to finish -
+ * just returns immediately.
+ *
+ * @param client the lint client receiving issue reports etc
+ * @param resources the resources (project, folder or file) to be analyzed
+ * @param source if checking a single source file, the source file. When
+ * single checking an XML file, this is typically the same as the
+ * file passed in the list in the first parameter, but when
+ * checking the .class files of a Java file for example, the
+ * .class file and all the inner classes of the Java file are
+ * passed in the first parameter, and the corresponding .java
+ * source file is passed here.
+ * @param show if true, show the results in a {@link LintViewPart}
+ * @return the job running lint in the background.
+ */
+ public static Job startLint(
+ @NonNull EclipseLintClient client,
+ @NonNull List<? extends IResource> resources,
+ @Nullable IResource source,
+ boolean show) {
+ if (resources != null && !resources.isEmpty()) {
+ if (!AdtPrefs.getPrefs().getSkipLibrariesFromLint()) {
+ resources = addLibraries(resources);
+ }
+
+ cancelCurrentJobs(false);
+
+ LintJob job = new LintJob(client, resources, source);
+ job.schedule();
+
+ if (show) {
+ // Show lint view where the results are listed
+ LintViewPart.show(resources);
+ }
+ return job;
+ }
+
+ return null;
+ }
+
+ /**
+ * Run Lint for an Export APK action. If it succeeds (no fatal errors)
+ * returns true, and if it fails it will display an error message and return
+ * false.
+ *
+ * @param shell the parent shell to show error messages in
+ * @param project the project to run lint on
+ * @return true if the lint run succeeded with no fatal errors
+ */
+ public static boolean runLintOnExport(Shell shell, IProject project) {
+ if (AdtPrefs.getPrefs().isLintOnExport()) {
+ boolean fatal = EclipseLintRunner.runLint(Collections.singletonList(project),
+ null, null, true /*fatalOnly*/);
+ if (fatal) {
+ MessageDialog.openWarning(shell,
+ "Export Aborted",
+ "Export aborted because fatal lint errors were found. These " +
+ "are listed in the Lint View. Either fix these before " +
+ "running Export again, or turn off \"Run full error check " +
+ "when exporting app\" in the Android > Lint Error Checking " +
+ "preference page.");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /** Cancels the current lint jobs, if any, and optionally waits for them to finish */
+ static void cancelCurrentJobs(boolean wait) {
+ // Cancel any current running jobs first
+ Job[] currentJobs = LintJob.getCurrentJobs();
+ for (Job job : currentJobs) {
+ job.cancel();
+ }
+
+ if (wait) {
+ for (Job job : currentJobs) {
+ try {
+ job.join();
+ } catch (InterruptedException e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+ }
+ }
+
+ /** If the resource list contains projects, add in any library projects as well */
+ private static List<? extends IResource> addLibraries(List<? extends IResource> resources) {
+ if (resources != null && !resources.isEmpty()) {
+ boolean haveProjects = false;
+ for (IResource resource : resources) {
+ if (resource instanceof IProject) {
+ haveProjects = true;
+ break;
+ }
+ }
+
+ if (haveProjects) {
+ List<IResource> result = new ArrayList<IResource>();
+ Map<IProject, IProject> allProjects = new IdentityHashMap<IProject, IProject>();
+ List<IProject> projects = new ArrayList<IProject>();
+ for (IResource resource : resources) {
+ if (resource instanceof IProject) {
+ IProject project = (IProject) resource;
+ allProjects.put(project, project);
+ projects.add(project);
+ } else {
+ result.add(resource);
+ }
+ }
+ for (IProject project : projects) {
+ ProjectState state = Sdk.getProjectState(project);
+ if (state != null) {
+ for (IProject library : state.getFullLibraryProjects()) {
+ allProjects.put(library, library);
+ }
+ }
+ }
+ for (IProject project : allProjects.keySet()) {
+ result.add(project);
+ }
+
+ return result;
+ }
+ }
+
+ return resources;
+ }
+}