Fix inliner to make inlining test pass.

This does not address the issue with inlining constructors on
Dalvik 4.4.4, yet.

Bug: 65355452
Change-Id: I548b4e49df1f67c833545905f500891edfc07624
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 e7f3f70..84d581d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -123,23 +123,34 @@
     return accessFlags.isConstructor() && accessFlags.isStatic();
   }
 
+  /**
+   * Returns true if this method can be invoked via invoke-virtual, invoke-super or
+   * invoke-interface.
+   */
   public boolean isVirtualMethod() {
     return !accessFlags.isStatic() && !accessFlags.isPrivate() && !accessFlags.isConstructor();
   }
 
+  /**
+   * Returns true if this method can be invoked via invoke-virtual, invoke-super or invoke-interface
+   * and is non-abstract.
+   */
   public boolean isNonAbstractVirtualMethod() {
-    return !accessFlags.isStatic()
-        && !accessFlags.isPrivate()
-        && !accessFlags.isConstructor()
-        && !accessFlags.isAbstract();
+    return isVirtualMethod() && !accessFlags.isAbstract();
   }
 
+  /**
+   * Returns true if this method can be invoked via invoke-direct.
+   */
   public boolean isDirectMethod() {
-    return accessFlags.isPrivate() && !accessFlags.isStatic();
+    return (accessFlags.isPrivate() || accessFlags.isConstructor()) && !accessFlags.isStatic();
   }
 
+  /**
+   * Returns true if this method can be invoked via invoke-static.
+   */
   public boolean isStaticMethod() {
-    return accessFlags.isStatic() || accessFlags.isConstructor();
+    return accessFlags.isStatic();
   }
 
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 12040e1..0c081c5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -107,7 +107,7 @@
         // We also have to take the constraint of the enclosing class into account.
         Constraint classConstraint = Constraint
             .deriveConstraint(holder, methodHolder, methodClass.accessFlags, info);
