Always verify constants in LspEnum.
Change-Id: I4d62eacbf97c5f83e0eab378bc7d239ab934e6b8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/505623 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
dfa4478902
commit
d6c87cc934
@@ -22,7 +22,7 @@ class CodegenTest {
|
||||
LspEnum(
|
||||
name: 'x',
|
||||
typeOfValues: TypeReference.int,
|
||||
members: [
|
||||
constants: [
|
||||
Constant(name: 'new', type: TypeReference.string, value: '1'),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -29,13 +29,13 @@ ast.LspEnum _enum({
|
||||
String name = 'x',
|
||||
String type = 'int',
|
||||
bool flags = false,
|
||||
required List<ast.Member> members,
|
||||
required List<ast.Constant> constants,
|
||||
}) {
|
||||
return ast.LspEnum(
|
||||
name: name,
|
||||
typeOfValues: ast.TypeReference(type),
|
||||
flags: flags,
|
||||
members: members,
|
||||
constants: constants,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,22 +48,35 @@ ast.UnionType _union(List<String> names) =>
|
||||
class DartTest {
|
||||
void test_flags_requiresPowerOfTwo_double() {
|
||||
expect(
|
||||
() => _enum(flags: true, members: [_constant(1.2)]),
|
||||
throwsA(isA<AssertionError>()),
|
||||
() => _enum(flags: true, constants: [_constant(1.2)]),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
void test_flags_requiresPowerOfTwo_nonPowerOfTwo() {
|
||||
expect(
|
||||
() => _enum(flags: true, members: [_constant(3)]),
|
||||
throwsA(isA<AssertionError>()),
|
||||
() => _enum(flags: true, constants: [_constant(3)]),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
void test_flags_requiresPowerOfTwo_string() {
|
||||
expect(
|
||||
() => _enum(flags: true, members: [_constant('test')]),
|
||||
throwsA(isA<AssertionError>()),
|
||||
() => _enum(flags: true, constants: [_constant('test')]),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
void test_flags_requiresUniqueValues() {
|
||||
expect(
|
||||
() => _enum(
|
||||
flags: true,
|
||||
constants: [
|
||||
_constant(1, name: 'a'),
|
||||
_constant(1, name: 'b'),
|
||||
],
|
||||
),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -385,13 +385,10 @@ Sometimes after a blank line we'll have a note.
|
||||
|
||||
expect(output[0], const TypeMatcher<LspEnum>());
|
||||
var namespace = output[0] as LspEnum;
|
||||
expect(namespace.members, hasLength(3));
|
||||
for (var m in namespace.members) {
|
||||
expect(m, const TypeMatcher<Constant>());
|
||||
}
|
||||
var create = namespace.members[0] as Constant,
|
||||
delete = namespace.members[1] as Constant,
|
||||
rename = namespace.members[2] as Constant;
|
||||
expect(namespace.constants, hasLength(3));
|
||||
var create = namespace.constants[0],
|
||||
delete = namespace.constants[1],
|
||||
rename = namespace.constants[2];
|
||||
expect(create.name, equals('Create'));
|
||||
expect(create.type, isSimpleType('ResourceOperationKind'));
|
||||
expect(create.comment, equals('Supports creating new files and folders.'));
|
||||
|
||||
@@ -633,7 +633,7 @@ void _writeDocCommentsAndAnnotations(
|
||||
|
||||
void _writeEnumClass(IndentableStringBuffer buffer, LspEnum namespace) {
|
||||
_writeDocCommentsAndAnnotations(buffer, namespace);
|
||||
var consts = namespace.members.cast<Constant>().toList();
|
||||
var consts = namespace.constants;
|
||||
var namespaceName = namespace.name;
|
||||
var typeOfValues = namespace.typeOfValues;
|
||||
var allowsAnyValue = enumClassAllowsAnyValue(namespaceName);
|
||||
@@ -674,10 +674,10 @@ void _writeEnumClass(IndentableStringBuffer buffer, LspEnum namespace) {
|
||||
..outdent()
|
||||
..writeIndentedln('}');
|
||||
}
|
||||
namespace.members.whereType<Constant>().forEach((cons) {
|
||||
for (var cons in consts) {
|
||||
// We don't use any deprecated enum values, so omit them entirely.
|
||||
if (cons.isDeprecated) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
_writeDocCommentsAndAnnotations(buffer, cons);
|
||||
var memberName = cons.dartSafeName;
|
||||
@@ -685,7 +685,7 @@ void _writeEnumClass(IndentableStringBuffer buffer, LspEnum namespace) {
|
||||
buffer.writeIndentedln(
|
||||
'static const $memberName = $namespaceName$constructorName($value);',
|
||||
);
|
||||
});
|
||||
}
|
||||
if (namespace.flags) {
|
||||
buffer
|
||||
..writeln()
|
||||
|
||||
@@ -137,7 +137,7 @@ final interactiveFormClasses = <LspEntity>[
|
||||
name: 'FileExistence',
|
||||
typeOfValues: TypeReference.int,
|
||||
flags: true,
|
||||
members: [
|
||||
constants: [
|
||||
// Values should be powers of 2 to allow New|Existing.
|
||||
Constant(
|
||||
name: 'New',
|
||||
@@ -161,7 +161,7 @@ final interactiveFormClasses = <LspEntity>[
|
||||
name: 'FileType',
|
||||
typeOfValues: TypeReference.int,
|
||||
flags: true,
|
||||
members: [
|
||||
constants: [
|
||||
// Values should be powers of 2 to allow Regular|Directory.
|
||||
Constant(
|
||||
name: 'Regular',
|
||||
|
||||
@@ -185,23 +185,49 @@ abstract class LspEntity {
|
||||
class LspEnum extends LspEntity {
|
||||
final TypeBase typeOfValues;
|
||||
final bool flags;
|
||||
final List<Member> members;
|
||||
final List<Constant> constants;
|
||||
LspEnum({
|
||||
required super.name,
|
||||
super.comment,
|
||||
super.isProposed,
|
||||
required this.typeOfValues,
|
||||
this.flags = false,
|
||||
required this.members,
|
||||
}) : assert(
|
||||
!flags ||
|
||||
members
|
||||
.whereType<Constant>()
|
||||
.map((member) => int.tryParse(member.value))
|
||||
.every((value) => value != null && _isPowerOfTwo(value)),
|
||||
'flags enums require all enum values to be int powers of two.',
|
||||
) {
|
||||
members.sortBy((member) => member.name.toLowerCase());
|
||||
required this.constants,
|
||||
}) {
|
||||
_validateFlagsEnum();
|
||||
constants.sortBy((constant) => constant.name.toLowerCase());
|
||||
}
|
||||
|
||||
void _validateFlagsEnum() {
|
||||
if (!flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeOfValues.dartTypeWithTypeArgs != 'int') {
|
||||
throw ArgumentError(
|
||||
'Flags enum $name has value type ${typeOfValues.dartTypeWithTypeArgs}; '
|
||||
'flags enum values must be ints.',
|
||||
);
|
||||
}
|
||||
|
||||
var usedValues = <int>{};
|
||||
for (var constant in constants) {
|
||||
var value = int.tryParse(constant.value);
|
||||
if (value == null || !_isPowerOfTwo(value)) {
|
||||
throw ArgumentError(
|
||||
'Flags enum $name constant ${constant.name} has value '
|
||||
'${constant.value}; '
|
||||
'flags enum values must be int powers of two.',
|
||||
);
|
||||
}
|
||||
|
||||
if (!usedValues.add(value)) {
|
||||
throw ArgumentError(
|
||||
'Flags enum $name has duplicate value $value; '
|
||||
'flags enum values must be unique.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,9 +191,9 @@ class LspMetaModelCleaner {
|
||||
isProposed: namespace.isProposed,
|
||||
typeOfValues: namespace.typeOfValues,
|
||||
flags: namespace.flags,
|
||||
members: namespace.members
|
||||
constants: namespace.constants
|
||||
.where(_includeEntityInOutput)
|
||||
.map((member) => _cleanMember(namespace.name, member))
|
||||
.map(_cleanConst)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
@@ -387,7 +387,7 @@ class LspMetaModelCleaner {
|
||||
isProposed: dest.isProposed,
|
||||
typeOfValues: dest.typeOfValues,
|
||||
flags: dest.flags || source.flags,
|
||||
members: [...dest.members, ...source.members],
|
||||
constants: [...dest.constants, ...source.constants],
|
||||
);
|
||||
} else if (source is Interface && dest is Interface) {
|
||||
return Interface(
|
||||
@@ -533,7 +533,7 @@ class LspMetaModelCleaner {
|
||||
isProposed: type.isProposed,
|
||||
typeOfValues: type.typeOfValues,
|
||||
flags: type.flags,
|
||||
members: type.members,
|
||||
constants: type.constants,
|
||||
);
|
||||
} else {
|
||||
throw 'Renaming ${type.runtimeType} is not implemented';
|
||||
|
||||
@@ -60,7 +60,7 @@ class LspMetaModelReader {
|
||||
|
||||
return LspMetaModel(
|
||||
types: types,
|
||||
methods: methodsEnum?.members.cast<Constant>().toList() ?? [],
|
||||
methods: methodsEnum?.constants.toList() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ class LspMetaModelReader {
|
||||
name: 'Method',
|
||||
comment: comment,
|
||||
typeOfValues: TypeReference.string,
|
||||
members: methodConstants,
|
||||
constants: methodConstants,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ class LspMetaModelReader {
|
||||
comment: documentation,
|
||||
isProposed: _isProposed(documentation),
|
||||
typeOfValues: baseType,
|
||||
members: [
|
||||
constants: [
|
||||
...?(model['values'] as List?)?.map((p) => _extractEnumValue(type, p)),
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user