2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.codeInspection.ex;
18 import com.intellij.codeHighlighting.HighlightDisplayLevel;
19 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
20 import com.intellij.codeInsight.daemon.InspectionProfileConvertor;
21 import com.intellij.codeInspection.InspectionEP;
22 import com.intellij.codeInspection.InspectionProfile;
23 import com.intellij.codeInspection.InspectionProfileEntry;
24 import com.intellij.codeInspection.ModifiableModel;
25 import com.intellij.configurationStore.SchemeDataHolder;
26 import com.intellij.configurationStore.SerializableScheme;
27 import com.intellij.lang.annotation.HighlightSeverity;
28 import com.intellij.openapi.application.ApplicationManager;
29 import com.intellij.openapi.diagnostic.Logger;
30 import com.intellij.openapi.extensions.Extensions;
31 import com.intellij.openapi.options.ExternalizableScheme;
32 import com.intellij.openapi.progress.ProcessCanceledException;
33 import com.intellij.openapi.project.Project;
34 import com.intellij.openapi.util.*;
35 import com.intellij.profile.ProfileEx;
36 import com.intellij.profile.ProfileManager;
37 import com.intellij.profile.codeInspection.InspectionProfileManager;
38 import com.intellij.profile.codeInspection.ProjectInspectionProfileManagerKt;
39 import com.intellij.profile.codeInspection.SeverityProvider;
40 import com.intellij.psi.PsiElement;
41 import com.intellij.psi.search.scope.packageSet.NamedScope;
42 import com.intellij.util.ArrayUtil;
43 import com.intellij.util.Consumer;
44 import com.intellij.util.containers.ContainerUtil;
45 import com.intellij.util.graph.CachingSemiGraph;
46 import com.intellij.util.graph.DFSTBuilder;
47 import com.intellij.util.graph.GraphGenerator;
48 import com.intellij.util.xmlb.annotations.Attribute;
49 import com.intellij.util.xmlb.annotations.Tag;
50 import com.intellij.util.xmlb.annotations.Transient;
51 import gnu.trove.THashMap;
52 import org.jdom.Element;
53 import org.jetbrains.annotations.NonNls;
54 import org.jetbrains.annotations.NotNull;
55 import org.jetbrains.annotations.Nullable;
56 import org.jetbrains.annotations.TestOnly;
58 import java.io.IOException;
60 import java.util.function.Supplier;
65 public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, InspectionProfile, ExternalizableScheme,
67 @NonNls static final String INSPECTION_TOOL_TAG = "inspection_tool";
68 @NonNls static final String CLASS_TAG = "class";
69 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.InspectionProfileImpl");
70 @NonNls private static final String VALID_VERSION = "1.0";
71 @NonNls private static final String VERSION_TAG = "version";
72 @NonNls private static final String USED_LEVELS = "used_levels";
73 public static final String DEFAULT_PROFILE_NAME = "Default";
75 public static boolean INIT_INSPECTIONS = false;
76 private static Map<String, InspectionElementsMerger> ourMergers;
77 private final InspectionToolRegistrar myRegistrar;
79 private final Map<String, Element> myInspectionsSettings = new TreeMap<>();
80 protected InspectionProfileImpl mySource;
81 private Map<String, ToolsImpl> myTools = new THashMap<>();
82 private volatile Map<String, Boolean> myDisplayLevelMap;
83 @Attribute("is_locked")
84 private boolean myLockedProfile;
85 private final InspectionProfileImpl myBaseProfile;
86 private volatile String myToolShortName = null;
87 private String[] myScopesOrder;
88 private String myDescription;
89 private boolean myModified;
90 private volatile boolean myInitialized;
92 private final Object myLock = new Object();
94 private SchemeDataHolder myDataHolder;
96 InspectionProfileImpl(@NotNull InspectionProfileImpl inspectionProfile) {
97 this(inspectionProfile.getName(), inspectionProfile.myRegistrar, inspectionProfile.getProfileManager(), inspectionProfile.myBaseProfile, null);
98 myInspectionsSettings.putAll(inspectionProfile.myInspectionsSettings);
100 setProjectLevel(inspectionProfile.isProjectLevel());
101 myLockedProfile = inspectionProfile.myLockedProfile;
102 mySource = inspectionProfile;
103 copyFrom(inspectionProfile);
106 public InspectionProfileImpl(@NotNull String profileName,
107 @NotNull InspectionToolRegistrar registrar,
108 @NotNull ProfileManager profileManager) {
109 this(profileName, registrar, profileManager, getDefaultProfile(), null);
112 public InspectionProfileImpl(@NotNull @NonNls String profileName) {
113 this(profileName, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), null, null);
116 public InspectionProfileImpl(@NotNull String profileName,
117 @NotNull InspectionToolRegistrar registrar,
118 @NotNull ProfileManager profileManager,
119 @Nullable InspectionProfileImpl baseProfile,
120 @Nullable SchemeDataHolder dataHolder) {
123 myRegistrar = registrar;
124 myBaseProfile = baseProfile;
125 myDataHolder = dataHolder;
126 myProfileManager = profileManager;
130 private static synchronized Map<String, InspectionElementsMerger> getMergers() {
131 if (ourMergers == null) {
132 ourMergers = new LinkedHashMap<>();
133 for (InspectionElementsMerger merger : Extensions.getExtensions(InspectionElementsMerger.EP_NAME)) {
134 ourMergers.put(merger.getMergedToolName(), merger);
141 public static InspectionProfileImpl createSimple(@NotNull String name,
142 @NotNull final Project project,
143 @NotNull final InspectionToolWrapper... toolWrappers) {
144 InspectionProfileImpl profile = new InspectionProfileImpl(name, new InspectionToolRegistrar() {
147 public List<InspectionToolWrapper> createTools() {
148 return Arrays.asList(toolWrappers);
150 }, InspectionProfileManager.getInstance());
152 profile.initInspectionTools(project);
155 for (InspectionToolWrapper toolWrapper : toolWrappers) {
156 profile.enableTool(toolWrapper.getShortName(), project);
161 private static boolean toolSettingsAreEqual(@NotNull String toolName, @NotNull InspectionProfileImpl profile1, @NotNull InspectionProfileImpl profile2) {
162 final Tools toolList1 = profile1.myTools.get(toolName);
163 final Tools toolList2 = profile2.myTools.get(toolName);
165 return Comparing.equal(toolList1, toolList2);
169 private static InspectionToolWrapper copyToolSettings(@NotNull InspectionToolWrapper toolWrapper)
170 throws WriteExternalException, InvalidDataException {
171 final InspectionToolWrapper inspectionTool = toolWrapper.createCopy();
172 if (toolWrapper.isInitialized()) {
173 @NonNls String tempRoot = "config";
174 Element config = new Element(tempRoot);
175 toolWrapper.getTool().writeSettings(config);
176 inspectionTool.getTool().readSettings(config);
178 return inspectionTool;
182 public static InspectionProfileImpl getDefaultProfile() {
183 return InspectionProfileImplHolder.DEFAULT_PROFILE;
187 public void setModified(final boolean modified) {
188 myModified = modified;
192 public InspectionProfile getParentProfile() {
197 @SuppressWarnings({"SimplifiableIfStatement"})
198 public boolean isChanged() {
199 if (mySource != null && mySource.myLockedProfile != myLockedProfile) return true;
204 public boolean isProperSetting(@NotNull String toolId) {
205 if (myBaseProfile != null) {
206 final Tools tools = myBaseProfile.getTools(toolId, null);
207 final Tools currentTools = myTools.get(toolId);
208 return !Comparing.equal(tools, currentTools);
214 public void resetToBase(Project project) {
215 initInspectionTools(project);
217 copyToolsConfigurations(myBaseProfile, project);
218 myDisplayLevelMap = null;
222 public void resetToEmpty(Project project) {
223 initInspectionTools(project);
224 final InspectionToolWrapper[] profileEntries = getInspectionTools(null);
225 for (InspectionToolWrapper toolWrapper : profileEntries) {
226 disableTool(toolWrapper.getShortName(), project);
231 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey inspectionToolKey, PsiElement element) {
232 Project project = element == null ? null : element.getProject();
233 final ToolsImpl tools = getTools(inspectionToolKey.toString(), project);
234 HighlightDisplayLevel level = tools != null ? tools.getLevel(element) : HighlightDisplayLevel.WARNING;
235 if (!((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().isSeverityValid(level.getSeverity().getName())) {
236 level = HighlightDisplayLevel.WARNING;
237 setErrorLevel(inspectionToolKey, level, project);
243 public void readExternal(@NotNull Element element) {
244 super.readExternal(element);
246 final String version = element.getAttributeValue(VERSION_TAG);
247 if (version == null || !version.equals(VALID_VERSION)) {
248 element = InspectionProfileConvertor.convertToNewFormat(element, this);
251 final Element highlightElement = element.getChild(USED_LEVELS);
252 if (highlightElement != null) {
254 ((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().readExternal(highlightElement);
257 for (Element toolElement : element.getChildren(INSPECTION_TOOL_TAG)) {
258 myInspectionsSettings.put(toolElement.getAttributeValue(CLASS_TAG), toolElement.clone());
263 public Set<HighlightSeverity> getUsedSeverities() {
264 LOG.assertTrue(myInitialized);
265 final Set<HighlightSeverity> result = new HashSet<>();
266 for (Tools tools : myTools.values()) {
267 for (ScopeToolState state : tools.getTools()) {
268 result.add(state.getLevel().getSeverity());
275 public Element writeScheme() {
276 if (myDataHolder != null) {
277 return myDataHolder.read();
280 Element result = isProjectLevel() ? new Element("profile").setAttribute("version", "1.0") : new Element("inspections").setAttribute("profile_name", getName());
281 serializeInto(result, false);
283 if (isProjectLevel()) {
284 return new Element("component").setAttribute("name", "InspectionProjectProfileManager").addContent(result);
290 public void serializeInto(@NotNull Element element, boolean preserveCompatibility) {
291 // must be first - compatibility
292 element.setAttribute(VERSION_TAG, VALID_VERSION);
294 super.serializeInto(element, preserveCompatibility);
296 synchronized (myLock) {
297 if (!myInitialized) {
298 for (Element el : myInspectionsSettings.values()) {
299 element.addContent(el.clone());
305 Map<String, Boolean> diffMap = getDisplayLevelMap();
306 if (diffMap == null) {
310 diffMap = new TreeMap<>(diffMap);
311 for (String toolName : myInspectionsSettings.keySet()) {
312 diffMap.put(toolName, false);
315 for (String toolName : diffMap.keySet()) {
316 if (!myLockedProfile && diffMap.get(toolName).booleanValue()) {
317 markSettingsMerged(toolName, element);
321 Element toolElement = myInspectionsSettings.get(toolName);
322 if (toolElement == null) {
323 ToolsImpl toolList = myTools.get(toolName);
324 LOG.assertTrue(toolList != null);
325 Element inspectionElement = new Element(INSPECTION_TOOL_TAG);
326 inspectionElement.setAttribute(CLASS_TAG, toolName);
328 toolList.writeExternal(inspectionElement);
330 catch (WriteExternalException e) {
335 if (!areSettingsMerged(toolName, inspectionElement)) {
336 element.addContent(inspectionElement);
340 element.addContent(toolElement.clone());
345 private void markSettingsMerged(@NotNull String toolName, @NotNull Element element) {
346 //add marker if already merged but result is now default (-> empty node)
347 final String mergedName = InspectionElementsMerger.getMergedMarkerName(toolName);
348 if (!myInspectionsSettings.containsKey(mergedName)) {
349 final InspectionElementsMerger merger = getMergers().get(toolName);
350 if (merger != null && merger.markSettingsMerged(myInspectionsSettings)) {
351 element.addContent(new Element(INSPECTION_TOOL_TAG).setAttribute(CLASS_TAG, mergedName));
356 private boolean areSettingsMerged(String toolName, Element inspectionElement) {
357 //skip merged settings as they could be restored from already provided data
358 final InspectionElementsMerger merger = getMergers().get(toolName);
359 return merger != null && merger.areSettingsMerged(myInspectionsSettings, inspectionElement);
362 public void collectDependentInspections(@NotNull InspectionToolWrapper toolWrapper,
363 @NotNull Set<InspectionToolWrapper> dependentEntries,
365 String mainToolId = toolWrapper.getMainToolId();
367 if (mainToolId != null) {
368 InspectionToolWrapper dependentEntryWrapper = getInspectionTool(mainToolId, project);
370 if (dependentEntryWrapper == null) {
371 LOG.error("Can't find main tool: '" + mainToolId+"' which was specified in "+toolWrapper);
374 if (!dependentEntries.add(dependentEntryWrapper)) {
375 collectDependentInspections(dependentEntryWrapper, dependentEntries, project);
382 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, @NotNull PsiElement element) {
383 final Tools toolList = getTools(shortName, element.getProject());
384 return toolList == null ? null : toolList.getInspectionTool(element);
389 public InspectionProfileEntry getUnwrappedTool(@NotNull String shortName, @NotNull PsiElement element) {
390 InspectionToolWrapper tool = getInspectionTool(shortName, element);
391 return tool == null ? null : tool.getTool();
395 public <T extends InspectionProfileEntry> T getUnwrappedTool(@NotNull Key<T> shortNameKey, @NotNull PsiElement element) {
396 //noinspection unchecked
397 return (T) getUnwrappedTool(shortNameKey.toString(), element);
401 public void modifyProfile(@NotNull Consumer<ModifiableModel> modelConsumer) {
402 ModifiableModel model = getModifiableModel();
403 modelConsumer.consume(model);
407 catch (IOException e) {
413 public <T extends InspectionProfileEntry> void modifyToolSettings(@NotNull final Key<T> shortNameKey,
414 @NotNull final PsiElement psiElement,
415 @NotNull final Consumer<T> toolConsumer) {
416 modifyProfile(model -> {
417 InspectionProfileEntry tool = model.getUnwrappedTool(shortNameKey.toString(), psiElement);
418 //noinspection unchecked
419 toolConsumer.consume((T) tool);
425 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, Project project) {
426 final ToolsImpl tools = getTools(shortName, project);
427 return tools != null? tools.getTool() : null;
430 public InspectionToolWrapper getToolById(@NotNull String id, @NotNull PsiElement element) {
431 initInspectionTools(element.getProject());
432 for (Tools toolList : myTools.values()) {
433 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
434 if (id.equals(tool.getID())) return tool;
440 public List<InspectionToolWrapper> findToolsById(@NotNull String id, @NotNull PsiElement element) {
441 List<InspectionToolWrapper> result = null;
442 initInspectionTools(element.getProject());
443 for (Tools toolList : myTools.values()) {
444 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
445 if (id.equals(tool.getID())) {
446 if (result == null) {
447 result = new ArrayList<>();
457 InspectionProfileManager.getInstance().fireProfileChanged(this);
462 public String getSingleTool() {
463 return myToolShortName;
467 public void setSingleTool(@NotNull final String toolShortName) {
468 myToolShortName = toolShortName;
473 public String getDisplayName() {
478 public void scopesChanged() {
479 for (ScopeToolState toolState : getAllTools(null)) {
480 toolState.scopesChanged();
482 InspectionProfileManager.getInstance().fireProfileChanged(this);
487 public boolean isProfileLocked() {
488 return myLockedProfile;
492 public void lockProfile(boolean isLocked) {
493 myLockedProfile = isLocked;
498 public InspectionToolWrapper[] getInspectionTools(@Nullable PsiElement element) {
499 initInspectionTools(element == null ? null : element.getProject());
500 List<InspectionToolWrapper> result = new ArrayList<>();
501 for (Tools toolList : myTools.values()) {
502 result.add(toolList.getInspectionTool(element));
504 return result.toArray(new InspectionToolWrapper[result.size()]);
509 public List<Tools> getAllEnabledInspectionTools(Project project) {
510 initInspectionTools(project);
511 List<Tools> result = new ArrayList<>();
512 for (final ToolsImpl toolList : myTools.values()) {
513 if (toolList.isEnabled()) {
514 result.add(toolList);
521 public void disableTool(@NotNull String toolId, @NotNull PsiElement element) {
522 getTools(toolId, element.getProject()).disableTool(element);
525 public void disableToolByDefault(@NotNull Collection<String> toolIds, @Nullable Project project) {
526 for (String toolId : toolIds) {
527 getToolDefaultState(toolId, project).setEnabled(false);
532 public ScopeToolState getToolDefaultState(@NotNull String toolId, @Nullable Project project) {
533 return getTools(toolId, project).getDefaultState();
536 public void enableToolsByDefault(@NotNull List<String> toolIds, Project project) {
537 for (final String toolId : toolIds) {
538 getToolDefaultState(toolId, project).setEnabled(true);
542 public boolean wasInitialized() {
543 return myInitialized;
546 public void initInspectionTools(@Nullable Project project) {
547 //noinspection TestOnlyProblems
548 if (myInitialized || (ApplicationManager.getApplication().isUnitTestMode() && !INIT_INSPECTIONS)) {
552 synchronized (myLock) {
553 if (!myInitialized) {
559 private void initialize(@Nullable Project project) {
560 SchemeDataHolder dataHolder = myDataHolder;
561 if (dataHolder != null) {
563 Element element = dataHolder.read();
564 if (element.getName().equals("component")) {
565 element = element.getChild("profile");
567 readExternal(element);
570 if (myBaseProfile != null) {
571 myBaseProfile.initInspectionTools(project);
574 final List<InspectionToolWrapper> tools;
576 tools = createTools(project);
578 catch (ProcessCanceledException ignored) {
582 final Map<String, List<String>> dependencies = new THashMap<>();
583 for (InspectionToolWrapper toolWrapper : tools) {
584 addTool(project, toolWrapper, dependencies);
587 DFSTBuilder<String> builder = new DFSTBuilder<>(GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<String>() {
589 public Collection<String> getNodes() {
590 return dependencies.keySet();
594 public Iterator<String> getIn(String n) {
595 return dependencies.get(n).iterator();
598 if (builder.isAcyclic()) {
599 myScopesOrder = ArrayUtil.toStringArray(builder.getSortedNodes());
602 if (mySource != null) {
603 copyToolsConfigurations(mySource, project);
606 myInitialized = true;
607 if (dataHolder != null) {
608 // should be only after set myInitialized
609 dataHolder.updateDigest();
613 public void addTool(@Nullable Project project, @NotNull InspectionToolWrapper toolWrapper, @NotNull Map<String, List<String>> dependencies) {
614 final String shortName = toolWrapper.getShortName();
615 HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
617 final InspectionEP extension = toolWrapper.getExtension();
618 Computable<String> computable = extension == null ? new Computable.PredefinedValueComputable<>(toolWrapper.getDisplayName()) : extension::getDisplayName;
619 if (toolWrapper instanceof LocalInspectionToolWrapper) {
620 key = HighlightDisplayKey.register(shortName, computable, toolWrapper.getID(),
621 ((LocalInspectionToolWrapper)toolWrapper).getAlternativeID());
624 key = HighlightDisplayKey.register(shortName, computable);
629 LOG.error(shortName + " ; number of initialized tools: " + myTools.size());
633 HighlightDisplayLevel baseLevel = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null
634 ? myBaseProfile.getErrorLevel(key, project)
635 : HighlightDisplayLevel.DO_NOT_SHOW;
636 HighlightDisplayLevel defaultLevel = toolWrapper.getDefaultLevel();
637 HighlightDisplayLevel level = baseLevel.getSeverity().compareTo(defaultLevel.getSeverity()) > 0 ? baseLevel : defaultLevel;
638 //HighlightDisplayLevel level = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null ? myBaseProfile.getErrorLevel(key, project) : toolWrapper.getDefaultLevel();
639 boolean enabled = myBaseProfile != null ? myBaseProfile.isToolEnabled(key) : toolWrapper.isEnabledByDefault();
640 final ToolsImpl toolsList = new ToolsImpl(toolWrapper, level, !myLockedProfile && enabled, enabled);
641 final Element element = myInspectionsSettings.remove(shortName);
643 if (element != null) {
644 toolsList.readExternal(element, this, dependencies);
646 else if (!myInspectionsSettings.containsKey(InspectionElementsMerger.getMergedMarkerName(shortName))) {
647 final InspectionElementsMerger merger = getMergers().get(shortName);
648 if (merger != null) {
649 final Element merged = merger.merge(myInspectionsSettings);
650 if (merged != null) {
651 toolsList.readExternal(merged, this, dependencies);
656 catch (InvalidDataException e) {
657 LOG.error("Can't read settings for " + toolWrapper, e);
659 myTools.put(shortName, toolsList);
664 public String[] getScopesOrder() {
665 return myScopesOrder;
668 public void setScopesOrder(String[] scopesOrder) {
669 myScopesOrder = scopesOrder;
673 private List<InspectionToolWrapper> createTools(@Nullable Project project) {
674 if (mySource != null) {
675 return ContainerUtil.map(mySource.getDefaultStates(project), ScopeToolState::getTool);
677 return myRegistrar.createTools();
680 private HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, @Nullable Project project) {
681 final ToolsImpl tools = getTools(key.toString(), project);
682 LOG.assertTrue(tools != null, "profile name: " + myName + " base profile: " + (myBaseProfile != null ? myBaseProfile.getName() : "-") + " key: " + key);
683 return tools.getLevel();
688 public InspectionProfileImpl getModifiableModel() {
689 return new InspectionProfileImpl(this);
692 private void copyToolsConfigurations(@NotNull InspectionProfileImpl profile, @Nullable Project project) {
694 for (ToolsImpl toolList : profile.myTools.values()) {
695 final ToolsImpl tools = myTools.get(toolList.getShortName());
696 final ScopeToolState defaultState = toolList.getDefaultState();
697 tools.setDefaultState(copyToolSettings(defaultState.getTool()), defaultState.isEnabled(), defaultState.getLevel());
698 tools.removeAllScopes();
699 final List<ScopeToolState> nonDefaultToolStates = toolList.getNonDefaultTools();
700 if (nonDefaultToolStates != null) {
701 for (ScopeToolState state : nonDefaultToolStates) {
702 final InspectionToolWrapper toolWrapper = copyToolSettings(state.getTool());
703 final NamedScope scope = state.getScope(project);
705 tools.addTool(scope, toolWrapper, state.isEnabled(), state.getLevel());
708 tools.addTool(state.getScopeName(), toolWrapper, state.isEnabled(), state.getLevel());
712 tools.setEnabled(toolList.isEnabled());
715 catch (WriteExternalException e) {
718 catch (InvalidDataException e) {
724 public void cleanup(@NotNull Project project) {
725 if (!myInitialized) {
729 for (final ToolsImpl toolList : myTools.values()) {
730 if (toolList.isEnabled()) {
731 for (InspectionToolWrapper toolWrapper : toolList.getAllTools()) {
732 toolWrapper.cleanup(project);
738 public void enableTool(@NotNull String toolId, Project project) {
739 final ToolsImpl tools = getTools(toolId, project);
740 tools.setEnabled(true);
741 if (tools.getNonDefaultTools() == null) {
742 tools.getDefaultState().setEnabled(true);
747 public void enableTool(@NotNull String inspectionTool, NamedScope namedScope, Project project) {
748 getTools(inspectionTool, project).enableTool(namedScope, project);
751 public void enableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, Project project) {
752 for (String inspectionTool : inspectionTools) {
753 enableTool(inspectionTool, namedScope, project);
758 public void disableTool(@NotNull String inspectionTool, NamedScope namedScope, @NotNull Project project) {
759 getTools(inspectionTool, project).disableTool(namedScope, project);
762 public void disableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, @NotNull Project project) {
763 for (String inspectionTool : inspectionTools) {
764 disableTool(inspectionTool, namedScope, project);
769 public void disableTool(@NotNull String inspectionTool, Project project) {
770 final ToolsImpl tools = getTools(inspectionTool, project);
771 tools.setEnabled(false);
772 if (tools.getNonDefaultTools() == null) {
773 tools.getDefaultState().setEnabled(false);
778 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, Project project) {
779 getTools(key.toString(), project).setLevel(level);
783 public boolean isToolEnabled(@Nullable HighlightDisplayKey key, PsiElement element) {
787 final Tools toolState = getTools(key.toString(), element == null ? null : element.getProject());
788 return toolState != null && toolState.isEnabled(element);
792 public boolean isToolEnabled(@Nullable HighlightDisplayKey key) {
793 return isToolEnabled(key, null);
797 public boolean isExecutable(Project project) {
798 initInspectionTools(project);
799 for (Tools tools : myTools.values()) {
800 if (tools.isEnabled()) return true;
805 //invoke when isChanged() == true
807 public void commit() throws IOException {
808 LOG.assertTrue(mySource != null);
809 mySource.commit(this);
810 getProfileManager().updateProfile(mySource);
814 private void commit(@NotNull InspectionProfileImpl model) {
815 setName(model.getName());
816 setDescription(model.getDescription());
817 setProjectLevel(model.isProjectLevel());
818 myLockedProfile = model.myLockedProfile;
819 myDisplayLevelMap = model.myDisplayLevelMap;
820 myTools = model.myTools;
821 myProfileManager = model.getProfileManager();
823 InspectionProfileManager.getInstance().fireProfileChanged(model);
827 public String getDescription() {
828 return myDescription;
831 public void setDescription(String description) {
832 myDescription = description;
835 public void convert(@NotNull Element element, @NotNull Project project) {
836 final Element scopes = element.getChild("scopes");
837 if (scopes == null) {
841 initInspectionTools(project);
843 for (Element scopeElement : scopes.getChildren(SCOPE)) {
844 final String profile = scopeElement.getAttributeValue(ProjectInspectionProfileManagerKt.PROFILE);
845 if (profile != null) {
846 final InspectionProfileImpl inspectionProfile = (InspectionProfileImpl)getProfileManager().getProfile(profile);
847 if (inspectionProfile != null) {
848 final NamedScope scope = getProfileManager().getScopesManager().getScope(scopeElement.getAttributeValue(NAME));
850 for (InspectionToolWrapper toolWrapper : inspectionProfile.getInspectionTools(null)) {
851 final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName());
853 InspectionToolWrapper toolWrapperCopy = copyToolSettings(toolWrapper);
854 HighlightDisplayLevel errorLevel = inspectionProfile.getErrorLevel(key, null, project);
855 getTools(toolWrapper.getShortName(), project).addTool(scope, toolWrapperCopy, inspectionProfile.isToolEnabled(key), errorLevel);
857 catch (Exception e) {
865 reduceConvertedScopes();
868 private void reduceConvertedScopes() {
869 for (ToolsImpl tools : myTools.values()) {
870 final ScopeToolState toolState = tools.getDefaultState();
871 final List<ScopeToolState> nonDefaultTools = tools.getNonDefaultTools();
872 if (nonDefaultTools != null) {
873 boolean equal = true;
874 boolean isEnabled = toolState.isEnabled();
875 for (ScopeToolState state : nonDefaultTools) {
876 isEnabled |= state.isEnabled();
877 if (!state.equalTo(toolState)) {
881 tools.setEnabled(isEnabled);
883 tools.removeAllScopes();
890 public List<ScopeToolState> getAllTools(Project project) {
891 initInspectionTools(project);
892 final List<ScopeToolState> result = new ArrayList<>();
893 for (Tools tools : myTools.values()) {
894 result.addAll(tools.getTools());
900 public List<ScopeToolState> getDefaultStates(@Nullable Project project) {
901 initInspectionTools(project);
902 final List<ScopeToolState> result = new ArrayList<>();
903 for (Tools tools : myTools.values()) {
904 result.add(tools.getDefaultState());
910 public List<ScopeToolState> getNonDefaultTools(@NotNull String shortName, Project project) {
911 final List<ScopeToolState> result = new ArrayList<>();
912 final List<ScopeToolState> nonDefaultTools = getTools(shortName, project).getNonDefaultTools();
913 if (nonDefaultTools != null) {
914 result.addAll(nonDefaultTools);
919 public boolean isToolEnabled(@NotNull HighlightDisplayKey key, NamedScope namedScope, Project project) {
920 return getTools(key.toString(), project).isEnabled(namedScope,project);
923 public void removeScope(@NotNull String toolId, @NotNull String scopeName, Project project) {
924 getTools(toolId, project).removeScope(scopeName);
927 public void removeScopes(@NotNull List<String> toolIds, @NotNull String scopeName, Project project) {
928 for (final String toolId : toolIds) {
929 removeScope(toolId, scopeName, project);
934 * @return null if it has no base profile
937 private Map<String, Boolean> getDisplayLevelMap() {
938 if (myBaseProfile == null) return null;
939 if (myDisplayLevelMap == null) {
940 synchronized (myLock) {
941 if (myDisplayLevelMap == null) {
942 initInspectionTools(null);
943 Set<String> names = myTools.keySet();
944 Map<String, Boolean> map = new THashMap<>(names.size());
945 for (String toolId : names) {
946 map.put(toolId, toolSettingsAreEqual(toolId, myBaseProfile, this));
948 myDisplayLevelMap = map;
953 return myDisplayLevelMap;
956 public void profileChanged() {
957 myDisplayLevelMap = null;
962 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, NamedScope scope, Project project) {
963 final ToolsImpl tools = getTools(key.toString(), project);
964 return tools != null ? tools.getLevel(scope, project) : HighlightDisplayLevel.WARNING;
967 public ScopeToolState addScope(@NotNull InspectionToolWrapper toolWrapper,
969 @NotNull HighlightDisplayLevel level,
972 return getTools(toolWrapper.getShortName(), project).prependTool(scope, toolWrapper, enabled, level);
975 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
976 getTools(key.toString(), project).setLevel(level, scopeName, project);
979 public void setErrorLevel(@NotNull List<HighlightDisplayKey> keys, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
980 for (HighlightDisplayKey key : keys) {
981 setErrorLevel(key, level, scopeName, project);
985 public ToolsImpl getTools(@NotNull String toolId, @Nullable Project project) {
986 initInspectionTools(project);
987 return myTools.get(toolId);
990 public void enableAllTools(Project project) {
991 for (InspectionToolWrapper entry : getInspectionTools(null)) {
992 enableTool(entry.getShortName(), project);
996 public void disableAllTools(Project project) {
997 for (InspectionToolWrapper entry : getInspectionTools(null)) {
998 disableTool(entry.getShortName(), project);
1004 public String toString() {
1005 return mySource == null ? getName() : getName() + " (copy)";
1009 public boolean equals(Object o) {
1010 return super.equals(o) && ((InspectionProfileImpl)o).getProfileManager() == getProfileManager();
1013 private static class InspectionProfileImplHolder {
1014 private static final InspectionProfileImpl DEFAULT_PROFILE = new InspectionProfileImpl(DEFAULT_PROFILE_NAME);
1017 @SuppressWarnings("TestOnlyProblems")
1018 public static <T> T initAndDo(@NotNull Supplier<T> runnable) {
1019 boolean old = INIT_INSPECTIONS;
1021 INIT_INSPECTIONS = true;
1022 return runnable.get();
1025 INIT_INSPECTIONS = old;