blob: f10f9cd5530ccbdde9c95e9b89ef9201913d6021 [file] [log] [blame]
// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.asm;
import com.android.tools.r8.keepanno.asm.ClassNameParser.ClassNameProperty;
import com.android.tools.r8.keepanno.ast.AnnotationConstants.AnnotationPattern;
import com.android.tools.r8.keepanno.ast.KeepAnnotationPattern;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
import com.android.tools.r8.keepanno.ast.ParsingContext;
import com.android.tools.r8.keepanno.ast.ParsingContext.AnnotationParsingContext;
import com.google.common.collect.ImmutableList;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.function.Consumer;
import org.objectweb.asm.AnnotationVisitor;
public class AnnotationPatternParser
extends PropertyParserBase<KeepAnnotationPattern, AnnotationPatternParser.AnnotationProperty> {
public enum AnnotationProperty {
PATTERN
}
public AnnotationPatternParser(ParsingContext parsingContext) {
super(parsingContext);
}
@Override
AnnotationVisitor tryPropertyAnnotation(
AnnotationProperty property,
String name,
String descriptor,
Consumer<KeepAnnotationPattern> setValue) {
switch (property) {
case PATTERN:
AnnotationParsingContext parsingContext =
getParsingContext().property(name).annotation(descriptor);
AnnotationDeclarationParser parser = new AnnotationDeclarationParser(parsingContext);
return new ParserVisitor(
parsingContext,
parser,
() ->
setValue.accept(
parser.isDeclared()
? parser.getValue()
: KeepAnnotationPattern.anyWithRuntimeRetention()));
default:
return super.tryPropertyAnnotation(property, name, descriptor, setValue);
}
}
private enum RetentionProperty {
RETENTION
}
private static class RetentionParser
extends PropertyParserBase<RetentionPolicy, RetentionProperty> {
private static final String RETENTION_POLICY_DESC = "Ljava/lang/annotation/RetentionPolicy;";
public RetentionParser(ParsingContext parsingContext) {
super(parsingContext);
}
@Override
public boolean tryPropertyEnum(
RetentionProperty property,
String name,
String descriptor,
String value,
Consumer<RetentionPolicy> setValue) {
assert property == RetentionProperty.RETENTION;
if (RETENTION_POLICY_DESC.equals(descriptor)) {
setValue.accept(RetentionPolicy.valueOf(value));
return true;
}
return super.tryPropertyEnum(property, name, descriptor, value, setValue);
}
}
private static class AnnotationDeclarationParser
extends DeclarationParser<KeepAnnotationPattern> {
private final ClassNameParser nameParser;
private final ArrayPropertyParser<RetentionPolicy, RetentionProperty> retentionParser;
private final List<Parser<?>> parsers;
public AnnotationDeclarationParser(ParsingContext parsingContext) {
nameParser = new ClassNameParser(parsingContext);
nameParser.setProperty(AnnotationPattern.name, ClassNameProperty.NAME);
nameParser.setProperty(AnnotationPattern.constant, ClassNameProperty.CONSTANT);
nameParser.setProperty(AnnotationPattern.namePattern, ClassNameProperty.PATTERN);
retentionParser = new ArrayPropertyParser<>(parsingContext, RetentionParser::new);
retentionParser.setProperty(AnnotationPattern.retention, RetentionProperty.RETENTION);
retentionParser.setValueCheck(
(value, propertyContext) -> {
if (value.isEmpty()) {
throw propertyContext.error("Expected non-empty array of retention policies");
}
});
parsers = ImmutableList.of(nameParser, retentionParser);
}
@Override
List<Parser<?>> parsers() {
return parsers;
}
public KeepAnnotationPattern getValue() {
if (isDefault()) {
return null;
}
KeepAnnotationPattern.Builder builder = KeepAnnotationPattern.builder();
if (retentionParser.isDeclared()) {
List<RetentionPolicy> policies = retentionParser.getValue();
policies.forEach(builder::addRetentionPolicy);
} else {
builder.addRetentionPolicy(RetentionPolicy.RUNTIME);
}
return builder
.setNamePattern(nameParser.getValueOrDefault(KeepQualifiedClassNamePattern.any()))
.build();
}
}
}