blob: 51fa2d145ece6a9195c4a86932547543c4849378 [file] [log] [blame]
/*
* 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);
}
}