2 * Copyright 2000-2015 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.lang.annotation.HighlightSeverity;
26 import com.intellij.openapi.application.ApplicationManager;
27 import com.intellij.openapi.diagnostic.Logger;
28 import com.intellij.openapi.extensions.Extensions;
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.DefaultProjectProfileManager;
34 import com.intellij.profile.ProfileEx;
35 import com.intellij.profile.ProfileManager;
36 import com.intellij.profile.codeInspection.InspectionProfileManager;
37 import com.intellij.profile.codeInspection.SeverityProvider;
38 import com.intellij.psi.PsiElement;
39 import com.intellij.psi.search.scope.packageSet.NamedScope;
40 import com.intellij.util.ArrayUtil;
41 import com.intellij.util.Consumer;
42 import com.intellij.util.IncorrectOperationException;
43 import com.intellij.util.containers.ContainerUtil;
44 import com.intellij.util.containers.StringInterner;
45 import com.intellij.util.graph.CachingSemiGraph;
46 import com.intellij.util.graph.DFSTBuilder;
47 import com.intellij.util.graph.GraphGenerator;
48 import com.intellij.util.xmlb.annotations.Attribute;
49 import com.intellij.util.xmlb.annotations.Tag;
50 import com.intellij.util.xmlb.annotations.Transient;
51 import gnu.trove.THashMap;
52 import org.jdom.Element;
53 import org.jetbrains.annotations.NonNls;
54 import org.jetbrains.annotations.NotNull;
55 import org.jetbrains.annotations.Nullable;
56 import org.jetbrains.annotations.TestOnly;
58 import java.io.IOException;
64 public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, InspectionProfile, ExternalizableScheme {
65 @NonNls static final String INSPECTION_TOOL_TAG = "inspection_tool";
66 @NonNls static final String CLASS_TAG = "class";
67 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.InspectionProfileImpl");
68 @NonNls private static final String VALID_VERSION = "1.0";
69 @NonNls private static final String VERSION_TAG = "version";
70 @NonNls private static final String USED_LEVELS = "used_levels";
71 public static final String DEFAULT_PROFILE_NAME = "Default";
73 public static boolean INIT_INSPECTIONS = false;
74 private final InspectionToolRegistrar myRegistrar;
76 private final Map<String, Element> myUninstalledInspectionsSettings;
77 protected InspectionProfileImpl mySource;
78 private Map<String, ToolsImpl> myTools = new THashMap<String, ToolsImpl>();
79 private volatile Map<String, Boolean> myDisplayLevelMap;
80 @Attribute("is_locked")
81 private boolean myLockedProfile;
82 private final InspectionProfileImpl myBaseProfile;
83 private volatile String myToolShortName = null;
84 private String[] myScopesOrder;
85 private String myDescription;
86 private boolean myModified;
87 private volatile boolean myInitialized;
89 private final Object myLock = new Object();
91 InspectionProfileImpl(@NotNull InspectionProfileImpl inspectionProfile) {
92 this(inspectionProfile.getName(), inspectionProfile.myRegistrar, inspectionProfile.getProfileManager(), inspectionProfile.myBaseProfile);
93 myUninstalledInspectionsSettings.putAll(inspectionProfile.myUninstalledInspectionsSettings);
95 setProjectLevel(inspectionProfile.isProjectLevel());
96 myLockedProfile = inspectionProfile.myLockedProfile;
97 mySource = inspectionProfile;
98 copyFrom(inspectionProfile);
101 public InspectionProfileImpl(@NotNull final String profileName,
102 @NotNull InspectionToolRegistrar registrar,
103 @NotNull final ProfileManager profileManager) {
104 this(profileName, registrar, profileManager, getDefaultProfile());
107 public InspectionProfileImpl(@NotNull @NonNls String profileName) {
108 this(profileName, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), null);
111 InspectionProfileImpl(@NotNull final String profileName,
112 @NotNull InspectionToolRegistrar registrar,
113 @NotNull final ProfileManager profileManager,
114 InspectionProfileImpl baseProfile) {
116 myRegistrar = registrar;
117 myBaseProfile = baseProfile;
118 setProfileManager(profileManager);
119 myUninstalledInspectionsSettings = new TreeMap<String, Element>();
123 public static InspectionProfileImpl createSimple(@NotNull String name,
124 @NotNull final Project project,
125 @NotNull final InspectionToolWrapper... toolWrappers) {
126 InspectionToolRegistrar registrar = new InspectionToolRegistrar() {
129 public List<InspectionToolWrapper> createTools() {
130 return Arrays.asList(toolWrappers);
133 final InspectionProfileImpl profile = new InspectionProfileImpl(name, registrar, InspectionProfileManager.getInstance());
134 initAndDo((Computable)() -> {
135 profile.initInspectionTools(project);
138 for (InspectionToolWrapper toolWrapper : toolWrappers) {
139 profile.enableTool(toolWrapper.getShortName(), project);
144 private static boolean toolSettingsAreEqual(@NotNull String toolName, @NotNull InspectionProfileImpl profile1, @NotNull InspectionProfileImpl profile2) {
145 final Tools toolList1 = profile1.myTools.get(toolName);
146 final Tools toolList2 = profile2.myTools.get(toolName);
148 return Comparing.equal(toolList1, toolList2);
152 private static InspectionToolWrapper copyToolSettings(@NotNull InspectionToolWrapper toolWrapper)
153 throws WriteExternalException, InvalidDataException {
154 final InspectionToolWrapper inspectionTool = toolWrapper.createCopy();
155 if (toolWrapper.isInitialized()) {
156 @NonNls String tempRoot = "config";
157 Element config = new Element(tempRoot);
158 toolWrapper.getTool().writeSettings(config);
159 inspectionTool.getTool().readSettings(config);
161 return inspectionTool;
165 public static InspectionProfileImpl getDefaultProfile() {
166 return InspectionProfileImplHolder.DEFAULT_PROFILE;
170 public void setModified(final boolean modified) {
171 myModified = modified;
175 public InspectionProfile getParentProfile() {
180 public String getBaseProfileName() {
181 if (myBaseProfile == null) return null;
182 return myBaseProfile.getName();
186 @Deprecated // use corresponding constructor instead
187 public void setBaseProfile(InspectionProfile profile) {
188 throw new IncorrectOperationException();
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 StringInterner interner = new StringInterner();
253 for (Element toolElement : element.getChildren(INSPECTION_TOOL_TAG)) {
254 // make clone to avoid retaining memory via o.parent pointers
255 toolElement = toolElement.clone();
256 JDOMUtil.internElement(toolElement, interner);
257 myUninstalledInspectionsSettings.put(toolElement.getAttributeValue(CLASS_TAG), toolElement);
262 public Set<HighlightSeverity> getUsedSeverities() {
263 LOG.assertTrue(myInitialized);
264 final Set<HighlightSeverity> result = new HashSet<HighlightSeverity>();
265 for (Tools tools : myTools.values()) {
266 for (ScopeToolState state : tools.getTools()) {
267 result.add(state.getLevel().getSeverity());
274 public void serializeInto(@NotNull Element element, boolean preserveCompatibility) {
275 // must be first - compatibility
276 element.setAttribute(VERSION_TAG, VALID_VERSION);
278 super.serializeInto(element, preserveCompatibility);
280 synchronized (myLock) {
281 if (!myInitialized) {
282 for (Element el : myUninstalledInspectionsSettings.values()) {
283 element.addContent(el.clone());
289 Map<String, Boolean> diffMap = getDisplayLevelMap();
290 if (diffMap != null) {
291 diffMap = new TreeMap<String, Boolean>(diffMap);
292 for (String toolName : myUninstalledInspectionsSettings.keySet()) {
293 diffMap.put(toolName, false);
296 for (String toolName : diffMap.keySet()) {
297 if (!myLockedProfile && diffMap.get(toolName).booleanValue()) {
298 markSettingsMerged(toolName, element);
302 Element toolElement = myUninstalledInspectionsSettings.get(toolName);
303 if (toolElement == null) {
304 ToolsImpl toolList = myTools.get(toolName);
305 LOG.assertTrue(toolList != null);
306 Element inspectionElement = new Element(INSPECTION_TOOL_TAG);
307 inspectionElement.setAttribute(CLASS_TAG, toolName);
309 toolList.writeExternal(inspectionElement);
311 catch (WriteExternalException e) {
316 if (!areSettingsMerged(toolName, inspectionElement)) {
317 element.addContent(inspectionElement);
321 element.addContent(toolElement.clone());
327 private void markSettingsMerged(String toolName, Element element) {
328 //add marker if already merged but result is now default (-> empty node)
329 final String mergedName = InspectionElementsMergerBase.getMergedMarkerName(toolName);
330 if (!myUninstalledInspectionsSettings.containsKey(mergedName)) {
331 final InspectionElementsMergerBase merger = getMerger(toolName);
332 if (merger != null && merger.markSettingsMerged(myUninstalledInspectionsSettings)) {
333 element.addContent(new Element(INSPECTION_TOOL_TAG).setAttribute(CLASS_TAG, mergedName));
338 private boolean areSettingsMerged(String toolName, Element inspectionElement) {
339 //skip merged settings as they could be restored from already provided data
340 final InspectionElementsMergerBase merger = getMerger(toolName);
341 return merger != null && merger.areSettingsMerged(myUninstalledInspectionsSettings, inspectionElement);
344 public void collectDependentInspections(@NotNull InspectionToolWrapper toolWrapper,
345 @NotNull Set<InspectionToolWrapper> dependentEntries,
347 String mainToolId = toolWrapper.getMainToolId();
349 if (mainToolId != null) {
350 InspectionToolWrapper dependentEntryWrapper = getInspectionTool(mainToolId, project);
352 if (dependentEntryWrapper == null) {
353 LOG.error("Can't find main tool: '" + mainToolId+"' which was specified in "+toolWrapper);
356 if (!dependentEntries.add(dependentEntryWrapper)) {
357 collectDependentInspections(dependentEntryWrapper, dependentEntries, project);
364 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, @NotNull PsiElement element) {
365 final Tools toolList = getTools(shortName, element.getProject());
366 return toolList == null ? null : toolList.getInspectionTool(element);
371 public InspectionProfileEntry getUnwrappedTool(@NotNull String shortName, @NotNull PsiElement element) {
372 InspectionToolWrapper tool = getInspectionTool(shortName, element);
373 return tool == null ? null : tool.getTool();
377 public <T extends InspectionProfileEntry> T getUnwrappedTool(@NotNull Key<T> shortNameKey, @NotNull PsiElement element) {
378 //noinspection unchecked
379 return (T) getUnwrappedTool(shortNameKey.toString(), element);
383 public void modifyProfile(@NotNull Consumer<ModifiableModel> modelConsumer) {
384 ModifiableModel model = getModifiableModel();
385 modelConsumer.consume(model);
389 catch (IOException e) {
395 public <T extends InspectionProfileEntry> void modifyToolSettings(@NotNull final Key<T> shortNameKey,
396 @NotNull final PsiElement psiElement,
397 @NotNull final Consumer<T> toolConsumer) {
398 modifyProfile(model -> {
399 InspectionProfileEntry tool = model.getUnwrappedTool(shortNameKey.toString(), psiElement);
400 //noinspection unchecked
401 toolConsumer.consume((T) tool);
407 public InspectionToolWrapper getInspectionTool(@NotNull String shortName, Project project) {
408 final ToolsImpl tools = getTools(shortName, project);
409 return tools != null? tools.getTool() : null;
412 public InspectionToolWrapper getToolById(@NotNull String id, @NotNull PsiElement element) {
413 initInspectionTools(element.getProject());
414 for (Tools toolList : myTools.values()) {
415 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
416 if (id.equals(tool.getID())) return tool;
422 public List<InspectionToolWrapper> findToolsById(@NotNull String id, @NotNull PsiElement element) {
423 List<InspectionToolWrapper> result = null;
424 initInspectionTools(element.getProject());
425 for (Tools toolList : myTools.values()) {
426 final InspectionToolWrapper tool = toolList.getInspectionTool(element);
427 if (id.equals(tool.getID())) {
428 if (result == null) {
429 result = new ArrayList<InspectionToolWrapper>();
438 public void save() throws IOException {
439 InspectionProfileManager.getInstance().fireProfileChanged(this);
444 public String getSingleTool() {
445 return myToolShortName;
449 public void setSingleTool(@NotNull final String toolShortName) {
450 myToolShortName = toolShortName;
455 public String getDisplayName() {
460 public void scopesChanged() {
461 for (ScopeToolState toolState : getAllTools(null)) {
462 toolState.scopesChanged();
464 InspectionProfileManager.getInstance().fireProfileChanged(this);
469 public boolean isProfileLocked() {
470 return myLockedProfile;
474 public void lockProfile(boolean isLocked) {
475 myLockedProfile = isLocked;
480 public InspectionToolWrapper[] getInspectionTools(@Nullable PsiElement element) {
481 initInspectionTools(element == null ? null : element.getProject());
482 List<InspectionToolWrapper> result = new ArrayList<InspectionToolWrapper>();
483 for (Tools toolList : myTools.values()) {
484 result.add(toolList.getInspectionTool(element));
486 return result.toArray(new InspectionToolWrapper[result.size()]);
491 public List<Tools> getAllEnabledInspectionTools(Project project) {
492 initInspectionTools(project);
493 List<Tools> result = new ArrayList<Tools>();
494 for (final ToolsImpl toolList : myTools.values()) {
495 if (toolList.isEnabled()) {
496 result.add(toolList);
503 public void disableTool(@NotNull String toolId, @NotNull PsiElement element) {
504 getTools(toolId, element.getProject()).disableTool(element);
507 public void disableToolByDefault(@NotNull List<String> toolIds, Project project) {
508 for (final String toolId : toolIds) {
509 getToolDefaultState(toolId, project).setEnabled(false);
514 public ScopeToolState getToolDefaultState(@NotNull String toolId, Project project) {
515 return getTools(toolId, project).getDefaultState();
518 public void enableToolsByDefault(@NotNull List<String> toolIds, Project project) {
519 for (final String toolId : toolIds) {
520 getToolDefaultState(toolId, project).setEnabled(true);
524 public boolean wasInitialized() {
525 return myInitialized;
528 public void initInspectionTools(@Nullable Project project) {
529 if (ApplicationManager.getApplication().isUnitTestMode() && !INIT_INSPECTIONS) return;
530 if (myInitialized) return;
531 synchronized (myLock) {
532 if (myInitialized) return;
533 myInitialized = initialize(project);
537 private boolean initialize(@Nullable Project project) {
538 if (myBaseProfile != null) {
539 myBaseProfile.initInspectionTools(project);
542 final List<InspectionToolWrapper> tools;
544 tools = createTools(project);
546 catch (ProcessCanceledException ignored) {
549 final Map<String, List<String>> dependencies = new HashMap<String, List<String>>();
550 for (InspectionToolWrapper toolWrapper : tools) {
551 addTool(project, toolWrapper, dependencies);
553 final GraphGenerator<String> graphGenerator = GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<String>() {
555 public Collection<String> getNodes() {
556 return dependencies.keySet();
560 public Iterator<String> getIn(String n) {
561 return dependencies.get(n).iterator();
565 DFSTBuilder<String> builder = new DFSTBuilder<String>(graphGenerator);
566 if (builder.isAcyclic()) {
567 final List<String> scopes = builder.getSortedNodes();
568 myScopesOrder = ArrayUtil.toStringArray(scopes);
571 if (mySource != null) {
572 copyToolsConfigurations(mySource, project);
577 public void removeTool(@NotNull InspectionToolWrapper toolWrapper) {
578 myTools.remove(toolWrapper.getShortName());
581 public void addTool(@Nullable Project project, @NotNull InspectionToolWrapper toolWrapper, @NotNull Map<String, List<String>> dependencies) {
582 final String shortName = toolWrapper.getShortName();
583 HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
585 final InspectionEP extension = toolWrapper.getExtension();
586 Computable<String> computable = extension == null ? new Computable.PredefinedValueComputable<String>(toolWrapper.getDisplayName()) : (Computable<String>)() -> extension.getDisplayName();
587 if (toolWrapper instanceof LocalInspectionToolWrapper) {
588 key = HighlightDisplayKey.register(shortName, computable, toolWrapper.getID(),
589 ((LocalInspectionToolWrapper)toolWrapper).getAlternativeID());
592 key = HighlightDisplayKey.register(shortName, computable);
596 LOG.assertTrue(key != null, shortName + " ; number of initialized tools: " + myTools.size());
597 HighlightDisplayLevel baseLevel = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null
598 ? myBaseProfile.getErrorLevel(key, project)
599 : HighlightDisplayLevel.DO_NOT_SHOW;
600 HighlightDisplayLevel defaultLevel = toolWrapper.getDefaultLevel();
601 HighlightDisplayLevel level = baseLevel.getSeverity().compareTo(defaultLevel.getSeverity()) > 0 ? baseLevel : defaultLevel;
602 //HighlightDisplayLevel level = myBaseProfile != null && myBaseProfile.getTools(shortName, project) != null ? myBaseProfile.getErrorLevel(key, project) : toolWrapper.getDefaultLevel();
603 boolean enabled = myBaseProfile != null ? myBaseProfile.isToolEnabled(key) : toolWrapper.isEnabledByDefault();
604 final ToolsImpl toolsList = new ToolsImpl(toolWrapper, level, !myLockedProfile && enabled, enabled);
605 final Element element = myUninstalledInspectionsSettings.remove(shortName);
607 if (element != null) {
608 toolsList.readExternal(element, this, dependencies);
610 else if (!myUninstalledInspectionsSettings.containsKey(InspectionElementsMergerBase.getMergedMarkerName(shortName))) {
611 final InspectionElementsMergerBase merger = getMerger(shortName);
612 if (merger != null) {
613 final Element merged = merger.merge(myUninstalledInspectionsSettings);
614 if (merged != null) {
615 toolsList.readExternal(merged, this, dependencies);
620 catch (InvalidDataException e) {
621 LOG.error("Can't read settings for " + toolWrapper, e);
623 myTools.put(shortName, toolsList);
627 private static InspectionElementsMergerBase getMerger(String shortName) {
628 final InspectionElementsMerger merger = InspectionElementsMerger.getMerger(shortName);
629 if (merger instanceof InspectionElementsMergerBase) {
630 return (InspectionElementsMergerBase)merger;
632 return merger != null ? new InspectionElementsMergerBase() {
634 public String getMergedToolName() {
635 return merger.getMergedToolName();
639 public String[] getSourceToolNames() {
640 return merger.getSourceToolNames();
647 public String[] getScopesOrder() {
648 return myScopesOrder;
651 public void setScopesOrder(String[] scopesOrder) {
652 myScopesOrder = scopesOrder;
656 private List<InspectionToolWrapper> createTools(Project project) {
657 if (mySource != null) {
658 return ContainerUtil.map(mySource.getDefaultStates(project), state -> state.getTool());
660 return myRegistrar.createTools();
663 private HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, Project project) {
664 final ToolsImpl tools = getTools(key.toString(), project);
665 LOG.assertTrue(tools != null, "profile name: " + myName + " base profile: " + (myBaseProfile != null ? myBaseProfile.getName() : "-") + " key: " + key);
666 return tools.getLevel();
671 public ModifiableModel getModifiableModel() {
672 return new InspectionProfileImpl(this);
676 public void copyFrom(@NotNull InspectionProfile profile) {
677 super.copyFrom(profile);
680 private void copyToolsConfigurations(@NotNull InspectionProfileImpl profile, @Nullable Project project) {
682 for (ToolsImpl toolList : profile.myTools.values()) {
683 final ToolsImpl tools = myTools.get(toolList.getShortName());
684 final ScopeToolState defaultState = toolList.getDefaultState();
685 tools.setDefaultState(copyToolSettings(defaultState.getTool()), defaultState.isEnabled(), defaultState.getLevel());
686 tools.removeAllScopes();
687 final List<ScopeToolState> nonDefaultToolStates = toolList.getNonDefaultTools();
688 if (nonDefaultToolStates != null) {
689 for (ScopeToolState state : nonDefaultToolStates) {
690 final InspectionToolWrapper toolWrapper = copyToolSettings(state.getTool());
691 final NamedScope scope = state.getScope(project);
693 tools.addTool(scope, toolWrapper, state.isEnabled(), state.getLevel());
696 tools.addTool(state.getScopeName(), toolWrapper, state.isEnabled(), state.getLevel());
700 tools.setEnabled(toolList.isEnabled());
703 catch (WriteExternalException e) {
706 catch (InvalidDataException e) {
712 public void cleanup(@NotNull Project project) {
713 for (final ToolsImpl toolList : myTools.values()) {
714 if (toolList.isEnabled()) {
715 for (InspectionToolWrapper toolWrapper : toolList.getAllTools()) {
716 toolWrapper.projectClosed(project);
717 toolWrapper.cleanup(project);
723 public void enableTool(@NotNull String toolId, Project project) {
724 final ToolsImpl tools = getTools(toolId, project);
725 tools.setEnabled(true);
726 if (tools.getNonDefaultTools() == null) {
727 tools.getDefaultState().setEnabled(true);
732 public void enableTool(@NotNull String inspectionTool, NamedScope namedScope, Project project) {
733 getTools(inspectionTool, project).enableTool(namedScope, project);
736 public void enableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, Project project) {
737 for (String inspectionTool : inspectionTools) {
738 enableTool(inspectionTool, namedScope, project);
743 public void disableTool(@NotNull String inspectionTool, NamedScope namedScope, @NotNull Project project) {
744 getTools(inspectionTool, project).disableTool(namedScope, project);
747 public void disableTools(@NotNull List<String> inspectionTools, NamedScope namedScope, @NotNull Project project) {
748 for (String inspectionTool : inspectionTools) {
749 disableTool(inspectionTool, namedScope, project);
754 public void disableTool(@NotNull String inspectionTool, Project project) {
755 final ToolsImpl tools = getTools(inspectionTool, project);
756 tools.setEnabled(false);
757 if (tools.getNonDefaultTools() == null) {
758 tools.getDefaultState().setEnabled(false);
763 public void setErrorLevel(@NotNull HighlightDisplayKey key, @NotNull HighlightDisplayLevel level, Project project) {
764 getTools(key.toString(), project).setLevel(level);
768 public boolean isToolEnabled(HighlightDisplayKey key, PsiElement element) {
772 final Tools toolState = getTools(key.toString(), element == null ? null : element.getProject());
773 return toolState != null && toolState.isEnabled(element);
777 public boolean isToolEnabled(HighlightDisplayKey key) {
778 return isToolEnabled(key, null);
782 public boolean isExecutable(Project project) {
783 initInspectionTools(project);
784 for (Tools tools : myTools.values()) {
785 if (tools.isEnabled()) return true;
790 //invoke when isChanged() == true
792 public void commit() throws IOException {
793 LOG.assertTrue(mySource != null);
794 mySource.commit(this);
795 getProfileManager().updateProfile(mySource);
799 private void commit(@NotNull InspectionProfileImpl model) {
800 setName(model.getName());
801 setDescription(model.getDescription());
802 setProjectLevel(model.isProjectLevel());
803 myLockedProfile = model.myLockedProfile;
804 myDisplayLevelMap = model.myDisplayLevelMap;
805 myTools = model.myTools;
806 myProfileManager = model.getProfileManager();
808 InspectionProfileManager.getInstance().fireProfileChanged(model);
812 public String getDescription() {
813 return myDescription;
816 public void setDescription(String description) {
817 myDescription = description;
821 public void convert(@NotNull Element element, @NotNull Project project) {
822 initInspectionTools(project);
823 final Element scopes = element.getChild(DefaultProjectProfileManager.SCOPES);
824 if (scopes == null) {
827 final List children = scopes.getChildren(SCOPE);
828 for (Object s : children) {
829 Element scopeElement = (Element)s;
830 final String profile = scopeElement.getAttributeValue(DefaultProjectProfileManager.PROFILE);
831 if (profile != null) {
832 final InspectionProfileImpl inspectionProfile = (InspectionProfileImpl)getProfileManager().getProfile(profile);
833 if (inspectionProfile != null) {
834 final NamedScope scope = getProfileManager().getScopesManager().getScope(scopeElement.getAttributeValue(NAME));
836 for (InspectionToolWrapper toolWrapper : inspectionProfile.getInspectionTools(null)) {
837 final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName());
839 InspectionToolWrapper toolWrapperCopy = copyToolSettings(toolWrapper);
840 HighlightDisplayLevel errorLevel = inspectionProfile.getErrorLevel(key, null, project);
841 getTools(toolWrapper.getShortName(), project).addTool(scope, toolWrapperCopy, inspectionProfile.isToolEnabled(key), errorLevel);
843 catch (Exception e) {
851 reduceConvertedScopes();
854 private void reduceConvertedScopes() {
855 for (ToolsImpl tools : myTools.values()) {
856 final ScopeToolState toolState = tools.getDefaultState();
857 final List<ScopeToolState> nonDefaultTools = tools.getNonDefaultTools();
858 if (nonDefaultTools != null) {
859 boolean equal = true;
860 boolean isEnabled = toolState.isEnabled();
861 for (ScopeToolState state : nonDefaultTools) {
862 isEnabled |= state.isEnabled();
863 if (!state.equalTo(toolState)) {
867 tools.setEnabled(isEnabled);
869 tools.removeAllScopes();
876 public List<ScopeToolState> getAllTools(Project project) {
877 initInspectionTools(project);
878 final List<ScopeToolState> result = new ArrayList<ScopeToolState>();
879 for (Tools tools : myTools.values()) {
880 result.addAll(tools.getTools());
886 public List<ScopeToolState> getDefaultStates(Project project) {
887 initInspectionTools(project);
888 final List<ScopeToolState> result = new ArrayList<ScopeToolState>();
889 for (Tools tools : myTools.values()) {
890 result.add(tools.getDefaultState());
896 public List<ScopeToolState> getNonDefaultTools(@NotNull String shortName, Project project) {
897 final List<ScopeToolState> result = new ArrayList<ScopeToolState>();
898 final List<ScopeToolState> nonDefaultTools = getTools(shortName, project).getNonDefaultTools();
899 if (nonDefaultTools != null) {
900 result.addAll(nonDefaultTools);
905 public boolean isToolEnabled(@NotNull HighlightDisplayKey key, NamedScope namedScope, Project project) {
906 return getTools(key.toString(), project).isEnabled(namedScope,project);
910 public void removeScope(@NotNull String toolId, int scopeIdx, Project project) {
911 getTools(toolId, project).removeScope(scopeIdx);
914 public void removeScope(@NotNull String toolId, @NotNull String scopeName, Project project) {
915 getTools(toolId, project).removeScope(scopeName);
918 public void removeScopes(@NotNull List<String> toolIds, @NotNull String scopeName, Project project) {
919 for (final String toolId : toolIds) {
920 removeScope(toolId, scopeName, project);
925 * @return null if it has no base profile
928 private Map<String, Boolean> getDisplayLevelMap() {
929 if (myBaseProfile == null) return null;
930 if (myDisplayLevelMap == null) {
931 // Synchronizing on myExternalInfo as initInspectionTools() synchronizes on it internally.
932 synchronized (myLock) {
933 if (myDisplayLevelMap == null) {
934 initInspectionTools(null);
935 TreeMap<String,Boolean> map = new TreeMap<String, Boolean>();
936 for (String toolId : myTools.keySet()) {
937 map.put(toolId, toolSettingsAreEqual(toolId, myBaseProfile, this));
939 myDisplayLevelMap = map;
944 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, 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);
1009 public static <T> T initAndDo(@NotNull Computable<T> runnable) {
1010 boolean old = INIT_INSPECTIONS;
1012 INIT_INSPECTIONS = true;
1013 return runnable.compute();
1016 INIT_INSPECTIONS = old;