/* * 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.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.util.ASTHelpers; 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.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.", 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 (ASTHelpers.isSameType( state.getSymtab().stringBuilderType, ASTHelpers.getType(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; } }