[analysis_server] Fix type aliases with multiple literal types in LSP TypeScript spec
Change-Id: I82a8344b5e4858355757b8d4d167a305f74f3ec4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/245172
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
index 299fa4e..4f05563 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
@@ -26552,8 +26552,16 @@
}
final notebookSelectorJson = json['notebookSelector'];
final notebookSelector = (notebookSelectorJson as List<Object?>)
- .map((item) => NotebookDocumentSyncOptionsNotebookSelector.fromJson(
- item as Map<String, Object?>))
+ .map((item) => NotebookDocumentSyncOptionsNotebookSelector.canParse(
+ item, nullLspJsonReporter)
+ ? Either2<NotebookDocumentSyncOptionsNotebookSelector, NotebookDocumentSyncOptionsNotebookSelector2>.t1(
+ NotebookDocumentSyncOptionsNotebookSelector.fromJson(
+ item as Map<String, Object?>))
+ : (NotebookDocumentSyncOptionsNotebookSelector2.canParse(item, nullLspJsonReporter)
+ ? Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>.t2(
+ NotebookDocumentSyncOptionsNotebookSelector2.fromJson(item as Map<String, Object?>))
+ : (throw '''$item was not one of (NotebookDocumentSyncOptionsNotebookSelector, NotebookDocumentSyncOptionsNotebookSelector2)''')))
.toList();
final saveJson = json['save'];
final save = saveJson as bool?;
@@ -26564,7 +26572,9 @@
}
/// The notebooks to be synced
- final List<NotebookDocumentSyncOptionsNotebookSelector> notebookSelector;
+ final List<
+ Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>> notebookSelector;
/// Whether save notification should be forwarded to the server. Will only be
/// honored if mode === `notebook`.
@@ -26572,8 +26582,7 @@
Map<String, Object?> toJson() {
var __result = <String, Object?>{};
- __result['notebookSelector'] =
- notebookSelector.map((item) => item.toJson()).toList();
+ __result['notebookSelector'] = notebookSelector;
if (save != null) {
__result['save'] = save;
}
@@ -26595,10 +26604,12 @@
}
if (!((notebookSelector is List<Object?> &&
(notebookSelector.every((item) =>
- NotebookDocumentSyncOptionsNotebookSelector.canParse(
- item, reporter)))))) {
+ (NotebookDocumentSyncOptionsNotebookSelector.canParse(
+ item, reporter) ||
+ NotebookDocumentSyncOptionsNotebookSelector2.canParse(
+ item, reporter))))))) {
reporter.reportError(
- 'must be of type List<NotebookDocumentSyncOptionsNotebookSelector>');
+ 'must be of type List<Either2<NotebookDocumentSyncOptionsNotebookSelector, NotebookDocumentSyncOptionsNotebookSelector2>>');
return false;
}
} finally {
@@ -26628,8 +26639,12 @@
return listEqual(
notebookSelector,
other.notebookSelector,
- (NotebookDocumentSyncOptionsNotebookSelector a,
- NotebookDocumentSyncOptionsNotebookSelector b) =>
+ (Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>
+ a,
+ Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>
+ b) =>
a == b) &&
save == other.save &&
true;
@@ -26715,6 +26730,74 @@
String toString() => jsonEncoder.convert(toJson());
}
+class NotebookDocumentSyncOptionsCells2 implements ToJsonable {
+ static const jsonHandler = LspJsonHandler(
+ NotebookDocumentSyncOptionsCells2.canParse,
+ NotebookDocumentSyncOptionsCells2.fromJson,
+ );
+
+ NotebookDocumentSyncOptionsCells2({
+ required this.language,
+ });
+ static NotebookDocumentSyncOptionsCells2 fromJson(Map<String, Object?> json) {
+ final languageJson = json['language'];
+ final language = languageJson as String;
+ return NotebookDocumentSyncOptionsCells2(
+ language: language,
+ );
+ }
+
+ final String language;
+
+ Map<String, Object?> toJson() {
+ var __result = <String, Object?>{};
+ __result['language'] = language;
+ return __result;
+ }
+
+ static bool canParse(Object? obj, LspJsonReporter reporter) {
+ if (obj is Map<String, Object?>) {
+ reporter.push('language');
+ try {
+ if (!obj.containsKey('language')) {
+ reporter.reportError('must not be undefined');
+ return false;
+ }
+ final language = obj['language'];
+ if (language == null) {
+ reporter.reportError('must not be null');
+ return false;
+ }
+ if (!(language is String)) {
+ reporter.reportError('must be of type String');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ return true;
+ } else {
+ reporter.reportError('must be of type NotebookDocumentSyncOptionsCells2');
+ return false;
+ }
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (other is NotebookDocumentSyncOptionsCells2 &&
+ other.runtimeType == NotebookDocumentSyncOptionsCells2) {
+ return language == other.language && true;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => language.hashCode;
+
+ @override
+ String toString() => jsonEncoder.convert(toJson());
+}
+
class NotebookDocumentSyncOptionsNotebookSelector implements ToJsonable {
static const jsonHandler = LspJsonHandler(
NotebookDocumentSyncOptionsNotebookSelector.canParse,
@@ -26722,34 +26805,33 @@
);
NotebookDocumentSyncOptionsNotebookSelector({
- required this.cells,
- this.notebookDocument,
+ this.cells,
+ required this.notebookDocument,
});
static NotebookDocumentSyncOptionsNotebookSelector fromJson(
Map<String, Object?> json) {
final cellsJson = json['cells'];
- final cells = (cellsJson as List<Object?>)
- .map((item) => NotebookDocumentSyncOptionsCells.fromJson(
+ final cells = (cellsJson as List<Object?>?)
+ ?.map((item) => NotebookDocumentSyncOptionsCells.fromJson(
item as Map<String, Object?>))
.toList();
final notebookDocumentJson = json['notebookDocument'];
- final notebookDocument = notebookDocumentJson == null
- ? null
- : ((NotebookDocumentFilter1.canParse(notebookDocumentJson, nullLspJsonReporter) ||
- NotebookDocumentFilter2.canParse(
- notebookDocumentJson, nullLspJsonReporter) ||
- NotebookDocumentFilter3.canParse(
- notebookDocumentJson, nullLspJsonReporter))
- ? Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>.t1(
- NotebookDocumentFilter1.canParse(notebookDocumentJson, nullLspJsonReporter)
- ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t1(
- NotebookDocumentFilter1.fromJson(
- notebookDocumentJson as Map<String, Object?>))
- : (NotebookDocumentFilter2.canParse(notebookDocumentJson, nullLspJsonReporter)
- ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t2(
- NotebookDocumentFilter2.fromJson(notebookDocumentJson as Map<String, Object?>))
- : (NotebookDocumentFilter3.canParse(notebookDocumentJson, nullLspJsonReporter) ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t3(NotebookDocumentFilter3.fromJson(notebookDocumentJson as Map<String, Object?>)) : (throw '''$notebookDocumentJson was not one of (NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3)'''))))
- : (notebookDocumentJson is String ? Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>.t2(notebookDocumentJson) : (throw '''$notebookDocumentJson was not one of (Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String)''')));
+ final notebookDocument = (NotebookDocumentFilter1.canParse(
+ notebookDocumentJson, nullLspJsonReporter) ||
+ NotebookDocumentFilter2.canParse(
+ notebookDocumentJson, nullLspJsonReporter) ||
+ NotebookDocumentFilter3.canParse(
+ notebookDocumentJson, nullLspJsonReporter))
+ ? Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>.t1(
+ NotebookDocumentFilter1.canParse(notebookDocumentJson, nullLspJsonReporter)
+ ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t1(
+ NotebookDocumentFilter1.fromJson(
+ notebookDocumentJson as Map<String, Object?>))
+ : (NotebookDocumentFilter2.canParse(notebookDocumentJson, nullLspJsonReporter)
+ ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t2(
+ NotebookDocumentFilter2.fromJson(notebookDocumentJson as Map<String, Object?>))
+ : (NotebookDocumentFilter3.canParse(notebookDocumentJson, nullLspJsonReporter) ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t3(NotebookDocumentFilter3.fromJson(notebookDocumentJson as Map<String, Object?>)) : (throw '''$notebookDocumentJson was not one of (NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3)'''))))
+ : (notebookDocumentJson is String ? Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>.t2(notebookDocumentJson) : (throw '''$notebookDocumentJson was not one of (Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String)'''));
return NotebookDocumentSyncOptionsNotebookSelector(
cells: cells,
notebookDocument: notebookDocument,
@@ -26757,21 +26839,21 @@
}
/// The cells of the matching notebook to be synced.
- final List<NotebookDocumentSyncOptionsCells> cells;
+ final List<NotebookDocumentSyncOptionsCells>? cells;
/// The notebook to be synced If a string value is provided it matches against
/// the notebook type. '*' matches every notebook.
final Either2<
Either3<NotebookDocumentFilter1, NotebookDocumentFilter2,
NotebookDocumentFilter3>,
- String>? notebookDocument;
+ String> notebookDocument;
Map<String, Object?> toJson() {
var __result = <String, Object?>{};
- __result['cells'] = cells.map((item) => item.toJson()).toList();
- if (notebookDocument != null) {
- __result['notebookDocument'] = notebookDocument;
+ if (cells != null) {
+ __result['cells'] = cells?.map((item) => item.toJson()).toList();
}
+ __result['notebookDocument'] = notebookDocument;
return __result;
}
@@ -26779,18 +26861,12 @@
if (obj is Map<String, Object?>) {
reporter.push('cells');
try {
- if (!obj.containsKey('cells')) {
- reporter.reportError('must not be undefined');
- return false;
- }
final cells = obj['cells'];
- if (cells == null) {
- reporter.reportError('must not be null');
- return false;
- }
- if (!((cells is List<Object?> &&
- (cells.every((item) =>
- NotebookDocumentSyncOptionsCells.canParse(item, reporter)))))) {
+ if (cells != null &&
+ !((cells is List<Object?> &&
+ (cells.every((item) =>
+ NotebookDocumentSyncOptionsCells.canParse(
+ item, reporter)))))) {
reporter.reportError(
'must be of type List<NotebookDocumentSyncOptionsCells>');
return false;
@@ -26800,14 +26876,19 @@
}
reporter.push('notebookDocument');
try {
+ if (!obj.containsKey('notebookDocument')) {
+ reporter.reportError('must not be undefined');
+ return false;
+ }
final notebookDocument = obj['notebookDocument'];
- if (notebookDocument != null &&
- !(((NotebookDocumentFilter1.canParse(notebookDocument, reporter) ||
- NotebookDocumentFilter2.canParse(
- notebookDocument, reporter) ||
- NotebookDocumentFilter3.canParse(
- notebookDocument, reporter)) ||
- notebookDocument is String))) {
+ if (notebookDocument == null) {
+ reporter.reportError('must not be null');
+ return false;
+ }
+ if (!(((NotebookDocumentFilter1.canParse(notebookDocument, reporter) ||
+ NotebookDocumentFilter2.canParse(notebookDocument, reporter) ||
+ NotebookDocumentFilter3.canParse(notebookDocument, reporter)) ||
+ notebookDocument is String))) {
reporter.reportError(
'must be of type Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>');
return false;
@@ -26849,6 +26930,140 @@
String toString() => jsonEncoder.convert(toJson());
}
+class NotebookDocumentSyncOptionsNotebookSelector2 implements ToJsonable {
+ static const jsonHandler = LspJsonHandler(
+ NotebookDocumentSyncOptionsNotebookSelector2.canParse,
+ NotebookDocumentSyncOptionsNotebookSelector2.fromJson,
+ );
+
+ NotebookDocumentSyncOptionsNotebookSelector2({
+ required this.cells,
+ this.notebookDocument,
+ });
+ static NotebookDocumentSyncOptionsNotebookSelector2 fromJson(
+ Map<String, Object?> json) {
+ final cellsJson = json['cells'];
+ final cells = (cellsJson as List<Object?>)
+ .map((item) => NotebookDocumentSyncOptionsCells2.fromJson(
+ item as Map<String, Object?>))
+ .toList();
+ final notebookDocumentJson = json['notebookDocument'];
+ final notebookDocument = notebookDocumentJson == null
+ ? null
+ : ((NotebookDocumentFilter1.canParse(notebookDocumentJson, nullLspJsonReporter) ||
+ NotebookDocumentFilter2.canParse(
+ notebookDocumentJson, nullLspJsonReporter) ||
+ NotebookDocumentFilter3.canParse(
+ notebookDocumentJson, nullLspJsonReporter))
+ ? Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>.t1(
+ NotebookDocumentFilter1.canParse(notebookDocumentJson, nullLspJsonReporter)
+ ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t1(
+ NotebookDocumentFilter1.fromJson(
+ notebookDocumentJson as Map<String, Object?>))
+ : (NotebookDocumentFilter2.canParse(notebookDocumentJson, nullLspJsonReporter)
+ ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t2(
+ NotebookDocumentFilter2.fromJson(notebookDocumentJson as Map<String, Object?>))
+ : (NotebookDocumentFilter3.canParse(notebookDocumentJson, nullLspJsonReporter) ? Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>.t3(NotebookDocumentFilter3.fromJson(notebookDocumentJson as Map<String, Object?>)) : (throw '''$notebookDocumentJson was not one of (NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3)'''))))
+ : (notebookDocumentJson is String ? Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>.t2(notebookDocumentJson) : (throw '''$notebookDocumentJson was not one of (Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String)''')));
+ return NotebookDocumentSyncOptionsNotebookSelector2(
+ cells: cells,
+ notebookDocument: notebookDocument,
+ );
+ }
+
+ /// The cells of the matching notebook to be synced.
+ final List<NotebookDocumentSyncOptionsCells2> cells;
+
+ /// The notebook to be synced If a string value is provided it matches against
+ /// the notebook type. '*' matches every notebook.
+ final Either2<
+ Either3<NotebookDocumentFilter1, NotebookDocumentFilter2,
+ NotebookDocumentFilter3>,
+ String>? notebookDocument;
+
+ Map<String, Object?> toJson() {
+ var __result = <String, Object?>{};
+ __result['cells'] = cells.map((item) => item.toJson()).toList();
+ if (notebookDocument != null) {
+ __result['notebookDocument'] = notebookDocument;
+ }
+ return __result;
+ }
+
+ static bool canParse(Object? obj, LspJsonReporter reporter) {
+ if (obj is Map<String, Object?>) {
+ reporter.push('cells');
+ try {
+ if (!obj.containsKey('cells')) {
+ reporter.reportError('must not be undefined');
+ return false;
+ }
+ final cells = obj['cells'];
+ if (cells == null) {
+ reporter.reportError('must not be null');
+ return false;
+ }
+ if (!((cells is List<Object?> &&
+ (cells.every((item) => NotebookDocumentSyncOptionsCells2.canParse(
+ item, reporter)))))) {
+ reporter.reportError(
+ 'must be of type List<NotebookDocumentSyncOptionsCells2>');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ reporter.push('notebookDocument');
+ try {
+ final notebookDocument = obj['notebookDocument'];
+ if (notebookDocument != null &&
+ !(((NotebookDocumentFilter1.canParse(notebookDocument, reporter) ||
+ NotebookDocumentFilter2.canParse(
+ notebookDocument, reporter) ||
+ NotebookDocumentFilter3.canParse(
+ notebookDocument, reporter)) ||
+ notebookDocument is String))) {
+ reporter.reportError(
+ 'must be of type Either2<Either3<NotebookDocumentFilter1, NotebookDocumentFilter2, NotebookDocumentFilter3>, String>');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ return true;
+ } else {
+ reporter.reportError(
+ 'must be of type NotebookDocumentSyncOptionsNotebookSelector2');
+ return false;
+ }
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (other is NotebookDocumentSyncOptionsNotebookSelector2 &&
+ other.runtimeType == NotebookDocumentSyncOptionsNotebookSelector2) {
+ return listEqual(
+ cells,
+ other.cells,
+ (NotebookDocumentSyncOptionsCells2 a,
+ NotebookDocumentSyncOptionsCells2 b) =>
+ a == b) &&
+ notebookDocument == other.notebookDocument &&
+ true;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => Object.hash(
+ lspHashCode(cells),
+ notebookDocument,
+ );
+
+ @override
+ String toString() => jsonEncoder.convert(toJson());
+}
+
/// Registration options specific to a notebook.
/// @since 3.17.0
class NotebookDocumentSyncRegistrationOptions
@@ -26872,8 +27087,16 @@
final id = idJson as String?;
final notebookSelectorJson = json['notebookSelector'];
final notebookSelector = (notebookSelectorJson as List<Object?>)
- .map((item) => NotebookDocumentSyncOptionsNotebookSelector.fromJson(
- item as Map<String, Object?>))
+ .map((item) => NotebookDocumentSyncOptionsNotebookSelector.canParse(
+ item, nullLspJsonReporter)
+ ? Either2<NotebookDocumentSyncOptionsNotebookSelector, NotebookDocumentSyncOptionsNotebookSelector2>.t1(
+ NotebookDocumentSyncOptionsNotebookSelector.fromJson(
+ item as Map<String, Object?>))
+ : (NotebookDocumentSyncOptionsNotebookSelector2.canParse(item, nullLspJsonReporter)
+ ? Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>.t2(
+ NotebookDocumentSyncOptionsNotebookSelector2.fromJson(item as Map<String, Object?>))
+ : (throw '''$item was not one of (NotebookDocumentSyncOptionsNotebookSelector, NotebookDocumentSyncOptionsNotebookSelector2)''')))
.toList();
final saveJson = json['save'];
final save = saveJson as bool?;
@@ -26889,7 +27112,9 @@
final String? id;
/// The notebooks to be synced
- final List<NotebookDocumentSyncOptionsNotebookSelector> notebookSelector;
+ final List<
+ Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>> notebookSelector;
/// Whether save notification should be forwarded to the server. Will only be
/// honored if mode === `notebook`.
@@ -26900,8 +27125,7 @@
if (id != null) {
__result['id'] = id;
}
- __result['notebookSelector'] =
- notebookSelector.map((item) => item.toJson()).toList();
+ __result['notebookSelector'] = notebookSelector;
if (save != null) {
__result['save'] = save;
}
@@ -26933,10 +27157,12 @@
}
if (!((notebookSelector is List<Object?> &&
(notebookSelector.every((item) =>
- NotebookDocumentSyncOptionsNotebookSelector.canParse(
- item, reporter)))))) {
+ (NotebookDocumentSyncOptionsNotebookSelector.canParse(
+ item, reporter) ||
+ NotebookDocumentSyncOptionsNotebookSelector2.canParse(
+ item, reporter))))))) {
reporter.reportError(
- 'must be of type List<NotebookDocumentSyncOptionsNotebookSelector>');
+ 'must be of type List<Either2<NotebookDocumentSyncOptionsNotebookSelector, NotebookDocumentSyncOptionsNotebookSelector2>>');
return false;
}
} finally {
@@ -26968,8 +27194,12 @@
listEqual(
notebookSelector,
other.notebookSelector,
- (NotebookDocumentSyncOptionsNotebookSelector a,
- NotebookDocumentSyncOptionsNotebookSelector b) =>
+ (Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>
+ a,
+ Either2<NotebookDocumentSyncOptionsNotebookSelector,
+ NotebookDocumentSyncOptionsNotebookSelector2>
+ b) =>
a == b) &&
save == other.save &&
true;
diff --git a/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart b/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
index 6cf66db..d2b2eab 100644
--- a/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
+++ b/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
@@ -253,6 +253,10 @@
final List<Token> _tokens;
int _current = 0;
final List<AstNode> _nodes = [];
+
+ /// A set of names already used (or reserved) by nodes.
+ final Set<String> _nodeNames = {};
+
Parser(this._tokens);
bool get _isAtEnd => _peek().type == TokenType.EOF;
@@ -260,7 +264,7 @@
List<AstNode> parse() {
if (_nodes.isEmpty) {
while (!_isAtEnd) {
- _nodes.add(_topLevel());
+ _addNode(_topLevel());
// Consume any trailing semicolons.
_match([TokenType.SEMI_COLON]);
}
@@ -268,6 +272,13 @@
return _nodes;
}
+ /// Adds [node] to the current list and prevents its name from being used
+ /// by generated interfaces.
+ void _addNode(AstNode node) {
+ _nodeNames.add(node.name);
+ _nodes.add(node);
+ }
+
/// Returns the current token and moves to the next.
Token _advance() => _tokenAt(_current++);
@@ -425,6 +436,28 @@
allowsNull: canBeNull, allowsUndefined: canBeUndefined);
}
+ /// Gets an available name for a node.
+ ///
+ /// If the computed name is already used, a number will be appended to the
+ /// end.
+ String _getAvailableName(String containerName, String? fieldName) {
+ final name = _joinNames(containerName, fieldName ?? '');
+ final requiresSuffix = fieldName == null;
+ // If the name has already been taken, try appending a number and try
+ // again.
+ String generatedName;
+ var suffixIndex = 1;
+ do {
+ if (suffixIndex > 20) {
+ throw 'Failed to generate an available name for $name';
+ }
+ generatedName =
+ requiresSuffix || suffixIndex > 1 ? '$name$suffixIndex' : name;
+ suffixIndex++;
+ } while (_nodeNames.contains(generatedName));
+ return generatedName;
+ }
+
Indexer _indexer(String containerName, Comment? leadingComment) {
final indexer = _field(containerName, leadingComment);
_consume(TokenType.RIGHT_BRACKET, 'Expected ]');
@@ -592,9 +625,7 @@
if (includeUndefined) {
types.add(Type.Undefined);
}
- var typeIndex = 0;
while (true) {
- typeIndex++;
TypeBase type;
if (_match([TokenType.LEFT_BRACE])) {
// Inline interfaces.
@@ -613,13 +644,8 @@
type = MapType(indexer.indexType, indexer.valueType);
} else {
// Add a synthetic interface to the parsers list of nodes to represent this type.
- // If we have no fieldName to base the synthetic name from, we should use
- // the index of this type, for example in:
- // type Foo = { [..] } | { [...] }
- // we will generate Foo1 and Foo2 for the types.
- final nameSuffix = fieldName ?? '$typeIndex';
- final generatedName = _joinNames(containerName, nameSuffix);
- _nodes.add(InlineInterface(generatedName, members));
+ final generatedName = _getAvailableName(containerName, fieldName);
+ _addNode(InlineInterface(generatedName, members));
// Record the type as a simple type that references this interface.
type = Type.identifier(generatedName);
}
@@ -705,6 +731,10 @@
TypeAlias _typeAlias(Comment? leadingComment) {
final name = _consume(TokenType.IDENTIFIER, 'Expected identifier');
_consume(TokenType.EQUAL, 'Expected =');
+ // Reserve the name for this alias before we start reading its type so that
+ // inline/literal types will not try to compute the same name if they do
+ // not have field names.
+ _nodeNames.add(name.lexeme);
final type = _type(name.lexeme, null);
if (!_isAtEnd) {
_consume(TokenType.SEMI_COLON, 'Expected ;');