Fix tree pruning bug with constructor delegation

-relax disables checks in Resolve to catch constructors that do not explicitly
delegate to a superclass constructor when no nullary superclass constructor
exists. Now that we're not using -relax, those constructor calls have to be
preserved.

--
MOS_MIGRATED_REVID=114875860
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/java/turbine/javac/TreePruner.java b/src/java_tools/buildjar/java/com/google/devtools/build/java/turbine/javac/TreePruner.java
index da74844..092b82b 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/java/turbine/javac/TreePruner.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/java/turbine/javac/TreePruner.java
@@ -22,16 +22,23 @@
 import com.sun.source.tree.LiteralTree;
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.ParenthesizedTree;
+import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.TypeCastTree;
 import com.sun.source.tree.UnaryTree;
 import com.sun.source.util.SimpleTreeVisitor;
 import com.sun.tools.javac.code.Flags;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.tree.TreeScanner;
 import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
 
 /**
  * Prunes AST nodes that are not required for header compilation.
@@ -65,6 +72,12 @@
           if (tree.body == null) {
             return;
           }
+          if (tree.getReturnType() == null && delegatingConstructor(tree.body.stats)) {
+            // if the first statement of a constructor declaration delegates to another
+            // constructor, it needs to be preserved to satisfy checks in Resolve
+            tree.body.stats = com.sun.tools.javac.util.List.of(tree.body.stats.get(0));
+            return;
+          }
           tree.body.stats = com.sun.tools.javac.util.List.nil();
         }
 
@@ -87,6 +100,26 @@
         }
       };
 
+  private static boolean delegatingConstructor(List<JCStatement> stats) {
+    if (stats.isEmpty()) {
+      return false;
+    }
+    JCStatement stat = stats.get(0);
+    if (stat.getKind() != Kind.EXPRESSION_STATEMENT) {
+      return false;
+    }
+    JCExpression expr = ((JCExpressionStatement) stat).getExpression();
+    if (expr.getKind() != Kind.METHOD_INVOCATION) {
+      return false;
+    }
+    JCExpression select = ((JCMethodInvocation) expr).getMethodSelect();
+    if (select.getKind() != Kind.IDENTIFIER) {
+      return false;
+    }
+    Name name = ((JCIdent) select).getName();
+    return name.contentEquals("this") || name.contentEquals("super");
+  }
+
   private static boolean isConstantVariable(JCVariableDecl tree) {
     if ((tree.mods.flags & Flags.FINAL) != Flags.FINAL) {
       return false;
diff --git a/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java b/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java
index f80dec4..c01f5d0 100644
--- a/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java
+++ b/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java
@@ -829,4 +829,36 @@
       assertThat(sw.toString()).contains("error reading");
     }
   }
+  
+  @Test
+  public void requiredConstructor() throws Exception {
+    addSourceLines("Super.java", "class Super {", "  public Super(int x) {}", "}");
+    addSourceLines(
+        "Hello.java",
+        "class Hello extends Super {",
+        "  public Hello() {",
+        "    super(42);",
+        "  }",
+        "}");
+
+    compile();
+
+    Map<String, byte[]> outputs = collectOutputs();
+
+    assertThat(outputs.keySet()).containsExactly("Super.class", "Hello.class");
+
+    String text = textify(outputs.get("Hello.class"));
+    String[] expected = {
+      "// class version 51.0 (51)",
+      "// access flags 0x20",
+      "class Hello extends Super  {",
+      "",
+      "",
+      "  // access flags 0x1",
+      "  public <init>()V",
+      "}",
+      ""
+    };
+    assertThat(text).isEqualTo(Joiner.on('\n').join(expected));
+  }
 }
diff --git a/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/TreePrunerTest.java b/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/TreePrunerTest.java
index 4455437..711b5524 100644
--- a/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/TreePrunerTest.java
+++ b/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/TreePrunerTest.java
@@ -220,6 +220,47 @@
     assertThat(printPruned("final int x = new X().y;")).isEqualTo("final int x");
   }
 
+  @Test
+  public void constructorChaining() {
+    String[] lines = {
+      "class Test {",
+      "  Test() {",
+      "    this(42);",
+      "    process();",
+      "  }",
+      "  Test() {",
+      "    this(42);",
+      "  }",
+      "  Test() {",
+      "    super(42);",
+      "  }",
+      "  Test() {}",
+      "}",
+    };
+    JCCompilationUnit tree = parseLines(lines);
+    TreePruner.prune(tree);
+    String[] expected = {
+      "class Test {",
+      "    ",
+      "    Test() {",
+      "        this(42);",
+      "    }",
+      "    ",
+      "    Test() {",
+      "        this(42);",
+      "    }",
+      "    ",
+      "    Test() {",
+      "        super(42);",
+      "    }",
+      "    ",
+      "    Test() {",
+      "    }",
+      "}",
+    };
+    assertThat(prettyPrint(tree)).isEqualTo(Joiner.on('\n').join(expected));
+  }
+
   private String prettyPrint(JCCompilationUnit tree) {
     return tree.toString().trim();
   }