blob: 1e71e5d1ce50e74e5a30af1d97f23088fa49aa75 [file] [log] [blame]
/*
* Copyright 2000-2009 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.
*/
package com.intellij.codeInspection.i18n.inconsistentResourceBundle;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.codeInspection.ui.OptionAccessor;
import com.intellij.lang.properties.*;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.util.*;
import com.intellij.psi.PsiFile;
import com.intellij.util.containers.BidirectionalMap;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FactoryMap;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.util.*;
/**
* @author max
*/
public class InconsistentResourceBundleInspection extends GlobalSimpleInspectionTool {
private static final Key<Set<ResourceBundle>> VISITED_BUNDLES_KEY = Key.create("VISITED_BUNDLES_KEY");
private final InconsistentResourceBundleInspectionProvider[] myInspectionProviders;
private final Map<String, Boolean> mySettings = new LinkedHashMap<String, Boolean>();
public InconsistentResourceBundleInspection() {
myInspectionProviders = new InconsistentResourceBundleInspectionProvider[] {
new PropertiesKeysConsistencyInspectionProvider(),
new DuplicatedPropertiesInspectionProvider(),
new MissingTranslationsInspectionProvider(),
new PropertiesPlaceholdersInspectionProvider(),
new InconsistentPropertiesEndsInspectionProvider(),
};
}
@Override
@NotNull
public String getGroupDisplayName() {
return PropertiesBundle.message("properties.files.inspection.group.display.name");
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("inconsistent.resource.bundle.display.name");
}
@Override
@NotNull
public String getShortName() {
return "InconsistentResourceBundle";
}
@Override
@NotNull
public HighlightDisplayLevel getDefaultLevel() {
return HighlightDisplayLevel.ERROR;
}
@Override
@Nullable
public JComponent createOptionsPanel() {
final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(new OptionAccessor() {
@Override
public boolean getOption(String optionName) {
return isProviderEnabled(optionName);
}
@Override
public void setOption(String optionName, boolean optionValue) {
if (optionValue) {
mySettings.remove(optionName);
}
else {
mySettings.put(optionName, false);
}
}
});
for (final InconsistentResourceBundleInspectionProvider provider : myInspectionProviders) {
panel.addCheckbox(provider.getPresentableName(), provider.getName());
}
return panel;
}
@Override
public void writeSettings(final @NotNull Element node) throws WriteExternalException {
for (final Map.Entry<String, Boolean> e : mySettings.entrySet()) {
JDOMExternalizerUtil.writeField(node, e.getKey(), Boolean.toString(e.getValue()));
}
}
@Override
public void readSettings(final @NotNull Element node) throws InvalidDataException {
mySettings.clear();
for (final Object o : node.getChildren()) {
if (o instanceof Element) {
final Element e = (Element) o;
final String name = e.getAttributeValue("name");
final boolean value = Boolean.parseBoolean(e.getAttributeValue("value"));
mySettings.put(name, value);
}
}
}
@Override
public void inspectionStarted(@NotNull InspectionManager manager,
@NotNull GlobalInspectionContext globalContext,
@NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) {
globalContext.putUserData(VISITED_BUNDLES_KEY, new THashSet<ResourceBundle>());
}
@Override
public void checkFile(@NotNull PsiFile file,
@NotNull InspectionManager manager,
@NotNull ProblemsHolder problemsHolder,
@NotNull GlobalInspectionContext globalContext,
@NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) {
Set<ResourceBundle> visitedBundles = globalContext.getUserData(VISITED_BUNDLES_KEY);
if (!(file instanceof PropertiesFile)) return;
final PropertiesFile propertiesFile = (PropertiesFile)file;
ResourceBundle resourceBundle = propertiesFile.getResourceBundle();
assert visitedBundles != null;
if (!visitedBundles.add(resourceBundle)) return;
List<PropertiesFile> files = resourceBundle.getPropertiesFiles();
if (files.size() < 2) return;
BidirectionalMap<PropertiesFile, PropertiesFile> parents = new BidirectionalMap<PropertiesFile, PropertiesFile>();
for (PropertiesFile f : files) {
PropertiesFile parent = PropertiesUtil.getParent(f, files);
if (parent != null) {
parents.put(f, parent);
}
}
final FactoryMap<PropertiesFile, Map<String,String>> propertiesFilesNamesMaps = new FactoryMap<PropertiesFile, Map<String, String>>() {
@Nullable
@Override
protected Map<String, String> create(PropertiesFile key) {
return key.getNamesMap();
}
};
Map<PropertiesFile, Set<String>> keysUpToParent = new THashMap<PropertiesFile, Set<String>>();
for (PropertiesFile f : files) {
Set<String> keys = new THashSet<String>(propertiesFilesNamesMaps.get(f).keySet());
PropertiesFile parent = parents.get(f);
while (parent != null) {
keys.addAll(propertiesFilesNamesMaps.get(parent).keySet());
parent = parents.get(parent);
}
keysUpToParent.put(f, keys);
}
for (final InconsistentResourceBundleInspectionProvider provider : myInspectionProviders) {
if (isProviderEnabled(provider.getName())) {
provider.check(parents, files, keysUpToParent, propertiesFilesNamesMaps, manager, globalContext.getRefManager(),
problemDescriptionsProcessor);
}
}
}
private boolean isProviderEnabled(final String providerName) {
return ContainerUtil.getOrElse(mySettings, providerName, true);
}
@TestOnly
public void enableProviders(final Class<? extends InconsistentResourceBundleInspectionProvider>... providerClasses) {
Set<Class<? extends InconsistentResourceBundleInspectionProvider>> providersToEnable = ContainerUtil.newHashSet(providerClasses);
for (InconsistentResourceBundleInspectionProvider inspectionProvider : myInspectionProviders) {
if (providersToEnable.contains(inspectionProvider.getClass())) {
mySettings.put(inspectionProvider.getName(), true);
}
}
}
@TestOnly
public void disableAllProviders() {
for (InconsistentResourceBundleInspectionProvider inspectionProvider : myInspectionProviders) {
mySettings.put(inspectionProvider.getName(), false);
}
}
@TestOnly
public void clearSettings() {
mySettings.clear();
}
}