@@ -84,9 +84,6 @@ public final class ThreadSafety {
84
84
private final ImmutableSet <String > suppressAnnotation ;
85
85
private final ImmutableSet <String > typeParameterAnnotation ;
86
86
87
- /** Stores recursive invocations of {@link #isTypeParameterThreadSafe} */
88
- private final Set <TypeVariableSymbol > recursiveThreadSafeTypeParameter = new HashSet <>();
89
-
90
87
public static Builder builder () {
91
88
return new Builder ();
92
89
}
@@ -418,6 +415,14 @@ public static Violation absent() {
418
415
*/
419
416
public Violation threadSafeInstantiation (
420
417
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 ) {
421
426
for (int i = 0 ; i < type .tsym .getTypeParameters ().size (); i ++) {
422
427
TypeVariableSymbol typaram = type .tsym .getTypeParameters ().get (i );
423
428
boolean immutableTypeParameter = hasThreadSafeTypeParameterAnnotation (typaram );
@@ -445,7 +450,12 @@ public Violation threadSafeInstantiation(
445
450
.toString ()))) {
446
451
continue ;
447
452
}
448
- Violation info = isThreadSafeType (!immutableTypeParameter , containerTypeParameters , tyarg );
453
+ Violation info =
454
+ isThreadSafeTypeInternal (
455
+ !immutableTypeParameter ,
456
+ containerTypeParameters ,
457
+ tyarg ,
458
+ recursiveThreadSafeTypeParameter );
449
459
if (info .isPresent ()) {
450
460
return info .plus (
451
461
String .format (
@@ -532,18 +542,35 @@ private boolean containerOfSubtyping(
532
542
*/
533
543
public Violation isThreadSafeType (
534
544
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 ) {
535
554
return type .accept (
536
- new ThreadSafeTypeVisitor (allowContainerTypeParameters , containerTypeParameters ), null );
555
+ new ThreadSafeTypeVisitor (
556
+ allowContainerTypeParameters ,
557
+ containerTypeParameters ,
558
+ recursiveThreadSafeTypeParameter ),
559
+ null );
537
560
}
538
561
539
562
private class ThreadSafeTypeVisitor extends Types .SimpleVisitor <Violation , Void > {
540
563
541
564
private final boolean allowContainerTypeParameters ;
542
565
private final Set <String > containerTypeParameters ;
566
+ private final Set <TypeVariableSymbol > recursiveThreadSafeTypeParameter ;
543
567
544
568
private ThreadSafeTypeVisitor (
545
- boolean allowContainerTypeParameters , Set <String > containerTypeParameters ) {
569
+ boolean allowContainerTypeParameters ,
570
+ Set <String > containerTypeParameters ,
571
+ Set <TypeVariableSymbol > recursiveThreadSafeTypeParameter ) {
546
572
this .allowContainerTypeParameters = allowContainerTypeParameters ;
573
+ this .recursiveThreadSafeTypeParameter = recursiveThreadSafeTypeParameter ;
547
574
this .containerTypeParameters =
548
575
!allowContainerTypeParameters ? ImmutableSet .of () : containerTypeParameters ;
549
576
}
@@ -564,7 +591,8 @@ public Violation visitTypeVar(TypeVar type, Void s) {
564
591
if (containerTypeParameters .contains (tyvar .getSimpleName ().toString ())) {
565
592
return Violation .absent ();
566
593
}
567
- if (isTypeParameterThreadSafe (tyvar , containerTypeParameters )) {
594
+ if (isTypeParameterThreadSafe (
595
+ tyvar , containerTypeParameters , recursiveThreadSafeTypeParameter )) {
568
596
return Violation .absent ();
569
597
}
570
598
String message ;
@@ -614,7 +642,8 @@ public Violation visitType(Type type, Void s) {
614
642
}
615
643
AnnotationInfo annotation = getMarkerOrAcceptedAnnotation (type .tsym , state );
616
644
if (annotation != null ) {
617
- return threadSafeInstantiation (containerTypeParameters , annotation , type );
645
+ return threadSafeInstantiation (
646
+ containerTypeParameters , annotation , type , recursiveThreadSafeTypeParameter );
618
647
}
619
648
String nameStr = type .tsym .flatName ().toString ();
620
649
if (knownTypes .getKnownUnsafeClasses ().contains (nameStr )) {
@@ -677,14 +706,23 @@ public boolean hasThreadSafeElementAnnotation(TypeVariableSymbol symbol) {
677
706
*/
678
707
private boolean isTypeParameterThreadSafe (
679
708
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 ) {
680
716
if (!recursiveThreadSafeTypeParameter .add (symbol )) {
681
717
return true ;
682
718
}
683
719
// TODO(b/77695285): Prevent type variables that are immutable because of an immutable upper
684
720
// bound to be marked thread-safe via containerOf or typeParameterAnnotation.
685
721
try {
686
722
for (Type bound : symbol .getBounds ()) {
687
- if (!isThreadSafeType (true , containerTypeParameters , bound ).isPresent ()) {
723
+ if (!isThreadSafeTypeInternal (
724
+ true , containerTypeParameters , bound , recursiveThreadSafeTypeParameter )
725
+ .isPresent ()) {
688
726
// A type variable is thread-safe if any upper bound is thread-safe.
689
727
return true ;
690
728
}
0 commit comments