mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
IDEA-194396 Merge StringConstructorInspection into RedundantStringOperationInspection
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
// "Replace with empty string" "true"
|
||||
class Foo {
|
||||
public static void main(String[] args) {
|
||||
String s = "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Replace with argument" "true"
|
||||
class Foo {
|
||||
public static void main(String[] args) {
|
||||
String s = "foo";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Replace with empty string" "true"
|
||||
class Foo {
|
||||
public static void main(String[] args) {
|
||||
String s = new Stri<caret>ng();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Replace with argument" "true"
|
||||
class Foo {
|
||||
public static void main(String[] args) {
|
||||
String s = new Stri<caret>ng("foo");
|
||||
}
|
||||
}
|
||||
@@ -179,7 +179,6 @@ com.siyeh.ig.performance.CallToSimpleSetterInClassInspection
|
||||
com.siyeh.ig.performance.MethodMayBeStaticInspection
|
||||
com.siyeh.ig.performance.SizeReplaceableByIsEmptyInspection
|
||||
com.siyeh.ig.performance.StringConcatenationInLoopsInspection
|
||||
com.siyeh.ig.performance.StringConstructorInspection
|
||||
com.siyeh.ig.performance.StringReplaceableByStringBufferInspection
|
||||
com.siyeh.ig.portability.HardcodedFileSeparatorsInspection
|
||||
com.siyeh.ig.resources.ChannelResourceInspection
|
||||
|
||||
@@ -1488,11 +1488,6 @@ before.or.after.is.public.void.no.arg.display.name=Malformed @Before or @After m
|
||||
before.or.after.is.public.void.no.arg.problem.descriptor=<code>#ref()</code> has incorrect signature for a @Before or @After method #loc
|
||||
before.class.or.after.class.is.public.static.void.no.arg.display.name=Malformed @BeforeClass/@BeforeAll or @AfterClass/@AfterAll method
|
||||
before.class.or.after.class.is.public.static.void.no.arg.problem.descriptor=<code>#ref()</code> has incorrect signature for a @{0} method #loc
|
||||
string.constructor.display.name=Redundant String constructor call
|
||||
string.constructor.problem.descriptor=<code>#ref</code> is redundant #loc
|
||||
string.constructor.replace.arg.quickfix=Replace with arg
|
||||
string.constructor.replace.empty.quickfix=Replace with empty string
|
||||
string.constructor.substring.parameter.option=Ignore string constructor calls with a 'substring()' call argument
|
||||
design.for.extension.display.name=Design for extension
|
||||
design.for.extension.problem.descriptor=Method <code>#ref()</code> may be overridden and its functionality ignored #loc
|
||||
bad.oddness.display.name=Suspicious test for oddness
|
||||
@@ -2216,9 +2211,11 @@ inspection.redundant.string.remove.fix.name=Remove redundant ''{0}()'' call
|
||||
inspection.redundant.string.fix.family.name=Remove redundant call
|
||||
inspection.redundant.string.call.message=Call to <code>#ref</code> is redundant #loc
|
||||
inspection.redundant.string.argument.message=Unnecessary empty string argument
|
||||
inspection.redundant.string.index.argument.message=Unnecessary zero index argument
|
||||
inspection.redundant.string.remove.argument.fix.name=Remove argument
|
||||
inspection.redundant.string.intern.on.constant.message=Call to <code>#ref</code> on compile-time constant is unnecessary #loc
|
||||
inspection.redundant.string.constructor.message=<code>#ref</code> is redundant #loc
|
||||
inspection.redundant.string.replace.with.arg.fix.name=Replace with argument
|
||||
inspection.redundant.string.replace.with.empty.fix.name=Replace with empty string
|
||||
|
||||
inspection.type.may.be.weakened.display.name=Type may be weakened
|
||||
inspection.type.may.be.weakened.problem.descriptor=Type of variable <code>#ref</code> may be weakened to {0} #loc
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2018 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* 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.performance;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.TypeUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class StringConstructorInspection extends BaseInspection {
|
||||
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
public boolean ignoreSubstringArguments = false;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"string.constructor.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "RedundantStringConstructorCall";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"string.constructor.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message(
|
||||
"string.constructor.substring.parameter.option"), this,
|
||||
"ignoreSubstringArguments");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new StringConstructorVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionGadgetsFix buildFix(Object... infos) {
|
||||
final Boolean noArguments = (Boolean)infos[0];
|
||||
return new StringConstructorFix(noArguments.booleanValue());
|
||||
}
|
||||
|
||||
private static class StringConstructorFix extends InspectionGadgetsFix {
|
||||
|
||||
private final String m_name;
|
||||
|
||||
private StringConstructorFix(boolean noArguments) {
|
||||
if (noArguments) {
|
||||
m_name = InspectionGadgetsBundle.message(
|
||||
"string.constructor.replace.empty.quickfix");
|
||||
}
|
||||
else {
|
||||
m_name = InspectionGadgetsBundle.message(
|
||||
"string.constructor.replace.arg.quickfix");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Simplify";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(Project project, ProblemDescriptor descriptor) {
|
||||
final PsiNewExpression expression = (PsiNewExpression)descriptor.getPsiElement();
|
||||
final PsiExpressionList argList = expression.getArgumentList();
|
||||
assert argList != null;
|
||||
final PsiExpression[] args = argList.getExpressions();
|
||||
CommentTracker commentTracker = new CommentTracker();
|
||||
final String argText = (args.length == 1) ? commentTracker.text(args[0]) : "\"\"";
|
||||
|
||||
PsiReplacementUtil.replaceExpression(expression, argText, commentTracker);
|
||||
}
|
||||
}
|
||||
|
||||
private class StringConstructorVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitNewExpression(
|
||||
@NotNull PsiNewExpression expression) {
|
||||
super.visitNewExpression(expression);
|
||||
final PsiType type = expression.getType();
|
||||
if (!TypeUtils.isJavaLangString(type)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpressionList argumentList = expression.getArgumentList();
|
||||
if (argumentList == null) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length > 1) {
|
||||
return;
|
||||
}
|
||||
if (arguments.length == 1) {
|
||||
final PsiExpression argument = arguments[0];
|
||||
final PsiType parameterType = argument.getType();
|
||||
if (!TypeUtils.isJavaLangString(parameterType)) {
|
||||
return;
|
||||
}
|
||||
if (ignoreSubstringArguments &&
|
||||
hasSubstringArgument(argument)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerError(expression, Boolean.valueOf(arguments.length == 0));
|
||||
}
|
||||
|
||||
private boolean hasSubstringArgument(PsiExpression argument) {
|
||||
if (!(argument instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression =
|
||||
(PsiMethodCallExpression)argument;
|
||||
final PsiReferenceExpression methodExpression =
|
||||
methodCallExpression.getMethodExpression();
|
||||
final PsiElement element = methodExpression.resolve();
|
||||
if (!(element instanceof PsiMethod)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethod method = (PsiMethod)element;
|
||||
final PsiClass aClass = method.getContainingClass();
|
||||
if (aClass == null) {
|
||||
return true;
|
||||
}
|
||||
final String className = aClass.getQualifiedName();
|
||||
@NonNls final String methodName = method.getName();
|
||||
return CommonClassNames.JAVA_LANG_STRING.equals(className) &&
|
||||
methodName.equals("substring");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2005,10 +2005,6 @@
|
||||
key="string.concatenation.inside.string.buffer.append.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.performance.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.performance.StringConcatenationInsideStringBufferAppendInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" suppressId="RedundantStringConstructorCall" shortName="StringConstructor" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="string.constructor.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.performance.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.performance.StringConstructorInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="StringEqualsEmptyString" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="string.equals.empty.string.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.performance.issues" enabledByDefault="false" level="WARNING"
|
||||
|
||||
@@ -6,10 +6,13 @@ import com.intellij.codeInsight.daemon.impl.quickfix.DeleteElementFix;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import com.siyeh.ig.callMatcher.CallMapper;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.*;
|
||||
@@ -83,13 +86,41 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
@Override
|
||||
public void visitNewExpression(PsiNewExpression expression) {
|
||||
PsiJavaCodeReferenceElement classRef = expression.getClassReference();
|
||||
ProblemDescriptor descriptor = null;
|
||||
if (ConstructionUtils.isReferenceTo(classRef, CommonClassNames.JAVA_LANG_STRING_BUILDER, CommonClassNames.JAVA_LANG_STRING_BUFFER)) {
|
||||
ProblemDescriptor descriptor = getRedundantArgumentProblem(getSingleEmptyStringArgument(expression));
|
||||
if (descriptor == null) return;
|
||||
descriptor = getRedundantArgumentProblem(getSingleEmptyStringArgument(expression));
|
||||
}
|
||||
else if (ConstructionUtils.isReferenceTo(classRef, JAVA_LANG_STRING)) {
|
||||
descriptor = getStringConstructorProblem(expression);
|
||||
}
|
||||
if (descriptor != null) {
|
||||
myHolder.registerProblem(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
private ProblemDescriptor getStringConstructorProblem(PsiNewExpression expression) {
|
||||
PsiExpressionList args = expression.getArgumentList();
|
||||
if (args == null) return null;
|
||||
if (args.isEmpty()) {
|
||||
return myManager.createProblemDescriptor(expression, InspectionGadgetsBundle.message(
|
||||
"inspection.redundant.string.constructor.message"),
|
||||
new StringConstructorFix(true),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly);
|
||||
}
|
||||
if (args.getExpressionCount() == 1) {
|
||||
PsiExpression arg = args.getExpressions()[0];
|
||||
if (TypeUtils.isJavaLangString(arg.getType()) &&
|
||||
(PsiUtil.getLanguageLevel(expression).isAtLeast(LanguageLevel.JDK_1_7) || !STRING_SUBSTRING.matches(arg))) {
|
||||
TextRange range = new TextRange(0, args.getStartOffsetInParent());
|
||||
return myManager.createProblemDescriptor(expression, range,
|
||||
InspectionGadgetsBundle.message("inspection.redundant.string.constructor.message"),
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL, myIsOnTheFly,
|
||||
new StringConstructorFix(false));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProblemDescriptor getAppendProblem(PsiMethodCallExpression call) {
|
||||
return getSingleEmptyStringArgument(call) != null ? getProblem(call, "inspection.redundant.string.call.message") : null;
|
||||
@@ -268,4 +299,44 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
statement.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringConstructorFix extends InspectionGadgetsFix {
|
||||
private final String myName;
|
||||
|
||||
private StringConstructorFix(boolean noArguments) {
|
||||
if (noArguments) {
|
||||
myName = InspectionGadgetsBundle.message(
|
||||
"inspection.redundant.string.replace.with.empty.fix.name");
|
||||
}
|
||||
else {
|
||||
myName = InspectionGadgetsBundle.message(
|
||||
"inspection.redundant.string.replace.with.arg.fix.name");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Simplify";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(Project project, ProblemDescriptor descriptor) {
|
||||
final PsiNewExpression expression = (PsiNewExpression)descriptor.getPsiElement();
|
||||
final PsiExpressionList argList = expression.getArgumentList();
|
||||
assert argList != null;
|
||||
final PsiExpression[] args = argList.getExpressions();
|
||||
CommentTracker commentTracker = new CommentTracker();
|
||||
final String argText = (args.length == 1) ? commentTracker.text(args[0]) : "\"\"";
|
||||
|
||||
PsiReplacementUtil.replaceExpression(expression, argText, commentTracker);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ public class RedundantStringOperationMerger extends InspectionElementsMerger {
|
||||
public String[] getSourceToolNames() {
|
||||
return new String[] {
|
||||
"StringToString", "RedundantStringToString",
|
||||
"SubstringZero", "ConstantStringIntern"
|
||||
"SubstringZero", "ConstantStringIntern",
|
||||
"RedundantStringConstructorCall", "StringConstructor"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports a variety of redundant String-related operations like calling <b>String.toString()</b> or <b>String.substring(0)</b>.
|
||||
Also reports usage of redundant String constructors like <b>new String()</b> (equivalent to <b>""</b>) or <b>new String(anotherString)</b>
|
||||
(equivalent to <b>anotherString</b>).
|
||||
<!-- tooltip end -->
|
||||
<p><small>New in 2018.1</small></p>
|
||||
</body>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports any attempt to instantiate a new
|
||||
<b>String</b> object by copying an existing string.
|
||||
Constructing new <b>String</b> objects in this way
|
||||
is rarely necessary, and may cause performance problems if done often enough.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
Use the checkbox below to ignore <b>String</b>
|
||||
constructor calls which have a <b>String.substring()</b>
|
||||
call as parameter. A call to <b>substring()</b>
|
||||
reuses the character array of the original string, which can cause a large
|
||||
amount of garbage to stay in memory if the substring is small in relation to the
|
||||
original <b>String</b>.
|
||||
<p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user