From e4c3842b30b9a95cbf6000928cd2947c77779faa Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 10 Oct 2023 21:36:53 +0200 Subject: [PATCH 1/2] feat: error if function pointers are used --- .../other/expressions/references.ts | 32 ++++++++- src/language/validation/safe-ds-validator.ts | 6 +- .../references/function pointer/main.sdstest | 68 +++++++++++++++++++ 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 tests/resources/validation/other/expressions/references/function pointer/main.sdstest diff --git a/src/language/validation/other/expressions/references.ts b/src/language/validation/other/expressions/references.ts index 1bb04dd27..0a08caaa7 100644 --- a/src/language/validation/other/expressions/references.ts +++ b/src/language/validation/other/expressions/references.ts @@ -1,8 +1,36 @@ -import { isSdsAnnotation, isSdsPipeline, isSdsSchema, SdsReference } from '../../../generated/ast.js'; -import { ValidationAcceptor } from 'langium'; +import { + isSdsAnnotation, + isSdsCall, + isSdsFunction, isSdsMemberAccess, + isSdsPipeline, + isSdsSchema, isSdsSegment, + SdsReference, +} from '../../../generated/ast.js'; +import { AstNode, ValidationAcceptor } from 'langium'; +export const CODE_REFERENCE_FUNCTION_POINTER = 'reference/function-pointer'; export const CODE_REFERENCE_TARGET = 'reference/target'; +export const referenceMustNotBeFunctionPointer = (node: SdsReference, accept: ValidationAcceptor): void => { + const target = node.target?.ref; + if (!isSdsFunction(target) && !isSdsSegment(target)) { + return; + } + + // + let container: AstNode | undefined = node.$container; + if (isSdsMemberAccess(container) && node.$containerProperty === 'member') { + container = container.$container; + } + + if (!isSdsCall(container)) { + accept('error', 'Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead.', { + node, + code: CODE_REFERENCE_FUNCTION_POINTER, + }); + } +}; + export const referenceTargetMustNotBeAnnotationPipelineOrSchema = ( node: SdsReference, accept: ValidationAcceptor, diff --git a/src/language/validation/safe-ds-validator.ts b/src/language/validation/safe-ds-validator.ts index 1644bb2e3..41e38f8c8 100644 --- a/src/language/validation/safe-ds-validator.ts +++ b/src/language/validation/safe-ds-validator.ts @@ -45,7 +45,10 @@ import { } from './other/types/callableTypes.js'; import { typeArgumentListMustNotHavePositionalArgumentsAfterNamedArguments } from './other/types/typeArgumentLists.js'; import { argumentListMustNotHavePositionalArgumentsAfterNamedArguments } from './other/argumentLists.js'; -import { referenceTargetMustNotBeAnnotationPipelineOrSchema } from './other/expressions/references.js'; +import { + referenceMustNotBeFunctionPointer, + referenceTargetMustNotBeAnnotationPipelineOrSchema, +} from './other/expressions/references.js'; import { annotationCallAnnotationShouldNotBeDeprecated, argumentCorrespondingParameterShouldNotBeDeprecated, @@ -141,6 +144,7 @@ export const registerValidationChecks = function (services: SafeDsServices) { SdsPipeline: [pipelineMustContainUniqueNames], SdsPlaceholder: [placeholdersMustNotBeAnAlias, placeholderShouldBeUsed(services)], SdsReference: [ + referenceMustNotBeFunctionPointer, referenceTargetMustNotBeAnnotationPipelineOrSchema, referenceTargetShouldNotBeDeprecated(services), referenceTargetShouldNotExperimental(services), diff --git a/tests/resources/validation/other/expressions/references/function pointer/main.sdstest b/tests/resources/validation/other/expressions/references/function pointer/main.sdstest new file mode 100644 index 000000000..e5a957baa --- /dev/null +++ b/tests/resources/validation/other/expressions/references/function pointer/main.sdstest @@ -0,0 +1,68 @@ +package tests.validation.other.expressions.references.target + +class MyClass { + fun myInstanceMethod() + static fun myStaticMethod() +} + +fun myFunction1() +fun myFunction2(p: Any) + +segment mySegment1() {} + +segment mySegment2() { + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass().»myInstanceMethod«; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass().»myInstanceMethod«.a; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass().»myInstanceMethod«.a(); + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + myFunction2(MyClass().»myInstanceMethod«); + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass().»myInstanceMethod«(); + + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass.»myStaticMethod«; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass.»myStaticMethod«.a; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass.»myStaticMethod«.a(); + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + myFunction2(MyClass.»myStaticMethod«); + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + MyClass.»myStaticMethod«(); + + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »myFunction1«; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »myFunction1«.a; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »myFunction1«.a(); + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + myFunction2(»myFunction1«); + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »myFunction1«(); + + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »mySegment1«; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »mySegment1«.a; + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »mySegment1«.a(); + // $TEST$ error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + myFunction2(»mySegment1«); + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »mySegment1«(); + + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »unresolved«; + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »unresolved«.a; + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »unresolved«.a(); + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + myFunction2(»unresolved«); + // $TEST$ no error "Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead." + »unresolved«(); +} From 9fdc1acbbac8cb9a6397dd232da8af3b6718076f Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:46:26 +0000 Subject: [PATCH 2/2] style: apply automated linter fixes --- .../validation/other/expressions/references.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/language/validation/other/expressions/references.ts b/src/language/validation/other/expressions/references.ts index 0a08caaa7..d88b80f98 100644 --- a/src/language/validation/other/expressions/references.ts +++ b/src/language/validation/other/expressions/references.ts @@ -1,9 +1,11 @@ import { isSdsAnnotation, isSdsCall, - isSdsFunction, isSdsMemberAccess, + isSdsFunction, + isSdsMemberAccess, isSdsPipeline, - isSdsSchema, isSdsSegment, + isSdsSchema, + isSdsSegment, SdsReference, } from '../../../generated/ast.js'; import { AstNode, ValidationAcceptor } from 'langium'; @@ -24,10 +26,14 @@ export const referenceMustNotBeFunctionPointer = (node: SdsReference, accept: Va } if (!isSdsCall(container)) { - accept('error', 'Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead.', { - node, - code: CODE_REFERENCE_FUNCTION_POINTER, - }); + accept( + 'error', + 'Function pointers are not allowed to provide a cleaner graphical view. Use a lambda instead.', + { + node, + code: CODE_REFERENCE_FUNCTION_POINTER, + }, + ); } };