Skip to content

Commit 291abc5

Browse files
authored
Optimize methods that check for annotations on a Symbol (#1362)
These methods are called very frequently. Previously these methods operated on `Stream`s, but that was causing overhead visible in profiles. Switch them to use `Iterator`s and a callback `Predicate`. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Consolidated annotation-checking logic by introducing a centralized utility method to streamline multiple annotation-matching operations into a single, reusable component. * Replaced stream-based checks with explicit iteration for improved performance and code consistency across annotation-checking operations. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent e4999a6 commit 291abc5

File tree

2 files changed

+52
-13
lines changed

2 files changed

+52
-13
lines changed

nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import java.util.Map;
5454
import java.util.Set;
5555
import java.util.function.BiPredicate;
56+
import java.util.function.Predicate;
5657
import java.util.stream.Collectors;
5758
import java.util.stream.Stream;
5859
import javax.lang.model.element.AnnotationMirror;
@@ -191,6 +192,37 @@ public static Stream<? extends AnnotationMirror> getAllAnnotations(Symbol symbol
191192
return Stream.concat(symbol.getAnnotationMirrors().stream(), typeUseAnnotations);
192193
}
193194

195+
/**
196+
* Check if any direct annotation a symbol matches a given predicate. Works for both source and
197+
* bytecode.
198+
*
199+
* @param symbol the symbol
200+
* @param config NullAway configuration
201+
* @param predicate the predicate to match annotation names against
202+
* @return true if any annotation on the symbol matches the predicate, false otherwise
203+
*/
204+
public static boolean hasAnyAnnotationMatching(
205+
Symbol symbol, Config config, Predicate<String> predicate) {
206+
for (AnnotationMirror annotationMirror : symbol.getAnnotationMirrors()) {
207+
if (predicate.test(annotationMirror.getAnnotationType().toString())) {
208+
return true;
209+
}
210+
}
211+
// to handle bytecodes, also check direct type-use annotations stored in attributes
212+
Symbol typeAnnotationOwner =
213+
symbol.getKind().equals(ElementKind.PARAMETER) ? symbol.owner : symbol;
214+
for (Attribute.TypeCompound typeCompound : typeAnnotationOwner.getRawTypeAttributes()) {
215+
if (!targetTypeMatches(symbol, typeCompound.position)
216+
|| !isDirectTypeUseAnnotation(typeCompound, symbol, config)) {
217+
continue;
218+
}
219+
if (predicate.test(typeCompound.getAnnotationType().toString())) {
220+
return true;
221+
}
222+
}
223+
return false;
224+
}
225+
194226
/**
195227
* Retrieve the {@code value} attribute of a method annotation of some type.
196228
*

nullaway/src/main/java/com/uber/nullaway/Nullness.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,10 @@ public static boolean isMonotonicNonNullAnnotation(String annotName) {
6868
* {@code symbol}. Used to reason whether a field may be null.
6969
*/
7070
public static boolean hasNullableOrMonotonicNonNullAnnotation(Symbol symbol, Config config) {
71-
return hasNullableOrMonotonicNonNullAnnotation(
72-
NullabilityUtil.getAllAnnotations(symbol, config), config);
73-
}
74-
75-
private static boolean hasNullableOrMonotonicNonNullAnnotation(
76-
Stream<? extends AnnotationMirror> annotations, Config config) {
77-
return annotations
78-
.map(anno -> anno.getAnnotationType().toString())
79-
.anyMatch(anno -> isNullableAnnotation(anno, config) || isMonotonicNonNullAnnotation(anno));
71+
return NullabilityUtil.hasAnyAnnotationMatching(
72+
symbol,
73+
config,
74+
annot -> isNullableAnnotation(annot, config) || isMonotonicNonNullAnnotation(annot));
8075
}
8176

8277
// The following leastUpperBound and greatestLowerBound methods were created by handwriting a
@@ -219,7 +214,8 @@ public static boolean isNonNullAnnotation(String annotName, Config config) {
219214
* Config)}
220215
*/
221216
public static boolean hasNonNullAnnotation(Symbol symbol, Config config) {
222-
return hasNonNullAnnotation(NullabilityUtil.getAllAnnotations(symbol, config), config);
217+
return NullabilityUtil.hasAnyAnnotationMatching(
218+
symbol, config, annot -> isNonNullAnnotation(annot, config));
223219
}
224220

225221
/**
@@ -230,7 +226,8 @@ public static boolean hasNonNullAnnotation(Symbol symbol, Config config) {
230226
* Config)}
231227
*/
232228
public static boolean hasNullableAnnotation(Symbol symbol, Config config) {
233-
return hasNullableAnnotation(NullabilityUtil.getAllAnnotations(symbol, config), config);
229+
return NullabilityUtil.hasAnyAnnotationMatching(
230+
symbol, config, annot -> isNullableAnnotation(annot, config));
234231
}
235232

236233
private static boolean hasNullableTypeUseAnnotation(Symbol symbol, Config config) {
@@ -316,11 +313,21 @@ public static boolean varargsArrayIsNullable(Symbol paramSymbol, Config config)
316313

317314
/** Checks if the symbol has a {@code @Nullable} declaration annotation */
318315
public static boolean hasNullableDeclarationAnnotation(Symbol symbol, Config config) {
319-
return hasNullableAnnotation(symbol.getRawAttributes().stream(), config);
316+
for (AnnotationMirror annotationMirror : symbol.getRawAttributes()) {
317+
if (isNullableAnnotation(annotationMirror.getAnnotationType().toString(), config)) {
318+
return true;
319+
}
320+
}
321+
return false;
320322
}
321323

322324
/** Checks if the symbol has a {@code @NonNull} declaration annotation */
323325
public static boolean hasNonNullDeclarationAnnotation(Symbol symbol, Config config) {
324-
return hasNonNullAnnotation(symbol.getRawAttributes().stream(), config);
326+
for (AnnotationMirror annotationMirror : symbol.getRawAttributes()) {
327+
if (isNonNullAnnotation(annotationMirror.getAnnotationType().toString(), config)) {
328+
return true;
329+
}
330+
}
331+
return false;
325332
}
326333
}

0 commit comments

Comments
 (0)