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.codeInspection.InspectionEP;
21 import com.intellij.codeInspection.InspectionProfile;
22 import com.intellij.codeInspection.InspectionProfileEntry;
23 import com.intellij.codeInspection.ModifiableModel;
24 import com.intellij.configurationStore.SchemeDataHolder;
25 import com.intellij.configurationStore.SerializableScheme;
26 import com.intellij.lang.annotation.HighlightSeverity;
27 import com.intellij.openapi.application.ApplicationManager;
28 import com.intellij.openapi.diagnostic.Logger;
29 import com.intellij.openapi.options.ExternalizableScheme;
30 import com.intellij.openapi.progress.ProcessCanceledException;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.util.*;
33 import com.intellij.profile.ProfileEx;
34 import com.intellij.profile.ProfileManager;
35 import com.intellij.profile.codeInspection.InspectionProfileManager;
36 import com.intellij.profile.codeInspection.ProjectInspectionProfileManager;
37 import com.intellij.profile.codeInspection.ProjectInspectionProfileManagerKt;
38 import com.intellij.profile.codeInspection.SeverityProvider;
39 import com.intellij.project.ProjectKt;
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 = false;
75 private final InspectionToolRegistrar myRegistrar;
77 private final Map<String, Element> myUninitializedSettings = new TreeMap<>();
78 protected InspectionProfileImpl mySource;
79 private Map<String, ToolsImpl> myTools = new THashMap<>();
80 private volatile Set<String> myChangedToolNames;
81 @Attribute("is_locked")
82 private boolean myLockedProfile;
83 private final InspectionProfileImpl myBaseProfile;
84 private volatile String myToolShortName = null;
85 private String[] myScopesOrder;
86 private String myDescription;
87 private boolean myModified;
88 private volatile boolean myInitialized;
90 private final Object myLock = new Object();
92 private SchemeDataHolder<? super InspectionProfileImpl> myDataHolder;
94 InspectionProfileImpl(@NotNull InspectionProfileImpl inspectionProfile) {
95 this(inspectionProfile.getName(), inspectionProfile.myRegistrar, inspectionProfile.getProfileManager(), inspectionProfile.myBaseProfile, null);
96 myUninitializedSettings.putAll(inspectionProfile.myUninitializedSettings);
98 setProjectLevel(inspectionProfile.isProjectLevel());
99 myLockedProfile = inspectionProfile.myLockedProfile;
100 mySource = inspectionProfile;
101 copyFrom(inspectionProfile);
104 public InspectionProfileImpl(@NotNull String profileName,
105 @NotNull InspectionToolRegistrar registrar,
106 @NotNull ProfileManager profileManager) {
107 this(profileName, registrar, profileManager, getDefaultProfile(), null);
110 public InspectionProfileImpl(@NotNull @NonNls String profileName) {
111 this(profileName, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), null, null);
114 public InspectionProfileImpl(@NotNull String profileName,
115 @NotNull InspectionToolRegistrar registrar,
116 @NotNull ProfileManager profileManager,
117 @Nullable InspectionProfileImpl baseProfile,
118 @Nullable SchemeDataHolder<? super InspectionProfileImpl> dataHolder) {
121 myRegistrar = registrar;
122 myBaseProfile = baseProfile;
123 myDataHolder = dataHolder;
124 myProfileManager = profileManager;
127 public InspectionProfileImpl(@NotNull String profileName,
128 @NotNull InspectionToolRegistrar registrar,
129 @NotNull ProfileManager profileManager,
130 @Nullable SchemeDataHolder<? super InspectionProfileImpl> dataHolder) {
131 this(profileName, registrar, profileManager, getDefaultProfile(), dataHolder);
135 public static InspectionProfileImpl createSimple(@NotNull String name,
136 @NotNull Project project,
137 @NotNull List<InspectionToolWrapper> toolWrappers) {
138 InspectionProfileImpl profile = new InspectionProfileImpl(name, new InspectionToolRegistrar() {
141 public List<InspectionToolWrapper> createTools() {
144 }, InspectionProfileManager.getInstance());
145 for (InspectionToolWrapper toolWrapper : toolWrappers) {
146 profile.enableTool(toolWrapper.getShortName(), project);
151 private static boolean toolSettingsAreEqual(@NotNull String toolName, @NotNull InspectionProfileImpl profile1, @NotNull InspectionProfileImpl profile2) {
152 final Tools toolList1 = profile1.myTools.get(toolName);
153 final Tools toolList2 = profile2.myTools.get(toolName);
154 return Comparing.equal(toolList1, toolList2);
158 private static InspectionToolWrapper copyToolSettings(@NotNull InspectionToolWrapper toolWrapper) {
159 final InspectionToolWrapper inspectionTool = toolWrapper.createCopy();
160 if (toolWrapper.isInitialized()) {
161 Element config = new Element("config");
162 toolWrapper.getTool().writeSettings(config);
163 inspectionTool.getTool().readSettings(config);
165 return inspectionTool;
169 public static InspectionProfileImpl getDefaultProfile() {
170 return InspectionProfileImplHolder.DEFAULT_PROFILE;
174 public void setModified(final boolean modified) {
175 myModified = modified;
179 public InspectionProfile getParentProfile() {
184 @SuppressWarnings({"SimplifiableIfStatement"})
185 public boolean isChanged() {
186 if (mySource != null && mySource.myLockedProfile != myLockedProfile) return true;
191 public boolean isProperSetting(@NotNull String toolId) {
192 if (myBaseProfile != null) {
193 final Tools tools = myBaseProfile.getTools(toolId, null);
194 final Tools currentTools = myTools.get(toolId);
195 return !Comparing.equal(tools, currentTools);
201 public void resetToBase(@Nullable Project project) {
202 initInspectionTools(project);
204 copyToolsConfigurations(myBaseProfile, project);
205 myChangedToolNames = null;
209 public void resetToEmpty(Project project) {
210 initInspectionTools(project);
211 final InspectionToolWrapper[] profileEntries = getInspectionTools(null);
212 for (InspectionToolWrapper toolWrapper : profileEntries) {
213 disableTool(toolWrapper.getShortName(), project);
218 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey inspectionToolKey, PsiElement element) {
219 Project project = element == null ? null : element.getProject();
220 final ToolsImpl tools = getTools(inspectionToolKey.toString(), project);
221 HighlightDisplayLevel level = tools != null ? tools.getLevel(element) : HighlightDisplayLevel.WARNING;
222 if (!((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().isSeverityValid(level.getSeverity().getName())) {
223 level = HighlightDisplayLevel.WARNING;
224 setErrorLevel(inspectionToolKey, level, project);
230 public void readExternal(@NotNull Element element) {
231 super.readExternal(element);
233 final Element highlightElement = element.getChild(USED_LEVELS);
234 if (highlightElement != null) {
236 ((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().readExternal(highlightElement);
239 String version = element.getAttributeValue(VERSION_TAG);
240 if (version == null || !version.equals(VALID_VERSION)) {
241 InspectionToolWrapper[] tools = getInspectionTools(null);
242 for (Element toolElement : element.getChildren("inspection_tool")) {
243 String toolClassName = toolElement.getAttributeValue(CLASS_TAG);
244 String shortName = convertToShortName(toolClassName, tools);
245 if (shortName == null) {
248 toolElement.setAttribute(CLASS_TAG, shortName);
249 myUninitializedSettings.put(shortName, toolElement.clone());
253 for (Element toolElement : element.getChildren(INSPECTION_TOOL_TAG)) {
254 myUninitializedSettings.put(toolElement.getAttributeValue(CLASS_TAG), toolElement.clone());
260 private static String convertToShortName(@Nullable String displayName, InspectionToolWrapper[] tools) {
261 if (displayName == null) return null;
262 for (InspectionToolWrapper tool : tools) {
263 if (displayName.equals(tool.getDisplayName())) {
264 return tool.getShortName();
271 public Set<HighlightSeverity> getUsedSeverities() {
272 LOG.assertTrue(myInitialized);
273 Set<HighlightSeverity> result = new THashSet<>();
274 for (Tools tools : myTools.values()) {
275 for (ScopeToolState state : tools.getTools()) {
276 result.add(state.getLevel().getSeverity());
283 public Element writeScheme() {
284 if (myDataHolder != null) {
285 return myDataHolder.read();
288 Element element = new Element("profile");
289 Element result = isProjectLevel() ? element.setAttribute("version", "1.0") : element.setAttribute("profile_name", getName());
290 serializeInto(result, false);
292 if (isProjectLevel() && ProjectKt.isDirectoryBased(((ProjectInspectionProfileManager)myProfileManager).getProject())) {
293 return new Element("component").setAttribute("name", "InspectionProjectProfileManager").addContent(result);
299 public void serializeInto(@NotNull Element element, boolean preserveCompatibility) {
300 // must be first - compatibility
301 element.setAttribute(VERSION_TAG, VALID_VERSION);
303 super.serializeInto(element, preserveCompatibility);
305 synchronized (myLock) {
306 if (!myInitialized) {
307 for (Element el : myUninitializedSettings.values()) {
308 element.addContent(el.clone());
314 Set<String> changedToolNames = getChangedToolNames();
315 if (changedToolNames == null) {
319 List<String> allToolNames = new ArrayList<>(myTools.keySet());
320 allToolNames.addAll(myUninitializedSettings.keySet());
321 allToolNames.sort(null);
322 for (String toolName : allToolNames) {
323 Element toolElement = myUninitializedSettings.get(toolName);
324 if (toolElement != null) {
325 element.addContent(toolElement.clone());
329 if (!myLockedProfile && !changedToolNames.contains(toolName)) {
330 markSettingsMerged(toolName, element);
334 ToolsImpl toolList = myTools.get(toolName);
335 LOG.assertTrue(toolList != null);
336 Element inspectionElement = new Element(INSPECTION_TOOL_TAG);
337 inspectionElement.setAttribute(CLASS_TAG, toolName);
339 toolList.writeExternal(inspectionElement);
341 catch (WriteExternalException e) {
346 if (!areSettingsMerged(toolName, inspectionElement)) {
347 element.addContent(inspectionElement);
352 private void markSettingsMerged(@NotNull String toolName, @NotNull Element element) {
353 //add marker if already merged but result is now default (-> empty node)
354 String mergedName = InspectionElementsMergerBase.getMergedMarkerName(toolName);
355 if (!myUninitializedSettings.containsKey(mergedName)) {
356 InspectionElementsMergerBase merger = getMerger(toolName);
357 if (merger != null && merger.markSettingsMerged(myUninitializedSettings)) {
358 element.addContent(new Element(INSPECTION_TOOL_TAG).setAttribute(CLASS_TAG, mergedName));
363 private boolean areSettingsMerged(String toolName, Element inspectionElement) {
364 //skip merged settings as they could be restored from already provided data
365 final InspectionElementsMergerBase merger = getMerger(toolName);
366 return merger != null && merger.areSettingsMerged(myUninitializedSettings, inspectionElement);
369 public void collectDependentInspections(@NotNull InspectionToolWrapper toolWrapper,
370 @NotNull Set<InspectionToolWrapper> dependentEntries,
372 String mainToolId = toolWrapper.getMainToolId();
374 if (mainToolId != null) {
375 InspectionToolWrapper dependentEntryWrapper = getInspectionTool(mainToolId, project);
377 if (dependentEntryWrapper == null) {
378 LOG.error("Can't find main tool: '" + mainToolId+"' which was specified in "+toolWrapper);
381 if (!dependentEntries.add(dependentEntryWrapper)) {
382 collectDependentInspections(dependentEntryWrapper, dependentEntries, project);
389 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, @NotNull PsiElement element) {
390 final Tools toolList = getTools(shortName, element.getProject());
391 return toolList == null ? null : toolList.getInspectionTool(element);
396 public InspectionProfileEntry getUnwrappedTool(@NotNull String shortName, @NotNull PsiElement element) {
397 InspectionToolWrapper tool = getInspectionTool(shortName, element);
398 return tool == null ? null : tool.getTool();
402 public <T extends InspectionProfileEntry> T getUnwrappedTool(@NotNull Key<T> shortNameKey, @NotNull PsiElement element) {
403 //noinspection unchecked
404 return (T) getUnwrappedTool(shortNameKey.toString(), element);
408 public void modifyProfile(@NotNull Consumer<ModifiableModel> modelConsumer) {
409 ModifiableModel model = getModifiableModel();
410 modelConsumer.consume(model);
415 public <T extends InspectionProfileEntry> void modifyToolSettings(@NotNull final Key<T> shortNameKey,
416 @NotNull final PsiElement psiElement,
417 @NotNull final Consumer<T> toolConsumer) {
418 modifyProfile(model -> {
419 InspectionProfileEntry tool = model.getUnwrappedTool(shortNameKey.toString(), psiElement);
420 //noinspection unchecked
421 toolConsumer.consume((T) tool);
427 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, Project project) {
428 final ToolsImpl tools = getTools(shortName, project);
429 return tools != null? tools.getTool() : null;
432 public InspectionToolWrapper getToolById(@NotNull String id, @NotNull PsiElement element) {
433 initInspectionTools(element.getProject());
434 for (Tools toolList : myTools.values()) {
435 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
436 if (id.equals(tool.getID())) return tool;
442 public List<InspectionToolWrapper> findToolsById(@NotNull String id, @NotNull PsiElement element) {
443 List<InspectionToolWrapper> result = null;
444 initInspectionTools(element.getProject());
445 for (Tools toolList : myTools.values()) {
446 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
447 if (id.equals(tool.getID())) {
448 if (result == null) {
449 result = new ArrayList<>();
459 InspectionProfileManager.getInstance().fireProfileChanged(this);
464 public String getSingleTool() {
465 return myToolShortName;
469 public void setSingleTool(@NotNull final String toolShortName) {
470 myToolShortName = toolShortName;
475 public String getDisplayName() {
480 public void scopesChanged() {
481 for (ScopeToolState toolState : getAllTools(null)) {
482 toolState.scopesChanged();
484 InspectionProfileManager.getInstance().fireProfileChanged(this);
489 public boolean isProfileLocked() {
490 return myLockedProfile;
494 public void lockProfile(boolean isLocked) {
495 myLockedProfile = isLocked;
500 public InspectionToolWrapper[] getInspectionTools(@Nullable PsiElement element) {
501 initInspectionTools(element == null ? null : element.getProject());
502 List<InspectionToolWrapper> result = new ArrayList<>();
503 for (Tools toolList : myTools.values()) {
504 result.add(toolList.getInspectionTool(element));
506 return result.toArray(new InspectionToolWrapper[result.size()]);
511 public List<Tools> getAllEnabledInspectionTools(Project project) {
512 initInspectionTools(project);
513 List<Tools> result = new ArrayList<>();
514 for (final ToolsImpl toolList : myTools.values()) {
515 if (toolList.isEnabled()) {
516 result.add(toolList);
523 public void disableTool(@NotNull String toolId, @NotNull PsiElement element) {
524 getTools(toolId, element.getProject()).disableTool(element);
527 public void disableToolByDefault(@NotNull Collection<String> toolIds, @Nullable Project project) {
528 for (String toolId : toolIds) {
529 getTools(toolId, project).setDefaultEnabled(false);
534 public ScopeToolState getToolDefaultState(@NotNull String toolId, @Nullable Project project) {
535 return getTools(toolId, project).getDefaultState();
538 public void enableToolsByDefault(@NotNull List<String> toolIds, Project project) {
539 for (final String toolId : toolIds) {
540 getTools(toolId, project).setDefaultEnabled(true);
544 public boolean wasInitialized() {
545 return myInitialized;
548 public void initInspectionTools(@Nullable Project project) {
549 //noinspection TestOnlyProblems
550 if (myInitialized || (ApplicationManager.getApplication().isUnitTestMode() && !INIT_INSPECTIONS)) {
554 synchronized (myLock) {
555 if (!myInitialized) {
561 private void initialize(@Nullable Project project) {
562 SchemeDataHolder<? super InspectionProfileImpl> dataHolder = myDataHolder;
563 if (dataHolder != null) {
565 Element element = dataHolder.read();
566 if (element.getName().equals("component")) {
567 element = element.getChild("profile");
569 assert element != null;
570 readExternal(element);
573 if (myBaseProfile != null) {
574 myBaseProfile.initInspectionTools(project);
577 final List<InspectionToolWrapper> tools;
579 if (mySource == null) {
580 tools = myRegistrar.createTools();
583 tools = ContainerUtil.map(mySource.getDefaultStates(project), ScopeToolState::getTool);
586 catch (ProcessCanceledException ignored) {
590 final Map<String, List<String>> dependencies = new THashMap<>();
591 for (InspectionToolWrapper toolWrapper : tools) {
592 addTool(project, toolWrapper, dependencies);
595 DFSTBuilder<String> builder = new DFSTBuilder<>(GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<String>() {
597 public Collection<String> getNodes() {
598 return dependencies.keySet();
602 public Iterator<String> getIn(String n) {
603 return dependencies.get(n).iterator();
606 if (builder.isAcyclic()) {
607 myScopesOrder = ArrayUtil.toStringArray(builder.getSortedNodes());
610 if (mySource != null) {
611 copyToolsConfigurations(mySource, project);
614 myInitialized = true;
615 if (dataHolder != null) {
616 // should be only after set myInitialized
617 dataHolder.updateDigest(this);
621 public void addTool(@Nullable Project project, @NotNull InspectionToolWrapper toolWrapper, @NotNull Map<String, List<String>> dependencies) {
622 final String shortName = toolWrapper.getShortName();
623 HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
625 final InspectionEP extension = toolWrapper.getExtension();
626 Computable<String> computable = extension == null ? new Computable.PredefinedValueComputable<>(toolWrapper.getDisplayName()) : extension::getDisplayName;
627 if (toolWrapper instanceof LocalInspectionToolWrapper) {
628 key = HighlightDisplayKey.register(shortName, computable, toolWrapper.getID(),
629 ((LocalInspectionToolWrapper)toolWrapper).getAlternativeID());
632 key = HighlightDisplayKey.register(shortName, computable);
637 LOG.error(shortName + " ; number of initialized tools: " + myTools.size());
641 HighlightDisplayLevel baseLevel = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null
642 ? myBaseProfile.getErrorLevel(key, project)
643 : HighlightDisplayLevel.DO_NOT_SHOW;
644 HighlightDisplayLevel defaultLevel = toolWrapper.getDefaultLevel();
645 HighlightDisplayLevel level = baseLevel.getSeverity().compareTo(defaultLevel.getSeverity()) > 0 ? baseLevel : defaultLevel;
646 boolean enabled = myBaseProfile != null ? myBaseProfile.isToolEnabled(key) : toolWrapper.isEnabledByDefault();
647 final ToolsImpl toolsList = new ToolsImpl(toolWrapper, level, !myLockedProfile && enabled, enabled);
648 final Element element = myUninitializedSettings.remove(shortName);
650 if (element != null) {
651 toolsList.readExternal(element, this, dependencies);
653 else if (!myUninitializedSettings.containsKey(InspectionElementsMergerBase.getMergedMarkerName(shortName))) {
654 final InspectionElementsMergerBase merger = getMerger(shortName);
655 Element merged = merger == null ? null : merger.merge(myUninitializedSettings);
656 if (merged != null) {
657 toolsList.readExternal(merged, this, dependencies);
659 else if (isProfileLocked()) {
660 // https://youtrack.jetbrains.com/issue/IDEA-158936
661 toolsList.setEnabled(false);
662 if (toolsList.getNonDefaultTools() == null) {
663 toolsList.getDefaultState().setEnabled(false);
668 catch (InvalidDataException e) {
669 LOG.error("Can't read settings for " + toolWrapper, e);
671 myTools.put(shortName, toolsList);
675 private static InspectionElementsMergerBase getMerger(String shortName) {
676 final InspectionElementsMerger merger = InspectionElementsMerger.getMerger(shortName);
677 if (merger instanceof InspectionElementsMergerBase) {
678 return (InspectionElementsMergerBase)merger;
680 return merger != null ? new InspectionElementsMergerBase() {
682 public String getMergedToolName() {
683 return merger.getMergedToolName();
687 public String[] getSourceToolNames() {
688 return merger.getSourceToolNames();
695 public String[] getScopesOrder() {
696 return myScopesOrder;
699 public void setScopesOrder(String[] scopesOrder) {
700 myScopesOrder = scopesOrder;
703 private HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, @Nullable Project project) {
704 final ToolsImpl tools = getTools(key.toString(), project);
705 LOG.assertTrue(tools != null, "profile name: " + myName + " base profile: " + (myBaseProfile != null ? myBaseProfile.getName() : "-") + " key: " + key);
706 return tools.getLevel();
711 public InspectionProfileImpl getModifiableModel() {
712 return new InspectionProfileImpl(this);
715 private void copyToolsConfigurations(@NotNull InspectionProfileImpl profile, @Nullable Project project) {
717 for (ToolsImpl toolList : profile.myTools.values()) {
718 final ToolsImpl tools = myTools.get(toolList.getShortName());
719 final ScopeToolState defaultState = toolList.getDefaultState();
720 tools.setDefaultState(copyToolSettings(defaultState.getTool()), defaultState.isEnabled(), defaultState.getLevel());
721 tools.removeAllScopes();
722 final List<ScopeToolState> nonDefaultToolStates = toolList.getNonDefaultTools();
723 if (nonDefaultToolStates != null) {
724 for (ScopeToolState state : nonDefaultToolStates) {
725 final InspectionToolWrapper toolWrapper = copyToolSettings(state.getTool());
726 final NamedScope scope = state.getScope(project);
728 tools.addTool(scope, toolWrapper, state.isEnabled(), state.getLevel());
731 tools.addTool(state.getScopeName(), toolWrapper, state.isEnabled(), state.getLevel());
735 tools.setEnabled(toolList.isEnabled());
738 catch (WriteExternalException e) {
741 catch (InvalidDataException e) {
747 public void cleanup(@NotNull Project project) {
748 if (!myInitialized) {
752 for (ToolsImpl toolList : myTools.values()) {
753 if (toolList.isEnabled()) {
754 toolList.cleanupTools(project);
759 public void enableTool(@NotNull String toolId, Project project) {
760 final ToolsImpl tools = getTools(toolId, project);
761 tools.setEnabled(true);
762 if (tools.getNonDefaultTools() == null) {
763 tools.getDefaultState().setEnabled(true);
768 public void enableTool(@NotNull String inspectionTool, NamedScope namedScope, Project project) {
769 getTools(inspectionTool, project).enableTool(namedScope, project);
772 public void enableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, Project project) {
773 for (String inspectionTool : inspectionTools) {
774 enableTool(inspectionTool, namedScope, project);
778 public void disableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, @NotNull Project project) {
779 for (String inspectionTool : inspectionTools) {
780 getTools(inspectionTool, project).disableTool(namedScope, project);
785 public void disableTool(@NotNull String inspectionTool, @Nullable Project project) {
786 ToolsImpl tools = getTools(inspectionTool, project);
787 tools.setEnabled(false);
788 if (tools.getNonDefaultTools() == null) {
789 tools.getDefaultState().setEnabled(false);
794 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, Project project) {
795 getTools(key.toString(), project).setLevel(level);
799 public boolean isToolEnabled(@Nullable HighlightDisplayKey key, PsiElement element) {
803 final Tools toolState = getTools(key.toString(), element == null ? null : element.getProject());
804 return toolState != null && toolState.isEnabled(element);
808 public boolean isToolEnabled(@Nullable HighlightDisplayKey key) {
809 return isToolEnabled(key, null);
813 public boolean isExecutable(Project project) {
814 initInspectionTools(project);
815 for (Tools tools : myTools.values()) {
816 if (tools.isEnabled()) return true;
821 //invoke when isChanged() == true
823 public void commit() {
824 LOG.assertTrue(mySource != null);
825 mySource.commit(this);
826 getProfileManager().updateProfile(mySource);
830 private void commit(@NotNull InspectionProfileImpl model) {
831 setName(model.getName());
832 setDescription(model.getDescription());
833 setProjectLevel(model.isProjectLevel());
834 myLockedProfile = model.myLockedProfile;
835 myChangedToolNames = model.myChangedToolNames;
836 myTools = model.myTools;
837 myProfileManager = model.getProfileManager();
839 InspectionProfileManager.getInstance().fireProfileChanged(model);
843 public String getDescription() {
844 return myDescription;
847 public void setDescription(String description) {
848 myDescription = description;
851 public void convert(@NotNull Element element, @NotNull Project project) {
852 final Element scopes = element.getChild("scopes");
853 if (scopes == null) {
857 initInspectionTools(project);
859 for (Element scopeElement : scopes.getChildren(SCOPE)) {
860 final String profile = scopeElement.getAttributeValue(ProjectInspectionProfileManagerKt.PROFILE);
861 if (profile != null) {
862 final InspectionProfileImpl inspectionProfile = (InspectionProfileImpl)getProfileManager().getProfile(profile);
863 if (inspectionProfile != null) {
864 final NamedScope scope = getProfileManager().getScopesManager().getScope(scopeElement.getAttributeValue(NAME));
866 for (InspectionToolWrapper toolWrapper : inspectionProfile.getInspectionTools(null)) {
867 final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName());
869 InspectionToolWrapper toolWrapperCopy = copyToolSettings(toolWrapper);
870 HighlightDisplayLevel errorLevel = inspectionProfile.getErrorLevel(key, null, project);
871 getTools(toolWrapper.getShortName(), project).addTool(scope, toolWrapperCopy, inspectionProfile.isToolEnabled(key), errorLevel);
873 catch (Exception e) {
881 reduceConvertedScopes();
884 private void reduceConvertedScopes() {
885 for (ToolsImpl tools : myTools.values()) {
886 final ScopeToolState toolState = tools.getDefaultState();
887 final List<ScopeToolState> nonDefaultTools = tools.getNonDefaultTools();
888 if (nonDefaultTools != null) {
889 boolean equal = true;
890 boolean isEnabled = toolState.isEnabled();
891 for (ScopeToolState state : nonDefaultTools) {
892 isEnabled |= state.isEnabled();
893 if (!state.equalTo(toolState)) {
897 tools.setEnabled(isEnabled);
899 tools.removeAllScopes();
906 public List<ScopeToolState> getAllTools(@Nullable Project project) {
907 initInspectionTools(project);
909 List<ScopeToolState> result = new ArrayList<>();
910 for (Tools tools : myTools.values()) {
911 tools.collectTools(result);
917 public List<ScopeToolState> getDefaultStates(@Nullable Project project) {
918 initInspectionTools(project);
919 List<ScopeToolState> result = new ArrayList<>();
920 for (Tools tools : myTools.values()) {
921 result.add(tools.getDefaultState());
927 public List<ScopeToolState> getNonDefaultTools(@NotNull String shortName, Project project) {
928 final List<ScopeToolState> result = new ArrayList<>();
929 final List<ScopeToolState> nonDefaultTools = getTools(shortName, project).getNonDefaultTools();
930 if (nonDefaultTools != null) {
931 result.addAll(nonDefaultTools);
936 public boolean isToolEnabled(@NotNull HighlightDisplayKey key, NamedScope namedScope, Project project) {
937 return getTools(key.toString(), project).isEnabled(namedScope,project);
940 public void removeScope(@NotNull String toolId, @NotNull String scopeName, Project project) {
941 getTools(toolId, project).removeScope(scopeName);
944 public void removeScopes(@NotNull List<String> toolIds, @NotNull String scopeName, Project project) {
945 for (final String toolId : toolIds) {
946 removeScope(toolId, scopeName, project);
951 * @return null if it has no base profile
954 private Set<String> getChangedToolNames() {
955 if (myBaseProfile == null) return null;
956 if (myChangedToolNames == null) {
957 synchronized (myLock) {
958 if (myChangedToolNames == null) {
959 initInspectionTools(null);
960 Set<String> names = myTools.keySet();
961 Set<String> map = new THashSet<>(names.size());
962 for (String toolId : names) {
963 if (!toolSettingsAreEqual(toolId, myBaseProfile, this)) {
967 myChangedToolNames = map;
972 return myChangedToolNames;
975 public void profileChanged() {
976 myChangedToolNames = null;
981 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, NamedScope scope, Project project) {
982 final ToolsImpl tools = getTools(key.toString(), project);
983 return tools != null ? tools.getLevel(scope, project) : HighlightDisplayLevel.WARNING;
986 public ScopeToolState addScope(@NotNull InspectionToolWrapper toolWrapper,
988 @NotNull HighlightDisplayLevel level,
991 return getTools(toolWrapper.getShortName(), project).prependTool(scope, toolWrapper, enabled, level);
994 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
995 getTools(key.toString(), project).setLevel(level, scopeName, project);
998 public void setErrorLevel(@NotNull List<HighlightDisplayKey> keys, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
999 for (HighlightDisplayKey key : keys) {
1000 setErrorLevel(key, level, scopeName, project);
1004 public ToolsImpl getTools(@NotNull String toolId, @Nullable Project project) {
1005 initInspectionTools(project);
1006 return myTools.get(toolId);
1009 public void enableAllTools(Project project) {
1010 for (InspectionToolWrapper entry : getInspectionTools(null)) {
1011 enableTool(entry.getShortName(), project);
1017 public String toString() {
1018 return mySource == null ? getName() : getName() + " (copy)";
1022 public boolean equals(Object o) {
1023 return super.equals(o) && ((InspectionProfileImpl)o).getProfileManager() == getProfileManager();
1026 private static class InspectionProfileImplHolder {
1027 private static final InspectionProfileImpl DEFAULT_PROFILE = new InspectionProfileImpl(DEFAULT_PROFILE_NAME);