blob: fe7443c521a99739b845f18f34ced4c1feec7ff1 [file] [log] [blame]
package org.jetbrains.android.inspections.lint;
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.google.common.collect.Lists;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.GlobalInspectionContext;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.codeInspection.ex.Tools;
import com.intellij.codeInspection.lang.GlobalInspectionContextExtension;
import com.intellij.facet.ProjectFacetManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.module.impl.scopes.ModuleWithDependenciesScope;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.ProgressWrapper;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
class AndroidLintGlobalInspectionContext implements GlobalInspectionContextExtension<AndroidLintGlobalInspectionContext> {
static final Key<AndroidLintGlobalInspectionContext> ID = Key.create("AndroidLintGlobalInspectionContext");
private Map<Issue, Map<File, List<ProblemData>>> myResults;
@NotNull
@Override
public Key<AndroidLintGlobalInspectionContext> getID() {
return ID;
}
@Override
public void performPreRunActivities(@NotNull List<Tools> globalTools, @NotNull List<Tools> localTools, @NotNull final GlobalInspectionContext context) {
final Project project = context.getProject();
if (!ProjectFacetManager.getInstance(project).hasFacets(AndroidFacet.ID)) {
return;
}
final List<Issue> issues = AndroidLintExternalAnnotator.getIssuesFromInspections(project, null);
if (issues.size() == 0) {
return;
}
final Map<Issue, Map<File, List<ProblemData>>> problemMap = new HashMap<Issue, Map<File, List<ProblemData>>>();
final AnalysisScope scope = context.getRefManager().getScope();
if (scope == null) {
return;
}
final IntellijLintClient client = IntellijLintClient.forBatch(project, problemMap, scope, issues);
final LintDriver lint = new LintDriver(new IntellijLintIssueRegistry(), client);
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
ProgressWrapper.unwrap(indicator).setText("Running Android Lint");
}
EnumSet<Scope> lintScope;
//noinspection ConstantConditions
if (!IntellijLintProject.SUPPORT_CLASS_FILES) {
lintScope = EnumSet.copyOf(Scope.ALL);
// Can't run class file based checks
lintScope.remove(Scope.CLASS_FILE);
lintScope.remove(Scope.ALL_CLASS_FILES);
lintScope.remove(Scope.JAVA_LIBRARIES);
} else {
lintScope = Scope.ALL;
}
List<VirtualFile> files = null;
final List<Module> modules = Lists.newArrayList();
int scopeType = scope.getScopeType();
switch (scopeType) {
case AnalysisScope.MODULE: {
SearchScope searchScope = scope.toSearchScope();
if (searchScope instanceof ModuleWithDependenciesScope) {
ModuleWithDependenciesScope s = (ModuleWithDependenciesScope)searchScope;
if (!s.isSearchInLibraries()) {
modules.add(s.getModule());
}
}
break;
}
case AnalysisScope.FILE:
case AnalysisScope.VIRTUAL_FILES:
case AnalysisScope.UNCOMMITTED_FILES: {
files = Lists.newArrayList();
SearchScope searchScope = scope.toSearchScope();
if (searchScope instanceof LocalSearchScope) {
final LocalSearchScope localSearchScope = (LocalSearchScope)searchScope;
final PsiElement[] elements = localSearchScope.getScope();
final List<VirtualFile> finalFiles = files;
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
for (PsiElement element : elements) {
if (element instanceof PsiFile) { // should be the case since scope type is FILE
Module module = ModuleUtilCore.findModuleForPsiElement(element);
if (module != null && !modules.contains(module)) {
modules.add(module);
}
VirtualFile virtualFile = ((PsiFile)element).getVirtualFile();
if (virtualFile != null) {
finalFiles.add(virtualFile);
}
}
}
}
});
} else {
final List<VirtualFile> finalList = files;
scope.accept(new PsiElementVisitor() {
@Override
public void visitFile(PsiFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null) {
finalList.add(virtualFile);
}
}
});
}
if (files.isEmpty()) {
files = null;
} else {
// Lint will compute it lazily based on actual files in the request
lintScope = null;
}
break;
}
case AnalysisScope.PROJECT: {
modules.addAll(Arrays.asList(ModuleManager.getInstance(project).getModules()));
break;
}
case AnalysisScope.CUSTOM:
case AnalysisScope.MODULES:
case AnalysisScope.DIRECTORY: {
// Handled by the getNarrowedComplementaryScope case below
break;
}
case AnalysisScope.INVALID:
break;
default:
Logger.getInstance(this.getClass()).warn("Unexpected inspection scope " + scope + ", " + scopeType);
}
if (modules.isEmpty()) {
for (Module module : ModuleManager.getInstance(project).getModules()) {
if (scope.containsModule(module)) {
modules.add(module);
}
}
if (modules.isEmpty() && files != null) {
for (VirtualFile file : files) {
Module module = ModuleUtilCore.findModuleForFile(file, project);
if (module != null && !modules.contains(module)) {
modules.add(module);
}
}
}
if (modules.isEmpty()) {
AnalysisScope narrowed = scope.getNarrowedComplementaryScope(project);
for (Module module : ModuleManager.getInstance(project).getModules()) {
if (narrowed.containsModule(module)) {
modules.add(module);
}
}
}
}
LintRequest request = new IntellijLintRequest(client, project, files, modules, false);
request.setScope(lintScope);
lint.analyze(request);
myResults = problemMap;
}
@Nullable
public Map<Issue, Map<File, List<ProblemData>>> getResults() {
return myResults;
}
@Override
public void performPostRunActivities(@NotNull List<InspectionToolWrapper> inspections, @NotNull final GlobalInspectionContext context) {
}
@Override
public void cleanup() {
}
}