Skip to content
Open
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 @@ -56,7 +56,8 @@ public static boolean supportsInstanceMainMethods(Context context) {
return sourceIsAtLeast(context, 25);
}

private static boolean sourceIsAtLeast(Context context, int version) {
/** Returns true if the compiler source version level is at least the given version. */
public static boolean sourceIsAtLeast(Context context, int version) {
Source lowerBound = Source.lookup(Integer.toString(version));
return lowerBound != null && Source.instance(context).compareTo(lowerBound) >= 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.google.errorprone.util.SourceVersion;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
Expand Down Expand Up @@ -157,9 +158,9 @@ Optional<Fix> fix(Tree tree, VisitorState state) {
.collect(toImmutableMap(Obsolete::qualifiedName, x -> x));

private record ObsoleteApi(
Matcher<ExpressionTree> matcher, String message, int androidMinSdkVersion) {
Matcher<ExpressionTree> matcher, String message, int androidMinSdkVersion, int jdkVersion) {
ObsoleteApi(Matcher<ExpressionTree> matcher, String message) {
this(matcher, message, 1);
this(matcher, message, 1, 1);
}
}

Expand Down Expand Up @@ -189,7 +190,8 @@ private record ObsoleteApi(
.named("toString")
.withParameters("java.lang.String"),
"Use ByteArrayOutputStream.toString(Charset) instead.",
33),
33,
10),
new ObsoleteApi(
instanceMethod()
.onExactClass("java.lang.String")
Expand All @@ -202,35 +204,40 @@ private record ObsoleteApi(
.named("decode")
.withParameters("java.lang.String", "java.lang.String"),
"Use URLDecoder.decode(String, Charset) instead.",
33),
33,
10),
new ObsoleteApi(
staticMethod()
.onClass("java.net.URLEncoder")
.named("encode")
.withParameters("java.lang.String", "java.lang.String"),
"Use URLEncoder.encode(String, Charset) instead.",
33),
33,
10),
new ObsoleteApi(
staticMethod()
.onClass("java.nio.channels.Channels")
.named("newReader")
.withParameters("java.nio.channels.ReadableByteChannel", "java.lang.String"),
"Use Channels.newReader(ReadableByteChannel, Charset) instead.",
33),
33,
10),
new ObsoleteApi(
staticMethod()
.onClass("java.nio.channels.Channels")
.named("newWriter")
.withParameters("java.nio.channels.WritableByteChannel", "java.lang.String"),
"Use Channels.newWriter(WritableByteChannel, Charset) instead.",
33),
33,
10),
new ObsoleteApi(
instanceMethod()
.onExactClass("java.util.Properties")
.named("storeToXML")
.withParameters("java.io.OutputStream", "java.lang.String", "java.lang.String"),
"Use Properties.storeToXML(OutputStream, String, Charset) instead.",
35),
35,
10),
new ObsoleteApi(
staticMethod()
.onClass(IO_UTILS)
Expand Down Expand Up @@ -343,25 +350,29 @@ private record ObsoleteApi(
.forClass("java.util.Scanner")
.withParameters("java.io.InputStream", "java.lang.String"),
"Use new Scanner(InputStream, Charset) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Scanner")
.withParameters("java.io.File", "java.lang.String"),
"Use new Scanner(File, Charset) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Scanner")
.withParameters("java.nio.file.Path", "java.lang.String"),
"Use new Scanner(Path, Charset) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Scanner")
.withParameters("java.nio.channels.ReadableByteChannel", "java.lang.String"),
"Use new Scanner(ReadableByteChannel, Charset) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.lang.String")
Expand All @@ -386,63 +397,79 @@ private record ObsoleteApi(
constructor()
.forClass("java.io.PrintStream")
.withParameters("java.io.OutputStream", "boolean", "java.lang.String"),
"Use new PrintStream(OutputStream, boolean, Charset) instead."),
"Use new PrintStream(OutputStream, boolean, Charset) instead.",
1,
10),
new ObsoleteApi(
constructor()
.forClass("java.io.PrintStream")
.withParameters("java.lang.String", "java.lang.String"),
"Use new PrintStream(String, Charset) instead."),
"Use new PrintStream(String, Charset) instead.",
1,
10),
new ObsoleteApi(
constructor()
.forClass("java.io.PrintStream")
.withParameters("java.io.File", "java.lang.String"),
"Use new PrintStream(File, Charset) instead."),
"Use new PrintStream(File, Charset) instead.",
1,
10),
new ObsoleteApi(
constructor()
.forClass("java.io.PrintWriter")
.withParameters("java.lang.String", "java.lang.String"),
"Use new PrintWriter(String, Charset) instead."),
"Use new PrintWriter(String, Charset) instead.",
1,
10),
new ObsoleteApi(
constructor()
.forClass("java.io.PrintWriter")
.withParameters("java.io.File", "java.lang.String"),
"Use new PrintWriter(File, Charset) instead."),
"Use new PrintWriter(File, Charset) instead.",
1,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Formatter")
.withParameters("java.lang.String", "java.lang.String"),
"Use new Formatter(String, Charset) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Formatter")
.withParameters("java.lang.String", "java.lang.String", "java.util.Locale"),
"Use new Formatter(String, Charset, Locale) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Formatter")
.withParameters("java.io.File", "java.lang.String"),
"Use new Formatter(File, Charset) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Formatter")
.withParameters("java.io.File", "java.lang.String", "java.util.Locale"),
"Use new Formatter(File, Charset, Locale) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Formatter")
.withParameters("java.io.OutputStream", "java.lang.String"),
"Use new Formatter(OutputStream, Charset) instead.",
34),
34,
10),
new ObsoleteApi(
constructor()
.forClass("java.util.Formatter")
.withParameters("java.io.OutputStream", "java.lang.String", "java.util.Locale"),
"Use new Formatter(OutputStream, Charset, Locale) instead.",
34));
34,
10));

