Add CfCode overload for adding diagnostic position

Bug: 210423420
Change-Id: I2bfbe3fe681c615e925c38e9ae62ca6814c50c78
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 660b1ef..01e1163 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -128,13 +128,7 @@
 
   private CfCode buildEmptyThrowingCfCode(DexMethod method) {
     CfInstruction insn[] = {new CfConstNull(), new CfThrow()};
-    return new CfCode(
-        method.holder,
-        1,
-        method.proto.parameters.size() + 1,
-        Arrays.asList(insn),
-        Collections.emptyList(),
-        Collections.emptyList());
+    return new CfCode(method.holder, 1, method.proto.parameters.size() + 1, Arrays.asList(insn));
   }
 
   private void addMethodsToHeaderJar(
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index a48fb5c..7c7824d 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -149,6 +149,7 @@
   private final List<CfTryCatch> tryCatchRanges;
   private final List<LocalVariableInfo> localVariables;
   private StackMapStatus stackMapStatus = StackMapStatus.NOT_VERIFIED;
+  private final com.android.tools.r8.position.Position diagnosticPosition;
 
   public CfCode(
       DexType originalHolder, int maxStack, int maxLocals, List<CfInstruction> instructions) {
@@ -168,12 +169,31 @@
       List<CfInstruction> instructions,
       List<CfTryCatch> tryCatchRanges,
       List<LocalVariableInfo> localVariables) {
+    this(
+        originalHolder,
+        maxStack,
+        maxLocals,
+        instructions,
+        tryCatchRanges,
+        localVariables,
+        com.android.tools.r8.position.Position.UNKNOWN);
+  }
+
+  public CfCode(
+      DexType originalHolder,
+      int maxStack,
+      int maxLocals,
+      List<CfInstruction> instructions,
+      List<CfTryCatch> tryCatchRanges,
+      List<LocalVariableInfo> localVariables,
+      com.android.tools.r8.position.Position diagnosticPosition) {
     this.originalHolder = originalHolder;
     this.maxStack = maxStack;
     this.maxLocals = maxLocals;
     this.instructions = instructions;
     this.tryCatchRanges = tryCatchRanges;
     this.localVariables = localVariables;
+    this.diagnosticPosition = diagnosticPosition;
   }
 
   @Override
@@ -208,6 +228,10 @@
     return stackMapStatus;
   }
 
+  public com.android.tools.r8.position.Position getDiagnosticPosition() {
+    return diagnosticPosition;
+  }
+
   public void setMaxLocals(int newMaxLocals) {
     maxLocals = newMaxLocals;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 7fab178..289f255 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -65,7 +65,6 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.ConsumerUtils;
@@ -82,7 +81,6 @@
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.function.BiConsumer;
@@ -963,9 +961,7 @@
         getReference().holder,
         1 + BooleanUtils.intValue(negate),
         getReference().getArity() + 1,
-        Arrays.asList(instructions),
-        Collections.emptyList(),
-        Collections.emptyList());
+        Arrays.asList(instructions));
   }
 
   public DexCode buildInstanceOfDexCode(DexType type, boolean negate) {
@@ -1083,13 +1079,7 @@
         .add(new CfConstString(message))
         .add(new CfInvoke(Opcodes.INVOKESPECIAL, exceptionInitMethod, false))
         .add(new CfThrow());
-    return new CfCode(
-        getReference().holder,
-        3,
-        locals,
-        instructionBuilder.build(),
-        Collections.emptyList(),
-        Collections.emptyList());
+    return new CfCode(getReference().holder, 3, locals, instructionBuilder.build());
   }
 
   public DexEncodedMethod toTypeSubstitutedMethod(DexMethod method) {
@@ -1246,10 +1236,6 @@
     return code == null ? "<no code>" : code.toString(this, null);
   }
 
-  public MethodPosition getPosition() {
-    return new MethodPosition(getReference().asMethodReference());
-  }
-
   @Override
   public boolean isDexEncodedMethod() {
     checkIfObsolete();
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index 2403804..ae16c5a 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -62,6 +62,8 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.MethodPosition;
+import com.android.tools.r8.position.TextPosition;
+import com.android.tools.r8.position.TextRange;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.ExceptionUtils;
@@ -368,6 +370,8 @@
     private final LazyCfCode code;
     private final DexMethod method;
     private final Origin origin;
+    private int minLine = Integer.MAX_VALUE;
+    private int maxLine = -1;
 
     MethodCodeVisitor(
         JarApplicationReader application,
@@ -406,7 +410,7 @@
         throw new CompilationError(
             "Absent Code attribute in method that is not native or abstract",
             origin,
-            new MethodPosition(method.asMethodReference()));
+            MethodPosition.create(method.asMethodReference(), getDiagnosticPosition()));
       }
       code.setCode(
           new CfCode(
@@ -415,7 +419,20 @@
               maxLocals,
               instructions,
               tryCatchRanges,
-              localVariables));
+              localVariables,
+              getDiagnosticPosition()));
+    }
+
+    private com.android.tools.r8.position.Position getDiagnosticPosition() {
+      if (minLine == Integer.MAX_VALUE) {
+        return com.android.tools.r8.position.Position.UNKNOWN;
+      } else if (minLine == maxLine) {
+        return new TextPosition(0, minLine, TextPosition.UNKNOWN_COLUMN);
+      } else {
+        return new TextRange(
+            new TextPosition(0, minLine, TextPosition.UNKNOWN_COLUMN),
+            new TextPosition(0, maxLine, TextPosition.UNKNOWN_COLUMN));
+      }
     }
 
     @Override
