implement list.insert for skylark rule

RELNOTES: implement list.insert for skylark rule

--
MOS_MIGRATED_REVID=119243427
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index 8a2901b..1535cd4 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -1263,19 +1263,45 @@
       };
 
   @SkylarkSignature(
+    name = "insert",
+    objectType = MutableList.class,
+    returnType = Runtime.NoneType.class,
+    doc = "Inserts an item at a given position.",
+    mandatoryPositionals = {
+      @Param(name = "self", type = MutableList.class, doc = "This list."),
+      @Param(name = "index", type = Integer.class, doc = "The index of the given position."),
+      @Param(name = "item", type = Object.class, doc = "The item.")
+    },
+    useLocation = true,
+    useEnvironment = true
+  )
+  private static final BuiltinFunction insert =
+      new BuiltinFunction("insert") {
+        public Runtime.NoneType invoke(
+            MutableList<Object> self, Integer index, Object item, Location loc, Environment env)
+            throws EvalException, ConversionException {
+          self.add(clampIndex(index, self.size()), item, loc, env);
+          return Runtime.NONE;
+        }
+      };
+
+  @SkylarkSignature(
     name = "extend",
     objectType = MutableList.class,
     returnType = Runtime.NoneType.class,
     doc = "Adds all items to the end of the list.",
     mandatoryPositionals = {
       @Param(name = "self", type = MutableList.class, doc = "This list."),
-      @Param(name = "items", type = SkylarkList.class, doc = "Items to add at the end.")},
+      @Param(name = "items", type = SkylarkList.class, doc = "Items to add at the end.")
+    },
     useLocation = true,
-    useEnvironment = true)
+    useEnvironment = true
+  )
   private static final BuiltinFunction extend =
       new BuiltinFunction("extend") {
-        public Runtime.NoneType invoke(MutableList<Object> self, SkylarkList<Object> items,
-            Location loc, Environment env) throws EvalException, ConversionException {
+        public Runtime.NoneType invoke(
+            MutableList<Object> self, SkylarkList<Object> items, Location loc, Environment env)
+            throws EvalException, ConversionException {
           self.addAll(items, loc, env);
           return Runtime.NONE;
         }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
index 102cd31..60d6754 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
@@ -353,6 +353,18 @@
       contents.add(element);
     }
 
+    /**
+     * Inserts an item at a given position to the MutableList.
+     * @param index the index of the given position
+     * @param element the element to add
+     * @param loc the Location at which to report any error
+     * @param env the Environment requesting the modification
+     */
+    public void add(int index, E element, Location loc, Environment env) throws EvalException {
+      checkMutable(loc, env);
+      contents.add(index, element);
+    }
+
     public void remove(int index, Location loc, Environment env) throws EvalException {
       checkMutable(loc, env);
       contents.remove(index);
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
index ec2d00f..9f1285c 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
@@ -1531,6 +1531,22 @@
   @Test
   public void testPyListAppend() throws Exception {
     new BuildTest()
+        .setUp("FOO = ['a', 'b']", "FOO.insert(0, 'c')")
+        .testLookup("FOO", MutableList.of(env, "c", "a", "b"))
+        .setUp("FOO.insert(1, 'd')")
+        .testLookup("FOO", MutableList.of(env, "c", "d", "a", "b"))
+        .setUp("FOO.insert(4, 'e')")
+        .testLookup("FOO", MutableList.of(env, "c", "d", "a", "b", "e"))
+        .setUp("FOO.insert(-10, 'f')")
+        .testLookup("FOO", MutableList.of(env, "f", "c", "d", "a", "b", "e"))
+        .setUp("FOO.insert(10, 'g')")
+        .testLookup("FOO", MutableList.of(env, "f", "c", "d", "a", "b", "e", "g"))
+        .testIfErrorContains("Type tuple has no function insert(int)", "(1, 2).insert(3)");
+  }
+
+  @Test
+  public void testPyListInsert() throws Exception {
+    new BuildTest()
         .setUp("FOO = ['a', 'b']", "FOO.append('c')")
         .testLookup("FOO", MutableList.of(env, "a", "b", "c"))
         .testIfErrorContains("Type tuple has no function append(int)", "(1, 2).append(3)");