Throw if ResolveMethod fails.

It's impractical for the lower-level Find*Method calls to throw because
they're used in class initialization and exception throwing.

Change-Id: Idece1ea99553a758ebc23d987e46b59f0445ea67
diff --git a/src/class_linker.cc b/src/class_linker.cc
index aa69c30..67acf9d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -51,6 +51,19 @@
   va_end(args);
 }
 
+void ThrowNoSuchMethodError(const char* kind,
+    Class* c, const StringPiece& name, const StringPiece& signature) {
+  DexCache* dex_cache = c->GetDexCache();
+  std::stringstream msg;
+  msg << "no " << kind << " method " << name << "." << signature
+      << " in class " << c->GetDescriptor()->ToModifiedUtf8()
+      << " or its superclasses";
+  if (dex_cache) {
+    msg << " (defined in " << dex_cache->GetLocation()->ToModifiedUtf8() << ")";
+  }
+  Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", "%s", msg.str().c_str());
+}
+
 void ThrowEarlierClassFailure(Class* c) {
   /*
    * The class failed to initialize on a previous attempt, so we want to throw
@@ -2263,6 +2276,7 @@
   const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
   Class* klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
   if (klass == NULL) {
+    DCHECK(Thread::Current()->IsExceptionPending());
     return NULL;
   }
 
@@ -2278,7 +2292,7 @@
   if (resolved != NULL) {
     dex_cache->SetResolvedMethod(method_idx, resolved);
   } else {
-    DCHECK(Thread::Current()->IsExceptionPending());
+    ThrowNoSuchMethodError(is_direct ? "direct" : "virtual", klass, name, signature);
   }
   return resolved;
 }