Skip to content

Commit d22c446

Browse files
authored
feat: error if @pythonName and @PythonCall are set on a function (#685)
### Summary of Changes `@PythonCall` is a more general version of `@PythonName`. If `@PythonCall` is set, `@PythonName` gets ignored completely. We now show an error if both annotation are used together on a function.
1 parent 15114df commit d22c446

File tree

8 files changed

+69
-12
lines changed

8 files changed

+69
-12
lines changed

src/language/validation/builtins/pythonModule.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const pythonModuleShouldDifferFromSafeDsPackage = (services: SafeDsServic
2020
'The Python module is identical to the Safe-DS package, so the annotation call can be removed.',
2121
{
2222
node: annotationCall,
23+
property: 'annotation',
2324
code: CODE_PYTHON_MODULE_SAME_AS_SAFE_DS_PACKAGE,
2425
},
2526
);

src/language/validation/builtins/pythonName.ts

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,32 @@
11
import { ValidationAcceptor } from 'langium';
2-
import { SdsDeclaration } from '../../generated/ast.js';
2+
import { SdsDeclaration, SdsFunction } from '../../generated/ast.js';
33
import { SafeDsServices } from '../../safe-ds-module.js';
4-
import { findFirstAnnotationCallOf } from '../../helpers/nodeProperties.js';
4+
import { findFirstAnnotationCallOf, hasAnnotationCallOf } from '../../helpers/nodeProperties.js';
55

6+
export const CODE_PYTHON_NAME_MUTUALLY_EXCLUSIVE_WITH_PYTHON_CALL = 'python-name/mutually-exclusive-with-python-call';
67
export const CODE_PYTHON_NAME_SAME_AS_SAFE_DS_NAME = 'python-name/same-as-safe-ds-name';
78

9+
export const pythonNameMustNotBeSetIfPythonCallIsSet = (services: SafeDsServices) => {
10+
const builtinAnnotations = services.builtins.Annotations;
11+
12+
return (node: SdsFunction, accept: ValidationAcceptor) => {
13+
if (!hasAnnotationCallOf(node, builtinAnnotations.PythonCall)) {
14+
return;
15+
}
16+
17+
const firstPythonName = findFirstAnnotationCallOf(node, builtinAnnotations.PythonName);
18+
if (!firstPythonName) {
19+
return;
20+
}
21+
22+
accept('error', 'A Python name must not be set if a Python call is set.', {
23+
node: firstPythonName,
24+
property: 'annotation',
25+
code: CODE_PYTHON_NAME_MUTUALLY_EXCLUSIVE_WITH_PYTHON_CALL,
26+
});
27+
};
28+
};
29+
830
export const pythonNameShouldDifferFromSafeDsName = (services: SafeDsServices) => {
931
const builtinAnnotations = services.builtins.Annotations;
1032

@@ -17,6 +39,7 @@ export const pythonNameShouldDifferFromSafeDsName = (services: SafeDsServices) =
1739
const annotationCall = findFirstAnnotationCallOf(node, builtinAnnotations.PythonName)!;
1840
accept('info', 'The Python name is identical to the Safe-DS name, so the annotation call can be removed.', {
1941
node: annotationCall,
42+
property: 'annotation',
2043
code: CODE_PYTHON_NAME_SAME_AS_SAFE_DS_NAME,
2144
});
2245
};

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,10 @@ import {
124124
namedTypeTypeArgumentListMustNotHavePositionalArgumentsAfterNamedArguments,
125125
} from './other/types/namedTypes.js';
126126
import { classMustNotInheritItself, classMustOnlyInheritASingleClass } from './inheritance.js';
127-
import { pythonNameShouldDifferFromSafeDsName } from './builtins/pythonName.js';
127+
import {
128+
pythonNameMustNotBeSetIfPythonCallIsSet,
129+
pythonNameShouldDifferFromSafeDsName,
130+
} from './builtins/pythonName.js';
128131
import { pythonModuleShouldDifferFromSafeDsPackage } from './builtins/pythonModule.js';
129132
import { divisionDivisorMustNotBeZero } from './other/expressions/infixOperations.js';
130133
import { constantParameterMustHaveConstantDefaultValue } from './other/declarations/parameters.js';
@@ -209,7 +212,11 @@ export const registerValidationChecks = function (services: SafeDsServices) {
209212
SdsEnumBody: [enumBodyShouldNotBeEmpty],
210213
SdsEnumVariant: [enumVariantMustContainUniqueNames, enumVariantParameterListShouldNotBeEmpty],
211214
SdsExpressionLambda: [expressionLambdaMustContainUniqueNames],
212-
SdsFunction: [functionMustContainUniqueNames, functionResultListShouldNotBeEmpty],
215+
SdsFunction: [
216+
functionMustContainUniqueNames,
217+
functionResultListShouldNotBeEmpty,
218+
pythonNameMustNotBeSetIfPythonCallIsSet(services),
219+
],
213220
SdsImport: [importPackageMustExist(services), importPackageShouldNotBeEmpty(services)],
214221
SdsImportedDeclaration: [importedDeclarationAliasShouldDifferFromDeclarationName],
215222
SdsIndexedAccess: [indexedAccessesShouldBeUsedWithCaution],
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// $TEST$ info "The Python module is identical to the Safe-DS package, so the annotation call can be removed."
2-
»@PythonModule("tests.validation.builtins.annotations.pythonModule")«
2+
PythonModule«("tests.validation.builtins.annotations.pythonModule")
33

44
package tests.validation.builtins.annotations.pythonModule
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// $TEST$ no info "The Python module is identical to the Safe-DS package, so the annotation call can be removed."
2-
»@PythonModule("tests.validation.builtins.annotations.pythonModule.other")«
2+
PythonModule«("tests.validation.builtins.annotations.pythonModule.other")
33
// $TEST$ no info "The Python module is identical to the Safe-DS package, so the annotation call can be removed."
4-
»@PythonModule("tests.validation.builtins.annotations.pythonModule")«
4+
PythonModule«("tests.validation.builtins.annotations.pythonModule")
55

66
package tests.validation.builtins.annotations.pythonModule
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
package tests.validation.builtins.annotations.pythonName
1+
package tests.validation.builtins.annotations.pythonName.identicalToSafeDsName
22

33
// $TEST$ info "The Python name is identical to the Safe-DS name, so the annotation call can be removed."
4-
»@PythonName("TestClass1")«
4+
PythonName«("TestClass1")
55
class TestClass1
66

77
// $TEST$ no info "The Python name is identical to the Safe-DS name, so the annotation call can be removed."
8-
»@PythonName("Test_Class_2")«
8+
PythonName«("Test_Class_2")
99
// $TEST$ no info "The Python name is identical to the Safe-DS name, so the annotation call can be removed."
10-
»@PythonName("TestClass2")«
10+
PythonName«("TestClass2")
1111
class TestClass2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tests.validation.builtins.annotations.pythonName
1+
package tests.validation.builtins.annotations.pythonName.identicalToSafeDsName
22

33
// $TEST$ no info "The Python name is identical to the Safe-DS name, so the annotation call can be removed."
44
class TestClass3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package tests.validation.builtins.annotations.pythonName.mutuallyExclusiveWithPythonCall
2+
3+
@PythonCall("myFunction1()")
4+
// $TEST$ error "A Python name must not be set if a Python call is set."
5+
@»PythonName«("my_function_1")
6+
// $TEST$ no error "A Python name must not be set if a Python call is set."
7+
@»PythonName«("my_function_1")
8+
fun myFunction1()
9+
10+
// $TEST$ error "A Python name must not be set if a Python call is set."
11+
@»PythonName«("my_function_2")
12+
// $TEST$ no error "A Python name must not be set if a Python call is set."
13+
@»PythonName«("my_function_2")
14+
@PythonCall("myFunction2()")
15+
fun myFunction2()
16+
17+
// $TEST$ no error "A Python name must not be set if a Python call is set."
18+
@»PythonName«("my_function_3")
19+
fun myFunction3()
20+
21+
// $TEST$ no error "A Python name must not be set if a Python call is set."
22+
@»PythonName«("my_function_2")
23+
// $TEST$ no error "A Python name must not be set if a Python call is set."
24+
@»PythonName«("my_function_2")
25+
@PythonCall("myFunction2()")
26+
class MyClass()

0 commit comments

Comments
 (0)