Merge "Fixed array bug for proguard keep file generation" am: d98baeca50 am: 5ba4db04eb
am: 15c6aa1023

Change-Id: Ic53ea8c705a67cec8b9d880efdb07ae247ecb176
diff --git a/src/main/java/com/android/tools/metalava/ProguardWriter.kt b/src/main/java/com/android/tools/metalava/ProguardWriter.kt
index 5ff6612..54e45e5 100644
--- a/src/main/java/com/android/tools/metalava/ProguardWriter.kt
+++ b/src/main/java/com/android/tools/metalava/ProguardWriter.kt
@@ -127,7 +127,12 @@
 
     private fun getCleanTypeName(t: TypeItem?): String {
         t ?: return ""
-        val cls = t.asClass() ?: return t.toSimpleType()
-        return cls.qualifiedNameWithDollarInnerClasses()
+        val cls = t.asClass() ?: return t.toCanonicalType()
+        var qualifiedName = cls.qualifiedNameWithDollarInnerClasses()
+
+        for (i in 0 until t.arrayDimensions()) {
+            qualifiedName += "[]"
+        }
+        return qualifiedName
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
index d879463..32c55f3 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
@@ -569,7 +569,11 @@
             val cls = psiType.resolve() ?: return null
             return findOrCreateClass(cls)
         } else if (psiType is PsiArrayType) {
-            val componentType = psiType.componentType
+            var componentType = psiType.componentType
+            // We repeatedly get the component type because the array may have multiple dimensions
+            while (componentType is PsiArrayType) {
+                componentType = componentType.componentType
+            }
             if (componentType is PsiClassType) {
                 val cls = componentType.resolve() ?: return null
                 return findOrCreateClass(cls)
diff --git a/src/test/java/com/android/tools/metalava/KeepFileTest.kt b/src/test/java/com/android/tools/metalava/KeepFileTest.kt
index 960d825..e35a9f8 100644
--- a/src/test/java/com/android/tools/metalava/KeepFileTest.kt
+++ b/src/test/java/com/android/tools/metalava/KeepFileTest.kt
@@ -82,4 +82,279 @@
             extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
         )
     }
