diff --git a/platform/analysis-api/src/com/intellij/codeInspection/ProblemDescriptor.java b/platform/analysis-api/src/com/intellij/codeInspection/ProblemDescriptor.java index d25d1e6d8061..e392fda638ba 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/ProblemDescriptor.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/ProblemDescriptor.java @@ -1,4 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection; import com.intellij.lang.annotation.ProblemGroup; @@ -51,4 +51,17 @@ public interface ProblemDescriptor extends CommonProblemDescriptor { void setProblemGroup(@Nullable ProblemGroup problemGroup); boolean showTooltip(); + + /** + * To report this problem as a different inspection. + * Can be used to let one master inspection pretend it is several different fake inspections. + * @return the shortName of the fake inspection + * @see InspectionEP#shortName + */ + @Nullable + default String getFakeInspectionShortName() { + return null; + } + + default void setFakeInspectionShortName(String shortName) {} } \ No newline at end of file diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java index e4e9caa54e47..bba1fc2b6db9 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection; import com.intellij.lang.annotation.ProblemGroup; @@ -30,6 +30,7 @@ public class ProblemDescriptorBase extends CommonProblemDescriptorImpl implement private TextAttributesKey myEnforcedTextAttributes; private int myLineNumber = -1; private ProblemGroup myProblemGroup; + private String myFakeInspectionShortName; @Nullable private final Throwable myCreationTrace; public ProblemDescriptorBase(@NotNull PsiElement startElement, @@ -269,4 +270,14 @@ public class ProblemDescriptorBase extends CommonProblemDescriptorImpl implement PsiElement element = getPsiElement(); return ProblemDescriptorUtil.renderDescriptionMessage(this, element); } + + @Override + public String getFakeInspectionShortName() { + return myFakeInspectionShortName; + } + + @Override + public void setFakeInspectionShortName(String shortName) { + myFakeInspectionShortName = shortName; + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index fdf391e0332e..015329be2187 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -518,6 +518,13 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass @NotNull HighlightSeverity severity, @NotNull ProblemDescriptor descriptor, @NotNull PsiElement element, boolean ignoreSuppressed) { + final String fakeShortName = descriptor.getFakeInspectionShortName(); + if (fakeShortName != null) { + final InspectionToolWrapper fakeTool = myProfileWrapper.getInspectionTool(fakeShortName, null); + assert fakeTool instanceof LocalInspectionToolWrapper; + toolWrapper = (LocalInspectionToolWrapper)fakeTool; + severity = myProfileWrapper.getErrorLevel(HighlightDisplayKey.find(fakeShortName), file).getSeverity(); + } LocalInspectionTool tool = toolWrapper.getTool(); if (ignoreSuppressed && SuppressionUtil.inspectionResultSuppressed(element, tool)) { registerSuppressedElements(toolWrapper, element); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java index ef09d90d4ea1..5d86df9146e7 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java @@ -30,7 +30,7 @@ public class GotoInspectionModel extends SimpleChooseByNameModel { public GotoInspectionModel(@NotNull Project project) { super(project, IdeBundle.message("prompt.goto.inspection.enter.name"), "goto.inspection.help.id"); - InspectionProfileImpl rootProfile = InspectionProfileManager.getInstance().getCurrentProfile(); + InspectionProfileImpl rootProfile = InspectionProfileManager.getInstance(project).getCurrentProfile(); for (ScopeToolState state : rootProfile.getAllTools()) { InspectionToolWrapper tool = LocalInspectionToolWrapper.findTool2RunInBatch(project, null, rootProfile, state.getTool()); if (tool != null) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionIntention.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionIntention.java index aae2e7438d69..751bd5ea6b97 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionIntention.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/RunInspectionIntention.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.actions; @@ -132,7 +118,7 @@ public class RunInspectionIntention implements IntentionAction, HighPriorityActi public static InspectionProfileImpl createProfile(@NotNull InspectionToolWrapper toolWrapper, @NotNull InspectionManagerEx managerEx, @Nullable PsiElement psiElement) { - InspectionProfileImpl rootProfile = InspectionProfileManager.getInstance().getCurrentProfile(); + InspectionProfileImpl rootProfile = InspectionProfileManager.getInstance(managerEx.getProject()).getCurrentProfile(); LinkedHashSet> allWrappers = new LinkedHashSet<>(); allWrappers.add(toolWrapper); rootProfile.collectDependentInspections(toolWrapper, allWrappers, managerEx.getProject()); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/InspectionProvider.java b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/InspectionProvider.java index fa9245880c0a..f4e14cbc8ecc 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/InspectionProvider.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/InspectionProvider.java @@ -2,6 +2,8 @@ package com.intellij.structuralsearch.inspection; import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.codeInspection.GlobalInspectionContext; +import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.ex.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupActivity; @@ -9,7 +11,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.structuralsearch.inspection.highlightTemplate.SSBasedInspection; -import com.intellij.structuralsearch.inspection.highlightTemplate.StructuralSearchFullInspection; +import com.intellij.structuralsearch.inspection.highlightTemplate.StructuralSearchFakeInspection; import com.intellij.structuralsearch.plugin.ui.Configuration; import org.jetbrains.annotations.NotNull; @@ -18,7 +20,7 @@ import java.util.UUID; /** * @author Bas Leijdekkers */ -public class InspectionProvider implements StartupActivity { +public class InspectionProvider implements StartupActivity.DumbAware { @Override public void runActivity(@NotNull Project project) { @@ -57,13 +59,27 @@ public class InspectionProvider implements StartupActivity { private static class StructuralSearchInspectionToolWrapper extends LocalInspectionToolWrapper { StructuralSearchInspectionToolWrapper(Configuration configuration) { - super(new StructuralSearchFullInspection(configuration)); + super(new StructuralSearchFakeInspection(configuration.getName(), configuration.getUuid())); + } + + private StructuralSearchInspectionToolWrapper(@NotNull LocalInspectionTool tool) { + super(tool); } @NotNull @Override public LocalInspectionToolWrapper createCopy() { - return this; + return new StructuralSearchInspectionToolWrapper(new StructuralSearchFakeInspection((StructuralSearchFakeInspection)getTool())); + } + + @Override + public void initialize(@NotNull GlobalInspectionContext context) { + super.initialize(context); + final InspectionProfileImpl profile = ((GlobalInspectionContextBase)context).getCurrentProfile(); + final InspectionToolWrapper tool = profile.getInspectionTool(SSBasedInspection.SHORT_NAME, context.getProject()); + assert tool != null; + final SSBasedInspection inspection = (SSBasedInspection)tool.getTool(); + inspection.setSessionProfile(profile); } } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java index 2c55947ff811..f6c77d735f2c 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java @@ -1,13 +1,16 @@ // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.inspection.highlightTemplate; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInspection.*; +import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.dupLocator.iterators.CountingNodeIterator; import com.intellij.notification.NotificationType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.registry.Registry; +import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.structuralsearch.MatchResult; @@ -44,6 +47,7 @@ public class SSBasedInspection extends LocalInspectionTool { public static final String SHORT_NAME = "SSBasedInspection"; private final List myConfigurations = ContainerUtil.createLockFreeCopyOnWriteList(); final Set myProblemsReported = new HashSet<>(1); + private InspectionProfileImpl mySessionProfile = null; @Override public void writeSettings(@NotNull Element node) throws WriteExternalException { @@ -70,16 +74,31 @@ public class SSBasedInspection extends LocalInspectionTool { return SHORT_NAME; } + public void setSessionProfile(InspectionProfileImpl profile) { + mySessionProfile = profile; + } + @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { final Project project = holder.getManager().getProject(); if (myConfigurations.isEmpty()) return PsiElementVisitor.EMPTY_VISITOR; - if (Registry.is("ssr.separate.inspections")) return PsiElementVisitor.EMPTY_VISITOR; + + final List configurations; + final InspectionProfileImpl profile; + if (Registry.is("ssr.separate.inspections")) { + profile = (mySessionProfile != null) ? mySessionProfile : InspectionProfileManager.getInstance(project).getCurrentProfile(); + configurations = ContainerUtil.filter(myConfigurations, x -> profile.isToolEnabled(HighlightDisplayKey.find(x.getUuid().toString()))); + if (configurations.isEmpty()) return PsiElementVisitor.EMPTY_VISITOR; + } + else { + profile = null; + configurations = myConfigurations; + } final Matcher matcher = new Matcher(project); final Map compiledOptions = - SSBasedInspectionCompiledPatternsCache.getCompiledOptions(myConfigurations, matcher); + SSBasedInspectionCompiledPatternsCache.getCompiledOptions(configurations, matcher); if (compiledOptions.isEmpty()) return PsiElementVisitor.EMPTY_VISITOR; return new PsiElementVisitor() { @@ -87,9 +106,12 @@ public class SSBasedInspection extends LocalInspectionTool { final PsiElement element = matchResult.getMatch(); final String name = configuration.getName(); final LocalQuickFix fix = createQuickFix(project, matchResult, configuration); - holder.registerProblem( - holder.getManager().createProblemDescriptor(element, name, fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly) - ); + final ProblemDescriptor descriptor = + holder.getManager().createProblemDescriptor(element, name, fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly); + if (Registry.is("ssr.separate.inspections")) { + descriptor.setFakeInspectionShortName(configuration.getUuid().toString()); + } + holder.registerProblem(descriptor); return true; }; @@ -103,7 +125,8 @@ public class SSBasedInspection extends LocalInspectionTool { final MatchContext context = entry.getValue(); if (context == null) continue; - if (Matcher.checkIfShouldAttemptToMatch(context, matchedNodes)) { + if (Matcher.checkIfShouldAttemptToMatch(context, matchedNodes) && + (profile == null || profile.isToolEnabled(HighlightDisplayKey.find(configuration.getUuid().toString()), element))) { final int nodeCount = context.getPattern().getNodeCount(); try { matcher.processMatchesInElement(context, configuration, new CountingNodeIterator(nodeCount, matchedNodes), processor); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/StructuralSearchFakeInspection.java b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/StructuralSearchFakeInspection.java new file mode 100644 index 000000000000..2d126faeb3ef --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/StructuralSearchFakeInspection.java @@ -0,0 +1,72 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.structuralsearch.inspection.highlightTemplate; + +import com.intellij.codeInspection.LocalInspectionTool; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * @author Bas Leijdekkers + */ +public class StructuralSearchFakeInspection extends LocalInspectionTool { + + private final String myShortName; + private String name = ""; + + @SuppressWarnings("unused") + public StructuralSearchFakeInspection() { + myShortName = ""; + } + + public StructuralSearchFakeInspection(String name, UUID uuid) { + this.name = name; + myShortName = uuid.toString(); + } + + public StructuralSearchFakeInspection(StructuralSearchFakeInspection copy) { + myShortName = copy.myShortName; + name = copy.name; + } + + + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String getDisplayName() { + return name; + } + + @NotNull + @Override + public String getShortName() { + return myShortName; + } + + @NotNull + @Override + public String getID() { + return myShortName; + } + + @Nullable + @Override + public String getMainToolId() { + return SSBasedInspection.SHORT_NAME; + } + + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String[] getGroupPath() { + return new String[]{"General", "Structural Search"}; + } + + @Nullable + @Override + public String getStaticDescription() { + return "no description provided"; + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/StructuralSearchFullInspection.java b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/StructuralSearchFullInspection.java deleted file mode 100644 index 7331846e11fd..000000000000 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/StructuralSearchFullInspection.java +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.structuralsearch.inspection.highlightTemplate; - -import com.intellij.codeInspection.*; -import com.intellij.dupLocator.iterators.CountingNodeIterator; -import com.intellij.notification.NotificationType; -import com.intellij.openapi.fileTypes.LanguageFileType; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiFile; -import com.intellij.structuralsearch.MatchResult; -import com.intellij.structuralsearch.Matcher; -import com.intellij.structuralsearch.SSRBundle; -import com.intellij.structuralsearch.StructuralSearchException; -import com.intellij.structuralsearch.impl.matcher.MatchContext; -import com.intellij.structuralsearch.impl.matcher.filters.LexicalNodesFilter; -import com.intellij.structuralsearch.impl.matcher.iterators.SsrFilteringNodeIterator; -import com.intellij.structuralsearch.impl.matcher.predicates.ScriptSupport; -import com.intellij.structuralsearch.plugin.ui.Configuration; -import com.intellij.structuralsearch.plugin.ui.UIUtil; -import com.intellij.util.PairProcessor; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; - -import java.util.*; - -/** - * @author Bas Leijdekkers - */ -public class StructuralSearchFullInspection extends LocalInspectionTool { - static final Object LOCK = new Object(); // hack to avoid race conditions in SSR - - private final List myConfigurations = ContainerUtil.createLockFreeCopyOnWriteList(); - private Map myCompiledOptionsCache = new HashMap<>(); - final Set myProblemsReported = new HashSet<>(1); - private final String myName; - private final String myShortName; - - public StructuralSearchFullInspection(Configuration configuration) { - myName = configuration.getName(); - myShortName = configuration.getUuid().toString(); - myConfigurations.add(configuration); - } - - @NotNull - @Override - public String getShortName() { - return myShortName; - } - - @Nls(capitalization = Nls.Capitalization.Sentence) - @NotNull - @Override - public String[] getGroupPath() { - return new String[]{"General", "Structural Search"}; - } - - @NotNull - @Override - public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) { - final PsiFile file = holder.getFile(); - if (!(file.getFileType() instanceof LanguageFileType)) return PsiElementVisitor.EMPTY_VISITOR; - final Project project = holder.getManager().getProject(); - if (myConfigurations.isEmpty()) return PsiElementVisitor.EMPTY_VISITOR; - final Matcher matcher = new Matcher(project); - myCompiledOptionsCache = SSBasedInspectionCompiledPatternsCache.getCompiledOptions(myConfigurations, matcher, myCompiledOptionsCache); - if (myCompiledOptionsCache.isEmpty()) return PsiElementVisitor.EMPTY_VISITOR; - - return new PsiElementVisitor() { - final PairProcessor processor = (matchResult, configuration) -> { - final PsiElement element = matchResult.getMatch(); - final String name = configuration.getName(); - final LocalQuickFix fix = SSBasedInspection.createQuickFix(project, matchResult, configuration); - holder.registerProblem( - holder.getManager().createProblemDescriptor(element, name, fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly) - ); - return true; - }; - - @Override - public void visitElement(@NotNull PsiElement element) { - if (LexicalNodesFilter.getInstance().accepts(element)) return; - synchronized (LOCK) { - final SsrFilteringNodeIterator matchedNodes = new SsrFilteringNodeIterator(element); - for (Map.Entry entry : myCompiledOptionsCache.entrySet()) { - final Configuration configuration = entry.getKey(); - final MatchContext context = entry.getValue(); - if (context == null) continue; - - if (Matcher.checkIfShouldAttemptToMatch(context, matchedNodes)) { - final int nodeCount = context.getPattern().getNodeCount(); - try { - matcher.processMatchesInElement(context, configuration, new CountingNodeIterator(nodeCount, matchedNodes), processor); - } - catch (StructuralSearchException e) { - if (myProblemsReported.add(configuration.getName())) { // don't overwhelm the user with messages - final String message = e.getMessage().replace(ScriptSupport.UUID, ""); - UIUtil.SSR_NOTIFICATION_GROUP.createNotification(NotificationType.ERROR) - .setContent(SSRBundle.message("inspection.script.problem", message, configuration.getName())) - .setImportant(true) - .notify(element.getProject()); - } - } - matchedNodes.reset(); - } - } - } - } - }; - } -}