blob: 30f7fec25ed31fff5804061e60ee8fc6a0b3183e [file] [log] [blame]
// Copyright (c) 2023, 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.asm.ClassSimpleNameParser.ClassSimpleNameProperty;
import com.android.tools.r8.keepanno.asm.PackageNameParser.PackageNameProperty;
import com.android.tools.r8.keepanno.asm.TypeParser.TypeProperty;
import com.android.tools.r8.keepanno.ast.AnnotationConstants.ClassNamePattern;
import com.android.tools.r8.keepanno.ast.KeepPackagePattern;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
import com.android.tools.r8.keepanno.ast.KeepTypePattern;
import com.android.tools.r8.keepanno.ast.KeepUnqualfiedClassNamePattern;
import com.android.tools.r8.keepanno.ast.ParsingContext;
import com.android.tools.r8.keepanno.ast.ParsingContext.AnnotationParsingContext;
import com.android.tools.r8.keepanno.ast.ParsingContext.PropertyParsingContext;
import com.google.common.collect.ImmutableList;
import java.util.function.Consumer;
import org.objectweb.asm.AnnotationVisitor;
public class ClassNameParser
extends PropertyParserBase<KeepQualifiedClassNamePattern, ClassNameProperty> {
public ClassNameParser(ParsingContext parsingContext) {
super(parsingContext);
}
public enum ClassNameProperty {
PATTERN,
NAME,
CONSTANT,
}
@Override
boolean tryProperty(
ClassNameProperty property,
String name,
Object value,
Consumer<KeepQualifiedClassNamePattern> setValue) {
switch (property) {
case NAME:
return new TypeParser(getParsingContext())
.tryProperty(
TypeProperty.TYPE_NAME,
name,
value,
type -> setValue.accept(typeToClassType(type, getParsingContext().property(name))));
case CONSTANT:
return new TypeParser(getParsingContext())
.tryProperty(
TypeProperty.TYPE_CONSTANT,
name,
value,
type -> setValue.accept(typeToClassType(type, getParsingContext().property(name))));
default:
return false;
}
}
KeepQualifiedClassNamePattern typeToClassType(
KeepTypePattern typePattern, PropertyParsingContext parsingContext) {
return typePattern.apply(
KeepQualifiedClassNamePattern::any,
primitiveTypePattern -> {
throw parsingContext.error("Invalid use of primitive type where class type was expected");
},
arrayTypePattern -> {
throw parsingContext.error("Invalid use of array type where class type was expected");
},
classNamePattern -> classNamePattern);
}
@Override
AnnotationVisitor tryPropertyAnnotation(
ClassNameProperty property,
String name,
String descriptor,
Consumer<KeepQualifiedClassNamePattern> setValue) {
switch (property) {
case PATTERN:
{
AnnotationParsingContext parsingContext =
getParsingContext().property(name).annotation(descriptor);
ClassNameParser fullNameParser = new ClassNameParser(parsingContext);
PackageNameParser packageParser = new PackageNameParser(parsingContext);
ClassSimpleNameParser simpleNameParser = new ClassSimpleNameParser(parsingContext);
fullNameParser.setProperty(ClassNamePattern.name, ClassNameProperty.NAME);
fullNameParser.setProperty(ClassNamePattern.constant, ClassNameProperty.CONSTANT);
packageParser.setProperty(ClassNamePattern.packageName, PackageNameProperty.NAME);
simpleNameParser.setProperty(ClassNamePattern.simpleName, ClassSimpleNameProperty.NAME);
return new ParserVisitor(
parsingContext,
ImmutableList.of(fullNameParser, packageParser, simpleNameParser),
() -> {
if (fullNameParser.isDeclared()) {
if (simpleNameParser.isDeclared() || packageParser.isDeclared()) {
throw parsingContext.error(
"Cannot specify both the full class name and its "
+ (simpleNameParser.isDeclared() ? "simple name" : "package"));
}
setValue.accept(fullNameParser.getValue());
return;
}
setValue.accept(
KeepQualifiedClassNamePattern.builder()
.setPackagePattern(
packageParser.getValueOrDefault(KeepPackagePattern.any()))
.setNamePattern(
simpleNameParser.getValueOrDefault(
KeepUnqualfiedClassNamePattern.any()))
.build());
});
}
default:
return null;
}
}
}