Skip to content

Commit eba27ed

Browse files
nick-someoneronshapiro
authored andcommitted
Updated JavaTimeDefaultTimeZone to avoid NPE'ing when the function it
finds was statically imported. Fixes #1252 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=241514576
1 parent d055fdb commit eba27ed

File tree

2 files changed

+45
-14
lines changed

2 files changed

+45
-14
lines changed

core/src/main/java/com/google/errorprone/bugpatterns/time/JavaTimeDefaultTimeZone.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import com.google.errorprone.util.ASTHelpers;
3131
import com.sun.source.tree.ExpressionTree;
3232
import com.sun.source.tree.MethodInvocationTree;
33-
import com.sun.tools.javac.code.Symbol.MethodSymbol;
3433
import java.util.ArrayList;
3534
import java.util.List;
3635

@@ -105,31 +104,39 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState
105104
return Description.NO_MATCH;
106105
}
107106

108-
MethodSymbol method = ASTHelpers.getSymbol(tree);
109-
String replacementMethod = method.name.toString();
110-
111-
// we special case Clock because the replacement isn't just an overload, but a new API entirely
112-
if (CLOCK_MATCHER.matches(tree, state)) {
113-
replacementMethod = "system";
114-
}
115-
116107
String idealReplacementCode = "ZoneId.of(\"America/Los_Angeles\")";
117108

118109
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
119110
String zoneIdName = SuggestedFixes.qualifyType(state, fixBuilder, "java.time.ZoneId");
120111
String replacementCode = zoneIdName + ".systemDefault()";
121112

122-
fixBuilder.replace(
123-
state.getEndPosition(ASTHelpers.getReceiver(tree)),
124-
state.getEndPosition(tree),
125-
"." + replacementMethod + "(" + replacementCode + ")");
113+
// The method could be statically imported and have no receiver: if so, just swap out the whole
114+
// tree as opposed to surgically replacing the post-receiver part..
115+
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
116+
// we special case Clock because the replacement isn't just an overload, but a new API entirely
117+
boolean systemDefaultZoneClockMethod = CLOCK_MATCHER.matches(tree, state);
118+
String replacementMethod =
119+
systemDefaultZoneClockMethod ? "system" : ASTHelpers.getSymbol(tree).name.toString();
120+
if (receiver != null) {
121+
fixBuilder.replace(
122+
state.getEndPosition(receiver),
123+
state.getEndPosition(tree),
124+
"." + replacementMethod + "(" + replacementCode + ")");
125+
} else {
126+
if (systemDefaultZoneClockMethod) {
127+
fixBuilder.addStaticImport("java.time.Clock.systemDefaultZone");
128+
}
129+
fixBuilder.replace(tree, replacementMethod + "(" + replacementCode + ")");
130+
}
126131

127132
return buildDescription(tree)
128133
.setMessage(
129134
String.format(
130135
"%s.%s is not allowed because it silently uses the system default time-zone. You "
131136
+ "must pass an explicit time-zone (e.g., %s) to this method.",
132-
method.owner.getSimpleName(), method, idealReplacementCode))
137+
ASTHelpers.getSymbol(tree).owner.getSimpleName(),
138+
ASTHelpers.getSymbol(tree),
139+
idealReplacementCode))
133140
.addFix(fixBuilder.build())
134141
.build();
135142
}

core/src/test/java/com/google/errorprone/bugpatterns/time/JavaTimeDefaultTimeZoneTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.google.errorprone.bugpatterns.time;
1717

18+
import com.google.errorprone.BugCheckerRefactoringTestHelper;
1819
import com.google.errorprone.CompilationTestHelper;
1920
import org.junit.Test;
2021
import org.junit.runner.RunWith;
@@ -42,6 +43,29 @@ public void clock() {
4243
.doTest();
4344
}
4445

46+
@Test
47+
public void staticImportOfStaticMethod() {
48+
BugCheckerRefactoringTestHelper.newInstance(
49+
new JavaTimeDefaultTimeZone(), JavaTimeDefaultTimeZoneTest.class)
50+
.addInputLines(
51+
"in/TestClass.java",
52+
"import static java.time.LocalDate.now;",
53+
"",
54+
"import java.time.LocalDate;",
55+
"public class TestClass {",
56+
" LocalDate date = now();",
57+
"}")
58+
.addOutputLines(
59+
"out/TestClass.java",
60+
"import static java.time.LocalDate.now;",
61+
"import java.time.LocalDate;",
62+
"import java.time.ZoneId;",
63+
"public class TestClass {",
64+
" LocalDate date = now(ZoneId.systemDefault());",
65+
"}")
66+
.doTest();
67+
}
68+
4569
@Test
4670
public void localDate() {
4771
helper

0 commit comments

Comments
 (0)