[ApiModel] Add flag to have unknown library references reported
Change-Id: Ia029077247307244c46883255c8ab2d138df370e
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index d57d450..6ef6c416 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -370,6 +370,10 @@
assert appView.rootSet().verifyKeptItemsAreKept(appView);
appView.rootSet().checkAllRulesAreUsed(options);
+ if (options.apiModelingOptions().reportUnknownApiReferences) {
+ appView.apiLevelCompute().reportUnknownApiReferences();
+ }
+
if (options.proguardSeedsConsumer != null) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bytes);
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiDiagnostic.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiDiagnostic.java
new file mode 100644
index 0000000..98471f2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiDiagnostic.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, 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.androidapi;
+
+import com.android.tools.r8.Diagnostic;
+
+/** Base class for api related diagnostics. */
+public abstract class AndroidApiDiagnostic implements Diagnostic {}
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
index 1c61851..5a0bd81 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.androidapi;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.androidapi.ComputedApiLevel.KnownApiLevel;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
@@ -44,6 +45,10 @@
public abstract boolean isEnabled();
+ public void reportUnknownApiReferences() {
+ // Do nothing here.
+ }
+
public ComputedApiLevel computeApiLevelForDefinition(
DexMember<?, ?> reference, DexItemFactory factory, ComputedApiLevel unknownValue) {
return computeApiLevelForDefinition(reference.getReferencedBaseTypes(factory), unknownValue);
@@ -105,10 +110,12 @@
private final AndroidApiReferenceLevelCache cache;
private final ComputedApiLevel minApiLevel;
+ private final DiagnosticsHandler diagnosticsHandler;
public DefaultAndroidApiLevelCompute(AppView<?> appView) {
this.cache = AndroidApiReferenceLevelCache.create(appView, this);
this.minApiLevel = of(appView.options().getMinApiLevel());
+ this.diagnosticsHandler = appView.reporter();
}
@Override
@@ -131,5 +138,14 @@
DexReference reference, ComputedApiLevel unknownValue) {
return cache.lookup(reference, unknownValue);
}
+
+ @Override
+ public void reportUnknownApiReferences() {
+ cache
+ .getUnknownReferencesToReport()
+ .forEach(
+ reference ->
+ diagnosticsHandler.warning(new AndroidApiUnknownReferenceDiagnostic(reference)));
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
index c4d2d5a..0e267e5 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -12,7 +12,9 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ConsumerUtils;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
import java.util.List;
+import java.util.Set;
import java.util.function.BiConsumer;
public class AndroidApiReferenceLevelCache {
@@ -22,6 +24,10 @@
private final AppView<?> appView;
private final DexItemFactory factory;
+ // Collection of unknown references attempteed to be looked up.
+ private final Set<DexReference> unknownReferencesToReport = Sets.newConcurrentHashSet();
+ private final boolean reportUnknownReferences;
+
private AndroidApiReferenceLevelCache(
AppView<?> appView,
AndroidApiLevelCompute apiLevelCompute,
@@ -32,6 +38,7 @@
androidApiLevelDatabase =
new AndroidApiLevelHashingDatabaseImpl(
predefinedApiTypeLookupForHashing, appView.options(), appView.reporter());
+ reportUnknownReferences = appView.options().apiModelingOptions().reportUnknownApiReferences;
}
public static AndroidApiReferenceLevelCache create(
@@ -49,6 +56,10 @@
return new AndroidApiReferenceLevelCache(appView, apiLevelCompute, builder.build());
}
+ public Set<DexReference> getUnknownReferencesToReport() {
+ return unknownReferencesToReport;
+ }
+
public ComputedApiLevel lookupMax(
DexReference reference, ComputedApiLevel minApiLevel, ComputedApiLevel unknownValue) {
assert !minApiLevel.isNotSetApiLevel();
@@ -98,8 +109,12 @@
androidApiLevelDatabase::getTypeApiLevel,
androidApiLevelDatabase::getFieldApiLevel,
androidApiLevelDatabase::getMethodApiLevel);
- return (foundApiLevel == null)
- ? unknownValue
- : apiLevelCompute.of(foundApiLevel.max(appView.options().getMinApiLevel()));
+ if (foundApiLevel == null) {
+ if (reportUnknownReferences) {
+ unknownReferencesToReport.add(reference);
+ }
+ return unknownValue;
+ }
+ return apiLevelCompute.of(foundApiLevel.max(appView.options().getMinApiLevel()));
}
}
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiUnknownReferenceDiagnostic.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiUnknownReferenceDiagnostic.java
new file mode 100644
index 0000000..fba87df
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiUnknownReferenceDiagnostic.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2022, 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.androidapi;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+@Keep
+public class AndroidApiUnknownReferenceDiagnostic extends AndroidApiDiagnostic {
+
+ private final DexReference reference;
+
+ AndroidApiUnknownReferenceDiagnostic(DexReference reference) {
+ this.reference = reference;
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return Origin.unknown();
+ }
+
+ @Override
+ public Position getPosition() {
+ return Position.UNKNOWN;
+ }
+
+ @Override
+ public String getDiagnosticMessage() {
+ return reference.toSourceString() + " cannot be found in the api database.";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 7571ef2..16ec417 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1764,6 +1764,8 @@
System.getProperty("com.android.tools.r8.disableApiModeling") == null;
public boolean enableOutliningOfMethods =
System.getProperty("com.android.tools.r8.disableApiModeling") == null;
+ public boolean reportUnknownApiReferences =
+ System.getProperty("com.android.tools.r8.reportUnknownApiReferences") != null;
// TODO(b/232823652): Enable when we can compute the offset correctly.
public boolean useMemoryMappedByteBuffer = false;