blob: caeb02a2316f051967ca3d337bf458819b1c9359 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* User: anna
* Date: 15-Apr-2009
*/
package com.intellij.codeInspection.ex;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.packageDependencies.DependencyValidationManager;
import com.intellij.profile.ProfileEx;
import com.intellij.profile.ProfileManager;
import com.intellij.profile.codeInspection.SeverityProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.scope.packageSet.CustomScopesProviderEx;
import com.intellij.psi.search.scope.packageSet.NamedScope;
import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
import com.intellij.psi.search.scope.packageSet.PackageSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class ToolsImpl implements Tools {
@NonNls private static final String ENABLED_BY_DEFAULT_ATTRIBUTE = "enabled_by_default";
@NonNls private static final String ENABLED_ATTRIBUTE = "enabled";
@NonNls private static final String LEVEL_ATTRIBUTE = "level";
private final String myShortName;
private final ScopeToolState myDefaultState;
private List<ScopeToolState> myTools;
private boolean myEnabled;
public ToolsImpl(@NotNull InspectionToolWrapper toolWrapper, @NotNull HighlightDisplayLevel level, boolean enabled, boolean enabledByDefault) {
this(toolWrapper.getShortName(), new ScopeToolState(CustomScopesProviderEx.getAllScope(), toolWrapper, enabledByDefault, level), null, enabled);
}
@TestOnly
public ToolsImpl(@NotNull InspectionToolWrapper toolWrapper, @NotNull HighlightDisplayLevel level, boolean enabled) {
this(toolWrapper, level, enabled, enabled);
}
private ToolsImpl(@NotNull String shortName, @NotNull ScopeToolState defaultState, @Nullable List<ScopeToolState> tools, boolean enabled) {
myShortName = shortName;
myDefaultState = defaultState;
myTools = tools;
myEnabled = enabled;
}
@NotNull
public ScopeToolState addTool(@NotNull NamedScope scope, @NotNull InspectionToolWrapper toolWrapper, boolean enabled, @NotNull HighlightDisplayLevel level) {
return insertTool(scope, toolWrapper, enabled, level, myTools != null ? myTools.size() : 0);
}
@NotNull
public ScopeToolState prependTool(@NotNull NamedScope scope, @NotNull InspectionToolWrapper toolWrapper, boolean enabled, @NotNull HighlightDisplayLevel level) {
return insertTool(scope, toolWrapper, enabled, level, 0);
}
public ScopeToolState addTool(@NotNull String scopeName, @NotNull InspectionToolWrapper toolWrapper, boolean enabled, @NotNull HighlightDisplayLevel level) {
return insertTool(new ScopeToolState(scopeName, toolWrapper, enabled, level), myTools != null ? myTools.size() : 0);
}
@NotNull
private ScopeToolState insertTool(@NotNull NamedScope scope, @NotNull InspectionToolWrapper toolWrapper, boolean enabled, @NotNull HighlightDisplayLevel level, int idx) {
return insertTool(new ScopeToolState(scope, toolWrapper, enabled, level), idx);
}
@NotNull
private ScopeToolState insertTool(@NotNull final ScopeToolState scopeToolState, final int idx) {
if (myTools == null) {
myTools = new ArrayList<ScopeToolState>();
if (scopeToolState.isEnabled()) {
setEnabled(true);
}
}
myTools.add(idx, scopeToolState);
return scopeToolState;
}
@NotNull
@Override
public InspectionToolWrapper getInspectionTool(PsiElement element) {
if (myTools != null) {
final Project project = element != null ? element.getProject() : null;
for (ScopeToolState state : myTools) {
if (element == null) {
return state.getTool();
}
else {
final NamedScope scope = state.getScope(project);
if (scope != null) {
final PackageSet packageSet = scope.getValue();
if (packageSet != null) {
final PsiFile containingFile = element.getContainingFile();
if (containingFile != null && packageSet.contains(containingFile, DependencyValidationManager.getInstance(project))) {
return state.getTool();
}
}
}
}
}
}
return myDefaultState.getTool();
}
@NotNull
@Override
public String getShortName() {
return myShortName;
}
@NotNull
public List<InspectionToolWrapper> getAllTools() {
List<InspectionToolWrapper> result = new ArrayList<InspectionToolWrapper>();
for (ScopeToolState state : getTools()) {
InspectionToolWrapper toolWrapper = state.getTool();
result.add(toolWrapper);
}
return result;
}
public void writeExternal(Element inspectionElement) throws WriteExternalException {
if (myTools != null) {
for (ScopeToolState state : myTools) {
final Element scopeElement = new Element("scope");
scopeElement.setAttribute("name", state.getScopeName());
scopeElement.setAttribute(LEVEL_ATTRIBUTE, state.getLevel().getName());
scopeElement.setAttribute(ENABLED_ATTRIBUTE, Boolean.toString(state.isEnabled()));
InspectionToolWrapper toolWrapper = state.getTool();
if (toolWrapper.isInitialized()) {
toolWrapper.getTool().writeSettings(scopeElement);
}
inspectionElement.addContent(scopeElement);
}
}
inspectionElement.setAttribute(ENABLED_ATTRIBUTE, Boolean.toString(isEnabled()));
inspectionElement.setAttribute(LEVEL_ATTRIBUTE, getLevel().getName());
inspectionElement.setAttribute(ENABLED_BY_DEFAULT_ATTRIBUTE, Boolean.toString(myDefaultState.isEnabled()));
InspectionToolWrapper toolWrapper = myDefaultState.getTool();
if (toolWrapper.isInitialized()) {
toolWrapper.getTool().writeSettings(inspectionElement);
}
}
void readExternal(@NotNull Element toolElement, @NotNull InspectionProfile profile, Map<String, List<String>> dependencies) throws InvalidDataException {
final String levelName = toolElement.getAttributeValue(LEVEL_ATTRIBUTE);
final ProfileManager profileManager = profile.getProfileManager();
final SeverityRegistrar registrar = ((SeverityProvider)profileManager).getOwnSeverityRegistrar();
HighlightDisplayLevel level = levelName != null ? HighlightDisplayLevel.find(registrar.getSeverity(levelName)) : null;
if (level == null || level == HighlightDisplayLevel.DO_NOT_SHOW) {//from old profiles
level = HighlightDisplayLevel.WARNING;
}
myDefaultState.setLevel(level);
final String enabled = toolElement.getAttributeValue(ENABLED_ATTRIBUTE);
final boolean isEnabled = enabled != null && Boolean.parseBoolean(enabled);
final String enabledTool = toolElement.getAttributeValue(ENABLED_BY_DEFAULT_ATTRIBUTE);
myDefaultState.setEnabled(enabledTool != null ? Boolean.parseBoolean(enabledTool) : isEnabled);
final InspectionToolWrapper toolWrapper = myDefaultState.getTool();
final List scopeElements = toolElement.getChildren(ProfileEx.SCOPE);
final List<String> scopeNames = new ArrayList<String>();
for (Object sO : scopeElements) {
final Element scopeElement = (Element)sO;
final String scopeName = scopeElement.getAttributeValue(ProfileEx.NAME);
if (scopeName == null) {
continue;
}
final NamedScopesHolder scopesHolder = profileManager.getScopesManager();
NamedScope namedScope = null;
if (scopesHolder != null) {
namedScope = scopesHolder.getScope(scopeName);
}
final String errorLevel = scopeElement.getAttributeValue(LEVEL_ATTRIBUTE);
final String enabledInScope = scopeElement.getAttributeValue(ENABLED_ATTRIBUTE);
final InspectionToolWrapper copyToolWrapper = toolWrapper.createCopy();
// check if unknown children exists
if (scopeElement.getAttributes().size() > 3 || !scopeElement.getChildren().isEmpty()) {
copyToolWrapper.getTool().readSettings(scopeElement);
}
HighlightDisplayLevel scopeLevel = errorLevel != null ?
HighlightDisplayLevel.find(registrar.getSeverity(errorLevel)) : null;
if (scopeLevel == null) {
scopeLevel = level;
}
if (namedScope != null) {
addTool(namedScope, copyToolWrapper, enabledInScope != null && Boolean.parseBoolean(enabledInScope), scopeLevel);
}
else {
addTool(scopeName, copyToolWrapper, enabledInScope != null && Boolean.parseBoolean(enabledInScope), scopeLevel);
}
scopeNames.add(scopeName);
}
for (int i = 0; i < scopeNames.size(); i++) {
String scopeName = scopeNames.get(i);
List<String> order = dependencies.get(scopeName);
if (order == null) {
order = new ArrayList<String>();
dependencies.put(scopeName, order);
}
for (int j = i + 1; j < scopeNames.size(); j++) {
order.add(scopeNames.get(j));
}
}
// check if unknown children exists
if (toolElement.getAttributes().size() > 4 || toolElement.getChildren().size() > scopeElements.size()) {
toolWrapper.getTool().readSettings(toolElement);
}
myEnabled = isEnabled;
}
@NotNull
@Override
public InspectionToolWrapper getTool() {
if (myTools == null) return myDefaultState.getTool();
return myTools.iterator().next().getTool();
}
@Override
@NotNull
public List<ScopeToolState> getTools() {
if (myTools == null) return Collections.singletonList(myDefaultState);
List<ScopeToolState> result = new ArrayList<ScopeToolState>(myTools);
result.add(myDefaultState);
return result;
}
@Override
@NotNull
public ScopeToolState getDefaultState() {
return myDefaultState;
}
public void removeScope(int scopeIdx) {
if (myTools != null && scopeIdx >= 0 && myTools.size() > scopeIdx) {
myTools.remove(scopeIdx);
checkToolsIsEmpty();
}
}
public void removeScope(final @NotNull String scopeName) {
if (myTools != null) {
for (ScopeToolState tool : myTools) {
if (scopeName.equals(tool.getScopeName())) {
myTools.remove(tool);
break;
}
}
checkToolsIsEmpty();
}
}
private void checkToolsIsEmpty() {
if (myTools.isEmpty()) {
myTools = null;
setEnabled(myDefaultState.isEnabled());
}
}
public void removeAllScopes() {
myTools = null;
}
public void setScope(int idx, NamedScope namedScope) {
if (myTools != null && myTools.size() > idx && idx >= 0) {
final ScopeToolState scopeToolState = myTools.get(idx);
InspectionToolWrapper toolWrapper = scopeToolState.getTool();
myTools.remove(idx);
myTools.add(idx, new ScopeToolState(namedScope, toolWrapper, scopeToolState.isEnabled(), scopeToolState.getLevel()));
}
}
public void moveScope(int idx, int dir) {
if (myTools != null && idx >= 0 && idx < myTools.size() && idx + dir >= 0 && idx + dir < myTools.size()) {
final ScopeToolState state = myTools.get(idx);
myTools.set(idx, myTools.get(idx + dir));
myTools.set(idx + dir, state);
}
}
public boolean isEnabled(NamedScope namedScope, Project project) {
if (!myEnabled) return false;
if (namedScope != null && myTools != null) {
for (ScopeToolState state : myTools) {
if (Comparing.equal(namedScope, state.getScope(project))) return state.isEnabled();
}
}
return myDefaultState.isEnabled();
}
public HighlightDisplayLevel getLevel(PsiElement element) {
if (myTools == null || element == null) return myDefaultState.getLevel();
final Project project = element.getProject();
final DependencyValidationManager manager = DependencyValidationManager.getInstance(project);
for (ScopeToolState state : myTools) {
final NamedScope scope = state.getScope(project);
final PackageSet set = scope != null ? scope.getValue() : null;
if (set != null && set.contains(element.getContainingFile(), manager)) {
return state.getLevel();
}
}
return myDefaultState.getLevel();
}
public HighlightDisplayLevel getLevel() {
return myDefaultState.getLevel();
}
@Override
public boolean isEnabled() {
return myEnabled;
}
@Override
public boolean isEnabled(PsiElement element) {
if (!myEnabled) return false;
if (myTools == null || element == null) return myDefaultState.isEnabled();
final Project project = element.getProject();
final DependencyValidationManager manager = DependencyValidationManager.getInstance(project);
for (ScopeToolState state : myTools) {
final NamedScope scope = state.getScope(project);
if (scope != null) {
final PackageSet set = scope.getValue();
if (set != null && set.contains(element.getContainingFile(), manager)) {
return state.isEnabled();
}
}
}
return myDefaultState.isEnabled();
}
@Override
@Nullable
public InspectionToolWrapper getEnabledTool(PsiElement element) {
if (!myEnabled) return null;
if (myTools == null || element == null) {
return myDefaultState.isEnabled() ? myDefaultState.getTool() : null;
}
final Project project = element.getProject();
final DependencyValidationManager manager = DependencyValidationManager.getInstance(project);
for (ScopeToolState state : myTools) {
final NamedScope scope = state.getScope(project);
if (scope != null) {
final PackageSet set = scope.getValue();
if (set != null && set.contains(element.getContainingFile(), manager)) {
return state.isEnabled() ? state.getTool() : null;
}
}
}
return myDefaultState.isEnabled() ? myDefaultState.getTool() : null;
}
public void setEnabled(boolean enabled) {
myEnabled = enabled;
}
public void enableTool(NamedScope namedScope, Project project) {
if (myTools != null) {
for (ScopeToolState state : myTools) {
if (Comparing.equal(state.getScope(project), namedScope)) {
state.setEnabled(true);
}
}
}
setEnabled(true);
}
public void disableTool(NamedScope namedScope, Project project) {
if (myTools != null) {
for (ScopeToolState state : myTools) {
if (Comparing.equal(state.getScope(project), namedScope)) {
state.setEnabled(false);
}
}
}
}
public void disableTool(@NotNull PsiElement element) {
final Project project = element.getProject();
final DependencyValidationManager validationManager = DependencyValidationManager.getInstance(project);
if (myTools != null) {
for (ScopeToolState state : myTools) {
final NamedScope scope = state.getScope(project);
if (scope != null) {
final PackageSet packageSet = scope.getValue();
if (packageSet != null && packageSet.contains(element.getContainingFile(), validationManager)) {
state.setEnabled(false);
return;
}
}
}
myDefaultState.setEnabled(false);
}
else {
myDefaultState.setEnabled(false);
setEnabled(false);
}
}
@NotNull
public HighlightDisplayLevel getLevel(final NamedScope scope, Project project) {
if (myTools != null && scope != null){
for (ScopeToolState state : myTools) {
if (Comparing.equal(state.getScope(project), scope)) {
return state.getLevel();
}
}
}
return myDefaultState.getLevel();
}
@Override
public boolean equals(Object o) {
ToolsImpl tools = (ToolsImpl)o;
if (myEnabled != tools.myEnabled) return false;
if (getTools().size() != tools.getTools().size()) return false;
for (int i = 0; i < getTools().size(); i++) {
final ScopeToolState state = getTools().get(i);
final ScopeToolState toolState = tools.getTools().get(i);
if (!state.equalTo(toolState)){
return false;
}
}
return true;
}
public void setLevel(@NotNull HighlightDisplayLevel level, @Nullable String scopeName, Project project) {
if (scopeName == null) {
myDefaultState.setLevel(level);
} else {
if (myTools == null) {
return;
}
ScopeToolState scopeToolState = null;
int index = -1;
for (int i = 0; i < myTools.size(); i++) {
ScopeToolState tool = myTools.get(i);
if (scopeName.equals(tool.getScopeName())) {
scopeToolState = tool;
myTools.remove(tool);
index = i;
break;
}
}
if (index < 0) {
throw new IllegalStateException("Scope " + scopeName + " not found");
}
final InspectionToolWrapper toolWrapper = scopeToolState.getTool();
final NamedScope scope = scopeToolState.getScope(project);
if (scope != null) {
myTools.add(index, new ScopeToolState(scope, toolWrapper, scopeToolState.isEnabled(), level));
}
else {
myTools.add(index, new ScopeToolState(scopeToolState.getScopeName(), toolWrapper, scopeToolState.isEnabled(), level));
}
}
}
public void setDefaultState(@NotNull InspectionToolWrapper toolWrapper, boolean enabled, @NotNull HighlightDisplayLevel level) {
myDefaultState.setTool(toolWrapper);
myDefaultState.setLevel(level);
myDefaultState.setEnabled(enabled);
}
public void setLevel(@NotNull HighlightDisplayLevel level) {
myDefaultState.setLevel(level);
}
@Nullable
public List<ScopeToolState> getNonDefaultTools() {
return myTools;
}
}