Descriptor references are direct references

We have to parse descriptors and treat the types they reference as direct
reference as we do for other direct type references. This is required because
Dalvik verifier is checking those descriptor the same way as it does for other
type references. See:
https://android.googlesource.com/platform/dalvik/+/kitkat-mr2.2-release/vm/analysis/CodeVerify.cpp#637

Bug: 19626444

(cherry picked from commit 8f9fb34f2d53beb22ad9055eb071a93157b922ba)

Change-Id: Ib9f43dd0c5f0b983fcc80e13caa13fd8b2dc2244
diff --git a/dx/src/com/android/multidex/ClassReferenceListBuilder.java b/dx/src/com/android/multidex/ClassReferenceListBuilder.java
index 0434cad..8218693 100644
--- a/dx/src/com/android/multidex/ClassReferenceListBuilder.java
+++ b/dx/src/com/android/multidex/ClassReferenceListBuilder.java
@@ -19,7 +19,11 @@
 import com.android.dx.cf.direct.DirectClassFile;
 import com.android.dx.rop.cst.Constant;
 import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstMethodRef;
 import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.StdTypeList;
 import com.android.dx.rop.type.Type;
 import com.android.dx.rop.type.TypeList;
 
@@ -37,8 +41,8 @@
 public class ClassReferenceListBuilder {
     private static final String CLASS_EXTENSION = ".class";
 
-    private Path path;
-    private Set<String> classNames = new HashSet<String>();
+    private final Path path;
+    private final Set<String> classNames = new HashSet<String>();
 
     public ClassReferenceListBuilder(Path path) {
         this.path = path;
@@ -96,23 +100,35 @@
     private void addDependencies(ConstantPool pool) {
         for (Constant constant : pool.getEntries()) {
             if (constant instanceof CstType) {
-                Type type = ((CstType) constant).getClassType();
-                String descriptor = type.getDescriptor();
-                if (descriptor.endsWith(";")) {
-                    int lastBrace = descriptor.lastIndexOf('[');
-                    if (lastBrace < 0) {
-                        addClassWithHierachy(descriptor.substring(1, descriptor.length()-1));
-                    } else {
-                        assert descriptor.length() > lastBrace + 3
-                        && descriptor.charAt(lastBrace + 1) == 'L';
-                        addClassWithHierachy(descriptor.substring(lastBrace + 2,
-                                descriptor.length() - 1));
-                    }
+                checkDescriptor(((CstType) constant).getClassType());
+            } else if (constant instanceof CstFieldRef) {
+                checkDescriptor(((CstFieldRef) constant).getType());
+            } else if (constant instanceof CstMethodRef) {
+                Prototype proto = ((CstMethodRef) constant).getPrototype();
+                checkDescriptor(proto.getReturnType());
+                StdTypeList args = proto.getParameterTypes();
+                for (int i = 0; i < args.size(); i++) {
+                    checkDescriptor(args.get(i));
                 }
             }
         }
     }
 
+    private void checkDescriptor(Type type) {
+        String descriptor = type.getDescriptor();
+        if (descriptor.endsWith(";")) {
+            int lastBrace = descriptor.lastIndexOf('[');
+            if (lastBrace < 0) {
+                addClassWithHierachy(descriptor.substring(1, descriptor.length()-1));
+            } else {
+                assert descriptor.length() > lastBrace + 3
+                && descriptor.charAt(lastBrace + 1) == 'L';
+                addClassWithHierachy(descriptor.substring(lastBrace + 2,
+                        descriptor.length() - 1));
+            }
+        }
+    }
+
     private void addClassWithHierachy(String classBinaryName) {
         if (classNames.contains(classBinaryName)) {
             return;