diff --git a/src/language/validation/safe-ds-validator.ts b/src/language/validation/safe-ds-validator.ts index c38d2d943..633cad68e 100644 --- a/src/language/validation/safe-ds-validator.ts +++ b/src/language/validation/safe-ds-validator.ts @@ -6,13 +6,12 @@ import { annotationParameterListShouldNotBeEmpty, assignmentShouldHaveMoreThanWildcardsAsAssignees, classBodyShouldNotBeEmpty, - classTypeParameterListShouldNotBeEmpty, + constraintListShouldNotBeEmpty, enumBodyShouldNotBeEmpty, enumVariantParameterListShouldNotBeEmpty, - enumVariantTypeParameterListShouldNotBeEmpty, functionResultListShouldNotBeEmpty, - functionTypeParameterListShouldNotBeEmpty, segmentResultListShouldNotBeEmpty, + typeParameterListShouldNotBeEmpty, unionTypeShouldNotHaveASingularTypeArgument, } from './style.js'; import { templateStringMustHaveExpressionBetweenTwoStringParts } from './other/expressions/templateStrings.js'; @@ -31,17 +30,19 @@ export const registerValidationChecks = function (services: SafeDsServices) { SdsAssignment: [assignmentShouldHaveMoreThanWildcardsAsAssignees], SdsAnnotation: [annotationParameterListShouldNotBeEmpty], SdsAttribute: [attributeMustHaveTypeHint], - SdsClass: [classBodyShouldNotBeEmpty, classTypeParameterListShouldNotBeEmpty], + SdsClassBody: [classBodyShouldNotBeEmpty], + SdsConstraintList: [constraintListShouldNotBeEmpty], SdsDeclaration: [nameMustNotStartWithBlockLambdaPrefix, nameShouldHaveCorrectCasing], - SdsEnum: [enumBodyShouldNotBeEmpty], - SdsEnumVariant: [enumVariantParameterListShouldNotBeEmpty, enumVariantTypeParameterListShouldNotBeEmpty], - SdsFunction: [functionResultListShouldNotBeEmpty, functionTypeParameterListShouldNotBeEmpty], + SdsEnumBody: [enumBodyShouldNotBeEmpty], + SdsEnumVariant: [enumVariantParameterListShouldNotBeEmpty], + SdsFunction: [functionResultListShouldNotBeEmpty], SdsModule: [moduleDeclarationsMustMatchFileKind, moduleWithDeclarationsMustStatePackage], SdsParameter: [parameterMustHaveTypeHint], SdsResult: [resultMustHaveTypeHint], SdsSegment: [segmentResultListShouldNotBeEmpty], SdsTemplateString: [templateStringMustHaveExpressionBetweenTwoStringParts], SdsTypeParameterConstraint: [typeParameterConstraintLeftOperandMustBeOwnTypeParameter], + SdsTypeParameterList: [typeParameterListShouldNotBeEmpty], SdsUnionType: [unionTypeShouldNotHaveASingularTypeArgument], SdsYield: [yieldMustNotBeUsedInPipeline], }; diff --git a/src/language/validation/style.ts b/src/language/validation/style.ts index 442d0aa92..2df07a734 100644 --- a/src/language/validation/style.ts +++ b/src/language/validation/style.ts @@ -2,11 +2,13 @@ import { isSdsWildcard, SdsAnnotation, SdsAssignment, - SdsClass, - SdsEnum, + SdsClassBody, + SdsConstraintList, + SdsEnumBody, SdsEnumVariant, SdsFunction, SdsSegment, + SdsTypeParameterList, SdsUnionType, } from '../generated/ast.js'; import { ValidationAcceptor } from 'langium'; @@ -15,6 +17,7 @@ import { isEmpty } from 'radash'; export const CODE_STYLE_UNNECESSARY_ASSIGNMENT = 'style/unnecessary-assignment'; export const CODE_STYLE_UNNECESSARY_ARGUMENT_LIST = 'style/unnecessary-argument-list'; export const CODE_STYLE_UNNECESSARY_BODY = 'style/unnecessary-body'; +export const CODE_STYLE_UNNECESSARY_CONSTRAINT_LIST = 'style/unnecessary-constraint-list'; export const CODE_STYLE_UNNECESSARY_ELVIS_OPERATOR = 'style/unnecessary-elvis-operator'; export const CODE_STYLE_UNNECESSARY_SAFE_ACCESS = 'style/unnecessary-safe-access'; export const CODE_STYLE_UNNECESSARY_PARAMETER_LIST = 'style/unnecessary-parameter-list'; @@ -44,26 +47,37 @@ export const assignmentShouldHaveMoreThanWildcardsAsAssignees = ( // Unnecessary bodies // ----------------------------------------------------------------------------- -export const classBodyShouldNotBeEmpty = (node: SdsClass, accept: ValidationAcceptor) => { - if (node.body && isEmpty(node.body.members)) { +export const classBodyShouldNotBeEmpty = (node: SdsClassBody, accept: ValidationAcceptor) => { + if (isEmpty(node.members)) { accept('info', 'This body can be removed.', { node, - property: 'body', code: CODE_STYLE_UNNECESSARY_BODY, }); } }; -export const enumBodyShouldNotBeEmpty = (node: SdsEnum, accept: ValidationAcceptor) => { - if (node.body && isEmpty(node.body.variants)) { +export const enumBodyShouldNotBeEmpty = (node: SdsEnumBody, accept: ValidationAcceptor) => { + if (isEmpty(node.variants)) { accept('info', 'This body can be removed.', { node, - property: 'body', code: CODE_STYLE_UNNECESSARY_BODY, }); } }; +// ----------------------------------------------------------------------------- +// Unnecessary constraint list +// ----------------------------------------------------------------------------- + +export const constraintListShouldNotBeEmpty = (node: SdsConstraintList, accept: ValidationAcceptor) => { + if (isEmpty(node.constraints)) { + accept('info', 'This constraint list can be removed.', { + node, + code: CODE_STYLE_UNNECESSARY_CONSTRAINT_LIST, + }); + } +}; + // ----------------------------------------------------------------------------- // Unnecessary parameter lists // ----------------------------------------------------------------------------- @@ -116,31 +130,10 @@ export const segmentResultListShouldNotBeEmpty = (node: SdsSegment, accept: Vali // Unnecessary type parameter lists // ----------------------------------------------------------------------------- -export const classTypeParameterListShouldNotBeEmpty = (node: SdsClass, accept: ValidationAcceptor) => { - if (node.typeParameterList && isEmpty(node.typeParameterList.typeParameters)) { - accept('info', 'This type parameter list can be removed.', { - node, - property: 'typeParameterList', - code: CODE_STYLE_UNNECESSARY_TYPE_PARAMETER_LIST, - }); - } -}; - -export const enumVariantTypeParameterListShouldNotBeEmpty = (node: SdsEnumVariant, accept: ValidationAcceptor) => { - if (node.typeParameterList && isEmpty(node.typeParameterList.typeParameters)) { - accept('info', 'This type parameter list can be removed.', { - node, - property: 'typeParameterList', - code: CODE_STYLE_UNNECESSARY_TYPE_PARAMETER_LIST, - }); - } -}; - -export const functionTypeParameterListShouldNotBeEmpty = (node: SdsFunction, accept: ValidationAcceptor) => { - if (node.typeParameterList && isEmpty(node.typeParameterList.typeParameters)) { +export const typeParameterListShouldNotBeEmpty = (node: SdsTypeParameterList, accept: ValidationAcceptor) => { + if (isEmpty(node.typeParameters)) { accept('info', 'This type parameter list can be removed.', { node, - property: 'typeParameterList', code: CODE_STYLE_UNNECESSARY_TYPE_PARAMETER_LIST, }); } diff --git a/tests/resources/validation/style/unnecessary constraint list in annotation/main.sdstest b/tests/resources/validation/style/unnecessary constraint list in annotation/main.sdstest new file mode 100644 index 000000000..19fb92a9d --- /dev/null +++ b/tests/resources/validation/style/unnecessary constraint list in annotation/main.sdstest @@ -0,0 +1,9 @@ +package tests.validation.style.unnecessaryConstraintListInAnnotation + +// $TEST$ info "This constraint list can be removed." +annotation MyAnnotation1 »where {}« + +// $TEST$ no info "This constraint list can be removed." +annotation MyAnnotation2 »where { + T sub Int +}« diff --git a/tests/resources/validation/style/unnecessary constraint list in class/main.sdstest b/tests/resources/validation/style/unnecessary constraint list in class/main.sdstest new file mode 100644 index 000000000..254eeb421 --- /dev/null +++ b/tests/resources/validation/style/unnecessary constraint list in class/main.sdstest @@ -0,0 +1,9 @@ +package tests.validation.style.unnecessaryConstraintListInClass + +// $TEST$ info "This constraint list can be removed." +class MyClass1 »where {}« + +// $TEST$ no info "This constraint list can be removed." +class MyClass2 »where { + T sub Int +}« diff --git a/tests/resources/validation/style/unnecessary constraint list in enum variant/main.sdstest b/tests/resources/validation/style/unnecessary constraint list in enum variant/main.sdstest new file mode 100644 index 000000000..4c058c694 --- /dev/null +++ b/tests/resources/validation/style/unnecessary constraint list in enum variant/main.sdstest @@ -0,0 +1,11 @@ +package tests.validation.style.unnecessaryConstraintInEnumVariant + +enum MyEnum { + // $TEST$ info "This constraint list can be removed." + MyVariant1 »where {}« + + // $TEST$ no info "This constraint list can be removed." + MyVariant2() »where { + T sub Int + }« +} diff --git a/tests/resources/validation/style/unnecessary constraint list in function/main.sdstest b/tests/resources/validation/style/unnecessary constraint list in function/main.sdstest new file mode 100644 index 000000000..fa82757b9 --- /dev/null +++ b/tests/resources/validation/style/unnecessary constraint list in function/main.sdstest @@ -0,0 +1,9 @@ +package tests.validation.style.unnecessaryConstraintListInFunction + +// $TEST$ info "This constraint list can be removed." +fun myFunction1() »where {}« + +// $TEST$ no info "This constraint list can be removed." +fun myFunction2() »where { + T sub Int +}«