@@ -1015,6 +1032,8 @@
 
     @Override
     public void visitLineNumber(int line, Label start) {
+      minLine = Math.min(line, minLine);
+      maxLine = Math.max(line, maxLine);
       if (debugParsingOptions.lineInfo) {
         instructions.add(
             new CfPosition(
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index cf866d4..9bd0c4a 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /** Type representing a method definition in the programs compilation unit and its holder. */
@@ -171,8 +170,4 @@
   public KotlinMethodLevelInfo getKotlinInfo() {
     return getDefinition().getKotlinInfo();
   }
-
-  public MethodPosition getPosition() {
-    return getDefinition().getPosition();
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index b1219c4..bb8f046 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -42,7 +42,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Set;
@@ -136,12 +135,7 @@
           SyntheticPosition.builder().setLine(0).setMethod(syntheticMethodReference).build();
       List<CfInstruction> instructions = buildInstructions(callerPosition);
       return new CfCode(
-          syntheticMethodReference.getHolderType(),
-          maxStack,
-          maxLocals,
-          instructions,
-          Collections.emptyList(),
-          Collections.emptyList());
+          syntheticMethodReference.getHolderType(), maxStack, maxLocals, instructions);
     }
 
     private List<CfInstruction> buildInstructions(Position callerPosition) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index b358828..34142c2 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -371,13 +371,19 @@
         localVariablesTable.add(info);
       }
     }
+    com.android.tools.r8.position.Position diagnosticPosition =
+        com.android.tools.r8.position.Position.UNKNOWN;
+    if (method.getCode().isCfCode()) {
+      diagnosticPosition = method.getCode().asCfCode().getDiagnosticPosition();
+    }
     return new CfCode(
         method.getHolderType(),
         stackHeightTracker.maxHeight,
         registerAllocator.registersUsed(),
         instructions,
         tryCatchRanges,
-        localVariablesTable);
+        localVariablesTable,
+        diagnosticPosition);
   }
 
   private static boolean isNopInstruction(Instruction instruction, BasicBlock nextBlock) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
index b0abf2a..ddcb68d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
@@ -30,8 +30,6 @@
             new CfStackInstruction(Opcode.Dup),
             new CfInvoke(Opcodes.INVOKESPECIAL, lambda.constructor, false),
             new CfStaticFieldWrite(lambda.lambdaField, lambda.lambdaField),
-            new CfReturnVoid()),
-        ImmutableList.of(),
-        ImmutableList.of());
+            new CfReturnVoid()));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index a8d8b14..0c1aaf8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -31,6 +31,7 @@
 import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
 import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.twr.TwrInstructionDesugaring;
+import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.utils.IntBox;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.SetUtils;
@@ -167,7 +168,7 @@
               new StringDiagnostic(
                   "Unsupported attempt to desugar non-CF code",
                   method.getOrigin(),
-                  method.getPosition()));
+                  MethodPosition.create(method)));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
index ee175f9..cd385e8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
@@ -60,13 +60,7 @@
             false),
         new CfReturn(ValueType.OBJECT));
 
-    return new CfCode(
-        method.holder,
-        4,
-        formalCount,
-        builder.build(),
-        ImmutableList.of(),
-        ImmutableList.of());
+    return new CfCode(method.holder, 4, formalCount, builder.build());
   }
 
   public static CfCode generateMapOf(
@@ -111,12 +105,6 @@
             false),
         new CfReturn(ValueType.OBJECT));
 
-    return new CfCode(
-        method.holder,
-        7,
-        formalCount * 2,
-        builder.build(),
-        ImmutableList.of(),
-        ImmutableList.of());
+    return new CfCode(method.holder, 7, formalCount * 2, builder.build());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index a4800c3..616cc07 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -481,9 +481,7 @@
                     ImmutableList.of(
                         new CfInitClass(iface.getType()),
                         new CfStackInstruction(Opcode.Pop),
-                        new CfReturnVoid()),
-                    ImmutableList.of(),
-                    ImmutableList.of());
+                        new CfReturnVoid()));
               }
               DexEncodedField clinitField =
                   ensureStaticClinitFieldToTriggerInterfaceInitialization(iface);
