blob: 45e83858a39692ff2bd8f5b9807461b55f3da0d7 [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.shaking.rules;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.keepanno.ast.KeepArrayTypePattern;
import com.android.tools.r8.keepanno.ast.KeepClassItemPattern;
import com.android.tools.r8.keepanno.ast.KeepInstanceOfPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodAccessPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodParametersPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodReturnTypePattern;
import com.android.tools.r8.keepanno.ast.KeepPrimitiveTypePattern;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
import com.android.tools.r8.keepanno.ast.KeepStringPattern;
import com.android.tools.r8.keepanno.ast.KeepTypePattern;
import com.android.tools.r8.keepanno.ast.OptionalPattern;
import java.util.List;
public class KeepAnnotationMatcherPredicates {
private final DexItemFactory factory;
public KeepAnnotationMatcherPredicates(DexItemFactory factory) {
this.factory = factory;
}
public boolean matchesClass(DexProgramClass clazz, KeepClassItemPattern classPattern) {
return matchesClassName(clazz.getType(), classPattern.getClassNamePattern())
&& matchesInstanceOfPattern(clazz, classPattern.getInstanceOfPattern())
&& matchesAnnotatedBy(clazz.annotations(), classPattern.getAnnotatedByPattern());
}
public boolean matchesClassName(DexType type, KeepQualifiedClassNamePattern pattern) {
if (pattern.isAny()) {
return true;
}
if (pattern.isExact()) {
return type.toDescriptorString().equals(pattern.getExactDescriptor());
}
throw new Unimplemented();
}
private boolean matchesInstanceOfPattern(
DexProgramClass unusedClazz, KeepInstanceOfPattern pattern) {
if (pattern.isAny()) {
return true;
}
throw new Unimplemented();
}
public boolean matchesMethod(KeepMethodPattern methodPattern, ProgramMethod method) {
if (methodPattern.isAnyMethod()) {
return true;
}
return matchesName(method.getName(), methodPattern.getNamePattern().asStringPattern())
&& matchesReturnType(method.getReturnType(), methodPattern.getReturnTypePattern())
&& matchesParameters(method.getParameters(), methodPattern.getParametersPattern())
&& matchesAnnotatedBy(method.getAnnotations(), methodPattern.getAnnotatedByPattern())
&& matchesAccess(method.getAccessFlags(), methodPattern.getAccessPattern());
}
public boolean matchesAccess(MethodAccessFlags access, KeepMethodAccessPattern pattern) {
if (pattern.isAny()) {
return true;
}
throw new Unimplemented();
}
public boolean matchesAnnotatedBy(
DexAnnotationSet annotations, OptionalPattern<KeepQualifiedClassNamePattern> pattern) {
if (pattern.isAbsent()) {
return true;
}
throw new Unimplemented();
}
public boolean matchesParameters(DexTypeList parameters, KeepMethodParametersPattern pattern) {
if (pattern.isAny()) {
return true;
}
List<KeepTypePattern> patternList = pattern.asList();
if (parameters.size() != patternList.size()) {
return false;
}
int size = parameters.size();
for (int i = 0; i < size; i++) {
if (!matchesType(parameters.get(i), patternList.get(i))) {
return false;
}
}
return true;
}
public boolean matchesName(DexString name, KeepStringPattern namePattern) {
if (namePattern.isAny()) {
return true;
}
if (namePattern.isExact()) {
return namePattern.asExactString().equals(name.toString());
}
throw new Unimplemented();
}
public boolean matchesReturnType(
DexType returnType, KeepMethodReturnTypePattern returnTypePattern) {
if (returnTypePattern.isAny()) {
return true;
}
if (returnTypePattern.isVoid() && returnType.isVoidType()) {
return true;
}
return matchesType(returnType, returnTypePattern.asType());
}
public boolean matchesType(DexType type, KeepTypePattern pattern) {
return pattern.apply(
() -> true,
p -> matchesPrimitiveType(type, p),
p -> matchesArrayType(type, p),
p -> matchesClassType(type, p));
}
public boolean matchesClassType(DexType type, KeepQualifiedClassNamePattern pattern) {
if (!type.isClassType()) {
return false;
}
if (pattern.isAny()) {
return true;
}
if (pattern.isExact()) {
return pattern.getExactDescriptor().equals(type.toDescriptorString());
}
throw new Unimplemented();
}
public boolean matchesArrayType(DexType type, KeepArrayTypePattern pattern) {
if (!type.isArrayType()) {
return false;
}
if (pattern.isAny()) {
return true;
}
if (type.getArrayTypeDimensions() < pattern.getDimensions()) {
return false;
}
return matchesType(
type.toArrayElementAfterDimension(pattern.getDimensions(), factory), pattern.getBaseType());
}
public boolean matchesPrimitiveType(DexType type, KeepPrimitiveTypePattern pattern) {
if (!type.isPrimitiveType()) {
return false;
}
if (pattern.isAny()) {
return true;
}
return type.asPrimitiveTypeDescriptorChar() == pattern.getDescriptorChar();
}
}