| /* |
| * Copyright (C) 2012 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 static com.android.SdkConstants.DOT_CLASS; |
| import static com.android.SdkConstants.DOT_JAVA; |
| import static com.android.SdkConstants.DOT_XML; |
| |
| import com.android.SdkConstants; |
| 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.tools.lint.client.api.IssueRegistry; |
| import com.android.tools.lint.client.api.LintDriver; |
| import com.android.tools.lint.client.api.LintRequest; |
| import com.android.tools.lint.detector.api.Issue; |
| import com.android.tools.lint.detector.api.Scope; |
| import com.android.utils.SdkUtils; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.IJobManager; |
| import org.eclipse.core.runtime.jobs.Job; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.EnumSet; |
| import java.util.List; |
| |
| /** Job to check lint on a set of resources */ |
| public final class LintJob extends Job { |
| /** Job family */ |
| private static final Object FAMILY_RUN_LINT = new Object(); |
| private final EclipseLintClient mClient; |
| private final List<? extends IResource> mResources; |
| private final IResource mSource; |
| private final IssueRegistry mRegistry; |
| private LintDriver mLint; |
| private boolean mFatal; |
| |
| public LintJob( |
| @NonNull EclipseLintClient client, |
| @NonNull List<? extends IResource> resources, |
| @Nullable IResource source, |
| @NonNull IssueRegistry registry) { |
| super("Running Android Lint"); |
| mClient = client; |
| mResources = resources; |
| mSource = source; |
| mRegistry = registry; |
| } |
| |
| public LintJob( |
| @NonNull EclipseLintClient client, |
| @NonNull List<? extends IResource> resources, |
| @Nullable IResource source) { |
| this(client, resources, source, EclipseLintClient.getRegistry()); |
| } |
| |
| @Override |
| public boolean belongsTo(Object family) { |
| return family == FAMILY_RUN_LINT; |
| } |
| |
| @Override |
| protected void canceling() { |
| super.canceling(); |
| if (mLint != null) { |
| mLint.cancel(); |
| } |
| } |
| |
| @Override |
| @NonNull |
| protected IStatus run(IProgressMonitor monitor) { |
| try { |
| monitor.beginTask("Looking for errors", IProgressMonitor.UNKNOWN); |
| EnumSet<Scope> scope = null; |
| List<File> files = new ArrayList<File>(mResources.size()); |
| for (IResource resource : mResources) { |
| File file = AdtUtils.getAbsolutePath(resource).toFile(); |
| files.add(file); |
| |
| if (resource instanceof IProject && mSource == null) { |
| scope = Scope.ALL; |
| } else { |
| String name = resource.getName(); |
| if (SdkUtils.endsWithIgnoreCase(name, DOT_XML)) { |
| if (name.equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) { |
| scope = EnumSet.of(Scope.MANIFEST); |
| } else { |
| scope = Scope.RESOURCE_FILE_SCOPE; |
| } |
| } else if (name.endsWith(DOT_JAVA) && resource instanceof IFile) { |
| if (scope != null) { |
| if (!scope.contains(Scope.JAVA_FILE)) { |
| scope = EnumSet.copyOf(scope); |
| scope.add(Scope.JAVA_FILE); |
| } |
| } else { |
| scope = Scope.JAVA_FILE_SCOPE; |
| } |
| } else if (name.endsWith(DOT_CLASS) && resource instanceof IFile) { |
| if (scope != null) { |
| if (!scope.contains(Scope.CLASS_FILE)) { |
| scope = EnumSet.copyOf(scope); |
| scope.add(Scope.CLASS_FILE); |
| } |
| } else { |
| scope = Scope.CLASS_FILE_SCOPE; |
| } |
| } else { |
| return new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, Status.ERROR, |
| "Only XML & Java files are supported for single file lint", null); //$NON-NLS-1$ |
| } |
| } |
| } |
| if (scope == null) { |
| scope = Scope.ALL; |
| } |
| if (mSource == null) { |
| assert !Scope.checkSingleFile(scope) : scope + " with " + mResources; |
| } |
| // Check single file? |
| if (mSource != null) { |
| // Delete specific markers |
| IMarker[] markers = EclipseLintClient.getMarkers(mSource); |
| for (IMarker marker : markers) { |
| String id = marker.getAttribute(EclipseLintRunner.MARKER_CHECKID_PROPERTY, ""); |
| Issue issue = mRegistry.getIssue(id); |
| if (issue == null) { |
| continue; |
| } |
| if (issue.getImplementation().isAdequate(scope)) { |
| marker.delete(); |
| } |
| } |
| mClient.setSearchForSuperClasses(true); |
| } else { |
| EclipseLintClient.clearMarkers(mResources); |
| } |
| |
| mLint = new LintDriver(mRegistry, mClient); |
| mLint.analyze(new LintRequest(mClient, files).setScope(scope)); |
| mFatal = mClient.hasFatalErrors(); |
| return Status.OK_STATUS; |
| } catch (Exception e) { |
| return new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, Status.ERROR, |
| "Failed", e); //$NON-NLS-1$ |
| } finally { |
| if (monitor != null) { |
| monitor.done(); |
| } |
| } |
| } |
| |
| /** |
| * Returns true if a fatal error was encountered |
| * |
| * @return true if a fatal error was encountered |
| */ |
| public boolean isFatal() { |
| return mFatal; |
| } |
| |
| /** |
| * Returns the associated lint client |
| * |
| * @return the associated lint client |
| */ |
| @NonNull |
| public EclipseLintClient getLintClient() { |
| return mClient; |
| } |
| |
| /** Returns the current lint jobs, if any (never returns null but array may be empty) */ |
| @NonNull |
| static Job[] getCurrentJobs() { |
| IJobManager jobManager = Job.getJobManager(); |
| return jobManager.find(LintJob.FAMILY_RUN_LINT); |
| } |
| } |