diff --git a/src/language/helpers/nodeProperties.ts b/src/language/helpers/nodeProperties.ts index e6009e10a..af0eb35b9 100644 --- a/src/language/helpers/nodeProperties.ts +++ b/src/language/helpers/nodeProperties.ts @@ -27,6 +27,7 @@ import { SdsCallable, SdsClass, SdsClassMember, + SdsColumn, SdsDeclaration, SdsEnum, SdsEnumVariant, @@ -42,6 +43,7 @@ import { SdsQualifiedImport, SdsResult, SdsResultList, + SdsSchema, SdsStatement, SdsType, SdsTypeArgument, @@ -132,13 +134,7 @@ export const blockLambdaResultsOrEmpty = (node: SdsBlockLambda | undefined): Sds .filter(isSdsBlockLambdaResult) .toArray(); }; -export const importedDeclarationsOrEmpty = (node: SdsQualifiedImport | undefined): SdsImportedDeclaration[] => { - return node?.importedDeclarationList?.importedDeclarations ?? []; -}; -export const literalsOrEmpty = (node: SdsLiteralType | undefined): SdsLiteral[] => { - return node?.literalList?.literals ?? []; -}; export const classMembersOrEmpty = ( node: SdsClass | undefined, filterFunction: (member: SdsClassMember) => boolean = () => true, @@ -146,6 +142,10 @@ export const classMembersOrEmpty = ( return node?.body?.members?.filter(filterFunction) ?? []; }; +export const columnsOrEmpty = (node: SdsSchema | undefined): SdsColumn[] => { + return node?.columnList?.columns ?? []; +}; + export const enumVariantsOrEmpty = (node: SdsEnum | undefined): SdsEnumVariant[] => { return node?.body?.variants ?? []; }; @@ -154,6 +154,14 @@ export const importsOrEmpty = (node: SdsModule | undefined): SdsImport[] => { return node?.imports ?? []; }; +export const importedDeclarationsOrEmpty = (node: SdsQualifiedImport | undefined): SdsImportedDeclaration[] => { + return node?.importedDeclarationList?.importedDeclarations ?? []; +}; + +export const literalsOrEmpty = (node: SdsLiteralType | undefined): SdsLiteral[] => { + return node?.literalList?.literals ?? []; +}; + export const moduleMembersOrEmpty = (node: SdsModule | undefined): SdsModuleMember[] => { return node?.members?.filter(isSdsModuleMember) ?? []; }; diff --git a/src/language/validation/names.ts b/src/language/validation/names.ts index c87e5b598..6357ffb48 100644 --- a/src/language/validation/names.ts +++ b/src/language/validation/names.ts @@ -1,4 +1,5 @@ import { + isSdsQualifiedImport, SdsAnnotation, SdsBlockLambda, SdsCallableType, @@ -8,21 +9,32 @@ import { SdsEnumVariant, SdsExpressionLambda, SdsFunction, + SdsImportedDeclaration, + SdsModule, SdsPipeline, + SdsSchema, SdsSegment, } from '../generated/ast.js'; -import { ValidationAcceptor } from 'langium'; +import { getDocument, ValidationAcceptor } from 'langium'; import { blockLambdaResultsOrEmpty, classMembersOrEmpty, + columnsOrEmpty, enumVariantsOrEmpty, + importedDeclarationsOrEmpty, + importsOrEmpty, isStatic, + moduleMembersOrEmpty, + packageNameOrUndefined, parametersOrEmpty, placeholdersOrEmpty, resultsOrEmpty, typeParametersOrEmpty, } from '../helpers/nodeProperties.js'; import { duplicatesBy } from '../helpers/collectionUtils.js'; +import { isInPipelineFile, isInStubFile, isInTestFile } from '../helpers/fileExtensions.js'; +import { declarationIsAllowedInPipelineFile, declarationIsAllowedInStubFile } from './other/modules.js'; +import { SafeDsServices } from '../safe-ds-module.js'; export const CODE_NAME_BLOCK_LAMBDA_PREFIX = 'name/block-lambda-prefix'; export const CODE_NAME_CASING = 'name/casing'; @@ -211,6 +223,75 @@ export const functionMustContainUniqueNames = (node: SdsFunction, accept: Valida ); }; +export const moduleMemberMustHaveNameThatIsUniqueInPackage = (services: SafeDsServices) => { + const packageManager = services.workspace.PackageManager; + + return (node: SdsModule, accept: ValidationAcceptor): void => { + for (const member of moduleMembersOrEmpty(node)) { + const packageName = packageNameOrUndefined(member) ?? ''; + const declarationsInPackage = packageManager.getDeclarationsInPackage(packageName); + const memberUri = getDocument(member).uri?.toString(); + + if ( + declarationsInPackage.some((it) => it.name === member.name && it.documentUri.toString() !== memberUri) + ) { + accept('error', `Multiple declarations in this package have the name '${member.name}'.`, { + node: member, + property: 'name', + code: CODE_NAME_DUPLICATE, + }); + } + } + }; +}; + +export const moduleMustContainUniqueNames = (node: SdsModule, accept: ValidationAcceptor): void => { + // Names of imported declarations must be unique + const importedDeclarations = importsOrEmpty(node).filter(isSdsQualifiedImport).flatMap(importedDeclarationsOrEmpty); + for (const duplicate of duplicatesBy(importedDeclarations, importedDeclarationName)) { + if (duplicate.alias) { + accept('error', `A declaration with name '${importedDeclarationName(duplicate)}' was imported already.`, { + node: duplicate.alias, + property: 'alias', + code: CODE_NAME_DUPLICATE, + }); + } else { + accept('error', `A declaration with name '${importedDeclarationName(duplicate)}' was imported already.`, { + node: duplicate, + property: 'declaration', + code: CODE_NAME_DUPLICATE, + }); + } + } + + // Names of module members must be unique + if (isInPipelineFile(node)) { + namesMustBeUnique( + moduleMembersOrEmpty(node), + (name) => `A declaration with name '${name}' exists already in this file.`, + accept, + declarationIsAllowedInPipelineFile, + ); + } else if (isInStubFile(node)) { + namesMustBeUnique( + moduleMembersOrEmpty(node), + (name) => `A declaration with name '${name}' exists already in this file.`, + accept, + declarationIsAllowedInStubFile, + ); + } else if (isInTestFile(node)) { + namesMustBeUnique( + moduleMembersOrEmpty(node), + (name) => `A declaration with name '${name}' exists already in this file.`, + accept, + ); + } +}; + +const importedDeclarationName = (node: SdsImportedDeclaration | undefined): string | undefined => { + return node?.alias?.alias ?? node?.declaration.ref?.name; +}; + export const pipelineMustContainUniqueNames = (node: SdsPipeline, accept: ValidationAcceptor): void => { namesMustBeUnique( placeholdersOrEmpty(node.body), @@ -219,6 +300,17 @@ export const pipelineMustContainUniqueNames = (node: SdsPipeline, accept: Valida ); }; +export const schemaMustContainUniqueNames = (node: SdsSchema, accept: ValidationAcceptor): void => { + const duplicates = duplicatesBy(columnsOrEmpty(node), (it) => it.columnName.value); + for (const duplicate of duplicates) { + accept('error', `A column with name '${duplicate.columnName.value}' exists already.`, { + node: duplicate, + property: 'columnName', + code: CODE_NAME_DUPLICATE, + }); + } +}; + export const segmentMustContainUniqueNames = (node: SdsSegment, accept: ValidationAcceptor): void => { const parametersAndPlaceholder = [...parametersOrEmpty(node), ...placeholdersOrEmpty(node.body)]; namesMustBeUnique( @@ -238,12 +330,15 @@ const namesMustBeUnique = ( nodes: Iterable, createMessage: (name: string) => string, accept: ValidationAcceptor, + shouldReportErrorOn: (node: SdsDeclaration) => boolean = () => true, ): void => { for (const node of duplicatesBy(nodes, (it) => it.name)) { - accept('error', createMessage(node.name), { - node, - property: 'name', - code: CODE_NAME_DUPLICATE, - }); + if (shouldReportErrorOn(node)) { + accept('error', createMessage(node.name), { + node, + property: 'name', + code: CODE_NAME_DUPLICATE, + }); + } } }; diff --git a/src/language/validation/other/modules.ts b/src/language/validation/other/modules.ts index 061f40f3a..2dcc94590 100644 --- a/src/language/validation/other/modules.ts +++ b/src/language/validation/other/modules.ts @@ -1,5 +1,5 @@ import { ValidationAcceptor } from 'langium'; -import { isSdsDeclaration, isSdsPipeline, isSdsSegment, SdsModule } from '../../generated/ast.js'; +import { isSdsDeclaration, isSdsPipeline, isSdsSegment, SdsDeclaration, SdsModule } from '../../generated/ast.js'; import { isInPipelineFile, isInStubFile } from '../../helpers/fileExtensions.js'; export const CODE_MODULE_MISSING_PACKAGE = 'module/missing-package'; @@ -24,7 +24,7 @@ export const moduleDeclarationsMustMatchFileKind = (node: SdsModule, accept: Val if (isInPipelineFile(node)) { for (const declaration of declarations) { - if (!isSdsPipeline(declaration) && !isSdsSegment(declaration)) { + if (!declarationIsAllowedInPipelineFile(declaration)) { accept('error', 'A pipeline file must only declare pipelines and segments.', { node: declaration, property: 'name', @@ -34,7 +34,7 @@ export const moduleDeclarationsMustMatchFileKind = (node: SdsModule, accept: Val } } else if (isInStubFile(node)) { for (const declaration of declarations) { - if (isSdsPipeline(declaration) || isSdsSegment(declaration)) { + if (!declarationIsAllowedInStubFile(declaration)) { accept('error', 'A stub file must not declare pipelines or segments.', { node: declaration, property: 'name', @@ -44,3 +44,11 @@ export const moduleDeclarationsMustMatchFileKind = (node: SdsModule, accept: Val } } }; + +export const declarationIsAllowedInPipelineFile = (declaration: SdsDeclaration): boolean => { + return isSdsPipeline(declaration) || isSdsSegment(declaration); +}; + +export const declarationIsAllowedInStubFile = (declaration: SdsDeclaration): boolean => { + return !isSdsPipeline(declaration) && !isSdsSegment(declaration); +}; diff --git a/src/language/validation/safe-ds-validator.ts b/src/language/validation/safe-ds-validator.ts index afe6d4775..93547e3f9 100644 --- a/src/language/validation/safe-ds-validator.ts +++ b/src/language/validation/safe-ds-validator.ts @@ -10,9 +10,12 @@ import { enumVariantMustContainUniqueNames, expressionLambdaMustContainUniqueNames, functionMustContainUniqueNames, + moduleMemberMustHaveNameThatIsUniqueInPackage, + moduleMustContainUniqueNames, nameMustNotStartWithBlockLambdaPrefix, nameShouldHaveCorrectCasing, pipelineMustContainUniqueNames, + schemaMustContainUniqueNames, segmentMustContainUniqueNames, } from './names.js'; import { @@ -156,7 +159,12 @@ export const registerValidationChecks = function (services: SafeDsServices) { memberAccessMustBeNullSafeIfReceiverIsNullable(services), memberAccessNullSafetyShouldBeNeeded(services), ], - SdsModule: [moduleDeclarationsMustMatchFileKind, moduleWithDeclarationsMustStatePackage], + SdsModule: [ + moduleDeclarationsMustMatchFileKind, + moduleMemberMustHaveNameThatIsUniqueInPackage(services), + moduleMustContainUniqueNames, + moduleWithDeclarationsMustStatePackage, + ], SdsNamedType: [ namedTypeDeclarationShouldNotBeDeprecated(services), namedTypeDeclarationShouldNotBeExperimental(services), @@ -181,6 +189,7 @@ export const registerValidationChecks = function (services: SafeDsServices) { referenceTargetShouldNotExperimental(services), ], SdsResult: [resultMustHaveTypeHint], + SdsSchema: [schemaMustContainUniqueNames], SdsSegment: [ segmentMustContainUniqueNames, segmentParameterShouldBeUsed(services), diff --git a/src/resources/builtins/safeds/lang/coreClasses.sdsstub b/src/resources/builtins/safeds/lang/coreClasses.sdsstub index 0ad91db59..1d966c47e 100644 --- a/src/resources/builtins/safeds/lang/coreClasses.sdsstub +++ b/src/resources/builtins/safeds/lang/coreClasses.sdsstub @@ -18,9 +18,6 @@ class Int sub Number @Description("A floating-point number.") class Float sub Number -@Description("A floating-point number.") -class Float sub Number - @Description("A list of elements.") class List diff --git a/tests/resources/validation/names/duplicates/across files/main.sdstest b/tests/resources/validation/names/duplicates/across files/main.sdstest new file mode 100644 index 000000000..433eb3458 --- /dev/null +++ b/tests/resources/validation/names/duplicates/across files/main.sdstest @@ -0,0 +1,78 @@ +package tests.validation.names.acrossFiles + +// $TEST$ error "Multiple declarations in this package have the name 'DuplicateAnnotation'." +annotation »DuplicateAnnotation« +// $TEST$ error "Multiple declarations in this package have the name 'DuplicateClass'." +class »DuplicateClass« +// $TEST$ error "Multiple declarations in this package have the name 'DuplicateEnum'." +enum »DuplicateEnum« +// $TEST$ error "Multiple declarations in this package have the name 'duplicateFunction'." +fun »duplicateFunction«() +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +pipeline »duplicatePipeline« {} +// $TEST$ error "Multiple declarations in this package have the name 'DuplicateSchema'." +schema »DuplicateSchema« {} +// $TEST$ error "Multiple declarations in this package have the name 'duplicatePublicSegment'." +segment »duplicatePublicSegment«() {} +// $TEST$ error "Multiple declarations in this package have the name 'duplicateInternalSegment'." +internal segment »duplicateInternalSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +private segment »duplicatePrivateSegment«() {} + + +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +annotation »UniqueAnnotation« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +class »UniqueClass« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +enum »UniqueEnum« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +fun »uniqueFunction«() +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +pipeline »uniquePipeline« {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +schema »UniqueSchema« {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +segment »uniquePublicSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +internal segment »uniqueInternalSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +private segment »uniquePrivateSegment«() {} + + +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +annotation »MyAnnotation« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +annotation »MyAnnotation« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +class »MyClass« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +class »MyClass« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +enum »MyEnum« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +enum »MyEnum« +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +fun »myFunction«() +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +fun »myFunction«() +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +pipeline »myPipeline« {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +pipeline »myPipeline« {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +schema »MySchema« {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +schema »MySchema« {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +segment »myPublicSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +segment »myPublicSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +internal segment »myInternalSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +internal segment »myInternalSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +private segment »myPrivateSegment«() {} +// $TEST$ no error r"Multiple declarations in this package have the name '\w*'\." +private segment »myPrivateSegment«() {} diff --git a/tests/resources/validation/names/duplicates/across files/other package.sdstest b/tests/resources/validation/names/duplicates/across files/other package.sdstest new file mode 100644 index 000000000..c859e3989 --- /dev/null +++ b/tests/resources/validation/names/duplicates/across files/other package.sdstest @@ -0,0 +1,11 @@ +package tests.validation.names.acrossFiles.other + +annotation UniqueAnnotation +class UniqueClass +enum UniqueEnum +fun uniqueFunction() +pipeline uniquePipeline {} +schema UniqueSchema {} +segment uniquePublicSegment() {} +internal segment uniqueInternalSegment() {} +private segment uniquePrivateSegment() {} diff --git a/tests/resources/validation/names/duplicates/across files/same package.sdstest b/tests/resources/validation/names/duplicates/across files/same package.sdstest new file mode 100644 index 000000000..04c8a4401 --- /dev/null +++ b/tests/resources/validation/names/duplicates/across files/same package.sdstest @@ -0,0 +1,11 @@ +package tests.validation.names.acrossFiles + +annotation DuplicateAnnotation +class DuplicateClass +enum DuplicateEnum +fun duplicateFunction() +pipeline duplicatePipeline {} +schema DuplicateSchema {} +segment duplicatePublicSegment() {} +internal segment duplicateInternalSegment() {} +private segment duplicatePrivateSegment() {} diff --git a/tests/resources/validation/names/duplicates/in pipeline file/main.sdspipe b/tests/resources/validation/names/duplicates/in pipeline file/main.sdspipe new file mode 100644 index 000000000..92c59bf41 --- /dev/null +++ b/tests/resources/validation/names/duplicates/in pipeline file/main.sdspipe @@ -0,0 +1,85 @@ +package tests.validation.names.inPipelineFile + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inPipelineFile.other import »UniqueImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inPipelineFile.other import »DuplicateImport« +// $TEST$ error "A declaration with name 'DuplicateImport' was imported already." +from tests.validation.names.inPipelineFile.other import »DuplicateImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +// $TEST$ error "A declaration with name 'DuplicateAliasedImport' was imported already." +from tests.validation.names.inPipelineFile.other import »DuplicateAliasedImport«, DuplicateImport as »DuplicateAliasedImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inPipelineFile.other import »Unresolved« +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inPipelineFile.other import »Unresolved« + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »UniqueAnnotation« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »DuplicateAnnotation« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »DuplicateAnnotation« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »UniqueClass« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »DuplicateClass« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »DuplicateClass« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »UniqueEnum« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »DuplicateEnum« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »DuplicateEnum« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »uniqueFunction«() +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »duplicateFunction«() +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »duplicateFunction«() + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »UniqueSchema« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »DuplicateSchema« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »DuplicateSchema« {} + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »uniquePipeline« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »duplicatePipeline« {} +// $TEST$ error "A declaration with name 'duplicatePipeline' exists already in this file." +pipeline »duplicatePipeline« {} + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »uniqueSegment«() {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »duplicateSegment«() {} +// $TEST$ error "A declaration with name 'duplicateSegment' exists already in this file." +segment »duplicateSegment«() {} + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »DuplicateDeclaration« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »DuplicateDeclaration« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »DuplicateDeclaration« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »DuplicateDeclaration«() +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »DuplicateDeclaration« {} +// $TEST$ error r"A declaration with name '\w*' exists already in this file\." +pipeline »DuplicateDeclaration« {} +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +segment »DuplicateDeclaration«() {} diff --git a/tests/resources/validation/names/duplicates/in pipeline file/resource.sdstest b/tests/resources/validation/names/duplicates/in pipeline file/resource.sdstest new file mode 100644 index 000000000..3f4d0553d --- /dev/null +++ b/tests/resources/validation/names/duplicates/in pipeline file/resource.sdstest @@ -0,0 +1,7 @@ +package tests.validation.names.inPipelineFile.other + +class UniqueImport + +class DuplicateImport + +class DuplicateAliasedImport diff --git a/tests/resources/validation/names/duplicates/in schema/main.sdstest b/tests/resources/validation/names/duplicates/in schema/main.sdstest new file mode 100644 index 000000000..735d2be79 --- /dev/null +++ b/tests/resources/validation/names/duplicates/in schema/main.sdstest @@ -0,0 +1,10 @@ +package tests.validation.names.duplicates.inSchema + +schema S { + // $TEST$ no error r"A column with name '\w*' exists already\." + »"duplicateColumn"«: Int, + // $TEST$ error "A column with name 'duplicateColumn' exists already." + »"duplicateColumn"«: Int, + // $TEST$ no error r"A column with name '\w*' exists already\." + »"uniqueColumn"«: Int, +} diff --git a/tests/resources/validation/names/duplicates/in stub file/main.sdsstub b/tests/resources/validation/names/duplicates/in stub file/main.sdsstub new file mode 100644 index 000000000..867baa1fb --- /dev/null +++ b/tests/resources/validation/names/duplicates/in stub file/main.sdsstub @@ -0,0 +1,85 @@ +package tests.validation.names.inStubFile + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inStubFile.other import »UniqueImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inStubFile.other import »DuplicateImport« +// $TEST$ error "A declaration with name 'DuplicateImport' was imported already." +from tests.validation.names.inStubFile.other import »DuplicateImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +// $TEST$ error "A declaration with name 'DuplicateAliasedImport' was imported already." +from tests.validation.names.inStubFile.other import »DuplicateAliasedImport«, DuplicateImport as »DuplicateAliasedImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inStubFile.other import »Unresolved« +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inStubFile.other import »Unresolved« + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »uniqueTest« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »duplicateTest« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »duplicateTest« {} + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »uniqueSegment«() {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »duplicateSegment«() {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »duplicateSegment«() {} + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »UniqueAnnotation« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »DuplicateAnnotation« +// $TEST$ error "A declaration with name 'DuplicateAnnotation' exists already in this file." +annotation »DuplicateAnnotation« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »UniqueClass« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »DuplicateClass« +// $TEST$ error "A declaration with name 'DuplicateClass' exists already in this file." +class »DuplicateClass« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »UniqueEnum« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »DuplicateEnum« +// $TEST$ error "A declaration with name 'DuplicateEnum' exists already in this file." +enum »DuplicateEnum« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »uniqueFunction«() +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »duplicateFunction«() +// $TEST$ error "A declaration with name 'duplicateFunction' exists already in this file." +fun »duplicateFunction«() + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »UniqueSchema« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »DuplicateSchema« {} +// $TEST$ error "A declaration with name 'DuplicateSchema' exists already in this file." +schema »DuplicateSchema« {} + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »DuplicateDeclaration« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »DuplicateDeclaration«() {} +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +annotation »DuplicateDeclaration« +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +class »DuplicateDeclaration« +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +enum »DuplicateDeclaration« +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +fun »DuplicateDeclaration«() +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +schema »DuplicateDeclaration« {} diff --git a/tests/resources/validation/names/duplicates/in stub file/resource.sdstest b/tests/resources/validation/names/duplicates/in stub file/resource.sdstest new file mode 100644 index 000000000..e2f05670c --- /dev/null +++ b/tests/resources/validation/names/duplicates/in stub file/resource.sdstest @@ -0,0 +1,7 @@ +package tests.validation.names.inStubFile.other + +class UniqueImport + +class DuplicateImport + +class DuplicateAliasedImport diff --git a/tests/resources/validation/names/duplicates/in test file/main.sdstest b/tests/resources/validation/names/duplicates/in test file/main.sdstest new file mode 100644 index 000000000..acd73161c --- /dev/null +++ b/tests/resources/validation/names/duplicates/in test file/main.sdstest @@ -0,0 +1,84 @@ +package tests.validation.names.inTestFile + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inTestFile.other import »UniqueImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inTestFile.other import »DuplicateImport« +// $TEST$ error "A declaration with name 'DuplicateImport' was imported already." +from tests.validation.names.inTestFile.other import »DuplicateImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +// $TEST$ error "A declaration with name 'DuplicateAliasedImport' was imported already." +from tests.validation.names.inTestFile.other import »DuplicateAliasedImport«, DuplicateImport as »DuplicateAliasedImport« + +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inTestFile.other import »Unresolved« +// $TEST$ no error r"A declaration with name '\w*' was imported already\." +from tests.validation.names.inTestFile.other import »Unresolved« + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »UniqueAnnotation« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »DuplicateAnnotation« +// $TEST$ error "A declaration with name 'DuplicateAnnotation' exists already in this file." +annotation »DuplicateAnnotation« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »UniqueClass« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +class »DuplicateClass« +// $TEST$ error "A declaration with name 'DuplicateClass' exists already in this file." +class »DuplicateClass« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »UniqueEnum« +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +enum »DuplicateEnum« +// $TEST$ error "A declaration with name 'DuplicateEnum' exists already in this file." +enum »DuplicateEnum« + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »uniqueFunction«() +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +fun »duplicateFunction«() +// $TEST$ error "A declaration with name 'duplicateFunction' exists already in this file." +fun »duplicateFunction«() + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »uniquePipeline« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +pipeline »duplicatePipeline« {} +// $TEST$ error "A declaration with name 'duplicatePipeline' exists already in this file." +pipeline »duplicatePipeline« {} + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »UniqueSchema« {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +schema »DuplicateSchema« {} +// $TEST$ error "A declaration with name 'DuplicateSchema' exists already in this file." +schema »DuplicateSchema« {} + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »uniqueSegment«() {} +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +segment »duplicateSegment«() {} +// $TEST$ error "A declaration with name 'duplicateSegment' exists already in this file." +segment »duplicateSegment«() {} + + +// $TEST$ no error r"A declaration with name '\w*' exists already in this file\." +annotation »DuplicateDeclaration« +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +class »DuplicateDeclaration« +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +enum »DuplicateDeclaration« +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +fun »DuplicateDeclaration«() +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +pipeline »DuplicateDeclaration« {} +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +segment »DuplicateDeclaration«() {} +// $TEST$ error "A declaration with name 'DuplicateDeclaration' exists already in this file." +schema »DuplicateDeclaration« {} diff --git a/tests/resources/validation/names/duplicates/in test file/resource.sdstest b/tests/resources/validation/names/duplicates/in test file/resource.sdstest new file mode 100644 index 000000000..9478f6097 --- /dev/null +++ b/tests/resources/validation/names/duplicates/in test file/resource.sdstest @@ -0,0 +1,7 @@ +package tests.validation.names.inTestFile.other + +class UniqueImport + +class DuplicateImport + +class DuplicateAliasedImport