diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureAdvanceResult.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureAdvanceResult.java index 58c7943ca0..3370b8c1b0 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureAdvanceResult.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureAdvanceResult.java @@ -1,17 +1,14 @@ package io.papermc.generator.rewriter.parser; -public enum ClosureAdvanceResult { - /** - * When the pointer advance on a closure. Escaped end closure are skipped! - */ - CHANGED, - /** - * When the pointer doesn't advance and cannot find the closure. - */ - IGNORED, - /** - * When the pointer advance by skipping strong closure within weak closure - * or by reaching a weak end closure escaped by '\' char preceding it. - */ - SKIPPED +public record ClosureAdvanceResult(boolean found, boolean advanced) { + + public static final ClosureAdvanceResult NONE = new ClosureAdvanceResult(false, false); + + public static ClosureAdvanceResult find(boolean found) { + return new ClosureAdvanceResult(found, true); + } + + public static ClosureAdvanceResult skip() { + return new ClosureAdvanceResult(false, true); + } } diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureType.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureType.java deleted file mode 100644 index cf1235a303..0000000000 --- a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureType.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.papermc.generator.rewriter.parser; - -import java.util.EnumSet; - -public enum ClosureType { // todo refactor? this become bigger than initially planned - PARENTHESIS("(", ")", false), - CURLY_BRACKET("{", "}", false), - BRACKET("[", "]", false), - COMMENT("/*", "*/"), - - // escape allowed - // todo could handle the extra newline needed after """ - PARAGRAPH("\"\"\"", "\"\"\""), // order matter here this one must be checked before string for the strong check - STRING("\"", "\""), - CHAR("'", "'"); - - public final String start; - public final String end; - public final boolean strong; // once within this closure ignore all the weak ones - - ClosureType(String start, String end) { - this(start, end, true); - } - - ClosureType(String start, String end, boolean strong) { - this.start = start; - this.end = end; - this.strong = strong; - } - - public static final EnumSet ALLOW_ESCAPE = EnumSet.of(STRING, CHAR, PARAGRAPH); -} diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureTypeAdvanceResult.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureTypeAdvanceResult.java new file mode 100644 index 0000000000..4520eba7de --- /dev/null +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/ClosureTypeAdvanceResult.java @@ -0,0 +1,20 @@ +package io.papermc.generator.rewriter.parser; + +import io.papermc.generator.rewriter.parser.closure.ClosureType; + +public enum ClosureTypeAdvanceResult { + /** + * When the pointer advance on a closure. Escaped end closure are skipped! + */ + CHANGED, + /** + * When the pointer doesn't advance and cannot find the closure. + */ + IGNORED, + /** + * When the pointer advance by reaching a leaf closure escaped by '\' char preceding it. + * + * @see ClosureType#ALLOW_ESCAPE + */ + SKIPPED +} diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/LineParser.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/LineParser.java index 6454edf9fd..219c312ae7 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/LineParser.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/LineParser.java @@ -1,93 +1,143 @@ package io.papermc.generator.rewriter.parser; +import com.google.common.base.Preconditions; import io.papermc.generator.rewriter.context.ImportCollector; +import io.papermc.generator.rewriter.parser.closure.AbstractClosure; +import io.papermc.generator.rewriter.parser.closure.Closure; +import io.papermc.generator.rewriter.parser.closure.ClosureType; import io.papermc.generator.rewriter.parser.step.IterativeStep; import io.papermc.generator.rewriter.parser.step.StepManager; -import io.papermc.generator.rewriter.parser.step.model.AnnotationSteps; -import io.papermc.generator.rewriter.parser.step.model.ImportSteps; +import io.papermc.generator.rewriter.parser.step.model.AnnotationSkipSteps; +import io.papermc.generator.rewriter.parser.step.model.ImportStatementSteps; import org.jetbrains.annotations.ApiStatus; -import java.util.EnumSet; -import java.util.Set; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.List; @ApiStatus.Internal public class LineParser { - private final Set closures = EnumSet.noneOf(ClosureType.class); private final StepManager stepManager = new StepManager(); - private ClosureType strongClosure; + private Closure nearestClosure; - public boolean advanceEnclosure(ClosureType type, StringReader line) { - return this.advanceEnclosure0(type, line) == ClosureAdvanceResult.CHANGED; + @Nullable + public Closure getNearestClosure() { + return this.nearestClosure; } - public ClosureAdvanceResult advanceEnclosure0(ClosureType type, StringReader line) { - boolean inside = this.closures.contains(type); - String closure = !inside ? type.start : type.end; - - // skip comments, char and string inside the upper closure for weak closure type - if (!type.strong && inside) { - ClosureType skipClosure = this.strongClosure; - if (skipClosure == null) { - for (ClosureType strongClosure : ClosureType.values()) { - if (!strongClosure.strong) { - continue; - } - - if (this.advanceEnclosure(strongClosure, line)) { - skipClosure = strongClosure; - break; - } + // internal use only or when nearestClosure = null + // doesn't support leaf closure char escape + public boolean tryAdvanceStartClosure(@NotNull ClosureType type, @NotNull StringReader line) { + if (line.trySkipString(type.start)) { // closure has been consumed + Closure previousNearestClosure = this.nearestClosure; + this.nearestClosure = Closure.create(type); + if (previousNearestClosure != null) { + if (ClosureType.LEAFS.contains(previousNearestClosure.getType())) { + throw new ParserException("Nested closure in a leaf closure is not allowed", line); } + ((AbstractClosure) this.nearestClosure).setParent(previousNearestClosure); } - - if (skipClosure != null) { - ClosureAdvanceResult result; - while ((result = this.advanceEnclosure0(skipClosure, line)) != ClosureAdvanceResult.CHANGED && line.canRead()) { - if (result == ClosureAdvanceResult.IGNORED) { - line.skip(); - } - } - return ClosureAdvanceResult.SKIPPED; - } + this.nearestClosure.onStart(line); + return true; } + return false; + } + + // for all closure, leaf closure type should use the other similar method after this one if possible + // ignoreNestedClosureTypes order matter here + public ClosureAdvanceResult tryAdvanceEndClosure(@NotNull Closure closure, @NotNull StringReader line) { + Preconditions.checkState(this.nearestClosure != null && this.nearestClosure.hasUpperClosure(closure), "Need to be in an upper closure of " + closure + " to find its end identifier"); + boolean directClosureFound = this.nearestClosure == closure; + boolean canSearchEndClosure = this.nearestClosure == null || directClosureFound; char previousChar = '\0'; if (line.getCursor() >= 1) { previousChar = line.peek(-1); } - if (line.trySkipString(closure)) { // closure has been consumed - if (!inside) { - if (!this.closures.add(type)) { - throw new ParserException("Nested same closure detected for " + type, line); - } - } else { - // skip escape closed closure - if (closure.length() == 1 && type.start.equals(type.end) && ClosureType.ALLOW_ESCAPE.contains(type)) { - if (previousChar == '\\') { - return ClosureAdvanceResult.SKIPPED; - } + ClosureType type = closure.getType(); + if (canSearchEndClosure && line.trySkipString(type.end)) { // closure has been consumed + // skip escape closed closure + if (type.end.length() == 1 && type.start.equals(type.end) && ClosureType.ALLOW_ESCAPE.contains(type)) { + if (previousChar == '\\') { + return ClosureAdvanceResult.skip(); } + } - if (!this.closures.remove(type)) { - throw new ParserException("Missing open closure? for " + type, line); - } + this.nearestClosure.onEnd(line); + if (this.nearestClosure.parent() != null) { + this.nearestClosure = this.nearestClosure.parent(); + } else { + this.nearestClosure = null; } - if (type.strong) { - this.strongClosure = !inside ? type : null; - } - return ClosureAdvanceResult.CHANGED; + return ClosureAdvanceResult.find(directClosureFound); } - return ClosureAdvanceResult.IGNORED; + + return ClosureAdvanceResult.NONE; } - public boolean skipComment(StringReader line) { + public boolean trySkipNestedClosures(@NotNull Closure inClosure, @NotNull StringReader line, @NotNull List computedTypes) { + boolean directClosureFound = this.nearestClosure == inClosure; + boolean isLeaf = this.nearestClosure != null && ClosureType.LEAFS.contains(this.nearestClosure.getType()); + if (this.nearestClosure != null && !directClosureFound) { + final boolean advanced; + if (isLeaf) { + advanced = this.tryAdvanceEndClosure(this.nearestClosure.getType(), line) != ClosureTypeAdvanceResult.IGNORED; + } else { + advanced = this.tryAdvanceEndClosure(this.nearestClosure, line).advanced(); + } + if (advanced) { + return true; + } + } + + if (this.nearestClosure == null || !isLeaf) { // leaf take the priority and doesn't allow any other nested type + for (ClosureType type : computedTypes) { + if (this.tryAdvanceStartClosure(type, line)) { + return true; + } + } + } + return false; + } + + // only valid for leaf closure type + public ClosureTypeAdvanceResult tryAdvanceEndClosure(@NotNull ClosureType type, @NotNull StringReader line) { + Preconditions.checkArgument(ClosureType.LEAFS.contains(type), "Only leaf closure can be advanced using its type only, for other, use the closure equivalent method to take in account nested closure"); + Preconditions.checkState(this.nearestClosure != null && this.nearestClosure.getType() == type, "Need an direct upper closure of " + type); + + char previousChar = '\0'; + if (line.getCursor() >= 1) { + previousChar = line.peek(-1); + } + + if (line.trySkipString(type.end)) { // closure has been consumed + // skip escape closed closure + if (type.end.length() == 1 && type.start.equals(type.end) && ClosureType.ALLOW_ESCAPE.contains(type)) { + if (previousChar == '\\') { + return ClosureTypeAdvanceResult.SKIPPED; + } + } + + this.nearestClosure.onEnd(line); + if (this.nearestClosure.parent() != null) { + this.nearestClosure = this.nearestClosure.parent(); + } else { + this.nearestClosure = null; + } + return ClosureTypeAdvanceResult.CHANGED; + } + return ClosureTypeAdvanceResult.IGNORED; + } + + public boolean skipComment(@NotNull StringReader line) { int previousCursor = line.getCursor(); - if (this.closures.contains(ClosureType.COMMENT) || this.advanceEnclosure(ClosureType.COMMENT, line)) { // open comment? - ClosureAdvanceResult result; - while ((result = this.advanceEnclosure0(ClosureType.COMMENT, line)) != ClosureAdvanceResult.CHANGED && line.canRead()) { // closed comment? - if (result == ClosureAdvanceResult.IGNORED) { + if ((this.nearestClosure != null && this.nearestClosure.getType() == ClosureType.COMMENT) || + this.tryAdvanceStartClosure(ClosureType.COMMENT, line)) { // open comment? + ClosureTypeAdvanceResult result; + while ((result = this.tryAdvanceEndClosure(ClosureType.COMMENT, line)) != ClosureTypeAdvanceResult.CHANGED && line.canRead()) { // closed comment? + if (result == ClosureTypeAdvanceResult.IGNORED) { line.skip(); } } @@ -96,7 +146,7 @@ public class LineParser { return false; } - public boolean skipCommentOrWhitespace(StringReader line) { + public boolean skipCommentOrWhitespace(@NotNull StringReader line) { boolean skipped = false; while (this.skipComment(line) || line.skipWhitespace() > 0) { skipped = true; @@ -104,7 +154,7 @@ public class LineParser { return skipped; } - public boolean trySkipCommentOrWhitespaceUntil(StringReader line, char terminator) { + public boolean trySkipCommentOrWhitespaceUntil(@NotNull StringReader line, char terminator) { int previousCursor = line.getCursor(); boolean skipped = this.skipCommentOrWhitespace(line); if (skipped && line.canRead() && line.peek() != terminator) { @@ -115,11 +165,11 @@ public class LineParser { return skipped; } - public boolean peekSingleLineComment(StringReader line) { - return line.peek() == '/' && line.canRead(2) && line.peek(1) == '/'; + public boolean peekSingleLineComment(@NotNull StringReader line) { + return line.canRead(2) && line.peek() == '/' && line.peek(1) == '/'; } - public boolean consumeImports(StringReader line, ImportCollector collector) { + public boolean consumeImports(@NotNull StringReader line, @NotNull ImportCollector collector) { outerLoop: while (line.canRead()) { IterativeStep step; @@ -141,13 +191,13 @@ public class LineParser { // not commented char c = line.peek(); - if (AnnotationSteps.canStart(c)) { // handle annotation with param to avoid open curly bracket that occur in array argument - this.stepManager.enqueue(new AnnotationSteps()); + if (AnnotationSkipSteps.canStart(c)) { // handle annotation with param to avoid open curly bracket that occur in array argument + this.stepManager.enqueue(new AnnotationSkipSteps()); continue; } else if (c == '{') { return true; - } else if (ImportSteps.canStart(line)) { - this.stepManager.enqueue(new ImportSteps(collector)); + } else if (ImportStatementSteps.canStart(line)) { + this.stepManager.enqueue(new ImportStatementSteps(collector)); continue; } @@ -156,6 +206,7 @@ public class LineParser { return false; } + @NotNull public StepManager getSteps() { return this.stepManager; } diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/AbstractClosure.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/AbstractClosure.java new file mode 100644 index 0000000000..acdd9ca746 --- /dev/null +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/AbstractClosure.java @@ -0,0 +1,33 @@ +package io.papermc.generator.rewriter.parser.closure; + +public class AbstractClosure implements Closure { + + private final ClosureType type; + private Closure parent; + + protected AbstractClosure(ClosureType type) { + this.type = type; + } + + @Override + public ClosureType getType() { + return this.type; + } + + @Override + public Closure parent() { + return this.parent; + } + + @Override + public String toString() { + return "Closure[" + this.type.name() + "](start=" + this.type.start + ", end=" + this.type.end + ")"; + } + + public void setParent(Closure parent) { + if (this.parent != null && parent != null) { + throw new IllegalStateException("Cannot set this parent closure since it is already in a closure: " + this.parent); + } + this.parent = parent; + } +} diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/Closure.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/Closure.java new file mode 100644 index 0000000000..3e280b2892 --- /dev/null +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/Closure.java @@ -0,0 +1,52 @@ +package io.papermc.generator.rewriter.parser.closure; + +import io.papermc.generator.rewriter.parser.ParserException; +import io.papermc.generator.rewriter.parser.StringReader; +import org.jetbrains.annotations.Nullable; +import java.util.function.Supplier; + +public interface Closure { + + ClosureType getType(); + + @Nullable + Closure parent(); + + default boolean hasUpperClosure(Closure closure) { + Closure parent = this; + while (parent != null) { + if (parent == closure) { + return true; + } + parent = parent.parent(); + } + return false; + } + + default void onStart(StringReader line) { + + } + + default void onEnd(StringReader line) { + + } + + static Closure create(ClosureType type) { + class SpecialClosure { + public static final Supplier PARAGRAPH = () -> new AbstractClosure(ClosureType.PARAGRAPH) { + + @Override + public void onStart(StringReader line) { + if (line.canRead()) { + throw new ParserException("Paragraph closure start must be followed by a newline", line); + } + } + }; + } + + if (type == ClosureType.PARAGRAPH) { + return SpecialClosure.PARAGRAPH.get(); + } + return new AbstractClosure(type); + } +} diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/ClosureType.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/ClosureType.java new file mode 100644 index 0000000000..d2d77e88b0 --- /dev/null +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/closure/ClosureType.java @@ -0,0 +1,38 @@ +package io.papermc.generator.rewriter.parser.closure; + +import java.util.Comparator; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +public enum ClosureType { + PARENTHESIS("(", ")"), + CURLY_BRACKET("{", "}"), + BRACKET("[", "]"), + COMMENT("/*", "*/"), + PARAGRAPH("\"\"\"", "\"\"\""), + STRING("\"", "\""), + CHAR("'", "'"); + + public final String start; + public final String end; + + ClosureType(String start, String end) { + this.start = start; + this.end = end; + } + + public static final EnumSet ALLOW_ESCAPE = EnumSet.of(STRING, CHAR, PARAGRAPH); + public static final EnumSet LEAFS = EnumSet.of(COMMENT, STRING, CHAR, PARAGRAPH); + + private static final List CHECK_FIRST = List.of(PARAGRAPH); + + public static List prioritySort(Set types) { + return types.stream() + .sorted(Comparator.comparingInt(o -> { + int index = CHECK_FIRST.indexOf(o); + return index == -1 ? CHECK_FIRST.size() : index; + })) + .toList(); + } +} diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/AnnotationSteps.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/AnnotationSkipSteps.java similarity index 76% rename from paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/AnnotationSteps.java rename to paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/AnnotationSkipSteps.java index 33e15920f7..b3da9afcf7 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/AnnotationSteps.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/AnnotationSkipSteps.java @@ -1,19 +1,23 @@ package io.papermc.generator.rewriter.parser.step.model; -import io.papermc.generator.rewriter.parser.ClosureAdvanceResult; -import io.papermc.generator.rewriter.parser.ClosureType; import io.papermc.generator.rewriter.parser.LineParser; import io.papermc.generator.rewriter.parser.ParserException; import io.papermc.generator.rewriter.parser.ProtoTypeName; +import io.papermc.generator.rewriter.parser.ClosureAdvanceResult; +import io.papermc.generator.rewriter.parser.closure.Closure; +import io.papermc.generator.rewriter.parser.closure.ClosureType; import io.papermc.generator.rewriter.parser.step.IterativeStep; import io.papermc.generator.rewriter.parser.step.StepHolder; import io.papermc.generator.rewriter.parser.StringReader; import io.papermc.generator.utils.NamingManager; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import java.util.HashSet; +import java.util.List; +import java.util.Set; // start once "@" is detected unless commented -// order is: skipAtSign -> skipPartName -> checkOpenParenthesis (-> skipParentheses) -public final class AnnotationSteps implements StepHolder { +// order is: skipAtSign -> skipPartName -> checkAnnotationName -> checkOpenParenthesis (-> skipParentheses) +public final class AnnotationSkipSteps implements StepHolder { public static boolean canStart(char currentChar) { return currentChar == '@'; @@ -22,6 +26,7 @@ public final class AnnotationSteps implements StepHolder { private final IterativeStep skipParenthesesStep = IterativeStep.createUntil(this::skipParentheses); private @MonotonicNonNull ProtoTypeName name; + private Closure parenthesisClosure; public void skipAtSign(StringReader line, LineParser parser) { line.skip(); // skip @ @@ -43,20 +48,29 @@ public final class AnnotationSteps implements StepHolder { this.name = line.getPartNameUntil('(', parser::skipCommentOrWhitespace, this.name); - if (line.canRead() && parser.peekSingleLineComment(line)) { + if (parser.peekSingleLineComment(line)) { // ignore single line comment at the end and allow the name to continue line.setCursor(line.getTotalLength()); } return !line.canRead(); } + private static final List IGNORE_NESTED_CLOSURES; + static { + Set types = new HashSet<>(ClosureType.LEAFS.size() + 1); + types.addAll(ClosureType.LEAFS); + types.add(ClosureType.PARENTHESIS); // skip nested annotation too + + IGNORE_NESTED_CLOSURES = ClosureType.prioritySort(types); + } + public boolean skipParentheses(StringReader line, LineParser parser) { ClosureAdvanceResult result; - while ((result = parser.advanceEnclosure0(ClosureType.PARENTHESIS, line)) != ClosureAdvanceResult.CHANGED) { // closed parenthesis? + while (!(result = parser.tryAdvanceEndClosure(this.parenthesisClosure, line)).found()) { if (!line.canRead()) { // parenthesis on another line? return true; } - if (result == ClosureAdvanceResult.IGNORED) { + if (!result.advanced() && !parser.trySkipNestedClosures(this.parenthesisClosure, line, IGNORE_NESTED_CLOSURES)) { line.skip(); } } @@ -88,7 +102,8 @@ public final class AnnotationSteps implements StepHolder { return true; } - if (parser.advanceEnclosure(ClosureType.PARENTHESIS, line)) { // open parenthesis? + if (parser.tryAdvanceStartClosure(ClosureType.PARENTHESIS, line)) { // open parenthesis? + this.parenthesisClosure = parser.getNearestClosure(); parser.getSteps().addPriority(this.skipParenthesesStep); } return false; diff --git a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/ImportSteps.java b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/ImportStatementSteps.java similarity index 96% rename from paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/ImportSteps.java rename to paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/ImportStatementSteps.java index e13d0a29c1..28fc98dfb4 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/ImportSteps.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/rewriter/parser/step/model/ImportStatementSteps.java @@ -12,7 +12,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; // start once "import" is detected unless commented // order is: enforceSpace -> checkStatic (-> enforceSpace) -> getPartName (-> skipUntilSemicolonAfterStar) -> collectImport -public final class ImportSteps implements StepHolder { +public final class ImportStatementSteps implements StepHolder { public static boolean canStart(StringReader line) { return line.trySkipString("import"); @@ -28,12 +28,12 @@ public final class ImportSteps implements StepHolder { private boolean isStatic; private @MonotonicNonNull ProtoTypeName name; - public ImportSteps(ImportCollector collector) { + public ImportStatementSteps(ImportCollector collector) { this.collector = collector; } public void enforceSpace(StringReader line, LineParser parser) { - if (line.canRead() && parser.peekSingleLineComment(line)) { + if (parser.peekSingleLineComment(line)) { // ignore single line comment at the end of import/static line.setCursor(line.getTotalLength()); return; diff --git a/paper-api-generator/src/test/java/io/papermc/generator/rewriter/data/sample/parser/area/AnnotationTrapClass.java b/paper-api-generator/src/test/java/io/papermc/generator/rewriter/data/sample/parser/area/AnnotationTrapClass.java index 878951472b..6b96ed54ba 100644 --- a/paper-api-generator/src/test/java/io/papermc/generator/rewriter/data/sample/parser/area/AnnotationTrapClass.java +++ b/paper-api-generator/src/test/java/io/papermc/generator/rewriter/data/sample/parser/area/AnnotationTrapClass.java @@ -1,6 +1,10 @@ package io.papermc.generator.rewriter.data.sample.parser.area; -@AnnotationTrapClass.Trapped(strings = {"trap: ) \" ) {"}, chars = {')', '{', '\''}, paragraphs = """ +@AnnotationTrapClass.Trapped(strings = {"trap: ) \" ) {"}, annotation = @AnnotationTrapClass.Trapped2(strings = {"trap: ) \" ) {"}, chars = {')', '{', '\''}, paragraphs = """ + ) + \"\"\" + { + """, clazz = AnnotationTrapClass.Trapped.class), chars = {')', '{', '\''}, paragraphs = """ ) \"\"\" { @@ -13,5 +17,19 @@ public class AnnotationTrapClass { // << 33 char[] chars(); String[] paragraphs(); + + Trapped2 annotation(); + } + + @interface Trapped2 { + + String[] strings(); + + char[] chars(); + + String[] paragraphs(); + + Class clazz(); + } }