diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java index 4cff679c1d2b..aae907de0bc1 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java @@ -727,6 +727,7 @@ public class HighlightInfo implements Segment { private final ProblemGroup myProblemGroup; private final String myDisplayName; private final Icon myIcon; + private Boolean myCanCleanup; public IntentionActionDescriptor(@NotNull IntentionAction action, final List options, final String displayName) { this(action, options, displayName, null); @@ -762,6 +763,20 @@ public class HighlightInfo implements Segment { return myAction; } + public boolean canCleanup(PsiElement element) { + if (myCanCleanup == null) { + InspectionProfile profile = InspectionProjectProfileManager.getInstance(element.getProject()).getInspectionProfile(); + final HighlightDisplayKey key = myKey; + if (key == null) { + myCanCleanup = false; + } else { + InspectionToolWrapper toolWrapper = profile.getInspectionTool(key.toString(), element); + myCanCleanup = toolWrapper != null && toolWrapper.isCleanupTool(); + } + } + return myCanCleanup; + } + @Nullable public List getOptions(@NotNull PsiElement element, @Nullable Editor editor) { if (editor != null && Boolean.FALSE.equals(editor.getUserData(IntentionManager.SHOW_INTENTION_OPTIONS_KEY))) { @@ -789,6 +804,9 @@ public class HighlightInfo implements Segment { } } if (toolWrapper != null) { + + myCanCleanup = toolWrapper.isCleanupTool(); + InspectionProfileEntry wrappedTool; if (toolWrapper instanceof LocalInspectionToolWrapper) { wrappedTool = ((LocalInspectionToolWrapper)toolWrapper).getTool(); diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/actions/CleanupAllIntention.java b/platform/analysis-impl/src/com/intellij/codeInspection/actions/CleanupAllIntention.java new file mode 100644 index 000000000000..25a025a28742 --- /dev/null +++ b/platform/analysis-impl/src/com/intellij/codeInspection/actions/CleanupAllIntention.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.intellij.codeInspection.actions; + +import com.intellij.analysis.AnalysisScope; +import com.intellij.codeInspection.*; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CleanupAllIntention extends CleanupIntention { + + public static final CleanupAllIntention INSTANCE = new CleanupAllIntention(); + + private CleanupAllIntention() {} + + @NotNull + @Override + public String getFamilyName() { + return InspectionsBundle.message("cleanup.in.file"); + } + + @Nullable + @Override + protected AnalysisScope getScope(Project project, PsiFile file) { + return new AnalysisScope(file); + } +} diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/actions/CleanupIntention.java b/platform/analysis-impl/src/com/intellij/codeInspection/actions/CleanupIntention.java new file mode 100644 index 000000000000..d0886d162393 --- /dev/null +++ b/platform/analysis-impl/src/com/intellij/codeInspection/actions/CleanupIntention.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.intellij.codeInspection.actions; + +import com.intellij.analysis.AnalysisScope; +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.InspectionProfile; +import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInspection.ex.GlobalInspectionContextBase; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class CleanupIntention implements IntentionAction, LowPriorityAction { + + protected CleanupIntention() {} + + @Override + @NotNull + public String getText() { + return getFamilyName(); + } + + @Override + @NotNull + public String getFamilyName() { + return InspectionsBundle.message("cleanup.in.scope"); + } + + @Override + public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { + if (!FileModificationService.getInstance().preparePsiElementForWrite(file)) return; + final InspectionManager managerEx = InspectionManager.getInstance(project); + final GlobalInspectionContextBase globalContext = (GlobalInspectionContextBase)managerEx.createNewGlobalContext(false); + final AnalysisScope scope = getScope(project, file); + if (scope != null) { + final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile(); + globalContext.codeCleanup(project, scope, profile, getText()); + } + } + + @Nullable + protected abstract AnalysisScope getScope(Project project, PsiFile file); + + @Override + public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) { + return true; + } + + @Override + public boolean startInWriteAction() { + return false; + } +} diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java index b74a11ddead2..3b6ab76fc0b0 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java @@ -402,7 +402,12 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G } } - public void close(boolean noSuspisiousCodeFound) { + public void codeCleanup(final Project project, + final AnalysisScope scope, + final InspectionProfile profile, + final String commandName) {} + + public void close(boolean noSuspisiousCodeFound) { cleanup(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/CleanupOnScopeIntention.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/CleanupOnScopeIntention.java new file mode 100644 index 000000000000..7eb4fe31c6b3 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/CleanupOnScopeIntention.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.intellij.codeInsight.daemon.impl; + +import com.intellij.analysis.AnalysisScope; +import com.intellij.analysis.AnalysisScopeBundle; +import com.intellij.analysis.AnalysisUIOptions; +import com.intellij.analysis.BaseAnalysisActionDialog; +import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInspection.actions.CleanupIntention; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.Nullable; + +/** +* Created by anna on 5/13/2014. +*/ +class CleanupOnScopeIntention extends CleanupIntention { + static final CleanupOnScopeIntention INSTANCE = new CleanupOnScopeIntention(); + + private CleanupOnScopeIntention() {} + + @Nullable + @Override + protected AnalysisScope getScope(final Project project, final PsiFile file) { + final Module module = ModuleUtilCore.findModuleForPsiElement(file); + AnalysisScope analysisScope = new AnalysisScope(file); + final VirtualFile virtualFile = file.getVirtualFile(); + if (file.isPhysical() || virtualFile == null || !virtualFile.isInLocalFileSystem()) { + analysisScope = new AnalysisScope(project); + } + final BaseAnalysisActionDialog dlg = new BaseAnalysisActionDialog( + AnalysisScopeBundle.message("specify.analysis.scope", InspectionsBundle.message("inspection.action.title")), + AnalysisScopeBundle.message("analysis.scope.title", InspectionsBundle.message("inspection.action.noun")), + project, + analysisScope, + module != null ? module.getName() : null, + true, AnalysisUIOptions.getInstance(project), file); + dlg.show(); + if (!dlg.isOK()) return null; + final AnalysisUIOptions uiOptions = AnalysisUIOptions.getInstance(project); + return dlg.getScope(uiOptions, analysisScope, project, module); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/EditCleanupProfileIntentionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/EditCleanupProfileIntentionAction.java new file mode 100644 index 000000000000..269e63acf624 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/EditCleanupProfileIntentionAction.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.intellij.codeInsight.daemon.impl; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.InspectionProfile; +import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import com.intellij.profile.codeInspection.InspectionProfileManager; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; +import com.intellij.profile.codeInspection.ui.IDEInspectionToolsConfigurable; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** +* Created by anna on 5/13/2014. +*/ +class EditCleanupProfileIntentionAction implements IntentionAction { + static final EditCleanupProfileIntentionAction INSTANCE = new EditCleanupProfileIntentionAction(); + private EditCleanupProfileIntentionAction() {} + + @Override + @NotNull + public String getText() { + return getFamilyName(); + } + + @Override + @NotNull + public String getFamilyName() { + return "Edit cleanup profile settings"; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return true; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final InspectionProjectProfileManager profileManager = InspectionProjectProfileManager.getInstance(project); + final InspectionProfile inspectionProfile = profileManager.getInspectionProfile(); + final IDEInspectionToolsConfigurable configurable = + new IDEInspectionToolsConfigurable(profileManager, + InspectionProfileManager.getInstance()) { + @Override + protected boolean acceptTool(InspectionToolWrapper entry) { + return super.acceptTool(entry) && entry.isCleanupTool(); + } + }; + ShowSettingsUtil.getInstance().editConfigurable(project, configurable, new Runnable() { + @Override + public void run() { + configurable.selectProfile(inspectionProfile.getName()); + } + }); + } + + @Override + public boolean startInWriteAction() { + return false; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java index 0250a15b7301..1984230809c5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java @@ -28,6 +28,7 @@ import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.codeInspection.actions.CleanupAllIntention; import com.intellij.ide.DataManager; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.actionSystem.ActionManager; @@ -230,6 +231,19 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass { }); } + private static boolean appendCleanupCode(final List actionDescriptors, PsiFile file) { + for (HighlightInfo.IntentionActionDescriptor descriptor : actionDescriptors) { + if (descriptor.canCleanup(file)) { + final ArrayList options = new ArrayList(); + options.add(EditCleanupProfileIntentionAction.INSTANCE); + options.add(CleanupOnScopeIntention.INSTANCE); + actionDescriptors.add(new HighlightInfo.IntentionActionDescriptor(CleanupAllIntention.INSTANCE, options, "Code Cleanup Options")); + return true; + } + } + return false; + } + private void updateActions(@NotNull DaemonCodeAnalyzerImpl codeAnalyzer) { IntentionHintComponent hintComponent = codeAnalyzer.getLastIntentionHint(); if (!myShowBulb || hintComponent == null) { @@ -326,6 +340,11 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass { return true; } }); + + boolean cleanup = appendCleanupCode(intentions.inspectionFixesToShow, hostFile); + if (!cleanup) { + appendCleanupCode(intentions.errorFixesToShow, hostFile); + } } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeCleanupAction.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeCleanupAction.java index 225034882c9d..4bae18588762 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeCleanupAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeCleanupAction.java @@ -17,33 +17,18 @@ package com.intellij.codeInspection.actions; import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.daemon.impl.HighlightInfoProcessor; -import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.ex.*; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.InspectionProfile; +import com.intellij.codeInspection.ex.GlobalInspectionContextBase; +import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; +import com.intellij.codeInspection.ex.InspectionManagerEx; +import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.profile.codeInspection.ui.IDEInspectionToolsConfigurable; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiFile; -import com.intellij.util.SequentialModalProgressTask; -import com.intellij.util.SequentialTask; import org.jetbrains.annotations.NotNull; -import java.util.*; - public class CodeCleanupAction extends CodeInspectionAction { public CodeCleanupAction() { super("Code Cleanup", "Code Cleanup"); @@ -52,66 +37,9 @@ public class CodeCleanupAction extends CodeInspectionAction { @Override protected void analyze(@NotNull final Project project, @NotNull final AnalysisScope scope) { final InspectionProfile profile = myExternalProfile != null ? myExternalProfile : InspectionProjectProfileManager.getInstance(project).getInspectionProfile(); - final List lTools = new ArrayList(); - final InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(project); - final GlobalInspectionContextImpl context = managerEx.createNewGlobalContext(false); - - final LinkedHashMap> results = new LinkedHashMap>(); - ProgressManager.getInstance().run(new Task.Backgroundable(project, "Inspect code...", true) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - scope.accept(new PsiElementVisitor() { - @Override - public void visitFile(PsiFile file) { - final VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile == null) return; - for (final Tools tools : profile.getAllEnabledInspectionTools(project)) { - if (tools.getTool().getTool() instanceof CleanupLocalInspectionTool) { - final InspectionToolWrapper tool = tools.getEnabledTool(file); - if (tool instanceof LocalInspectionToolWrapper) { - lTools.add((LocalInspectionToolWrapper)tool); - tool.initialize(context); - } - } - } - - if (!lTools.isEmpty()) { - final LocalInspectionsPass pass = new LocalInspectionsPass(file, PsiDocumentManager.getInstance(project).getDocument(file), 0, - file.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true, - HighlightInfoProcessor.getEmpty()); - Runnable runnable = new Runnable() { - public void run() { - pass.doInspectInBatch(context, managerEx, lTools); - } - }; - ApplicationManager.getApplication().runReadAction(runnable); - results.put(file, pass.getInfos()); - } - } - }); - } - - @Override - public void onSuccess() { - if (!FileModificationService.getInstance().preparePsiElementsForWrite(results.keySet())) return; - - final SequentialModalProgressTask progressTask = new SequentialModalProgressTask(project, "Code Cleanup", true); - progressTask.setMinIterationTime(200); - progressTask.setTask(new SequentialCleanupTask(project, results, progressTask)); - CommandProcessor.getInstance().executeCommand(project, new Runnable() { - @Override - public void run() { - CommandProcessor.getInstance().markCurrentCommandAsGlobal(project); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - ProgressManager.getInstance().run(progressTask); - } - }); - } - }, getTemplatePresentation().getText(), null); - } - }); + final InspectionManager managerEx = InspectionManager.getInstance(project); + final GlobalInspectionContextBase globalContext = (GlobalInspectionContextBase)managerEx.createNewGlobalContext(false); + globalContext.codeCleanup(project, scope, profile, getTemplatePresentation().getText()); } @Override @@ -125,49 +53,3 @@ public class CodeCleanupAction extends CodeInspectionAction { }; } } - -class SequentialCleanupTask implements SequentialTask { - - private final Project myProject; - private final LinkedHashMap> myResults; - private Iterator myFileIterator; - private final SequentialModalProgressTask myProgressTask; - private int myCount = 0; - - public SequentialCleanupTask(Project project, LinkedHashMap> results, SequentialModalProgressTask task) { - myProject = project; - myResults = results; - myProgressTask = task; - myFileIterator = myResults.keySet().iterator(); - } - - @Override - public void prepare() {} - - @Override - public boolean isDone() { - return myFileIterator == null || !myFileIterator.hasNext(); - } - - @Override - public boolean iteration() { - final ProgressIndicator indicator = myProgressTask.getIndicator(); - if (indicator != null) { - indicator.setFraction((double) myCount++/myResults.size()); - } - final PsiFile file = myFileIterator.next(); - final List infos = myResults.get(file); - Collections.reverse(infos); //sort bottom - top - for (HighlightInfo info : infos) { - for (final Pair actionRange : info.quickFixActionRanges) { - actionRange.getFirst().getAction().invoke(myProject, null, file); - } - } - return true; - } - - @Override - public void stop() { - myFileIterator = null; - } -} diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index b2c6985993d2..e289a9b5c14a 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -19,6 +19,8 @@ package com.intellij.codeInspection.ex; import com.intellij.analysis.AnalysisScope; import com.intellij.analysis.AnalysisUIOptions; import com.intellij.analysis.PerformAnalysisInBackgroundOption; +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoProcessor; import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass; import com.intellij.codeInspection.*; @@ -36,10 +38,10 @@ import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.notification.NotificationGroup; import com.intellij.openapi.actionSystem.ToggleAction; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.PerformInBackgroundOption; -import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.*; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectUtilCore; @@ -56,6 +58,7 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.content.*; import com.intellij.util.Processor; +import com.intellij.util.SequentialModalProgressTask; import com.intellij.util.TripleFunction; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; @@ -71,10 +74,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class GlobalInspectionContextImpl extends GlobalInspectionContextBase implements GlobalInspectionContext { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl"); @@ -606,4 +606,69 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp } return presentation; } + + @Override + public void codeCleanup(final Project project, + final AnalysisScope scope, + final InspectionProfile profile, + final String commandName) { + final List lTools = new ArrayList(); + + final LinkedHashMap> results = new LinkedHashMap>(); + ProgressManager.getInstance().run(new Task.Backgroundable(project, "Inspect code...", true) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + scope.accept(new PsiElementVisitor() { + @Override + public void visitFile(PsiFile file) { + final VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile == null) return; + for (final Tools tools : profile.getAllEnabledInspectionTools(project)) { + if (tools.getTool().getTool() instanceof CleanupLocalInspectionTool) { + final InspectionToolWrapper tool = tools.getEnabledTool(file); + if (tool instanceof LocalInspectionToolWrapper) { + lTools.add((LocalInspectionToolWrapper)tool); + tool.initialize(GlobalInspectionContextImpl.this); + } + } + } + + if (!lTools.isEmpty()) { + final LocalInspectionsPass pass = new LocalInspectionsPass(file, PsiDocumentManager.getInstance(project).getDocument(file), 0, + file.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true, + HighlightInfoProcessor.getEmpty()); + Runnable runnable = new Runnable() { + public void run() { + pass.doInspectInBatch(GlobalInspectionContextImpl.this, (InspectionManagerEx)InspectionManager.getInstance(project), lTools); + } + }; + ApplicationManager.getApplication().runReadAction(runnable); + results.put(file, pass.getInfos()); + } + } + }); + } + + @Override + public void onSuccess() { + if (!FileModificationService.getInstance().preparePsiElementsForWrite(results.keySet())) return; + + final SequentialModalProgressTask progressTask = new SequentialModalProgressTask(project, "Code Cleanup", true); + progressTask.setMinIterationTime(200); + progressTask.setTask(new SequentialCleanupTask(project, results, progressTask)); + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + CommandProcessor.getInstance().markCurrentCommandAsGlobal(project); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + ProgressManager.getInstance().run(progressTask); + } + }); + } + }, commandName, null); + } + }); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/SequentialCleanupTask.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/SequentialCleanupTask.java new file mode 100644 index 000000000000..dbfb13106d9b --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/SequentialCleanupTask.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.intellij.codeInspection.ex; + +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiFile; +import com.intellij.util.SequentialModalProgressTask; +import com.intellij.util.SequentialTask; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; + +class SequentialCleanupTask implements SequentialTask { + + private final Project myProject; + private final LinkedHashMap> myResults; + private Iterator myFileIterator; + private final SequentialModalProgressTask myProgressTask; + private int myCount = 0; + + public SequentialCleanupTask(Project project, LinkedHashMap> results, SequentialModalProgressTask task) { + myProject = project; + myResults = results; + myProgressTask = task; + myFileIterator = myResults.keySet().iterator(); + } + + @Override + public void prepare() {} + + @Override + public boolean isDone() { + return myFileIterator == null || !myFileIterator.hasNext(); + } + + @Override + public boolean iteration() { + final ProgressIndicator indicator = myProgressTask.getIndicator(); + if (indicator != null) { + indicator.setFraction((double) myCount++/myResults.size()); + } + final PsiFile file = myFileIterator.next(); + final List infos = myResults.get(file); + Collections.reverse(infos); //sort bottom - top + for (HighlightInfo info : infos) { + for (final Pair actionRange : info.quickFixActionRanges) { + actionRange.getFirst().getAction().invoke(myProject, null, file); + } + } + return true; + } + + @Override + public void stop() { + myFileIterator = null; + } +} diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 755e97610c8b..525c0d510e24 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -664,6 +664,8 @@ unused.library.backward.analysis.job.description=Perform backward analysis inspection.duplicates.option.report.propertykey.expressions=&Ignore @PropertyKey expressions inspection.same.parameter.fix.name=Inline value ''{1}'' for parameter ''{0}'' fix.all.inspection.problems.in.file=Fix all ''{0}'' problems +cleanup.in.file=Cleanup code +cleanup.in.scope=Cleanup code on... severities.default.settings.message=Edit Settings|Colors \\& Fonts unsupported.character.for.the.charset=Unsupported characters for the charset ''{0}'' lossy.encoding=Lossy encoding