Model api level of referenced types for live methods and fields

Bug: 188388130
Bug: 138781768
Bug: 188499184
Bug: 188498051
Change-Id: I426198648662be0d0b81e9f6079ae07c378dd6e9
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 1e10fa9..0611cdd5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo;
 import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
@@ -132,6 +133,10 @@
     optimizationInfo = info;
   }
 
+  public void setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo info) {
+    optimizationInfo = info;
+  }
+
   @Override
   public KotlinFieldLevelInfo getKotlinInfo() {
     return kotlinMemberInfo;
diff --git a/src/main/java/com/android/tools/r8/graph/DexMember.java b/src/main/java/com/android/tools/r8/graph/DexMember.java
index 9b62855..ae9d9fb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMember.java
@@ -3,7 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.Iterables;
+import java.util.Map;
 import java.util.function.Function;
 
 public abstract class DexMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
@@ -60,4 +62,14 @@
   public Iterable<DexType> getReferencedBaseTypes(DexItemFactory dexItemFactory) {
     return Iterables.transform(getReferencedTypes(), type -> type.toBaseType(dexItemFactory));
   }
+
+  public AndroidApiLevel computeApiLevelForReferencedTypes(
+      AppView<?> appView, Map<DexReference, AndroidApiLevel> apiLevelMap) {
+    AndroidApiLevel minApiLevel = appView.options().minApiLevel;
+    AndroidApiLevel apiLevel = minApiLevel;
+    for (DexType type : getReferencedBaseTypes(appView.dexItemFactory())) {
+      apiLevel = apiLevel.max(apiLevelMap.getOrDefault(type, minApiLevel));
+    }
+    return apiLevel;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
new file mode 100644
index 0000000..f93437e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -0,0 +1,82 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMember;
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo;
+import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo;
+import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo;
+import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Map;
+
+public class ApiModelAnalysis extends EnqueuerAnalysis {
+
+  private final AppView<?> appView;
+  private final AndroidApiLevel minApiLevel;
+  private final Map<DexReference, AndroidApiLevel> referenceToApiLevelMap;
+
+  public ApiModelAnalysis(
+      AppView<?> appView, Map<DexReference, AndroidApiLevel> referenceToApiLevelMap) {
+    this.appView = appView;
+    this.minApiLevel = appView.options().minApiLevel;
+    this.referenceToApiLevelMap = referenceToApiLevelMap;
+  }
+
+  @Override
+  public void processNewlyLiveField(ProgramField field, ProgramDefinition context) {
+    setApiLevelForMember(
+        field.getDefinition(), computeApiLevelForReferencedTypes(field.getReference()));
+  }
+
+  @Override
+  public void processNewlyLiveMethod(ProgramMethod method, ProgramDefinition context) {
+    setApiLevelForMember(
+        method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference()));
+  }
+
+  @Override
+  public void processTracedCode(ProgramMethod method, DefaultEnqueuerUseRegistry registry) {
+    assert registry.getMaxApiReferenceLevel().isGreaterThanOrEqualTo(minApiLevel);
+    setApiLevelForMember(method.getDefinition(), registry.getMaxApiReferenceLevel());
+  }
+
+  private void setApiLevelForMember(DexEncodedMember<?, ?> member, AndroidApiLevel apiLevel) {
+    // To not have mutable update information for all members that all has min api level we
+    // swap the default optimization info for one with that marks the api level to be min api.
+    MemberOptimizationInfo<?> optimizationInfo = member.getOptimizationInfo();
+    if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) {
+      member.apply(
+          field -> {
+            field.setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo.getInstance());
+          },
+          method -> {
+            method.setMinApiOptimizationInfo(DefaultMethodOptimizationWithMinApiInfo.getInstance());
+          });
+    } else {
+      AndroidApiLevel maxApiLevel =
+          optimizationInfo.hasApiReferenceLevel()
+              ? apiLevel.max(optimizationInfo.getApiReferenceLevel(minApiLevel))
+              : apiLevel;
+      member.apply(
+          field -> {
+            field.getMutableOptimizationInfo().setApiReferenceLevel(maxApiLevel);
+          },
+          method -> {
+            method.getMutableOptimizationInfo().setApiReferenceLevel(maxApiLevel);
+          });
+    }
+  }
+
+  private AndroidApiLevel computeApiLevelForReferencedTypes(DexMember<?, ?> member) {
+    return member.computeApiLevelForReferencedTypes(appView, referenceToApiLevelMap);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index 9e09724..dc87519 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerWorklist;
 import com.android.tools.r8.utils.Timing;
@@ -26,6 +27,9 @@
   /** Called when a method is found to be live. */
   public void processNewlyLiveMethod(ProgramMethod method, ProgramDefinition context) {}
 
+  /** Called when a method's code has been processed by the registry. */
+  public void processTracedCode(ProgramMethod method, DefaultEnqueuerUseRegistry registry) {}
+
   /**
    * Called when the Enqueuer reaches a fixpoint. This may happen multiple times, since each
    * analysis may enqueue items into the worklist upon the fixpoint using {@param worklist}.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
index 0408418..533174b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
@@ -8,12 +8,13 @@
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.utils.AndroidApiLevel;
 
 public class DefaultFieldOptimizationInfo extends FieldOptimizationInfo {
 
   private static final DefaultFieldOptimizationInfo INSTANCE = new DefaultFieldOptimizationInfo();
 
-  private DefaultFieldOptimizationInfo() {}
+  protected DefaultFieldOptimizationInfo() {}
 
   public static DefaultFieldOptimizationInfo getInstance() {
     return INSTANCE;
@@ -55,6 +56,11 @@
   }
 
   @Override
+  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
+    throw new RuntimeException("Should never be called");
+  }
+
+  @Override
   public MutableFieldOptimizationInfo toMutableOptimizationInfo() {
     return new MutableFieldOptimizationInfo();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
new file mode 100644
index 0000000..27c6f43
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.optimize.info;
+
+import com.android.tools.r8.utils.AndroidApiLevel;
+
+public class DefaultFieldOptimizationWithMinApiInfo extends DefaultFieldOptimizationInfo {
+
+  private static final DefaultFieldOptimizationWithMinApiInfo INSTANCE =
+      new DefaultFieldOptimizationWithMinApiInfo();
+
+  public static DefaultFieldOptimizationWithMinApiInfo getInstance() {
+    return INSTANCE;
+  }
+
+  @Override
+  public boolean hasApiReferenceLevel() {
+    return true;
+  }
+
+  @Override
+  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
+    return minApi;
+  }
+
+  @Override
+  public MutableFieldOptimizationInfo toMutableOptimizationInfo() {
+    MutableFieldOptimizationInfo updatableFieldOptimizationInfo = super.toMutableOptimizationInfo();
+    // Use null to specify that the min api is set to minApi.
+    updatableFieldOptimizationInfo.setMinApiReferenceLevel();
+    return updatableFieldOptimizationInfo;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index 1df189a..0aed133 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -180,7 +180,7 @@
 
   @Override
   public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
-    return UNKNOWN_API_REFERENCE_LEVEL;
+    throw new RuntimeException("Should never be called");
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
index a5e21d9..0638369 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
@@ -30,7 +30,7 @@
     MutableMethodOptimizationInfo updatableMethodOptimizationInfo =
         super.toMutableOptimizationInfo();
     // Use null to specify that the min api is set to minApi.
-    updatableMethodOptimizationInfo.setApiReferenceLevel(null);
+    updatableMethodOptimizationInfo.setMinApiReferenceLevel();
     return updatableMethodOptimizationInfo;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
index e9ce890..910669d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.optimize.info;
 
+import com.android.tools.r8.utils.AndroidApiLevel;
+
 public interface MemberOptimizationInfo<
     T extends MemberOptimizationInfo<T> & MutableOptimizationInfo> {
 
@@ -19,5 +21,11 @@
     return null;
   }
 
+  default boolean hasApiReferenceLevel() {
+    return false;
+  }
+
+  AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi);
+
   T toMutableOptimizationInfo();
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index 41c145f..748d82d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.OptionalBool;
 import java.util.BitSet;
@@ -95,10 +94,6 @@
 
   public abstract boolean returnValueHasBeenPropagated();
 
-  public abstract AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi);
-
-  public abstract boolean hasApiReferenceLevel();
-
   public static OptionalBool isApiSafeForInlining(
       MethodOptimizationInfo caller, MethodOptimizationInfo inlinee, InternalOptions options) {
     if (!options.apiModelingOptions().enableApiCallerIdentification) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index 9150ea0..d00377e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -15,6 +15,8 @@
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Optional;
 import java.util.Set;
 
 /**
@@ -36,6 +38,7 @@
   private int readBits = 0;
   private ClassTypeElement dynamicLowerBoundType = null;
   private TypeElement dynamicUpperBoundType = null;
+  private Optional<AndroidApiLevel> apiReferenceLevel = null;
 
   public MutableFieldOptimizationInfo fixupClassTypeReferences(
       AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
@@ -150,4 +153,29 @@
   public MutableFieldOptimizationInfo asMutableFieldOptimizationInfo() {
     return this;
   }
+
+  @SuppressWarnings("OptionalAssignedToNull")
+  @Override
+  public boolean hasApiReferenceLevel() {
+    return apiReferenceLevel != null;
+  }
+
+  @Override
+  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApi) {
+    assert hasApiReferenceLevel();
+    return apiReferenceLevel.orElse(minApi);
+  }
+
+  @Override
+  @SuppressWarnings("OptionalAssignedToNull")
+  public void setMinApiReferenceLevel() {
+    assert apiReferenceLevel == null;
+    this.apiReferenceLevel = Optional.empty();
+  }
+
+  @Override
+  public void setApiReferenceLevel(AndroidApiLevel apiReferenceLevel) {
+    assert apiReferenceLevel != null;
+    this.apiReferenceLevel = Optional.of(apiReferenceLevel);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 95d817f..1b47801 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -498,6 +498,19 @@
   }
 
   @Override
+  @SuppressWarnings("OptionalAssignedToNull")
+  public void setMinApiReferenceLevel() {
+    assert apiReferenceLevel == null;
+    this.apiReferenceLevel = Optional.empty();
+  }
+
+  @Override
+  public void setApiReferenceLevel(AndroidApiLevel apiReferenceLevel) {
+    assert apiReferenceLevel != null;
+    this.apiReferenceLevel = Optional.of(apiReferenceLevel);
+  }
+
+  @Override
   public boolean isMutableOptimizationInfo() {
     return true;
   }
@@ -512,11 +525,6 @@
     return this;
   }
 
-  public MutableMethodOptimizationInfo setApiReferenceLevel(AndroidApiLevel apiReferenceLevel) {
-    this.apiReferenceLevel = Optional.ofNullable(apiReferenceLevel);
-    return this;
-  }
-
   public MutableMethodOptimizationInfo mutableCopy() {
     return new MutableMethodOptimizationInfo(this);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
index bf34966..db7bd1d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
@@ -4,4 +4,11 @@
 
 package com.android.tools.r8.ir.optimize.info;
 
-public interface MutableOptimizationInfo {}
+import com.android.tools.r8.utils.AndroidApiLevel;
+
+public interface MutableOptimizationInfo {
+
+  void setMinApiReferenceLevel();
+
+  void setApiReferenceLevel(AndroidApiLevel apiReferenceLevel);
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index e93af67..b560847 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -182,6 +182,13 @@
   }
 
   private void setMaxApiReferenceLevel(DexReference reference) {
+    if (reference.isDexMember()) {
+      this.maxApiReferenceLevel =
+          maxApiReferenceLevel.max(
+              reference
+                  .asDexMember()
+                  .computeApiLevelForReferencedTypes(appView, apiReferenceMapping));
+    }
     this.maxApiReferenceLevel =
         maxApiReferenceLevel.max(apiReferenceMapping.getOrDefault(reference, maxApiReferenceLevel));
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index d2c666a..16d8707 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -80,6 +80,7 @@
 import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import com.android.tools.r8.graph.analysis.ApiModelAnalysis;
 import com.android.tools.r8.graph.analysis.DesugaredLibraryConversionWrapperAnalysis;
 import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
 import com.android.tools.r8.graph.analysis.EnqueuerCheckCastAnalysis;
@@ -102,8 +103,6 @@
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.LambdaClass;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo;
 import com.android.tools.r8.kotlin.KotlinMetadataEnqueuerExtension;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
@@ -2983,6 +2982,9 @@
         && appView.options().getProguardConfiguration().getKeepAttributes().signature) {
       registerAnalysis(new GenericSignatureEnqueuerAnalysis(enqueuerDefinitionSupplier));
     }
+    if (appView.options().apiModelingOptions().enableApiCallerIdentification) {
+      registerAnalysis(new ApiModelAnalysis(appView, referenceToApiLevelMap));
+    }
     if (mode.isInitialTreeShaking()) {
       // This is simulating the effect of the "root set" applied rules.
       // This is done only in the initial pass, in subsequent passes the "rules" are reapplied
@@ -3910,19 +3912,8 @@
     DefaultEnqueuerUseRegistry registry =
         useRegistryFactory.create(appView, method, this, referenceToApiLevelMap);
     method.registerCodeReferences(registry);
-    DexEncodedMethod methodDefinition = method.getDefinition();
-    AndroidApiLevel maxApiReferenceLevel = registry.getMaxApiReferenceLevel();
-    assert maxApiReferenceLevel.isGreaterThanOrEqualTo(options.minApiLevel);
-    // To not have mutable update information for all methods that all has min api level we
-    // swap the default optimization info for one with that marks the api level to be min api.
-    if (methodDefinition.getOptimizationInfo() == DefaultMethodOptimizationInfo.getInstance()
-        && maxApiReferenceLevel == options.minApiLevel) {
-      methodDefinition.setMinApiOptimizationInfo(
-          DefaultMethodOptimizationWithMinApiInfo.getInstance());
-      return;
-    }
-    methodDefinition.setOptimizationInfo(
-        methodDefinition.getMutableOptimizationInfo().setApiReferenceLevel(maxApiReferenceLevel));
+    // Notify analyses.
+    analyses.forEach(analysis -> analysis.processTracedCode(method, registry));
   }
 
   private void checkDefinitionForSoftPinning(ProgramDefinition definition) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java
index 5a88c7c..f6996e9 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java
@@ -6,6 +6,9 @@
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForType;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
@@ -34,9 +37,8 @@
 
   @Test
   public void testR8() throws Exception {
-    Method apiCallerApiLevel1 = ApiCaller.class.getDeclaredMethod("apiLevel22");
-    Method apiCallerCallerApiLevel1 = ApiCallerCaller.class.getDeclaredMethod("apiLevel22");
-    Method otherCallerApiLevel1 = OtherCaller.class.getDeclaredMethod("apiLevel1");
+    Method apiCallerApiLevel22 = ApiCaller.class.getDeclaredMethod("apiLevel22");
+    Method apiCallerCallerApiLevel22 = ApiCallerCaller.class.getDeclaredMethod("apiLevel22");
     testForR8(parameters.getBackend())
         .addProgramClasses(ApiCaller.class, ApiCallerCaller.class, OtherCaller.class, Main.class)
         .addLibraryClasses(ApiType.class)
@@ -50,16 +52,15 @@
         .addRunClasspathClasses(ApiType.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(ApiType.class.getName())
-        .inspect(verifyThat(parameters, apiCallerApiLevel1).inlinedInto(apiCallerCallerApiLevel1))
-        // TODO(b/138781768): Should not be inlined
-        .inspect(
-            verifyThat(parameters, apiCallerCallerApiLevel1).inlinedInto(otherCallerApiLevel1));
+        .inspect(verifyThat(parameters, apiCallerApiLevel22).inlinedInto(apiCallerCallerApiLevel22))
+        .inspect(inspector -> assertThat(inspector.clazz(OtherCaller.class), not(isPresent())));
   }
 
   public static class ApiType {}
 
   @NoHorizontalClassMerging
   public static class ApiCaller {
+
     public static ApiType apiLevel22() throws Exception {
       // The reflective call here is to ensure that the setting of A's api level is not based on
       // a method reference to `Api` and only because of the type reference in the field `api`.
@@ -81,6 +82,7 @@
     }
   }
 
+  @NoHorizontalClassMerging
   public static class OtherCaller {
 
     public static void apiLevel1() throws Exception {