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 gnu.trove.THashSet;
53 import org.jdom.Element;
54 import org.jetbrains.annotations.NonNls;
55 import org.jetbrains.annotations.NotNull;
56 import org.jetbrains.annotations.Nullable;
57 import org.jetbrains.annotations.TestOnly;
64 public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, InspectionProfile, ExternalizableScheme,
66 @NonNls static final String INSPECTION_TOOL_TAG = "inspection_tool";
67 @NonNls static final String CLASS_TAG = "class";
68 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.InspectionProfileImpl");
69 @NonNls private static final String VALID_VERSION = "1.0";
70 @NonNls private static final String VERSION_TAG = "version";
71 @NonNls private static final String USED_LEVELS = "used_levels";
72 public static final String DEFAULT_PROFILE_NAME = "Default";
74 public static boolean INIT_INSPECTIONS;
75 private static Map<String, InspectionElementsMerger> ourMergers;
76 private final InspectionToolRegistrar myRegistrar;
78 private final Map<String, Element> myInspectionsSettings = new TreeMap<>();
79 protected InspectionProfileImpl mySource;
80 private Map<String, ToolsImpl> myTools = new THashMap<>();
81 private volatile Map<String, Boolean> myDisplayLevelMap;
82 @Attribute("is_locked")
83 private boolean myLockedProfile;
84 private final InspectionProfileImpl myBaseProfile;
85 private volatile String myToolShortName = null;
86 private String[] myScopesOrder;
87 private String myDescription;
88 private boolean myModified;
89 private volatile boolean myInitialized;
91 private final Object myLock = new Object();
93 private SchemeDataHolder<InspectionProfileImpl> myDataHolder;
95 InspectionProfileImpl(@NotNull InspectionProfileImpl inspectionProfile) {
96 this(inspectionProfile.getName(), inspectionProfile.myRegistrar, inspectionProfile.getProfileManager(), inspectionProfile.myBaseProfile, null);
97 myInspectionsSettings.putAll(inspectionProfile.myInspectionsSettings);
99 setProjectLevel(inspectionProfile.isProjectLevel());
100 myLockedProfile = inspectionProfile.myLockedProfile;
101 mySource = inspectionProfile;
102 copyFrom(inspectionProfile);
105 public InspectionProfileImpl(@NotNull String profileName,
106 @NotNull InspectionToolRegistrar registrar,
107 @NotNull ProfileManager profileManager) {
108 this(profileName, registrar, profileManager, getDefaultProfile(), null);
111 public InspectionProfileImpl(@NotNull @NonNls String profileName) {
112 this(profileName, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), null, null);
115 public InspectionProfileImpl(@NotNull String profileName,
116 @NotNull InspectionToolRegistrar registrar,
117 @NotNull ProfileManager profileManager,
118 @Nullable InspectionProfileImpl baseProfile,
119 @Nullable SchemeDataHolder<InspectionProfileImpl> dataHolder) {
122 myRegistrar = registrar;
123 myBaseProfile = baseProfile;
124 myDataHolder = dataHolder;
125 myProfileManager = profileManager;
129 private static synchronized Map<String, InspectionElementsMerger> getMergers() {
130 if (ourMergers == null) {
131 ourMergers = new LinkedHashMap<>();
132 for (InspectionElementsMerger merger : Extensions.getExtensions(InspectionElementsMerger.EP_NAME)) {
133 ourMergers.put(merger.getMergedToolName(), merger);
140 public static InspectionProfileImpl createSimple(@NotNull String name,
141 @NotNull Project project,
142 @NotNull List<InspectionToolWrapper> toolWrappers) {
143 InspectionProfileImpl profile = new InspectionProfileImpl(name, new InspectionToolRegistrar() {
146 public List<InspectionToolWrapper> createTools() {
149 }, InspectionProfileManager.getInstance());
150 for (InspectionToolWrapper toolWrapper : toolWrappers) {
151 profile.enableTool(toolWrapper.getShortName(), project);
156 private static boolean toolSettingsAreEqual(@NotNull String toolName, @NotNull InspectionProfileImpl profile1, @NotNull InspectionProfileImpl profile2) {
157 final Tools toolList1 = profile1.myTools.get(toolName);
158 final Tools toolList2 = profile2.myTools.get(toolName);
160 return Comparing.equal(toolList1, toolList2);
164 private static InspectionToolWrapper copyToolSettings(@NotNull InspectionToolWrapper toolWrapper)
165 throws WriteExternalException, InvalidDataException {
166 final InspectionToolWrapper inspectionTool = toolWrapper.createCopy();
167 if (toolWrapper.isInitialized()) {
168 @NonNls String tempRoot = "config";
169 Element config = new Element(tempRoot);
170 toolWrapper.getTool().writeSettings(config);
171 inspectionTool.getTool().readSettings(config);
173 return inspectionTool;
177 public static InspectionProfileImpl getDefaultProfile() {
178 return InspectionProfileImplHolder.DEFAULT_PROFILE;
182 public void setModified(final boolean modified) {
183 myModified = modified;
187 public InspectionProfile getParentProfile() {
192 @SuppressWarnings({"SimplifiableIfStatement"})
193 public boolean isChanged() {
194 if (mySource != null && mySource.myLockedProfile != myLockedProfile) return true;
199 public boolean isProperSetting(@NotNull String toolId) {
200 if (myBaseProfile != null) {
201 final Tools tools = myBaseProfile.getTools(toolId, null);
202 final Tools currentTools = myTools.get(toolId);
203 return !Comparing.equal(tools, currentTools);
209 public void resetToBase(Project project) {
210 initInspectionTools(project);
212 copyToolsConfigurations(myBaseProfile, project);
213 myDisplayLevelMap = null;
217 public void resetToEmpty(Project project) {
218 initInspectionTools(project);
219 final InspectionToolWrapper[] profileEntries = getInspectionTools(null);
220 for (InspectionToolWrapper toolWrapper : profileEntries) {
221 disableTool(toolWrapper.getShortName(), project);
226 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey inspectionToolKey, PsiElement element) {
227 Project project = element == null ? null : element.getProject();
228 final ToolsImpl tools = getTools(inspectionToolKey.toString(), project);
229 HighlightDisplayLevel level = tools != null ? tools.getLevel(element) : HighlightDisplayLevel.WARNING;
230 if (!((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().isSeverityValid(level.getSeverity().getName())) {
231 level = HighlightDisplayLevel.WARNING;
232 setErrorLevel(inspectionToolKey, level, project);
238 public void readExternal(@NotNull Element element) {
239 super.readExternal(element);
241 final String version = element.getAttributeValue(VERSION_TAG);
242 if (version == null || !version.equals(VALID_VERSION)) {
243 element = InspectionProfileConvertor.convertToNewFormat(element, this);
246 final Element highlightElement = element.getChild(USED_LEVELS);
247 if (highlightElement != null) {
249 ((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().readExternal(highlightElement);
252 for (Element toolElement : element.getChildren(INSPECTION_TOOL_TAG)) {
253 myInspectionsSettings.put(toolElement.getAttributeValue(CLASS_TAG), toolElement.clone());
258 public Set<HighlightSeverity> getUsedSeverities() {
259 LOG.assertTrue(myInitialized);
260 Set<HighlightSeverity> result = new THashSet<>();
261 for (Tools tools : myTools.values()) {
262 for (ScopeToolState state : tools.getTools()) {
263 result.add(state.getLevel().getSeverity());
270 public Element writeScheme() {
271 if (myDataHolder != null) {
272 return myDataHolder.read();
275 Element result = isProjectLevel() ? new Element("profile").setAttribute("version", "1.0") : new Element("inspections").setAttribute("profile_name", getName());
276 serializeInto(result, false);
278 if (isProjectLevel()) {
279 return new Element("component").setAttribute("name", "InspectionProjectProfileManager").addContent(result);
285 public void serializeInto(@NotNull Element element, boolean preserveCompatibility) {
286 // must be first - compatibility
287 element.setAttribute(VERSION_TAG, VALID_VERSION);
289 super.serializeInto(element, preserveCompatibility);
291 synchronized (myLock) {
292 if (!myInitialized) {
293 for (Element el : myInspectionsSettings.values()) {
294 element.addContent(el.clone());
300 Map<String, Boolean> diffMap = getDisplayLevelMap();
301 if (diffMap == null) {
305 diffMap = new TreeMap<>(diffMap);
306 for (String toolName : myInspectionsSettings.keySet()) {
307 diffMap.put(toolName, false);
310 for (String toolName : diffMap.keySet()) {
311 if (!myLockedProfile && diffMap.get(toolName).booleanValue()) {
312 markSettingsMerged(toolName, element);
316 Element toolElement = myInspectionsSettings.get(toolName);
317 if (toolElement == null) {
318 ToolsImpl toolList = myTools.get(toolName);
319 LOG.assertTrue(toolList != null);
320 Element inspectionElement = new Element(INSPECTION_TOOL_TAG);
321 inspectionElement.setAttribute(CLASS_TAG, toolName);
323 toolList.writeExternal(inspectionElement);
325 catch (WriteExternalException e) {
330 if (!areSettingsMerged(toolName, inspectionElement)) {
331 element.addContent(inspectionElement);
335 element.addContent(toolElement.clone());
340 private void markSettingsMerged(@NotNull String toolName, @NotNull Element element) {
341 //add marker if already merged but result is now default (-> empty node)
342 final String mergedName = InspectionElementsMerger.getMergedMarkerName(toolName);
343 if (!myInspectionsSettings.containsKey(mergedName)) {
344 final InspectionElementsMerger merger = getMergers().get(toolName);
345 if (merger != null && merger.markSettingsMerged(myInspectionsSettings)) {
346 element.addContent(new Element(INSPECTION_TOOL_TAG).setAttribute(CLASS_TAG, mergedName));
351 private boolean areSettingsMerged(String toolName, Element inspectionElement) {
352 //skip merged settings as they could be restored from already provided data
353 final InspectionElementsMerger merger = getMergers().get(toolName);
354 return merger != null && merger.areSettingsMerged(myInspectionsSettings, inspectionElement);
357 public void collectDependentInspections(@NotNull InspectionToolWrapper toolWrapper,
358 @NotNull Set<InspectionToolWrapper> dependentEntries,
360 String mainToolId = toolWrapper.getMainToolId();
362 if (mainToolId != null) {
363 InspectionToolWrapper dependentEntryWrapper = getInspectionTool(mainToolId, project);
365 if (dependentEntryWrapper == null) {
366 LOG.error("Can't find main tool: '" + mainToolId+"' which was specified in "+toolWrapper);
369 if (!dependentEntries.add(dependentEntryWrapper)) {
370 collectDependentInspections(dependentEntryWrapper, dependentEntries, project);
377 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, @NotNull PsiElement element) {
378 final Tools toolList = getTools(shortName, element.getProject());
379 return toolList == null ? null : toolList.getInspectionTool(element);
384 public InspectionProfileEntry getUnwrappedTool(@NotNull String shortName, @NotNull PsiElement element) {
385 InspectionToolWrapper tool = getInspectionTool(shortName, element);
386 return tool == null ? null : tool.getTool();
390 public <T extends InspectionProfileEntry> T getUnwrappedTool(@NotNull Key<T> shortNameKey, @NotNull PsiElement element) {
391 //noinspection unchecked
392 return (T) getUnwrappedTool(shortNameKey.toString(), element);
396 public void modifyProfile(@NotNull Consumer<ModifiableModel> modelConsumer) {
397 ModifiableModel model = getModifiableModel();
398 modelConsumer.consume(model);
403 public <T extends InspectionProfileEntry> void modifyToolSettings(@NotNull final Key<T> shortNameKey,
404 @NotNull final PsiElement psiElement,
405 @NotNull final Consumer<T> toolConsumer) {
406 modifyProfile(model -> {
407 InspectionProfileEntry tool = model.getUnwrappedTool(shortNameKey.toString(), psiElement);
408 //noinspection unchecked
409 toolConsumer.consume((T) tool);
415 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, Project project) {
416 final ToolsImpl tools = getTools(shortName, project);
417 return tools != null? tools.getTool() : null;
420 public InspectionToolWrapper getToolById(@NotNull String id, @NotNull PsiElement element) {
421 initInspectionTools(element.getProject());
422 for (Tools toolList : myTools.values()) {
423 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
424 if (id.equals(tool.getID())) return tool;
430 public List<InspectionToolWrapper> findToolsById(@NotNull String id, @NotNull PsiElement element) {
431 List<InspectionToolWrapper> result = null;
432 initInspectionTools(element.getProject());
433 for (Tools toolList : myTools.values()) {
434 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
435 if (id.equals(tool.getID())) {
436 if (result == null) {
437 result = new ArrayList<>();
447 InspectionProfileManager.getInstance().fireProfileChanged(this);
452 public String getSingleTool() {
453 return myToolShortName;
457 public void setSingleTool(@NotNull final String toolShortName) {
458 myToolShortName = toolShortName;
463 public String getDisplayName() {
468 public void scopesChanged() {
469 for (ScopeToolState toolState : getAllTools(null)) {
470 toolState.scopesChanged();
472 InspectionProfileManager.getInstance().fireProfileChanged(this);
477 public boolean isProfileLocked() {
478 return myLockedProfile;
482 public void lockProfile(boolean isLocked) {
483 myLockedProfile = isLocked;
488 public InspectionToolWrapper[] getInspectionTools(@Nullable PsiElement element) {
489 initInspectionTools(element == null ? null : element.getProject());
490 List<InspectionToolWrapper> result = new ArrayList<>();
491 for (Tools toolList : myTools.values()) {
492 result.add(toolList.getInspectionTool(element));
494 return result.toArray(new InspectionToolWrapper[result.size()]);
499 public List<Tools> getAllEnabledInspectionTools(Project project) {
500 initInspectionTools(project);
501 List<Tools> result = new ArrayList<>();
502 for (final ToolsImpl toolList : myTools.values()) {
503 if (toolList.isEnabled()) {
504 result.add(toolList);
511 public void disableTool(@NotNull String toolId, @NotNull PsiElement element) {
512 getTools(toolId, element.getProject()).disableTool(element);
515 public void disableToolByDefault(@NotNull Collection<String> toolIds, @Nullable Project project) {
516 for (String toolId : toolIds) {
517 getToolDefaultState(toolId, project).setEnabled(false);
522 public ScopeToolState getToolDefaultState(@NotNull String toolId, @Nullable Project project) {
523 return getTools(toolId, project).getDefaultState();
526 public void enableToolsByDefault(@NotNull List<String> toolIds, Project project) {
527 for (final String toolId : toolIds) {
528 getToolDefaultState(toolId, project).setEnabled(true);
532 public boolean wasInitialized() {
533 return myInitialized;
536 public void initInspectionTools(@Nullable Project project) {
537 //noinspection TestOnlyProblems
538 if (myInitialized || (ApplicationManager.getApplication().isUnitTestMode() && !INIT_INSPECTIONS)) {
542 synchronized (myLock) {
543 if (!myInitialized) {
549 private void initialize(@Nullable Project project) {
550 SchemeDataHolder<InspectionProfileImpl> dataHolder = myDataHolder;
551 if (dataHolder != null) {
553 Element element = dataHolder.read();
554 if (element.getName().equals("component")) {
555 element = element.getChild("profile");
557 assert element != null;
558 readExternal(element);
561 if (myBaseProfile != null) {
562 myBaseProfile.initInspectionTools(project);
565 final List<InspectionToolWrapper> tools;
567 tools = createTools(project);
569 catch (ProcessCanceledException ignored) {
573 final Map<String, List<String>> dependencies = new THashMap<>();
574 for (InspectionToolWrapper toolWrapper : tools) {
575 addTool(project, toolWrapper, dependencies);
578 DFSTBuilder<String> builder = new DFSTBuilder<>(GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<String>() {
580 public Collection<String> getNodes() {
581 return dependencies.keySet();
585 public Iterator<String> getIn(String n) {
586 return dependencies.get(n).iterator();
589 if (builder.isAcyclic()) {
590 myScopesOrder = ArrayUtil.toStringArray(builder.getSortedNodes());
593 if (mySource != null) {
594 copyToolsConfigurations(mySource, project);
597 myInitialized = true;
598 if (dataHolder != null) {
599 // should be only after set myInitialized
600 dataHolder.updateDigest(this);
604 public void addTool(@Nullable Project project, @NotNull InspectionToolWrapper toolWrapper, @NotNull Map<String, List<String>> dependencies) {
605 final String shortName = toolWrapper.getShortName();
606 HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
608 final InspectionEP extension = toolWrapper.getExtension();
609 Computable<String> computable = extension == null ? new Computable.PredefinedValueComputable<>(toolWrapper.getDisplayName()) : extension::getDisplayName;
610 if (toolWrapper instanceof LocalInspectionToolWrapper) {
611 key = HighlightDisplayKey.register(shortName, computable, toolWrapper.getID(),
612 ((LocalInspectionToolWrapper)toolWrapper).getAlternativeID());
615 key = HighlightDisplayKey.register(shortName, computable);
620 LOG.error(shortName + " ; number of initialized tools: " + myTools.size());
624 HighlightDisplayLevel baseLevel = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null
625 ? myBaseProfile.getErrorLevel(key, project)
626 : HighlightDisplayLevel.DO_NOT_SHOW;
627 HighlightDisplayLevel defaultLevel = toolWrapper.getDefaultLevel();
628 HighlightDisplayLevel level = baseLevel.getSeverity().compareTo(defaultLevel.getSeverity()) > 0 ? baseLevel : defaultLevel;
629 //HighlightDisplayLevel level = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null ? myBaseProfile.getErrorLevel(key, project) : toolWrapper.getDefaultLevel();
630 boolean enabled = myBaseProfile != null ? myBaseProfile.isToolEnabled(key) : toolWrapper.isEnabledByDefault();
631 final ToolsImpl toolsList = new ToolsImpl(toolWrapper, level, !myLockedProfile && enabled, enabled);
632 final Element element = myInspectionsSettings.remove(shortName);
634 if (element != null) {
635 toolsList.readExternal(element, this, dependencies);
637 else if (!myInspectionsSettings.containsKey(InspectionElementsMerger.getMergedMarkerName(shortName))) {
638 final InspectionElementsMerger merger = getMergers().get(shortName);
639 if (merger != null) {
640 final Element merged = merger.merge(myInspectionsSettings);
641 if (merged != null) {
642 toolsList.readExternal(merged, this, dependencies);
647 catch (InvalidDataException e) {
648 LOG.error("Can't read settings for " + toolWrapper, e);
650 myTools.put(shortName, toolsList);
655 public String[] getScopesOrder() {
656 return myScopesOrder;
659 public void setScopesOrder(String[] scopesOrder) {
660 myScopesOrder = scopesOrder;
664 private List<InspectionToolWrapper> createTools(@Nullable Project project) {
665 if (mySource != null) {
666 return ContainerUtil.map(mySource.getDefaultStates(project), ScopeToolState::getTool);
668 return myRegistrar.createTools();
671 private HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, @Nullable Project project) {
672 final ToolsImpl tools = getTools(key.toString(), project);
673 LOG.assertTrue(tools != null, "profile name: " + myName + " base profile: " + (myBaseProfile != null ? myBaseProfile.getName() : "-") + " key: " + key);
674 return tools.getLevel();
679 public InspectionProfileImpl getModifiableModel() {
680 return new InspectionProfileImpl(this);
683 private void copyToolsConfigurations(@NotNull InspectionProfileImpl profile, @Nullable Project project) {
685 for (ToolsImpl toolList : profile.myTools.values()) {
686 final ToolsImpl tools = myTools.get(toolList.getShortName());
687 final ScopeToolState defaultState = toolList.getDefaultState();
688 tools.setDefaultState(copyToolSettings(defaultState.getTool()), defaultState.isEnabled(), defaultState.getLevel());
689 tools.removeAllScopes();
690 final List<ScopeToolState> nonDefaultToolStates = toolList.getNonDefaultTools();
691 if (nonDefaultToolStates != null) {
692 for (ScopeToolState state : nonDefaultToolStates) {
693 final InspectionToolWrapper toolWrapper = copyToolSettings(state.getTool());
694 final NamedScope scope = state.getScope(project);
696 tools.addTool(scope, toolWrapper, state.isEnabled(), state.getLevel());
699 tools.addTool(state.getScopeName(), toolWrapper, state.isEnabled(), state.getLevel());
703 tools.setEnabled(toolList.isEnabled());
706 catch (WriteExternalException e) {
709 catch (InvalidDataException e) {
715 public void cleanup(@NotNull Project project) {
716 if (!myInitialized) {
720 for (final ToolsImpl toolList : myTools.values()) {
721 if (toolList.isEnabled()) {
722 for (InspectionToolWrapper toolWrapper : toolList.getAllTools()) {
723 toolWrapper.cleanup(project);
729 public void enableTool(@NotNull String toolId, Project project) {
730 final ToolsImpl tools = getTools(toolId, project);
731 tools.setEnabled(true);
732 if (tools.getNonDefaultTools() == null) {
733 tools.getDefaultState().setEnabled(true);
738 public void enableTool(@NotNull String inspectionTool, NamedScope namedScope, Project project) {
739 getTools(inspectionTool, project).enableTool(namedScope, project);
742 public void enableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, Project project) {
743 for (String inspectionTool : inspectionTools) {
744 enableTool(inspectionTool, namedScope, project);
749 public void disableTool(@NotNull String inspectionTool, NamedScope namedScope, @NotNull Project project) {
750 getTools(inspectionTool, project).disableTool(namedScope, project);
753 public void disableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, @NotNull Project project) {
754 for (String inspectionTool : inspectionTools) {
755 disableTool(inspectionTool, namedScope, project);
760 public void disableTool(@NotNull String inspectionTool, Project project) {
761 final ToolsImpl tools = getTools(inspectionTool, project);
762 tools.setEnabled(false);
763 if (tools.getNonDefaultTools() == null) {
764 tools.getDefaultState().setEnabled(false);
769 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, Project project) {
770 getTools(key.toString(), project).setLevel(level);
774 public boolean isToolEnabled(@Nullable HighlightDisplayKey key, PsiElement element) {
778 final Tools toolState = getTools(key.toString(), element == null ? null : element.getProject());
779 return toolState != null && toolState.isEnabled(element);
783 public boolean isToolEnabled(@Nullable HighlightDisplayKey key) {
784 return isToolEnabled(key, null);
788 public boolean isExecutable(Project project) {
789 initInspectionTools(project);
790 for (Tools tools : myTools.values()) {
791 if (tools.isEnabled()) return true;
796 //invoke when isChanged() == true
798 public void commit() {
799 LOG.assertTrue(mySource != null);
800 mySource.commit(this);
801 getProfileManager().updateProfile(mySource);
805 private void commit(@NotNull InspectionProfileImpl model) {
806 setName(model.getName());
807 setDescription(model.getDescription());
808 setProjectLevel(model.isProjectLevel());
809 myLockedProfile = model.myLockedProfile;
810 myDisplayLevelMap = model.myDisplayLevelMap;
811 myTools = model.myTools;
812 myProfileManager = model.getProfileManager();
814 InspectionProfileManager.getInstance().fireProfileChanged(model);
818 public String getDescription() {
819 return myDescription;
822 public void setDescription(String description) {
823 myDescription = description;
826 public void convert(@NotNull Element element, @NotNull Project project) {
827 final Element scopes = element.getChild("scopes");
828 if (scopes == null) {
832 initInspectionTools(project);
834 for (Element scopeElement : scopes.getChildren(SCOPE)) {
835 final String profile = scopeElement.getAttributeValue(ProjectInspectionProfileManagerKt.PROFILE);
836 if (profile != null) {
837 final InspectionProfileImpl inspectionProfile = (InspectionProfileImpl)getProfileManager().getProfile(profile);
838 if (inspectionProfile != null) {
839 final NamedScope scope = getProfileManager().getScopesManager().getScope(scopeElement.getAttributeValue(NAME));
841 for (InspectionToolWrapper toolWrapper : inspectionProfile.getInspectionTools(null)) {
842 final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName());
844 InspectionToolWrapper toolWrapperCopy = copyToolSettings(toolWrapper);
845 HighlightDisplayLevel errorLevel = inspectionProfile.getErrorLevel(key, null, project);
846 getTools(toolWrapper.getShortName(), project).addTool(scope, toolWrapperCopy, inspectionProfile.isToolEnabled(key), errorLevel);
848 catch (Exception e) {
856 reduceConvertedScopes();
859 private void reduceConvertedScopes() {
860 for (ToolsImpl tools : myTools.values()) {
861 final ScopeToolState toolState = tools.getDefaultState();
862 final List<ScopeToolState> nonDefaultTools = tools.getNonDefaultTools();
863 if (nonDefaultTools != null) {
864 boolean equal = true;
865 boolean isEnabled = toolState.isEnabled();
866 for (ScopeToolState state : nonDefaultTools) {
867 isEnabled |= state.isEnabled();
868 if (!state.equalTo(toolState)) {
872 tools.setEnabled(isEnabled);
874 tools.removeAllScopes();
881 public List<ScopeToolState> getAllTools(@Nullable Project project) {
882 initInspectionTools(project);
884 List<ScopeToolState> result = new ArrayList<>();
885 for (Tools tools : myTools.values()) {
886 tools.collectTools(result);
892 public List<ScopeToolState> getDefaultStates(@Nullable Project project) {
893 initInspectionTools(project);
894 final List<ScopeToolState> result = new ArrayList<>();
895 for (Tools tools : myTools.values()) {
896 result.add(tools.getDefaultState());
902 public List<ScopeToolState> getNonDefaultTools(@NotNull String shortName, Project project) {
903 final List<ScopeToolState> result = new ArrayList<>();
904 final List<ScopeToolState> nonDefaultTools = getTools(shortName, project).getNonDefaultTools();
905 if (nonDefaultTools != null) {
906 result.addAll(nonDefaultTools);
911 public boolean isToolEnabled(@NotNull HighlightDisplayKey key, NamedScope namedScope, Project project) {
912 return getTools(key.toString(), project).isEnabled(namedScope,project);
915 public void removeScope(@NotNull String toolId, @NotNull String scopeName, Project project) {
916 getTools(toolId, project).removeScope(scopeName);
919 public void removeScopes(@NotNull List<String> toolIds, @NotNull String scopeName, Project project) {
920 for (final String toolId : toolIds) {
921 removeScope(toolId, scopeName, project);
926 * @return null if it has no base profile
929 private Map<String, Boolean> getDisplayLevelMap() {
930 if (myBaseProfile == null) return null;
931 if (myDisplayLevelMap == null) {
932 synchronized (myLock) {
933 if (myDisplayLevelMap == null) {
934 initInspectionTools(null);
935 Set<String> names = myTools.keySet();
936 Map<String, Boolean> map = new THashMap<>(names.size());
937 for (String toolId : names) {
938 map.put(toolId, toolSettingsAreEqual(toolId, myBaseProfile, this));
940 myDisplayLevelMap = map;
945 return myDisplayLevelMap;
948 public void profileChanged() {
949 myDisplayLevelMap = null;
954 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, NamedScope scope, Project project) {
955 final ToolsImpl tools = getTools(key.toString(), project);
956 return tools != null ? tools.getLevel(scope, project) : HighlightDisplayLevel.WARNING;
959 public ScopeToolState addScope(@NotNull InspectionToolWrapper toolWrapper,
961 @NotNull HighlightDisplayLevel level,
964 return getTools(toolWrapper.getShortName(), project).prependTool(scope, toolWrapper, enabled, level);
967 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
968 getTools(key.toString(), project).setLevel(level, scopeName, project);
971 public void setErrorLevel(@NotNull List<HighlightDisplayKey> keys, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
972 for (HighlightDisplayKey key : keys) {
973 setErrorLevel(key, level, scopeName, project);
977 public ToolsImpl getTools(@NotNull String toolId, @Nullable Project project) {
978 initInspectionTools(project);
979 return myTools.get(toolId);
982 public void enableAllTools(Project project) {
983 for (InspectionToolWrapper entry : getInspectionTools(null)) {
984 enableTool(entry.getShortName(), project);
988 public void disableAllTools(Project project) {
989 for (InspectionToolWrapper entry : getInspectionTools(null)) {
990 disableTool(entry.getShortName(), project);
996 public String toString() {
997 return mySource == null ? getName() : getName() + " (copy)";
1001 public boolean equals(Object o) {
1002 return super.equals(o) && ((InspectionProfileImpl)o).getProfileManager() == getProfileManager();
1005 private static class InspectionProfileImplHolder {
1006 private static final InspectionProfileImpl DEFAULT_PROFILE = new InspectionProfileImpl(DEFAULT_PROFILE_NAME);