Skip to content

Commit

Permalink
feat: error if function pointers are used (#629)
Browse files Browse the repository at this point in the history
Closes #565
Closes partially #543

### Summary of Changes

To provide a cleaner graphical view, this PR makes the use of function
pointers (to functions/segments) an error. Lambdas can be used instead.

---------

Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com>
  • Loading branch information
lars-reimann and megalinter-bot committed Oct 10, 2023
1 parent b99ab25 commit 01933b9
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 3 deletions.
38 changes: 36 additions & 2 deletions src/language/validation/other/expressions/references.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,42 @@
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,
Expand Down
6 changes: 5 additions & 1 deletion src/language/validation/safe-ds-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -141,6 +144,7 @@ export const registerValidationChecks = function (services: SafeDsServices) {
SdsPipeline: [pipelineMustContainUniqueNames],
SdsPlaceholder: [placeholdersMustNotBeAnAlias, placeholderShouldBeUsed(services)],
SdsReference: [
referenceMustNotBeFunctionPointer,
referenceTargetMustNotBeAnnotationPipelineOrSchema,
referenceTargetShouldNotBeDeprecated(services),
referenceTargetShouldNotExperimental(services),
Expand Down
Original file line number Diff line number Diff line change
@@ -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«();
}

0 comments on commit 01933b9

Please sign in to comment.