Version 1.4.0-dev.6.4 svn merge -c 35866 https://dart.googlecode.com/svn/branches/bleeding_edge trunk svn merge -c 36037 https://dart.googlecode.com/svn/branches/bleeding_edge trunk svn merge -c 36038 https://dart.googlecode.com/svn/branches/bleeding_edge trunk git-svn-id: http://dart.googlecode.com/svn/trunk@36091 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/docgen/lib/src/models/closure.dart b/pkg/docgen/lib/src/models/closure.dart new file mode 100644 index 0000000..2fcfa19 --- /dev/null +++ b/pkg/docgen/lib/src/models/closure.dart
@@ -0,0 +1,35 @@ +// Copyright (c) 2014, 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 docgen.models.closure; + +import '../exports/source_mirrors.dart'; + +import 'doc_gen_type.dart'; +import 'indexable.dart'; +import 'mirror_based.dart'; +import 'model_helpers.dart'; +import 'parameter.dart'; + +/// A class containing the properties of a function to be called (used in our +/// case specifically to illustrate evidence of the type of function for a +/// parameter). +class Closure extends MirrorBased<FunctionTypeMirror> { + + /// Parameters for this method. + final Map<String, Parameter> parameters; + final DocGenType returnType; + final FunctionTypeMirror mirror; + + Closure(FunctionTypeMirror mirror, Indexable owner) + : returnType = new DocGenType(mirror.returnType, owner.owningLibrary), + parameters = createParameters(mirror.parameters, owner), + mirror = mirror; + + /// Generates a map describing the [Method] object. + Map toMap() => { + 'return': [returnType.toMap()], + 'parameters': recurseMap(parameters), + }; +} \ No newline at end of file
diff --git a/pkg/docgen/lib/src/models/method.dart b/pkg/docgen/lib/src/models/method.dart index 9483a37..f25d53b 100644 --- a/pkg/docgen/lib/src/models/method.dart +++ b/pkg/docgen/lib/src/models/method.dart
@@ -153,4 +153,4 @@ } bool isValidMirror(DeclarationMirror mirror) => mirror is MethodMirror; -} +} \ No newline at end of file
diff --git a/pkg/docgen/lib/src/models/model_helpers.dart b/pkg/docgen/lib/src/models/model_helpers.dart index 48babc9..e5e55a0e 100644 --- a/pkg/docgen/lib/src/models/model_helpers.dart +++ b/pkg/docgen/lib/src/models/model_helpers.dart
@@ -28,15 +28,15 @@ /// Expand the method map [mapToExpand] into a more detailed map that /// separates out setters, getters, constructors, operators, and methods. Map expandMethodMap(Map<String, Method> mapToExpand) => { - 'setters': recurseMap(filterMap(mapToExpand, + 'setters': recurseMap(_filterMap(mapToExpand, (key, val) => val.mirror.isSetter)), - 'getters': recurseMap(filterMap(mapToExpand, + 'getters': recurseMap(_filterMap(mapToExpand, (key, val) => val.mirror.isGetter)), - 'constructors': recurseMap(filterMap(mapToExpand, + 'constructors': recurseMap(_filterMap(mapToExpand, (key, val) => val.mirror.isConstructor)), - 'operators': recurseMap(filterMap(mapToExpand, + 'operators': recurseMap(_filterMap(mapToExpand, (key, val) => val.mirror.isOperator)), - 'methods': recurseMap(filterMap(mapToExpand, + 'methods': recurseMap(_filterMap(mapToExpand, (key, val) => val.mirror.isRegularMethod && !val.mirror.isOperator)) }; @@ -105,7 +105,7 @@ /// Transforms the map by calling toMap on each value in it. Map recurseMap(Map inputMap) { - var outputMap = new SplayTreeMap(); + var outputMap = new LinkedHashMap(); inputMap.forEach((key, value) { if (value is Map) { outputMap[key] = recurseMap(value); @@ -116,14 +116,6 @@ return outputMap; } -Map filterMap(Map map, Function test) { - var exported = new Map(); - map.forEach((key, value) { - if (test(key, value)) exported[key] = value; - }); - return exported; -} - /// Read a pubspec and return the library name given a [LibraryMirror]. String getPackageName(LibraryMirror mirror) { if (mirror.uri.scheme != 'file') return ''; @@ -149,9 +141,9 @@ Map<String, Map<String, DeclarationMirror>> calcExportedItems( LibrarySourceMirror library) { var exports = {}; - exports['classes'] = {}; - exports['methods'] = {}; - exports['variables'] = {}; + exports['classes'] = new SplayTreeMap(); + exports['methods'] = new SplayTreeMap(); + exports['variables'] = new SplayTreeMap(); // Determine the classes, variables and methods that are exported for a // specific dependency. @@ -220,7 +212,7 @@ /// purposes). Map<String, Variable> createVariables(Iterable<VariableMirror> mirrors, Indexable owner) { - var data = {}; + var data = new SplayTreeMap<String, Variable>(); // TODO(janicejl): When map to map feature is created, replace the below // with a filter. Issue(#9590). mirrors.forEach((dart2js_mirrors.Dart2JsFieldMirror mirror) { @@ -238,7 +230,7 @@ /// purposes). Map<String, Method> createMethods(Iterable<MethodMirror> mirrors, Indexable owner) { - var group = new Map<String, Method>(); + var group = new SplayTreeMap<String, Method>(); mirrors.forEach((MethodMirror mirror) { if (includePrivateMembers || !mirror.isPrivate) { group[dart2js_util.nameOf(mirror)] = new Method(mirror, owner); @@ -265,6 +257,14 @@ value: (e) => new Generic(e)); } +Map _filterMap(Map map, bool test(k, v)) { + var exported = new SplayTreeMap(); + map.forEach((key, value) { + if (test(key, value)) exported[key] = value; + }); + return exported; +} + /// Annotations that we do not display in the viewer. const List<String> _SKIPPED_ANNOTATIONS = const [ 'metadata.DocsEditable', '_js_helper.JSName', '_js_helper.Creates',
diff --git a/pkg/docgen/lib/src/models/parameter.dart b/pkg/docgen/lib/src/models/parameter.dart index 2f8798c..ef9d9ab 100644 --- a/pkg/docgen/lib/src/models/parameter.dart +++ b/pkg/docgen/lib/src/models/parameter.dart
@@ -8,6 +8,7 @@ import '../exports/source_mirrors.dart'; import 'annotation.dart'; +import 'closure.dart'; import 'doc_gen_type.dart'; import 'library.dart'; import 'mirror_based.dart'; @@ -25,6 +26,9 @@ final String defaultValue; /// List of the meta annotations on the parameter. final List<Annotation> annotations; + final Library owningLibrary; + // Only non-null if this parameter is a function declaration. + Closure functionDeclaration; Parameter(ParameterMirror mirror, Library owningLibrary) : this.mirror = mirror, @@ -34,16 +38,28 @@ hasDefaultValue = mirror.hasDefaultValue, defaultValue = getDefaultValue(mirror), type = new DocGenType(mirror.type, owningLibrary), - annotations = createAnnotations(mirror, owningLibrary); + annotations = createAnnotations(mirror, owningLibrary), + owningLibrary = owningLibrary { + if (mirror.type is FunctionTypeMirror) { + functionDeclaration = + new Closure(mirror.type as FunctionTypeMirror, owningLibrary); + } + } /// Generates a map describing the [Parameter] object. - Map toMap() => { - 'name': name, - 'optional': isOptional, - 'named': isNamed, - 'default': hasDefaultValue, - 'type': new List.filled(1, type.toMap()), - 'value': defaultValue, - 'annotations': annotations.map((a) => a.toMap()).toList() - }; -} + Map toMap() { + var map = { + 'name': name, + 'optional': isOptional, + 'named': isNamed, + 'default': hasDefaultValue, + 'type': new List.filled(1, type.toMap()), + 'value': defaultValue, + 'annotations': annotations.map((a) => a.toMap()).toList() + }; + if (functionDeclaration != null) { + map['functionDeclaration'] = functionDeclaration.toMap(); + } + return map; + } +} \ No newline at end of file
diff --git a/pkg/docgen/test/constant_argument_test.dart b/pkg/docgen/test/constant_argument_test.dart index ca735f4..6380fdd 100644 --- a/pkg/docgen/test/constant_argument_test.dart +++ b/pkg/docgen/test/constant_argument_test.dart
@@ -42,6 +42,9 @@ var params = functionDef['parameters'] as Map<String, dynamic>; + expect(params.keys, orderedEquals(_PARAM_NAME_ORDER), + reason: 'parameter order must be maintained'); + var vals = {}; params.forEach((paramName, paramHash) { expect(_PARAM_VALUES, contains(paramName)); @@ -53,10 +56,19 @@ } final _PARAM_VALUES = { - "boolConst": "true", "intConst": "42", + "boolConst": "true", "listConst": '[true, 42, "Shanna", null, 3.14, []]', + "stringConst": "\"Shanna\"", "mapConst": startsWith("Map"), - "emptyMap": '{}', - "stringConst": "\"Shanna\"" + "emptyMap": '{}' }; + +const _PARAM_NAME_ORDER = const [ + "intConst", + "boolConst", + "listConst", + "stringConst", + "mapConst", + "emptyMap" +];
diff --git a/pkg/docgen/test/method_param_test.dart b/pkg/docgen/test/method_param_test.dart new file mode 100644 index 0000000..a12840e --- /dev/null +++ b/pkg/docgen/test/method_param_test.dart
@@ -0,0 +1,28 @@ +// Copyright (c) 2014, 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 docgen.test.method_param; + +import 'package:path/path.dart' as path; +import 'package:scheduled_test/scheduled_test.dart'; + +import 'util.dart'; +import '../lib/docgen.dart' as gen; + +void main() { + test('method function parameters', () { + var lib_file = path.toUri(path.join(getMultiLibraryCodePath(), 'lib', + 'test_lib2.dart')); + return gen.getMirrorSystem([lib_file], false) + .then((mirrorSystem) { + var library = new gen.Library(mirrorSystem.libraries[lib_file]); + + // Test that libraries do recursive exports correctly. + var funcParams = library.functions['fooFunc'].parameters; + expect('Symbol("dart.core.int")', library.functions['fooFunc'] + .parameters['fooFuncParam'].functionDeclaration.parameters['x'] + .type.mirror.qualifiedName.toString()); + }); + }); +} \ No newline at end of file
diff --git a/pkg/docgen/test/multi_library_code/lib/test_lib2.dart b/pkg/docgen/test/multi_library_code/lib/test_lib2.dart index d9fa7ee..b28f6d8 100644 --- a/pkg/docgen/test/multi_library_code/lib/test_lib2.dart +++ b/pkg/docgen/test/multi_library_code/lib/test_lib2.dart
@@ -5,3 +5,5 @@ library test_lib2; export 'test_lib2_foo.dart'; + +String fooFunc(bool fooFuncParam(int x)) => 'hi'; \ No newline at end of file
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart index 1b19fbf..2592a72 100644 --- a/sdk/lib/_internal/lib/js_helper.dart +++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -1097,16 +1097,19 @@ class JsCache { /// Returns a JavaScript object suitable for use as a cache. static allocate() { - var result = JS('=Object', '{x:0}'); + var result = JS('=Object', 'Object.create(null)'); // Deleting a property makes V8 assume that it shouldn't create a hidden // class for [result] and map transitions. Although these map transitions // pay off if there are many cache hits for the same keys, it becomes // really slow when there aren't many repeated hits. + JS('void', '#.x=0', result); JS('void', 'delete #.x', result); return result; } - static fetch(cache, String key) => JS('', '#[#]', cache, key); + static fetch(cache, String key) { + return JS('', '#[#]', cache, key); + } static void update(cache, String key, value) { JS('void', '#[#] = #', cache, key, value);
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart index e7ebddb..fdf7393 100644 --- a/sdk/lib/_internal/lib/js_mirrors.dart +++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -1064,7 +1064,7 @@ var cache = _getterCache; if (isMissingCache(cache)) { if ((_getterCache = --cache) != 0) return result; - cache = _getterCache = JS('=Object', '({})'); + cache = _getterCache = JS('=Object', 'Object.create(null)'); } // Make sure that symbol [fieldName] has a cache probing function ($p).
diff --git a/tests/lib/mirrors/get_field_cache_test.dart b/tests/lib/mirrors/get_field_cache_test.dart new file mode 100644 index 0000000..4c71dbc --- /dev/null +++ b/tests/lib/mirrors/get_field_cache_test.dart
@@ -0,0 +1,36 @@ +// Copyright (c) 2014, 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. + +@MirrorsUsed(targets: const ["A", "B"]) +import 'dart:mirrors'; + +import 'package:expect/expect.dart'; + +class A { + toString() => "A"; +} + +class B { + int x = 99; + toString() => "B"; +} + +void main() { + var a = new A(); + var am = reflect(a); + for (int i = 0; i < 10; i++) { + // Adds a probe function on the symbol. + am.getField(#toString); + } + var b = new B(); + var bm = reflect(b); + for (int i = 0; i < 10; i++) { + // Adds a field-cache on the mirror. + bm.getField(#x); + } + // There is a cache now, but the cache should not contain 'toString' from + // JavaScript's Object.prototype. + var toString = bm.getField(#toString).reflectee; + Expect.equals("B", toString()); +}
diff --git a/tests/lib/mirrors/invocation_cache_test.dart b/tests/lib/mirrors/invocation_cache_test.dart new file mode 100644 index 0000000..0d9624a --- /dev/null +++ b/tests/lib/mirrors/invocation_cache_test.dart
@@ -0,0 +1,19 @@ +// Copyright (c) 2014, 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. + +@MirrorsUsed(targets: const ["A"]) +import 'dart:mirrors'; + +import 'package:expect/expect.dart'; + +class A { + toString() => "A"; +} + +main() { + // The invocation cache must not find the 'toString' from JavaScript's + // Object.prototype. + var toString = reflect(new A()).getField(#toString).reflectee; + Expect.equals("A", Function.apply(toString, [], {})); +}
diff --git a/tools/VERSION b/tools/VERSION index 962d60b..423c53d 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -28,4 +28,4 @@ MINOR 4 PATCH 0 PRERELEASE 6 -PRERELEASE_PATCH 4 +PRERELEASE_PATCH 5