Skip to content

Commit 29d9335

Browse files
graememorganError Prone Team
authored and
Error Prone Team
committed
Remove mutable state from ThreadSafety.
Ironically, this is stopping the class being thread-safe. PiperOrigin-RevId: 619256145
1 parent 527171c commit 29d9335

File tree

1 file changed

+47
-9
lines changed

1 file changed

+47
-9
lines changed

core/src/main/java/com/google/errorprone/bugpatterns/threadsafety/ThreadSafety.java

+47-9
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,6 @@ public final class ThreadSafety {
8484
private final ImmutableSet<String> suppressAnnotation;
8585
private final ImmutableSet<String> typeParameterAnnotation;
8686

87-
/** Stores recursive invocations of {@link #isTypeParameterThreadSafe} */
88-
private final Set<TypeVariableSymbol> recursiveThreadSafeTypeParameter = new HashSet<>();
89-
9087
public static Builder builder() {
9188
return new Builder();
9289
}
@@ -418,6 +415,14 @@ public static Violation absent() {
418415
*/
419416
public Violation threadSafeInstantiation(
420417
Set<String> containerTypeParameters, AnnotationInfo annotation, Type type) {
418+
return threadSafeInstantiation(containerTypeParameters, annotation, type, new HashSet<>());
419+
}
420+
421+
public Violation threadSafeInstantiation(
422+
Set<String> containerTypeParameters,
423+
AnnotationInfo annotation,
424+
Type type,
425+
Set<TypeVariableSymbol> recursiveThreadSafeTypeParameter) {
421426
for (int i = 0; i < type.tsym.getTypeParameters().size(); i++) {
422427
TypeVariableSymbol typaram = type.tsym.getTypeParameters().get(i);
423428
boolean immutableTypeParameter = hasThreadSafeTypeParameterAnnotation(typaram);
@@ -445,7 +450,12 @@ public Violation threadSafeInstantiation(
445450
.toString()))) {
446451
continue;
447452
}
448-
Violation info = isThreadSafeType(!immutableTypeParameter, containerTypeParameters, tyarg);
453+
Violation info =
454+
isThreadSafeTypeInternal(
455+
!immutableTypeParameter,
456+
containerTypeParameters,
457+
tyarg,
458+
recursiveThreadSafeTypeParameter);
449459
if (info.isPresent()) {
450460
return info.plus(
451461
String.format(
@@ -532,18 +542,35 @@ private boolean containerOfSubtyping(
532542
*/
533543
public Violation isThreadSafeType(
534544
boolean allowContainerTypeParameters, Set<String> containerTypeParameters, Type type) {
545+
return isThreadSafeTypeInternal(
546+
allowContainerTypeParameters, containerTypeParameters, type, new HashSet<>());
547+
}
548+
549+
private Violation isThreadSafeTypeInternal(
550+
boolean allowContainerTypeParameters,
551+
Set<String> containerTypeParameters,
552+
Type type,
553+
Set<TypeVariableSymbol> recursiveThreadSafeTypeParameter) {
535554
return type.accept(
536-
new ThreadSafeTypeVisitor(allowContainerTypeParameters, containerTypeParameters), null);
555+
new ThreadSafeTypeVisitor(
556+
allowContainerTypeParameters,
557+
containerTypeParameters,
558+
recursiveThreadSafeTypeParameter),
559+
null);
537560
}
538561

539562
private class ThreadSafeTypeVisitor extends Types.SimpleVisitor<Violation, Void> {
540563

541564
private final boolean allowContainerTypeParameters;
542565
private final Set<String> containerTypeParameters;
566+
private final Set<TypeVariableSymbol> recursiveThreadSafeTypeParameter;
543567

544568
private ThreadSafeTypeVisitor(
545-
boolean allowContainerTypeParameters, Set<String> containerTypeParameters) {
569+
boolean allowContainerTypeParameters,
570+
Set<String> containerTypeParameters,
571+
Set<TypeVariableSymbol> recursiveThreadSafeTypeParameter) {
546572
this.allowContainerTypeParameters = allowContainerTypeParameters;
573+
this.recursiveThreadSafeTypeParameter = recursiveThreadSafeTypeParameter;
547574
this.containerTypeParameters =
548575
!allowContainerTypeParameters ? ImmutableSet.of() : containerTypeParameters;
549576
}
@@ -564,7 +591,8 @@ public Violation visitTypeVar(TypeVar type, Void s) {
564591
if (containerTypeParameters.contains(tyvar.getSimpleName().toString())) {
565592
return Violation.absent();
566593
}
567-
if (isTypeParameterThreadSafe(tyvar, containerTypeParameters)) {
594+
if (isTypeParameterThreadSafe(
595+
tyvar, containerTypeParameters, recursiveThreadSafeTypeParameter)) {
568596
return Violation.absent();
569597
}
570598
String message;
@@ -614,7 +642,8 @@ public Violation visitType(Type type, Void s) {
614642
}
615643
AnnotationInfo annotation = getMarkerOrAcceptedAnnotation(type.tsym, state);
616644
if (annotation != null) {
617-
return threadSafeInstantiation(containerTypeParameters, annotation, type);
645+
return threadSafeInstantiation(
646+
containerTypeParameters, annotation, type, recursiveThreadSafeTypeParameter);
618647
}
619648
String nameStr = type.tsym.flatName().toString();
620649
if (knownTypes.getKnownUnsafeClasses().contains(nameStr)) {
@@ -677,14 +706,23 @@ public boolean hasThreadSafeElementAnnotation(TypeVariableSymbol symbol) {
677706
*/
678707
private boolean isTypeParameterThreadSafe(
679708
TypeVariableSymbol symbol, Set<String> containerTypeParameters) {
709+
return isTypeParameterThreadSafe(symbol, containerTypeParameters, new HashSet<>());
710+
}
711+
712+
private boolean isTypeParameterThreadSafe(
713+
TypeVariableSymbol symbol,
714+
Set<String> containerTypeParameters,
715+
Set<TypeVariableSymbol> recursiveThreadSafeTypeParameter) {
680716
if (!recursiveThreadSafeTypeParameter.add(symbol)) {
681717
return true;
682718
}
683719
// TODO(b/77695285): Prevent type variables that are immutable because of an immutable upper
684720
// bound to be marked thread-safe via containerOf or typeParameterAnnotation.
685721
try {
686722
for (Type bound : symbol.getBounds()) {
687-
if (!isThreadSafeType(true, containerTypeParameters, bound).isPresent()) {
723+
if (!isThreadSafeTypeInternal(
724+
true, containerTypeParameters, bound, recursiveThreadSafeTypeParameter)
725+
.isPresent()) {
688726
// A type variable is thread-safe if any upper bound is thread-safe.
689727
return true;
690728
}

0 commit comments

Comments
 (0)