Remove the usage of signatures in method specifications.

+ updated test9_003 which was not correctly written.
+ tests with regex that should not match anything.

Bug: 29263760

Change-Id: I26f0fa1070a1d9447a4c6c5f8b11623bee112c84
diff --git a/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java b/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
index f180081..7f6d639 100644
--- a/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
+++ b/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
@@ -267,6 +267,11 @@
     runTest("056", "001", "");
   }
 
+  @Test
+  public void test58_001() throws Exception {
+    runTest("058", "001", "");
+  }
+
   @Nonnull
   private static File shrobTestsDir =
       AbstractTestTools.getTestRootDir("com.android.jack.shrob");
diff --git a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags003 b/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags003
index fc2359a..e6ff9df 100644
--- a/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags003
+++ b/jack-tests/tests/com/android/jack/shrob/test009/proguard.flags003
@@ -1,3 +1,3 @@
 -keep class ** {
-  void m(int,...,long,...);
+  void m(int,...,long);
 }
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test058/info.txt b/jack-tests/tests/com/android/jack/shrob/test058/info.txt
new file mode 100644
index 0000000..3591acd
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test058/info.txt
@@ -0,0 +1,2 @@
+This test contains a class which contains an inner class and members using this
+inner class.
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test058/jack/MyClass.java b/jack-tests/tests/com/android/jack/shrob/test058/jack/MyClass.java
new file mode 100644
index 0000000..d6d7ddc
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test058/jack/MyClass.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.shrob.test058.jack;
+
+public class MyClass implements MyInterface {
+  public static final Inner<Object> field = null;
+
+  public Inner m(Inner t) {
+    return null;
+  }
+
+  public static class Inner <T> {
+
+  }
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/test058/jack/MyInterface.java b/jack-tests/tests/com/android/jack/shrob/test058/jack/MyInterface.java
new file mode 100644
index 0000000..38bc8d9
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test058/jack/MyInterface.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.shrob.test058.jack;
+
+public interface MyInterface {
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/test058/proguard.flags001 b/jack-tests/tests/com/android/jack/shrob/test058/proguard.flags001
new file mode 100644
index 0000000..d3092c4
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test058/proguard.flags001
@@ -0,0 +1,6 @@
+-keep, allowobfuscation class **.MyClass
+-keepclassmembers class * implements **.MyInterface {
+  public static final *.* field;
+  public *.* m(...);
+  public *** m(*.*);
+}
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test058/refsObfuscationWithoutMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test058/refsObfuscationWithoutMapping/expected-001.txt
new file mode 100644
index 0000000..8b4b00c
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test058/refsObfuscationWithoutMapping/expected-001.txt
@@ -0,0 +1,2 @@
+com.android.jack.shrob.test058.jack.MyClass -> pbz.naqebvq.wnpx.fuebo.grfg058.wnpx.ZlPynff:
+    void <init>() -> <init>
\ No newline at end of file
diff --git a/jack/src/com/android/jack/shrob/proguard/GrammarActions.java b/jack/src/com/android/jack/shrob/proguard/GrammarActions.java
index 6dc5205..3c917b8 100644
--- a/jack/src/com/android/jack/shrob/proguard/GrammarActions.java
+++ b/jack/src/com/android/jack/shrob/proguard/GrammarActions.java
@@ -79,10 +79,10 @@
       SourceFormatter.getFormatter();
 
   enum FilterSeparator {
-    GENERAL(".", "[^./]*"),
-    FILE(".", "[^/]*"),
-    CLASS("[^.]", "[^.]*"),
-    ATTRIBUTE(".", ".*");
+    GENERAL(".", "[^./]*", ".*"),
+    FILE(".", "[^/]*", ".*"),
+    CLASS("[^.]", "[^.]*", "[^\\[\\]]*"),
+    ATTRIBUTE(".", ".*", ".*");
 
     /**
      * Represents the pattern equivalent to Proguard's "?"
@@ -96,9 +96,17 @@
     @Nonnull
     private final String multipleCharWildcard;
 
-    FilterSeparator(@Nonnull String singleCharWilcard, @Nonnull String multipleCharWildcard) {
+    /**
+     * Represents the pattern equivalent to Proguard's "**"
+     */
+    @Nonnull
+    private final String multipleCharWildcardWithSeparator;
+
+    FilterSeparator(@Nonnull String singleCharWilcard, @Nonnull String multipleCharWildcard,
+        @Nonnull String multipleCharWildcardWithSeparator) {
       this.singleCharWilcard = singleCharWilcard;
       this.multipleCharWildcard = multipleCharWildcard;
+      this.multipleCharWildcardWithSeparator = multipleCharWildcardWithSeparator;
     }
   }
 
@@ -117,7 +125,6 @@
 
   @Nonnull
   public static String getSignature(@Nonnull String name) {
-    assert name != null;
     int lastOpeningBracketPos = name.lastIndexOf('[');
     if (lastOpeningBracketPos != -1) {
       String nameWithoutArray = name.substring(0, lastOpeningBracketPos);
@@ -149,16 +156,15 @@
     return sig.toString();
   }
 
+  private static final String PRIMITIVE_TYPE_NON_VOID =
+      "(boolean|byte|char|short|int|float|double|long)";
+
   @Nonnull
-  static String getSignatureRegex(@Nonnull String name, int dim) {
+  static String getSourceNamePattern(@Nonnull String name, int dim) {
     assert name != null;
 
     StringBuilder sig = new StringBuilder();
 
-    for (int i = 0; i < dim; i++) {
-      sig.append("\\[");
-    }
-
     // ... matches any number of arguments of any type
     if (name.equals("...")) {
       sig.append(".*");
@@ -167,28 +173,16 @@
       sig.append(".*");
       // % matches any primitive type ("boolean", "int", etc, but not "void")
     } else if (name.equals("%")) {
-      sig.append("(B|C|D|F|I|J|S|Z)");
-    } else if (name.equals("boolean")) {
-      sig.append('Z');
-    } else if (name.equals("byte")) {
-      sig.append('B');
-    } else if (name.equals("char")) {
-      sig.append('C');
-    } else if (name.equals("short")) {
-      sig.append('S');
-    } else if (name.equals("int")) {
-      sig.append('I');
-    } else if (name.equals("float")) {
-      sig.append('F');
-    } else if (name.equals("double")) {
-      sig.append('D');
-    } else if (name.equals("long")) {
-      sig.append('J');
-    } else if (name.equals("void")) {
-      sig.append('V');
+      sig.append(PRIMITIVE_TYPE_NON_VOID);
+    } else if (name.equals("**")) {
+      sig.append("[^\\[\\[]*(?<!" + PRIMITIVE_TYPE_NON_VOID + ")");
     } else {
       sig.append(
-          convertNameToRegex(NamingTools.getTypeSignatureName(name), FilterSeparator.CLASS));
+          convertNameToRegex(name, FilterSeparator.CLASS));
+    }
+
+    for (int i = 0; i < dim; i++) {
+      sig.append("\\[\\]");
     }
 
     return sig.toString();
@@ -209,7 +203,7 @@
           if (j < name.length() && name.charAt(j) == '*') {
             // ** matches any part of a name, possibly containing
             // any number of package separators or directory separators
-            sb.append(".*");
+            sb.append(separator.multipleCharWildcardWithSeparator);
             i++;
           } else {
             // * matches any part of a name not containing
@@ -302,15 +296,15 @@
     assert name != null;
     String fullName = "^" + convertNameToRegex(name, FilterSeparator.CLASS);
     fullName += signature;
+    NameSpecification typeSignature = null;
     if (typeSigRegex != null) {
-      fullName += typeSigRegex;
-    } else {
-      fullName += "V";
+      Pattern pattern = Pattern.compile("^" + typeSigRegex + "$");
+      typeSignature = new NameSpecification(pattern);
     }
     fullName += "$";
     Pattern pattern = Pattern.compile(fullName);
     classSpec.add(new MethodSpecification(new NameSpecification(pattern),
-        modifier, annotationType));
+        modifier, typeSignature, annotationType));
   }
 
   static void fieldOrAnyMember(@Nonnull ClassSpecification classSpec,
@@ -325,9 +319,9 @@
       // This is the "any member" case, we have to handle methods as well.
       method(classSpec,
           annotationType,
-          getSignatureRegex("***", 0),
+          getSourceNamePattern("***", 0),
           "*",
-          "\\(" + getSignatureRegex("...", 0) + "\\)",
+          "\\(" + getSourceNamePattern("...", 0) + "\\)",
           modifier);
     }
     field(classSpec, annotationType, typeSig, name, modifier, inputStream);
@@ -340,7 +334,7 @@
     assert name != null;
     NameSpecification typeSignature = null;
     if (typeSigRegex != null) {
-      Pattern pattern = Pattern.compile(typeSigRegex);
+      Pattern pattern = Pattern.compile("^" + typeSigRegex + "$");
       typeSignature = new NameSpecification(pattern);
     } else {
       if (!name.equals("*")) {
diff --git a/jack/src/com/android/jack/shrob/proguard/Proguard.g b/jack/src/com/android/jack/shrob/proguard/Proguard.g
index e67a7d7..e045dec 100644
--- a/jack/src/com/android/jack/shrob/proguard/Proguard.g
+++ b/jack/src/com/android/jack/shrob/proguard/Proguard.g
@@ -204,7 +204,7 @@
       (typeSig=type)? name=(NAME|'<init>') (signature=arguments {GrammarActions.method(classSpec, $annotation.annotSpec, typeSig, $name.text, signature, $modifiers.modifiers);}
                   | {assert $name != null; GrammarActions.fieldOrAnyMember(classSpec, $annotation.annotSpec, typeSig, $name.text, $modifiers.modifiers, $name.getInputStream());})
       | '<methods>' {GrammarActions.method(classSpec, $annotation.annotSpec,
-          GrammarActions.getSignatureRegex("***", 0), "*", "\\("+ GrammarActions.getSignatureRegex("...", 0) + "\\)",
+          GrammarActions.getSourceNamePattern("***", 0), "*", "\\("+ GrammarActions.getSourceNamePattern("...", 0) + "\\)",
           $modifiers.modifiers);}
       | fields='<fields>' {GrammarActions.field(classSpec, $annotation.annotSpec, null, "*", $modifiers.modifiers, $fields.getInputStream());}
     ) ';'
@@ -261,20 +261,20 @@
   '(' {signature = "\\(";}
     (
       (
-        parameterSig=type {signature += parameterSig;}
-        (',' parameterSig=type {signature += parameterSig;})*
+        parameterSig=type {signature += $parameterSig.typeSourceNamePattern;}
+        (',' parameterSig=type {signature += ", " + $parameterSig.typeSourceNamePattern;})*
         )?
       )
     ')' {signature += "\\)";}
   ;
 
-private type returns [String signature]
+private type returns [String typeSourceNamePattern]
 @init {
   int dim = 0;
 }
   :
   (
-    typeName=('%' | NAME) ('[]' {dim++;})*  {String sig = $typeName.text; signature = GrammarActions.getSignatureRegex(sig == null ? "" : sig, dim);}
+    typeName=('%' | NAME) ('[]' {dim++;})*  {String sig = $typeName.text; typeSourceNamePattern = GrammarActions.getSourceNamePattern(sig == null ? "" : sig, dim);}
   )
   ;
 
diff --git a/jack/src/com/android/jack/shrob/spec/FieldSpecification.java b/jack/src/com/android/jack/shrob/spec/FieldSpecification.java
index 3b01752..5fc8427 100644
--- a/jack/src/com/android/jack/shrob/spec/FieldSpecification.java
+++ b/jack/src/com/android/jack/shrob/spec/FieldSpecification.java
@@ -65,7 +65,7 @@
     }
 
     if (type != null
-        && !type.matches(GrammarActions.getSignatureFormatter().getName(f.getType()))) {
+        && !type.matches(GrammarActions.getSourceFormatter().getName(f.getType()))) {
       return false;
     }
 
diff --git a/jack/src/com/android/jack/shrob/spec/MethodSpecification.java b/jack/src/com/android/jack/shrob/spec/MethodSpecification.java
index 63d2c29..9ad6790 100644
--- a/jack/src/com/android/jack/shrob/spec/MethodSpecification.java
+++ b/jack/src/com/android/jack/shrob/spec/MethodSpecification.java
@@ -34,16 +34,21 @@
   @CheckForNull
   private final ModifierSpecification modifier;
 
+  @CheckForNull
+  private final NameSpecification type;
+
   @Nonnull
-  private final NameSpecification sigPattern;
+  private final NameSpecification fullSourceName;
 
   public MethodSpecification(
       @Nonnull NameSpecification sigPattern,
       @CheckForNull ModifierSpecification modifier,
+      @CheckForNull NameSpecification type,
       @CheckForNull AnnotationSpecification annotationType) {
-    this.sigPattern = sigPattern;
+    this.fullSourceName = sigPattern;
     this.modifier = modifier;
     this.annotationType = annotationType;
+    this.type = type;
   }
 
   @Override
@@ -56,20 +61,26 @@
       return false;
     }
 
-    String signature = GrammarActions.getSignatureFormatter().getName(t);
+    if (type != null
+        && !type.matches(GrammarActions.getSourceFormatter().getName(t.getType()))) {
+      return false;
+    }
+
+    String signature =
+        GrammarActions.getSourceFormatter().getNameWithoutReturnType(t.getMethodIdWide());
     if (t instanceof JConstructor) {
       String methodName = signature.replace(NamingTools.INIT_NAME, t.getEnclosingType().getName());
-      if (sigPattern.matches(methodName)) {
+      if (fullSourceName.matches(methodName)) {
         return true;
       }
       methodName = signature.replace(NamingTools.INIT_NAME,
           GrammarActions.getSourceFormatter().getName(t.getEnclosingType()));
-      if (sigPattern.matches(methodName)) {
+      if (fullSourceName.matches(methodName)) {
         return true;
       }
     }
 
-    return sigPattern.matches(signature);
+    return fullSourceName.matches(signature);
   }
 
   @Override
@@ -87,7 +98,12 @@
       sb.append(' ');
     }
 
-    sb.append(sigPattern);
+    if (type != null) {
+      sb.append(type);
+      sb.append(' ');
+    }
+
+    sb.append(fullSourceName);
     sb.append(';');
 
     return sb.toString();