naming convention: extract api

This commit is contained in:
Anna.Kozlova
2017-09-26 12:01:35 +02:00
parent ecab3d9b87
commit 7fae88f175
15 changed files with 248 additions and 198 deletions
@@ -13,12 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.naming;
package com.intellij.codeInspection;
import com.intellij.psi.PsiMember;
import com.siyeh.InspectionGadgetsBundle;
public abstract class NamingConvention<T extends PsiMember> {
public abstract class NamingConvention<T> {
public abstract boolean isApplicable(T member);
public abstract String getElementDescription();
@@ -29,14 +26,14 @@ public abstract class NamingConvention<T extends PsiMember> {
public String createErrorMessage(String name, NamingConventionBean bean) {
final int length = name.length();
if (length < bean.m_minLength) {
return InspectionGadgetsBundle.message("naming.convention.problem.descriptor.short", getElementDescription(),
return InspectionsBundle.message("naming.convention.problem.descriptor.short", getElementDescription(),
Integer.valueOf(length), Integer.valueOf(bean.m_minLength));
}
else if (bean.m_maxLength > 0 && length > bean.m_maxLength) {
return InspectionGadgetsBundle.message("naming.convention.problem.descriptor.long", getElementDescription(),
return InspectionsBundle.message("naming.convention.problem.descriptor.long", getElementDescription(),
Integer.valueOf(length), Integer.valueOf(bean.m_maxLength));
}
return InspectionGadgetsBundle.message("naming.convention.problem.descriptor.regex.mismatch", getElementDescription(), bean.m_regex);
return InspectionsBundle.message("naming.convention.problem.descriptor.regex.mismatch", getElementDescription(), bean.m_regex);
}
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.naming;
package com.intellij.codeInspection;
import com.intellij.codeInspection.ui.ConventionOptionsPanel;
import com.siyeh.HardcodedMethodConstants;
import javax.swing.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -28,16 +30,19 @@ public class NamingConventionBean {
public int m_minLength;
public int m_maxLength;
public NamingConventionBean(String regex, int minLength, int maxLength) {
private Set<String> myPredefinedNames = new HashSet<>();
public NamingConventionBean(String regex, int minLength, int maxLength, String... predefinedNames2Ignore) {
m_regex = regex;
m_minLength = minLength;
m_maxLength = maxLength;
myPredefinedNames.addAll(Arrays.asList(predefinedNames2Ignore));
initPattern();
}
protected Pattern m_regexPattern;
public boolean isValid(String name) {
public boolean isValid(String name) {
final int length = name.length();
if (length < m_minLength) {
return false;
@@ -45,7 +50,7 @@ public class NamingConventionBean {
if (m_maxLength > 0 && length > m_maxLength) {
return false;
}
if (HardcodedMethodConstants.SERIAL_VERSION_UID.equals(name)) {
if (myPredefinedNames.contains(name)) {
return true;
}
final Matcher matcher = m_regexPattern.matcher(name);
@@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.naming;
package com.intellij.codeInspection;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
@@ -36,7 +35,7 @@ public class NamingConventionWithFallbackBean extends NamingConventionBean {
public JComponent createOptionsPanel() {
JPanel panel = new JPanel(new BorderLayout());
JComponent selfOptions = super.createOptionsPanel();
JBCheckBox inheritCb = new JBCheckBox("Use settings of class naming conventions", inheritDefaultSettings);
JCheckBox inheritCb = new JCheckBox("Use settings of class naming conventions", inheritDefaultSettings);
panel.add(inheritCb, BorderLayout.NORTH);
inheritCb.addActionListener(e -> {
inheritDefaultSettings = inheritCb.isSelected();
@@ -785,6 +785,10 @@ inspection.requires.auto.module.message='requires' directive for an automatic mo
inspection.requires.auto.module.transitive='requires transitive' directive for an automatic module
inspection.requires.auto.module.option=Highlight only transitive dependencies
naming.convention.problem.descriptor.short={0} name <code>#ref</code> is too short ({1} < {2}) #loc
naming.convention.problem.descriptor.long={0} name <code>#ref</code> is too long ({1} > {2}) #loc
naming.convention.problem.descriptor.regex.mismatch={0} name <code>#ref</code> doesn''t match regex ''{1}'' #loc
inspection.java.module.naming=Java module naming conventions
inspection.java.module.naming.terminal.digits=Module name component ''{0}'' should avoid terminal digits
@@ -905,4 +909,4 @@ unused.import.display.name=Unused import
inspection.fuse.stream.operations.fix.family.name=Fuse more statements to the Stream API chain
inspection.fuse.stream.operations.fix.name=Fuse {0} into the Stream API chain
inspection.fuse.stream.operations.message=Stream may be extended replacing {0}
inspection.fuse.stream.operations.display.name=Subsequent steps can be fused into Stream API chain
inspection.fuse.stream.operations.display.name=Subsequent steps can be fused into Stream API chain
@@ -1,7 +1,7 @@
<idea-plugin>
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.naming.convention.class" interface="com.siyeh.ig.naming.NamingConvention"/>
<extensionPoint qualifiedName="com.intellij.naming.convention.class" interface="com.intellij.codeInspection.NamingConvention"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
@@ -16,11 +16,11 @@
package com.siyeh.ig.junit;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiModifier;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.naming.NamingConvention;
import com.siyeh.ig.naming.NamingConventionBean;
public class AbstractTestClassNamingConvention extends NamingConvention<PsiClass> {
@@ -16,10 +16,10 @@
package com.siyeh.ig.junit;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.psi.PsiClass;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.naming.NamingConvention;
import com.siyeh.ig.naming.NamingConventionBean;
public class TestClassNamingConvention extends NamingConvention<PsiClass> {
@@ -15,6 +15,9 @@
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.codeInspection.NamingConventionWithFallbackBean;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiModifier;
import com.siyeh.InspectionGadgetsBundle;
@@ -0,0 +1,195 @@
/*
* Copyright 2000-2017 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.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.codeInspection.NamingConventionWithFallbackBean;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.ui.CheckBoxList;
import com.intellij.ui.CheckBoxListListener;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ui.JBUI;
import com.intellij.util.xmlb.XmlSerializationException;
import com.intellij.util.xmlb.XmlSerializer;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.fixes.RenameFix;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.function.Consumer;
public abstract class AbstractNamingConventionInspection<T> extends BaseInspection {
protected final Map<String, NamingConvention<T>> myNamingConventions = new LinkedHashMap<>();
protected final Map<String, NamingConventionBean> myNamingConventionBeans = new LinkedHashMap<>();
protected final Set<String> myDisabledShortNames = new HashSet<>();
private final String myDefaultConventionShortName;
public AbstractNamingConventionInspection(NamingConvention<T>[] extensions, final String defaultConventionShortName) {
for (NamingConvention<T> convention : extensions) {
myNamingConventions.put(convention.getShortName(), convention);
myNamingConventionBeans.put(convention.getShortName(), convention.createDefaultBean());
}
initDisabledState();
myDefaultConventionShortName = defaultConventionShortName;
}
private void initDisabledState() {
myDisabledShortNames.clear();
myDisabledShortNames.addAll(myNamingConventions.keySet());
}
public NamingConventionBean getNamingConventionBean(String shortName) {
return myNamingConventionBeans.get(shortName);
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
final String name = (String)infos[0];
final String shortName = (String)infos[1];
return myNamingConventions.get(shortName).createErrorMessage(name, myNamingConventionBeans.get(shortName));
}
@Override
public void readSettings(@NotNull Element node) {
initDisabledState();
for (Element extension : node.getChildren("extension")) {
String shortName = extension.getAttributeValue("name");
if (shortName == null) continue;
NamingConventionBean conventionBean = myNamingConventionBeans.get(shortName);
try {
XmlSerializer.deserializeInto(conventionBean, extension);
conventionBean.initPattern();
}
catch (XmlSerializationException e) {
throw new InvalidDataException(e);
}
String enabled = extension.getAttributeValue("enabled");
if (Boolean.parseBoolean(enabled)) {
myDisabledShortNames.remove(shortName);
}
}
}
@Override
public void writeSettings(@NotNull Element node) {
for (NamingConvention<T> convention : myNamingConventions.values()) {
String shortName = convention.getShortName();
boolean disabled = myDisabledShortNames.contains(shortName);
Element element = new Element("extension")
.setAttribute("name", shortName)
.setAttribute("enabled", disabled ? "false" : "true");
NamingConventionBean conventionBean = myNamingConventionBeans.get(shortName);
if (!convention.createDefaultBean().equals(conventionBean)) {
XmlSerializer.serializeInto(conventionBean, element);
}
else {
if (disabled) continue;
}
node.addContent(element);
}
}
public boolean isConventionEnabled(String shortName) {
return !myDisabledShortNames.contains(shortName);
}
protected void checkName(T member, String name, Consumer<String> errorRegister) {
for (NamingConvention<T> namingConvention : myNamingConventions.values()) {
if (namingConvention.isApplicable(member)) {
String shortName = namingConvention.getShortName();
if (myDisabledShortNames.contains(shortName)) {
break;
}
NamingConventionBean activeBean = myNamingConventionBeans.get(shortName);
if (activeBean instanceof NamingConventionWithFallbackBean && ((NamingConventionWithFallbackBean)activeBean).isInheritDefaultSettings()) {
//disabled when fallback is disabled
if (myDisabledShortNames.contains(myDefaultConventionShortName)) {
break;
}
activeBean = myNamingConventionBeans.get(myDefaultConventionShortName);
}
if (!activeBean.isValid(name)) {
errorRegister.accept(shortName);
}
break;
}
}
}
@Nullable
@Override
public JComponent createOptionsPanel() {
JPanel panel = new JPanel(new BorderLayout(JBUI.scale(2), JBUI.scale(2)));
CardLayout layout = new CardLayout();
JPanel descriptionPanel = new JPanel(layout);
descriptionPanel.setBorder(JBUI.Borders.empty(2));
panel.add(descriptionPanel, BorderLayout.CENTER);
CheckBoxList<NamingConvention<T>> list = new CheckBoxList<>();
list.setBorder(JBUI.Borders.empty(2));
List<NamingConvention<T>> values = new ArrayList<>(myNamingConventions.values());
Collections.reverse(values);
for (NamingConvention<T> convention : values) {
String shortName = convention.getShortName();
list.addItem(convention, convention.getElementDescription(), !myDisabledShortNames.contains(shortName));
descriptionPanel.add(myNamingConventionBeans.get(shortName).createOptionsPanel(), shortName);
}
list.addListSelectionListener((e) -> {
int selectedIndex = list.getSelectedIndex();
NamingConvention<T> item = list.getItemAt(selectedIndex);
if (item != null) {
layout.show(descriptionPanel, item.getShortName());
}
});
list.setCheckBoxListListener(new CheckBoxListListener() {
@Override
public void checkBoxSelectionChanged(int index, boolean value) {
NamingConvention<T> convention = new ArrayList<>(myNamingConventions.values()).get(index);
setEnabled(value, convention.getShortName());
}
});
list.setSelectedIndex(0);
panel.add(new JBScrollPane(list), BorderLayout.WEST);
return panel;
}
public void setEnabled(boolean value, String conventionShortName) {
if (value) {
myDisabledShortNames.remove(conventionShortName);
}
else {
myDisabledShortNames.add(conventionShortName);
}
}
@Override
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
return true;
}
@Nullable
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
return new RenameFix();
}
}
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.psi.PsiClass;
import com.siyeh.InspectionGadgetsBundle;
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.psi.PsiClass;
import com.siyeh.InspectionGadgetsBundle;
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.psi.PsiClass;
import com.siyeh.InspectionGadgetsBundle;
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.psi.PsiClass;
import com.siyeh.InspectionGadgetsBundle;
@@ -29,57 +29,23 @@
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassOwner;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.CheckBoxList;
import com.intellij.ui.CheckBoxListListener;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ui.JBUI;
import com.intellij.util.xmlb.XmlSerializationException;
import com.intellij.util.xmlb.XmlSerializer;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.fixes.RenameFix;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
public class NewClassNamingConventionInspection extends BaseInspection {
public class NewClassNamingConventionInspection extends AbstractNamingConventionInspection<PsiClass> {
public static final ExtensionPointName<NamingConvention<PsiClass>> EP_NAME = ExtensionPointName.create("com.intellij.naming.convention.class");
private final Map<String, NamingConvention<PsiClass>> myNamingConventions = new LinkedHashMap<>();
private final Map<String, NamingConventionBean> myNamingConventionBeans = new LinkedHashMap<>();
private final Set<String> myDisabledShortNames = new HashSet<>();
public NewClassNamingConventionInspection() {
for (NamingConvention<PsiClass> convention : EP_NAME.getExtensions()) {
myNamingConventions.put(convention.getShortName(), convention);
myNamingConventionBeans.put(convention.getShortName(), convention.createDefaultBean());
}
initDisabledState();
super(EP_NAME.getExtensions(), ClassNamingConvention.CLASS_NAMING_CONVENTION_SHORT_NAME);
}
private void initDisabledState() {
myDisabledShortNames.clear();
myDisabledShortNames.addAll(myNamingConventions.keySet());
}
public NamingConventionBean getNamingConventionBean(String shortName) {
return myNamingConventionBeans.get(shortName);
}
@Override
public boolean shouldInspect(PsiFile file) {
return file instanceof PsiClassOwner;
@@ -92,147 +58,18 @@ public class NewClassNamingConventionInspection extends BaseInspection {
"class.naming.convention.display.name");
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
final String name = (String)infos[0];
final String shortName = (String)infos[1];
return myNamingConventions.get(shortName).createErrorMessage(name, myNamingConventionBeans.get(shortName));
}
@Override
public void readSettings(@NotNull Element node) {
initDisabledState();
for (Element extension : node.getChildren("extension")) {
String shortName = extension.getAttributeValue("name");
if (shortName == null) continue;
NamingConventionBean conventionBean = myNamingConventionBeans.get(shortName);
try {
XmlSerializer.deserializeInto(conventionBean, extension);
conventionBean.initPattern();
}
catch (XmlSerializationException e) {
throw new InvalidDataException(e);
}
String enabled = extension.getAttributeValue("enabled");
if (Boolean.parseBoolean(enabled)) {
myDisabledShortNames.remove(shortName);
}
}
}
@Override
public void writeSettings(@NotNull Element node) {
for (NamingConvention<PsiClass> convention : myNamingConventions.values()) {
String shortName = convention.getShortName();
boolean disabled = myDisabledShortNames.contains(shortName);
Element element = new Element("extension")
.setAttribute("name", shortName)
.setAttribute("enabled", disabled ? "false" : "true");
NamingConventionBean conventionBean = myNamingConventionBeans.get(shortName);
if (!convention.createDefaultBean().equals(conventionBean)) {
XmlSerializer.serializeInto(conventionBean, element);
}
else {
if (disabled) continue;
}
node.addContent(element);
}
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new NamingConventionsVisitor();
}
public boolean isConventionEnabled(String shortName) {
return !myDisabledShortNames.contains(shortName);
}
private class NamingConventionsVisitor extends BaseInspectionVisitor {
@Override
public void visitElement(PsiElement element) {
if (element instanceof PsiClass) {
PsiClass aClass = (PsiClass)element;
final String name = aClass.getName();
if (name == null) return;
for (NamingConvention<PsiClass> namingConvention : myNamingConventions.values()) {
if (namingConvention.isApplicable(aClass)) {
String shortName = namingConvention.getShortName();
if (myDisabledShortNames.contains(shortName)) {
break;
}
NamingConventionBean activeBean = myNamingConventionBeans.get(shortName);
if (activeBean instanceof NamingConventionWithFallbackBean && ((NamingConventionWithFallbackBean)activeBean).isInheritDefaultSettings()) {
//disabled when fallback is disabled
if (myDisabledShortNames.contains(ClassNamingConvention.CLASS_NAMING_CONVENTION_SHORT_NAME)) {
break;
}
activeBean = myNamingConventionBeans.get(ClassNamingConvention.CLASS_NAMING_CONVENTION_SHORT_NAME);
}
if (!activeBean.isValid(name)) {
registerClassError(aClass, name, shortName);
}
break;
}
return new BaseInspectionVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof PsiClass) {
PsiClass aClass = (PsiClass)element;
final String name = aClass.getName();
if (name == null) return;
checkName(aClass, name, shortName -> registerClassError(aClass, name, shortName));
}
}
}
}
@Nullable
@Override
public JComponent createOptionsPanel() {
JPanel panel = new JPanel(new BorderLayout(JBUI.scale(2), JBUI.scale(2)));
CardLayout layout = new CardLayout();
JPanel descriptionPanel = new JPanel(layout);
descriptionPanel.setBorder(JBUI.Borders.empty(2));
panel.add(descriptionPanel, BorderLayout.CENTER);
CheckBoxList<NamingConvention<PsiClass>> list = new CheckBoxList<>();
list.setBorder(JBUI.Borders.empty(2));
List<NamingConvention<PsiClass>> values = new ArrayList<>(myNamingConventions.values());
Collections.reverse(values);
for (NamingConvention<PsiClass> convention : values) {
String shortName = convention.getShortName();
list.addItem(convention, convention.getElementDescription(), !myDisabledShortNames.contains(shortName));
descriptionPanel.add(myNamingConventionBeans.get(shortName).createOptionsPanel(), shortName);
}
list.addListSelectionListener((e) -> {
int selectedIndex = list.getSelectedIndex();
NamingConvention<PsiClass> item = list.getItemAt(selectedIndex);
if (item != null) {
layout.show(descriptionPanel, item.getShortName());
}
});
list.setCheckBoxListListener(new CheckBoxListListener() {
@Override
public void checkBoxSelectionChanged(int index, boolean value) {
NamingConvention<PsiClass> convention = new ArrayList<>(myNamingConventions.values()).get(index);
setEnabled(value, convention.getShortName());
}
});
list.setSelectedIndex(0);
panel.add(new JBScrollPane(list), BorderLayout.WEST);
return panel;
}
public void setEnabled(boolean value, String conventionShortName) {
if (value) {
myDisabledShortNames.remove(conventionShortName);
}
else {
myDisabledShortNames.add(conventionShortName);
}
}
@Override
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
return true;
}
@Nullable
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
return new RenameFix();
};
}
}
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.NamingConvention;
import com.intellij.codeInspection.NamingConventionBean;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiTypeParameter;
import com.siyeh.InspectionGadgetsBundle;