@@ -497,9 +495,7 @@
                       isWide
                           ? new CfStackInstruction(Opcode.Pop2)
                           : new CfStackInstruction(Opcode.Pop),
-                      new CfReturnVoid()),
-                  ImmutableList.of(),
-                  ImmutableList.of());
+                      new CfReturnVoid()));
             });
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
index 182b415..096c2cf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -40,7 +40,6 @@
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import org.objectweb.asm.Opcodes;
@@ -271,13 +270,7 @@
 
       int maxStack = 4;
       int maxLocals = 0;
-      return new CfCode(
-          sharedUtilityClassType,
-          maxStack,
-          maxLocals,
-          instructions,
-          Collections.emptyList(),
-          Collections.emptyList());
+      return new CfCode(sharedUtilityClassType, maxStack, maxLocals, instructions);
     }
 
     private DexEncodedMethod createValuesMethod(
@@ -325,9 +318,7 @@
                   Opcodes.INVOKESTATIC, dexItemFactory.javaLangSystemMethods.arraycopy, false),
               // return result
               new CfLoad(ValueType.OBJECT, resultLocalSlot),
-              new CfReturn(ValueType.OBJECT)),
-          Collections.emptyList(),
-          Collections.emptyList());
+              new CfReturn(ValueType.OBJECT)));
     }
 
     private static DexProgramClass findDeterministicContextType(Set<DexProgramClass> contexts) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticCfCodeProvider.java
index 05f88a1..8e166d1 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticCfCodeProvider.java
@@ -5,11 +5,9 @@
 package com.android.tools.r8.ir.synthetic;
 
 import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.cf.code.CfTryCatch;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexType;
-import com.google.common.collect.ImmutableList;
 import java.util.List;
 
 public abstract class SyntheticCfCodeProvider {
@@ -29,13 +27,7 @@
   public abstract CfCode generateCfCode();
 
   protected CfCode standardCfCodeFromInstructions(List<CfInstruction> instructions) {
-    return new CfCode(
-        holder,
-        defaultMaxStack(),
-        defaultMaxLocals(),
-        instructions,
-        defaultTryCatchs(),
-        ImmutableList.of());
+    return new CfCode(holder, defaultMaxStack(), defaultMaxLocals(), instructions);
   }
 
   protected int defaultMaxStack() {
@@ -45,8 +37,4 @@
   protected int defaultMaxLocals() {
     return 16;
   }
-
-  protected List<CfTryCatch> defaultTryCatchs() {
-    return ImmutableList.of();
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/position/MethodPosition.java b/src/main/java/com/android/tools/r8/position/MethodPosition.java
index fa86ac8..12a7d8d 100644
--- a/src/main/java/com/android/tools/r8/position/MethodPosition.java
+++ b/src/main/java/com/android/tools/r8/position/MethodPosition.java
@@ -4,7 +4,9 @@
 package com.android.tools.r8.position;
 
 import com.android.tools.r8.Keep;
+import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.TypeReference;
 import java.util.List;
@@ -15,14 +17,41 @@
 public class MethodPosition implements Position {
 
   private final MethodReference method;
+  private final Position textPosition;
 
   @Deprecated
   public MethodPosition(DexMethod method) {
     this(method.asMethodReference());
   }
 
+  @Deprecated
   public MethodPosition(MethodReference method) {
+    this(method, Position.UNKNOWN);
+  }
+
+  private MethodPosition(MethodReference method, Position textPosition) {
     this.method = method;
+    this.textPosition = textPosition;
+  }
+
+  public static MethodPosition create(ProgramMethod method) {
+    return create(method.getDefinition());
+  }
+
+  public static MethodPosition create(DexEncodedMethod method) {
+    Position position = UNKNOWN;
+    if (method.hasCode() && method.getCode().isCfCode()) {
+      position = method.getCode().asCfCode().getDiagnosticPosition();
+    }
+    return create(method.getReference().asMethodReference(), position);
+  }
+
+  public static MethodPosition create(MethodReference method) {
+    return new MethodPosition(method, Position.UNKNOWN);
+  }
+
+  public static MethodPosition create(MethodReference method, Position position) {
+    return new MethodPosition(method, position);
   }
 
   /** The method */
@@ -51,6 +80,10 @@
         .collect(Collectors.toList());
   }
 
+  public Position getTextPosition() {
+    return textPosition;
+  }
+
   @Override
   public String toString() {
     return method.toString();