Index: runtime/lib/mirrors.cc |
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc |
index 3a5ba02cb9d3a1612a648bbec75a03f4c5a1228e..4de3ffb41325cd9e128b70e9043df8a1bbe84f80 100644 |
--- a/runtime/lib/mirrors.cc |
+++ b/runtime/lib/mirrors.cc |
@@ -1902,23 +1902,86 @@ static RawInstance* CreateSourceLocation(const String& uri, |
} |
-DEFINE_NATIVE_ENTRY(MethodMirror_location, 1) { |
- GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0)); |
- const Function& func = Function::Handle(ref.GetFunctionReferent()); |
- if (func.IsImplicitConstructor() || func.IsSignatureFunction()) { |
- // These are synthetic methods; they have no source. |
- return Instance::null(); |
+DEFINE_NATIVE_ENTRY(DeclarationMirror_location, 1) { |
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(0)); |
+ Object& decl = Object::Handle(); |
+ if (reflectee.IsMirrorReference()) { |
+ const MirrorReference& decl_ref = MirrorReference::Cast(reflectee); |
+ decl = decl_ref.referent(); |
+ } else if (reflectee.IsTypeParameter()) { |
+ decl = reflectee.raw(); |
+ } else { |
+ UNREACHABLE(); |
} |
- const Script& script = Script::Handle(func.script()); |
+ |
+ Script& script = Script::Handle(); |
+ intptr_t token_pos = Scanner::kNoSourcePos; |
+ |
+ if (decl.IsFunction()) { |
+ const Function& func = Function::Cast(decl); |
+ if (func.IsImplicitConstructor() || func.IsSignatureFunction()) { |
+ // These are synthetic methods; they have no source. |
+ return Instance::null(); |
+ } |
+ script = func.script(); |
+ token_pos = func.token_pos(); |
+ } else if (decl.IsClass()) { |
+ const Class& cls = Class::Cast(decl); |
+ const bool is_typedef = cls.IsSignatureClass() && |
+ !cls.IsCanonicalSignatureClass(); |
+ if (cls.is_synthesized_class() && |
+ !is_typedef && |
+ !cls.is_mixin_app_alias() && |
+ !cls.is_enum_class()) { |
+ return Instance::null(); // Synthetic. |
+ } |
+ script = cls.script(); |
+ token_pos = cls.token_pos(); |
+ } else if (decl.IsField()) { |
+ const Field& field = Field::Cast(decl); |
+ const Class& owner = Class::Handle(field.owner()); |
+ script = owner.script(); |
+ token_pos = field.token_pos(); |
+ } else if (decl.IsTypeParameter()) { |
+ const TypeParameter& type_var = TypeParameter::Cast(decl); |
+ const Class& owner = Class::Handle(type_var.parameterized_class()); |
+ script = owner.script(); |
+ token_pos = type_var.token_pos(); |
+ } else if (decl.IsLibrary()) { |
+ const Library& lib = Library::Cast(decl); |
+ if (lib.raw() == Library::NativeWrappersLibrary()) { |
+ return Instance::null(); // No source. |
+ } |
+ const Array& scripts = Array::Handle(lib.LoadedScripts()); |
+ for (intptr_t i = 0; i < scripts.Length(); i++) { |
+ script ^= scripts.At(i); |
+ if (script.kind() == RawScript::kLibraryTag) break; |
+ } |
+ ASSERT(!script.IsNull()); |
+ const String& libname = String::Handle(lib.name()); |
+ if (libname.Length() == 0) { |
+ // No library declaration. |
+ const String& uri = String::Handle(script.url()); |
+ return CreateSourceLocation(uri, 1, 1); |
+ } |
+ const TokenStream& stream = TokenStream::Handle(script.tokens()); |
+ TokenStream::Iterator tkit(stream, 0); |
+ if (tkit.CurrentTokenKind() == Token::kSCRIPTTAG) tkit.Advance(); |
+ token_pos = tkit.CurrentPosition(); |
+ } |
+ |
+ ASSERT(!script.IsNull()); |
+ ASSERT(token_pos != Scanner::kNoSourcePos); |
+ |
const String& uri = String::Handle(script.url()); |
intptr_t from_line = 0; |
intptr_t from_col = 0; |
if (script.HasSource()) { |
- script.GetTokenLocation(func.token_pos(), &from_line, &from_col); |
+ script.GetTokenLocation(token_pos, &from_line, &from_col); |
} else { |
// Avoid the slow path of printing the token stream when precise source |
// information is not available. |
- script.GetTokenLocation(func.token_pos(), &from_line, NULL); |
+ script.GetTokenLocation(token_pos, &from_line, NULL); |
} |
// We should always have at least the line number. |
ASSERT(from_line != 0); |