| // Copyright (c) 2020, 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.graph; | |
| import com.android.tools.r8.graph.LookupResult.LookupResultSuccess.LookupResultCollectionState; | |
| import com.android.tools.r8.utils.internal.collections.WorkList; | |
| import com.google.common.collect.Sets; | |
| import java.util.Set; | |
| public class LookupCompletenessHelper { | |
| private final PinnedPredicate pinnedPredicate; | |
| private Set<DexType> pinnedInstantiations; | |
| private Set<DexMethod> pinnedMethods; | |
| LookupCompletenessHelper(PinnedPredicate pinnedPredicate) { | |
| this.pinnedPredicate = pinnedPredicate; | |
| } | |
| void checkClass(DexClass clazz) { | |
| if (pinnedPredicate.isPinned(clazz)) { | |
| if (pinnedInstantiations == null) { | |
| pinnedInstantiations = Sets.newIdentityHashSet(); | |
| } | |
| pinnedInstantiations.add(clazz.type); | |
| } | |
| } | |
| void checkMethod(DexEncodedMethod method) { | |
| if (pinnedPredicate.isPinned(method)) { | |
| if (pinnedMethods == null) { | |
| pinnedMethods = Sets.newIdentityHashSet(); | |
| } | |
| pinnedMethods.add(method.getReference()); | |
| } | |
| } | |
| void checkDexClassAndMethod(LookupMethodTarget methodTarget) { | |
| checkClass(methodTarget.getHolder()); | |
| checkMethod(methodTarget.getDefinition()); | |
| } | |
| LookupResultCollectionState computeCollectionState( | |
| DexMethod method, AppInfoWithClassHierarchy appInfo) { | |
| assert pinnedInstantiations == null || !pinnedInstantiations.isEmpty(); | |
| if (pinnedInstantiations == null) { | |
| return LookupResultCollectionState.Complete; | |
| } | |
| if (pinnedMethods != null) { | |
| return LookupResultCollectionState.Incomplete; | |
| } | |
| WorkList<DexType> workList = WorkList.newIdentityWorkList(pinnedInstantiations); | |
| while (workList.hasNext()) { | |
| if (isMethodKeptInSuperTypeOrIsLibrary(workList, method, appInfo)) { | |
| return LookupResultCollectionState.Incomplete; | |
| } | |
| } | |
| return LookupResultCollectionState.Complete; | |
| } | |
| private boolean isMethodKeptInSuperTypeOrIsLibrary( | |
| WorkList<DexType> workList, DexMethod method, AppInfoWithClassHierarchy appInfo) { | |
| while (workList.hasNext()) { | |
| DexClass parent = appInfo.definitionFor(workList.next()); | |
| if (parent == null) { | |
| continue; | |
| } | |
| DexEncodedMethod methodInClass = parent.lookupVirtualMethod(method); | |
| if (methodInClass != null | |
| && (parent.isNotProgramClass() || pinnedPredicate.isPinned(methodInClass))) { | |
| return true; | |
| } | |
| if (parent.superType != null) { | |
| workList.addIfNotSeen(parent.superType); | |
| } | |
| workList.addIfNotSeen(parent.interfaces.values); | |
| } | |
| return false; | |
| } | |
| } |