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.SeverityProvider;
37 import com.intellij.psi.PsiElement;
38 import com.intellij.psi.search.scope.packageSet.NamedScope;
39 import com.intellij.util.ArrayUtil;
40 import com.intellij.util.Consumer;
41 import com.intellij.util.containers.ContainerUtil;
42 import com.intellij.util.graph.CachingSemiGraph;
43 import com.intellij.util.graph.DFSTBuilder;
44 import com.intellij.util.graph.GraphGenerator;
45 import com.intellij.util.xmlb.annotations.Attribute;
46 import com.intellij.util.xmlb.annotations.Tag;
47 import com.intellij.util.xmlb.annotations.Transient;
48 import gnu.trove.THashMap;
49 import gnu.trove.THashSet;
50 import org.jdom.Element;
51 import org.jetbrains.annotations.NonNls;
52 import org.jetbrains.annotations.NotNull;
53 import org.jetbrains.annotations.Nullable;
54 import org.jetbrains.annotations.TestOnly;
61 public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, InspectionProfile, ExternalizableScheme,
63 @NonNls static final String INSPECTION_TOOL_TAG = "inspection_tool";
64 @NonNls static final String CLASS_TAG = "class";
65 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.InspectionProfileImpl");
66 @NonNls private static final String VALID_VERSION = "1.0";
67 @NonNls private static final String VERSION_TAG = "version";
68 @NonNls private static final String USED_LEVELS = "used_levels";
69 public static final String DEFAULT_PROFILE_NAME = "Default";
71 public static boolean INIT_INSPECTIONS = false;
72 private final InspectionToolRegistrar myRegistrar;
74 private final Map<String, Element> myUninitializedSettings = new TreeMap<>();
75 protected InspectionProfileImpl mySource;
76 private Map<String, ToolsImpl> myTools = new THashMap<>();
77 private volatile Set<String> myChangedToolNames;
78 @Attribute("is_locked")
79 private boolean myLockedProfile;
80 private final InspectionProfileImpl myBaseProfile;
81 private volatile String myToolShortName = null;
82 private String[] myScopesOrder;
83 private String myDescription;
84 private boolean myModified;
85 private volatile boolean myInitialized;
87 private final Object myLock = new Object();
89 private SchemeDataHolder<? super InspectionProfileImpl> myDataHolder;
91 InspectionProfileImpl(@NotNull InspectionProfileImpl inspectionProfile) {
92 this(inspectionProfile.getName(), inspectionProfile.myRegistrar, inspectionProfile.getProfileManager(), inspectionProfile.myBaseProfile, null);
93 myUninitializedSettings.putAll(inspectionProfile.myUninitializedSettings);
95 setProjectLevel(inspectionProfile.isProjectLevel());
96 myLockedProfile = inspectionProfile.myLockedProfile;
97 mySource = inspectionProfile;
98 copyFrom(inspectionProfile);
101 public InspectionProfileImpl(@NotNull String profileName,
102 @NotNull InspectionToolRegistrar registrar,
103 @NotNull ProfileManager profileManager) {
104 this(profileName, registrar, profileManager, getBaseProfile(), null);
107 public InspectionProfileImpl(@NotNull @NonNls String profileName) {
108 this(profileName, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), null, null);
111 public InspectionProfileImpl(@NotNull String profileName,
112 @NotNull InspectionToolRegistrar registrar,
113 @NotNull ProfileManager profileManager,
114 @Nullable InspectionProfileImpl baseProfile,
115 @Nullable SchemeDataHolder<? super InspectionProfileImpl> dataHolder) {
118 myRegistrar = registrar;
119 myBaseProfile = baseProfile;
120 myDataHolder = dataHolder;
121 myProfileManager = profileManager;
124 public InspectionProfileImpl(@NotNull String profileName,
125 @NotNull InspectionToolRegistrar registrar,
126 @NotNull ProfileManager profileManager,
127 @Nullable SchemeDataHolder<? super InspectionProfileImpl> dataHolder) {
128 this(profileName, registrar, profileManager, getBaseProfile(), dataHolder);
132 public static InspectionProfileImpl createSimple(@NotNull String name,
133 @NotNull Project project,
134 @NotNull List<InspectionToolWrapper> toolWrappers) {
135 InspectionProfileImpl profile = new InspectionProfileImpl(name, new InspectionToolRegistrar() {
138 public List<InspectionToolWrapper> createTools() {
141 }, InspectionProfileManager.getInstance());
142 for (InspectionToolWrapper toolWrapper : toolWrappers) {
143 profile.enableTool(toolWrapper.getShortName(), project);
148 private static boolean toolSettingsAreEqual(@NotNull String toolName, @NotNull InspectionProfileImpl profile1, @NotNull InspectionProfileImpl profile2) {
149 final Tools toolList1 = profile1.myTools.get(toolName);
150 final Tools toolList2 = profile2.myTools.get(toolName);
151 return Comparing.equal(toolList1, toolList2);
155 private static InspectionToolWrapper copyToolSettings(@NotNull InspectionToolWrapper toolWrapper) {
156 final InspectionToolWrapper inspectionTool = toolWrapper.createCopy();
157 if (toolWrapper.isInitialized()) {
158 Element config = new Element("config");
159 toolWrapper.getTool().writeSettings(config);
160 inspectionTool.getTool().readSettings(config);
162 return inspectionTool;
166 public static InspectionProfileImpl getBaseProfile() {
167 return InspectionProfileImplHolder.DEFAULT_PROFILE;
171 public void setModified(final boolean modified) {
172 myModified = modified;
176 public InspectionProfile getParentProfile() {
181 @SuppressWarnings({"SimplifiableIfStatement"})
182 public boolean isChanged() {
183 if (mySource != null && mySource.myLockedProfile != myLockedProfile) return true;
188 public boolean isProperSetting(@NotNull String toolId) {
189 if (myBaseProfile != null) {
190 final Tools tools = myBaseProfile.getTools(toolId, null);
191 final Tools currentTools = myTools.get(toolId);
192 return !Comparing.equal(tools, currentTools);
198 public void resetToBase(@Nullable Project project) {
199 initInspectionTools(project);
201 copyToolsConfigurations(myBaseProfile, project);
202 myChangedToolNames = null;
206 public void resetToEmpty(Project project) {
207 initInspectionTools(project);
208 final InspectionToolWrapper[] profileEntries = getInspectionTools(null);
209 for (InspectionToolWrapper toolWrapper : profileEntries) {
210 disableTool(toolWrapper.getShortName(), project);
215 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey inspectionToolKey, PsiElement element) {
216 Project project = element == null ? null : element.getProject();
217 final ToolsImpl tools = getTools(inspectionToolKey.toString(), project);
218 HighlightDisplayLevel level = tools != null ? tools.getLevel(element) : HighlightDisplayLevel.WARNING;
219 if (!((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().isSeverityValid(level.getSeverity().getName())) {
220 level = HighlightDisplayLevel.WARNING;
221 setErrorLevel(inspectionToolKey, level, project);
227 public void readExternal(@NotNull Element element) {
228 super.readExternal(element);
230 final Element highlightElement = element.getChild(USED_LEVELS);
231 if (highlightElement != null) {
233 ((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().readExternal(highlightElement);
236 String version = element.getAttributeValue(VERSION_TAG);
237 if (version == null || !version.equals(VALID_VERSION)) {
238 InspectionToolWrapper[] tools = getInspectionTools(null);
239 for (Element toolElement : element.getChildren("inspection_tool")) {
240 String toolClassName = toolElement.getAttributeValue(CLASS_TAG);
241 String shortName = convertToShortName(toolClassName, tools);
242 if (shortName == null) {
245 toolElement.setAttribute(CLASS_TAG, shortName);
246 myUninitializedSettings.put(shortName, toolElement.clone());
250 for (Element toolElement : element.getChildren(INSPECTION_TOOL_TAG)) {
251 myUninitializedSettings.put(toolElement.getAttributeValue(CLASS_TAG), toolElement.clone());
257 private static String convertToShortName(@Nullable String displayName, InspectionToolWrapper[] tools) {
258 if (displayName == null) return null;
259 for (InspectionToolWrapper tool : tools) {
260 if (displayName.equals(tool.getDisplayName())) {
261 return tool.getShortName();
268 public Set<HighlightSeverity> getUsedSeverities() {
269 LOG.assertTrue(myInitialized);
270 Set<HighlightSeverity> result = new THashSet<>();
271 for (Tools tools : myTools.values()) {
272 for (ScopeToolState state : tools.getTools()) {
273 result.add(state.getLevel().getSeverity());
280 public Element writeScheme() {
281 return myDataHolder == null ? super.writeScheme() : myDataHolder.read();
285 public void writeExternal(@NotNull Element element) {
286 // must be first - compatibility
287 element.setAttribute(VERSION_TAG, VALID_VERSION);
289 super.writeExternal(element);
291 synchronized (myLock) {
292 if (!myInitialized) {
293 for (Element el : myUninitializedSettings.values()) {
294 element.addContent(el.clone());
300 Set<String> changedToolNames = getChangedToolNames();
301 if (changedToolNames == null) {
305 List<String> allToolNames = new ArrayList<>(myTools.keySet());
306 allToolNames.addAll(myUninitializedSettings.keySet());
307 allToolNames.sort(null);
308 for (String toolName : allToolNames) {
309 Element toolElement = myUninitializedSettings.get(toolName);
310 if (toolElement != null) {
311 element.addContent(toolElement.clone());
315 if (!myLockedProfile && !changedToolNames.contains(toolName)) {
316 markSettingsMerged(toolName, element);
320 ToolsImpl toolList = myTools.get(toolName);
321 LOG.assertTrue(toolList != null);
322 Element inspectionElement = new Element(INSPECTION_TOOL_TAG);
323 inspectionElement.setAttribute(CLASS_TAG, toolName);
325 toolList.writeExternal(inspectionElement);
327 catch (WriteExternalException e) {
332 if (!areSettingsMerged(toolName, inspectionElement)) {
333 element.addContent(inspectionElement);
338 private void markSettingsMerged(@NotNull String toolName, @NotNull Element element) {
339 //add marker if already merged but result is now default (-> empty node)
340 String mergedName = InspectionElementsMergerBase.getMergedMarkerName(toolName);
341 if (!myUninitializedSettings.containsKey(mergedName)) {
342 InspectionElementsMergerBase merger = getMerger(toolName);
343 if (merger != null && merger.markSettingsMerged(myUninitializedSettings)) {
344 element.addContent(new Element(INSPECTION_TOOL_TAG).setAttribute(CLASS_TAG, mergedName));
349 private boolean areSettingsMerged(String toolName, Element inspectionElement) {
350 //skip merged settings as they could be restored from already provided data
351 final InspectionElementsMergerBase merger = getMerger(toolName);
352 return merger != null && merger.areSettingsMerged(myUninitializedSettings, inspectionElement);
355 public void collectDependentInspections(@NotNull InspectionToolWrapper toolWrapper,
356 @NotNull Set<InspectionToolWrapper> dependentEntries,
358 String mainToolId = toolWrapper.getMainToolId();
360 if (mainToolId != null) {
361 InspectionToolWrapper dependentEntryWrapper = getInspectionTool(mainToolId, project);
363 if (dependentEntryWrapper == null) {
364 LOG.error("Can't find main tool: '" + mainToolId+"' which was specified in "+toolWrapper);
367 if (!dependentEntries.add(dependentEntryWrapper)) {
368 collectDependentInspections(dependentEntryWrapper, dependentEntries, project);
375 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, @NotNull PsiElement element) {
376 final Tools toolList = getTools(shortName, element.getProject());
377 return toolList == null ? null : toolList.getInspectionTool(element);
382 public InspectionProfileEntry getUnwrappedTool(@NotNull String shortName, @NotNull PsiElement element) {
383 InspectionToolWrapper tool = getInspectionTool(shortName, element);
384 return tool == null ? null : tool.getTool();
388 public <T extends InspectionProfileEntry> T getUnwrappedTool(@NotNull Key<T> shortNameKey, @NotNull PsiElement element) {
389 //noinspection unchecked
390 return (T) getUnwrappedTool(shortNameKey.toString(), element);
394 public void modifyProfile(@NotNull Consumer<ModifiableModel> modelConsumer) {
395 ModifiableModel model = getModifiableModel();
396 modelConsumer.consume(model);
401 public <T extends InspectionProfileEntry> void modifyToolSettings(@NotNull final Key<T> shortNameKey,
402 @NotNull final PsiElement psiElement,
403 @NotNull final Consumer<T> toolConsumer) {
404 modifyProfile(model -> {
405 InspectionProfileEntry tool = model.getUnwrappedTool(shortNameKey.toString(), psiElement);
406 //noinspection unchecked
407 toolConsumer.consume((T) tool);
413 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, Project project) {
414 final ToolsImpl tools = getTools(shortName, project);
415 return tools != null? tools.getTool() : null;
418 public InspectionToolWrapper getToolById(@NotNull String id, @NotNull PsiElement element) {
419 initInspectionTools(element.getProject());
420 for (Tools toolList : myTools.values()) {
421 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
422 if (id.equals(tool.getID())) return tool;
428 public List<InspectionToolWrapper> findToolsById(@NotNull String id, @NotNull PsiElement element) {
429 List<InspectionToolWrapper> result = null;
430 initInspectionTools(element.getProject());
431 for (Tools toolList : myTools.values()) {
432 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
433 if (id.equals(tool.getID())) {
434 if (result == null) {
435 result = new ArrayList<>();
445 InspectionProfileManager.getInstance().fireProfileChanged(this);
450 public String getSingleTool() {
451 return myToolShortName;
455 public void setSingleTool(@NotNull final String toolShortName) {
456 myToolShortName = toolShortName;
461 public String getDisplayName() {
466 public void scopesChanged() {
467 for (ScopeToolState toolState : getAllTools(null)) {
468 toolState.scopesChanged();
470 InspectionProfileManager.getInstance().fireProfileChanged(this);
475 public boolean isProfileLocked() {
476 return myLockedProfile;
480 public void lockProfile(boolean isLocked) {
481 myLockedProfile = isLocked;
486 public InspectionToolWrapper[] getInspectionTools(@Nullable PsiElement element) {
487 initInspectionTools(element == null ? null : element.getProject());
488 List<InspectionToolWrapper> result = new ArrayList<>();
489 for (Tools toolList : myTools.values()) {
490 result.add(toolList.getInspectionTool(element));
492 return result.toArray(new InspectionToolWrapper[result.size()]);
497 public List<Tools> getAllEnabledInspectionTools(Project project) {
498 initInspectionTools(project);
499 List<Tools> result = new ArrayList<>();
500 for (final ToolsImpl toolList : myTools.values()) {
501 if (toolList.isEnabled()) {
502 result.add(toolList);
509 public void disableTool(@NotNull String toolId, @NotNull PsiElement element) {
510 getTools(toolId, element.getProject()).disableTool(element);
513 public void disableToolByDefault(@NotNull Collection<String> toolIds, @Nullable Project project) {
514 for (String toolId : toolIds) {
515 getTools(toolId, project).setDefaultEnabled(false);
520 public ScopeToolState getToolDefaultState(@NotNull String toolId, @Nullable Project project) {
521 return getTools(toolId, project).getDefaultState();
524 public void enableToolsByDefault(@NotNull List<String> toolIds, Project project) {
525 for (final String toolId : toolIds) {
526 getTools(toolId, project).setDefaultEnabled(true);
530 public boolean wasInitialized() {
531 return myInitialized;
534 public void initInspectionTools(@Nullable Project project) {
535 //noinspection TestOnlyProblems
536 if (myInitialized || (ApplicationManager.getApplication().isUnitTestMode() && !INIT_INSPECTIONS)) {
540 synchronized (myLock) {
541 if (!myInitialized) {
547 private void initialize(@Nullable Project project) {
548 SchemeDataHolder<? super InspectionProfileImpl> dataHolder = myDataHolder;
549 if (dataHolder != null) {
551 Element element = dataHolder.read();
552 if (element.getName().equals("component")) {
553 element = element.getChild("profile");
555 assert element != null;
556 readExternal(element);
559 if (myBaseProfile != null) {
560 myBaseProfile.initInspectionTools(project);
563 final List<InspectionToolWrapper> tools;
565 if (mySource == null) {
566 tools = myRegistrar.createTools();
569 tools = ContainerUtil.map(mySource.getDefaultStates(project), ScopeToolState::getTool);
572 catch (ProcessCanceledException ignored) {
576 final Map<String, List<String>> dependencies = new THashMap<>();
577 for (InspectionToolWrapper toolWrapper : tools) {
578 addTool(project, toolWrapper, dependencies);
581 DFSTBuilder<String> builder = new DFSTBuilder<>(GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<String>() {
583 public Collection<String> getNodes() {
584 return dependencies.keySet();
588 public Iterator<String> getIn(String n) {
589 return dependencies.get(n).iterator();
592 if (builder.isAcyclic()) {
593 myScopesOrder = ArrayUtil.toStringArray(builder.getSortedNodes());
596 if (mySource != null) {
597 copyToolsConfigurations(mySource, project);
600 myInitialized = true;
601 if (dataHolder != null) {
602 // should be only after set myInitialized
603 dataHolder.updateDigest(this);
607 public void addTool(@Nullable Project project, @NotNull InspectionToolWrapper toolWrapper, @NotNull Map<String, List<String>> dependencies) {
608 final String shortName = toolWrapper.getShortName();
609 HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
611 final InspectionEP extension = toolWrapper.getExtension();
612 Computable<String> computable = extension == null ? new Computable.PredefinedValueComputable<>(toolWrapper.getDisplayName()) : extension::getDisplayName;
613 if (toolWrapper instanceof LocalInspectionToolWrapper) {
614 key = HighlightDisplayKey.register(shortName, computable, toolWrapper.getID(),
615 ((LocalInspectionToolWrapper)toolWrapper).getAlternativeID());
618 key = HighlightDisplayKey.register(shortName, computable);
623 LOG.error(shortName + " ; number of initialized tools: " + myTools.size());
627 HighlightDisplayLevel baseLevel = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null
628 ? myBaseProfile.getErrorLevel(key, project)
629 : HighlightDisplayLevel.DO_NOT_SHOW;
630 HighlightDisplayLevel defaultLevel = toolWrapper.getDefaultLevel();
631 HighlightDisplayLevel level = baseLevel.getSeverity().compareTo(defaultLevel.getSeverity()) > 0 ? baseLevel : defaultLevel;
632 boolean enabled = myBaseProfile != null ? myBaseProfile.isToolEnabled(key) : toolWrapper.isEnabledByDefault();
633 final ToolsImpl toolsList = new ToolsImpl(toolWrapper, level, !myLockedProfile && enabled, enabled);
634 final Element element = myUninitializedSettings.remove(shortName);
636 if (element != null) {
637 toolsList.readExternal(element, this, dependencies);
639 else if (!myUninitializedSettings.containsKey(InspectionElementsMergerBase.getMergedMarkerName(shortName))) {
640 final InspectionElementsMergerBase merger = getMerger(shortName);
641 Element merged = merger == null ? null : merger.merge(myUninitializedSettings);
642 if (merged != null) {
643 toolsList.readExternal(merged, this, dependencies);
645 else if (isProfileLocked()) {
646 // https://youtrack.jetbrains.com/issue/IDEA-158936
647 toolsList.setEnabled(false);
648 if (toolsList.getNonDefaultTools() == null) {
649 toolsList.getDefaultState().setEnabled(false);
654 catch (InvalidDataException e) {
655 LOG.error("Can't read settings for " + toolWrapper, e);
657 myTools.put(shortName, toolsList);
661 private static InspectionElementsMergerBase getMerger(String shortName) {
662 final InspectionElementsMerger merger = InspectionElementsMerger.getMerger(shortName);
663 if (merger instanceof InspectionElementsMergerBase) {
664 return (InspectionElementsMergerBase)merger;
666 return merger != null ? new InspectionElementsMergerBase() {
668 public String getMergedToolName() {
669 return merger.getMergedToolName();
673 public String[] getSourceToolNames() {
674 return merger.getSourceToolNames();
681 public String[] getScopesOrder() {
682 return myScopesOrder;
685 public void setScopesOrder(String[] scopesOrder) {
686 myScopesOrder = scopesOrder;
689 private HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, @Nullable Project project) {
690 final ToolsImpl tools = getTools(key.toString(), project);
691 LOG.assertTrue(tools != null, "profile name: " + myName + " base profile: " + (myBaseProfile != null ? myBaseProfile.getName() : "-") + " key: " + key);
692 return tools.getLevel();
697 public InspectionProfileImpl getModifiableModel() {
698 return new InspectionProfileImpl(this);
701 private void copyToolsConfigurations(@NotNull InspectionProfileImpl profile, @Nullable Project project) {
703 for (ToolsImpl toolList : profile.myTools.values()) {
704 final ToolsImpl tools = myTools.get(toolList.getShortName());
705 final ScopeToolState defaultState = toolList.getDefaultState();
706 tools.setDefaultState(copyToolSettings(defaultState.getTool()), defaultState.isEnabled(), defaultState.getLevel());
707 tools.removeAllScopes();
708 final List<ScopeToolState> nonDefaultToolStates = toolList.getNonDefaultTools();
709 if (nonDefaultToolStates != null) {
710 for (ScopeToolState state : nonDefaultToolStates) {
711 final InspectionToolWrapper toolWrapper = copyToolSettings(state.getTool());
712 final NamedScope scope = state.getScope(project);
714 tools.addTool(scope, toolWrapper, state.isEnabled(), state.getLevel());
717 tools.addTool(state.getScopeName(), toolWrapper, state.isEnabled(), state.getLevel());
721 tools.setEnabled(toolList.isEnabled());
724 catch (WriteExternalException e) {
727 catch (InvalidDataException e) {
733 public void cleanup(@NotNull Project project) {
734 if (!myInitialized) {
738 for (ToolsImpl toolList : myTools.values()) {
739 if (toolList.isEnabled()) {
740 toolList.cleanupTools(project);
745 public void enableTool(@NotNull String toolId, Project project) {
746 final ToolsImpl tools = getTools(toolId, project);
747 tools.setEnabled(true);
748 if (tools.getNonDefaultTools() == null) {
749 tools.getDefaultState().setEnabled(true);
754 public void enableTool(@NotNull String inspectionTool, NamedScope namedScope, Project project) {
755 getTools(inspectionTool, project).enableTool(namedScope, project);
758 public void enableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, Project project) {
759 for (String inspectionTool : inspectionTools) {
760 enableTool(inspectionTool, namedScope, project);
764 public void disableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, @NotNull Project project) {
765 for (String inspectionTool : inspectionTools) {
766 getTools(inspectionTool, project).disableTool(namedScope, project);
771 public void disableTool(@NotNull String inspectionTool, @Nullable Project project) {
772 ToolsImpl tools = getTools(inspectionTool, project);
773 tools.setEnabled(false);
774 if (tools.getNonDefaultTools() == null) {
775 tools.getDefaultState().setEnabled(false);
780 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, Project project) {
781 getTools(key.toString(), project).setLevel(level);
785 public boolean isToolEnabled(@Nullable HighlightDisplayKey key, PsiElement element) {
789 final Tools toolState = getTools(key.toString(), element == null ? null : element.getProject());
790 return toolState != null && toolState.isEnabled(element);
794 public boolean isToolEnabled(@Nullable HighlightDisplayKey key) {
795 return isToolEnabled(key, null);
799 public boolean isExecutable(Project project) {
800 initInspectionTools(project);
801 for (Tools tools : myTools.values()) {
802 if (tools.isEnabled()) return true;
807 //invoke when isChanged() == true
809 public void commit() {
810 LOG.assertTrue(mySource != null);
811 mySource.commit(this);
812 getProfileManager().updateProfile(mySource);
816 private void commit(@NotNull InspectionProfileImpl model) {
817 setName(model.getName());
818 setDescription(model.getDescription());
819 setProjectLevel(model.isProjectLevel());
820 myLockedProfile = model.myLockedProfile;
821 myChangedToolNames = model.myChangedToolNames;
822 myTools = model.myTools;
823 myProfileManager = model.getProfileManager();
825 InspectionProfileManager.getInstance().fireProfileChanged(model);
829 public String getDescription() {
830 return myDescription;
833 public void setDescription(String description) {
834 myDescription = description;
837 public void convert(@NotNull Element element, @NotNull Project project) {
838 final Element scopes = element.getChild("scopes");
839 if (scopes == null) {
843 initInspectionTools(project);
845 for (Element scopeElement : scopes.getChildren(SCOPE)) {
846 final String profile = scopeElement.getAttributeValue(PROFILE);
847 InspectionProfileImpl inspectionProfile = profile == null ? null : (InspectionProfileImpl)getProfileManager().getProfile(profile);
848 NamedScope scope = inspectionProfile == null ? null : getProfileManager().getScopesManager().getScope(scopeElement.getAttributeValue(NAME));
853 for (InspectionToolWrapper toolWrapper : inspectionProfile.getInspectionTools(null)) {
854 final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName());
856 InspectionToolWrapper toolWrapperCopy = copyToolSettings(toolWrapper);
857 HighlightDisplayLevel errorLevel = inspectionProfile.getErrorLevel(key, null, project);
858 getTools(toolWrapper.getShortName(), project)
859 .addTool(scope, toolWrapperCopy, inspectionProfile.isToolEnabled(key), errorLevel);
861 catch (Exception e) {
866 reduceConvertedScopes();
869 private void reduceConvertedScopes() {
870 for (ToolsImpl tools : myTools.values()) {
871 final ScopeToolState toolState = tools.getDefaultState();
872 final List<ScopeToolState> nonDefaultTools = tools.getNonDefaultTools();
873 if (nonDefaultTools != null) {
874 boolean equal = true;
875 boolean isEnabled = toolState.isEnabled();
876 for (ScopeToolState state : nonDefaultTools) {
877 isEnabled |= state.isEnabled();
878 if (!state.equalTo(toolState)) {
882 tools.setEnabled(isEnabled);
884 tools.removeAllScopes();
891 public List<ScopeToolState> getAllTools(@Nullable Project project) {
892 initInspectionTools(project);
894 List<ScopeToolState> result = new ArrayList<>();
895 for (Tools tools : myTools.values()) {
896 tools.collectTools(result);
902 public List<ScopeToolState> getDefaultStates(@Nullable Project project) {
903 initInspectionTools(project);
904 List<ScopeToolState> result = new ArrayList<>();
905 for (Tools tools : myTools.values()) {
906 result.add(tools.getDefaultState());
912 public List<ScopeToolState> getNonDefaultTools(@NotNull String shortName, Project project) {
913 final List<ScopeToolState> result = new ArrayList<>();
914 final List<ScopeToolState> nonDefaultTools = getTools(shortName, project).getNonDefaultTools();
915 if (nonDefaultTools != null) {
916 result.addAll(nonDefaultTools);
921 public boolean isToolEnabled(@NotNull HighlightDisplayKey key, NamedScope namedScope, Project project) {
922 return getTools(key.toString(), project).isEnabled(namedScope,project);
925 public void removeScope(@NotNull String toolId, @NotNull String scopeName, Project project) {
926 getTools(toolId, project).removeScope(scopeName);
929 public void removeScopes(@NotNull List<String> toolIds, @NotNull String scopeName, Project project) {
930 for (final String toolId : toolIds) {
931 removeScope(toolId, scopeName, project);
936 * @return null if it has no base profile
939 private Set<String> getChangedToolNames() {
940 if (myBaseProfile == null) return null;
941 if (myChangedToolNames == null) {
942 synchronized (myLock) {
943 if (myChangedToolNames == null) {
944 initInspectionTools(null);
945 Set<String> names = myTools.keySet();
946 Set<String> map = new THashSet<>(names.size());
947 for (String toolId : names) {
948 if (!toolSettingsAreEqual(toolId, myBaseProfile, this)) {
952 myChangedToolNames = map;
957 return myChangedToolNames;
960 public void profileChanged() {
961 myChangedToolNames = null;
966 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, NamedScope scope, Project project) {
967 final ToolsImpl tools = getTools(key.toString(), project);
968 return tools != null ? tools.getLevel(scope, project) : HighlightDisplayLevel.WARNING;
971 public ScopeToolState addScope(@NotNull InspectionToolWrapper toolWrapper,
973 @NotNull HighlightDisplayLevel level,
976 return getTools(toolWrapper.getShortName(), project).prependTool(scope, toolWrapper, enabled, level);
979 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
980 getTools(key.toString(), project).setLevel(level, scopeName, project);
983 public void setErrorLevel(@NotNull List<HighlightDisplayKey> keys, @NotNull HighlightDisplayLevel level, String scopeName, Project project) {
984 for (HighlightDisplayKey key : keys) {
985 setErrorLevel(key, level, scopeName, project);
989 public ToolsImpl getTools(@NotNull String toolId, @Nullable Project project) {
990 initInspectionTools(project);
991 return myTools.get(toolId);
994 public void enableAllTools(Project project) {
995 for (InspectionToolWrapper entry : getInspectionTools(null)) {
996 enableTool(entry.getShortName(), project);
1002 public String toString() {
1003 return mySource == null ? getName() : getName() + " (copy)";
1007 public boolean equals(Object o) {
1008 return super.equals(o) && ((InspectionProfileImpl)o).getProfileManager() == getProfileManager();
1011 private static class InspectionProfileImplHolder {
1012 private static final InspectionProfileImpl DEFAULT_PROFILE = new InspectionProfileImpl(DEFAULT_PROFILE_NAME);