diff --git a/pkg/analysis_server/test/lsp/call_hierarchy_test.dart b/pkg/analysis_server/test/lsp/call_hierarchy_test.dart index 40b4d2e1407e..ee8d1a0bc149 100644 --- a/pkg/analysis_server/test/lsp/call_hierarchy_test.dart +++ b/pkg/analysis_server/test/lsp/call_hierarchy_test.dart @@ -94,6 +94,162 @@ class Bar { ); } + Future test_constructorFromNullAwareElementInList() async { + var code = TestCode.parse(''' +class Foo { + Fo^o(); +} +'''); + + var otherCode = TestCode.parse(''' +import 'main.dart'; + +class Bar { + final foo = [?Foo()]; +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyIncomingCall( + // Container of the call + from: CallHierarchyItem( + name: 'Bar', + detail: 'other.dart', + kind: SymbolKind.Class, + uri: otherFileUri, + range: rangeOfPattern( + otherCode, RegExp(r'class Bar \{.*\}', dotAll: true)), + selectionRange: rangeOfString(otherCode, 'Bar'), + ), + // Ranges of calls within this container + fromRanges: [ + rangeOfString(otherCode, 'Foo'), + ], + ), + ], + ); + } + + Future test_constructorFromNullAwareElementInMapKey() async { + var code = TestCode.parse(''' +class Foo { + Fo^o(); +} +'''); + + var otherCode = TestCode.parse(''' +import 'main.dart'; + +class Bar { + final foo = {?Foo(): ""}; +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyIncomingCall( + // Container of the call + from: CallHierarchyItem( + name: 'Bar', + detail: 'other.dart', + kind: SymbolKind.Class, + uri: otherFileUri, + range: rangeOfPattern( + otherCode, RegExp(r'class Bar \{.*\}', dotAll: true)), + selectionRange: rangeOfString(otherCode, 'Bar'), + ), + // Ranges of calls within this container + fromRanges: [ + rangeOfString(otherCode, 'Foo'), + ], + ), + ], + ); + } + + Future test_constructorFromNullAwareElementInMapValue() async { + var code = TestCode.parse(''' +class Foo { + Fo^o(); +} +'''); + + var otherCode = TestCode.parse(''' +import 'main.dart'; + +class Bar { + final foo = {"": ?Foo()}; +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyIncomingCall( + // Container of the call + from: CallHierarchyItem( + name: 'Bar', + detail: 'other.dart', + kind: SymbolKind.Class, + uri: otherFileUri, + range: rangeOfPattern( + otherCode, RegExp(r'class Bar \{.*\}', dotAll: true)), + selectionRange: rangeOfString(otherCode, 'Bar'), + ), + // Ranges of calls within this container + fromRanges: [ + rangeOfString(otherCode, 'Foo'), + ], + ), + ], + ); + } + + Future test_constructorFromNullAwareElementInSet() async { + var code = TestCode.parse(''' +class Foo { + Fo^o(); +} +'''); + + var otherCode = TestCode.parse(''' +import 'main.dart'; + +class Bar { + final foo = {?Foo()}; +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyIncomingCall( + // Container of the call + from: CallHierarchyItem( + name: 'Bar', + detail: 'other.dart', + kind: SymbolKind.Class, + uri: otherFileUri, + range: rangeOfPattern( + otherCode, RegExp(r'class Bar \{.*\}', dotAll: true)), + selectionRange: rangeOfString(otherCode, 'Bar'), + ), + // Ranges of calls within this container + fromRanges: [ + rangeOfString(otherCode, 'Foo'), + ], + ), + ], + ); + } + Future test_function() async { var code = TestCode.parse(''' void fo^o() {} @@ -441,6 +597,150 @@ void bar() {} ); } + Future test_functionInNullAwareElementInList() async { + var code = TestCode.parse(''' +import 'other.dart'; + +void fo^o() { + [?bar()]; +} +'''); + + var otherCode = TestCode.parse(''' +int? bar() => null; +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyOutgoingCall( + // Target of the call. + to: CallHierarchyItem( + name: 'bar', + detail: 'other.dart', + kind: SymbolKind.Function, + uri: otherFileUri, + range: rangeOfString(otherCode, 'int? bar() => null;'), + selectionRange: rangeOfString(otherCode, 'bar'), + ), + // Ranges of the outbound call. + fromRanges: [ + rangeOfString(code, 'bar'), + ], + ), + ], + ); + } + + Future test_functionInNullAwareElementInMapKey() async { + var code = TestCode.parse(''' +import 'other.dart'; + +void fo^o() { + {?bar(): ""}; +} +'''); + + var otherCode = TestCode.parse(''' +int? bar() => null; +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyOutgoingCall( + // Target of the call. + to: CallHierarchyItem( + name: 'bar', + detail: 'other.dart', + kind: SymbolKind.Function, + uri: otherFileUri, + range: rangeOfString(otherCode, 'int? bar() => null;'), + selectionRange: rangeOfString(otherCode, 'bar'), + ), + // Ranges of the outbound call. + fromRanges: [ + rangeOfString(code, 'bar'), + ], + ), + ], + ); + } + + Future test_functionInNullAwareElementInMapValue() async { + var code = TestCode.parse(''' +import 'other.dart'; + +void fo^o() { + {"": ?bar()}; +} +'''); + + var otherCode = TestCode.parse(''' +int? bar() => null; +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyOutgoingCall( + // Target of the call. + to: CallHierarchyItem( + name: 'bar', + detail: 'other.dart', + kind: SymbolKind.Function, + uri: otherFileUri, + range: rangeOfString(otherCode, 'int? bar() => null;'), + selectionRange: rangeOfString(otherCode, 'bar'), + ), + // Ranges of the outbound call. + fromRanges: [ + rangeOfString(code, 'bar'), + ], + ), + ], + ); + } + + Future test_functionInNullAwareElementInSet() async { + var code = TestCode.parse(''' +import 'other.dart'; + +void fo^o() { + {?bar()}; +} +'''); + + var otherCode = TestCode.parse(''' +int? bar() => null; +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResults: [ + CallHierarchyOutgoingCall( + // Target of the call. + to: CallHierarchyItem( + name: 'bar', + detail: 'other.dart', + kind: SymbolKind.Function, + uri: otherFileUri, + range: rangeOfString(otherCode, 'int? bar() => null;'), + selectionRange: rangeOfString(otherCode, 'bar'), + ), + // Ranges of the outbound call. + fromRanges: [ + rangeOfString(code, 'bar'), + ], + ), + ], + ); + } + Future test_functionInPattern() async { var code = TestCode.parse(''' import 'other.dart'; @@ -823,6 +1123,118 @@ class Foo {} ); } + Future test_insideNullAwareElementInList() async { + var code = TestCode.parse(''' +import 'other.dart'; + +main() { + final foo = [?Foo.Ba^r()]; +} +'''); + + var otherCode = TestCode.parse(''' +class Foo { + Foo.Bar(); +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResult: CallHierarchyItem( + name: 'Foo.Bar', + detail: 'Foo', // Containing class name + kind: SymbolKind.Constructor, + uri: otherFileUri, + range: rangeOfString(otherCode, 'Foo.Bar();'), + selectionRange: rangeOfString(otherCode, 'Bar')), + ); + } + + Future test_insideNullAwareElementInMapKey() async { + var code = TestCode.parse(''' +import 'other.dart'; + +main() { + final foo = {?Foo.Ba^r(): ""}; +} +'''); + + var otherCode = TestCode.parse(''' +class Foo { + Foo.Bar(); +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResult: CallHierarchyItem( + name: 'Foo.Bar', + detail: 'Foo', // Containing class name + kind: SymbolKind.Constructor, + uri: otherFileUri, + range: rangeOfString(otherCode, 'Foo.Bar();'), + selectionRange: rangeOfString(otherCode, 'Bar')), + ); + } + + Future test_insideNullAwareElementInMapValue() async { + var code = TestCode.parse(''' +import 'other.dart'; + +main() { + final foo = {"": ?Foo.Ba^r()}; +} +'''); + + var otherCode = TestCode.parse(''' +class Foo { + Foo.Bar(); +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResult: CallHierarchyItem( + name: 'Foo.Bar', + detail: 'Foo', // Containing class name + kind: SymbolKind.Constructor, + uri: otherFileUri, + range: rangeOfString(otherCode, 'Foo.Bar();'), + selectionRange: rangeOfString(otherCode, 'Bar')), + ); + } + + Future test_insideNullAwareElementInSet() async { + var code = TestCode.parse(''' +import 'other.dart'; + +main() { + final foo = {?Foo.Ba^r()}; +} +'''); + + var otherCode = TestCode.parse(''' +class Foo { + Foo.Bar(); +} +'''); + + await expectResults( + mainCode: code, + otherCode: otherCode, + expectedResult: CallHierarchyItem( + name: 'Foo.Bar', + detail: 'Foo', // Containing class name + kind: SymbolKind.Constructor, + uri: otherFileUri, + range: rangeOfString(otherCode, 'Foo.Bar();'), + selectionRange: rangeOfString(otherCode, 'Bar')), + ); + } + Future test_method() async { var code = TestCode.parse(''' class Foo { diff --git a/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart b/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart index 379f147bed2d..1bb52e0fc444 100644 --- a/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart +++ b/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart @@ -328,6 +328,110 @@ void f() { )); } + Future test_functionCallInNullAwareElementInList() async { + var code = TestCode.parse(''' +import 'other.dart' as other; + +void f() { + [?other.myFun^ction()]; +} +'''); + + var otherCode = TestCode.parse(''' +[!String? myFunction() => null;!] +'''); + + newFile(otherFile, otherCode.code); + await expectTarget( + code, + _isItem( + CallHierarchyKind.function, + 'myFunction', + otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('myFunction', otherCode), + codeRange: otherCode.range.sourceRange, + )); + } + + Future test_functionCallInNullAwareElementInMapKey() async { + var code = TestCode.parse(''' +import 'other.dart' as other; + +void f() { + {?other.myFun^ction(): 0}; +} +'''); + + var otherCode = TestCode.parse(''' +[!String? myFunction() => null;!] +'''); + + newFile(otherFile, otherCode.code); + await expectTarget( + code, + _isItem( + CallHierarchyKind.function, + 'myFunction', + otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('myFunction', otherCode), + codeRange: otherCode.range.sourceRange, + )); + } + + Future test_functionCallInNullAwareElementInMapValue() async { + var code = TestCode.parse(''' +import 'other.dart' as other; + +void f() { + {0: ?other.myFun^ction()}; +} +'''); + + var otherCode = TestCode.parse(''' +[!String? myFunction() => null;!] +'''); + + newFile(otherFile, otherCode.code); + await expectTarget( + code, + _isItem( + CallHierarchyKind.function, + 'myFunction', + otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('myFunction', otherCode), + codeRange: otherCode.range.sourceRange, + )); + } + + Future test_functionCallInNullAwareElementInSet() async { + var code = TestCode.parse(''' +import 'other.dart' as other; + +void f() { + {?other.myFun^ction()}; +} +'''); + + var otherCode = TestCode.parse(''' +[!String? myFunction() => null;!] +'''); + + newFile(otherFile, otherCode.code); + await expectTarget( + code, + _isItem( + CallHierarchyKind.function, + 'myFunction', + otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('myFunction', otherCode), + codeRange: otherCode.range.sourceRange, + )); + } + Future test_getter() async { var code = TestCode.parse(''' class Foo { @@ -1158,6 +1262,166 @@ augment class Foo { ]); } + Future test_methodInNullAwareElementInList() async { + var code = TestCode.parse(''' +class Foo { + bool? myMet^hod() => null; +} +'''); + + var otherCode = TestCode.parse(''' +import 'test.dart'; + +[!void f() { + dynamic tearoff; + [ + ?Foo().myMethod(), + ?tearoff = Foo().myMethod, + ]; +}!] +'''); + + // Gets the expected range that follows the string [prefix]. + SourceRange rangeAfter(String prefix) => + rangeAfterPrefix(prefix, otherCode, 'myMethod'); + + newFile(otherFile, otherCode.code); + var calls = await findIncomingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.function, 'f', otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('f() {', otherCode, 'f'), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfter('Foo().'), + rangeAfter('tearoff = Foo().'), + ]), + ]), + ); + } + + Future test_methodInNullAwareElementInMapKey() async { + var code = TestCode.parse(''' +class Foo { + bool? myMet^hod() => null; +} +'''); + + var otherCode = TestCode.parse(''' +import 'test.dart'; + +[!void f() { + dynamic tearoff; + { + ?Foo().myMethod(): 0, + ?tearoff = Foo().myMethod: 1, + }; +}!] +'''); + + // Gets the expected range that follows the string [prefix]. + SourceRange rangeAfter(String prefix) => + rangeAfterPrefix(prefix, otherCode, 'myMethod'); + + newFile(otherFile, otherCode.code); + var calls = await findIncomingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.function, 'f', otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('f() {', otherCode, 'f'), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfter('Foo().'), + rangeAfter('tearoff = Foo().'), + ]), + ]), + ); + } + + Future test_methodInNullAwareElementInMapValue() async { + var code = TestCode.parse(''' +class Foo { + bool? myMet^hod() => null; +} +'''); + + var otherCode = TestCode.parse(''' +import 'test.dart'; + +[!void f() { + dynamic tearoff; + { + "foo": ?Foo().myMethod(), + "bar": ?tearoff = Foo().myMethod, + }; +}!] +'''); + + // Gets the expected range that follows the string [prefix]. + SourceRange rangeAfter(String prefix) => + rangeAfterPrefix(prefix, otherCode, 'myMethod'); + + newFile(otherFile, otherCode.code); + var calls = await findIncomingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.function, 'f', otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('f() {', otherCode, 'f'), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfter('Foo().'), + rangeAfter('tearoff = Foo().'), + ]), + ]), + ); + } + + Future test_methodInNullAwareElementInSet() async { + var code = TestCode.parse(''' +class Foo { + bool? myMet^hod() => null; +} +'''); + + var otherCode = TestCode.parse(''' +import 'test.dart'; + +[!void f() { + dynamic tearoff; + { + ?Foo().myMethod(), + ?tearoff = Foo().myMethod, + }; +}!] +'''); + + // Gets the expected range that follows the string [prefix]. + SourceRange rangeAfter(String prefix) => + rangeAfterPrefix(prefix, otherCode, 'myMethod'); + + newFile(otherFile, otherCode.code); + var calls = await findIncomingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.function, 'f', otherFile, + containerName: 'other.dart', + nameRange: rangeAtSearch('f() {', otherCode, 'f'), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfter('Foo().'), + rangeAfter('tearoff = Foo().'), + ]), + ]), + ); + } + Future test_mixin_method() async { var code = TestCode.parse(''' mixin Bar { @@ -1727,6 +1991,170 @@ class A { ); } + Future test_namedConstructorInNullAwareElementInList() async { + var code = TestCode.parse(''' +// ignore_for_file: unused_local_variable +import 'other.dart'; + +class Foo { + Foo.B^ar(bool b) { + dynamic a1; + dynamic a2; + [ + ?a1 = b ? A.named() : null, + ?a2 = b ? A.named : null, + ]; + } +} +'''); + + var otherCode = TestCode.parse(''' +void f() {} +class A { + [!A.named();!] +} +'''); + + newFile(otherFile, otherCode.code); + var calls = await findOutgoingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.constructor, 'A.named', otherFile, + containerName: 'A', + nameRange: rangeAtSearch('named', otherCode), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfterPrefix('?a1 = b ? A.', code, 'named'), + rangeAfterPrefix('?a2 = b ? A.', code, 'named'), + ]), + ]), + ); + } + + Future test_namedConstructorInNullAwareElementInMapKey() async { + var code = TestCode.parse(''' +// ignore_for_file: unused_local_variable +import 'other.dart'; + +class Foo { + Foo.B^ar(bool b) { + dynamic a1; + dynamic a2; + { + ?a1 = b ? A.named() : null: #foo, + ?a2 = b ? A.named : null: #bar, + }; + } +} +'''); + + var otherCode = TestCode.parse(''' +void f() {} +class A { + [!A.named();!] +} +'''); + + newFile(otherFile, otherCode.code); + var calls = await findOutgoingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.constructor, 'A.named', otherFile, + containerName: 'A', + nameRange: rangeAtSearch('named', otherCode), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfterPrefix('?a1 = b ? A.', code, 'named'), + rangeAfterPrefix('?a2 = b ? A.', code, 'named'), + ]), + ]), + ); + } + + Future test_namedConstructorInNullAwareElementInMapValue() async { + var code = TestCode.parse(''' +// ignore_for_file: unused_local_variable +import 'other.dart'; + +class Foo { + Foo.B^ar(bool b) { + dynamic a1; + dynamic a2; + { + #foo: ?a1 = b ? A.named() : null, + #bar: ?a2 = b ? A.named : null, + }; + } +} +'''); + + var otherCode = TestCode.parse(''' +void f() {} +class A { + [!A.named();!] +} +'''); + + newFile(otherFile, otherCode.code); + var calls = await findOutgoingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.constructor, 'A.named', otherFile, + containerName: 'A', + nameRange: rangeAtSearch('named', otherCode), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfterPrefix('?a1 = b ? A.', code, 'named'), + rangeAfterPrefix('?a2 = b ? A.', code, 'named'), + ]), + ]), + ); + } + + Future test_namedConstructorInNullAwareElementInSet() async { + var code = TestCode.parse(''' +// ignore_for_file: unused_local_variable +import 'other.dart'; + +class Foo { + Foo.B^ar(bool b) { + dynamic a1; + dynamic a2; + { + ?a1 = b ? A.named() : null, + ?a2 = b ? A.named : null, + }; + } +} +'''); + + var otherCode = TestCode.parse(''' +void f() {} +class A { + [!A.named();!] +} +'''); + + newFile(otherFile, otherCode.code); + var calls = await findOutgoingCalls(code); + expect( + calls, + unorderedEquals([ + _isResult(CallHierarchyKind.constructor, 'A.named', otherFile, + containerName: 'A', + nameRange: rangeAtSearch('named', otherCode), + codeRange: otherCode.range.sourceRange, + ranges: [ + rangeAfterPrefix('?a1 = b ? A.', code, 'named'), + rangeAfterPrefix('?a2 = b ? A.', code, 'named'), + ]), + ]), + ); + } + Future test_prefixedTypes() async { // Prefixed type names that are not tear-offs should never be included. var code = TestCode.parse('''