blob: b9e893d4056883b0c2cd589fe2709ea1baf8f9f2 [file]
// Copyright (c) 2026, 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.apimodel;
import com.android.tools.r8.ApiDatabaseGeneratorException;
import com.android.tools.r8.apimodel.ApiAmendments.ClassAmendment;
import com.android.tools.r8.apimodel.ApiAmendments.FieldAmendment;
import com.android.tools.r8.apimodel.ApiAmendments.MethodAmendment;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class ParsedApiClassAmending {
public static void amendApi(Collection<ParsedApiClass> apiClasses, ApiAmendments amendments)
throws ApiDatabaseGeneratorException {
Map<ClassReference, ParsedApiClass> classMap = new HashMap<>();
for (ParsedApiClass apiClass : apiClasses) {
classMap.put(apiClass.getClassReference(), apiClass);
}
for (ApiAmendments.ClassAmendment classAmendment : amendments.getClasses()) {
amendApiClass(apiClasses, classAmendment, classMap);
}
for (ApiAmendments.MethodAmendment methodAmendment : amendments.getMethods()) {
amendApiMethod(methodAmendment, classMap);
}
for (ApiAmendments.FieldAmendment fieldAmendment : amendments.getFields()) {
amendApiField(fieldAmendment, classMap);
}
}
private static void amendApiField(
FieldAmendment fieldAmendment, Map<ClassReference, ParsedApiClass> classMap)
throws ApiDatabaseGeneratorException {
FieldTypelessReference fieldRef = fieldAmendment.getFieldReference();
ParsedApiClass holder = classMap.get(fieldRef.getHolderClass());
if (holder == null) {
throw new ApiDatabaseGeneratorException(
"Holder class "
+ fieldRef.getHolderClass()
+ " for field "
+ fieldRef
+ " does not exist");
}
if (holder.hasField(fieldRef)) {
throw new ApiDatabaseGeneratorException(
"Field " + fieldRef + " already exists in " + holder.getClassReference());
}
holder.registerField(fieldRef, new ApiRange(fieldAmendment.getApiLevel()));
}
private static void amendApiMethod(
MethodAmendment methodAmendment, Map<ClassReference, ParsedApiClass> classMap)
throws ApiDatabaseGeneratorException {
MethodReference methodRef = methodAmendment.getMethodReference();
ParsedApiClass holder = classMap.get(methodRef.getHolderClass());
if (holder == null) {
throw new ApiDatabaseGeneratorException(
"Holder class "
+ methodRef.getHolderClass()
+ " for method "
+ methodRef
+ " does not exist");
}
if (holder.hasMethod(methodRef)) {
throw new ApiDatabaseGeneratorException(
"Method " + methodRef + " already exists in " + holder.getClassReference());
}
holder.registerMethod(methodRef, new ApiRange(methodAmendment.getApiLevel()));
}
private static void amendApiClass(
Collection<ParsedApiClass> apiClasses,
ClassAmendment classAmendment,
Map<ClassReference, ParsedApiClass> classMap)
throws ApiDatabaseGeneratorException {
ClassReference classRef = classAmendment.getClassReference();
if (classMap.containsKey(classRef)) {
throw new ApiDatabaseGeneratorException("Class " + classRef + " already exists");
} else {
ParsedApiClass newClass =
new ParsedApiClass(classRef, new ApiRange(classAmendment.getApiLevel()));
apiClasses.add(newClass);
classMap.put(classRef, newClass);
}
}
}