Index: sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart |
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart b/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart |
index 19f133e20db62f961dac77f4f726903e8f323cf5..f3dce015cc55fc42c11c8323d4d06b3000d67609 100644 |
--- a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart |
+++ b/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart |
@@ -2,29 +2,208 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
-library dart2js_util; |
+library mirrors_dart2js; |
-import 'dart:async' show Future; |
+import 'dart:async'; |
+import 'dart:collection' show LinkedHashMap; |
import 'dart:io' show Path; |
import 'dart:uri'; |
-import '../../../compiler/compiler.dart' as api; |
-import '../../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js |
- show analyze, Dart2JsMirrorSystem; |
-import '../../../compiler/implementation/mirrors/mirrors.dart' |
- show MirrorSystem; |
-import '../../../compiler/implementation/source_file_provider.dart' |
- show FormattingDiagnosticHandler, SourceFileProvider; |
-import '../../../compiler/implementation/filenames.dart' |
- show appendSlash, currentDirectory; |
+import '../../compiler.dart' as api; |
+import '../elements/elements.dart'; |
+import '../resolution/resolution.dart' show ResolverTask, ResolverVisitor; |
+import '../apiimpl.dart' as apiimpl; |
+import '../scanner/scannerlib.dart' hide SourceString; |
+import '../ssa/ssa.dart'; |
+import '../dart2jslib.dart'; |
+import '../dart_types.dart'; |
+import '../filenames.dart'; |
+import '../source_file.dart'; |
+import '../tree/tree.dart'; |
+import '../util/util.dart'; |
+import '../util/uri_extras.dart'; |
+import '../dart2js.dart'; |
+import '../util/characters.dart'; |
+import '../source_file_provider.dart'; |
+ |
+import 'mirrors.dart'; |
+import 'mirrors_util.dart'; |
+import 'util.dart'; |
+ |
+//------------------------------------------------------------------------------ |
+// Utility types and functions for the dart2js mirror system |
+//------------------------------------------------------------------------------ |
+ |
+bool _isPrivate(String name) { |
+ return name.startsWith('_'); |
+} |
+ |
+List<ParameterMirror> _parametersFromFunctionSignature( |
+ Dart2JsMirrorSystem system, |
+ Dart2JsMethodMirror method, |
+ FunctionSignature signature) { |
+ var parameters = <ParameterMirror>[]; |
+ Link<Element> link = signature.requiredParameters; |
+ while (!link.isEmpty) { |
+ parameters.add(new Dart2JsParameterMirror( |
+ system, method, link.head, false, false)); |
+ link = link.tail; |
+ } |
+ link = signature.optionalParameters; |
+ bool isNamed = signature.optionalParametersAreNamed; |
+ while (!link.isEmpty) { |
+ parameters.add(new Dart2JsParameterMirror( |
+ system, method, link.head, true, isNamed)); |
+ link = link.tail; |
+ } |
+ return parameters; |
+} |
+ |
+Dart2JsTypeMirror _convertTypeToTypeMirror( |
+ Dart2JsMirrorSystem system, |
+ DartType type, |
+ InterfaceType defaultType, |
+ [FunctionSignature functionSignature]) { |
+ if (type == null) { |
+ return new Dart2JsInterfaceTypeMirror(system, defaultType); |
+ } else if (type is InterfaceType) { |
+ if (type == system.compiler.types.dynamicType) { |
+ return new Dart2JsDynamicMirror(system, type); |
+ } else { |
+ return new Dart2JsInterfaceTypeMirror(system, type); |
+ } |
+ } else if (type is TypeVariableType) { |
+ return new Dart2JsTypeVariableMirror(system, type); |
+ } else if (type is FunctionType) { |
+ return new Dart2JsFunctionTypeMirror(system, type, functionSignature); |
+ } else if (type is VoidType) { |
+ return new Dart2JsVoidMirror(system, type); |
+ } else if (type is TypedefType) { |
+ return new Dart2JsTypedefMirror(system, type); |
+ } else if (type is MalformedType) { |
+ // TODO(johnniwinther): We need a mirror on malformed types. |
+ return system.dynamicType; |
+ } |
+ system.compiler.internalError("Unexpected type $type of kind ${type.kind}"); |
+} |
+ |
+Iterable<Dart2JsMemberMirror> _convertElementMemberToMemberMirrors( |
+ Dart2JsContainerMirror library, Element element) { |
+ if (element.isSynthesized) { |
+ return const <Dart2JsMemberMirror>[]; |
+ } else if (element is VariableElement) { |
+ return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(library, element)]; |
+ } else if (element is FunctionElement) { |
+ return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(library, element)]; |
+ } else if (element is AbstractFieldElement) { |
+ var members = <Dart2JsMemberMirror>[]; |
+ if (element.getter != null) { |
+ members.add(new Dart2JsMethodMirror(library, element.getter)); |
+ } |
+ if (element.setter != null) { |
+ members.add(new Dart2JsMethodMirror(library, element.setter)); |
+ } |
+ return members; |
+ } |
+ library.mirrors.compiler.internalError( |
+ "Unexpected member type $element ${element.kind}"); |
+} |
+ |
+MethodMirror _convertElementMethodToMethodMirror(Dart2JsContainerMirror library, |
+ Element element) { |
+ if (element is FunctionElement) { |
+ return new Dart2JsMethodMirror(library, element); |
+ } else { |
+ return null; |
+ } |
+} |
+ |
+InstanceMirror _convertConstantToInstanceMirror(Dart2JsMirrorSystem mirrors, |
+ Constant constant) { |
+ if (constant is BoolConstant) { |
+ return new Dart2JsBoolConstantMirror(mirrors, constant); |
+ } else if (constant is NumConstant) { |
+ return new Dart2JsNumConstantMirror(mirrors, constant); |
+ } else if (constant is StringConstant) { |
+ return new Dart2JsStringConstantMirror(mirrors, constant); |
+ } else if (constant is ListConstant) { |
+ return new Dart2JsListConstantMirror(mirrors, constant); |
+ } else if (constant is MapConstant) { |
+ return new Dart2JsMapConstantMirror(mirrors, constant); |
+ } else if (constant is TypeConstant) { |
+ return new Dart2JsTypeConstantMirror(mirrors, constant); |
+ } else if (constant is FunctionConstant) { |
+ return new Dart2JsConstantMirror(mirrors, constant); |
+ } else if (constant is NullConstant) { |
+ return new Dart2JsNullConstantMirror(mirrors, constant); |
+ } else if (constant is ConstructedConstant) { |
+ return new Dart2JsConstructedConstantMirror(mirrors, constant); |
+ } |
+ mirrors.compiler.internalError("Unexpected constant $constant"); |
+} |
+ |
+class Dart2JsMethodKind { |
+ static const Dart2JsMethodKind REGULAR = const Dart2JsMethodKind("regular"); |
+ static const Dart2JsMethodKind GENERATIVE = |
+ const Dart2JsMethodKind("generative"); |
+ static const Dart2JsMethodKind REDIRECTING = |
+ const Dart2JsMethodKind("redirecting"); |
+ static const Dart2JsMethodKind CONST = const Dart2JsMethodKind("const"); |
+ static const Dart2JsMethodKind FACTORY = const Dart2JsMethodKind("factory"); |
+ static const Dart2JsMethodKind GETTER = const Dart2JsMethodKind("getter"); |
+ static const Dart2JsMethodKind SETTER = const Dart2JsMethodKind("setter"); |
+ static const Dart2JsMethodKind OPERATOR = const Dart2JsMethodKind("operator"); |
+ |
+ final String text; |
+ |
+ const Dart2JsMethodKind(this.text); |
+ |
+ String toString() => text; |
+} |
+ |
+ |
+String _getOperatorFromOperatorName(String name) { |
+ Map<String, String> mapping = const { |
+ 'eq': '==', |
+ 'not': '~', |
+ 'index': '[]', |
+ 'indexSet': '[]=', |
+ 'mul': '*', |
+ 'div': '/', |
+ 'mod': '%', |
+ 'tdiv': '~/', |
+ 'add': '+', |
+ 'sub': '-', |
+ 'shl': '<<', |
+ 'shr': '>>', |
+ 'ge': '>=', |
+ 'gt': '>', |
+ 'le': '<=', |
+ 'lt': '<', |
+ 'and': '&', |
+ 'xor': '^', |
+ 'or': '|', |
+ }; |
+ String newName = mapping[name]; |
+ if (newName == null) { |
+ throw new Exception('Unhandled operator name: $name'); |
+ } |
+ return newName; |
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Compilation implementation |
+//------------------------------------------------------------------------------ |
// TODO(johnniwinther): Support client configurable providers. |
/** |
* Returns a future that completes to a non-null String when [script] |
* has been successfully compiled. |
+ * |
+ * TODO(johnniwinther): The method is deprecated but here to support [Path] |
+ * which is used through dartdoc. |
*/ |
-// TODO(amouravski): Remove this method and call dart2js via a process instead. |
Future<String> compile(Path script, |
Path libraryRoot, |
{Path packageRoot, |
@@ -49,6 +228,52 @@ Future<String> compile(Path script, |
* Analyzes set of libraries and provides a mirror system which can be used for |
* static inspection of the source code. |
*/ |
+// TODO(johnniwinther): Move this to [compiler/compiler.dart] and rename to |
+// [:analyze:]. |
+Future<MirrorSystem> analyzeUri(List<Uri> libraries, |
+ Uri libraryRoot, |
+ Uri packageRoot, |
+ api.CompilerInputProvider inputProvider, |
+ api.DiagnosticHandler diagnosticHandler, |
+ [List<String> options = const <String>[]]) { |
+ if (!libraryRoot.path.endsWith("/")) { |
+ throw new ArgumentError("libraryRoot must end with a /"); |
+ } |
+ if (packageRoot != null && !packageRoot.path.endsWith("/")) { |
+ throw new ArgumentError("packageRoot must end with a /"); |
+ } |
+ options = new List<String>.from(options); |
+ options.add('--analyze-only'); |
+ options.add('--analyze-signatures-only'); |
+ options.add('--analyze-all'); |
+ |
+ bool compilationFailed = false; |
+ void internalDiagnosticHandler(Uri uri, int begin, int end, |
+ String message, api.Diagnostic kind) { |
+ if (kind == api.Diagnostic.ERROR || |
+ kind == api.Diagnostic.CRASH) { |
+ compilationFailed = true; |
+ } |
+ diagnosticHandler(uri, begin, end, message, kind); |
+ } |
+ |
+ Compiler compiler = new apiimpl.Compiler(inputProvider, |
+ null, |
+ internalDiagnosticHandler, |
+ libraryRoot, packageRoot, options); |
+ compiler.librariesToAnalyzeWhenRun = libraries; |
+ bool success = compiler.run(null); |
+ if (success && !compilationFailed) { |
+ return new Future<MirrorSystem>.value(new Dart2JsMirrorSystem(compiler)); |
+ } else { |
+ return new Future<MirrorSystem>.error('Failed to create mirror system.'); |
+ } |
+} |
+ |
+/** |
+ * Analyzes set of libraries and provides a mirror system which can be used for |
+ * static inspection of the source code. |
+ */ |
// TODO(johnniwinther): Move dart:io dependent parts outside |
// dart2js_mirror.dart. |
Future<MirrorSystem> analyze(List<Path> libraries, |
@@ -70,7 +295,1462 @@ Future<MirrorSystem> analyze(List<Path> libraries, |
for (Path library in libraries) { |
librariesUri.add(currentDirectory.resolve(library.toString())); |
} |
- return dart2js.analyze(librariesUri, libraryUri, packageUri, |
- provider.readStringFromUri, diagnosticHandler, |
- options); |
+ return analyzeUri(librariesUri, libraryUri, packageUri, |
+ provider.readStringFromUri, diagnosticHandler, options); |
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Dart2Js specific extensions of mirror interfaces |
+//------------------------------------------------------------------------------ |
+ |
+abstract class Dart2JsMirror implements Mirror { |
+ Dart2JsMirrorSystem get mirrors; |
+} |
+ |
+abstract class Dart2JsDeclarationMirror extends Dart2JsMirror |
+ implements DeclarationMirror { |
+ |
+ bool get isTopLevel => owner != null && owner is LibraryMirror; |
+ |
+ bool get isPrivate => _isPrivate(simpleName); |
+ |
+ /** |
+ * Returns the first token for the source of this declaration, not including |
+ * metadata annotations. |
+ */ |
+ Token getBeginToken(); |
+ |
+ /** |
+ * Returns the last token for the source of this declaration. |
+ */ |
+ Token getEndToken(); |
+ |
+ /** |
+ * Returns the script for the source of this declaration. |
+ */ |
+ Script getScript(); |
+} |
+ |
+abstract class Dart2JsTypeMirror extends Dart2JsDeclarationMirror |
+ implements TypeMirror { |
+} |
+ |
+abstract class Dart2JsElementMirror extends Dart2JsDeclarationMirror { |
+ final Dart2JsMirrorSystem mirrors; |
+ final Element _element; |
+ List<InstanceMirror> _metadata; |
+ |
+ Dart2JsElementMirror(this.mirrors, this._element) { |
+ assert (mirrors != null); |
+ assert (_element != null); |
+ } |
+ |
+ /** |
+ * Returns the element to be used to determine the begin token of this |
+ * declaration and the metadata associated with this declaration. |
+ * |
+ * This indirection is needed to use the [VariableListElement] as the location |
+ * for type and metadata information on a [VariableElement]. |
+ */ |
+ Element get _beginElement => _element; |
+ |
+ String get simpleName => _element.name.slowToString(); |
+ |
+ String get displayName => simpleName; |
+ |
+ /** |
+ * Computes the first token for this declaration using the begin token of the |
+ * element node or element position as indicator. |
+ */ |
+ Token getBeginToken() { |
+ // TODO(johnniwinther): Avoid calling [parseNode]. |
+ Node node = _beginElement.parseNode(mirrors.compiler); |
+ if (node == null) { |
+ return _beginElement.position(); |
+ } |
+ return node.getBeginToken(); |
+ } |
+ |
+ /** |
+ * Computes the last token for this declaration using the end token of the |
+ * element node or element position as indicator. |
+ */ |
+ Token getEndToken() { |
+ // TODO(johnniwinther): Avoid calling [parseNode]. |
+ Node node = _element.parseNode(mirrors.compiler); |
+ if (node == null) { |
+ return _element.position(); |
+ } |
+ return node.getEndToken(); |
+ } |
+ |
+ /** |
+ * Returns the first token for the source of this declaration, including |
+ * metadata annotations. |
+ */ |
+ Token getFirstToken() { |
+ if (!_beginElement.metadata.isEmpty) { |
+ for (MetadataAnnotation metadata in _beginElement.metadata) { |
+ if (metadata.beginToken != null) { |
+ return metadata.beginToken; |
+ } |
+ } |
+ } |
+ return getBeginToken(); |
+ } |
+ |
+ Script getScript() => _element.getCompilationUnit().script; |
+ |
+ SourceLocation get location { |
+ Token beginToken = getFirstToken(); |
+ Script script = getScript(); |
+ SourceSpan span; |
+ if (beginToken == null) { |
+ span = new SourceSpan(script.uri, 0, 0); |
+ } else { |
+ Token endToken = getEndToken(); |
+ span = mirrors.compiler.spanFromTokens(beginToken, endToken, script.uri); |
+ } |
+ return new Dart2JsSourceLocation(script, span); |
+ } |
+ |
+ String toString() => _element.toString(); |
+ |
+ int get hashCode => qualifiedName.hashCode; |
+ |
+ void _appendCommentTokens(Token commentToken) { |
+ while (commentToken != null && commentToken.kind == COMMENT_TOKEN) { |
+ _metadata.add(new Dart2JsCommentInstanceMirror( |
+ mirrors, commentToken.slowToString())); |
+ commentToken = commentToken.next; |
+ } |
+ } |
+ |
+ List<InstanceMirror> get metadata { |
+ if (_metadata == null) { |
+ _metadata = <InstanceMirror>[]; |
+ for (MetadataAnnotation metadata in _element.metadata) { |
+ _appendCommentTokens(mirrors.compiler.commentMap[metadata.beginToken]); |
+ metadata.ensureResolved(mirrors.compiler); |
+ _metadata.add( |
+ _convertConstantToInstanceMirror(mirrors, metadata.value)); |
+ } |
+ _appendCommentTokens(mirrors.compiler.commentMap[getBeginToken()]); |
+ } |
+ // TODO(johnniwinther): Return an unmodifiable list instead. |
+ return new List<InstanceMirror>.from(_metadata); |
+ } |
+} |
+ |
+abstract class Dart2JsMemberMirror extends Dart2JsElementMirror |
+ implements MemberMirror { |
+ |
+ Dart2JsMemberMirror(Dart2JsMirrorSystem system, Element element) |
+ : super(system, element); |
+ |
+ bool get isConstructor => false; |
+ |
+ bool get isVariable => false; |
+ |
+ bool get isMethod => false; |
+ |
+ bool get isStatic => false; |
+ |
+ bool get isParameter => false; |
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Mirror system implementation. |
+//------------------------------------------------------------------------------ |
+ |
+class Dart2JsMirrorSystem extends MirrorSystem { |
+ final Compiler compiler; |
+ Map<Uri, Dart2JsLibraryMirror> _libraries; |
+ Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap; |
+ |
+ Dart2JsMirrorSystem(this.compiler) |
+ : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>(); |
+ |
+ void _ensureLibraries() { |
+ if (_libraries == null) { |
+ _libraries = new Map<Uri, Dart2JsLibraryMirror>(); |
+ compiler.libraries.forEach((_, LibraryElement v) { |
+ var mirror = new Dart2JsLibraryMirror(mirrors, v); |
+ _libraries[mirror.uri] = mirror; |
+ _libraryMap[v] = mirror; |
+ }); |
+ } |
+ } |
+ |
+ Map<Uri, LibraryMirror> get libraries { |
+ _ensureLibraries(); |
+ return new ImmutableMapWrapper<Uri, LibraryMirror>(_libraries); |
+ } |
+ |
+ Dart2JsLibraryMirror _getLibrary(LibraryElement element) => |
+ _libraryMap[element]; |
+ |
+ Dart2JsMirrorSystem get mirrors => this; |
+ |
+ TypeMirror get dynamicType => |
+ _convertTypeToTypeMirror(this, compiler.types.dynamicType, null); |
+ |
+ TypeMirror get voidType => |
+ _convertTypeToTypeMirror(this, compiler.types.voidType, null); |
+} |
+ |
+abstract class Dart2JsContainerMirror extends Dart2JsElementMirror |
+ implements ContainerMirror { |
+ Map<String, MemberMirror> _members; |
+ |
+ Dart2JsContainerMirror(Dart2JsMirrorSystem system, Element element) |
+ : super(system, element); |
+ |
+ void _ensureMembers(); |
+ |
+ Map<String, MemberMirror> get members { |
+ _ensureMembers(); |
+ return new ImmutableMapWrapper<String, MemberMirror>(_members); |
+ } |
+ |
+ Map<String, MethodMirror> get functions { |
+ _ensureMembers(); |
+ return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( |
+ _members, |
+ (MemberMirror member) => member is MethodMirror ? member : null); |
+ } |
+ |
+ Map<String, MethodMirror> get getters { |
+ _ensureMembers(); |
+ return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( |
+ _members, |
+ (MemberMirror member) => |
+ member is MethodMirror && (member as MethodMirror).isGetter ? |
+ member : null); |
+ } |
+ |
+ Map<String, MethodMirror> get setters { |
+ _ensureMembers(); |
+ return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( |
+ _members, |
+ (MemberMirror member) => |
+ member is MethodMirror && (member as MethodMirror).isSetter ? |
+ member : null); |
+ } |
+ |
+ Map<String, VariableMirror> get variables { |
+ _ensureMembers(); |
+ return new AsFilteredImmutableMap<String, MemberMirror, VariableMirror>( |
+ _members, |
+ (MemberMirror member) => member is VariableMirror ? member : null); |
+ } |
+} |
+ |
+class Dart2JsLibraryMirror extends Dart2JsContainerMirror |
+ implements LibraryMirror { |
+ Map<String, ClassMirror> _classes; |
+ |
+ Dart2JsLibraryMirror(Dart2JsMirrorSystem system, LibraryElement library) |
+ : super(system, library); |
+ |
+ LibraryElement get _library => _element; |
+ |
+ Uri get uri => _library.canonicalUri; |
+ |
+ DeclarationMirror get owner => null; |
+ |
+ bool get isPrivate => false; |
+ |
+ LibraryMirror library() => this; |
+ |
+ /** |
+ * Returns the library name (for libraries with a #library tag) or the script |
+ * file name (for scripts without a #library tag). The latter case is used to |
+ * provide a 'library name' for scripts, to use for instance in dartdoc. |
+ */ |
+ String get simpleName { |
+ if (_library.libraryTag != null) { |
+ // TODO(ahe): Remove StringNode check when old syntax is removed. |
+ StringNode name = _library.libraryTag.name.asStringNode(); |
+ if (name != null) { |
+ return name.dartString.slowToString(); |
+ } else { |
+ return _library.libraryTag.name.toString(); |
+ } |
+ } else { |
+ // Use the file name as script name. |
+ String path = _library.canonicalUri.path; |
+ return path.substring(path.lastIndexOf('/') + 1); |
+ } |
+ } |
+ |
+ String get qualifiedName => simpleName; |
+ |
+ void _ensureClasses() { |
+ if (_classes == null) { |
+ _classes = <String, ClassMirror>{}; |
+ _library.forEachLocalMember((Element e) { |
+ if (e.isClass()) { |
+ ClassElement classElement = e; |
+ classElement.ensureResolved(mirrors.compiler); |
+ var type = new Dart2JsClassMirror.fromLibrary(this, classElement); |
+ assert(invariant(_library, !_classes.containsKey(type.simpleName), |
+ message: "Type name '${type.simpleName}' " |
+ "is not unique in $_library.")); |
+ _classes[type.simpleName] = type; |
+ } else if (e.isTypedef()) { |
+ var type = new Dart2JsTypedefMirror.fromLibrary(this, |
+ e.computeType(mirrors.compiler)); |
+ assert(invariant(_library, !_classes.containsKey(type.simpleName), |
+ message: "Type name '${type.simpleName}' " |
+ "is not unique in $_library.")); |
+ _classes[type.simpleName] = type; |
+ } |
+ }); |
+ } |
+ } |
+ |
+ void _ensureMembers() { |
+ if (_members == null) { |
+ _members = <String, MemberMirror>{}; |
+ _library.forEachLocalMember((Element e) { |
+ if (!e.isClass() && !e.isTypedef()) { |
+ for (var member in _convertElementMemberToMemberMirrors(this, e)) { |
+ assert(!_members.containsKey(member.simpleName)); |
+ _members[member.simpleName] = member; |
+ } |
+ } |
+ }); |
+ } |
+ } |
+ |
+ Map<String, ClassMirror> get classes { |
+ _ensureClasses(); |
+ return new ImmutableMapWrapper<String, ClassMirror>(_classes); |
+ } |
+ |
+ /** |
+ * Computes the first token of this library using the first library tag as |
+ * indicator. |
+ */ |
+ Token getBeginToken() { |
+ if (_library.libraryTag != null) { |
+ return _library.libraryTag.getBeginToken(); |
+ } else if (!_library.tags.isEmpty) { |
+ return _library.tags.reverse().head.getBeginToken(); |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * Computes the first token of this library using the last library tag as |
+ * indicator. |
+ */ |
+ Token getEndToken() { |
+ if (!_library.tags.isEmpty) { |
+ return _library.tags.head.getEndToken(); |
+ } |
+ return null; |
+ } |
+} |
+ |
+class Dart2JsSourceLocation implements SourceLocation { |
+ final Script _script; |
+ final SourceSpan _span; |
+ int _line; |
+ int _column; |
+ |
+ Dart2JsSourceLocation(this._script, this._span); |
+ |
+ int _computeLine() { |
+ var sourceFile = _script.file as SourceFile; |
+ if (sourceFile != null) { |
+ return sourceFile.getLine(offset) + 1; |
+ } |
+ var index = 0; |
+ var lineNumber = 0; |
+ while (index <= offset && index < sourceText.length) { |
+ index = sourceText.indexOf('\n', index) + 1; |
+ if (index <= 0) break; |
+ lineNumber++; |
+ } |
+ return lineNumber; |
+ } |
+ |
+ int get line { |
+ if (_line == null) { |
+ _line = _computeLine(); |
+ } |
+ return _line; |
+ } |
+ |
+ int _computeColumn() { |
+ if (length == 0) return 0; |
+ |
+ var sourceFile = _script.file as SourceFile; |
+ if (sourceFile != null) { |
+ return sourceFile.getColumn(sourceFile.getLine(offset), offset) + 1; |
+ } |
+ int index = offset - 1; |
+ var columnNumber = 0; |
+ while (0 <= index && index < sourceText.length) { |
+ columnNumber++; |
+ var codeUnit = sourceText.codeUnitAt(index); |
+ if (codeUnit == $CR || codeUnit == $LF) { |
+ break; |
+ } |
+ index--; |
+ } |
+ return columnNumber; |
+ } |
+ |
+ int get column { |
+ if (_column == null) { |
+ _column = _computeColumn(); |
+ } |
+ return _column; |
+ } |
+ |
+ int get offset => _span.begin; |
+ |
+ int get length => _span.end - _span.begin; |
+ |
+ String get text => _script.text.substring(_span.begin, _span.end); |
+ |
+ Uri get sourceUri => _script.uri; |
+ |
+ String get sourceText => _script.text; |
+} |
+ |
+class Dart2JsParameterMirror extends Dart2JsMemberMirror |
+ implements ParameterMirror { |
+ final MethodMirror _method; |
+ final bool isOptional; |
+ final bool isNamed; |
+ |
+ factory Dart2JsParameterMirror(Dart2JsMirrorSystem system, |
+ MethodMirror method, |
+ VariableElement element, |
+ bool isOptional, |
+ bool isNamed) { |
+ if (element is FieldParameterElement) { |
+ return new Dart2JsFieldParameterMirror(system, |
+ method, element, isOptional, isNamed); |
+ } |
+ return new Dart2JsParameterMirror._normal(system, |
+ method, element, isOptional, isNamed); |
+ } |
+ |
+ Dart2JsParameterMirror._normal(Dart2JsMirrorSystem system, |
+ this._method, |
+ VariableElement element, |
+ this.isOptional, |
+ this.isNamed) |
+ : super(system, element); |
+ |
+ Element get _beginElement => _variableElement.variables; |
+ |
+ DeclarationMirror get owner => _method; |
+ |
+ VariableElement get _variableElement => _element; |
+ |
+ String get qualifiedName => '${_method.qualifiedName}#${simpleName}'; |
+ |
+ TypeMirror get type => _convertTypeToTypeMirror(mirrors, |
+ _variableElement.computeType(mirrors.compiler), |
+ mirrors.compiler.types.dynamicType, |
+ _variableElement.variables.functionSignature); |
+ |
+ |
+ bool get isFinal => false; |
+ |
+ bool get isConst => false; |
+ |
+ String get defaultValue { |
+ if (hasDefaultValue) { |
+ SendSet expression = _variableElement.cachedNode.asSendSet(); |
+ return unparse(expression.arguments.head); |
+ } |
+ return null; |
+ } |
+ |
+ bool get hasDefaultValue { |
+ return _variableElement.cachedNode != null && |
+ _variableElement.cachedNode is SendSet; |
+ } |
+ |
+ bool get isInitializingFormal => false; |
+ |
+ VariableMirror get initializedField => null; |
+} |
+ |
+class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror { |
+ |
+ Dart2JsFieldParameterMirror(Dart2JsMirrorSystem system, |
+ MethodMirror method, |
+ FieldParameterElement element, |
+ bool isOptional, |
+ bool isNamed) |
+ : super._normal(system, method, element, isOptional, isNamed); |
+ |
+ FieldParameterElement get _fieldParameterElement => _element; |
+ |
+ TypeMirror get type { |
+ VariableListElement variables = _fieldParameterElement.variables; |
+ VariableDefinitions node = variables.parseNode(mirrors.compiler); |
+ if (node.type != null) { |
+ return super.type; |
+ } |
+ // Use the field type for initializing formals with no type annotation. |
+ return _convertTypeToTypeMirror(mirrors, |
+ _fieldParameterElement.fieldElement.computeType(mirrors.compiler), |
+ mirrors.compiler.types.dynamicType, |
+ _variableElement.variables.functionSignature); |
+ } |
+ |
+ bool get isInitializingFormal => true; |
+ |
+ VariableMirror get initializedField => new Dart2JsFieldMirror( |
+ _method.owner, _fieldParameterElement.fieldElement); |
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Declarations |
+//------------------------------------------------------------------------------ |
+class Dart2JsClassMirror extends Dart2JsContainerMirror |
+ implements Dart2JsTypeMirror, ClassMirror { |
+ final Dart2JsLibraryMirror library; |
+ List<TypeVariableMirror> _typeVariables; |
+ |
+ Dart2JsClassMirror(Dart2JsMirrorSystem system, ClassElement _class) |
+ : this.library = system._getLibrary(_class.getLibrary()), |
+ super(system, _class); |
+ |
+ ClassElement get _class => _element; |
+ |
+ Dart2JsClassMirror.fromLibrary(Dart2JsLibraryMirror library, |
+ ClassElement _class) |
+ : this.library = library, |
+ super(library.mirrors, _class); |
+ |
+ DeclarationMirror get owner => library; |
+ |
+ String get qualifiedName => '${library.qualifiedName}.${simpleName}'; |
+ |
+ void _ensureMembers() { |
+ if (_members == null) { |
+ _members = <String, Dart2JsMemberMirror>{}; |
+ _class.forEachMember((_, e) { |
+ for (var member in _convertElementMemberToMemberMirrors(this, e)) { |
+ assert(!_members.containsKey(member.simpleName)); |
+ _members[member.simpleName] = member; |
+ } |
+ }); |
+ } |
+ } |
+ |
+ Map<String, MethodMirror> get methods => functions; |
+ |
+ Map<String, MethodMirror> get constructors { |
+ _ensureMembers(); |
+ return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( |
+ _members, (m) => m.isConstructor ? m : null); |
+ } |
+ |
+ bool get isObject => _class == mirrors.compiler.objectClass; |
+ |
+ bool get isDynamic => false; |
+ |
+ bool get isVoid => false; |
+ |
+ bool get isTypeVariable => false; |
+ |
+ bool get isTypedef => false; |
+ |
+ bool get isFunction => false; |
+ |
+ ClassMirror get originalDeclaration => this; |
+ |
+ ClassMirror get superclass { |
+ if (_class.supertype != null) { |
+ return new Dart2JsInterfaceTypeMirror(mirrors, _class.supertype); |
+ } |
+ return null; |
+ } |
+ |
+ List<ClassMirror> get superinterfaces { |
+ var list = <ClassMirror>[]; |
+ Link<DartType> link = _class.interfaces; |
+ while (!link.isEmpty) { |
+ var type = _convertTypeToTypeMirror(mirrors, link.head, |
+ mirrors.compiler.types.dynamicType); |
+ list.add(type); |
+ link = link.tail; |
+ } |
+ return list; |
+ } |
+ |
+ bool get isClass => !_class.isInterface(); |
+ |
+ bool get isInterface => _class.isInterface(); |
+ |
+ bool get isAbstract => _class.modifiers.isAbstract(); |
+ |
+ bool get isOriginalDeclaration => true; |
+ |
+ List<TypeMirror> get typeArguments { |
+ throw new UnsupportedError( |
+ 'Declarations do not have type arguments'); |
+ } |
+ |
+ List<TypeVariableMirror> get typeVariables { |
+ if (_typeVariables == null) { |
+ _typeVariables = <TypeVariableMirror>[]; |
+ _class.ensureResolved(mirrors.compiler); |
+ for (TypeVariableType typeVariable in _class.typeVariables) { |
+ _typeVariables.add( |
+ new Dart2JsTypeVariableMirror(mirrors, typeVariable)); |
+ } |
+ } |
+ return _typeVariables; |
+ } |
+ |
+ /** |
+ * Returns the default type for this interface. |
+ */ |
+ ClassMirror get defaultFactory { |
+ if (_class.defaultClass != null) { |
+ return new Dart2JsInterfaceTypeMirror(mirrors, _class.defaultClass); |
+ } |
+ return null; |
+ } |
+ |
+ bool operator ==(Object other) { |
+ if (identical(this, other)) { |
+ return true; |
+ } |
+ if (other is! ClassMirror) { |
+ return false; |
+ } |
+ if (library != other.library) { |
+ return false; |
+ } |
+ if (!identical(isOriginalDeclaration, other.isOriginalDeclaration)) { |
+ return false; |
+ } |
+ return qualifiedName == other.qualifiedName; |
+ } |
+} |
+ |
+class Dart2JsTypedefMirror extends Dart2JsTypeElementMirror |
+ implements Dart2JsTypeMirror, TypedefMirror { |
+ final Dart2JsLibraryMirror _library; |
+ List<TypeVariableMirror> _typeVariables; |
+ TypeMirror _definition; |
+ |
+ Dart2JsTypedefMirror(Dart2JsMirrorSystem system, TypedefType _typedef) |
+ : this._library = system._getLibrary(_typedef.element.getLibrary()), |
+ super(system, _typedef); |
+ |
+ Dart2JsTypedefMirror.fromLibrary(Dart2JsLibraryMirror library, |
+ TypedefType _typedef) |
+ : this._library = library, |
+ super(library.mirrors, _typedef); |
+ |
+ TypedefType get _typedef => _type; |
+ |
+ String get qualifiedName => '${library.qualifiedName}.${simpleName}'; |
+ |
+ LibraryMirror get library => _library; |
+ |
+ bool get isTypedef => true; |
+ |
+ List<TypeMirror> get typeArguments { |
+ throw new UnsupportedError( |
+ 'Declarations do not have type arguments'); |
+ } |
+ |
+ List<TypeVariableMirror> get typeVariables { |
+ if (_typeVariables == null) { |
+ _typeVariables = <TypeVariableMirror>[]; |
+ for (TypeVariableType typeVariable in _typedef.typeArguments) { |
+ _typeVariables.add( |
+ new Dart2JsTypeVariableMirror(mirrors, typeVariable)); |
+ } |
+ } |
+ return _typeVariables; |
+ } |
+ |
+ TypeMirror get value { |
+ if (_definition == null) { |
+ // TODO(johnniwinther): Should be [ensureResolved]. |
+ mirrors.compiler.resolveTypedef(_typedef.element); |
+ _definition = _convertTypeToTypeMirror( |
+ mirrors, |
+ _typedef.element.alias, |
+ mirrors.compiler.types.dynamicType, |
+ _typedef.element.functionSignature); |
+ } |
+ return _definition; |
+ } |
+ |
+ ClassMirror get originalDeclaration => this; |
+ |
+ // TODO(johnniwinther): How should a typedef respond to these? |
+ ClassMirror get superclass => null; |
+ |
+ List<ClassMirror> get superinterfaces => const <ClassMirror>[]; |
+ |
+ bool get isClass => false; |
+ |
+ bool get isInterface => false; |
+ |
+ bool get isOriginalDeclaration => true; |
+ |
+ bool get isAbstract => false; |
+} |
+ |
+class Dart2JsTypeVariableMirror extends Dart2JsTypeElementMirror |
+ implements TypeVariableMirror { |
+ final TypeVariableType _typeVariableType; |
+ ClassMirror _declarer; |
+ |
+ Dart2JsTypeVariableMirror(Dart2JsMirrorSystem system, |
+ TypeVariableType typeVariableType) |
+ : this._typeVariableType = typeVariableType, |
+ super(system, typeVariableType) { |
+ assert(_typeVariableType != null); |
+ } |
+ |
+ |
+ String get qualifiedName => '${declarer.qualifiedName}.${simpleName}'; |
+ |
+ ClassMirror get declarer { |
+ if (_declarer == null) { |
+ if (_typeVariableType.element.enclosingElement.isClass()) { |
+ _declarer = new Dart2JsClassMirror(mirrors, |
+ _typeVariableType.element.enclosingElement); |
+ } else if (_typeVariableType.element.enclosingElement.isTypedef()) { |
+ _declarer = new Dart2JsTypedefMirror(mirrors, |
+ _typeVariableType.element.enclosingElement.computeType( |
+ mirrors.compiler)); |
+ } |
+ } |
+ return _declarer; |
+ } |
+ |
+ LibraryMirror get library => declarer.library; |
+ |
+ DeclarationMirror get owner => declarer; |
+ |
+ bool get isTypeVariable => true; |
+ |
+ TypeMirror get upperBound => _convertTypeToTypeMirror( |
+ mirrors, |
+ _typeVariableType.element.bound, |
+ mirrors.compiler.objectClass.computeType(mirrors.compiler)); |
+ |
+ bool operator ==(Object other) { |
+ if (identical(this, other)) { |
+ return true; |
+ } |
+ if (other is! TypeVariableMirror) { |
+ return false; |
+ } |
+ if (declarer != other.declarer) { |
+ return false; |
+ } |
+ return qualifiedName == other.qualifiedName; |
+ } |
+} |
+ |
+ |
+//------------------------------------------------------------------------------ |
+// Types |
+//------------------------------------------------------------------------------ |
+ |
+abstract class Dart2JsTypeElementMirror extends Dart2JsElementMirror |
+ implements Dart2JsTypeMirror { |
+ final DartType _type; |
+ |
+ Dart2JsTypeElementMirror(Dart2JsMirrorSystem system, DartType type) |
+ : super(system, type.element), |
+ this._type = type; |
+ |
+ String get simpleName => _type.name.slowToString(); |
+ |
+ DeclarationMirror get owner => library; |
+ |
+ LibraryMirror get library { |
+ return mirrors._getLibrary(_type.element.getLibrary()); |
+ } |
+ |
+ bool get isObject => false; |
+ |
+ bool get isVoid => false; |
+ |
+ bool get isDynamic => false; |
+ |
+ bool get isTypeVariable => false; |
+ |
+ bool get isTypedef => false; |
+ |
+ bool get isFunction => false; |
+ |
+ String toString() => _type.toString(); |
+ |
+ Map<String, MemberMirror> get members => const <String, MemberMirror>{}; |
+ |
+ Map<String, MethodMirror> get constructors => const <String, MethodMirror>{}; |
+ |
+ Map<String, MethodMirror> get methods => const <String, MethodMirror>{}; |
+ |
+ Map<String, MethodMirror> get getters => const <String, MethodMirror>{}; |
+ |
+ Map<String, MethodMirror> get setters => const <String, MethodMirror>{}; |
+ |
+ Map<String, VariableMirror> get variables => const <String, VariableMirror>{}; |
+ |
+ ClassMirror get defaultFactory => null; |
+} |
+ |
+class Dart2JsInterfaceTypeMirror extends Dart2JsTypeElementMirror |
+ implements ClassMirror { |
+ List<TypeMirror> _typeArguments; |
+ |
+ Dart2JsInterfaceTypeMirror(Dart2JsMirrorSystem system, |
+ InterfaceType interfaceType) |
+ : super(system, interfaceType); |
+ |
+ InterfaceType get _interfaceType => _type; |
+ |
+ String get qualifiedName => originalDeclaration.qualifiedName; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ Map<String, MemberMirror> get members => originalDeclaration.members; |
+ |
+ bool get isObject => mirrors.compiler.objectClass == _type.element; |
+ |
+ bool get isDynamic => mirrors.compiler.dynamicClass == _type.element; |
+ |
+ ClassMirror get originalDeclaration |
+ => new Dart2JsClassMirror(mirrors, _type.element); |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ ClassMirror get superclass => originalDeclaration.superclass; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces; |
+ |
+ bool get isClass => originalDeclaration.isClass; |
+ |
+ bool get isInterface => originalDeclaration.isInterface; |
+ |
+ bool get isAbstract => originalDeclaration.isAbstract; |
+ |
+ bool get isPrivate => originalDeclaration.isPrivate; |
+ |
+ bool get isOriginalDeclaration => false; |
+ |
+ List<TypeMirror> get typeArguments { |
+ if (_typeArguments == null) { |
+ _typeArguments = <TypeMirror>[]; |
+ if (!_interfaceType.isRaw) { |
+ Link<DartType> type = _interfaceType.typeArguments; |
+ while (type != null && type.head != null) { |
+ _typeArguments.add(_convertTypeToTypeMirror(mirrors, type.head, |
+ mirrors.compiler.types.dynamicType)); |
+ type = type.tail; |
+ } |
+ } |
+ } |
+ return _typeArguments; |
+ } |
+ |
+ List<TypeVariableMirror> get typeVariables => |
+ originalDeclaration.typeVariables; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ Map<String, MethodMirror> get constructors => |
+ originalDeclaration.constructors; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ Map<String, MethodMirror> get methods => originalDeclaration.methods; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ Map<String, MethodMirror> get setters => originalDeclaration.setters; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ Map<String, MethodMirror> get getters => originalDeclaration.getters; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ Map<String, VariableMirror> get variables => originalDeclaration.variables; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables? |
+ ClassMirror get defaultFactory => originalDeclaration.defaultFactory; |
+ |
+ bool operator ==(Object other) { |
+ if (identical(this, other)) { |
+ return true; |
+ } |
+ if (other is! ClassMirror) { |
+ return false; |
+ } |
+ if (other.isOriginalDeclaration) { |
+ return false; |
+ } |
+ if (originalDeclaration != other.originalDeclaration) { |
+ return false; |
+ } |
+ var thisTypeArguments = typeArguments.iterator; |
+ var otherTypeArguments = other.typeArguments.iterator; |
+ while (thisTypeArguments.moveNext()) { |
+ if (!otherTypeArguments.moveNext()) return false; |
+ if (thisTypeArguments.current != otherTypeArguments.current) { |
+ return false; |
+ } |
+ } |
+ return !otherTypeArguments.moveNext(); |
+ } |
+} |
+ |
+ |
+class Dart2JsFunctionTypeMirror extends Dart2JsTypeElementMirror |
+ implements FunctionTypeMirror { |
+ final FunctionSignature _functionSignature; |
+ List<ParameterMirror> _parameters; |
+ |
+ Dart2JsFunctionTypeMirror(Dart2JsMirrorSystem system, |
+ FunctionType functionType, this._functionSignature) |
+ : super(system, functionType) { |
+ assert (_functionSignature != null); |
+ } |
+ |
+ FunctionType get _functionType => _type; |
+ |
+ // TODO(johnniwinther): Is this the qualified name of a function type? |
+ String get qualifiedName => originalDeclaration.qualifiedName; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ Map<String, MemberMirror> get members { |
+ var method = callMethod; |
+ if (method != null) { |
+ var map = new Map<String, MemberMirror>.from( |
+ originalDeclaration.members); |
+ var name = method.qualifiedName; |
+ assert(!map.containsKey(name)); |
+ map[name] = method; |
+ return new ImmutableMapWrapper<String, MemberMirror>(map); |
+ } |
+ return originalDeclaration.members; |
+ } |
+ |
+ bool get isFunction => true; |
+ |
+ MethodMirror get callMethod => _convertElementMethodToMethodMirror( |
+ mirrors._getLibrary(_functionType.element.getLibrary()), |
+ _functionType.element); |
+ |
+ ClassMirror get originalDeclaration |
+ => new Dart2JsClassMirror(mirrors, mirrors.compiler.functionClass); |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ ClassMirror get superclass => originalDeclaration.superclass; |
+ |
+ // TODO(johnniwinther): Substitute type arguments for type variables. |
+ List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces; |
+ |
+ bool get isClass => originalDeclaration.isClass; |
+ |
+ bool get isInterface => originalDeclaration.isInterface; |
+ |
+ bool get isPrivate => originalDeclaration.isPrivate; |
+ |
+ bool get isOriginalDeclaration => false; |
+ |
+ bool get isAbstract => false; |
+ |
+ List<TypeMirror> get typeArguments => const <TypeMirror>[]; |
+ |
+ List<TypeVariableMirror> get typeVariables => |
+ originalDeclaration.typeVariables; |
+ |
+ TypeMirror get returnType { |
+ return _convertTypeToTypeMirror(mirrors, _functionType.returnType, |
+ mirrors.compiler.types.dynamicType); |
+ } |
+ |
+ List<ParameterMirror> get parameters { |
+ if (_parameters == null) { |
+ _parameters = _parametersFromFunctionSignature(mirrors, callMethod, |
+ _functionSignature); |
+ } |
+ return _parameters; |
+ } |
+} |
+ |
+class Dart2JsVoidMirror extends Dart2JsTypeElementMirror { |
+ |
+ Dart2JsVoidMirror(Dart2JsMirrorSystem system, VoidType voidType) |
+ : super(system, voidType); |
+ |
+ VoidType get _voidType => _type; |
+ |
+ String get qualifiedName => simpleName; |
+ |
+ /** |
+ * The void type has no location. |
+ */ |
+ SourceLocation get location => null; |
+ |
+ /** |
+ * The void type has no library. |
+ */ |
+ LibraryMirror get library => null; |
+ |
+ bool get isVoid => true; |
+ |
+ bool operator ==(Object other) { |
+ if (identical(this, other)) { |
+ return true; |
+ } |
+ if (other is! TypeMirror) { |
+ return false; |
+ } |
+ return other.isVoid; |
+ } |
+} |
+ |
+ |
+class Dart2JsDynamicMirror extends Dart2JsTypeElementMirror { |
+ Dart2JsDynamicMirror(Dart2JsMirrorSystem system, InterfaceType voidType) |
+ : super(system, voidType); |
+ |
+ InterfaceType get _dynamicType => _type; |
+ |
+ String get qualifiedName => simpleName; |
+ |
+ /** |
+ * The dynamic type has no location. |
+ */ |
+ SourceLocation get location => null; |
+ |
+ /** |
+ * The dynamic type has no library. |
+ */ |
+ LibraryMirror get library => null; |
+ |
+ bool get isDynamic => true; |
+ |
+ bool operator ==(Object other) { |
+ if (identical(this, other)) { |
+ return true; |
+ } |
+ if (other is! TypeMirror) { |
+ return false; |
+ } |
+ return other.isDynamic; |
+ } |
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Member mirrors implementation. |
+//------------------------------------------------------------------------------ |
+ |
+class Dart2JsMethodMirror extends Dart2JsMemberMirror |
+ implements MethodMirror { |
+ final Dart2JsContainerMirror _objectMirror; |
+ final String simpleName; |
+ final String displayName; |
+ final String constructorName; |
+ final String operatorName; |
+ final Dart2JsMethodKind _kind; |
+ |
+ Dart2JsMethodMirror._internal(Dart2JsContainerMirror objectMirror, |
+ FunctionElement function, |
+ String this.simpleName, |
+ String this.displayName, |
+ String this.constructorName, |
+ String this.operatorName, |
+ Dart2JsMethodKind this._kind) |
+ : this._objectMirror = objectMirror, |
+ super(objectMirror.mirrors, function); |
+ |
+ factory Dart2JsMethodMirror(Dart2JsContainerMirror objectMirror, |
+ FunctionElement function) { |
+ String realName = function.name.slowToString(); |
+ // TODO(ahe): This method should not be calling |
+ // Elements.operatorNameToIdentifier. |
+ String simpleName = |
+ Elements.operatorNameToIdentifier(function.name).slowToString(); |
+ String displayName; |
+ String constructorName = null; |
+ String operatorName = null; |
+ Dart2JsMethodKind kind; |
+ if (function.kind == ElementKind.GETTER) { |
+ kind = Dart2JsMethodKind.GETTER; |
+ displayName = simpleName; |
+ } else if (function.kind == ElementKind.SETTER) { |
+ kind = Dart2JsMethodKind.SETTER; |
+ displayName = simpleName; |
+ simpleName = '$simpleName='; |
+ } else if (function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
+ // TODO(johnniwinther): Support detection of redirecting constructors. |
+ constructorName = ''; |
+ int dollarPos = simpleName.indexOf('\$'); |
+ if (dollarPos != -1) { |
+ constructorName = simpleName.substring(dollarPos + 1); |
+ simpleName = simpleName.substring(0, dollarPos); |
+ // Simple name is TypeName.constructorName. |
+ simpleName = '$simpleName.$constructorName'; |
+ } else { |
+ // Simple name is TypeName. |
+ } |
+ if (function.modifiers.isConst()) { |
+ kind = Dart2JsMethodKind.CONST; |
+ } else { |
+ kind = Dart2JsMethodKind.GENERATIVE; |
+ } |
+ displayName = simpleName; |
+ } else if (function.modifiers.isFactory()) { |
+ kind = Dart2JsMethodKind.FACTORY; |
+ constructorName = ''; |
+ int dollarPos = simpleName.indexOf('\$'); |
+ if (dollarPos != -1) { |
+ constructorName = simpleName.substring(dollarPos+1); |
+ simpleName = simpleName.substring(0, dollarPos); |
+ simpleName = '$simpleName.$constructorName'; |
+ } |
+ // Simple name is TypeName.constructorName. |
+ displayName = simpleName; |
+ } else if (realName == 'unary-') { |
+ kind = Dart2JsMethodKind.OPERATOR; |
+ operatorName = '-'; |
+ // Simple name is 'unary-'. |
+ simpleName = Mirror.UNARY_MINUS; |
+ // Display name is 'operator operatorName'. |
+ displayName = 'operator -'; |
+ } else if (simpleName.startsWith('operator\$')) { |
+ String str = simpleName.substring(9); |
+ simpleName = 'operator'; |
+ kind = Dart2JsMethodKind.OPERATOR; |
+ operatorName = _getOperatorFromOperatorName(str); |
+ // Simple name is 'operator operatorName'. |
+ simpleName = operatorName; |
+ // Display name is 'operator operatorName'. |
+ displayName = 'operator $operatorName'; |
+ } else { |
+ kind = Dart2JsMethodKind.REGULAR; |
+ displayName = simpleName; |
+ } |
+ return new Dart2JsMethodMirror._internal(objectMirror, function, |
+ simpleName, displayName, constructorName, operatorName, kind); |
+ } |
+ |
+ FunctionElement get _function => _element; |
+ |
+ String get qualifiedName |
+ => '${owner.qualifiedName}.$simpleName'; |
+ |
+ DeclarationMirror get owner => _objectMirror; |
+ |
+ bool get isTopLevel => _objectMirror is LibraryMirror; |
+ |
+ bool get isConstructor |
+ => isGenerativeConstructor || isConstConstructor || |
+ isFactoryConstructor || isRedirectingConstructor; |
+ |
+ bool get isMethod => !isConstructor; |
+ |
+ bool get isPrivate => |
+ isConstructor ? _isPrivate(constructorName) : _isPrivate(simpleName); |
+ |
+ bool get isStatic => _function.modifiers.isStatic(); |
+ |
+ List<ParameterMirror> get parameters { |
+ return _parametersFromFunctionSignature(mirrors, this, |
+ _function.computeSignature(mirrors.compiler)); |
+ } |
+ |
+ TypeMirror get returnType => _convertTypeToTypeMirror( |
+ mirrors, _function.computeSignature(mirrors.compiler).returnType, |
+ mirrors.compiler.types.dynamicType); |
+ |
+ bool get isAbstract => _function.isAbstract(mirrors.compiler); |
+ |
+ bool get isRegularMethod => !(isGetter || isSetter || isConstructor); |
+ |
+ bool get isConstConstructor => _kind == Dart2JsMethodKind.CONST; |
+ |
+ bool get isGenerativeConstructor => _kind == Dart2JsMethodKind.GENERATIVE; |
+ |
+ bool get isRedirectingConstructor => _kind == Dart2JsMethodKind.REDIRECTING; |
+ |
+ bool get isFactoryConstructor => _kind == Dart2JsMethodKind.FACTORY; |
+ |
+ bool get isGetter => _kind == Dart2JsMethodKind.GETTER; |
+ |
+ bool get isSetter => _kind == Dart2JsMethodKind.SETTER; |
+ |
+ bool get isOperator => _kind == Dart2JsMethodKind.OPERATOR; |
+} |
+ |
+class Dart2JsFieldMirror extends Dart2JsMemberMirror implements VariableMirror { |
+ Dart2JsContainerMirror _objectMirror; |
+ VariableElement _variable; |
+ |
+ Dart2JsFieldMirror(Dart2JsContainerMirror objectMirror, |
+ VariableElement variable) |
+ : this._objectMirror = objectMirror, |
+ this._variable = variable, |
+ super(objectMirror.mirrors, variable); |
+ |
+ Element get _beginElement => _variable.variables; |
+ |
+ String get qualifiedName |
+ => '${owner.qualifiedName}.$simpleName'; |
+ |
+ DeclarationMirror get owner => _objectMirror; |
+ |
+ bool get isTopLevel => _objectMirror is LibraryMirror; |
+ |
+ bool get isVariable => true; |
+ |
+ bool get isStatic => _variable.modifiers.isStatic(); |
+ |
+ bool get isFinal => _variable.modifiers.isFinal(); |
+ |
+ bool get isConst => _variable.modifiers.isConst(); |
+ |
+ TypeMirror get type => _convertTypeToTypeMirror(mirrors, |
+ _variable.computeType(mirrors.compiler), |
+ mirrors.compiler.types.dynamicType); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// Mirrors on constant values used for metadata. |
+//////////////////////////////////////////////////////////////////////////////// |
+ |
+class Dart2JsConstantMirror extends InstanceMirror { |
+ final Dart2JsMirrorSystem mirrors; |
+ final Constant _constant; |
+ |
+ Dart2JsConstantMirror(this.mirrors, this._constant); |
+ |
+ ClassMirror get type { |
+ return new Dart2JsClassMirror(mirrors, |
+ _constant.computeType(mirrors.compiler).element); |
+ } |
+ |
+ bool get hasReflectee => false; |
+ |
+ get reflectee { |
+ // TODO(johnniwinther): Which exception/error should be thrown here? |
+ throw new UnsupportedError('InstanceMirror does not have a reflectee'); |
+ } |
+ |
+ Future<InstanceMirror> getField(String fieldName) { |
+ // TODO(johnniwinther): Which exception/error should be thrown here? |
+ throw new UnsupportedError('InstanceMirror does not have a reflectee'); |
+ } |
+} |
+ |
+class Dart2JsNullConstantMirror extends Dart2JsConstantMirror { |
+ Dart2JsNullConstantMirror(Dart2JsMirrorSystem mirrors, NullConstant constant) |
+ : super(mirrors, constant); |
+ |
+ NullConstant get _constant => super._constant; |
+ |
+ bool get hasReflectee => true; |
+ |
+ get reflectee => null; |
+} |
+ |
+class Dart2JsBoolConstantMirror extends Dart2JsConstantMirror { |
+ Dart2JsBoolConstantMirror(Dart2JsMirrorSystem mirrors, BoolConstant constant) |
+ : super(mirrors, constant); |
+ |
+ Dart2JsBoolConstantMirror.fromBool(Dart2JsMirrorSystem mirrors, bool value) |
+ : super(mirrors, value ? new TrueConstant() : new FalseConstant()); |
+ |
+ BoolConstant get _constant => super._constant; |
+ |
+ bool get hasReflectee => true; |
+ |
+ get reflectee => _constant is TrueConstant; |
+} |
+ |
+class Dart2JsStringConstantMirror extends Dart2JsConstantMirror { |
+ Dart2JsStringConstantMirror(Dart2JsMirrorSystem mirrors, |
+ StringConstant constant) |
+ : super(mirrors, constant); |
+ |
+ Dart2JsStringConstantMirror.fromString(Dart2JsMirrorSystem mirrors, |
+ String text) |
+ : super(mirrors, |
+ new StringConstant(new DartString.literal(text), null)); |
+ |
+ StringConstant get _constant => super._constant; |
+ |
+ bool get hasReflectee => true; |
+ |
+ get reflectee => _constant.value.slowToString(); |
+} |
+ |
+class Dart2JsNumConstantMirror extends Dart2JsConstantMirror { |
+ Dart2JsNumConstantMirror(Dart2JsMirrorSystem mirrors, |
+ NumConstant constant) |
+ : super(mirrors, constant); |
+ |
+ NumConstant get _constant => super._constant; |
+ |
+ bool get hasReflectee => true; |
+ |
+ get reflectee => _constant.value; |
+} |
+ |
+class Dart2JsListConstantMirror extends Dart2JsConstantMirror |
+ implements ListInstanceMirror { |
+ Dart2JsListConstantMirror(Dart2JsMirrorSystem mirrors, |
+ ListConstant constant) |
+ : super(mirrors, constant); |
+ |
+ ListConstant get _constant => super._constant; |
+ |
+ int get length => _constant.length; |
+ |
+ Future<InstanceMirror> operator[](int index) { |
+ if (index < 0) throw new RangeError('Negative index'); |
+ if (index >= _constant.length) throw new RangeError('Index out of bounds'); |
+ return new Future<InstanceMirror>.value( |
+ _convertConstantToInstanceMirror(mirrors, _constant.entries[index])); |
+ } |
+} |
+ |
+class Dart2JsMapConstantMirror extends Dart2JsConstantMirror |
+ implements MapInstanceMirror { |
+ List<String> _listCache; |
+ |
+ Dart2JsMapConstantMirror(Dart2JsMirrorSystem mirrors, |
+ MapConstant constant) |
+ : super(mirrors, constant); |
+ |
+ MapConstant get _constant => super._constant; |
+ |
+ List<String> get _list { |
+ if (_listCache == null) { |
+ _listCache = new List<String>(_constant.keys.entries.length); |
+ int index = 0; |
+ for (StringConstant keyConstant in _constant.keys.entries) { |
+ _listCache[index] = keyConstant.value.slowToString(); |
+ index++; |
+ } |
+ } |
+ return _listCache; |
+ } |
+ |
+ int get length => _constant.length; |
+ |
+ Iterable<String> get keys { |
+ // TODO(johnniwinther): Return an unmodifiable list instead. |
+ return new List<String>.from(_list); |
+ } |
+ |
+ Future<InstanceMirror> operator[](String key) { |
+ int index = _list.indexOf(key); |
+ if (index == -1) return null; |
+ return new Future<InstanceMirror>.value( |
+ _convertConstantToInstanceMirror(mirrors, _constant.values[index])); |
+ } |
+} |
+ |
+class Dart2JsTypeConstantMirror extends Dart2JsConstantMirror |
+ implements TypeInstanceMirror { |
+ |
+ Dart2JsTypeConstantMirror(Dart2JsMirrorSystem mirrors, |
+ TypeConstant constant) |
+ : super(mirrors, constant); |
+ |
+ TypeConstant get _constant => super._constant; |
+ |
+ TypeMirror get representedType => _convertTypeToTypeMirror( |
+ mirrors, _constant.representedType, mirrors.compiler.types.dynamicType); |
+} |
+ |
+class Dart2JsConstructedConstantMirror extends Dart2JsConstantMirror { |
+ Map<String,Constant> _fieldMapCache; |
+ |
+ Dart2JsConstructedConstantMirror(Dart2JsMirrorSystem mirrors, |
+ ConstructedConstant constant) |
+ : super(mirrors, constant); |
+ |
+ ConstructedConstant get _constant => super._constant; |
+ |
+ Map<String,Constant> get _fieldMap { |
+ if (_fieldMapCache == null) { |
+ _fieldMapCache = new LinkedHashMap<String,Constant>(); |
+ if (identical(_constant.type.element.kind, ElementKind.CLASS)) { |
+ var index = 0; |
+ ClassElement element = _constant.type.element; |
+ element.forEachInstanceField((_, Element field) { |
+ String fieldName = field.name.slowToString(); |
+ _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]); |
+ index++; |
+ }, includeBackendMembers: true, includeSuperMembers: true); |
+ } |
+ } |
+ return _fieldMapCache; |
+ } |
+ |
+ Future<InstanceMirror> getField(String fieldName) { |
+ Constant fieldConstant = _fieldMap[fieldName]; |
+ if (fieldConstant != null) { |
+ return new Future<InstanceMirror>.value( |
+ _convertConstantToInstanceMirror(mirrors, fieldConstant)); |
+ } |
+ return super.getField(fieldName); |
+ } |
+} |
+ |
+class Dart2JsCommentInstanceMirror implements CommentInstanceMirror { |
+ final Dart2JsMirrorSystem mirrors; |
+ final String text; |
+ String _trimmedText; |
+ |
+ Dart2JsCommentInstanceMirror(this.mirrors, this.text); |
+ |
+ ClassMirror get type { |
+ return new Dart2JsClassMirror(mirrors, mirrors.compiler.documentClass); |
+ } |
+ |
+ bool get isDocComment => text.startsWith('/**') || text.startsWith('///'); |
+ |
+ String get trimmedText { |
+ if (_trimmedText == null) { |
+ _trimmedText = stripComment(text); |
+ } |
+ return _trimmedText; |
+ } |
+ |
+ bool get hasReflectee => false; |
+ |
+ get reflectee { |
+ // TODO(johnniwinther): Which exception/error should be thrown here? |
+ throw new UnsupportedError('InstanceMirror does not have a reflectee'); |
+ } |
+ |
+ Future<InstanceMirror> getField(String fieldName) { |
+ if (fieldName == 'isDocComment') { |
+ return new Future.value( |
+ new Dart2JsBoolConstantMirror.fromBool(mirrors, isDocComment)); |
+ } else if (fieldName == 'text') { |
+ return new Future.value( |
+ new Dart2JsStringConstantMirror.fromString(mirrors, text)); |
+ } else if (fieldName == 'trimmedText') { |
+ return new Future.value( |
+ new Dart2JsStringConstantMirror.fromString(mirrors, trimmedText)); |
+ } |
+ // TODO(johnniwinther): Which exception/error should be thrown here? |
+ throw new UnsupportedError('InstanceMirror does not have a reflectee'); |
+ } |
} |