-        result = Constraint.min(methodConstraint, classConstraint);
+        result = Constraint.min(result, classConstraint);
       }
       if (result == Constraint.NEVER) {
         break;
diff --git a/src/test/examples/inlining/A.java b/src/test/examples/inlining/A.java
new file mode 100644
index 0000000..dd857c8
--- /dev/null
+++ b/src/test/examples/inlining/A.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2017, 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 inlining;
+
+class A {
+
+  int a;
+
+  A(int a) {
+    this.a = a;
+  }
+
+  int a() {
+    return a;
+  }
+
+  int cannotInline(int v) {
+    // Cannot inline due to recursion.
+    if (v > 0) {
+      return cannotInline(v - 1);
+    }
+    return 42;
+  }
+}
diff --git a/src/test/examples/inlining/B.java b/src/test/examples/inlining/B.java
new file mode 100644
index 0000000..0628187
--- /dev/null
+++ b/src/test/examples/inlining/B.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2017, 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 inlining;
+
+class B extends A {
+
+  B(int a) {
+    super(a);
+  }
+
+  int cannotInline(int v) {
+    return -1;
+  }
+
+  int callMethodInSuper() {
+    return super.cannotInline(10);
+  }
+}
diff --git a/src/test/examples/inlining/InlineConstructor.java b/src/test/examples/inlining/InlineConstructor.java
new file mode 100644
index 0000000..382d0c7
--- /dev/null
+++ b/src/test/examples/inlining/InlineConstructor.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2017, 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 inlining;
+
+class InlineConstructor {
+
+  int a;
+
+  @CheckDiscarded
+  InlineConstructor(int a) {
+    this.a = a;
+  }
+
+  InlineConstructor(long a) {
+    this((int) a);
+  }
+
+  InlineConstructor(int a, int loopy) {
+    this.a = a;
+    // Make this too big to inline.
+    if (loopy > 10) {
+      throw new RuntimeException("Too big!");
+    }
+    for (int i = 1; i < loopy; i++) {
+      this.a = this.a * i;
+    }
+  }
+
+  // TODO(b/65355452): This should be inlined.
+  // @CheckDiscarded
+  InlineConstructor() {
+    this(42, 9);
+  }
+
+  static InlineConstructor create() {
+    return new InlineConstructor(10L);
+  }
+
+  static InlineConstructor createMore() {
+    new InlineConstructor(0, 0);
+    new InlineConstructor(0, 0);
+    new InlineConstructor(0, 0);
+    new InlineConstructor(0, 0);
+    new InlineConstructor(0, 0);
+    new InlineConstructor(0, 0);
+    return new InlineConstructor();
+  }
+}
diff --git a/src/test/examples/inlining/InlineConstructorOfInner.java b/src/test/examples/inlining/InlineConstructorOfInner.java
new file mode 100644
index 0000000..cec7d3f
--- /dev/null
+++ b/src/test/examples/inlining/InlineConstructorOfInner.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2017, 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 inlining;
+
+class InlineConstructorOfInner {
+
+  class Inner {
+
+    int a;
+
+    @CheckDiscarded
+    Inner(int a) {
+      this.a = a;
+    }
+
+    // This is not inlined, even though it is only called once, as it is only called from a
+    // non-constructor, and will set a field (the outer object) before calling the other
+    // constructor.
+    Inner(long a) {
+      this((int) a);
+    }
+
+    public Inner create() {
+      return new Inner(10L);
+    }
+  }
+
+  Inner inner;
+
+  InlineConstructorOfInner() {
+    inner = new Inner(10L).create();
+  }
+}
diff --git a/src/test/examples/inlining/Inlining.java b/src/test/examples/inlining/Inlining.java
index 02a4b7c..c72812c 100644
--- a/src/test/examples/inlining/Inlining.java
+++ b/src/test/examples/inlining/Inlining.java
@@ -7,116 +7,6 @@
 import inlining.pkg.PublicClass;
 import inlining.pkg.Subclass;
 
-class A {
-
-  int a;
-
-  A(int a) {
-    this.a = a;
-  }
-
-  int a() {
-    return a;
-  }
-
-  int cannotInline(int v) {
-    // Cannot inline due to recursion.
-    if (v > 0) {
-      return cannotInline(v - 1);
-    }
-    return 42;
-  }
-}
-
-class B extends A {
-
-  B(int a) {
-    super(a);
-  }
-
-  int cannotInline(int v) {
-    return -1;
-  }
-
-  int callMethodInSuper() {
-    return super.cannotInline(10);
-  }
-}
-
-class InlineConstructor {
-
-  int a;
-
-  @CheckDiscarded
-  InlineConstructor(int a) {
-    this.a = a;
-  }
-
-  InlineConstructor(long a) {
-    this((int) a);
-  }
-
-  InlineConstructor(int a, int loopy) {
-    this.a = a;
-    // Make this too big to inline.
-    if (loopy > 10) {
-      throw new RuntimeException("Too big!");
-    }
-    for (int i = 1; i < loopy; i++) {
-      this.a = this.a * i;
-    }
-  }
-
-  @CheckDiscarded
-  InlineConstructor() {
-    this(42, 9);
-  }
-
-  static InlineConstructor create() {
-    return new InlineConstructor(10L);
-  }
-
-  static InlineConstructor createMore() {
-    new InlineConstructor(0, 0);
-    new InlineConstructor(0, 0);
-    new InlineConstructor(0, 0);
-    new InlineConstructor(0, 0);
-    new InlineConstructor(0, 0);
-    new InlineConstructor(0, 0);
-    return new InlineConstructor();
-  }
-}
-
-class InlineConstructorOfInner {
-
-  class Inner {
-
-    int a;
-
-    @CheckDiscarded
-    Inner(int a) {
-      this.a = a;
-    }
-
-    // This is not inlined, even though it is only called once, as it is only called from a
-    // non-constructor, and will set a field (the outer object) before calling the other
-    // constructor.
-    Inner(long a) {
-      this((int) a);
-    }
-
-    public Inner create() {
-      return new Inner(10L);
-    }
-  }
-
-  Inner inner;
-
-  InlineConstructorOfInner() {
-    inner = new Inner(10L).create();
-  }
-}
-
 public class Inlining {
 
   private static void Assert(boolean value) {
@@ -202,6 +92,10 @@
     aNumber += longMethodThatWeShouldNotInline("zi", "za", "zo");
     aNumber += longMethodThatWeShouldNotInline("do", "de", "da");
     System.out.println(aNumber);
+
+    // Call a method that contains a call to a protected method. Should not be inlined.
+    aNumber = new SubClassOfPublicClass().public_protectedMethod(0);
+    System.out.println(aNumber);
   }
 
   private static boolean intCmpExpression(A a, A b) {
diff --git a/src/test/examples/inlining/PublicClass.java b/src/test/examples/inlining/PublicClass.java
new file mode 100644
index 0000000..70219ff
--- /dev/null
+++ b/src/test/examples/inlining/PublicClass.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2017, 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 inlining;
+
+public class PublicClass {
+
+  protected int protectedMethod(int loopy) {
+    if (loopy > 0) {
+      return protectedMethod(loopy - 1);
+    }
+    return 42;
+  }
+}
diff --git a/src/test/examples/inlining/SubClassOfPublicClass.java b/src/test/examples/inlining/SubClassOfPublicClass.java
new file mode 100644
index 0000000..306ba53
--- /dev/null
+++ b/src/test/examples/inlining/SubClassOfPublicClass.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, 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 inlining;
+
+public class SubClassOfPublicClass extends PublicClass {
+
+  public int public_protectedMethod(int loopy) {
+    return protectedMethod(loopy);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
index 8dfcbfe..388e1fe 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -85,8 +85,7 @@
       "examplesAndroidN/shaking:keep-rules.txt:DEX:AGGRESSIVE"
   );
 
-  // TODO(65355452): Reenable or remove inlining tests.
-  private static Set<String> SKIPPED = ImmutableSet.of("examples/inlining");
+  private static Set<String> SKIPPED = Collections.emptySet();
 
   private final MinifyMode minify;
 
@@ -657,6 +656,7 @@
             "examples/annotationremoval",
             "examples/memberrebinding2",
             "examples/memberrebinding3",
+            "examples/inlining",
             "examples/simpleproto1",
             "examples/simpleproto2",
             "examples/simpleproto3",