mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-125474 Local inspections run globally should use multiple cores
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,7 +41,8 @@ public interface GlobalInspectionContext extends UserDataHolder {
|
||||
*
|
||||
* @return the reference graph instance.
|
||||
*/
|
||||
@NotNull RefManager getRefManager();
|
||||
@NotNull
|
||||
RefManager getRefManager();
|
||||
|
||||
/**
|
||||
* Checks if the inspection with the specified ID is suppressed for the
|
||||
@@ -52,7 +53,7 @@ public interface GlobalInspectionContext extends UserDataHolder {
|
||||
* @return true if the inspection is suppressed, false otherwise.
|
||||
* @deprecated use #shouldCheck instead
|
||||
*/
|
||||
boolean isSuppressed(RefEntity entity, String inspectionToolId);
|
||||
boolean isSuppressed(@NotNull RefEntity entity, @NotNull String inspectionToolId);
|
||||
|
||||
/**
|
||||
* Checks if the inspection is suppressed for the specified reference graph node. Should not be called manually in normal case.
|
||||
@@ -61,7 +62,7 @@ public interface GlobalInspectionContext extends UserDataHolder {
|
||||
* @param tool the inspection to check.
|
||||
* @return true if the inspection is suppressed, false otherwise.
|
||||
*/
|
||||
boolean shouldCheck(RefEntity entity, GlobalInspectionTool tool);
|
||||
boolean shouldCheck(@NotNull RefEntity entity, @NotNull GlobalInspectionTool tool);
|
||||
|
||||
/**
|
||||
* Checks if the inspection with the specified ID is suppressed for the
|
||||
@@ -76,9 +77,9 @@ public interface GlobalInspectionContext extends UserDataHolder {
|
||||
@NotNull
|
||||
Project getProject();
|
||||
|
||||
<T> T getExtension(Key<T> key);
|
||||
<T> T getExtension(@NotNull Key<T> key);
|
||||
|
||||
void incrementJobDoneAmount(JobDescriptor job, String message);
|
||||
void incrementJobDoneAmount(@NotNull JobDescriptor job, @NotNull String message);
|
||||
|
||||
@NotNull
|
||||
StdJobDescriptors getStdJobDescriptors();
|
||||
|
||||
+31
-37
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,7 @@ import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -69,10 +69,10 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
|
||||
private AnalysisScope myCurrentScope;
|
||||
private final Project myProject;
|
||||
private List<JobDescriptor> myJobDescriptors;
|
||||
private final List<JobDescriptor> myJobDescriptors = new ArrayList<JobDescriptor>();
|
||||
|
||||
private final StdJobDescriptors myStdJobDescriptors = new StdJobDescriptors();
|
||||
protected ProgressIndicator myProgressIndicator;
|
||||
protected ProgressIndicator myProgressIndicator = new EmptyProgressIndicator();
|
||||
|
||||
private InspectionProfile myExternalProfile;
|
||||
|
||||
@@ -82,8 +82,6 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
|
||||
@NonNls public static final String LOCAL_TOOL_ATTRIBUTE = "is_local_tool";
|
||||
|
||||
private boolean myUseProgressIndicatorInTests = false;
|
||||
|
||||
public GlobalInspectionContextBase(@NotNull Project project) {
|
||||
myProject = project;
|
||||
|
||||
@@ -93,7 +91,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
}
|
||||
|
||||
public AnalysisScope getCurrentScope() {
|
||||
AnalysisScope getCurrentScope() {
|
||||
return myCurrentScope;
|
||||
}
|
||||
|
||||
@@ -104,7 +102,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getExtension(final Key<T> key) {
|
||||
public <T> T getExtension(@NotNull final Key<T> key) {
|
||||
//noinspection unchecked
|
||||
return (T)myExtensions.get(key);
|
||||
}
|
||||
@@ -130,12 +128,12 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressed(RefEntity entity, String id) {
|
||||
public boolean isSuppressed(@NotNull RefEntity entity, @NotNull String id) {
|
||||
return entity instanceof RefElementImpl && ((RefElementImpl)entity).isSuppressed(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCheck(RefEntity entity, GlobalInspectionTool tool) {
|
||||
public boolean shouldCheck(@NotNull RefEntity entity, @NotNull GlobalInspectionTool tool) {
|
||||
return !(entity instanceof RefElementImpl) || isToCheckMember((RefElementImpl)entity, tool);
|
||||
}
|
||||
|
||||
@@ -150,9 +148,8 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
|
||||
|
||||
protected void cleanupTools() {
|
||||
myProgressIndicator = null;
|
||||
|
||||
void cleanupTools() {
|
||||
myProgressIndicator.cancel();
|
||||
for (GlobalInspectionContextExtension extension : myExtensions.values()) {
|
||||
extension.cleanup();
|
||||
}
|
||||
@@ -178,6 +175,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
myCurrentScope = null;
|
||||
}
|
||||
}
|
||||
myJobDescriptors.clear();
|
||||
}
|
||||
|
||||
public void setCurrentScope(@NotNull AnalysisScope currentScope) {
|
||||
@@ -231,6 +229,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
|
||||
protected void launchInspections(@NotNull final AnalysisScope scope) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
||||
|
||||
LOG.info("Code inspection started");
|
||||
@@ -238,7 +237,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
createOption()) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
performInspectionsWithProgress(scope, false);
|
||||
performInspectionsWithProgress(scope, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -248,6 +247,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected PerformInBackgroundOption createOption() {
|
||||
return new PerformInBackgroundOption(){
|
||||
@Override
|
||||
@@ -265,9 +265,12 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
protected void notifyInspectionsFinished() {
|
||||
}
|
||||
|
||||
public void performInspectionsWithProgress(@NotNull final AnalysisScope scope, final boolean runGlobalToolsOnly) {
|
||||
public void performInspectionsWithProgress(@NotNull final AnalysisScope scope, final boolean runGlobalToolsOnly, final boolean isOfflineInspections) {
|
||||
myProgressIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (myProgressIndicator == null) {
|
||||
throw new IllegalStateException("Inspections must be run under progress");
|
||||
}
|
||||
final PsiManager psiManager = PsiManager.getInstance(myProject);
|
||||
myProgressIndicator = getProgressIndicator();
|
||||
//init manager in read action
|
||||
RefManagerImpl refManager = (RefManagerImpl)getRefManager();
|
||||
try {
|
||||
@@ -280,7 +283,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runTools(scope, runGlobalToolsOnly);
|
||||
runTools(scope, runGlobalToolsOnly, isOfflineInspections);
|
||||
}
|
||||
}, ProgressWrapper.wrap(myProgressIndicator));
|
||||
}
|
||||
@@ -302,24 +305,13 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
}
|
||||
|
||||
private ProgressIndicator getProgressIndicator() {
|
||||
return ApplicationManager.getApplication().isUnitTestMode() && !myUseProgressIndicatorInTests
|
||||
? new EmptyProgressIndicator() : ProgressManager.getInstance().getProgressIndicator();
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void setUseProgressIndicatorInTests(boolean useProgressIndicatorInTests) {
|
||||
myUseProgressIndicatorInTests = useProgressIndicatorInTests;
|
||||
}
|
||||
|
||||
protected void runTools(@NotNull AnalysisScope scope, boolean runGlobalToolsOnly) {
|
||||
protected void runTools(@NotNull AnalysisScope scope, boolean runGlobalToolsOnly, boolean isOfflineInspections) {
|
||||
}
|
||||
|
||||
|
||||
public void initializeTools(@NotNull List<Tools> outGlobalTools,
|
||||
@NotNull List<Tools> outLocalTools,
|
||||
@NotNull List<Tools> outGlobalSimpleTools) {
|
||||
myJobDescriptors = new ArrayList<JobDescriptor>();
|
||||
final List<Tools> usedTools = getUsedTools();
|
||||
for (Tools currentTools : usedTools) {
|
||||
final String shortName = currentTools.getShortName();
|
||||
@@ -341,6 +333,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected List<Tools> getUsedTools() {
|
||||
InspectionProfileImpl profile = new InspectionProfileImpl((InspectionProfileImpl)getCurrentProfile());
|
||||
List<Tools> tools = profile.getAllEnabledInspectionTools(myProject);
|
||||
@@ -391,26 +384,27 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
return myTools;
|
||||
}
|
||||
|
||||
public void appendJobDescriptor(@NotNull JobDescriptor job) {
|
||||
private void appendJobDescriptor(@NotNull JobDescriptor job) {
|
||||
if (!myJobDescriptors.contains(job)) {
|
||||
myJobDescriptors.add(job);
|
||||
job.setDoneAmount(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void codeCleanup(final Project project,
|
||||
final AnalysisScope scope,
|
||||
final InspectionProfile profile,
|
||||
final String commandName, Runnable postRunnable,
|
||||
public void codeCleanup(@NotNull Project project,
|
||||
@NotNull AnalysisScope scope,
|
||||
@NotNull InspectionProfile profile,
|
||||
@Nullable String commandName,
|
||||
@Nullable Runnable postRunnable,
|
||||
final boolean modal) {}
|
||||
|
||||
public static void codeCleanup(Project project, AnalysisScope scope, Runnable runnable) {
|
||||
public static void codeCleanup(@NotNull Project project, @NotNull AnalysisScope scope, @Nullable Runnable runnable) {
|
||||
GlobalInspectionContextBase globalContext = (GlobalInspectionContextBase)InspectionManager.getInstance(project).createNewGlobalContext(false);
|
||||
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
|
||||
globalContext.codeCleanup(project, scope, profile, null, runnable, false);
|
||||
}
|
||||
|
||||
public static void cleanupElements(final Project project, final Runnable runnable, final PsiElement... scope) {
|
||||
public static void cleanupElements(@NotNull final Project project, @Nullable final Runnable runnable, @NotNull PsiElement... scope) {
|
||||
final List<SmartPsiElementPointer<PsiElement>> elements = new ArrayList<SmartPsiElementPointer<PsiElement>>();
|
||||
final SmartPointerManager manager = SmartPointerManager.getInstance(project);
|
||||
for (PsiElement element : scope) {
|
||||
@@ -456,7 +450,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementJobDoneAmount(JobDescriptor job, String message) {
|
||||
public void incrementJobDoneAmount(@NotNull JobDescriptor job, @NotNull String message) {
|
||||
if (myProgressIndicator == null) return;
|
||||
|
||||
ProgressManager.checkCanceled();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,12 @@
|
||||
package com.intellij.psi.util;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.FileASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
@@ -30,10 +33,13 @@ import com.intellij.psi.meta.PsiMetaData;
|
||||
import com.intellij.psi.meta.PsiMetaOwner;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiElementProcessor;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.TimeoutUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -45,7 +51,8 @@ import java.util.Collection;
|
||||
*/
|
||||
public class PsiUtilCore {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.PsiUtilCore");
|
||||
public static final PsiElement NULL_PSI_ELEMENT = new PsiElement() {
|
||||
public static final PsiElement NULL_PSI_ELEMENT = new NullPsiElement();
|
||||
private static class NullPsiElement implements PsiElement {
|
||||
@Override
|
||||
@NotNull
|
||||
public Project getProject() {
|
||||
@@ -250,8 +257,8 @@ public class PsiUtilCore {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
private PsiInvalidElementAccessException createException() {
|
||||
return new PsiInvalidElementAccessException(this, "NULL_PSI_ELEMENT", null);
|
||||
protected PsiInvalidElementAccessException createException() {
|
||||
return new PsiInvalidElementAccessException(this, toString(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -335,7 +342,7 @@ public class PsiUtilCore {
|
||||
public String toString() {
|
||||
return "NULL_PSI_ELEMENT";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiElement[] toPsiElementArray(@NotNull Collection<? extends PsiElement> collection) {
|
||||
@@ -467,7 +474,6 @@ public class PsiUtilCore {
|
||||
* Checks if the element is valid. If not, throws {@link com.intellij.psi.PsiInvalidElementAccessException} with
|
||||
* a meaningful message that points to the reasons why the element is not valid and may contain the stack trace
|
||||
* when it was invalidated.
|
||||
* @param element
|
||||
*/
|
||||
public static void ensureValid(@NotNull PsiElement element) {
|
||||
if (!element.isValid()) {
|
||||
@@ -547,4 +553,113 @@ public class PsiUtilCore {
|
||||
public static IElementType getElementType(@Nullable PsiElement element) {
|
||||
return element == null ? null : getElementType(element.getNode());
|
||||
}
|
||||
|
||||
public static final PsiFile NULL_PSI_FILE = new NullPsiFile();
|
||||
private static class NullPsiFile extends NullPsiElement implements PsiFile {
|
||||
@Override
|
||||
public FileASTNode getNode() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiDirectory getParent() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getVirtualFile() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiDirectory getContainingDirectory() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getModificationStamp() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiFile getOriginalFile() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileType getFileType() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiFile[] getPsiRoots() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileViewProvider getViewProvider() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subtreeChanged() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processChildren(PsiElementProcessor<PsiFileSystemItem> processor) {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemPresentation getPresentation() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigate(boolean requestFocus) {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigate() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigateToSource() {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSetName(String name) throws IncorrectOperationException {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
|
||||
throw createException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NULL_PSI_FILE";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+222
-159
@@ -33,17 +33,21 @@ import com.intellij.codeInspection.ui.DefaultInspectionToolPresentation;
|
||||
import com.intellij.codeInspection.ui.InspectionResultsView;
|
||||
import com.intellij.codeInspection.ui.InspectionToolPresentation;
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.concurrency.JobSchedulerImpl;
|
||||
import com.intellij.concurrency.JobLauncherImpl;
|
||||
import com.intellij.concurrency.SensitiveProgressWrapper;
|
||||
import com.intellij.lang.annotation.ProblemGroup;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.notification.NotificationGroup;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.progress.*;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectUtilCore;
|
||||
@@ -59,6 +63,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.content.*;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -79,14 +84,16 @@ import java.util.*;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class GlobalInspectionContextImpl extends GlobalInspectionContextBase implements GlobalInspectionContext {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl");
|
||||
private static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("Inspection Results", ToolWindowId.INSPECTION);
|
||||
private final NotNullLazyValue<ContentManager> myContentManager;
|
||||
private InspectionResultsView myView = null;
|
||||
private Content myContent = null;
|
||||
private InspectionResultsView myView;
|
||||
private Content myContent;
|
||||
|
||||
@NotNull
|
||||
private AnalysisUIOptions myUIOptions;
|
||||
|
||||
public GlobalInspectionContextImpl(@NotNull Project project, @NotNull NotNullLazyValue<ContentManager> contentManager) {
|
||||
@@ -96,11 +103,12 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
myContentManager = contentManager;
|
||||
}
|
||||
|
||||
public ContentManager getContentManager() {
|
||||
@NotNull
|
||||
private ContentManager getContentManager() {
|
||||
return myContentManager.getValue();
|
||||
}
|
||||
|
||||
public synchronized void addView(@NotNull InspectionResultsView view, String title) {
|
||||
public synchronized void addView(@NotNull InspectionResultsView view, @NotNull String title) {
|
||||
if (myContent != null) return;
|
||||
myContentManager.getValue().addContentManagerListener(new ContentManagerAdapter() {
|
||||
@Override
|
||||
@@ -153,84 +161,8 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
performInspectionsWithProgress(scope, runGlobalToolsOnly);
|
||||
@NonNls final String ext = ".xml";
|
||||
final Map<Element, Tools> globalTools = new HashMap<Element, Tools>();
|
||||
for (Map.Entry<String,Tools> stringSetEntry : myTools.entrySet()) {
|
||||
final Tools sameTools = stringSetEntry.getValue();
|
||||
boolean hasProblems = false;
|
||||
String toolName = stringSetEntry.getKey();
|
||||
if (sameTools != null) {
|
||||
for (ScopeToolState toolDescr : sameTools.getTools()) {
|
||||
InspectionToolWrapper toolWrapper = toolDescr.getTool();
|
||||
if (toolWrapper instanceof LocalInspectionToolWrapper) {
|
||||
hasProblems = new File(outputPath, toolName + ext).exists();
|
||||
}
|
||||
else {
|
||||
InspectionToolPresentation presentation = getPresentation(toolWrapper);
|
||||
presentation.updateContent();
|
||||
if (presentation.hasReportedProblems()) {
|
||||
final Element root = new Element(InspectionsBundle.message("inspection.problems"));
|
||||
globalTools.put(root, sameTools);
|
||||
LOG.assertTrue(!hasProblems, toolName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasProblems) continue;
|
||||
try {
|
||||
new File(outputPath).mkdirs();
|
||||
final File file = new File(outputPath, toolName + ext);
|
||||
inspectionsResults.add(file);
|
||||
FileUtil.writeToFile(file, ("</" + InspectionsBundle.message("inspection.problems") + ">").getBytes(CharsetToolkit.UTF8_CHARSET), true);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
getRefManager().iterate(new RefVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull final RefEntity refEntity) {
|
||||
for (Element element : globalTools.keySet()) {
|
||||
final Tools tools = globalTools.get(element);
|
||||
for (ScopeToolState state : tools.getTools()) {
|
||||
try {
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
InspectionToolPresentation presentation = getPresentation(toolWrapper);
|
||||
presentation.exportResults(element, refEntity);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error("Problem when exporting: " + refEntity.getExternalName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (Element element : globalTools.keySet()) {
|
||||
final String toolName = globalTools.get(element).getShortName();
|
||||
element.setAttribute(LOCAL_TOOL_ATTRIBUTE, Boolean.toString(false));
|
||||
final org.jdom.Document doc = new org.jdom.Document(element);
|
||||
PathMacroManager.getInstance(getProject()).collapsePaths(doc.getRootElement());
|
||||
try {
|
||||
new File(outputPath).mkdirs();
|
||||
final File file = new File(outputPath, toolName + ext);
|
||||
inspectionsResults.add(file);
|
||||
|
||||
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), CharsetToolkit.UTF8_CHARSET);
|
||||
try {
|
||||
JDOMUtil.writeDocument(doc, writer, "\n");
|
||||
}
|
||||
finally {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
performInspectionsWithProgress(scope, runGlobalToolsOnly, true);
|
||||
exportResults(inspectionsResults, outputPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -239,7 +171,91 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
}
|
||||
|
||||
public void ignoreElement(@NotNull InspectionProfileEntry tool, final PsiElement element) {
|
||||
private void exportResults(@NotNull List<File> inspectionsResults, @Nullable String outputPath) {
|
||||
@NonNls final String ext = ".xml";
|
||||
final Map<Element, Tools> globalTools = new HashMap<Element, Tools>();
|
||||
for (Map.Entry<String,Tools> entry : myTools.entrySet()) {
|
||||
final Tools sameTools = entry.getValue();
|
||||
boolean hasProblems = false;
|
||||
String toolName = entry.getKey();
|
||||
if (sameTools != null) {
|
||||
for (ScopeToolState toolDescr : sameTools.getTools()) {
|
||||
InspectionToolWrapper toolWrapper = toolDescr.getTool();
|
||||
if (toolWrapper instanceof LocalInspectionToolWrapper) {
|
||||
hasProblems = new File(outputPath, toolName + ext).exists();
|
||||
}
|
||||
else {
|
||||
InspectionToolPresentation presentation = getPresentation(toolWrapper);
|
||||
presentation.updateContent();
|
||||
if (presentation.hasReportedProblems()) {
|
||||
final Element root = new Element(InspectionsBundle.message("inspection.problems"));
|
||||
globalTools.put(root, sameTools);
|
||||
LOG.assertTrue(!hasProblems, toolName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasProblems) {
|
||||
try {
|
||||
new File(outputPath).mkdirs();
|
||||
final File file = new File(outputPath, toolName + ext);
|
||||
inspectionsResults.add(file);
|
||||
FileUtil
|
||||
.writeToFile(file, ("</" + InspectionsBundle.message("inspection.problems") + ">").getBytes(CharsetToolkit.UTF8_CHARSET), true);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getRefManager().iterate(new RefVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull final RefEntity refEntity) {
|
||||
for (Map.Entry<Element, Tools> entry : globalTools.entrySet()) {
|
||||
Tools tools = entry.getValue();
|
||||
Element element = entry.getKey();
|
||||
for (ScopeToolState state : tools.getTools()) {
|
||||
try {
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
InspectionToolPresentation presentation = getPresentation(toolWrapper);
|
||||
presentation.exportResults(element, refEntity);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error("Problem when exporting: " + refEntity.getExternalName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (Map.Entry<Element, Tools> entry : globalTools.entrySet()) {
|
||||
final String toolName = entry.getValue().getShortName();
|
||||
Element element = entry.getKey();
|
||||
element.setAttribute(LOCAL_TOOL_ATTRIBUTE, Boolean.toString(false));
|
||||
final org.jdom.Document doc = new org.jdom.Document(element);
|
||||
PathMacroManager.getInstance(getProject()).collapsePaths(doc.getRootElement());
|
||||
try {
|
||||
new File(outputPath).mkdirs();
|
||||
final File file = new File(outputPath, toolName + ext);
|
||||
inspectionsResults.add(file);
|
||||
|
||||
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), CharsetToolkit.UTF8_CHARSET);
|
||||
try {
|
||||
JDOMUtil.writeDocument(doc, writer, "\n");
|
||||
}
|
||||
finally {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ignoreElement(@NotNull InspectionProfileEntry tool, @NotNull PsiElement element) {
|
||||
final RefElement refElement = getRefManager().getReference(element);
|
||||
final Tools tools = myTools.get(tool.getShortName());
|
||||
if (tools != null){
|
||||
@@ -267,6 +283,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AnalysisUIOptions getUIOptions() {
|
||||
return myUIOptions;
|
||||
}
|
||||
@@ -275,6 +292,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
myUIOptions.SPLITTER_PROPORTION = proportion;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ToggleAction createToggleAutoscrollAction() {
|
||||
return myUIOptions.getAutoScrollToSourceHandler().createToggleAction();
|
||||
}
|
||||
@@ -286,6 +304,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
super.launchInspections(scope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PerformInBackgroundOption createOption() {
|
||||
return new PerformAnalysisInBackgroundOption(getProject());
|
||||
@@ -313,10 +332,21 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTools(@NotNull final AnalysisScope scope, boolean runGlobalToolsOnly) {
|
||||
protected void runTools(@NotNull final AnalysisScope scope, boolean runGlobalToolsOnly, boolean isOfflineInspections) {
|
||||
final ProgressIndicator progressIndicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
|
||||
if (progressIndicator == null) {
|
||||
throw new IncorrectOperationException("Must be run under progress");
|
||||
}
|
||||
if (!isOfflineInspections && ApplicationManager.getApplication().isDispatchThread()) {
|
||||
throw new IncorrectOperationException("Must not start inspections from within EDT");
|
||||
}
|
||||
if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
throw new IncorrectOperationException("Must not start inspections from within write action");
|
||||
}
|
||||
// in offline inspection application we don't care about global read action
|
||||
if (!isOfflineInspections && ApplicationManager.getApplication().isReadAccessAllowed()) {
|
||||
throw new IncorrectOperationException("Must not start inspections from within global read action");
|
||||
}
|
||||
final InspectionManager inspectionManager = InspectionManager.getInstance(getProject());
|
||||
final List<Tools> globalTools = new ArrayList<Tools>();
|
||||
final List<Tools> localTools = new ArrayList<Tools>();
|
||||
@@ -325,7 +355,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
appendPairedInspectionsForUnfairTools(globalTools, globalSimpleTools, localTools);
|
||||
|
||||
((RefManagerImpl)getRefManager()).initializeAnnotators();
|
||||
runGlobalTools(scope, inspectionManager, globalTools);
|
||||
runGlobalTools(scope, inspectionManager, globalTools, isOfflineInspections);
|
||||
|
||||
if (runGlobalToolsOnly) return;
|
||||
|
||||
@@ -339,20 +369,57 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
final boolean headlessEnvironment = ApplicationManager.getApplication().isHeadlessEnvironment();
|
||||
final Map<String, InspectionToolWrapper> map = getInspectionWrappersMap(localTools);
|
||||
|
||||
final BlockingQueue<List<PsiFile>> chunksToInspect = new ArrayBlockingQueue<List<PsiFile>>(10);
|
||||
startIterateScopeIntoChunks(scope, localScopeFiles, headlessEnvironment, chunksToInspect);
|
||||
try {
|
||||
for (List<PsiFile> chunk = chunksToInspect.take(); !chunk.isEmpty(); chunk = chunksToInspect.take()) {
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(chunk, myProgressIndicator, true, false, new Processor<PsiFile>() {
|
||||
final BlockingQueue<PsiFile> filesToInspect = new ArrayBlockingQueue<PsiFile>(1000);
|
||||
final Queue<PsiFile> filesFailedToInspect = new LinkedBlockingQueue<PsiFile>();
|
||||
// use original progress indicator here since we don't want it to cancel on write action start
|
||||
startIterateScope(scope, localScopeFiles, headlessEnvironment, filesToInspect, progressIndicator);
|
||||
|
||||
Processor<PsiFile> processor = new Processor<PsiFile>() {
|
||||
@Override
|
||||
public boolean process(final PsiFile file) {
|
||||
ProgressManager.checkCanceled();
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() {
|
||||
@Override
|
||||
public boolean process(final PsiFile file) {
|
||||
return inspectFile(file, inspectionManager, localTools, globalSimpleTools, map);
|
||||
public void run() {
|
||||
if (!file.isValid()) {
|
||||
return;
|
||||
}
|
||||
inspectFile(file, inspectionManager, localTools, globalSimpleTools, map);
|
||||
}
|
||||
});
|
||||
})) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
while (true) {
|
||||
Disposable disposable = Disposer.newDisposable();
|
||||
ProgressIndicator wrapper = new SensitiveProgressWrapper(progressIndicator);
|
||||
wrapper.start();
|
||||
ProgressIndicatorUtils.forceWriteActionPriority(wrapper, disposable);
|
||||
|
||||
try {
|
||||
// use wrapper here to cancel early when write action start but do not affect the original indicator
|
||||
((JobLauncherImpl)JobLauncher.getInstance()).processQueue(filesToInspect, filesFailedToInspect, wrapper, TOMBSTONE, processor);
|
||||
break;
|
||||
}
|
||||
catch (ProcessCanceledException ignored) {
|
||||
progressIndicator.checkCanceled();
|
||||
// PCE may be thrown from inside wrapper when write action started
|
||||
// go on with the write and then resume processing the rest of the queue
|
||||
assert !ApplicationManager.getApplication().isReadAccessAllowed();
|
||||
assert !ApplicationManager.getApplication().isDispatchThread();
|
||||
|
||||
// wait for write action to complete
|
||||
ApplicationManager.getApplication().runReadAction(EmptyRunnable.getInstance());
|
||||
}
|
||||
finally {
|
||||
Disposer.dispose(disposable);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
progressIndicator.checkCanceled();
|
||||
|
||||
for (Tools tools : globalSimpleTools) {
|
||||
GlobalInspectionToolWrapper toolWrapper = (GlobalInspectionToolWrapper)tools.getTool();
|
||||
GlobalSimpleInspectionTool tool = (GlobalSimpleInspectionTool)toolWrapper.getTool();
|
||||
@@ -368,6 +435,11 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
@NotNull final Map<String, InspectionToolWrapper> wrappersMap) {
|
||||
Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file);
|
||||
if (document == null) return true;
|
||||
|
||||
VirtualFile virtualFile = file.getVirtualFile();
|
||||
String url = ProjectUtilCore.displayUrlRelativeToProject(virtualFile, virtualFile.getPresentableUrl(), getProject(), true, false);
|
||||
incrementJobDoneAmount(getStdJobDescriptors().LOCAL_ANALYSIS, url);
|
||||
|
||||
final LocalInspectionsPass pass = new LocalInspectionsPass(file, document, 0,
|
||||
file.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true,
|
||||
HighlightInfoProcessor.getEmpty());
|
||||
@@ -409,59 +481,54 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
return true;
|
||||
}
|
||||
|
||||
private void startIterateScopeIntoChunks(@NotNull final AnalysisScope scope,
|
||||
final Set<VirtualFile> localScopeFiles,
|
||||
final boolean headlessEnvironment,
|
||||
@NotNull final BlockingQueue<List<PsiFile>> chunksToInspect) {
|
||||
private static final PsiFile TOMBSTONE = PsiUtilCore.NULL_PSI_FILE;
|
||||
|
||||
private void startIterateScope(@NotNull final AnalysisScope scope,
|
||||
@Nullable final Collection<VirtualFile> localScopeFiles,
|
||||
final boolean headlessEnvironment,
|
||||
@NotNull final BlockingQueue<PsiFile> outFilesToInspect,
|
||||
@NotNull final ProgressIndicator progressIndicator) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final List<PsiFile> chunk = new ArrayList<PsiFile>();
|
||||
try {
|
||||
scope.accept(new Processor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean process(final VirtualFile file) {
|
||||
progressIndicator.checkCanceled();
|
||||
final PsiFile[] psiFile = new PsiFile[1];
|
||||
|
||||
Document document = ApplicationManager.getApplication().runReadAction(new Computable<Document>() {
|
||||
@Override
|
||||
public Document compute() {
|
||||
PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file);
|
||||
Document document = psiFile == null ? null : shouldProcess(psiFile, headlessEnvironment, localScopeFiles);
|
||||
PsiFile psi = PsiManager.getInstance(getProject()).findFile(file);
|
||||
Document document = psi == null ? null : shouldProcess(psi, headlessEnvironment, localScopeFiles);
|
||||
if (document != null) {
|
||||
chunk.add(psiFile);
|
||||
psiFile[0] = psi;
|
||||
}
|
||||
return document;
|
||||
}
|
||||
});
|
||||
//do not inspect binary files
|
||||
if (document != null) {
|
||||
document.getText(); // preload text
|
||||
|
||||
if (chunk.size() >= JobSchedulerImpl.CORES_COUNT) {
|
||||
try {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed());
|
||||
chunksToInspect.put(new ArrayList<PsiFile>(chunk));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
chunk.clear();
|
||||
if (document != null && psiFile[0] != null) {
|
||||
try {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed());
|
||||
outFilesToInspect.put(psiFile[0]);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (!chunk.isEmpty()) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed());
|
||||
chunksToInspect.put(new ArrayList<PsiFile>(chunk));
|
||||
chunk.clear();
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e);
|
||||
catch (ProcessCanceledException e) {
|
||||
// ignore, but put tombstone
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
chunksToInspect.put(Collections.<PsiFile>emptyList()); // tombstone
|
||||
outFilesToInspect.put(TOMBSTONE);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e);
|
||||
@@ -471,7 +538,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
});
|
||||
}
|
||||
|
||||
private Document shouldProcess(@NotNull PsiFile file, boolean headlessEnvironment, Set<VirtualFile> localScopeFiles) {
|
||||
private Document shouldProcess(@NotNull PsiFile file, boolean headlessEnvironment, @Nullable Collection<VirtualFile> localScopeFiles) {
|
||||
final VirtualFile virtualFile = file.getVirtualFile();
|
||||
if (virtualFile == null) return null;
|
||||
if (isBinary(file)) return null; //do not inspect binary files
|
||||
@@ -484,16 +551,17 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
LOG.debug("Running local inspections on " + virtualFile.getPath());
|
||||
}
|
||||
|
||||
String url = ProjectUtilCore.displayUrlRelativeToProject(virtualFile, virtualFile.getPresentableUrl(), getProject(), true, false);
|
||||
incrementJobDoneAmount(getStdJobDescriptors().LOCAL_ANALYSIS, url);
|
||||
if (SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile)) return null;
|
||||
if (localScopeFiles != null && !localScopeFiles.add(virtualFile)) return null;
|
||||
|
||||
return PsiDocumentManager.getInstance(getProject()).getDocument(file);
|
||||
}
|
||||
|
||||
private void runGlobalTools(@NotNull final AnalysisScope scope, @NotNull final InspectionManager inspectionManager, @NotNull List<Tools> globalTools) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed() || ApplicationManager.getApplication().isHeadlessEnvironment(), "Must not run under read action, too unresponsive");
|
||||
private void runGlobalTools(@NotNull final AnalysisScope scope,
|
||||
@NotNull final InspectionManager inspectionManager,
|
||||
@NotNull List<Tools> globalTools,
|
||||
boolean isOfflineInspections) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed() || isOfflineInspections, "Must not run under read action, too unresponsive");
|
||||
final List<InspectionToolWrapper> needRepeatSearchRequest = new ArrayList<InspectionToolWrapper>();
|
||||
|
||||
final boolean canBeExternalUsages = scope.getScopeType() != AnalysisScope.PROJECT;
|
||||
@@ -584,9 +652,11 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends InspectionToolWrapper> List<T> getWrappersFromTools(List<Tools> localTools, PsiFile file) {
|
||||
@NotNull
|
||||
private static <T extends InspectionToolWrapper> List<T> getWrappersFromTools(@NotNull List<Tools> localTools, @NotNull PsiFile file) {
|
||||
final List<T> lTools = new ArrayList<T>();
|
||||
for (Tools tool : localTools) {
|
||||
//noinspection unchecked
|
||||
final T enabledTool = (T)tool.getEnabledTool(file);
|
||||
if (enabledTool != null) {
|
||||
lTools.add(enabledTool);
|
||||
@@ -667,9 +737,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
AnalysisUIOptions.getInstance(getProject()).save(myUIOptions);
|
||||
if (myContent != null) {
|
||||
final ContentManager contentManager = getContentManager();
|
||||
if (contentManager != null) { //null for tests
|
||||
contentManager.removeContent(myContent, true);
|
||||
}
|
||||
contentManager.removeContent(myContent, true);
|
||||
}
|
||||
myView = null;
|
||||
super.close(noSuspisiousCodeFound);
|
||||
@@ -714,36 +782,31 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codeCleanup(final Project project,
|
||||
final AnalysisScope scope,
|
||||
final InspectionProfile profile,
|
||||
final String commandName,
|
||||
final Runnable postRunnable,
|
||||
public void codeCleanup(@NotNull final Project project,
|
||||
@NotNull final AnalysisScope scope,
|
||||
@NotNull final InspectionProfile profile,
|
||||
@Nullable final String commandName,
|
||||
@Nullable final Runnable postRunnable,
|
||||
final boolean modal) {
|
||||
Task task;
|
||||
if (modal) {
|
||||
task = new Task.Modal(project, "Inspect code...", true) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
cleanup(scope, profile, project, postRunnable, commandName);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
task = new Task.Backgroundable(project, "Inspect code...", true) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
cleanup(scope, profile, project, postRunnable, commandName);
|
||||
}
|
||||
};
|
||||
}
|
||||
Task task = modal ? new Task.Modal(project, "Inspect code...", true) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
cleanup(scope, profile, project, postRunnable, commandName);
|
||||
}
|
||||
} : new Task.Backgroundable(project, "Inspect code...", true) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
cleanup(scope, profile, project, postRunnable, commandName);
|
||||
}
|
||||
};
|
||||
ProgressManager.getInstance().run(task);
|
||||
}
|
||||
|
||||
private void cleanup(@NotNull AnalysisScope scope,
|
||||
@NotNull InspectionProfile profile,
|
||||
final Project project,
|
||||
final Runnable postRunnable,
|
||||
final String commandName) {
|
||||
@NotNull final Project project,
|
||||
@Nullable final Runnable postRunnable,
|
||||
@Nullable final String commandName) {
|
||||
final int fileCount = scope.getFileCount();
|
||||
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
final List<LocalInspectionToolWrapper> lTools = new ArrayList<LocalInspectionToolWrapper>();
|
||||
@@ -772,7 +835,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
});
|
||||
scope.accept(new PsiElementVisitor() {
|
||||
private int myCount = 0;
|
||||
private int myCount;
|
||||
@Override
|
||||
public void visitFile(PsiFile file) {
|
||||
if (progressIndicator != null) {
|
||||
@@ -863,7 +926,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBinary(PsiFile file) {
|
||||
private static boolean isBinary(@NotNull PsiFile file) {
|
||||
return file instanceof PsiBinaryFile || file.getFileType().isBinary();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,6 @@ package com.intellij.codeInspection.ex;
|
||||
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.QuickFix;
|
||||
import com.intellij.codeInspection.offlineViewer.OfflineInspectionRVContentProvider;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.ui.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ package com.intellij.codeInspection.ex;
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.reference.*;
|
||||
import com.intellij.codeInspection.ui.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
@@ -94,6 +95,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
|
||||
@NotNull final Map<String, Set<RefEntity>> contents,
|
||||
@NotNull final Map<RefEntity, CommonProblemDescriptor[]> problems,
|
||||
DefaultTreeModel model) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
final InspectionToolWrapper toolWrapper = toolNode.getToolWrapper();
|
||||
|
||||
Function<RefEntity, UserObjectContainer<RefEntity>> computeContainer = new Function<RefEntity, UserObjectContainer<RefEntity>>() {
|
||||
|
||||
+62
-29
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import gnu.trove.Equality;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jdom.Element;
|
||||
@@ -195,7 +196,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProblemElement(RefEntity refElement, boolean filterSuppressed, @NotNull CommonProblemDescriptor... descriptors) {
|
||||
public void addProblemElement(final RefEntity refElement, boolean filterSuppressed, @NotNull final CommonProblemDescriptor... descriptors) {
|
||||
if (refElement == null) return;
|
||||
if (descriptors.length == 0) return;
|
||||
if (filterSuppressed) {
|
||||
@@ -203,7 +204,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
synchronized (lock) {
|
||||
Map<RefEntity, CommonProblemDescriptor[]> problemElements = getProblemElements();
|
||||
CommonProblemDescriptor[] problems = problemElements.get(refElement);
|
||||
problems = problems == null ? descriptors : ArrayUtil.mergeArrays(problems, descriptors, CommonProblemDescriptor.ARRAY_FACTORY);
|
||||
problems = problems == null ? descriptors : mergeDescriptors(problems, descriptors);
|
||||
problemElements.put(refElement, problems);
|
||||
}
|
||||
for (CommonProblemDescriptor description : descriptors) {
|
||||
@@ -227,34 +228,34 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
if (view == null || !(refElement instanceof RefElement)) {
|
||||
return;
|
||||
}
|
||||
final InspectionNode toolNode;
|
||||
synchronized (myToolLock) {
|
||||
if (myToolNode == null) {
|
||||
final HighlightSeverity currentSeverity = getSeverity((RefElement)refElement);
|
||||
toolNode = view.addTool(myToolWrapper, HighlightDisplayLevel.find(currentSeverity), context.getUIOptions().GROUP_BY_SEVERITY);
|
||||
}
|
||||
else {
|
||||
toolNode = myToolNode;
|
||||
if (toolNode.isTooBigForOnlineRefresh()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<RefEntity, CommonProblemDescriptor[]>();
|
||||
problems.put(refElement, descriptors);
|
||||
final Map<String, Set<RefEntity>> contents = new HashMap<String, Set<RefEntity>>();
|
||||
final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement);
|
||||
Set<RefEntity> content = contents.get(groupName);
|
||||
if (content == null) {
|
||||
content = new HashSet<RefEntity>();
|
||||
contents.put(groupName, content);
|
||||
}
|
||||
content.add(refElement);
|
||||
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isDisposed()) {
|
||||
final InspectionNode toolNode;
|
||||
synchronized (myToolLock) {
|
||||
if (myToolNode == null) {
|
||||
final HighlightSeverity currentSeverity = getSeverity((RefElement)refElement);
|
||||
toolNode = view.addTool(myToolWrapper, HighlightDisplayLevel.find(currentSeverity), context.getUIOptions().GROUP_BY_SEVERITY);
|
||||
}
|
||||
else {
|
||||
toolNode = myToolNode;
|
||||
if (toolNode.isTooBigForOnlineRefresh()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<RefEntity, CommonProblemDescriptor[]>();
|
||||
problems.put(refElement, descriptors);
|
||||
final Map<String, Set<RefEntity>> contents = new HashMap<String, Set<RefEntity>>();
|
||||
final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement);
|
||||
Set<RefEntity> content = contents.get(groupName);
|
||||
if (content == null) {
|
||||
content = new HashSet<RefEntity>();
|
||||
contents.put(groupName, content);
|
||||
}
|
||||
content.add(refElement);
|
||||
|
||||
view.getProvider().appendToolNodeContent(context, toolNode,
|
||||
(InspectionTreeNode)toolNode.getParent(), context.getUIOptions().SHOW_STRUCTURE,
|
||||
contents, problems, (DefaultTreeModel)view.getTree().getModel());
|
||||
@@ -262,11 +263,43 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private static CommonProblemDescriptor[] mergeDescriptors(@NotNull CommonProblemDescriptor[] problems1,
|
||||
@NotNull CommonProblemDescriptor[] problems2) {
|
||||
CommonProblemDescriptor[] out = new CommonProblemDescriptor[problems1.length + problems2.length];
|
||||
int o = problems1.length;
|
||||
Equality<CommonProblemDescriptor> equality = new Equality<CommonProblemDescriptor>() {
|
||||
@Override
|
||||
public boolean equals(CommonProblemDescriptor o1, CommonProblemDescriptor o2) {
|
||||
if (o1 instanceof ProblemDescriptor) {
|
||||
ProblemDescriptorBase p1 = (ProblemDescriptorBase)o1;
|
||||
ProblemDescriptorBase p2 = (ProblemDescriptorBase)o2;
|
||||
if (!Comparing.equal(p1.getDescriptionTemplate(), p2.getDescriptionTemplate())) return false;
|
||||
if (!Comparing.equal(p1.getTextRange(), p2.getTextRange())) return false;
|
||||
if (!Comparing.equal(p1.getHighlightType(), p2.getHighlightType())) return false;
|
||||
if (!Comparing.equal(p1.getProblemGroup(), p2.getProblemGroup())) return false;
|
||||
if (!Comparing.equal(p1.getStartElement(), p2.getStartElement())) return false;
|
||||
if (!Comparing.equal(p1.getEndElement(), p2.getEndElement())) return false;
|
||||
}
|
||||
else {
|
||||
if (!o1.toString().equals(o2.toString())) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
for (CommonProblemDescriptor descriptor : problems2) {
|
||||
if (ArrayUtil.indexOf(problems1, descriptor, equality) == -1) {
|
||||
out[o++] = descriptor;
|
||||
}
|
||||
}
|
||||
System.arraycopy(problems1, 0, out, 0, problems1.length);
|
||||
return Arrays.copyOfRange(out, 0, o);
|
||||
}
|
||||
|
||||
|
||||
public void setToolNode(InspectionNode toolNode) {
|
||||
synchronized (myToolLock) {
|
||||
myToolNode = toolNode;
|
||||
|
||||
@@ -29,7 +29,9 @@ import jsr166e.ForkJoinWorkerThread;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -84,41 +86,11 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
boolean runInReadAction,
|
||||
boolean failFastOnAcquireReadAction,
|
||||
@NotNull final Processor<? super T> thingProcessor) throws ProcessCanceledException {
|
||||
//if (runInReadAction && ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
// throw new RuntimeException("Must not run invokeConcurrentlyUnderProgress() from under write action because of imminent deadlock");
|
||||
//}
|
||||
if (things.isEmpty()) return true;
|
||||
// supply our own indicator even if we haven't given one - to support cancellation
|
||||
final ProgressIndicator wrapper = progress == null ? new AbstractProgressIndicatorBase() : new SensitiveProgressWrapper(progress);
|
||||
|
||||
if (things.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= CORES_FORK_THRESHOLD) {
|
||||
final AtomicBoolean result = new AtomicBoolean(true);
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < things.size(); i++) {
|
||||
T thing = things.get(i);
|
||||
if (!thingProcessor.process(thing)) {
|
||||
result.set(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, wrapper);
|
||||
}
|
||||
};
|
||||
if (runInReadAction) {
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) return false;
|
||||
}
|
||||
else {
|
||||
runnable.run();
|
||||
}
|
||||
return result.get();
|
||||
}
|
||||
Boolean result = processImmediatelyIfTooFew(things, wrapper, runInReadAction, thingProcessor);
|
||||
if (result != null) return result.booleanValue();
|
||||
|
||||
ApplierCompleter<T> applier = new ApplierCompleter<T>(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null);
|
||||
try {
|
||||
@@ -146,6 +118,49 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
return applier.completeTaskWhichFailToAcquireReadAction();
|
||||
}
|
||||
|
||||
// if {@code things} are too few to be processed in the real pool, returns TRUE if processed successfully, FALSE if not
|
||||
// returns null if things need to be processed in the real pool
|
||||
private static <T> Boolean processImmediatelyIfTooFew(@NotNull final List<T> things,
|
||||
final ProgressIndicator progress,
|
||||
boolean runInReadAction,
|
||||
@NotNull final Processor<? super T> thingProcessor) {
|
||||
// commit can be invoked from within write action
|
||||
//if (runInReadAction && ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
// throw new RuntimeException("Must not run invokeConcurrentlyUnderProgress() from under write action because of imminent deadlock");
|
||||
//}
|
||||
if (things.isEmpty()) return true;
|
||||
|
||||
if (things.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= CORES_FORK_THRESHOLD) {
|
||||
final AtomicBoolean result = new AtomicBoolean(true);
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < things.size(); i++) {
|
||||
T thing = things.get(i);
|
||||
if (!thingProcessor.process(thing)) {
|
||||
result.set(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, progress);
|
||||
}
|
||||
};
|
||||
if (runInReadAction) {
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) return false;
|
||||
}
|
||||
else {
|
||||
runnable.run();
|
||||
}
|
||||
return result.get();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// This implementation is not really async
|
||||
|
||||
@NotNull
|
||||
@@ -159,7 +174,7 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Job<Void> submitToJobThread(@NotNull final Runnable action, final Consumer<Future> onDoneCallback) {
|
||||
public Job<Void> submitToJobThread(@NotNull final Runnable action, @Nullable Consumer<Future> onDoneCallback) {
|
||||
VoidForkJoinTask task = new VoidForkJoinTask(action, onDoneCallback);
|
||||
pool.submit(task);
|
||||
return task;
|
||||
@@ -246,4 +261,103 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
get(millis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all elements from the {@code failedToProcess} and then {@code things} concurrently in the underlying pool maintaining its load.
|
||||
* Stop when {@code tombStone} element is occurred.
|
||||
* If was unable to process some element, add it back to the {@code failedToProcess} queue.
|
||||
* @return true if all elements processed successfully, false if at least one processor returned false or exception occurred
|
||||
*/
|
||||
public <T> boolean processQueue(@NotNull final BlockingQueue<T> things,
|
||||
@NotNull final Queue<T> failedToProcess,
|
||||
@NotNull final ProgressIndicator progress,
|
||||
@NotNull final T tombStone,
|
||||
@NotNull final Processor<? super T> thingProcessor) {
|
||||
class MyTask implements Callable<Boolean> {
|
||||
private final int mySeq;
|
||||
private boolean result;
|
||||
|
||||
private MyTask(int seq) {
|
||||
mySeq = seq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
progress.checkCanceled();
|
||||
T element = failedToProcess.poll();
|
||||
if (element == null) element = things.take();
|
||||
|
||||
if (element == tombStone) {
|
||||
things.offer(element);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
if (!thingProcessor.process(element)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
failedToProcess.add(element);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}, progress);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " seq="+mySeq;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSmallEnough = things.contains(tombStone);
|
||||
if (isSmallEnough) {
|
||||
try {
|
||||
// do not distribute for small queues
|
||||
return new MyTask(0).call();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
List<ForkJoinTask<Boolean>> tasks = new ArrayList<ForkJoinTask<Boolean>>();
|
||||
for (int i = 0; i < JobSchedulerImpl.CORES_COUNT; i++) {
|
||||
tasks.add(pool.submit(new MyTask(i)));
|
||||
}
|
||||
|
||||
boolean result = true;
|
||||
RuntimeException exception = null;
|
||||
for (ForkJoinTask<Boolean> task : tasks) {
|
||||
try {
|
||||
result &= task.join();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user