Skip to content

Commit ac12f41

Browse files
committed
feat: add meta-annotation for multi-level annotation propagation
Allow annotations to be inherited at multiple levels of the type hierarchy, enabling both broad and specific configuration of mutators. Use case: Configure mutators that share common types. For example, annotate a fuzz test method to apply default settings to all String mutators, while still allowing individual String parameters to override those settings with different values. Without this feature, an annotation could only appear once in the inheritance chain, preventing this layered configuration approach.
1 parent 986ede1 commit ac12f41

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

src/main/java/com/code_intelligence/jazzer/mutation/support/TypeSupport.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import com.code_intelligence.jazzer.mutation.annotation.NotNull;
2929
import com.code_intelligence.jazzer.mutation.annotation.WithLength;
30+
import com.code_intelligence.jazzer.mutation.utils.IgnoreRecursiveConflicts;
3031
import com.code_intelligence.jazzer.mutation.utils.PropertyConstraint;
3132
import java.lang.annotation.Annotation;
3233
import java.lang.annotation.Inherited;
@@ -578,6 +579,9 @@ private static Annotation[] checkExtraAnnotations(
578579
.collect(Collectors.toCollection(HashSet::new));
579580
for (Annotation annotation : extraAnnotations) {
580581
boolean added = existingAnnotationTypes.add(annotation.annotationType());
582+
if (annotation.annotationType().isAnnotationPresent(IgnoreRecursiveConflicts.class)) {
583+
continue;
584+
}
581585
require(added, annotation + " already directly present on " + base);
582586
}
583587
return extraAnnotations;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2025 Code Intelligence GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.code_intelligence.jazzer.mutation.utils;
18+
19+
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
20+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
21+
22+
import java.lang.annotation.Documented;
23+
import java.lang.annotation.Retention;
24+
import java.lang.annotation.Target;
25+
26+
/**
27+
* A meta-annotation to turn off the check in {@code checkExtraAnnotations} that throws if some
28+
* annotation is present multiple times on a type. This allows annotations like e.g.
29+
* {@code @DictionaryProvider} to be propagated down the type hierarchy and accumulated along the
30+
* way.
31+
*
32+
* <p>E.g. {@code @A("data1") List<@A("data2") String> arg} - the String mutator will can make use
33+
* of {@code @A("data1")} and {@code @A("data2")}, but the List mutator can only see
34+
* {@code @A("data1")}.
35+
*/
36+
@Target(ANNOTATION_TYPE)
37+
@Retention(RUNTIME)
38+
@Documented
39+
public @interface IgnoreRecursiveConflicts {}

0 commit comments

Comments
 (0)