static final Matcher<ExpressionTree> MATCHER_STRINGBUFFER =
anyOf(
Expand Down Expand Up @@ -748,6 +775,8 @@ private Description matchObsoleteApi(
api ->
(androidMinSdkVersion.isEmpty()
|| androidMinSdkVersion.get() >= api.androidMinSdkVersion())
&& (api.jdkVersion() <= 1
|| SourceVersion.sourceIsAtLeast(state.context, api.jdkVersion()))
&& api.matcher().matches(tree, state))
.map(api -> buildDescription(tree).setMessage(api.message()).build())
.findFirst()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,70 @@ void scanner(InputStream is, String fileName, File file, Path path, ReadableByte
.doTest();
}

@Test
public void preferCharsetAcceptingApis_jdk9() {
testHelper
.addSourceLines(
"Test.java",
"""
import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.*;
import java.net.*;
import java.nio.channels.*;
import java.util.*;

class Test {
private static final String UTF8_NAME = UTF_8.name();

void string(byte[] bytes) throws Exception {
// BUG: Diagnostic contains: String.getBytes(Charset)
"foo".getBytes(UTF8_NAME);
// BUG: Diagnostic contains: new String(byte[], Charset)
new String(bytes, UTF8_NAME);
// BUG: Diagnostic contains: new String(byte[], int, int, Charset)
new String(bytes, 0, 1, UTF8_NAME);
}

void inputStreamReader(InputStream is) throws Exception {
// BUG: Diagnostic contains: new InputStreamReader(InputStream, Charset)
new InputStreamReader(is, UTF8_NAME);
}

void outputStreamWriter(OutputStream os) throws Exception {
// BUG: Diagnostic contains: new OutputStreamWriter(OutputStream, Charset)
new OutputStreamWriter(os, UTF8_NAME);
}

void urlEncoder(String UTF8_NAME) throws Exception {
URLEncoder.encode("foo", UTF8_NAME);
}

void urlDecoder(String UTF8_NAME) throws Exception {
URLDecoder.decode("foo", UTF8_NAME);
}

void newReader(ReadableByteChannel rbc) throws Exception {
Channels.newReader(rbc, UTF8_NAME);
}

void printStream(String fileName) throws Exception {
new PrintStream(fileName, UTF8_NAME);
}

void printWriter(String fileName) throws Exception {
new PrintWriter(fileName, UTF8_NAME);
}

void scanner(InputStream is) throws Exception {
new Scanner(is, UTF8_NAME);
}
}
""")
.setArgs("--release", "9")
.doTest();
}

@Test
public void preferCharsetAcceptingApis_androidMinSdk32() {
testHelper
Expand Down