Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warn about use of String charset methods #941

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.matchers.Description.NO_MATCH;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.method.MethodMatchers.constructor;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;

Expand All @@ -29,13 +30,15 @@
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MemberReferenceTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.ClassTree;
Expand Down Expand Up @@ -70,7 +73,7 @@
severity = WARNING
)
public class JdkObsolete extends BugChecker
implements NewClassTreeMatcher, ClassTreeMatcher, MemberReferenceTreeMatcher {
implements NewClassTreeMatcher, ClassTreeMatcher, MethodInvocationTreeMatcher, MemberReferenceTreeMatcher {

static class Obsolete {
final String qualifiedName;
Expand Down Expand Up @@ -118,6 +121,9 @@ Optional<Fix> fix(Tree tree, VisitorState state) {
"Stack is a nonstandard class that predates the Java Collections Framework;"
+ " prefer ArrayDeque. Note that the Stack methods push/pop/peek correspond"
+ " to the Deque methods addFirst/removeFirst/peekFirst."),
new Obsolete(
"java.lang.String",
"String methods should use typed Charset instead of String charset."),
new Obsolete(
"java.lang.StringBuffer",
"StringBuffer performs synchronization that is usually unnecessary;"
Expand Down Expand Up @@ -157,6 +163,17 @@ Optional<Fix> fix(Tree tree, VisitorState state) {
.onExactClass("com.google.re2j.Matcher")
.withSignature("appendReplacement(java.lang.StringBuffer,java.lang.String)"));

static final Matcher<ExpressionTree> MATCHER_STRING =
anyOf(
constructor()
.forClass("java.lang.String")
.withParameters(ImmutableList.of(
Suppliers.arrayOf(Suppliers.BYTE_TYPE),
Suppliers.typeFromClass(String.class))),
instanceMethod()
.onExactClass("java.lang.String")
.withSignature("getBytes(java.lang.String)"));

@Override
public Description matchNewClass(NewClassTree tree, VisitorState state) {
MethodSymbol constructor = ASTHelpers.getSymbol(tree);
Expand Down Expand Up @@ -189,6 +206,10 @@ public Void visitMethodInvocation(MethodInvocationTree tree, Void unused) {
if (found[0]) {
return NO_MATCH;
}
} else if (owner.getQualifiedName().contentEquals("java.lang.String")) {
if (!MATCHER_STRING.matches(tree, state)) {
return NO_MATCH;
}
}
return description;
}
Expand All @@ -207,6 +228,16 @@ public Description matchClass(ClassTree tree, VisitorState state) {
return describeIfObsolete(null, state.getTypes().directSupertypes(symbol.asType()), state);
}

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (MATCHER_STRING.matches(tree, state)) {
MethodSymbol symbol = ASTHelpers.getSymbol(tree);
return describeIfObsolete(
tree, ImmutableList.of(symbol.owner.asType()), state);
}
return NO_MATCH;
}

@Override
public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) {
MethodSymbol symbol = ASTHelpers.getSymbol(tree);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ public void positive() {
testHelper
.addSourceLines(
"Test.java",
"import java.nio.file.Path;",
"import java.io.UnsupportedEncodingException;",
"class Test {",
" {",
" void f() throws UnsupportedEncodingException {",
" // BUG: Diagnostic contains:",
" new java.util.LinkedList<>();",
" // BUG: Diagnostic contains:",
Expand All @@ -60,6 +60,25 @@ public void positive() {
" new StringBuffer();",
" // BUG: Diagnostic contains:",
" new java.util.Hashtable<Object, Object>() {};",
" // BUG: Diagnostic contains:",
" new String(new byte[0], \"UTF-8\");",
" // BUG: Diagnostic contains:",
" \"\".getBytes(\"UTF-8\");",
" }",
"}")
.doTest();
}

@Test
public void negative() {
testHelper
.addSourceLines(
"Test.java",
"import java.nio.charset.StandardCharsets;",
"class Test {",
" void f() {",
" new String(new byte[0], StandardCharsets.UTF_8);",
" \"\".getBytes(StandardCharsets.UTF_8);",
" }",
"}")
.doTest();
Expand Down