mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
PRP-10968 Flag discouraged time zone-dependent APIs (#9)
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.BugPattern.LinkType;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import com.google.errorprone.BugPattern.StandardTags;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/** A {@link BugChecker} which flags illegal time-zone related operations. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "TimeZoneUsage",
|
||||
summary =
|
||||
"Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone",
|
||||
linkType = LinkType.NONE,
|
||||
severity = SeverityLevel.WARNING,
|
||||
tags = StandardTags.FRAGILE_CODE)
|
||||
public final class TimeZoneUsageCheck extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> IS_BANNED_TIME_METHOD =
|
||||
anyOf(
|
||||
instanceMethod().onDescendantOf(Clock.class.getName()).namedAnyOf("getZone", "withZone"),
|
||||
staticMethod()
|
||||
.onClass(Clock.class.getName())
|
||||
.namedAnyOf(
|
||||
"system",
|
||||
"systemDefaultZone",
|
||||
"systemUTC",
|
||||
"tickMillis",
|
||||
"tickMinutes",
|
||||
"tickSeconds"),
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
Instant.class.getName(),
|
||||
LocalDate.class.getName(),
|
||||
LocalDateTime.class.getName(),
|
||||
LocalTime.class.getName())
|
||||
.named("now"));
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
return IS_BANNED_TIME_METHOD.matches(tree, state)
|
||||
? buildDescription(tree).build()
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public final class TimeZoneUsageCheckTest {
|
||||
private final CompilationTestHelper compilationHelper =
|
||||
CompilationTestHelper.newInstance(TimeZoneUsageCheck.class, getClass())
|
||||
.expectErrorMessage(
|
||||
"X",
|
||||
Predicates.containsPattern(
|
||||
"Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone"));
|
||||
|
||||
@Test
|
||||
public void testIdentification() {
|
||||
compilationHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static java.time.ZoneOffset.UTC;",
|
||||
"",
|
||||
"import java.time.Clock;",
|
||||
"import java.time.Duration;",
|
||||
"import java.time.Instant;",
|
||||
"import java.time.LocalDate;",
|
||||
"import java.time.LocalDateTime;",
|
||||
"import java.time.LocalTime;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Clock clock = Clock.fixed(Instant.EPOCH, UTC);",
|
||||
" clock.instant();",
|
||||
" clock.millis();",
|
||||
" Clock.offset(clock, Duration.ZERO);",
|
||||
" Clock.tick(clock, Duration.ZERO);",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Clock.systemUTC();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Clock.systemDefaultZone();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Clock.system(UTC);",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Clock.tickMillis(UTC);",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Clock.tickMinutes(UTC);",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Clock.tickSeconds(UTC);",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" clock.getZone();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" clock.withZone(UTC);",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Instant.now();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Instant.now(clock);",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalDate.now();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalDate.now(clock);",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalDate.now(UTC);",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalDateTime.now();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalDateTime.now(clock);",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalDateTime.now(UTC);",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalTime.now();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalTime.now(clock);",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalTime.now(UTC);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user