blob: 717f23596998106162b33d45414984520fb2e573 [file] [log] [blame]
// Copyright (c) 2021, 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.ir.desugar.itf;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
// Helper class implementing bunch of default interface method handling operations.
final class DefaultMethodsHelper {
// Current set of default interface methods, may overlap with `hidden`.
private final Set<DexEncodedMethod> candidates = Sets.newIdentityHashSet();
// Current set of known hidden default interface methods.
private final Set<DexEncodedMethod> hidden = Sets.newIdentityHashSet();
// Represents information about default interface methods of an
// interface and its superinterfaces. Namely: a list of live (not hidden)
// and hidden default interface methods in this interface's hierarchy.
//
// Note that it is assumes that these lists should never be big.
static final class Collection {
static final Collection EMPTY =
new Collection(Collections.emptyList(), Collections.emptyList());
// All live default interface methods in this interface's hierarchy.
private final List<DexEncodedMethod> live;
// All hidden default interface methods in this interface's hierarchy.
private final List<DexEncodedMethod> hidden;
private Collection(List<DexEncodedMethod> live, List<DexEncodedMethod> hidden) {
this.live = live;
this.hidden = hidden;
}
// If there is just one live method having specified
// signature return it, otherwise return null.
DexMethod getSingleCandidate(DexMethod method) {
DexMethod candidate = null;
for (DexEncodedMethod encodedMethod : live) {
DexMethod current = encodedMethod.getReference();
if (current.proto == method.proto && current.name == method.name) {
if (candidate != null) {
return null;
}
candidate = current;
}
}
return candidate;
}
}
final void merge(Collection collection) {
candidates.addAll(collection.live);
hidden.addAll(collection.hidden);
}
final void hideMatches(DexMethod method) {
Iterator<DexEncodedMethod> it = candidates.iterator();
while (it.hasNext()) {
DexEncodedMethod candidate = it.next();
if (method.match(candidate)) {
hidden.add(candidate);
it.remove();
}
}
}
final void addDefaultMethod(DexEncodedMethod encoded) {
candidates.add(encoded);
}
// Create default interface collection based on collected information.
final Collection wrapInCollection() {
candidates.removeAll(hidden);
return (candidates.isEmpty() && hidden.isEmpty())
? Collection.EMPTY
: new Collection(Lists.newArrayList(candidates), Lists.newArrayList(hidden));
}
}