diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index eff2b8e1932a..70bdf3dbb2d1 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -1221,6 +1221,10 @@ key="property.value.set.to.itself.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.javabeans.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.javabeans.PropertyValueSetToItselfInspection"/> + #ref is located in ''{0}'' while super method parameter type is located in ''{1}'' preventing overriding parameter.type.prevents.overriding.quickfix=Change type of parameter to ''{0}'' parameter.type.prevents.overriding.family.quickfix=Change type of parameter +suspicious.getter.setter.display.name=Suspicious getter/setter +suspicious.setter.problem.descriptor=Setter #ref() assigns field ''{0}'' +suspicious.getter.problem.descriptor=Getter #ref() returns field ''{0}'' diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/SuspiciousGetterSetterInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/SuspiciousGetterSetterInspection.java new file mode 100644 index 000000000000..44a71f3a7cb7 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/SuspiciousGetterSetterInspection.java @@ -0,0 +1,143 @@ +/* + * 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. + */ +package com.siyeh.ig.javabeans; + +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.PropertyUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Bas Leijdekkers + */ +public class SuspiciousGetterSetterInspection extends BaseInspection { + + @SuppressWarnings("PublicField") + public boolean onlyWarnWhenFieldPresent = false; + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("suspicious.getter.setter.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return ((Boolean)infos[0]).booleanValue() + ? InspectionGadgetsBundle.message("suspicious.setter.problem.descriptor", infos[1]) + : InspectionGadgetsBundle.message("suspicious.getter.problem.descriptor", infos[1]); + } + + @Nullable + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Only warn when field matching getter/setter name is present", this, "onlyWarnWhenFieldPresent"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new SuspiciousGetterSetterVisitor(); + } + + private class SuspiciousGetterSetterVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final String name = method.getName(); + final String fieldName; + final boolean setter; + final String extractedFieldName; + if (nameStartsWith(name, "get")) { + final PsiField getterField = PropertyUtil.getFieldOfGetter(method); + if (getterField == null) { + return; + } + fieldName = getterField.getName(); + extractedFieldName = name.substring(3); + setter = false; + } + else if (nameStartsWith(name, "is")) { + final PsiField getterField = PropertyUtil.getFieldOfGetter(method); + if (getterField == null) { + return; + } + fieldName = getterField.getName(); + extractedFieldName = name.substring(2); + setter = false; + } + else if (nameStartsWith(name, "set")) { + final PsiField setterField = PropertyUtil.getFieldOfSetter(method); + if (setterField == null) { + return; + } + fieldName = setterField.getName(); + extractedFieldName = name.substring(3); + setter = true; + } + else { + return; + } + final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(method.getProject()); + final String computedFieldName = codeStyleManager.propertyNameToVariableName(decapitalize(extractedFieldName), VariableKind.FIELD); + if (fieldName.equalsIgnoreCase(computedFieldName)) { + return; + } + if (onlyWarnWhenFieldPresent) { + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + if (aClass.findFieldByName(computedFieldName, true) == null) { + return; + } + } + registerMethodError(method, Boolean.valueOf(setter), fieldName); + } + } + + private static boolean nameStartsWith(String name, String prefix) { + return name.startsWith(prefix) && name.length() != prefix.length() && Character.isUpperCase(name.charAt(prefix.length())); + } + + private static String decapitalize(String name) { + final StringBuilder result = new StringBuilder(); + for (int i = 0, length = name.length(); i < length; i++) { + final char c = name.charAt(i); + if (Character.isUpperCase(c)) { + result.append(Character.toLowerCase(c)); + } + else { + result.append(name.substring(i)); + return result.toString(); + } + } + return result.toString(); + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SuspiciousGetterSetter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SuspiciousGetterSetter.html new file mode 100644 index 000000000000..5c0f91608cde --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SuspiciousGetterSetter.html @@ -0,0 +1,13 @@ + + +Reports suspicious getter or setter methods. +A getter or setter is suspicious if it accesses a different field than would be expected by its name. + + +

+Use the checkbox below to indicate the inspection should only warn when a field +with a name matching the getter or setter name is present in the class. +

+New in 14 + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/javabeans/suspicious_getter_setter/SuspiciousGetterSetter.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/javabeans/suspicious_getter_setter/SuspiciousGetterSetter.java new file mode 100644 index 000000000000..1194eb44fda7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/javabeans/suspicious_getter_setter/SuspiciousGetterSetter.java @@ -0,0 +1,13 @@ +public class SuspiciousGetterSetter { + + private String myOne; + private String myTwo; + + public String getTwo() { + return myOne; + } + + public void setTwo(String two) { + myOne = two; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/javabeans/SuspiciousGetterSetterInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/javabeans/SuspiciousGetterSetterInspectionTest.java new file mode 100644 index 000000000000..376de8cb8f77 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/javabeans/SuspiciousGetterSetterInspectionTest.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package com.siyeh.ig.javabeans; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class SuspiciousGetterSetterInspectionTest extends LightInspectionTestCase { + + public void testSuspiciousGetterSetter() { + final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(getProject()).getCurrentSettings(); + final String oldPrefix = settings.FIELD_NAME_PREFIX; + try { + settings.FIELD_NAME_PREFIX = "my"; + doTest(); + } finally { + settings.FIELD_NAME_PREFIX = oldPrefix; + } + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + final SuspiciousGetterSetterInspection inspection = new SuspiciousGetterSetterInspection(); + inspection.onlyWarnWhenFieldPresent = true; + return inspection; + } +} \ No newline at end of file