eb979c2f0c
Fixes https://github.com/dart-lang/sdk/issues/63560 Change-Id: I2c93e4a1011075e103d9165d0664f588f3109c40 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/510821 Commit-Queue: Keerti Parthasarathy <keertip@google.com> Reviewed-by: Keerti Parthasarathy <keertip@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
1056 lines
23 KiB
Dart
1056 lines
23 KiB
Dart
// Copyright (c) 2018, 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 'package:analysis_server/lsp_protocol/protocol.dart';
|
|
import 'package:analyzer/src/test_utilities/test_code_format.dart';
|
|
import 'package:test/test.dart';
|
|
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
|
|
|
import '../utils/test_code_extensions.dart';
|
|
import 'server_abstract.dart';
|
|
|
|
void main() {
|
|
defineReflectiveSuite(() {
|
|
defineReflectiveTests(SignatureHelpTest);
|
|
});
|
|
}
|
|
|
|
mixin SignatureHelpMixin on AbstractLspAnalysisServerTest {
|
|
Future<void> expectNoSignature(
|
|
String content, {
|
|
Uri? fileUri,
|
|
Position? position,
|
|
SignatureHelpContext? context,
|
|
}) async {
|
|
var code = TestCode.parse(content);
|
|
fileUri ??= mainFileUri;
|
|
position ??= code.position.position;
|
|
|
|
await initialize();
|
|
await openFile(fileUri, code.code);
|
|
|
|
var res = await getSignatureHelp(fileUri, position, context);
|
|
expect(res, isNull);
|
|
}
|
|
|
|
Future<void> _expectSignature(
|
|
String content,
|
|
String expectedLabel, {
|
|
String? expectedDoc,
|
|
List<ParameterInformation>? expectedParams,
|
|
MarkupKind? expectedFormat = MarkupKind.Markdown,
|
|
SignatureHelpContext? context,
|
|
_FileState state = _FileState.open,
|
|
int? activeParameter,
|
|
}) async {
|
|
var code = TestCode.parse(content);
|
|
if (state == _FileState.closed) {
|
|
newFile(mainFilePath, code.code);
|
|
}
|
|
await initialize();
|
|
if (state == _FileState.open) {
|
|
await openFile(mainFileUri, code.code);
|
|
}
|
|
await initialAnalysis;
|
|
|
|
var res = (await getSignatureHelp(
|
|
mainFileUri,
|
|
code.position.position,
|
|
context,
|
|
))!;
|
|
|
|
if (activeParameter != null) {
|
|
expect(res.activeParameter, activeParameter);
|
|
}
|
|
expect(res.activeSignature, equals(0));
|
|
expect(res.signatures, hasLength(1));
|
|
var sig = res.signatures.first;
|
|
expect(sig.label, equals(expectedLabel));
|
|
if (expectedParams != null) {
|
|
expect(sig.parameters, equals(expectedParams));
|
|
}
|
|
|
|
if (expectedDoc != null) {
|
|
// Test the format matches the tests expectation.
|
|
// For clients that don't support MarkupContent it'll be a plain string,
|
|
// but otherwise it'll be a MarkupContent of type PlainText or Markdown.
|
|
var doc = sig.documentation!;
|
|
if (expectedFormat == null) {
|
|
// Plain string.
|
|
expect(doc.valueEquals(expectedDoc), isTrue);
|
|
} else {
|
|
var expected = MarkupContent(kind: expectedFormat, value: expectedDoc);
|
|
expect(doc.valueEquals(expected), isTrue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@reflectiveTest
|
|
class SignatureHelpTest extends AbstractLspAnalysisServerTest
|
|
with SignatureHelpMixin {
|
|
Future<void> assertArgsDocumentation(
|
|
String? preference, {
|
|
required bool includesSummary,
|
|
required bool includesFull,
|
|
}) {
|
|
var content = '''
|
|
class A {
|
|
/// Summary.
|
|
///
|
|
/// Full.
|
|
A();
|
|
}
|
|
|
|
final a = A(^);
|
|
''';
|
|
|
|
return assertDocumentation(
|
|
preference,
|
|
content,
|
|
includesSummary: includesSummary,
|
|
includesFull: includesFull,
|
|
);
|
|
}
|
|
|
|
/// Checks whether the correct types of documentation are returned in
|
|
/// signature help for function arguments based on [preference].
|
|
Future<void> assertDocumentation(
|
|
String? preference,
|
|
String content, {
|
|
required bool includesSummary,
|
|
required bool includesFull,
|
|
}) async {
|
|
var code = TestCode.parse(content);
|
|
await provideConfig(initialize, {'documentation': ?preference});
|
|
await openFile(mainFileUri, code.code);
|
|
await initialAnalysis;
|
|
var signatureHelp = await getSignatureHelp(
|
|
mainFileUri,
|
|
code.position.position,
|
|
);
|
|
var docs = signatureHelp!.signatures.single.documentation?.map(
|
|
(markup) => markup.value,
|
|
(string) => string,
|
|
);
|
|
|
|
if (includesSummary) {
|
|
expect(docs, contains('Summary.'));
|
|
} else {
|
|
expect(docs, isNot(contains('Summary.')));
|
|
}
|
|
|
|
if (includesFull) {
|
|
expect(docs, contains('Full.'));
|
|
} else {
|
|
expect(docs, isNot(contains('Full.')));
|
|
}
|
|
}
|
|
|
|
@override
|
|
void setUp() {
|
|
super.setUp();
|
|
|
|
// Signature help tests have incomplete signatures.
|
|
failTestOnErrorDiagnostic = false;
|
|
|
|
setSignatureHelpContentFormat([MarkupKind.Markdown]);
|
|
}
|
|
|
|
Future<void> test_activeParameter_named_withLabel_inOrder() async {
|
|
var content = '''
|
|
void f({int a, int b}) {
|
|
f(a: 1, b: ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f({int a, int b})',
|
|
// We matched on the name.
|
|
activeParameter: 1,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_named_withLabel_invalid() async {
|
|
var content = '''
|
|
void f({int a}) {
|
|
f(b: ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f({int a})',
|
|
// First invalid index, because we don't match a named parameter.
|
|
activeParameter: 1,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_named_withLabel_outOfOrder1() async {
|
|
var content = '''
|
|
void f({int a, int b}) {
|
|
f(b: ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f({int a, int b})',
|
|
// We matched on the name.
|
|
activeParameter: 1,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_named_withLabel_outOfOrder2() async {
|
|
var content = '''
|
|
void f({int a, int b, int c}) {
|
|
f(a: 1, c: ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f({int a, int b, int c})',
|
|
// We matched on the name.
|
|
activeParameter: 2,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_named_withoutLabel1() async {
|
|
var content = '''
|
|
void f({int a}) {
|
|
f(^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f({int a})',
|
|
// First invalid index, because we don't try to guess named parameters.
|
|
activeParameter: 1,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_named_withoutLabel2() async {
|
|
var content = '''
|
|
void f({int a, int b}) {
|
|
f(a: 1, ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f({int a, int b})',
|
|
// First invalid index, because we don't try to guess named parameters.
|
|
activeParameter: 2,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_none() async {
|
|
var content = '''
|
|
void f() {
|
|
f(^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f()',
|
|
// First invalid index (there is no 0th parameter).
|
|
activeParameter: 0,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_positional1() async {
|
|
var content = '''
|
|
void f(int a) {
|
|
f(^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f(int a)',
|
|
// Matched on index.
|
|
activeParameter: 0,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_positional2() async {
|
|
var content = '''
|
|
void f(int a, int b) {
|
|
f(1, ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f(int a, int b)',
|
|
// Matched on index.
|
|
activeParameter: 1,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_positional_afterNamed() async {
|
|
var content = '''
|
|
void f(int a, int b, int c, {int d}) {
|
|
f(1, d: 2, 3, ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f(int a, int b, int c, {int d})',
|
|
// Matched on index of positionals (c).
|
|
activeParameter: 2,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_positional_withExprsesion() async {
|
|
var content = '''
|
|
void f(int a) {
|
|
f(1 + ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f(int a)',
|
|
// Matched on index.
|
|
activeParameter: 0,
|
|
);
|
|
}
|
|
|
|
Future<void> test_activeParameter_positionalinvalid() async {
|
|
var content = '''
|
|
void f(int a, int b) {
|
|
f(1, 2, ^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f(int a, int b)',
|
|
// First invalid index because there's no valid parameter.
|
|
activeParameter: 2,
|
|
);
|
|
}
|
|
|
|
Future<void> test_augmentation_method() async {
|
|
var content = '''
|
|
part 'a.dart';
|
|
|
|
class Foo {}
|
|
|
|
void bar() {
|
|
Foo().myMethod(^);
|
|
}
|
|
''';
|
|
|
|
var augmentationFilePath = join(projectFolderPath, 'lib', 'a.dart');
|
|
var augmentationCode = '''
|
|
part of 'main.dart';
|
|
|
|
augment class Foo {
|
|
/// My method.
|
|
void myMethod(String s) {}
|
|
}
|
|
''';
|
|
newFile(augmentationFilePath, augmentationCode);
|
|
var expectedLabel = 'myMethod(String s)';
|
|
var expectedDoc = 'My method.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [ParameterInformation(label: 'String s')],
|
|
);
|
|
}
|
|
|
|
Future<void> test_callableClass() async {
|
|
var content = '''
|
|
class Foo {
|
|
/// Does foo.
|
|
int call(String s, int i) {
|
|
var foo = Foo();
|
|
return foo(^);
|
|
}
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_dartDocMacro() async {
|
|
setSignatureHelpContentFormat(null);
|
|
|
|
var content = '''
|
|
/// {@template template_name}
|
|
/// This is shared content.
|
|
/// {@endtemplate}
|
|
const String bar = null;
|
|
|
|
/// {@macro template_name}
|
|
foo(String s, int i) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'This is shared content.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
expectedFormat: null,
|
|
);
|
|
}
|
|
|
|
Future<void> test_dartDocPreference_full() => assertArgsDocumentation(
|
|
'full',
|
|
includesSummary: true,
|
|
includesFull: true,
|
|
);
|
|
|
|
Future<void> test_dartDocPreference_summary() => assertArgsDocumentation(
|
|
'summary',
|
|
includesSummary: true,
|
|
// Doc preferences don't apply to single-result requests so always expect
|
|
// full docs.
|
|
includesFull: true,
|
|
);
|
|
|
|
/// No preference should result in full docs.
|
|
Future<void> test_dartDocPreference_unset() =>
|
|
assertArgsDocumentation(null, includesSummary: true, includesFull: true);
|
|
|
|
Future<void> test_error_methodInvocation_importPrefix() async {
|
|
var content = '''
|
|
import 'dart:async' as prefix;
|
|
|
|
void f() {
|
|
prefix(^);
|
|
}
|
|
''';
|
|
|
|
// Expect no result.
|
|
await expectNoSignature(content);
|
|
}
|
|
|
|
Future<void> test_extensionType() async {
|
|
var content = '''
|
|
class A {
|
|
void f(int a) {}
|
|
}
|
|
|
|
extension type E(A a) {
|
|
void f(int e) {}
|
|
}
|
|
|
|
void f() {
|
|
final e = E(A());
|
|
e.f(^);
|
|
}
|
|
''';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
'f(int e)',
|
|
expectedParams: [ParameterInformation(label: 'int e')],
|
|
);
|
|
}
|
|
|
|
Future<void> test_formats_markdown() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_formats_notSupported() async {
|
|
setSignatureHelpContentFormat(null);
|
|
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
expectedFormat: null,
|
|
);
|
|
}
|
|
|
|
Future<void> test_formats_plainTextOnly() async {
|
|
setSignatureHelpContentFormat([MarkupKind.PlainText]);
|
|
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
expectedFormat: MarkupKind.PlainText,
|
|
);
|
|
}
|
|
|
|
Future<void> test_formats_plainTextPreferred() async {
|
|
setSignatureHelpContentFormat([MarkupKind.PlainText, MarkupKind.Markdown]);
|
|
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
// We say we prefer PlainText as a client, but since we only really
|
|
// support Markdown and the client supports it, we expect the server
|
|
// to provide Markdown.
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_functionExpression_local() async {
|
|
var content = '''
|
|
|
|
void f() {
|
|
var foo = (String s, int i) => s;
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_functionExpression_topLevel() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
var foo = (String s, int i) => s;
|
|
|
|
void f() {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_manualTrigger_invalidLocation() async {
|
|
// If the user invokes signature help, we should show it even if it's a
|
|
// location where we wouldn't automatically trigger (for example in a string).
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo('this is a (^test');
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
context: SignatureHelpContext(
|
|
triggerKind: SignatureHelpTriggerKind.Invoked,
|
|
isRetrigger: false,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> test_noDefaultConstructor() async {
|
|
var content = '''
|
|
class A {
|
|
A._();
|
|
}
|
|
|
|
final a = A(^);
|
|
''';
|
|
|
|
await expectNoSignature(content);
|
|
}
|
|
|
|
Future<void> test_nonDartFile() async {
|
|
await expectNoSignature(
|
|
simplePubspecContent,
|
|
fileUri: pubspecFileUri,
|
|
position: startOfDocPos,
|
|
);
|
|
}
|
|
|
|
/// Keywords for declaraing parameters should not be shown because they don't
|
|
/// change the parameters and are just visual noise.
|
|
Future<void> test_params_final() async {
|
|
var content = '''
|
|
foo(final String s) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'foo(String s)';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedParams: [ParameterInformation(label: 'String s')],
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_multipleNamed() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, {bool b = true, bool a}) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'foo(String s, {bool b = true, bool a})';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'bool b = true'),
|
|
ParameterInformation(label: 'bool a'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_multipleNamed_retrigger() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, {bool b = true, bool a}) {
|
|
foo('s',^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'foo(String s, {bool b = true, bool a})';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'bool b = true'),
|
|
ParameterInformation(label: 'bool a'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_multipleOptional() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, [bool b = true, bool a]) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'foo(String s, [bool b = true, bool a])';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'bool b = true'),
|
|
ParameterInformation(label: 'bool a'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_named() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, {bool b = true}) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'foo(String s, {bool b = true})';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'bool b = true'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_optional() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, [bool b = true]) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'foo(String s, [bool b = true])';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'bool b = true'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_primaryConstructor() async {
|
|
var content = '''
|
|
class A(final int x, var int y, int z);
|
|
|
|
final a = A(^);
|
|
''';
|
|
var expectedLabel = 'A(int x, int y, int z)';
|
|
var expectedParams = [
|
|
ParameterInformation(label: 'int x'),
|
|
ParameterInformation(label: 'int y'),
|
|
ParameterInformation(label: 'int z'),
|
|
];
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedParams: expectedParams,
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_recordType() async {
|
|
var content = '''
|
|
/// Does something.
|
|
void f((String, int) r) {
|
|
f(^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'f((String, int) r)';
|
|
var expectedDoc = 'Does something.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [ParameterInformation(label: '(String, int) r')],
|
|
);
|
|
}
|
|
|
|
Future<void> test_params_requiredNamed() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, {bool? b = true, required bool a}) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
|
|
var expectedLabel = 'foo(String s, {bool? b = true, required bool a})';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'bool? b = true'),
|
|
ParameterInformation(label: 'required bool a'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_simple() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_triggerCharacter_invalidLocation() async {
|
|
// The client will automatically trigger when the user types ( so we need to
|
|
// ignore it when we're not in a suitable location.
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo('this is a (^test');
|
|
}
|
|
''';
|
|
|
|
// Expect no result.
|
|
await expectNoSignature(
|
|
content,
|
|
context: SignatureHelpContext(
|
|
triggerKind: SignatureHelpTriggerKind.TriggerCharacter,
|
|
isRetrigger: false,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> test_triggerCharacter_validLocation() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo(^
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
context: SignatureHelpContext(
|
|
triggerKind: SignatureHelpTriggerKind.Invoked,
|
|
isRetrigger: false,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> test_typeArgs_dartDocPreference_full() =>
|
|
assertArgsDocumentation(
|
|
'full',
|
|
includesSummary: true,
|
|
includesFull: true,
|
|
);
|
|
|
|
Future<void>
|
|
test_typeArgs_dartDocPreference_summary() => assertArgsDocumentation(
|
|
'summary',
|
|
includesSummary: true,
|
|
// Doc preferences don't apply to single-result requests so always expect
|
|
// full docs.
|
|
includesFull: true,
|
|
);
|
|
|
|
/// No preference should result in full docs.
|
|
Future<void> test_typeArgs_dartDocPreference_unset() =>
|
|
assertArgsDocumentation(null, includesSummary: true, includesFull: true);
|
|
|
|
Future<void> test_typeParams_class() async {
|
|
var content = '''
|
|
/// My Foo.
|
|
class Foo<T1, T2 extends String> {}
|
|
|
|
class Bar extends Foo<^> {}
|
|
''';
|
|
|
|
const expectedLabel = 'class Foo<T1, T2 extends String>';
|
|
const expectedDoc = 'My Foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'T1'),
|
|
ParameterInformation(label: 'T2 extends String'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_typeParams_function() async {
|
|
var content = '''
|
|
/// My Foo.
|
|
void foo<T1, T2 extends String>() {
|
|
foo<^>();
|
|
}
|
|
''';
|
|
|
|
const expectedLabel = 'void foo<T1, T2 extends String>()';
|
|
const expectedDoc = 'My Foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'T1'),
|
|
ParameterInformation(label: 'T2 extends String'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_typeParams_method() async {
|
|
var content = '''
|
|
class Foo {
|
|
/// My Foo.
|
|
void foo<T1, T2 extends String>() {
|
|
foo<^>();
|
|
}
|
|
}
|
|
''';
|
|
|
|
const expectedLabel = 'void foo<T1, T2 extends String>()';
|
|
const expectedDoc = 'My Foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'T1'),
|
|
ParameterInformation(label: 'T2 extends String'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> test_typeParams_primaryConstructor() async {
|
|
var content = '''
|
|
class A<T1, T2>(int x);
|
|
var a = A<^>();
|
|
''';
|
|
|
|
var expectedLabel = 'class A<T1, T2>';
|
|
var expectedParams = [
|
|
ParameterInformation(label: 'T1'),
|
|
ParameterInformation(label: 'T2'),
|
|
];
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedParams: expectedParams,
|
|
);
|
|
}
|
|
|
|
Future<void> test_unopenFile() async {
|
|
var content = '''
|
|
/// Does foo.
|
|
foo(String s, int i) {
|
|
foo(^);
|
|
}
|
|
''';
|
|
var expectedLabel = 'foo(String s, int i)';
|
|
var expectedDoc = 'Does foo.';
|
|
|
|
await _expectSignature(
|
|
content,
|
|
expectedLabel,
|
|
expectedDoc: expectedDoc,
|
|
expectedParams: [
|
|
ParameterInformation(label: 'String s'),
|
|
ParameterInformation(label: 'int i'),
|
|
],
|
|
state: _FileState.closed,
|
|
);
|
|
}
|
|
}
|
|
|
|
enum _FileState { open, closed }
|