| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // 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 mirrors_dart2js; |
| |
| import 'dart:async'; |
| |
| import '../../compiler.dart' as api; |
| import '../elements/elements.dart'; |
| import '../apiimpl.dart' as apiimpl; |
| import '../scanner/scannerlib.dart'; |
| import '../resolution/resolution.dart' show Scope; |
| import '../dart2jslib.dart'; |
| import '../dart_types.dart'; |
| import '../tree/tree.dart'; |
| import '../util/util.dart' show Spannable, Link; |
| import '../util/characters.dart' show $CR, $LF; |
| |
| 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, isOptional: false, isNamed: false)); |
| link = link.tail; |
| } |
| link = signature.optionalParameters; |
| bool isNamed = signature.optionalParametersAreNamed; |
| while (!link.isEmpty) { |
| parameters.add(new Dart2JsParameterMirror( |
| system, method, link.head, isOptional: true, isNamed: 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>[]; |
| AbstractFieldElement field = element; |
| if (field.getter != null) { |
| members.add(new Dart2JsMethodMirror(library, field.getter)); |
| } |
| if (field.setter != null) { |
| members.add(new Dart2JsMethodMirror(library, field.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; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Analysis entry point. |
| //------------------------------------------------------------------------------ |
| |
| /** |
| * 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]. |
| Future<MirrorSystem> analyze(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'); |
| options.add('--categories=Client,Server'); |
| |
| 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; |
| return compiler.run(null).then((bool success) { |
| if (success && !compilationFailed) { |
| return new Dart2JsMirrorSystem(compiler); |
| } else { |
| throw new StateError('Failed to create mirror system.'); |
| } |
| }); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // 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; |
| |
| /** |
| * 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(); |
| |
| void _appendCommentTokens(Token commentToken) { |
| while (commentToken != null && commentToken.kind == COMMENT_TOKEN) { |
| _metadata.add(new Dart2JsCommentInstanceMirror( |
| mirrors, commentToken.value)); |
| 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); |
| } |
| |
| DeclarationMirror lookupInScope(String name) { |
| // TODO(11653): Support lookup of constructors. |
| Scope scope = _element.buildScope(); |
| Element result; |
| int index = name.indexOf('.'); |
| if (index != -1) { |
| // Lookup [: prefix.id :]. |
| String prefix = name.substring(0, index); |
| String id = name.substring(index+1); |
| result = scope.lookup(prefix); |
| if (result != null && result.isPrefix()) { |
| PrefixElement prefix = result; |
| result = prefix.lookupLocalMember(id); |
| } else { |
| result = null; |
| } |
| } else { |
| // Lookup [: id :]. |
| result = scope.lookup(name); |
| } |
| if (result == null || result.isPrefix()) return null; |
| return _convertElementToDeclarationMirror(mirrors, result); |
| } |
| |
| bool operator ==(var other) { |
| if (identical(this, other)) return true; |
| if (other == null) return false; |
| if (other is! Dart2JsElementMirror) return false; |
| return _element == other._element && |
| owner == other.owner; |
| } |
| |
| int get hashCode { |
| return 13 * _element.hashCode + 17 * owner.hashCode; |
| } |
| } |
| |
| 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()) { |
| // TODO(ahe): I think it is incorrect to filter out classes |
| // and typedefs. See http://dartbug.com/10371. |
| 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; |
| 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; |
| 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: false, |
| bool isNamed: false}) { |
| 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 => true; |
| |
| 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; |
| } |
| |
| bool operator ==(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 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 ==(var 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; |
| |
| 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>{}; |
| } |
| |
| 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; |
| |
| // TODO(johnniwinther): How to show malformed types? |
| bool get isDynamic => _type.isDynamic; |
| |
| 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 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; |
| |
| bool operator ==(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 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 ==(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 ==(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 Dart2JsMethodKind _kind; |
| |
| Dart2JsMethodMirror._internal(Dart2JsContainerMirror objectMirror, |
| FunctionElement function, |
| String this.simpleName, |
| Dart2JsMethodKind this._kind) |
| : this._objectMirror = objectMirror, |
| super(objectMirror.mirrors, function); |
| |
| factory Dart2JsMethodMirror(Dart2JsContainerMirror objectMirror, |
| FunctionElement function) { |
| String realName = function.name; |
| // TODO(ahe): This method should not be calling |
| // Elements.operatorNameToIdentifier. |
| String simpleName = |
| Elements.operatorNameToIdentifier(function.name); |
| Dart2JsMethodKind kind; |
| if (function.kind == ElementKind.GETTER) { |
| kind = Dart2JsMethodKind.GETTER; |
| } else if (function.kind == ElementKind.SETTER) { |
| kind = Dart2JsMethodKind.SETTER; |
| simpleName = '$simpleName='; |
| } else if (function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| // TODO(johnniwinther): Support detection of redirecting constructors. |
| if (function.modifiers.isConst()) { |
| kind = Dart2JsMethodKind.CONST; |
| } else { |
| kind = Dart2JsMethodKind.GENERATIVE; |
| } |
| } else if (function.modifiers.isFactory()) { |
| kind = Dart2JsMethodKind.FACTORY; |
| } else if (realName == 'unary-') { |
| kind = Dart2JsMethodKind.OPERATOR; |
| // Simple name is 'unary-'. |
| simpleName = Mirror.UNARY_MINUS; |
| } else if (simpleName.startsWith('operator\$')) { |
| String str = simpleName.substring(9); |
| simpleName = 'operator'; |
| kind = Dart2JsMethodKind.OPERATOR; |
| simpleName = _getOperatorFromOperatorName(str); |
| } else { |
| kind = Dart2JsMethodKind.REGULAR; |
| } |
| return new Dart2JsMethodMirror._internal(objectMirror, function, |
| simpleName, 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 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; |
| |
| DeclarationMirror lookupInScope(String name) { |
| for (ParameterMirror parameter in parameters) { |
| if (parameter.simpleName == name) { |
| return parameter; |
| } |
| } |
| return super.lookupInScope(name); |
| } |
| } |
| |
| 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'); |
| } |
| |
| 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; |
| |
| InstanceMirror operator[](int index) { |
| if (index < 0) throw new RangeError('Negative index'); |
| if (index >= _constant.length) throw new RangeError('Index out of bounds'); |
| return _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); |
| } |
| |
| InstanceMirror operator[](String key) { |
| int index = _list.indexOf(key); |
| if (index == -1) return null; |
| return _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 Map<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; |
| _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]); |
| index++; |
| }, includeSuperAndInjectedMembers: true); |
| } |
| } |
| return _fieldMapCache; |
| } |
| |
| InstanceMirror getField(String fieldName) { |
| Constant fieldConstant = _fieldMap[fieldName]; |
| if (fieldConstant != null) { |
| return _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'); |
| } |
| |
| InstanceMirror getField(String fieldName) { |
| if (fieldName == 'isDocComment') { |
| return new Dart2JsBoolConstantMirror.fromBool(mirrors, isDocComment); |
| } else if (fieldName == 'text') { |
| return new Dart2JsStringConstantMirror.fromString(mirrors, text); |
| } else if (fieldName == 'trimmedText') { |
| return new Dart2JsStringConstantMirror.fromString(mirrors, trimmedText); |
| } |
| // TODO(johnniwinther): Which exception/error should be thrown here? |
| throw new UnsupportedError('InstanceMirror does not have a reflectee'); |
| } |
| } |
| |
| _convertElementToMembers(Dart2JsLibraryMirror library, Element e) { |
| // TODO(ahe): This method creates new mirror objects which is not correct. |
| if (e.isClass()) { |
| ClassElement classElement = e; |
| classElement.ensureResolved(library.mirrors.compiler); |
| return [new Dart2JsClassMirror.fromLibrary(library, classElement)]; |
| } else if (e.isTypedef()) { |
| return [new Dart2JsTypedefMirror.fromLibrary( |
| library, e.computeType(library.mirrors.compiler))]; |
| } else { |
| return _convertElementMemberToMemberMirrors(library, e); |
| } |
| } |
| |
| /** |
| * Converts [element] into its corresponding [DeclarationMirror], if any. |
| * |
| * If [element] is an [AbstractFieldElement] the mirror for its getter is |
| * returned or, if not present, the mirror for its setter. |
| */ |
| DeclarationMirror _convertElementToDeclarationMirror(Dart2JsMirrorSystem system, |
| Element element) { |
| if (element.isTypeVariable()) { |
| return new Dart2JsTypeVariableMirror( |
| system, element.computeType(system.compiler)); |
| } |
| |
| Dart2JsLibraryMirror library = system._libraryMap[element.getLibrary()]; |
| if (element.isLibrary()) return library; |
| if (element.isTypedef()) { |
| return new Dart2JsTypedefMirror.fromLibrary( |
| library, element.computeType(system.compiler)); |
| } |
| |
| Dart2JsContainerMirror container = library; |
| if (element.getEnclosingClass() != null) { |
| container = new Dart2JsClassMirror.fromLibrary( |
| library, element.getEnclosingClass()); |
| } |
| if (element.isClass()) return container; |
| if (element.isParameter()) { |
| MethodMirror method = _convertElementMethodToMethodMirror( |
| container, element.getOutermostEnclosingMemberOrTopLevel()); |
| // TODO(johnniwinther): Find the right info for [isOptional] and [isNamed]. |
| return new Dart2JsParameterMirror( |
| system, method, element, isOptional: false, isNamed: false); |
| } |
| Iterable<MemberMirror> members = |
| _convertElementMemberToMemberMirrors(container, element); |
| if (members.isEmpty) return null; |
| return members.first; |
| } |
| |
| /** |
| * Experimental API for accessing compilation units defined in a |
| * library. |
| */ |
| // TODO(ahe): Superclasses? Is this really a mirror? |
| class Dart2JsCompilationUnitMirror extends Dart2JsMirror { |
| final Dart2JsLibraryMirror _library; |
| final CompilationUnitElement _element; |
| |
| Dart2JsCompilationUnitMirror(this._element, this._library); |
| |
| Dart2JsMirrorSystem get mirrors => _library.mirrors; |
| |
| List<DeclarationMirror> get members { |
| // TODO(ahe): Should return an immutable List. |
| // TODO(johnniwinther): make sure that these are returned in declaration |
| // order. |
| List<DeclarationMirror> members= <DeclarationMirror>[]; |
| _element.forEachLocalMember((m) { |
| members.addAll(_convertElementToMembers(_library, m)); |
| }); |
| return members; |
| } |
| |
| Uri get uri => _element.script.uri; |
| } |
| |
| /** |
| * Transitional class that allows access to features that have not yet |
| * made it to the mirror API. |
| * |
| * All API in this class is experimental. |
| */ |
| class BackDoor { |
| /// Return the compilation units comprising [library]. |
| static List<Mirror> compilationUnitsOf(Dart2JsLibraryMirror library) { |
| return library._library.compilationUnits.toList().map( |
| (cu) => new Dart2JsCompilationUnitMirror(cu, library)).toList(); |
| } |
| } |