Updates to pase tuples in LSP spec

Change-Id: Ia1ce7579e954a8000b3460445859a2d221cf1a8c
Reviewed-on: https://dart-review.googlesource.com/c/87441
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Danny Tuppeny <dantup@google.com>
This commit is contained in:
Danny Tuppeny 2018-12-17 17:58:17 +00:00 committed by commit-bot@chromium.org
parent 988a376803
commit 666eee40c7
5 changed files with 338 additions and 33 deletions

View file

@ -4935,6 +4935,95 @@ class Location implements ToJsonable {
String toString() => jsonEncoder.convert(toJson());
}
class LocationLink implements ToJsonable {
LocationLink(this.originSelectionRange, this.targetUri, this.targetRange,
this.targetSelectionRange) {
if (targetUri == null) {
throw 'targetUri is required but was not provided';
}
if (targetRange == null) {
throw 'targetRange is required but was not provided';
}
}
static LocationLink fromJson(Map<String, dynamic> json) {
final originSelectionRange = json['originSelectionRange'] != null
? Range.fromJson(json['originSelectionRange'])
: null;
final targetUri = json['targetUri'];
final targetRange = json['targetRange'] != null
? Range.fromJson(json['targetRange'])
: null;
final targetSelectionRange = json['targetSelectionRange'] != null
? Range.fromJson(json['targetSelectionRange'])
: null;
return new LocationLink(
originSelectionRange, targetUri, targetRange, targetSelectionRange);
}
/// Span of the origin of this link.
///
/// Used as the underlined span for mouse interaction. Defaults to the word
/// range at the mouse position.
final Range originSelectionRange;
/// The full target range of this link.
final Range targetRange;
/// The span of this link.
final Range targetSelectionRange;
/// The target resource identifier of this link.
final String targetUri;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
if (originSelectionRange != null) {
__result['originSelectionRange'] = originSelectionRange;
}
__result['targetUri'] =
targetUri ?? (throw 'targetUri is required but was not set');
__result['targetRange'] =
targetRange ?? (throw 'targetRange is required but was not set');
if (targetSelectionRange != null) {
__result['targetSelectionRange'] = targetSelectionRange;
}
return __result;
}
static bool canParse(Object obj) {
return obj is Map<String, dynamic> &&
obj.containsKey('targetUri') &&
obj['targetUri'] is String &&
obj.containsKey('targetRange') &&
Range.canParse(obj['targetRange']);
}
@override
bool operator ==(other) {
if (other is LocationLink) {
return originSelectionRange == other.originSelectionRange &&
targetUri == other.targetUri &&
targetRange == other.targetRange &&
targetSelectionRange == other.targetSelectionRange &&
true;
}
return false;
}
@override
int get hashCode {
int hash = 0;
hash = JenkinsSmiHash.combine(hash, originSelectionRange.hashCode);
hash = JenkinsSmiHash.combine(hash, targetUri.hashCode);
hash = JenkinsSmiHash.combine(hash, targetRange.hashCode);
hash = JenkinsSmiHash.combine(hash, targetSelectionRange.hashCode);
return JenkinsSmiHash.finish(hash);
}
@override
String toString() => jsonEncoder.convert(toJson());
}
class LogMessageParams implements ToJsonable {
LogMessageParams(this.type, this.message) {
if (type == null) {
@ -5276,6 +5365,7 @@ class Method {
case r'completionItem/resolve':
case r'textDocument/hover':
case r'textDocument/signatureHelp':
case r'textDocument/declaration':
case r'textDocument/definition':
case r'textDocument/typeDefinition':
case r'textDocument/implementation':
@ -5397,6 +5487,10 @@ class Method {
static const textDocument_signatureHelp =
const Method._(r'textDocument/signatureHelp');
/// Constant for the 'textDocument/declaration' method.
static const textDocument_declaration =
const Method._(r'textDocument/declaration');
/// Constant for the 'textDocument/definition' method.
static const textDocument_definition =
const Method._(r'textDocument/definition');
@ -5571,7 +5665,12 @@ class ParameterInformation implements ToJsonable {
/// but can be omitted.
final Either2<String, MarkupContent> documentation;
/// The label of this parameter. Will be shown in the UI.
/// The label of this parameter information.
///
/// Either a string or an inclusive start and exclusive end offsets within its
/// containing signature label. (see SignatureInformation.label). *Note*: A
/// label of type string must be a substring of its containing signature
/// label.
final String label;
Map<String, dynamic> toJson() {
@ -7866,6 +7965,7 @@ class TextDocumentClientCapabilities implements ToJsonable {
this.formatting,
this.rangeFormatting,
this.onTypeFormatting,
this.declaration,
this.definition,
this.typeDefinition,
this.implementation,
@ -7913,6 +8013,10 @@ class TextDocumentClientCapabilities implements ToJsonable {
? TextDocumentClientCapabilitiesOnTypeFormatting.fromJson(
json['onTypeFormatting'])
: null;
final declaration = json['declaration'] != null
? TextDocumentClientCapabilitiesDeclaration.fromJson(
json['declaration'])
: null;
final definition = json['definition'] != null
? TextDocumentClientCapabilitiesDefinition.fromJson(json['definition'])
: null;
@ -7960,6 +8064,7 @@ class TextDocumentClientCapabilities implements ToJsonable {
formatting,
rangeFormatting,
onTypeFormatting,
declaration,
definition,
typeDefinition,
implementation,
@ -7987,6 +8092,9 @@ class TextDocumentClientCapabilities implements ToJsonable {
/// Capabilities specific to the `textDocument/completion`
final TextDocumentClientCapabilitiesCompletion completion;
/// Capabilities specific to the `textDocument/declaration`
final TextDocumentClientCapabilitiesDeclaration declaration;
/// Capabilities specific to the `textDocument/definition`
final TextDocumentClientCapabilitiesDefinition definition;
@ -8071,6 +8179,9 @@ class TextDocumentClientCapabilities implements ToJsonable {
if (onTypeFormatting != null) {
__result['onTypeFormatting'] = onTypeFormatting;
}
if (declaration != null) {
__result['declaration'] = declaration;
}
if (definition != null) {
__result['definition'] = definition;
}
@ -8121,6 +8232,7 @@ class TextDocumentClientCapabilities implements ToJsonable {
formatting == other.formatting &&
rangeFormatting == other.rangeFormatting &&
onTypeFormatting == other.onTypeFormatting &&
declaration == other.declaration &&
definition == other.definition &&
typeDefinition == other.typeDefinition &&
implementation == other.implementation &&
@ -8149,6 +8261,7 @@ class TextDocumentClientCapabilities implements ToJsonable {
hash = JenkinsSmiHash.combine(hash, formatting.hashCode);
hash = JenkinsSmiHash.combine(hash, rangeFormatting.hashCode);
hash = JenkinsSmiHash.combine(hash, onTypeFormatting.hashCode);
hash = JenkinsSmiHash.combine(hash, declaration.hashCode);
hash = JenkinsSmiHash.combine(hash, definition.hashCode);
hash = JenkinsSmiHash.combine(hash, typeDefinition.hashCode);
hash = JenkinsSmiHash.combine(hash, implementation.hashCode);
@ -8652,22 +8765,88 @@ class TextDocumentClientCapabilitiesCompletionItemKind implements ToJsonable {
String toString() => jsonEncoder.convert(toJson());
}
class TextDocumentClientCapabilitiesDefinition implements ToJsonable {
TextDocumentClientCapabilitiesDefinition(this.dynamicRegistration);
static TextDocumentClientCapabilitiesDefinition fromJson(
class TextDocumentClientCapabilitiesDeclaration implements ToJsonable {
TextDocumentClientCapabilitiesDeclaration(
this.dynamicRegistration, this.linkSupport);
static TextDocumentClientCapabilitiesDeclaration fromJson(
Map<String, dynamic> json) {
final dynamicRegistration = json['dynamicRegistration'];
return new TextDocumentClientCapabilitiesDefinition(dynamicRegistration);
final linkSupport = json['linkSupport'];
return new TextDocumentClientCapabilitiesDeclaration(
dynamicRegistration, linkSupport);
}
/// Whether definition supports dynamic registration.
/// Whether declaration supports dynamic registration. If this is set to
/// `true` the client supports the new `(TextDocumentRegistrationOptions &
/// StaticRegistrationOptions)` return value for the corresponding server
/// capability as well.
final bool dynamicRegistration;
/// The client supports additional metadata in the form of declaration links.
final bool linkSupport;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
if (dynamicRegistration != null) {
__result['dynamicRegistration'] = dynamicRegistration;
}
if (linkSupport != null) {
__result['linkSupport'] = linkSupport;
}
return __result;
}
static bool canParse(Object obj) {
return obj is Map<String, dynamic>;
}
@override
bool operator ==(other) {
if (other is TextDocumentClientCapabilitiesDeclaration) {
return dynamicRegistration == other.dynamicRegistration &&
linkSupport == other.linkSupport &&
true;
}
return false;
}
@override
int get hashCode {
int hash = 0;
hash = JenkinsSmiHash.combine(hash, dynamicRegistration.hashCode);
hash = JenkinsSmiHash.combine(hash, linkSupport.hashCode);
return JenkinsSmiHash.finish(hash);
}
@override
String toString() => jsonEncoder.convert(toJson());
}
class TextDocumentClientCapabilitiesDefinition implements ToJsonable {
TextDocumentClientCapabilitiesDefinition(
this.dynamicRegistration, this.linkSupport);
static TextDocumentClientCapabilitiesDefinition fromJson(
Map<String, dynamic> json) {
final dynamicRegistration = json['dynamicRegistration'];
final linkSupport = json['linkSupport'];
return new TextDocumentClientCapabilitiesDefinition(
dynamicRegistration, linkSupport);
}
/// Whether definition supports dynamic registration.
final bool dynamicRegistration;
/// The client supports additional metadata in the form of definition links.
final bool linkSupport;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
if (dynamicRegistration != null) {
__result['dynamicRegistration'] = dynamicRegistration;
}
if (linkSupport != null) {
__result['linkSupport'] = linkSupport;
}
return __result;
}
@ -8678,7 +8857,9 @@ class TextDocumentClientCapabilitiesDefinition implements ToJsonable {
@override
bool operator ==(other) {
if (other is TextDocumentClientCapabilitiesDefinition) {
return dynamicRegistration == other.dynamicRegistration && true;
return dynamicRegistration == other.dynamicRegistration &&
linkSupport == other.linkSupport &&
true;
}
return false;
}
@ -8687,6 +8868,7 @@ class TextDocumentClientCapabilitiesDefinition implements ToJsonable {
int get hashCode {
int hash = 0;
hash = JenkinsSmiHash.combine(hash, dynamicRegistration.hashCode);
hash = JenkinsSmiHash.combine(hash, linkSupport.hashCode);
return JenkinsSmiHash.finish(hash);
}
@ -9021,12 +9203,14 @@ class TextDocumentClientCapabilitiesHover implements ToJsonable {
}
class TextDocumentClientCapabilitiesImplementation implements ToJsonable {
TextDocumentClientCapabilitiesImplementation(this.dynamicRegistration);
TextDocumentClientCapabilitiesImplementation(
this.dynamicRegistration, this.linkSupport);
static TextDocumentClientCapabilitiesImplementation fromJson(
Map<String, dynamic> json) {
final dynamicRegistration = json['dynamicRegistration'];
final linkSupport = json['linkSupport'];
return new TextDocumentClientCapabilitiesImplementation(
dynamicRegistration);
dynamicRegistration, linkSupport);
}
/// Whether implementation supports dynamic registration. If this is set to
@ -9035,11 +9219,17 @@ class TextDocumentClientCapabilitiesImplementation implements ToJsonable {
/// capability as well.
final bool dynamicRegistration;
/// The client supports additional metadata in the form of definition links.
final bool linkSupport;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
if (dynamicRegistration != null) {
__result['dynamicRegistration'] = dynamicRegistration;
}
if (linkSupport != null) {
__result['linkSupport'] = linkSupport;
}
return __result;
}
@ -9050,7 +9240,9 @@ class TextDocumentClientCapabilitiesImplementation implements ToJsonable {
@override
bool operator ==(other) {
if (other is TextDocumentClientCapabilitiesImplementation) {
return dynamicRegistration == other.dynamicRegistration && true;
return dynamicRegistration == other.dynamicRegistration &&
linkSupport == other.linkSupport &&
true;
}
return false;
}
@ -9059,6 +9251,7 @@ class TextDocumentClientCapabilitiesImplementation implements ToJsonable {
int get hashCode {
int hash = 0;
hash = JenkinsSmiHash.combine(hash, dynamicRegistration.hashCode);
hash = JenkinsSmiHash.combine(hash, linkSupport.hashCode);
return JenkinsSmiHash.finish(hash);
}
@ -9109,6 +9302,50 @@ class TextDocumentClientCapabilitiesOnTypeFormatting implements ToJsonable {
String toString() => jsonEncoder.convert(toJson());
}
class TextDocumentClientCapabilitiesParameterInformation implements ToJsonable {
TextDocumentClientCapabilitiesParameterInformation(this.labelOffsetSupport);
static TextDocumentClientCapabilitiesParameterInformation fromJson(
Map<String, dynamic> json) {
final labelOffsetSupport = json['labelOffsetSupport'];
return new TextDocumentClientCapabilitiesParameterInformation(
labelOffsetSupport);
}
/// The client supports processing label offsets instead of a simple label
/// string.
final bool labelOffsetSupport;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
if (labelOffsetSupport != null) {
__result['labelOffsetSupport'] = labelOffsetSupport;
}
return __result;
}
static bool canParse(Object obj) {
return obj is Map<String, dynamic>;
}
@override
bool operator ==(other) {
if (other is TextDocumentClientCapabilitiesParameterInformation) {
return labelOffsetSupport == other.labelOffsetSupport && true;
}
return false;
}
@override
int get hashCode {
int hash = 0;
hash = JenkinsSmiHash.combine(hash, labelOffsetSupport.hashCode);
return JenkinsSmiHash.finish(hash);
}
@override
String toString() => jsonEncoder.convert(toJson());
}
class TextDocumentClientCapabilitiesPublishDiagnostics implements ToJsonable {
TextDocumentClientCapabilitiesPublishDiagnostics(this.relatedInformation);
static TextDocumentClientCapabilitiesPublishDiagnostics fromJson(
@ -9351,26 +9588,37 @@ class TextDocumentClientCapabilitiesSignatureHelp implements ToJsonable {
}
class TextDocumentClientCapabilitiesSignatureInformation implements ToJsonable {
TextDocumentClientCapabilitiesSignatureInformation(this.documentationFormat);
TextDocumentClientCapabilitiesSignatureInformation(
this.documentationFormat, this.parameterInformation);
static TextDocumentClientCapabilitiesSignatureInformation fromJson(
Map<String, dynamic> json) {
final documentationFormat = json['documentationFormat']
?.map((item) => item != null ? MarkupKind.fromJson(item) : null)
?.cast<MarkupKind>()
?.toList();
final parameterInformation = json['parameterInformation'] != null
? TextDocumentClientCapabilitiesParameterInformation.fromJson(
json['parameterInformation'])
: null;
return new TextDocumentClientCapabilitiesSignatureInformation(
documentationFormat);
documentationFormat, parameterInformation);
}
/// The client supports the follow content formats for the documentation
/// property. The order describes the preferred format of the client.
final List<MarkupKind> documentationFormat;
/// Client capabilities specific to parameter information.
final TextDocumentClientCapabilitiesParameterInformation parameterInformation;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
if (documentationFormat != null) {
__result['documentationFormat'] = documentationFormat;
}
if (parameterInformation != null) {
__result['parameterInformation'] = parameterInformation;
}
return __result;
}
@ -9383,6 +9631,7 @@ class TextDocumentClientCapabilitiesSignatureInformation implements ToJsonable {
if (other is TextDocumentClientCapabilitiesSignatureInformation) {
return listEqual(documentationFormat, other.documentationFormat,
(MarkupKind a, MarkupKind b) => a == b) &&
parameterInformation == other.parameterInformation &&
true;
}
return false;
@ -9392,6 +9641,7 @@ class TextDocumentClientCapabilitiesSignatureInformation implements ToJsonable {
int get hashCode {
int hash = 0;
hash = JenkinsSmiHash.combine(hash, documentationFormat.hashCode);
hash = JenkinsSmiHash.combine(hash, parameterInformation.hashCode);
return JenkinsSmiHash.finish(hash);
}
@ -9526,12 +9776,14 @@ class TextDocumentClientCapabilitiesSynchronization implements ToJsonable {
}
class TextDocumentClientCapabilitiesTypeDefinition implements ToJsonable {
TextDocumentClientCapabilitiesTypeDefinition(this.dynamicRegistration);
TextDocumentClientCapabilitiesTypeDefinition(
this.dynamicRegistration, this.linkSupport);
static TextDocumentClientCapabilitiesTypeDefinition fromJson(
Map<String, dynamic> json) {
final dynamicRegistration = json['dynamicRegistration'];
final linkSupport = json['linkSupport'];
return new TextDocumentClientCapabilitiesTypeDefinition(
dynamicRegistration);
dynamicRegistration, linkSupport);
}
/// Whether typeDefinition supports dynamic registration. If this is set to
@ -9540,11 +9792,17 @@ class TextDocumentClientCapabilitiesTypeDefinition implements ToJsonable {
/// capability as well.
final bool dynamicRegistration;
/// The client supports additional metadata in the form of definition links.
final bool linkSupport;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
if (dynamicRegistration != null) {
__result['dynamicRegistration'] = dynamicRegistration;
}
if (linkSupport != null) {
__result['linkSupport'] = linkSupport;
}
return __result;
}
@ -9555,7 +9813,9 @@ class TextDocumentClientCapabilitiesTypeDefinition implements ToJsonable {
@override
bool operator ==(other) {
if (other is TextDocumentClientCapabilitiesTypeDefinition) {
return dynamicRegistration == other.dynamicRegistration && true;
return dynamicRegistration == other.dynamicRegistration &&
linkSupport == other.linkSupport &&
true;
}
return false;
}
@ -9564,6 +9824,7 @@ class TextDocumentClientCapabilitiesTypeDefinition implements ToJsonable {
int get hashCode {
int hash = 0;
hash = JenkinsSmiHash.combine(hash, dynamicRegistration.hashCode);
hash = JenkinsSmiHash.combine(hash, linkSupport.hashCode);
return JenkinsSmiHash.finish(hash);
}

View file

@ -520,6 +520,7 @@ mixin ClientCapabilitiesHelperMixin {
null,
null,
null,
null,
null);
final emptyWorkspaceClientCapabilities = new WorkspaceClientCapabilities(

View file

@ -283,5 +283,26 @@ export namespace ResourceOperationKind {
expect(delete.commentText,
equals('Supports deleting existing files and folders.'));
});
test('parses a tuple in an array', () {
final String input = '''
interface SomeInformation {
label: string | [number, number];
}
''';
final List<AstNode> output = parseFile(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
final Interface interface = output[0];
expect(interface.members, hasLength(1));
final Field field = interface.members.first;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('label'));
expect(field.type, const TypeMatcher<UnionType>());
UnionType union = field.type;
expect(union.types, hasLength(2));
expect(union.types[0], isSimpleType('string'));
expect(union.types[1], isArrayOf(isSimpleType('number')));
});
});
}

View file

@ -70,6 +70,9 @@ String getImprovedType(String interfaceName, String fieldName) {
"SymbolInformation": {
"kind": "SymbolKind",
},
"ParameterInformation": {
"label": "String",
}
};
final interface = _improvedTypeMappings[interfaceName];

View file

@ -379,13 +379,16 @@ class Parser {
_consume(TokenType.LEFT_BRACE, 'Expected {');
final members = <Member>[];
while (!_check(TokenType.RIGHT_BRACE)) {
members.add(_member(name.lexeme));
final member = _member(name.lexeme);
// TODO(dantup): Remove this temp workaround once spec is fixed/clarified.
// https://github.com/Microsoft/language-server-protocol/issues/643
if (members.any((m) => m.name == member.name)) {
print('Skipping duplicate member ${member.name} in ${name.lexeme}');
continue;
}
members.add(member);
}
// TODO(dantup): Temporary hack until we handle indexers. Remove nulls, which
// are (currently) returned by _field() for indexers.
members.removeWhere((m) => m == null);
_consume(TokenType.RIGHT_BRACE, 'Expected }');
return new Interface(leadingComment, name, typeArgs, baseTypes, members);
@ -478,10 +481,6 @@ class Parser {
members.add(_member(containerName));
}
// TODO(dantup): Temporary hack until we handle indexers. Remove nulls, which
// are (currently) returned by _field() for indexers.
members.removeWhere((m) => m == null);
_consume(TokenType.RIGHT_BRACE, 'Expected }');
// Some of the inline interfaces have trailing commas (and some do not!)
_match([TokenType.COMMA]);
@ -512,6 +511,21 @@ class Parser {
// export const Invoked: 1 = 1;
// the best we can do is use their base type (number).
type = Type.identifier('number');
} else if (_match([TokenType.LEFT_BRACKET])) {
// Tuples will just be converted to List/Array.
final tupleElementTypes = <TypeBase>[];
while (!_check(TokenType.RIGHT_BRACKET)) {
tupleElementTypes.add(_type(containerName, fieldName));
// Remove commas in between.
_match([TokenType.COMMA]);
}
_consume(TokenType.RIGHT_BRACKET, 'Expected ]');
final uniqueTypes = _getUniqueTypes(tupleElementTypes);
var tupleType = uniqueTypes.length == 1
? uniqueTypes.single
: new UnionType(uniqueTypes);
type = new ArrayType(tupleType);
} else {
var typeName = _consume(TokenType.IDENTIFIER, 'Expected identifier');
final typeArgs = <Type>[];
@ -553,12 +567,7 @@ class Parser {
}
}
// Remove any duplicate types (for ex. if we map multiple types into dynamic)
// we don't want to end up with `dynamic | dynamic`. Key on dartType to
// ensure we different types that will map down to the same type.
final uniqueTypes = new Map.fromEntries(
types.map((t) => new MapEntry(t.dartTypeWithTypeArgs, t)),
).values.toList();
final uniqueTypes = _getUniqueTypes(types);
var type = uniqueTypes.length == 1
? uniqueTypes.single
@ -574,6 +583,16 @@ class Parser {
return type;
}
/// Remove any duplicate types (for ex. if we map multiple types into dynamic)
/// we don't want to end up with `dynamic | dynamic`. Key on dartType to
/// ensure we different types that will map down to the same type.
List<TypeBase> _getUniqueTypes(List<TypeBase> types) {
final uniqueTypes = new Map.fromEntries(
types.map((t) => new MapEntry(t.dartTypeWithTypeArgs, t)),
).values.toList();
return uniqueTypes;
}
TypeAlias _typeAlias(Comment leadingComment) {
final name = _consume(TokenType.IDENTIFIER, 'Expected identifier');
_consume(TokenType.EQUAL, 'Expected =');