org.netbeans.modules.java.hints.StringBuilderAppend Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.java.hints;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.ParenthesizedTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.TreePath;
import java.util.Collections;
import java.util.List;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.TreeMaker;
import org.netbeans.api.java.source.WorkingCopy;
import org.netbeans.modules.java.hints.errors.Utilities;
import org.netbeans.spi.java.hints.ConstraintVariableType;
import org.netbeans.spi.java.hints.Hint;
import org.netbeans.spi.java.hints.TriggerPattern;
import org.netbeans.spi.java.hints.HintContext;
import org.netbeans.spi.java.hints.JavaFix;
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.openide.util.NbBundle;
/**
*
* @author lahvac
*/
@Hint(displayName = "#DN_StringBuilderAppend", description = "#DESC_StringBuilderAppend", id="StringBuilderAppend", category="performance", suppressWarnings="StringConcatenationInsideStringBufferAppend")
public class StringBuilderAppend {
@TriggerPattern(value="$build.append($app)",
constraints={
@ConstraintVariableType(variable="$build", type="java.lang.StringBuilder"),
@ConstraintVariableType(variable="$app", type="java.lang.String")
})
public static ErrorDescription builder(HintContext ctx) {
return hint(ctx, "StringBuilder");
}
@TriggerPattern(value="$build.append($app)",
constraints={
@ConstraintVariableType(variable="$build", type="java.lang.StringBuffer"),
@ConstraintVariableType(variable="$app", type="java.lang.String")
})
public static ErrorDescription buffer(HintContext ctx) {
return hint(ctx, "StringBuffer");
}
private static ErrorDescription hint(HintContext ctx, String clazzName) {
CompilationInfo info = ctx.getInfo();
MethodInvocationTree mit = (MethodInvocationTree) ctx.getPath().getLeaf();
ExpressionTree param = mit.getArguments().get(0);
List> sorted = Utilities.splitStringConcatenationToElements(info, new TreePath(ctx.getPath(), param));
if (sorted.size() > 1) {
String error = NbBundle.getMessage(StringBuilderAppend.class, "ERR_StringBuilderAppend", clazzName);
return ErrorDescriptionFactory.forTree(ctx, param, error, new FixImpl(info, ctx.getPath()).toEditorFix());
}
return null;
}
private static final class FixImpl extends JavaFix {
public FixImpl(CompilationInfo info, TreePath tp) {
super(info, tp);
}
public String getText() {
return NbBundle.getMessage(StringBuilderAppend.class, "FIX_StringBuilderAppend");
}
private ExpressionTree merge(TreeMaker make, ExpressionTree arg1, ExpressionTree arg2) {
if (arg1 == null) {
return arg2;
} else if (arg2 == null) {
return arg1;
} else if (arg1 == arg2) {
return arg1;
}
return make.Binary(Kind.PLUS, arg1, arg2);
}
private ExpressionTree merge(TreeMaker make, ExpressionTree arg, ExpressionTree singleLeaf,
StringBuilder literal, ExpressionTree l) {
ExpressionTree n;
if (singleLeaf != null) {
n = singleLeaf;
literal.delete(0, literal.length());
n = merge(make, n, l);
} else if (literal.length() > 0) {
n = make.Literal(literal.toString());
literal.delete(0, literal.length());
n = merge(make, n, l);
} else {
n = l;
}
return merge(make, arg, n);
}
@Override
protected void performRewrite(TransformationContext ctx) {
WorkingCopy copy = ctx.getWorkingCopy();
TreePath tp = ctx.getPath();
MethodInvocationTree mit = (MethodInvocationTree) tp.getLeaf();
ExpressionTree param = mit.getArguments().get(0);
List> sorted = Utilities.splitStringConcatenationToElements(copy, new TreePath(tp, param));
ExpressionTree site = ((MemberSelectTree) mit.getMethodSelect()).getExpression();
TreeMaker make = copy.getTreeMaker();
for (List cluster : sorted) {
StringBuilder literal = new StringBuilder();
ExpressionTree singleLeaf = null;
ExpressionTree arg = null;
if (cluster.size() == 1 &&
!Utilities.isConstantString(copy, cluster.get(0), true)) {
arg = (ExpressionTree)cluster.get(0).getLeaf();
} else {
for (TreePath p : cluster) {
ExpressionTree l = (ExpressionTree)p.getLeaf();
if (Utilities.isStringOrCharLiteral(l)) {
if (literal.length() == 0) {
singleLeaf = l;
} else {
singleLeaf = null;
}
literal.append(
((LiteralTree)l).getValue().toString()
);
} else {
ExpressionTree n;
arg = merge(make, arg, singleLeaf, literal, l);
singleLeaf = null;
}
}
}
arg = merge(make, arg, singleLeaf, literal, null);
site = make.MethodInvocation(Collections.emptyList(), make.MemberSelect(site, "append"), Collections.singletonList(arg));
}
copy.rewrite(mit, site);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy