Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: error if @PythonName and @PythonCall are set on a function #685

Merged
merged 3 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/language/validation/builtins/pythonModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const pythonModuleShouldDifferFromSafeDsPackage = (services: SafeDsServic
'The Python module is identical to the Safe-DS package, so the annotation call can be removed.',
{
node: annotationCall,
property: 'annotation',
code: CODE_PYTHON_MODULE_SAME_AS_SAFE_DS_PACKAGE,
},
);
Expand Down
27 changes: 25 additions & 2 deletions src/language/validation/builtins/pythonName.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import { ValidationAcceptor } from 'langium';
import { SdsDeclaration } from '../../generated/ast.js';
import { SdsDeclaration, SdsFunction } from '../../generated/ast.js';
import { SafeDsServices } from '../../safe-ds-module.js';
import { findFirstAnnotationCallOf } from '../../helpers/nodeProperties.js';
import { findFirstAnnotationCallOf, hasAnnotationCallOf } from '../../helpers/nodeProperties.js';

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

export const pythonNameMustNotBeSetIfPythonCallIsSet = (services: SafeDsServices) => {
const builtinAnnotations = services.builtins.Annotations;

return (node: SdsFunction, accept: ValidationAcceptor) => {
if (!hasAnnotationCallOf(node, builtinAnnotations.PythonCall)) {
return;
}

const firstPythonName = findFirstAnnotationCallOf(node, builtinAnnotations.PythonName);
if (!firstPythonName) {
return;
}

accept('error', 'A Python name must not be set if a Python call is set.', {
node: firstPythonName,
property: 'annotation',
code: CODE_PYTHON_NAME_MUTUALLY_EXCLUSIVE_WITH_PYTHON_CALL,
});
};
};

export const pythonNameShouldDifferFromSafeDsName = (services: SafeDsServices) => {
const builtinAnnotations = services.builtins.Annotations;

Expand All @@ -17,6 +39,7 @@ export const pythonNameShouldDifferFromSafeDsName = (services: SafeDsServices) =
const annotationCall = findFirstAnnotationCallOf(node, builtinAnnotations.PythonName)!;
accept('info', 'The Python name is identical to the Safe-DS name, so the annotation call can be removed.', {
node: annotationCall,
property: 'annotation',
code: CODE_PYTHON_NAME_SAME_AS_SAFE_DS_NAME,
});
};
Expand Down
11 changes: 9 additions & 2 deletions src/language/validation/safe-ds-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ import {
namedTypeTypeArgumentListMustNotHavePositionalArgumentsAfterNamedArguments,
} from './other/types/namedTypes.js';
import { classMustNotInheritItself, classMustOnlyInheritASingleClass } from './inheritance.js';
import { pythonNameShouldDifferFromSafeDsName } from './builtins/pythonName.js';
import {
pythonNameMustNotBeSetIfPythonCallIsSet,
pythonNameShouldDifferFromSafeDsName,
} from './builtins/pythonName.js';
import { pythonModuleShouldDifferFromSafeDsPackage } from './builtins/pythonModule.js';
import { divisionDivisorMustNotBeZero } from './other/expressions/infixOperations.js';
import { constantParameterMustHaveConstantDefaultValue } from './other/declarations/parameters.js';
Expand Down Expand Up @@ -209,7 +212,11 @@ export const registerValidationChecks = function (services: SafeDsServices) {
SdsEnumBody: [enumBodyShouldNotBeEmpty],
SdsEnumVariant: [enumVariantMustContainUniqueNames, enumVariantParameterListShouldNotBeEmpty],
SdsExpressionLambda: [expressionLambdaMustContainUniqueNames],
SdsFunction: [functionMustContainUniqueNames, functionResultListShouldNotBeEmpty],
SdsFunction: [
functionMustContainUniqueNames,
functionResultListShouldNotBeEmpty,
pythonNameMustNotBeSetIfPythonCallIsSet(services),
],
SdsImport: [importPackageMustExist(services), importPackageShouldNotBeEmpty(services)],
SdsImportedDeclaration: [importedDeclarationAliasShouldDifferFromDeclarationName],
SdsIndexedAccess: [indexedAccessesShouldBeUsedWithCaution],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// $TEST$ info "The Python module is identical to the Safe-DS package, so the annotation call can be removed."
»@PythonModule("tests.validation.builtins.annotations.pythonModule")«
PythonModule«("tests.validation.builtins.annotations.pythonModule")

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

package tests.validation.builtins.annotations.pythonModule
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package tests.validation.builtins.annotations.pythonName
package tests.validation.builtins.annotations.pythonName.identicalToSafeDsName

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

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

// $TEST$ no info "The Python name is identical to the Safe-DS name, so the annotation call can be removed."
class TestClass3
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tests.validation.builtins.annotations.pythonName.mutuallyExclusiveWithPythonCall

@PythonCall("myFunction1()")
// $TEST$ error "A Python name must not be set if a Python call is set."
@»PythonName«("my_function_1")
// $TEST$ no error "A Python name must not be set if a Python call is set."
@»PythonName«("my_function_1")
fun myFunction1()

// $TEST$ error "A Python name must not be set if a Python call is set."
@»PythonName«("my_function_2")
// $TEST$ no error "A Python name must not be set if a Python call is set."
@»PythonName«("my_function_2")
@PythonCall("myFunction2()")
fun myFunction2()

// $TEST$ no error "A Python name must not be set if a Python call is set."
@»PythonName«("my_function_3")
fun myFunction3()

// $TEST$ no error "A Python name must not be set if a Python call is set."
@»PythonName«("my_function_2")
// $TEST$ no error "A Python name must not be set if a Python call is set."
@»PythonName«("my_function_2")
@PythonCall("myFunction2()")
class MyClass()