+
+    @Test
+    fun `Primitive types`() {
+        check(
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClass {
+                        public int testMethodA(int a) {}
+                        public boolean testMethodB(boolean a) {}
+                        public float testMethodC(float a) {}
+                        public double testMethodD(double a) {}
+                        public byte testMethodE(byte a) {}
+                    }
+                    """
+                )
+            ),
+            proguard = """
+                -keep class test.pkg.MyClass {
+                    <init>();
+                    public int testMethodA(int);
+                    public boolean testMethodB(boolean);
+                    public float testMethodC(float);
+                    public double testMethodD(double);
+                    public byte testMethodE(byte);
+                }
+                """,
+            extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
+        )
+    }
+
+    @Test
+    fun `Primitive array types`() {
+        check(
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClass {
+                        public int[] testMethodA(int[] a) {}
+                        public float[][] testMethodB(float[][] a) {}
+                        public double[][][] testMethodC(double[][][] a) {}
+                        public byte testMethodD(byte... a) {}
+                    }
+                    """
+                )
+            ),
+            proguard = """
+                -keep class test.pkg.MyClass {
+                    <init>();
+                    public int[] testMethodA(int[]);
+                    public float[][] testMethodB(float[][]);
+                    public double[][][] testMethodC(double[][][]);
+                    public byte testMethodD(byte[]);
+                }
+                """,
+            extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
+        )
+    }
+
+    @Test
+    fun `Object Array parameters`() {
+        check(
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClass {
+                        public void testMethodA(String a) {}
+                        public void testMethodB(Boolean[] a) {}
+                        public void testMethodC(Integer... a) {}
+                    }
+                    """
+                )
+            ),
+            proguard = """
+                -keep class test.pkg.MyClass {
+                    <init>();
+                    public void testMethodA(java.lang.String);
+                    public void testMethodB(java.lang.Boolean[]);
+                    public void testMethodC(java.lang.Integer[]);
+                }
+                """,
+            extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
+        )
+    }
+
+    @Test
+    fun `Arrays with Inner class`() {
+        check(
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClass {
+                        public void testMethodA(InnerClass a) {}
+                        public void testMethodB(InnerClass[] a) {}
+                        public void testMethodC(InnerClass... a) {}
+                        public class InnerClass {}
+                    }
+                    """
+                )
+            ),
+            proguard = """
+                -keep class test.pkg.MyClass {
+                    <init>();
+                    public void testMethodA(test.pkg.MyClass${"$"}InnerClass);
+                    public void testMethodB(test.pkg.MyClass${"$"}InnerClass[]);
+                    public void testMethodC(test.pkg.MyClass${"$"}InnerClass[]);
+                }
+                -keep class test.pkg.MyClass${"$"}InnerClass {
+                    <init>();
+                }
+                """,
+            extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
+        )
+    }
+
+    @Test
+    fun `Conflicting Class Names in parameters`() {
+        check(
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class String {}
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClass {
+                        public void testMethodA(String a, String b) {}
+                        public void testMethodB(String a, test.pkg.String b) {}
+                        public void testMethodC(String a, java.lang.String b) {}
+                        public void testMethodD(java.lang.String a, test.pkg.String b) {}
+                    }
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClassArrays {
+                        public void testMethodA(String[] a, String[] b) {}
+                        public void testMethodB(String[] a, test.pkg.String[] b) {}
+                        public void testMethodC(String[] a, java.lang.String[] b) {}
+                        public void testMethodD(java.lang.String... a, test.pkg.String... b) {}
+                    }
+                    """
+                )
+            ),
+            proguard = """
+                -keep class test.pkg.MyClass {
+                    <init>();
+                    public void testMethodA(test.pkg.String, test.pkg.String);
+                    public void testMethodB(test.pkg.String, test.pkg.String);
+                    public void testMethodC(test.pkg.String, java.lang.String);
+                    public void testMethodD(java.lang.String, test.pkg.String);
+                }
+                -keep class test.pkg.MyClassArrays {
+                    <init>();
+                    public void testMethodA(test.pkg.String[], test.pkg.String[]);
+                    public void testMethodB(test.pkg.String[], test.pkg.String[]);
+                    public void testMethodC(test.pkg.String[], java.lang.String[]);
+                    public void testMethodD(java.lang.String[], test.pkg.String[]);
+                }
+                -keep class test.pkg.String {
+                    <init>();
+                }
+                """,
+            extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
+        )
+    }
+
+    @Test
+    fun `Multi dimensional arrays`() {
+        check(
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class String {}
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClassArrays {
+                        public void testMethodA(String[][] a, String[][] b) {}
+                        public void testMethodB(String[][][] a, test.pkg.String[][][] b) {}
+                        public void testMethodC(String[][] a, java.lang.String[][] b) {}
+                        public class InnerClass {}
+                        public void testMethodD(InnerClass[][] a) {}
+                    }
+                    """
+                )
+            ),
+            proguard = """
+                -keep class test.pkg.MyClassArrays {
+                    <init>();
+                    public void testMethodA(test.pkg.String[][], test.pkg.String[][]);
+                    public void testMethodB(test.pkg.String[][][], test.pkg.String[][][]);
+                    public void testMethodC(test.pkg.String[][], java.lang.String[][]);
+                    public void testMethodD(test.pkg.MyClassArrays${"$"}InnerClass[][]);
+                }
+                -keep class test.pkg.MyClassArrays${"$"}InnerClass {
+                    <init>();
+                }
+                -keep class test.pkg.String {
+                    <init>();
+                }
+                """,
+            extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
+        )
+    }
+
+    @Test
+    fun `Methods with arrays as the return type`() {
+        check(
+            checkDoclava1 = true,
+            sourceFiles = *arrayOf(
+                java(
+                    """
+                    package test.pkg;
+                    public class MyClass {
+                        public String[] testMethodA() {}
+                        public String[][] testMethodB() {}
+                        public String[][][] testMethodC() {}
+                    }
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg;
+                    public class MyOtherClass {
+                        public java.lang.String[] testMethodA() {}
+                        public String[][] testMethodB() {}
+                        public test.pkg.String[][][] testMethodC() {}
+                    }
+                    """
+                ),
+                java(
+                    """
+                    package test.pkg;
+                    public class String {}
+                    """
+                )
+            ),
+            proguard = """
+                -keep class test.pkg.MyClass {
+                    <init>();
+                    public test.pkg.String[] testMethodA();
+                    public test.pkg.String[][] testMethodB();
+                    public test.pkg.String[][][] testMethodC();
+                }
+                -keep class test.pkg.MyOtherClass {
+                    <init>();
+                    public java.lang.String[] testMethodA();
+                    public test.pkg.String[][] testMethodB();
+                    public test.pkg.String[][][] testMethodC();
+                }
+                -keep class test.pkg.String {
+                    <init>();
+                }
+                """,
+            extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword")
+        )
+    }
 }
\ No newline at end of file