Even better reflection IllegalArgumentException detail messages and less code.

Also ensure that the new 200-reflection-errors run-test test gets run
by the "test-art" make target.

Bug: 6504175
Change-Id: I5afee8845715151d25ed4751381b6ceb8cb4eca5
diff --git a/Android.mk b/Android.mk
index 6eb4299..aa567a7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -123,7 +123,7 @@
 TEST_ART_HOST_RUN_TEST_TARGETS += test-art-host-run-test-$(1)
 endef
 
-$(foreach test, $(wildcard art/test/0*), $(eval $(call declare-test-art-host-run-test,$(notdir $(test)))))
+$(foreach test, $(wildcard art/test/[0-9]*), $(eval $(call declare-test-art-host-run-test,$(notdir $(test)))))
 
 .PHONY: test-art-host-run-test
 test-art-host-run-test: $(TEST_ART_HOST_RUN_TEST_TARGETS)
@@ -162,7 +162,7 @@
 TEST_ART_TARGET_RUN_TEST_TARGETS += test-art-target-run-test-$(1)
 endef
 
-$(foreach test, $(wildcard art/test/0*), $(eval $(call declare-test-art-target-run-test,$(notdir $(test)))))
+$(foreach test, $(wildcard art/test/[0-9]*), $(eval $(call declare-test-art-target-run-test,$(notdir $(test)))))
 
 .PHONY: test-art-target-run-test
 test-art-target-run-test: $(TEST_ART_TARGET_RUN_TEST_TARGETS)
diff --git a/src/reflection.cc b/src/reflection.cc
index 6763100..12ecbe1 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -90,18 +90,13 @@
   for (uint32_t i = 0; i < arg_count; ++i) {
     Object* arg = objects->Get(i);
     Class* dst_class = mh.GetClassFromTypeIdx(classes->GetTypeItem(i).type_idx_);
-    if (dst_class->IsPrimitive()) {
-      if (!UnboxPrimitiveForArgument(arg, dst_class, decoded_args[i], i)) {
+    if (dst_class->IsPrimitive() || (arg != NULL && !arg->InstanceOf(dst_class))) {
+      // We want to actually unbox primitives, but only reuse the error reporting for reference types.
+      if (!UnboxPrimitiveForArgument(arg, dst_class, decoded_args[i], m, i)) {
         return NULL;
       }
-    } else if (arg != NULL && !arg->InstanceOf(dst_class)) {
-      self->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
-                               "argument %d has type %s, got %s",
-                               i + 1,
-                               PrettyDescriptor(dst_class).c_str(),
-                               PrettyTypeOf(arg).c_str());
-      return NULL;
     } else {
+      // We already tested that these types are compatible.
       args[i].l = AddLocalReference<jobject>(env, arg);
     }
   }
@@ -271,9 +266,10 @@
   m->Invoke(self, NULL, args, &value);
 }
 
-static std::string UnboxingFailureKind(int index, Field* f) {
-  if (index != -1) {
-    return StringPrintf("argument %d", index + 1); // Humans count from 1.
+static std::string UnboxingFailureKind(Method* m, int index, Field* f) {
+  if (m != NULL && index != -1) {
+    ++index; // Humans count from 1.
+    return StringPrintf("method %s argument %d", PrettyMethod(m, false).c_str(), index);
   }
   if (f != NULL) {
     return "field " + PrettyField(f, false);
@@ -281,12 +277,12 @@
   return "result";
 }
 
-static bool UnboxPrimitive(Object* o, Class* dst_class, JValue& unboxed_value, int index, Field* f) {
+static bool UnboxPrimitive(Object* o, Class* dst_class, JValue& unboxed_value, Method* m, int index, Field* f) {
   if (!dst_class->IsPrimitive()) {
     if (o != NULL && !o->InstanceOf(dst_class)) {
       Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                             "%s has type %s, got %s",
-                                            UnboxingFailureKind(index, f).c_str(),
+                                            UnboxingFailureKind(m, index, f).c_str(),
                                             PrettyDescriptor(dst_class).c_str(),
                                             PrettyTypeOf(o).c_str());
       return false;
@@ -296,14 +292,14 @@
   } else if (dst_class->GetPrimitiveType() == Primitive::kPrimVoid) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                           "can't unbox %s to void",
-                                          UnboxingFailureKind(index, f).c_str());
+                                          UnboxingFailureKind(m, index, f).c_str());
     return false;
   }
 
   if (o == NULL) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                           "%s has type %s, got null",
-                                          UnboxingFailureKind(index, f).c_str(),
+                                          UnboxingFailureKind(m, index, f).c_str(),
                                           PrettyDescriptor(dst_class).c_str());
     return false;
   }
@@ -340,7 +336,7 @@
   } else {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                           "%s has type %s, got %s",
-                                          UnboxingFailureKind(index, f).c_str(),
+                                          UnboxingFailureKind(m, index, f).c_str(),
                                           PrettyDescriptor(dst_class).c_str(),
                                           PrettyDescriptor(src_descriptor.c_str()).c_str());
     return false;
@@ -350,17 +346,18 @@
                                boxed_value, unboxed_value);
 }
 
-bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value, size_t index) {
-  return UnboxPrimitive(o, dst_class, unboxed_value, index, NULL);
+bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value, Method* m, size_t index) {
+  CHECK(m != NULL);
+  return UnboxPrimitive(o, dst_class, unboxed_value, m, index, NULL);
 }
 
 bool UnboxPrimitiveForField(Object* o, Class* dst_class, JValue& unboxed_value, Field* f) {
   CHECK(f != NULL);
-  return UnboxPrimitive(o, dst_class, unboxed_value, -1, f);
+  return UnboxPrimitive(o, dst_class, unboxed_value, NULL, -1, f);
 }
 
 bool UnboxPrimitiveForResult(Object* o, Class* dst_class, JValue& unboxed_value) {
-  return UnboxPrimitive(o, dst_class, unboxed_value, -1, NULL);
+  return UnboxPrimitive(o, dst_class, unboxed_value, NULL, -1, NULL);
 }
 
 }  // namespace art
diff --git a/src/reflection.h b/src/reflection.h
index aabf513..50c36d7 100644
--- a/src/reflection.h
+++ b/src/reflection.h
@@ -25,11 +25,12 @@
 class Class;
 class Field;
 union JValue;
+class Method;
 class Object;
 
 void InitBoxingMethods();
 void BoxPrimitive(Primitive::Type src_class, JValue& value);
-bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value, size_t index);
+bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value, Method* m, size_t index);
 bool UnboxPrimitiveForField(Object* o, Class* dst_class, JValue& unboxed_value, Field* f);
 bool UnboxPrimitiveForResult(Object* o, Class* dst_class, JValue& unboxed_value);
 
diff --git a/test/200-reflection-errors/expected.txt b/test/200-reflection-errors/expected.txt
index b5b201d..d042d05 100644
--- a/test/200-reflection-errors/expected.txt
+++ b/test/200-reflection-errors/expected.txt
@@ -1,5 +1,5 @@
 field A.b has type java.lang.String, got java.lang.Integer
 field A.i has type int, got null
 field A.i has type int, got java.lang.String
-argument 2 has type java.lang.String, got java.lang.Integer
-argument 1 has type int, got null
+method A.m argument 2 has type java.lang.String, got java.lang.Integer
+method A.m argument 1 has type int, got null