/*
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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.google.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.MaturityLevel.MATURE;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.Category;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matchers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Convert;
import javax.lang.model.type.TypeKind;
/**
* @author lowasser@google.com (Louis Wasserman)
*/
@BugPattern(category = Category.JDK, explanation =
"StringBuilder does not have a char constructor, so instead this code creates "
+ "a StringBuilder with initial size equal to the code point of the specified char.",
maturity = MATURE, name = "StringBuilderInitWithChar", severity = ERROR,
summary = "StringBuilder does not have a char constructor; this invokes the int constructor.")
public class StringBuilderInitWithChar extends BugChecker implements NewClassTreeMatcher {
@Override
public Description matchNewClass(NewClassTree tree, VisitorState state) {
if (Matchers.isSameType(Symtab.instance(state.context).stringBuilderType).matches(
tree.getIdentifier(), state) && tree.getArguments().size() == 1) {
ExpressionTree argument = tree.getArguments().get(0);
Type type = ((JCTree) argument).type;
if (type.getKind() == TypeKind.CHAR) {
if (argument.getKind() == Kind.CHAR_LITERAL) {
char ch = (Character) ((LiteralTree) argument).getValue();
return describeMatch(tree,
SuggestedFix.replace(argument, "\"" + Convert.quote(Character.toString(ch)) + "\""));
} else {
return describeMatch(tree, SuggestedFix.replace(tree,
"new StringBuilder().append(" + state.getSourceForNode((JCTree) argument) + ")"));
}
}
}
return Description.NO_MATCH;
}
}