Skip to content

Commit 8cb2120

Browse files
authored
feat: show error if own declaration has same name as core one (#762)
Closes #760 ### Summary of Changes Core declarations like `Any` should never be shadowed by own declarations. Thus, it's now an error to give own declarations the same name as a core declaration.
1 parent 36663ca commit 8cb2120

File tree

8 files changed

+52
-4
lines changed

8 files changed

+52
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export const BUILTINS_ROOT_PACKAGE = 'safeds';
2+
export const BUILTINS_LANG_PACKAGE = `${BUILTINS_ROOT_PACKAGE}.lang`;

packages/safe-ds-lang/src/language/validation/inheritance.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const classMemberMustMatchOverriddenMemberAndShouldBeNeeded = (services:
4141
);
4242
} else if (typeChecker.isAssignableTo(overriddenMemberType, ownMemberType)) {
4343
// Prevents the info from showing when editing the builtin files
44-
if (isInSafedsLangAnyClass(node)) {
44+
if (isInSafedsLangAnyClass(services, node)) {
4545
return;
4646
}
4747

@@ -54,9 +54,12 @@ export const classMemberMustMatchOverriddenMemberAndShouldBeNeeded = (services:
5454
};
5555
};
5656

57-
const isInSafedsLangAnyClass = (node: SdsClassMember): boolean => {
57+
const isInSafedsLangAnyClass = (services: SafeDsServices, node: SdsClassMember): boolean => {
5858
const containingClass = getContainerOfType(node, isSdsClass);
59-
return isSdsClass(containingClass) && getQualifiedName(containingClass) === 'safeds.lang.Any';
59+
return (
60+
isSdsClass(containingClass) &&
61+
getQualifiedName(containingClass) === getQualifiedName(services.builtins.Classes.Any)
62+
);
6063
};
6164

6265
export const classMustOnlyInheritASingleClass = (services: SafeDsServices) => {

packages/safe-ds-lang/src/language/validation/names.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AstNodeDescription, getDocument, ValidationAcceptor } from 'langium';
22
import { duplicatesBy } from '../../helpers/collectionUtils.js';
33
import { listBuiltinFiles } from '../builtins/fileFinder.js';
4-
import { BUILTINS_ROOT_PACKAGE } from '../builtins/packageNames.js';
4+
import { BUILTINS_LANG_PACKAGE, BUILTINS_ROOT_PACKAGE } from '../builtins/packageNames.js';
55
import {
66
isSdsQualifiedImport,
77
SdsAnnotation,
@@ -46,6 +46,7 @@ import { SafeDsServices } from '../safe-ds-module.js';
4646
import { declarationIsAllowedInPipelineFile, declarationIsAllowedInStubFile } from './other/modules.js';
4747

4848
export const CODE_NAME_CODEGEN_PREFIX = 'name/codegen-prefix';
49+
export const CODE_NAME_CORE_DECLARATION = 'name/core-declaration';
4950
export const CODE_NAME_CASING = 'name/casing';
5051
export const CODE_NAME_DUPLICATE = 'name/duplicate';
5152

@@ -68,6 +69,36 @@ export const nameMustNotStartWithCodegenPrefix = (node: SdsDeclaration, accept:
6869
}
6970
};
7071

72+
// -----------------------------------------------------------------------------
73+
// Core declaration
74+
// -----------------------------------------------------------------------------
75+
76+
export const nameMustNotOccurOnCoreDeclaration = (services: SafeDsServices) => {
77+
const packageManager = services.workspace.PackageManager;
78+
79+
return (node: SdsDeclaration, accept: ValidationAcceptor) => {
80+
if (!node.name) {
81+
/* c8 ignore next 2 */
82+
return;
83+
}
84+
85+
// Prevents the error from showing when editing the builtin files
86+
const packageName = getPackageName(node);
87+
if (packageName === BUILTINS_LANG_PACKAGE) {
88+
return;
89+
}
90+
91+
const coreDeclarations = packageManager.getDeclarationsInPackage(BUILTINS_LANG_PACKAGE);
92+
if (coreDeclarations.some((it) => it.name === node.name)) {
93+
accept('error', 'Names of core declarations must not be used for own declarations.', {
94+
node,
95+
property: 'name',
96+
code: CODE_NAME_CORE_DECLARATION,
97+
});
98+
}
99+
};
100+
};
101+
71102
// -----------------------------------------------------------------------------
72103
// Casing
73104
// -----------------------------------------------------------------------------

packages/safe-ds-lang/src/language/validation/safe-ds-validator.ts

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import {
5151
functionMustContainUniqueNames,
5252
moduleMemberMustHaveNameThatIsUniqueInPackage,
5353
moduleMustContainUniqueNames,
54+
nameMustNotOccurOnCoreDeclaration,
5455
nameMustNotStartWithCodegenPrefix,
5556
nameShouldHaveCorrectCasing,
5657
pipelineMustContainUniqueNames,
@@ -231,6 +232,7 @@ export const registerValidationChecks = function (services: SafeDsServices) {
231232
SdsClassMember: [classMemberMustMatchOverriddenMemberAndShouldBeNeeded(services)],
232233
SdsConstraintList: [constraintListsShouldBeUsedWithCaution, constraintListShouldNotBeEmpty],
233234
SdsDeclaration: [
235+
nameMustNotOccurOnCoreDeclaration(services),
234236
nameMustNotStartWithCodegenPrefix,
235237
nameShouldHaveCorrectCasing,
236238
pythonNameShouldDifferFromSafeDsName(services),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package safeds.lang
2+
3+
// $TEST$ no error "Names of core declarations must not be used for own declarations."
4+
annotation »Number«
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package tests.validation.names.coreNames
2+
3+
// $TEST$ error "Names of core declarations must not be used for own declarations."
4+
annotation »Any«
5+
6+
// $TEST$ no error "Names of core declarations must not be used for own declarations."
7+
annotation »Any1«

0 commit comments

Comments
 (0)