| // Copyright (c) 2017, 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. | |
| import 'dart:convert'; | |
| import 'package:analysis_server/src/computer/computer_outline.dart'; | |
| import 'package:analyzer/src/test_utilities/test_code_format.dart'; | |
| import 'package:analyzer_plugin/protocol/protocol_common.dart'; | |
| import 'package:analyzer_testing/src/abstract_context.dart'; | |
| import 'package:test/test.dart'; | |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| import '../../utils/test_code_extensions.dart'; | |
| void main() { | |
| defineReflectiveSuite(() { | |
| defineReflectiveTests(FlutterOutlineComputerTest); | |
| defineReflectiveTests(OutlineComputerTest); | |
| }); | |
| } | |
| class AbstractOutlineComputerTest extends AbstractContextTest { | |
| late TestCode parsedTestCode; | |
| late String testPath; | |
| late String testCode; | |
| @override | |
| void setUp() { | |
| super.setUp(); | |
| testPath = convertPath('$testPackageLibPath/test.dart'); | |
| } | |
| Future<Outline> _computeOutline(String code) async { | |
| parsedTestCode = TestCode.parseNormalized(code); | |
| testCode = parsedTestCode.code; | |
| newFile(testPath, testCode); | |
| var resolveResult = await getResolvedUnit(testFile); | |
| return DartUnitOutlineComputer( | |
| resolveResult, | |
| withBasicFlutter: true, | |
| ).compute(); | |
| } | |
| } | |
| @reflectiveTest | |
| class FlutterOutlineComputerTest extends AbstractOutlineComputerTest { | |
| @override | |
| bool get addFlutterPackageDep => true; | |
| Future<void> test_columnWithChildren() async { | |
| var unitOutline = await _computeOutline(''' | |
| import 'package:flutter/widgets.dart'; | |
| class MyWidget extends StatelessWidget { | |
| @override | |
| Widget build(BuildContext context) { | |
| return new Column(children: [ | |
| const Text('aaa'), | |
| const Text('bbb'), | |
| ]); // Column | |
| } | |
| } | |
| '''); | |
| expect(_toText(unitOutline), r''' | |
| MyWidget | |
| build | |
| Column | |
| Text('aaa') | |
| Text('bbb') | |
| '''); | |
| var myWidget = unitOutline.children![0]; | |
| var build = myWidget.children![0]; | |
| var columnOutline = build.children![0]; | |
| { | |
| var offset = testCode.indexOf('new Column'); | |
| var length = testCode.indexOf('; // Column') - offset; | |
| _expect( | |
| columnOutline, | |
| name: 'Column', | |
| elementOffset: offset, | |
| offset: offset, | |
| length: length, | |
| ); | |
| } | |
| { | |
| var textOutline = columnOutline.children![0]; | |
| var text = "const Text('aaa')"; | |
| var offset = testCode.indexOf(text); | |
| _expect( | |
| textOutline, | |
| name: "Text('aaa')", | |
| elementOffset: offset, | |
| offset: offset, | |
| length: text.length, | |
| ); | |
| } | |
| { | |
| var textOutline = columnOutline.children![1]; | |
| var text = "const Text('bbb')"; | |
| var offset = testCode.indexOf(text); | |
| _expect( | |
| textOutline, | |
| name: "Text('bbb')", | |
| elementOffset: offset, | |
| offset: offset, | |
| length: text.length, | |
| ); | |
| } | |
| } | |
| void _expect( | |
| Outline outline, { | |
| required String name, | |
| required int elementOffset, | |
| required int offset, | |
| required int length, | |
| }) { | |
| var element = outline.element; | |
| expect(element.name, name); | |
| expect(element.location!.offset, elementOffset); | |
| expect(outline.offset, offset); | |
| expect(outline.length, length); | |
| } | |
| static String _toText(Outline outline) { | |
| var buffer = StringBuffer(); | |
| void writeOutline(Outline outline, String indent) { | |
| buffer.write(indent); | |
| buffer.writeln(outline.element.name); | |
| for (var child in outline.children ?? const <Outline>[]) { | |
| writeOutline(child, '$indent '); | |
| } | |
| } | |
| for (var child in outline.children!) { | |
| writeOutline(child, ''); | |
| } | |
| return buffer.toString(); | |
| } | |
| } | |
| @reflectiveTest | |
| class OutlineComputerTest extends AbstractOutlineComputerTest { | |
| @override | |
| bool get addMetaPackageDep => true; | |
| void assertJson(Object object, Map<String, dynamic> expected) { | |
| var expectedJson = JsonEncoder.withIndent(' ').convert(expected); | |
| var actual = JsonEncoder.withIndent(' ').convert(object); | |
| if (actual != expectedJson) { | |
| print('-----'); | |
| print(actual); | |
| print('-----'); | |
| } | |
| expect(actual, expectedJson); | |
| } | |
| Matcher hasCodeOffsetLength(TestCodeRange range) { | |
| return TypeMatcher<Outline>() | |
| .having( | |
| (outline) => outline.codeOffset, | |
| 'codeOffset', | |
| range.sourceRange.offset, | |
| ) | |
| .having( | |
| (outline) => outline.codeLength, | |
| 'codeLength', | |
| range.sourceRange.length, | |
| ); | |
| } | |
| Matcher hasElementOffsetLength(TestCodeRange range) { | |
| return TypeMatcher<Element>() | |
| .having( | |
| (element) => element.location?.offset, | |
| 'offset', | |
| range.sourceRange.offset, | |
| ) | |
| .having( | |
| (element) => element.location?.length, | |
| 'length', | |
| range.sourceRange.length, | |
| ); | |
| } | |
| Matcher hasOffsetLength(TestCodeRange range) { | |
| return TypeMatcher<Outline>() | |
| .having((outline) => outline.offset, 'offset', range.sourceRange.offset) | |
| .having( | |
| (outline) => outline.length, | |
| 'length', | |
| range.sourceRange.length, | |
| ); | |
| } | |
| Future<void> test_class() async { | |
| var unitOutline = await _computeOutline(''' | |
| abstract class A<K, V> { | |
| int fa, fb; | |
| String fc; | |
| A(int i, String s); | |
| A.name(num p); | |
| A._privateName(num p); | |
| static String ma(int pa) => null; | |
| _mb(int pb); | |
| R mc<R, P>(P p) {} | |
| String get propA => null; | |
| set propB(int v) {} | |
| } | |
| class B { | |
| B(int p); | |
| } | |
| String fa(int pa) => null; | |
| R fb<R, P>(P p) {} | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(4)); | |
| // A | |
| { | |
| var outline_A = topOutlines[0]; | |
| var element_A = outline_A.element; | |
| expect(element_A.kind, ElementKind.CLASS); | |
| expect(element_A.name, 'A'); | |
| expect(element_A.typeParameters, '<K, V>'); | |
| { | |
| var location = element_A.location!; | |
| expect(location.offset, testCode.indexOf('A<K, V> {')); | |
| expect(location.length, 1); | |
| } | |
| expect(element_A.parameters, null); | |
| expect(element_A.returnType, null); | |
| // A children | |
| var outlines_A = outline_A.children!; | |
| expect(outlines_A, hasLength(11)); | |
| { | |
| var outline = outlines_A[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FIELD); | |
| expect(element.name, 'fa'); | |
| expect(element.parameters, isNull); | |
| expect(element.returnType, 'int'); | |
| } | |
| { | |
| var outline = outlines_A[1]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FIELD); | |
| expect(element.name, 'fb'); | |
| expect(element.parameters, isNull); | |
| expect(element.returnType, 'int'); | |
| } | |
| { | |
| var outline = outlines_A[2]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FIELD); | |
| expect(element.name, 'fc'); | |
| expect(element.parameters, isNull); | |
| expect(element.returnType, 'String'); | |
| } | |
| { | |
| var outline = outlines_A[3]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CONSTRUCTOR); | |
| expect(element.name, 'A'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('A(int i, String s);')); | |
| expect(location.length, 'A'.length); | |
| } | |
| expect(element.parameters, '(int i, String s)'); | |
| expect(element.returnType, isNull); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isFalse); | |
| } | |
| { | |
| var outline = outlines_A[4]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CONSTRUCTOR); | |
| expect(element.name, 'A.name'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('name(num p);')); | |
| expect(location.length, 'name'.length); | |
| } | |
| expect(element.parameters, '(num p)'); | |
| expect(element.returnType, isNull); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isFalse); | |
| } | |
| { | |
| var outline = outlines_A[5]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CONSTRUCTOR); | |
| expect(element.name, 'A._privateName'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('_privateName(num p);')); | |
| expect(location.length, '_privateName'.length); | |
| } | |
| expect(element.parameters, '(num p)'); | |
| expect(element.returnType, isNull); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isFalse); | |
| } | |
| { | |
| var outline = outlines_A[6]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.METHOD); | |
| expect(element.name, 'ma'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('ma(int pa) => null;')); | |
| expect(location.length, 'ma'.length); | |
| } | |
| expect(element.parameters, '(int pa)'); | |
| expect(element.returnType, 'String'); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isTrue); | |
| } | |
| { | |
| var outline = outlines_A[7]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.METHOD); | |
| expect(element.name, '_mb'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('_mb(int pb);')); | |
| expect(location.length, '_mb'.length); | |
| } | |
| expect(element.parameters, '(int pb)'); | |
| expect(element.returnType, ''); | |
| expect(element.isAbstract, isTrue); | |
| expect(element.isStatic, isFalse); | |
| } | |
| { | |
| var outline = outlines_A[8]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.METHOD); | |
| expect(element.name, 'mc'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('mc<R, P>')); | |
| expect(location.length, 'mc'.length); | |
| } | |
| expect(element.parameters, '(P p)'); | |
| expect(element.returnType, 'R'); | |
| expect(element.typeParameters, '<R, P>'); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isFalse); | |
| } | |
| { | |
| var outline = outlines_A[9]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.GETTER); | |
| expect(element.name, 'propA'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('propA => null;')); | |
| expect(location.length, 'propA'.length); | |
| } | |
| expect(element.parameters, isNull); | |
| expect(element.returnType, 'String'); | |
| } | |
| { | |
| var outline = outlines_A[10]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.SETTER); | |
| expect(element.name, 'propB'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('propB(int v) {}')); | |
| expect(location.length, 'propB'.length); | |
| } | |
| expect(element.parameters, '(int v)'); | |
| expect(element.returnType, ''); | |
| } | |
| } | |
| // B | |
| { | |
| var outline_B = topOutlines[1]; | |
| var element_B = outline_B.element; | |
| expect(element_B.kind, ElementKind.CLASS); | |
| expect(element_B.name, 'B'); | |
| expect(element_B.typeParameters, isNull); | |
| { | |
| var location = element_B.location!; | |
| expect(location.offset, testCode.indexOf('B {')); | |
| expect(location.length, 1); | |
| } | |
| expect(element_B.parameters, null); | |
| expect(element_B.returnType, null); | |
| // B children | |
| var outlines_B = outline_B.children!; | |
| expect(outlines_B, hasLength(1)); | |
| { | |
| var outline = outlines_B[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CONSTRUCTOR); | |
| expect(element.name, 'B'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('B(int p);')); | |
| expect(location.length, 'B'.length); | |
| } | |
| expect(element.parameters, '(int p)'); | |
| expect(element.returnType, isNull); | |
| } | |
| } | |
| { | |
| var outline = topOutlines[2]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION); | |
| expect(element.name, 'fa'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('fa(int pa)')); | |
| expect(location.length, 'ma'.length); | |
| } | |
| expect(element.parameters, '(int pa)'); | |
| expect(element.returnType, 'String'); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isTrue); | |
| } | |
| { | |
| var outline = topOutlines[3]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION); | |
| expect(element.name, 'fb'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('fb<R, P>')); | |
| expect(location.length, 'fb'.length); | |
| } | |
| expect(element.parameters, '(P p)'); | |
| expect(element.returnType, 'R'); | |
| expect(element.typeParameters, '<R, P>'); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isTrue); | |
| } | |
| } | |
| Future<void> test_class_augment() async { | |
| newFile('$testPackageLibPath/a.dart', ''' | |
| part 'test.dart'; | |
| class C { | |
| // Ensure that the outline for the augment doesn't include members from the | |
| // augmented class. | |
| void n() {} | |
| } | |
| '''); | |
| var unitOutline = await _computeOutline(''' | |
| part of 'a.dart'; | |
| augment class C { | |
| String f = ''; | |
| C(); | |
| C.named(); | |
| void m() {} | |
| augment m() {} | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // C | |
| var outline_C = topOutlines[0]; | |
| var element_C = outline_C.element; | |
| expect(element_C.kind, ElementKind.CLASS); | |
| expect(element_C.name, 'C'); | |
| // C children | |
| var outlines_C = outline_C.children!; | |
| expect(outlines_C, hasLength(5)); | |
| // C.f | |
| var outline_f = outlines_C[0]; | |
| var element_f = outline_f.element; | |
| expect(element_f.kind, ElementKind.FIELD); | |
| expect(element_f.name, 'f'); | |
| // C.new | |
| var outline_new = outlines_C[1]; | |
| var element_new = outline_new.element; | |
| expect(element_new.kind, ElementKind.CONSTRUCTOR); | |
| expect(element_new.name, 'C'); | |
| // C.named | |
| var outline_named = outlines_C[2]; | |
| var element_named = outline_named.element; | |
| expect(element_named.kind, ElementKind.CONSTRUCTOR); | |
| expect(element_named.name, 'C.named'); | |
| // C.m | |
| var outline_m = outlines_C[3]; | |
| var element_m = outline_m.element; | |
| expect(element_m.kind, ElementKind.METHOD); | |
| expect(element_m.name, 'm'); | |
| expect(element_m.location?.offset, testCode.indexOf('m()')); | |
| // C.m augmented | |
| var outline_ma = outlines_C[4]; | |
| var element_ma = outline_ma.element; | |
| expect(element_ma.kind, ElementKind.METHOD); | |
| expect(element_ma.name, 'm'); | |
| expect( | |
| element_ma.location?.offset, | |
| testCode.indexOf('m()', testCode.indexOf('m()') + 1), | |
| ); | |
| } | |
| Future<void> test_emptyBodies() async { | |
| var unitOutline = await _computeOutline(''' | |
| class /*[0*/A/*0]*/; | |
| mixin /*[1*/M/*1]*/; | |
| enum /*[2*/En/*2]*/; | |
| extension /*[3*/Ex1/*3]*/ on String; | |
| extension /*[4*/Ex2/*4]*/; | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| void expectItem(int i, String expectedName) { | |
| var expectedRange = parsedTestCode.ranges[i]; | |
| var actualElement = topOutlines[i].element; | |
| expect(actualElement.name, expectedName); | |
| expect(actualElement, hasElementOffsetLength(expectedRange)); | |
| } | |
| expectItem(0, 'A'); | |
| expectItem(1, 'M'); | |
| expectItem(2, 'En'); | |
| expectItem(3, 'Ex1'); | |
| expectItem(4, 'Ex2'); | |
| } | |
| Future<void> test_enum_constants() async { | |
| var unitOutline = await _computeOutline(''' | |
| /*[0*/enum /*[1*/E/*1]*/ { | |
| /*[2*/v1/*2]*/, /*[3*/v2/*3]*/ | |
| }/*0]*/ | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| assertJson(topOutlines[0], { | |
| 'element': { | |
| 'kind': 'ENUM', | |
| 'name': 'E', | |
| 'location': _elementLocation(parsedTestCode.ranges[1]), | |
| 'flags': 0, | |
| }, | |
| ..._location(parsedTestCode.ranges[0], parsedTestCode.ranges[0]), | |
| 'children': [ | |
| { | |
| 'element': { | |
| 'kind': 'ENUM_CONSTANT', | |
| 'name': 'v1', | |
| 'location': _elementLocation(parsedTestCode.ranges[2]), | |
| 'flags': 0, | |
| }, | |
| ..._location(parsedTestCode.ranges[2], parsedTestCode.ranges[2]), | |
| }, | |
| { | |
| 'element': { | |
| 'kind': 'ENUM_CONSTANT', | |
| 'name': 'v2', | |
| 'location': _elementLocation(parsedTestCode.ranges[3]), | |
| 'flags': 0, | |
| }, | |
| ..._location(parsedTestCode.ranges[3], parsedTestCode.ranges[3]), | |
| }, | |
| ], | |
| }); | |
| } | |
| Future<void> test_enum_members() async { | |
| var unitOutline = await _computeOutline(''' | |
| /*[0*/enum /*[1*/E/*1]*/ { | |
| /*[2*/v/*2]*/; | |
| /*[3*/final int /*[4*//*[5*/f/*4]*/ = 0/*5]*/;/*3]*/ | |
| /*[6*/const /*[7*/E/*7]*/();/*6]*/ | |
| /*[8*/const E./*[9*/named/*9]*/();/*8]*/ | |
| /*[10*/void /*[11*/aMethod/*11]*/() {}/*10]*/; | |
| /*[12*/int get /*[13*/aGetter/*13]*/ => 0;/*12]*/ | |
| /*[14*/set /*[15*/aSetter/*15]*/(int value) {}/*14]*/; | |
| }/*0]*/ | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| assertJson(topOutlines[0], { | |
| 'element': { | |
| 'kind': 'ENUM', | |
| 'name': 'E', | |
| 'location': _elementLocation(parsedTestCode.ranges[1]), | |
| 'flags': 0, | |
| }, | |
| ..._location(parsedTestCode.ranges[0], parsedTestCode.ranges[0]), | |
| 'children': [ | |
| { | |
| 'element': { | |
| 'kind': 'ENUM_CONSTANT', | |
| 'name': 'v', | |
| 'location': _elementLocation(parsedTestCode.ranges[2]), | |
| 'flags': 0, | |
| }, | |
| ..._location(parsedTestCode.ranges[2], parsedTestCode.ranges[2]), | |
| }, | |
| { | |
| 'element': { | |
| 'kind': 'FIELD', | |
| 'name': 'f', | |
| 'location': _elementLocation(parsedTestCode.ranges[4]), | |
| 'flags': 4, | |
| 'returnType': 'int', | |
| }, | |
| ..._location(parsedTestCode.ranges[3], parsedTestCode.ranges[5]), | |
| }, | |
| { | |
| 'element': { | |
| 'kind': 'CONSTRUCTOR', | |
| 'name': 'E', | |
| 'location': _elementLocation(parsedTestCode.ranges[7]), | |
| 'flags': 0, | |
| 'parameters': '()', | |
| }, | |
| ..._location(parsedTestCode.ranges[6], parsedTestCode.ranges[6]), | |
| }, | |
| { | |
| 'element': { | |
| 'kind': 'CONSTRUCTOR', | |
| 'name': 'E.named', | |
| 'location': _elementLocation(parsedTestCode.ranges[9]), | |
| 'flags': 0, | |
| 'parameters': '()', | |
| }, | |
| ..._location(parsedTestCode.ranges[8], parsedTestCode.ranges[8]), | |
| }, | |
| { | |
| 'element': { | |
| 'kind': 'METHOD', | |
| 'name': 'aMethod', | |
| 'location': _elementLocation(parsedTestCode.ranges[11]), | |
| 'flags': 0, | |
| 'parameters': '()', | |
| 'returnType': 'void', | |
| }, | |
| ..._location(parsedTestCode.ranges[10], parsedTestCode.ranges[10]), | |
| }, | |
| { | |
| 'element': { | |
| 'kind': 'GETTER', | |
| 'name': 'aGetter', | |
| 'location': _elementLocation(parsedTestCode.ranges[13]), | |
| 'flags': 0, | |
| 'returnType': 'int', | |
| }, | |
| ..._location(parsedTestCode.ranges[12], parsedTestCode.ranges[12]), | |
| }, | |
| { | |
| 'element': { | |
| 'kind': 'SETTER', | |
| 'name': 'aSetter', | |
| 'location': _elementLocation(parsedTestCode.ranges[15]), | |
| 'flags': 0, | |
| 'parameters': '(int value)', | |
| 'returnType': '', | |
| }, | |
| ..._location(parsedTestCode.ranges[14], parsedTestCode.ranges[14]), | |
| }, | |
| ], | |
| }); | |
| } | |
| Future<void> test_extension_named() async { | |
| var unitOutline = await _computeOutline(''' | |
| extension MyExt on String { | |
| int get halfLength => length ~/ 2; | |
| void writeOn(StringBuffer b) { | |
| b.write(this); | |
| } | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // MyExt | |
| { | |
| var outline_MyExt = topOutlines[0]; | |
| var element_MyExt = outline_MyExt.element; | |
| expect(element_MyExt.kind, ElementKind.EXTENSION); | |
| expect(element_MyExt.name, 'MyExt'); | |
| { | |
| var location = element_MyExt.location!; | |
| expect(location.offset, testCode.indexOf('MyExt on')); | |
| expect(location.length, 'MyExt'.length); | |
| } | |
| expect(element_MyExt.parameters, null); | |
| expect(element_MyExt.returnType, null); | |
| // StringUtilities children | |
| var outlines_MyExt = outline_MyExt.children; | |
| expect(outlines_MyExt, hasLength(2)); | |
| } | |
| } | |
| Future<void> test_extension_unnamed() async { | |
| var unitOutline = await _computeOutline(''' | |
| extension on String { | |
| int get halfLength => length ~/ 2; | |
| void writeOn(StringBuffer b) { | |
| b.write(this); | |
| } | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // MyExt | |
| { | |
| var outline_MyExt = topOutlines[0]; | |
| var element_MyExt = outline_MyExt.element; | |
| expect(element_MyExt.kind, ElementKind.EXTENSION); | |
| expect(element_MyExt.name, ''); | |
| { | |
| var location = element_MyExt.location!; | |
| expect(location.offset, testCode.indexOf('String')); | |
| expect(location.length, 'String'.length); | |
| } | |
| expect(element_MyExt.parameters, null); | |
| expect(element_MyExt.returnType, null); | |
| // StringUtilities children | |
| var outlines_MyExt = outline_MyExt.children; | |
| expect(outlines_MyExt, hasLength(2)); | |
| } | |
| } | |
| Future<void> test_extensionType() async { | |
| var unitOutline = await _computeOutline(''' | |
| extension type A(int it) { | |
| int get foo => 0; | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // MyExt | |
| { | |
| var outline = topOutlines[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.EXTENSION_TYPE); | |
| expect(element.name, 'A'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('A')); | |
| expect(location.length, 'A'.length); | |
| } | |
| expect(element.parameters, null); | |
| expect(element.returnType, null); | |
| var outlines_A = outline.children; | |
| expect(outlines_A, hasLength(1)); | |
| } | |
| } | |
| Future<void> test_factoryMethod_before() async { | |
| var unitOutline = await _computeOutline(''' | |
| // @dart=3.10 | |
| class C { | |
| factory() => C(); | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| var outline_C = topOutlines[0]; | |
| var element_C = outline_C.element; | |
| expect(element_C.kind, ElementKind.CLASS); | |
| expect(element_C.name, 'C'); | |
| var outlines_C = outline_C.children!; | |
| expect(outlines_C, hasLength(1)); | |
| var outline = outlines_C[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.METHOD); | |
| expect(element.name, 'factory'); | |
| } | |
| Future<void> test_genericTypeAlias_functionType() async { | |
| var unitOutline = await _computeOutline(''' | |
| typedef F = void Function(); | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // F | |
| var outline_F = topOutlines[0]; | |
| var element_F = outline_F.element; | |
| expect(element_F.kind, ElementKind.FUNCTION_TYPE_ALIAS); | |
| expect(element_F.name, 'F'); | |
| { | |
| var location = element_F.location!; | |
| expect(location.offset, testCode.indexOf('F =')); | |
| expect(location.length, 'F'.length); | |
| } | |
| expect(element_F.aliasedType, 'void Function()'); | |
| expect(element_F.parameters, '()'); | |
| expect(element_F.returnType, 'void'); | |
| expect(element_F.typeParameters, isNull); | |
| } | |
| Future<void> test_genericTypeAlias_functionType_noReturnType() async { | |
| var unitOutline = await _computeOutline(''' | |
| typedef F = Function(); | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // F | |
| var outline_F = topOutlines[0]; | |
| var element_F = outline_F.element; | |
| expect(element_F.kind, ElementKind.FUNCTION_TYPE_ALIAS); | |
| expect(element_F.name, 'F'); | |
| { | |
| var location = element_F.location!; | |
| expect(location.offset, testCode.indexOf('F =')); | |
| expect(location.length, 'F'.length); | |
| } | |
| expect(element_F.aliasedType, ' Function()'); | |
| expect(element_F.parameters, '()'); | |
| expect(element_F.returnType, ''); | |
| expect(element_F.typeParameters, isNull); | |
| } | |
| Future<void> test_genericTypeAlias_interfaceType() async { | |
| var unitOutline = await _computeOutline(''' | |
| typedef F<T> = Map<int, T>; | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // F | |
| var outline_F = topOutlines[0]; | |
| var element_F = outline_F.element; | |
| expect(element_F.kind, ElementKind.TYPE_ALIAS); | |
| expect(element_F.name, 'F'); | |
| { | |
| var location = element_F.location!; | |
| expect(location.offset, testCode.indexOf('F<T> =')); | |
| expect(location.length, 'F'.length); | |
| } | |
| expect(element_F.aliasedType, 'Map<int, T>'); | |
| expect(element_F.parameters, isNull); | |
| expect(element_F.returnType, isNull); | |
| expect(element_F.typeParameters, '<T>'); | |
| } | |
| Future<void> test_groupAndTest() async { | |
| var outline = await _computeOutline(''' | |
| void group(name, closure) {} | |
| void test(name) {} | |
| void f() { | |
| group('group1', () { | |
| group('group1_1', () { | |
| test('test1_1_1'); | |
| test('test1_1_2'); | |
| }); | |
| group('group1_2', () { | |
| test('test1_2_1'); | |
| }); | |
| }); | |
| group('group2', () { | |
| test('test2_1'); | |
| test('test2_2'); | |
| }); | |
| } | |
| '''); | |
| // unit | |
| var unit_children = outline.children!; | |
| expect(unit_children, hasLength(3)); | |
| // f | |
| var f_outline = unit_children[2]; | |
| _expect( | |
| f_outline, | |
| kind: ElementKind.FUNCTION, | |
| name: 'f', | |
| offset: testCode.indexOf('f() {'), | |
| parameters: '()', | |
| returnType: 'void', | |
| ); | |
| var f_children = f_outline.children!; | |
| expect(f_children, hasLength(2)); | |
| // group1 | |
| var group1_outline = f_children[0]; | |
| _expect( | |
| group1_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 5, | |
| name: 'group("group1")', | |
| offset: testCode.indexOf("group('group1'"), | |
| ); | |
| var group1_children = group1_outline.children!; | |
| expect(group1_children, hasLength(2)); | |
| // group1_1 | |
| var group1_1_outline = group1_children[0]; | |
| _expect( | |
| group1_1_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 5, | |
| name: 'group("group1_1")', | |
| offset: testCode.indexOf("group('group1_1'"), | |
| ); | |
| var group1_1_children = group1_1_outline.children!; | |
| expect(group1_1_children, hasLength(2)); | |
| // test1_1_1 | |
| var test1_1_1_outline = group1_1_children[0]; | |
| _expect( | |
| test1_1_1_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 4, | |
| name: 'test("test1_1_1")', | |
| offset: testCode.indexOf("test('test1_1_1'"), | |
| ); | |
| // test1_1_1 | |
| var test1_1_2_outline = group1_1_children[1]; | |
| _expect( | |
| test1_1_2_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 4, | |
| name: 'test("test1_1_2")', | |
| offset: testCode.indexOf("test('test1_1_2'"), | |
| ); | |
| // group1_2 | |
| var group1_2_outline = group1_children[1]; | |
| _expect( | |
| group1_2_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 5, | |
| name: 'group("group1_2")', | |
| offset: testCode.indexOf("group('group1_2'"), | |
| ); | |
| var group1_2_children = group1_2_outline.children!; | |
| expect(group1_2_children, hasLength(1)); | |
| // test2_1 | |
| var test1_2_1_outline = group1_2_children[0]; | |
| _expect( | |
| test1_2_1_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 4, | |
| name: 'test("test1_2_1")', | |
| offset: testCode.indexOf("test('test1_2_1'"), | |
| ); | |
| // group2 | |
| var group2_outline = f_children[1]; | |
| _expect( | |
| group2_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 5, | |
| name: 'group("group2")', | |
| offset: testCode.indexOf("group('group2'"), | |
| ); | |
| var group2_children = group2_outline.children!; | |
| expect(group2_children, hasLength(2)); | |
| // test2_1 | |
| var test2_1_outline = group2_children[0]; | |
| _expect( | |
| test2_1_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 4, | |
| name: 'test("test2_1")', | |
| offset: testCode.indexOf("test('test2_1'"), | |
| ); | |
| // test2_2 | |
| var test2_2_outline = group2_children[1]; | |
| _expect( | |
| test2_2_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 4, | |
| name: 'test("test2_2")', | |
| offset: testCode.indexOf("test('test2_2'"), | |
| ); | |
| } | |
| Future<void> test_inBodyConstructor_factoryKeyword() async { | |
| var unitOutline = await _computeOutline(''' | |
| class C { | |
| C._(); | |
| factory() => C._(); | |
| factory named() => C._(); | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| var outline_C = topOutlines[0]; | |
| var element_C = outline_C.element; | |
| expect(element_C.kind, ElementKind.CLASS); | |
| expect(element_C.name, 'C'); | |
| var outlines_C = outline_C.children!; | |
| expect(outlines_C, hasLength(3)); | |
| var defaultFactory = outlines_C[1].element; | |
| expect(defaultFactory.kind, ElementKind.CONSTRUCTOR); | |
| expect(defaultFactory.name, 'C'); | |
| expect(defaultFactory.parameters, '()'); | |
| expect(defaultFactory.location!.offset, testCode.indexOf('factory()')); | |
| expect(defaultFactory.location!.length, 'factory'.length); | |
| var namedFactory = outlines_C[2].element; | |
| expect(namedFactory.kind, ElementKind.CONSTRUCTOR); | |
| expect(namedFactory.name, 'C.named'); | |
| expect(namedFactory.parameters, '()'); | |
| expect(namedFactory.location!.offset, testCode.indexOf('named()')); | |
| expect(namedFactory.location!.length, 'named'.length); | |
| } | |
| Future<void> test_inBodyConstructor_newKeyword() async { | |
| var unitOutline = await _computeOutline(''' | |
| class C { | |
| new(); | |
| new named(); | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| var outline_C = topOutlines[0]; | |
| var element_C = outline_C.element; | |
| expect(element_C.kind, ElementKind.CLASS); | |
| expect(element_C.name, 'C'); | |
| var outlines_C = outline_C.children!; | |
| expect(outlines_C, hasLength(2)); | |
| var defaultConstructor = outlines_C[0].element; | |
| expect(defaultConstructor.kind, ElementKind.CONSTRUCTOR); | |
| expect(defaultConstructor.name, 'C'); | |
| expect(defaultConstructor.parameters, '()'); | |
| expect(defaultConstructor.location!.offset, testCode.indexOf('new();')); | |
| expect(defaultConstructor.location!.length, 'new'.length); | |
| var namedConstructor = outlines_C[1].element; | |
| expect(namedConstructor.kind, ElementKind.CONSTRUCTOR); | |
| expect(namedConstructor.name, 'C.named'); | |
| expect(namedConstructor.parameters, '()'); | |
| expect(namedConstructor.location!.offset, testCode.indexOf('named();')); | |
| expect(namedConstructor.location!.length, 'named'.length); | |
| } | |
| Future<void> test_inBodyConstructor_typeName_newKeyword() async { | |
| var unitOutline = await _computeOutline(''' | |
| class C { | |
| C.new(); | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| var outline_C = topOutlines[0]; | |
| var outlines_C = outline_C.children!; | |
| expect(outlines_C, hasLength(1)); | |
| var defaultConstructor = outlines_C[0].element; | |
| expect(defaultConstructor.kind, ElementKind.CONSTRUCTOR); | |
| expect(defaultConstructor.name, 'C'); | |
| expect(defaultConstructor.parameters, '()'); | |
| expect(defaultConstructor.location!.offset, testCode.indexOf('new();')); | |
| expect(defaultConstructor.location!.length, 'new'.length); | |
| } | |
| /// Code like this caused NPE in the past. | |
| /// | |
| /// https://code.google.com/p/dart/issues/detail?id=21373 | |
| Future<void> test_invalidGetterInConstructor() async { | |
| var outline = await _computeOutline(''' | |
| class A { | |
| A() { | |
| get badGetter { | |
| const int CONST = 0; | |
| } | |
| } | |
| } | |
| '''); | |
| expect(outline, isNotNull); | |
| } | |
| /// Code like this caused Dart2 failure in the past. | |
| /// | |
| /// https://github.com/dart-lang/sdk/issues/33228 | |
| Future<void> test_invocation_ofParameter() async { | |
| var outline = await _computeOutline(''' | |
| void f(p()) { | |
| p(); | |
| } | |
| '''); | |
| expect(outline, isNotNull); | |
| } | |
| Future<void> test_isTest_isTestGroup() async { | |
| var outline = await _computeOutline(''' | |
| import 'package:meta/meta.dart'; | |
| @isTestGroup | |
| void myGroup(name, body()) {} | |
| @isTest | |
| void myTest(name) {} | |
| void f() { | |
| myGroup('group1', () { | |
| myGroup('group1_1', () { | |
| myTest('test1_1_1'); | |
| myTest('test1_1_2'); | |
| }); | |
| myGroup('group1_2', () { | |
| myTest('test1_2_1'); | |
| }); | |
| }); | |
| myGroup('group2', () { | |
| myTest('test2_1'); | |
| myTest('test2_2'); | |
| }); | |
| } | |
| '''); | |
| // unit | |
| var unit_children = outline.children!; | |
| expect(unit_children, hasLength(3)); | |
| // f | |
| var f_outline = unit_children[2]; | |
| _expect( | |
| f_outline, | |
| kind: ElementKind.FUNCTION, | |
| name: 'f', | |
| offset: testCode.indexOf('f() {'), | |
| parameters: '()', | |
| returnType: 'void', | |
| ); | |
| var f_children = f_outline.children!; | |
| expect(f_children, hasLength(2)); | |
| // group1 | |
| var group1_outline = f_children[0]; | |
| _expect( | |
| group1_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 7, | |
| name: 'myGroup("group1")', | |
| offset: testCode.indexOf("myGroup('group1'"), | |
| ); | |
| var group1_children = group1_outline.children!; | |
| expect(group1_children, hasLength(2)); | |
| // group1_1 | |
| var group1_1_outline = group1_children[0]; | |
| _expect( | |
| group1_1_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 7, | |
| name: 'myGroup("group1_1")', | |
| offset: testCode.indexOf("myGroup('group1_1'"), | |
| ); | |
| var group1_1_children = group1_1_outline.children!; | |
| expect(group1_1_children, hasLength(2)); | |
| // test1_1_1 | |
| var test1_1_1_outline = group1_1_children[0]; | |
| _expect( | |
| test1_1_1_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 6, | |
| name: 'myTest("test1_1_1")', | |
| offset: testCode.indexOf("myTest('test1_1_1'"), | |
| ); | |
| // test1_1_1 | |
| var test1_1_2_outline = group1_1_children[1]; | |
| _expect( | |
| test1_1_2_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 6, | |
| name: 'myTest("test1_1_2")', | |
| offset: testCode.indexOf("myTest('test1_1_2'"), | |
| ); | |
| // group1_2 | |
| var group1_2_outline = group1_children[1]; | |
| _expect( | |
| group1_2_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 7, | |
| name: 'myGroup("group1_2")', | |
| offset: testCode.indexOf("myGroup('group1_2'"), | |
| ); | |
| var group1_2_children = group1_2_outline.children!; | |
| expect(group1_2_children, hasLength(1)); | |
| // test2_1 | |
| var test1_2_1_outline = group1_2_children[0]; | |
| _expect( | |
| test1_2_1_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 6, | |
| name: 'myTest("test1_2_1")', | |
| offset: testCode.indexOf("myTest('test1_2_1'"), | |
| ); | |
| // group2 | |
| var group2_outline = f_children[1]; | |
| _expect( | |
| group2_outline, | |
| kind: ElementKind.UNIT_TEST_GROUP, | |
| length: 7, | |
| name: 'myGroup("group2")', | |
| offset: testCode.indexOf("myGroup('group2'"), | |
| ); | |
| var group2_children = group2_outline.children!; | |
| expect(group2_children, hasLength(2)); | |
| // test2_1 | |
| var test2_1_outline = group2_children[0]; | |
| _expect( | |
| test2_1_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 6, | |
| name: 'myTest("test2_1")', | |
| offset: testCode.indexOf("myTest('test2_1'"), | |
| ); | |
| // test2_2 | |
| var test2_2_outline = group2_children[1]; | |
| _expect( | |
| test2_2_outline, | |
| kind: ElementKind.UNIT_TEST_TEST, | |
| leaf: true, | |
| length: 6, | |
| name: 'myTest("test2_2")', | |
| offset: testCode.indexOf("myTest('test2_2'"), | |
| ); | |
| } | |
| Future<void> test_localFunctions() async { | |
| var unitOutline = await _computeOutline(''' | |
| class A { | |
| A() { | |
| int local_A() {} | |
| } | |
| m() { | |
| local_m() {} | |
| } | |
| } | |
| f() { | |
| local_f1(int i) {} | |
| local_f2(String s) { | |
| local_f21(int p) {} | |
| } | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(2)); | |
| // A | |
| { | |
| var outline_A = topOutlines[0]; | |
| var element_A = outline_A.element; | |
| expect(element_A.kind, ElementKind.CLASS); | |
| expect(element_A.name, 'A'); | |
| { | |
| var location = element_A.location!; | |
| expect(location.offset, testCode.indexOf('A {')); | |
| expect(location.length, 'A'.length); | |
| } | |
| expect(element_A.parameters, null); | |
| expect(element_A.returnType, null); | |
| // A children | |
| var outlines_A = outline_A.children!; | |
| expect(outlines_A, hasLength(2)); | |
| { | |
| var constructorOutline = outlines_A[0]; | |
| var constructorElement = constructorOutline.element; | |
| expect(constructorElement.kind, ElementKind.CONSTRUCTOR); | |
| expect(constructorElement.name, 'A'); | |
| { | |
| var location = constructorElement.location!; | |
| expect(location.offset, testCode.indexOf('A() {')); | |
| expect(location.length, 'A'.length); | |
| } | |
| expect(constructorElement.parameters, '()'); | |
| expect(constructorElement.returnType, isNull); | |
| // local function | |
| var outlines_constructor = constructorOutline.children!; | |
| expect(outlines_constructor, hasLength(1)); | |
| { | |
| var outline = outlines_constructor[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION); | |
| expect(element.name, 'local_A'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('local_A() {}')); | |
| expect(location.length, 'local_A'.length); | |
| } | |
| expect(element.parameters, '()'); | |
| expect(element.returnType, 'int'); | |
| } | |
| } | |
| { | |
| var outline_m = outlines_A[1]; | |
| var element_m = outline_m.element; | |
| expect(element_m.kind, ElementKind.METHOD); | |
| expect(element_m.name, 'm'); | |
| { | |
| var location = element_m.location!; | |
| expect(location.offset, testCode.indexOf('m() {')); | |
| expect(location.length, 'm'.length); | |
| } | |
| expect(element_m.parameters, '()'); | |
| expect(element_m.returnType, ''); | |
| // local function | |
| var methodChildren = outline_m.children!; | |
| expect(methodChildren, hasLength(1)); | |
| { | |
| var outline = methodChildren[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION); | |
| expect(element.name, 'local_m'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('local_m() {}')); | |
| expect(location.length, 'local_m'.length); | |
| } | |
| expect(element.parameters, '()'); | |
| expect(element.returnType, ''); | |
| } | |
| } | |
| } | |
| // f() | |
| { | |
| var outline_f = topOutlines[1]; | |
| var element_f = outline_f.element; | |
| expect(element_f.kind, ElementKind.FUNCTION); | |
| expect(element_f.name, 'f'); | |
| { | |
| var location = element_f.location!; | |
| expect(location.offset, testCode.indexOf('f() {')); | |
| expect(location.length, 'f'.length); | |
| } | |
| expect(element_f.parameters, '()'); | |
| expect(element_f.returnType, ''); | |
| // f() children | |
| var outlines_f = outline_f.children!; | |
| expect(outlines_f, hasLength(2)); | |
| { | |
| var outline_f1 = outlines_f[0]; | |
| var element_f1 = outline_f1.element; | |
| expect(element_f1.kind, ElementKind.FUNCTION); | |
| expect(element_f1.name, 'local_f1'); | |
| { | |
| var location = element_f1.location!; | |
| expect(location.offset, testCode.indexOf('local_f1(int i) {}')); | |
| expect(location.length, 'local_f1'.length); | |
| } | |
| expect(element_f1.parameters, '(int i)'); | |
| expect(element_f1.returnType, ''); | |
| } | |
| { | |
| var outline_f2 = outlines_f[1]; | |
| var element_f2 = outline_f2.element; | |
| expect(element_f2.kind, ElementKind.FUNCTION); | |
| expect(element_f2.name, 'local_f2'); | |
| { | |
| var location = element_f2.location!; | |
| expect(location.offset, testCode.indexOf('local_f2(String s) {')); | |
| expect(location.length, 'local_f2'.length); | |
| } | |
| expect(element_f2.parameters, '(String s)'); | |
| expect(element_f2.returnType, ''); | |
| // local_f2() local function | |
| var outlines_f2 = outline_f2.children!; | |
| expect(outlines_f2, hasLength(1)); | |
| { | |
| var outline_f21 = outlines_f2[0]; | |
| var element_f21 = outline_f21.element; | |
| expect(element_f21.kind, ElementKind.FUNCTION); | |
| expect(element_f21.name, 'local_f21'); | |
| { | |
| var location = element_f21.location!; | |
| expect(location.offset, testCode.indexOf('local_f21(int p) {')); | |
| expect(location.length, 'local_f21'.length); | |
| } | |
| expect(element_f21.parameters, '(int p)'); | |
| expect(element_f21.returnType, ''); | |
| } | |
| } | |
| } | |
| } | |
| Future<void> test_mixin() async { | |
| var unitOutline = await _computeOutline(''' | |
| mixin M<N> { | |
| c(int d) {} | |
| String get e => null; | |
| set f(int g) {} | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // M | |
| { | |
| var outline_M = topOutlines[0]; | |
| var element_M = outline_M.element; | |
| expect(element_M.kind, ElementKind.MIXIN); | |
| expect(element_M.name, 'M'); | |
| expect(element_M.typeParameters, '<N>'); | |
| { | |
| var location = element_M.location!; | |
| expect(location.offset, testCode.indexOf('M<N>')); | |
| expect(location.length, 1); | |
| } | |
| expect(element_M.parameters, isNull); | |
| expect(element_M.returnType, isNull); | |
| // M children | |
| var outlines_M = outline_M.children!; | |
| expect(outlines_M, hasLength(3)); | |
| { | |
| var outline = outlines_M[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.METHOD); | |
| expect(element.name, 'c'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('c(int d)')); | |
| expect(location.length, 1); | |
| } | |
| expect(element.parameters, '(int d)'); | |
| expect(element.returnType, ''); | |
| expect(element.isAbstract, isFalse); | |
| expect(element.isStatic, isFalse); | |
| } | |
| { | |
| var outline = outlines_M[1]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.GETTER); | |
| expect(element.name, 'e'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('e => null')); | |
| expect(location.length, 1); | |
| } | |
| expect(element.parameters, isNull); | |
| expect(element.returnType, 'String'); | |
| } | |
| { | |
| var outline = outlines_M[2]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.SETTER); | |
| expect(element.name, 'f'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('f(int g)')); | |
| expect(location.length, 1); | |
| } | |
| expect(element.parameters, '(int g)'); | |
| expect(element.returnType, ''); | |
| } | |
| } | |
| } | |
| Future<void> test_primaryConstructor() async { | |
| var unitOutline = await _computeOutline(''' | |
| abstract class C(var int x, final int y, int z) {} | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| // The class `C`. | |
| expect(topOutlines, hasLength(1)); | |
| var outline_C = topOutlines[0]; | |
| var element_C = outline_C.element; | |
| expect(element_C.kind, ElementKind.CLASS); | |
| expect(element_C.name, 'C'); | |
| var location = element_C.location!; | |
| expect(location.offset, testCode.indexOf('C(')); | |
| expect(location.length, 1); | |
| var outlines_A = outline_C.children!; | |
| expect(outlines_A, hasLength(3)); | |
| // The primary constructor | |
| var outline_A_new = outlines_A[0]; | |
| var element_A_new = outline_A_new.element; | |
| expect(element_A_new.kind, ElementKind.CONSTRUCTOR); | |
| expect(element_A_new.name, 'C'); | |
| expect(element_A_new.parameters, '(var int x, final int y, int z)'); | |
| expect(element_A_new.returnType, isNull); | |
| // The field `x` | |
| var outline_x = outlines_A[1]; | |
| var element_x = outline_x.element; | |
| expect(element_x.kind, ElementKind.FIELD); | |
| expect(element_x.isFinal, false); | |
| expect(element_x.name, 'x'); | |
| expect(element_x.parameters, isNull); | |
| expect(element_x.returnType, 'int'); | |
| // The field `y` | |
| var outline_y = outlines_A[2]; | |
| var element_y = outline_y.element; | |
| expect(element_y.kind, ElementKind.FIELD); | |
| expect(element_y.isFinal, true); | |
| expect(element_y.name, 'y'); | |
| expect(element_y.parameters, isNull); | |
| expect(element_y.returnType, 'int'); | |
| } | |
| Future<void> test_primaryConstructor_body() async { | |
| var unitOutline = await _computeOutline(''' | |
| class A(final int a, int b) { | |
| this {} | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| var outline_A = topOutlines[0]; | |
| var element_A = outline_A.element; | |
| expect(element_A.kind, ElementKind.CLASS); | |
| expect(element_A.name, 'A'); | |
| var outlines_A = outline_A.children!; | |
| expect(outlines_A, hasLength(3)); | |
| var primaryConstructor = outlines_A[0].element; | |
| expect(primaryConstructor.kind, ElementKind.CONSTRUCTOR); | |
| expect(primaryConstructor.name, 'A'); | |
| expect(primaryConstructor.parameters, '(final int a, int b)'); | |
| var field_a = outlines_A[1].element; | |
| expect(field_a.kind, ElementKind.FIELD); | |
| expect(field_a.name, 'a'); | |
| var thisConstructor = outlines_A[2].element; | |
| expect(thisConstructor.kind, ElementKind.CONSTRUCTOR); | |
| expect(thisConstructor.name, 'this'); | |
| expect(thisConstructor.parameters, isNull); | |
| expect(thisConstructor.location!.offset, testCode.indexOf('this')); | |
| expect(thisConstructor.location!.length, 'this'.length); | |
| } | |
| Future<void> test_primaryConstructor_noClassBody() async { | |
| var unitOutline = await _computeOutline(''' | |
| class C(var int x); | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| // The class `C`. | |
| expect(topOutlines, hasLength(1)); | |
| var outline_C = topOutlines[0]; | |
| var element_C = outline_C.element; | |
| expect(element_C.kind, ElementKind.CLASS); | |
| expect(element_C.name, 'C'); | |
| var location = element_C.location!; | |
| expect(location.offset, testCode.indexOf('C(')); | |
| expect(location.length, 1); | |
| var outlines_A = outline_C.children!; | |
| expect(outlines_A, hasLength(2)); | |
| // The primary constructor | |
| var outline_A_new = outlines_A[0]; | |
| var element_A_new = outline_A_new.element; | |
| expect(element_A_new.kind, ElementKind.CONSTRUCTOR); | |
| expect(element_A_new.name, 'C'); | |
| expect(element_A_new.parameters, '(var int x)'); | |
| expect(element_A_new.returnType, isNull); | |
| // The field `x` | |
| var outline_x = outlines_A[1]; | |
| var element_x = outline_x.element; | |
| expect(element_x.kind, ElementKind.FIELD); | |
| expect(element_x.isFinal, false); | |
| expect(element_x.name, 'x'); | |
| expect(element_x.parameters, isNull); | |
| expect(element_x.returnType, 'int'); | |
| } | |
| Future<void> test_primaryConstructor_parameterDefault_issue62390() async { | |
| var unitOutline = await _computeOutline(''' | |
| class A([final int x = 0]) {} | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| // The class `A`. | |
| var outline_A = topOutlines[0]; | |
| var element_A = outline_A.element; | |
| expect(element_A.kind, ElementKind.CLASS); | |
| expect(element_A.name, 'A'); | |
| var location = element_A.location!; | |
| expect(location.offset, testCode.indexOf('A(')); | |
| expect(location.length, 1); | |
| var outlines_A = outline_A.children!; | |
| expect(outlines_A, hasLength(2)); | |
| // The primary constructor | |
| var outline_A_new = outlines_A[0]; | |
| var element_A_new = outline_A_new.element; | |
| expect(element_A_new.kind, ElementKind.CONSTRUCTOR); | |
| expect(element_A_new.name, 'A'); | |
| expect(element_A_new.parameters, '([final int x = 0])'); | |
| expect(element_A_new.returnType, isNull); | |
| // The field `x` | |
| var outline_x = outlines_A[1]; | |
| var element_x = outline_x.element; | |
| expect(element_x.kind, ElementKind.FIELD); | |
| expect(element_x.isFinal, true); | |
| expect(element_x.name, 'x'); | |
| expect(element_x.parameters, isNull); | |
| expect(element_x.returnType, 'int'); | |
| } | |
| Future<void> test_privateNamedParameter() async { | |
| var unitOutline = await _computeOutline(''' | |
| class C { | |
| int? _x; | |
| C({this._x}); | |
| } | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| // The class `C`. | |
| expect(topOutlines, hasLength(1)); | |
| var outline_C = topOutlines[0]; | |
| var outlines_C = outline_C.children!; | |
| expect(outlines_C, hasLength(2)); | |
| // The field '_x'. | |
| var outline_x = outlines_C[0]; | |
| var element_x = outline_x.element; | |
| expect(element_x.kind, ElementKind.FIELD); | |
| expect(element_x.name, '_x'); | |
| // The constructor. | |
| var outline_ctor = outlines_C[1]; | |
| var element_ctor = outline_ctor.element; | |
| expect(element_ctor.kind, ElementKind.CONSTRUCTOR); | |
| expect(element_ctor.name, 'C'); | |
| // TODO(rnystrom): It might be better to show the parameter signature as | |
| // it would appear to a caller like `({int? x})`, but that would be a large | |
| // change. Currently, outlines always show the parameter signature as it is | |
| // declared. | |
| // See: https://github.com/dart-lang/sdk/issues/62608 | |
| expect(element_ctor.parameters, '({this._x})'); | |
| } | |
| Future<void> test_sourceRanges_fields() async { | |
| var unitOutline = await _computeOutline(''' | |
| class A { | |
| /*[0*/int /*[1*/fieldA/*1]*//*0]*/, /*[2*//*[3*/fieldB = 2/*3]*/;/*2]*/ | |
| /*[4*/int /*[5*/fieldC/*5]*/;/*4]*/ | |
| /*[6*///// Documentation. | |
| int /*[7*/fieldD/*7]*/;/*6]*/ | |
| } | |
| '''); | |
| var outlines = unitOutline.children![0].children!; | |
| expect(outlines, hasLength(4)); | |
| // fieldA | |
| { | |
| var outline = outlines[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FIELD); | |
| expect(element.name, 'fieldA'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[0])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[1])); | |
| } | |
| // fieldB | |
| { | |
| var outline = outlines[1]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FIELD); | |
| expect(element.name, 'fieldB'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[2])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[3])); | |
| } | |
| // fieldC | |
| { | |
| var outline = outlines[2]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FIELD); | |
| expect(element.name, 'fieldC'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[4])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[5])); | |
| } | |
| // fieldD | |
| { | |
| var outline = outlines[3]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FIELD); | |
| expect(element.name, 'fieldD'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[6])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[7])); | |
| } | |
| } | |
| Future<void> test_sourceRanges_inUnit() async { | |
| var unitOutline = await _computeOutline(''' | |
| /*[0*//// My first class. | |
| /*[1*/class A {}/*1]*//*0]*/ | |
| /*[2*/class B {}/*2]*/ | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(2)); | |
| // A | |
| { | |
| var outline = topOutlines[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CLASS); | |
| expect(element.name, 'A'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[0])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[1])); | |
| } | |
| // B | |
| { | |
| var outline = topOutlines[1]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CLASS); | |
| expect(element.name, 'B'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[2])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[2])); | |
| } | |
| } | |
| Future<void> test_sourceRanges_method() async { | |
| var unitOutline = await _computeOutline(''' | |
| class A { | |
| /*[0*/int methodA() {}/*0]*/ | |
| /*[1*//// Documentation. | |
| @override | |
| /*[2*/int methodB() {}/*2]*//*1]*/ | |
| } | |
| '''); | |
| var outlines = unitOutline.children![0].children!; | |
| expect(outlines, hasLength(2)); | |
| // methodA | |
| { | |
| var outline = outlines[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.METHOD); | |
| expect(element.name, 'methodA'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[0])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[0])); | |
| } | |
| // methodB | |
| { | |
| var outline = outlines[1]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.METHOD); | |
| expect(element.name, 'methodB'); | |
| expect(outline, hasOffsetLength(parsedTestCode.ranges[1])); | |
| expect(outline, hasCodeOffsetLength(parsedTestCode.ranges[2])); | |
| } | |
| } | |
| Future<void> test_topLevel() async { | |
| var unitOutline = await _computeOutline(''' | |
| typedef String FTA<K, V>(int i, String s); | |
| typedef FTB(int p); | |
| typedef GTAF<T> = void Function<S>(T t, S s); | |
| class A<T> {} | |
| class B {} | |
| class CTA<T> = A<T> with B; | |
| class CTB = A with B; | |
| String fA(int i, String s) => null; | |
| fB(int p) => null; | |
| String get propA => null; | |
| set propB(int v) {} | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(11)); | |
| // FTA | |
| { | |
| var outline = topOutlines[0]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS); | |
| expect(element.name, 'FTA'); | |
| expect(element.typeParameters, '<K, V>'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('FTA<K, V>(')); | |
| expect(location.length, 'FTA'.length); | |
| } | |
| expect(element.parameters, '(int i, String s)'); | |
| expect(element.returnType, 'String'); | |
| } | |
| // FTB | |
| { | |
| var outline = topOutlines[1]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS); | |
| expect(element.name, 'FTB'); | |
| expect(element.typeParameters, isNull); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('FTB(')); | |
| expect(location.length, 'FTB'.length); | |
| } | |
| expect(element.parameters, '(int p)'); | |
| expect(element.returnType, ''); | |
| } | |
| // GenericTypeAlias - function | |
| { | |
| var outline = topOutlines[2]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS); | |
| expect(element.name, 'GTAF'); | |
| expect(element.typeParameters, '<T>'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('GTAF<T> =')); | |
| expect(location.length, 'GTAF'.length); | |
| } | |
| expect(element.parameters, '(T t, S s)'); | |
| expect(element.returnType, 'void'); | |
| } | |
| // CTA | |
| { | |
| var outline = topOutlines[5]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CLASS_TYPE_ALIAS); | |
| expect(element.name, 'CTA'); | |
| expect(element.typeParameters, '<T>'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('CTA<T> =')); | |
| expect(location.length, 'CTA'.length); | |
| } | |
| expect(element.parameters, isNull); | |
| expect(element.returnType, isNull); | |
| } | |
| // CTB | |
| { | |
| var outline = topOutlines[6]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.CLASS_TYPE_ALIAS); | |
| expect(element.name, 'CTB'); | |
| expect(element.typeParameters, isNull); | |
| expect(element.returnType, isNull); | |
| } | |
| // fA | |
| { | |
| var outline = topOutlines[7]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION); | |
| expect(element.name, 'fA'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('fA(')); | |
| expect(location.length, 'fA'.length); | |
| } | |
| expect(element.parameters, '(int i, String s)'); | |
| expect(element.returnType, 'String'); | |
| } | |
| // fB | |
| { | |
| var outline = topOutlines[8]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.FUNCTION); | |
| expect(element.name, 'fB'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('fB(')); | |
| expect(location.length, 'fB'.length); | |
| } | |
| expect(element.parameters, '(int p)'); | |
| expect(element.returnType, ''); | |
| } | |
| // propA | |
| { | |
| var outline = topOutlines[9]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.GETTER); | |
| expect(element.name, 'propA'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('propA => null;')); | |
| expect(location.length, 'propA'.length); | |
| } | |
| expect(element.parameters, ''); | |
| expect(element.returnType, 'String'); | |
| } | |
| // propB | |
| { | |
| var outline = topOutlines[10]; | |
| var element = outline.element; | |
| expect(element.kind, ElementKind.SETTER); | |
| expect(element.name, 'propB'); | |
| { | |
| var location = element.location!; | |
| expect(location.offset, testCode.indexOf('propB(int v) {}')); | |
| expect(location.length, 'propB'.length); | |
| } | |
| expect(element.parameters, '(int v)'); | |
| expect(element.returnType, ''); | |
| } | |
| } | |
| Future<void> test_topLevelFunction_recordTypes() async { | |
| var unitOutline = await _computeOutline(''' | |
| /*[0*/(int, int) /*[1*/f/*1]*/((String, String) r) => throw '';/*0]*/ | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| assertJson(topOutlines[0], { | |
| 'element': { | |
| 'kind': 'FUNCTION', | |
| 'name': 'f', | |
| 'location': _elementLocation(parsedTestCode.ranges[1]), | |
| 'flags': 8, | |
| 'parameters': '((String, String) r)', | |
| 'returnType': '(int, int)', | |
| }, | |
| ..._location(parsedTestCode.ranges[0], parsedTestCode.ranges[0]), | |
| }); | |
| } | |
| Future<void> test_topLevelVariable_recordTypes() async { | |
| var unitOutline = await _computeOutline(''' | |
| /*[0*/(int, int)? /*[1*//*[2*/r/*2]*/ = null/*1]*/;/*0]*/ | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| assertJson(topOutlines[0], { | |
| 'element': { | |
| 'kind': 'TOP_LEVEL_VARIABLE', | |
| 'name': 'r', | |
| 'location': _elementLocation(parsedTestCode.ranges[2]), | |
| 'flags': 0, | |
| 'returnType': '(int, int)?', | |
| }, | |
| ..._location(parsedTestCode.ranges[0], parsedTestCode.ranges[1]), | |
| }); | |
| } | |
| Future<void> test_wildcardLocalFunction() async { | |
| var unitOutline = await _computeOutline(''' | |
| /*[0*//*[1*/f/*1]*/() { | |
| /*[2*//*[3*/_/*3]*/() { | |
| /*[4*//*[5*/_/*5]*/(){}/*4]*/ | |
| }/*2]*/ | |
| }/*0]*/ | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| assertJson(topOutlines.first, { | |
| 'element': { | |
| 'kind': 'FUNCTION', | |
| 'name': 'f', | |
| 'location': _elementLocation(parsedTestCode.ranges[1]), | |
| 'flags': 8, | |
| 'parameters': '()', | |
| 'returnType': '', | |
| }, | |
| ..._location(parsedTestCode.ranges[0], parsedTestCode.ranges[0]), | |
| 'children': [ | |
| { | |
| 'element': { | |
| 'kind': 'FUNCTION', | |
| 'name': '_', | |
| 'location': _elementLocation(parsedTestCode.ranges[3]), | |
| 'flags': 16, | |
| 'parameters': '()', | |
| 'returnType': '', | |
| }, | |
| ..._location(parsedTestCode.ranges[2], parsedTestCode.ranges[2]), | |
| 'children': [ | |
| { | |
| 'element': { | |
| 'kind': 'FUNCTION', | |
| 'name': '_', | |
| 'location': _elementLocation(parsedTestCode.ranges[5]), | |
| 'flags': 16, | |
| 'parameters': '()', | |
| 'returnType': '', | |
| }, | |
| ..._location(parsedTestCode.ranges[4], parsedTestCode.ranges[4]), | |
| }, | |
| ], | |
| }, | |
| ], | |
| }); | |
| } | |
| Future<void> test_wildcardLocalFunction_preWildcards() async { | |
| var unitOutline = await _computeOutline(''' | |
| // @dart = 3.4 | |
| // (pre wildcard-variables) | |
| /*[0*//*[1*/f/*1]*/() { | |
| /*[2*//*[3*/_/*3]*/() { | |
| /*[4*//*[5*/_/*5]*/(){}/*4]*/ | |
| }/*2]*/ | |
| }/*0]*/ | |
| '''); | |
| var topOutlines = unitOutline.children!; | |
| expect(topOutlines, hasLength(1)); | |
| assertJson(topOutlines.first, { | |
| 'element': { | |
| 'kind': 'FUNCTION', | |
| 'name': 'f', | |
| 'location': _elementLocation(parsedTestCode.ranges[1]), | |
| 'flags': 8, | |
| 'parameters': '()', | |
| 'returnType': '', | |
| }, | |
| ..._location(parsedTestCode.ranges[0], parsedTestCode.ranges[0]), | |
| 'children': [ | |
| { | |
| 'element': { | |
| 'kind': 'FUNCTION', | |
| 'name': '_', | |
| 'location': _elementLocation(parsedTestCode.ranges[3]), | |
| 'flags': 16, | |
| 'parameters': '()', | |
| 'returnType': '', | |
| }, | |
| ..._location(parsedTestCode.ranges[2], parsedTestCode.ranges[2]), | |
| 'children': [ | |
| { | |
| 'element': { | |
| 'kind': 'FUNCTION', | |
| 'name': '_', | |
| 'location': _elementLocation(parsedTestCode.ranges[5]), | |
| 'flags': 16, | |
| 'parameters': '()', | |
| 'returnType': '', | |
| }, | |
| ..._location(parsedTestCode.ranges[4], parsedTestCode.ranges[4]), | |
| }, | |
| ], | |
| }, | |
| ], | |
| }); | |
| } | |
| Map<String, Object?> _elementLocation(TestCodeRange range) { | |
| return { | |
| 'file': convertPath(testFilePath), | |
| 'offset': range.sourceRange.offset, | |
| 'length': range.sourceRange.length, | |
| 'startLine': range.range.start.line + 1, | |
| 'startColumn': range.range.start.character + 1, | |
| 'endLine': range.range.end.line + 1, | |
| 'endColumn': range.range.end.character + 1, | |
| }; | |
| } | |
| void _expect( | |
| Outline outline, { | |
| ElementKind? kind, | |
| bool leaf = false, | |
| int? length, | |
| String? name, | |
| int? offset, | |
| String? parameters, | |
| String? returnType, | |
| }) { | |
| var element = outline.element; | |
| var location = element.location!; | |
| if (kind != null) { | |
| expect(element.kind, kind); | |
| } | |
| if (leaf) { | |
| expect(outline.children, isNull); | |
| } | |
| length ??= name?.length; | |
| if (length != null) { | |
| expect(location.length, length); | |
| } | |
| if (name != null) { | |
| expect(element.name, name); | |
| } | |
| if (offset != null) { | |
| expect(location.offset, offset); | |
| } | |
| if (parameters != null) { | |
| expect(element.parameters, parameters); | |
| } | |
| if (returnType != null) { | |
| expect(element.returnType, returnType); | |
| } | |
| } | |
| Map<String, Object?> _location(TestCodeRange name, TestCodeRange code) { | |
| return { | |
| 'offset': name.sourceRange.offset, | |
| 'length': name.sourceRange.length, | |
| 'codeOffset': code.sourceRange.offset, | |
| 'codeLength': code.sourceRange.length, | |
| }; | |
| } | |
| } |