diff options
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.java | 238 |
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; + } +} |