Add InnerClass attributes for enclosing declarations first

The integration tests normalize attribute order, so this wasn't showing
up.  javac's class reader expects InnerClass attributes for enclosing
declarations to appear before their members, the previous ordering as
causing it to resolve the binary names of any enclosing declarations
that were themselves inner classes (e.g. `Outer$Inner.InnerMost`).

MOE_MIGRATED_REVID=136541546
diff --git a/java/com/google/turbine/lower/Lower.java b/java/com/google/turbine/lower/Lower.java
index ef6cdf7..40fcee6 100644
--- a/java/com/google/turbine/lower/Lower.java
+++ b/java/com/google/turbine/lower/Lower.java
@@ -222,13 +222,19 @@
     return inners.build();
   }
 
+  /**
+   * Record all enclosing declarations of a symbol, to make sure the necessary InnerClass attributes
+   * are added.
+   *
+   * <p>javac expects InnerClass attributes for enclosing classes to appear before their member
+   * classes' entries.
+   */
   private void addEnclosing(
       Env<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> all, ClassSymbol sym) {
-    TypeBoundClass innerinfo = env.get(sym);
-    while (innerinfo.owner() != null) {
+    ClassSymbol owner = env.get(sym).owner();
+    if (owner != null) {
+      addEnclosing(env, all, owner);
       all.add(sym);
-      sym = innerinfo.owner();
-      innerinfo = env.get(sym);
     }
   }
 
diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java
index 74e87df..744128c 100644
--- a/javatests/com/google/turbine/lower/LowerTest.java
+++ b/javatests/com/google/turbine/lower/LowerTest.java
@@ -19,9 +19,12 @@
 import static com.google.common.truth.Truth.assertThat;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.io.ByteStreams;
+import com.google.turbine.binder.Binder;
+import com.google.turbine.binder.Binder.BindingResult;
 import com.google.turbine.binder.ClassPathBinder;
 import com.google.turbine.binder.bound.SourceTypeBoundClass;
 import com.google.turbine.binder.bytecode.BytecodeBoundClass;
@@ -36,13 +39,19 @@
 import com.google.turbine.model.TurbineConstantTypeKind;
 import com.google.turbine.model.TurbineFlag;
 import com.google.turbine.model.TurbineTyKind;
+import com.google.turbine.parse.Parser;
 import com.google.turbine.type.Type;
+import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
 
 @RunWith(JUnit4.class)
 public class LowerTest {
@@ -197,4 +206,36 @@
                     LowerTest.class.getResourceAsStream("testdata/golden/inner.txt")),
                 UTF_8));
   }
+
+  @Test
+  public void innerClassAttributeOrder() throws IOException {
+    BindingResult bound =
+        Binder.bind(
+            ImmutableList.of(
+                Parser.parse(
+                    Joiner.on('\n')
+                        .join(
+                            "class Test {", //
+                            "  class Inner {",
+                            "    class InnerMost {}",
+                            "  }",
+                            "}"))),
+            ImmutableList.of(),
+            BOOTCLASSPATH);
+    Map<String, byte[]> lowered = Lower.lowerAll(bound.units(), bound.classPathEnv());
+    List<String> attributes = new ArrayList<>();
+    new org.objectweb.asm.ClassReader(lowered.get("Test$Inner$InnerMost"))
+        .accept(
+            new ClassVisitor(Opcodes.ASM5) {
+              @Override
+              public void visitInnerClass(
+                  String name, String outerName, String innerName, int access) {
+                attributes.add(String.format("%s %s %s", name, outerName, innerName));
+              }
+            },
+            0);
+    assertThat(attributes)
+        .containsExactly("Test$Inner Test Inner", "Test$Inner$InnerMost Test$Inner InnerMost")
+        .inOrder();
+  }
 }