diff --git a/packages/safe-ds-lang/src/language/builtins/packageNames.ts b/packages/safe-ds-lang/src/language/builtins/packageNames.ts index b6abe37d9..4e225348b 100644 --- a/packages/safe-ds-lang/src/language/builtins/packageNames.ts +++ b/packages/safe-ds-lang/src/language/builtins/packageNames.ts @@ -1 +1,2 @@ export const BUILTINS_ROOT_PACKAGE = 'safeds'; +export const BUILTINS_LANG_PACKAGE = `${BUILTINS_ROOT_PACKAGE}.lang`; diff --git a/packages/safe-ds-lang/src/language/validation/inheritance.ts b/packages/safe-ds-lang/src/language/validation/inheritance.ts index 3e89a4c0e..a5e382df8 100644 --- a/packages/safe-ds-lang/src/language/validation/inheritance.ts +++ b/packages/safe-ds-lang/src/language/validation/inheritance.ts @@ -41,7 +41,7 @@ export const classMemberMustMatchOverriddenMemberAndShouldBeNeeded = (services: ); } else if (typeChecker.isAssignableTo(overriddenMemberType, ownMemberType)) { // Prevents the info from showing when editing the builtin files - if (isInSafedsLangAnyClass(node)) { + if (isInSafedsLangAnyClass(services, node)) { return; } @@ -54,9 +54,12 @@ export const classMemberMustMatchOverriddenMemberAndShouldBeNeeded = (services: }; }; -const isInSafedsLangAnyClass = (node: SdsClassMember): boolean => { +const isInSafedsLangAnyClass = (services: SafeDsServices, node: SdsClassMember): boolean => { const containingClass = getContainerOfType(node, isSdsClass); - return isSdsClass(containingClass) && getQualifiedName(containingClass) === 'safeds.lang.Any'; + return ( + isSdsClass(containingClass) && + getQualifiedName(containingClass) === getQualifiedName(services.builtins.Classes.Any) + ); }; export const classMustOnlyInheritASingleClass = (services: SafeDsServices) => { diff --git a/packages/safe-ds-lang/src/language/validation/names.ts b/packages/safe-ds-lang/src/language/validation/names.ts index 5a9d43e6a..c529efcb6 100644 --- a/packages/safe-ds-lang/src/language/validation/names.ts +++ b/packages/safe-ds-lang/src/language/validation/names.ts @@ -1,7 +1,7 @@ import { AstNodeDescription, getDocument, ValidationAcceptor } from 'langium'; import { duplicatesBy } from '../../helpers/collectionUtils.js'; import { listBuiltinFiles } from '../builtins/fileFinder.js'; -import { BUILTINS_ROOT_PACKAGE } from '../builtins/packageNames.js'; +import { BUILTINS_LANG_PACKAGE, BUILTINS_ROOT_PACKAGE } from '../builtins/packageNames.js'; import { isSdsQualifiedImport, SdsAnnotation, @@ -46,6 +46,7 @@ import { SafeDsServices } from '../safe-ds-module.js'; import { declarationIsAllowedInPipelineFile, declarationIsAllowedInStubFile } from './other/modules.js'; export const CODE_NAME_CODEGEN_PREFIX = 'name/codegen-prefix'; +export const CODE_NAME_CORE_DECLARATION = 'name/core-declaration'; export const CODE_NAME_CASING = 'name/casing'; export const CODE_NAME_DUPLICATE = 'name/duplicate'; @@ -68,6 +69,36 @@ export const nameMustNotStartWithCodegenPrefix = (node: SdsDeclaration, accept: } }; +// ----------------------------------------------------------------------------- +// Core declaration +// ----------------------------------------------------------------------------- + +export const nameMustNotOccurOnCoreDeclaration = (services: SafeDsServices) => { + const packageManager = services.workspace.PackageManager; + + return (node: SdsDeclaration, accept: ValidationAcceptor) => { + if (!node.name) { + /* c8 ignore next 2 */ + return; + } + + // Prevents the error from showing when editing the builtin files + const packageName = getPackageName(node); + if (packageName === BUILTINS_LANG_PACKAGE) { + return; + } + + const coreDeclarations = packageManager.getDeclarationsInPackage(BUILTINS_LANG_PACKAGE); + if (coreDeclarations.some((it) => it.name === node.name)) { + accept('error', 'Names of core declarations must not be used for own declarations.', { + node, + property: 'name', + code: CODE_NAME_CORE_DECLARATION, + }); + } + }; +}; + // ----------------------------------------------------------------------------- // Casing // ----------------------------------------------------------------------------- diff --git a/packages/safe-ds-lang/src/language/validation/safe-ds-validator.ts b/packages/safe-ds-lang/src/language/validation/safe-ds-validator.ts index a7be8a0b5..26b405ed2 100644 --- a/packages/safe-ds-lang/src/language/validation/safe-ds-validator.ts +++ b/packages/safe-ds-lang/src/language/validation/safe-ds-validator.ts @@ -51,6 +51,7 @@ import { functionMustContainUniqueNames, moduleMemberMustHaveNameThatIsUniqueInPackage, moduleMustContainUniqueNames, + nameMustNotOccurOnCoreDeclaration, nameMustNotStartWithCodegenPrefix, nameShouldHaveCorrectCasing, pipelineMustContainUniqueNames, @@ -231,6 +232,7 @@ export const registerValidationChecks = function (services: SafeDsServices) { SdsClassMember: [classMemberMustMatchOverriddenMemberAndShouldBeNeeded(services)], SdsConstraintList: [constraintListsShouldBeUsedWithCaution, constraintListShouldNotBeEmpty], SdsDeclaration: [ + nameMustNotOccurOnCoreDeclaration(services), nameMustNotStartWithCodegenPrefix, nameShouldHaveCorrectCasing, pythonNameShouldDifferFromSafeDsName(services), diff --git a/packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name with block lambda prefix.sdstest b/packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name with codegen prefix.sdstest similarity index 100% rename from packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name with block lambda prefix.sdstest rename to packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name with codegen prefix.sdstest diff --git a/packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name without block lambda prefix.sdstest b/packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name without codegen prefix.sdstest similarity index 100% rename from packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name without block lambda prefix.sdstest rename to packages/safe-ds-lang/tests/resources/validation/names/codegen prefix/package name without codegen prefix.sdstest diff --git a/packages/safe-ds-lang/tests/resources/validation/names/core names/in safeds lang.sdstest b/packages/safe-ds-lang/tests/resources/validation/names/core names/in safeds lang.sdstest new file mode 100644 index 000000000..e3a02f0a0 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/validation/names/core names/in safeds lang.sdstest @@ -0,0 +1,4 @@ +package safeds.lang + +// $TEST$ no error "Names of core declarations must not be used for own declarations." +annotation »Number« diff --git a/packages/safe-ds-lang/tests/resources/validation/names/core names/main.sdstest b/packages/safe-ds-lang/tests/resources/validation/names/core names/main.sdstest new file mode 100644 index 000000000..78ccb7d08 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/validation/names/core names/main.sdstest @@ -0,0 +1,7 @@ +package tests.validation.names.coreNames + +// $TEST$ error "Names of core declarations must not be used for own declarations." +annotation »Any« + +// $TEST$ no error "Names of core declarations must not be used for own declarations." +annotation »Any1«