From f97734c35e04ac18a80bcda0a0689b9ff1afb240 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Sun, 22 Oct 2023 15:20:37 +0200 Subject: [PATCH 1/5] chore: add remaining old validation test files but skip them for now --- .../duplicate entry/duplicateTarget.sdstest | 11 + .../target/wrong target/target.sdstest | 151 ++++++++ .../validation/skip-old/arguments.sdstest | 336 ++++++++++++++++++ .../skip-old/assignments/hasNoEffect.sdstest | 19 + .../validation/skip-old/defaultValues.sdstest | 19 + .../expressionStatements/hasNoEffect.sdstest | 78 ++++ .../skip-old/indexedAccesses.sdstest | 39 ++ .../skip-old/infixOperations.sdstest | 230 ++++++++++++ .../skip-old/parameter types.sdstest | 52 +++ .../skip-old/prefixOperations.sdstest | 38 ++ .../skip-old/purePropagates.sdstest | 21 ++ .../validation/skip-old/recursion.sdstest | 68 ++++ .../skip-old/schemaEffectArguments.sdstest | 22 ++ .../skip-old/staticAnalysis/recursion.sdstest | 90 +++++ .../staticAnalysis/sideEffects.sdstest | 147 ++++++++ .../validation/skip-old/yields.sdstest | 13 + 16 files changed, 1334 insertions(+) create mode 100644 tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest create mode 100644 tests/resources/validation/builtins/annotations/target/wrong target/target.sdstest create mode 100644 tests/resources/validation/skip-old/arguments.sdstest create mode 100644 tests/resources/validation/skip-old/assignments/hasNoEffect.sdstest create mode 100644 tests/resources/validation/skip-old/defaultValues.sdstest create mode 100644 tests/resources/validation/skip-old/expressionStatements/hasNoEffect.sdstest create mode 100644 tests/resources/validation/skip-old/indexedAccesses.sdstest create mode 100644 tests/resources/validation/skip-old/infixOperations.sdstest create mode 100644 tests/resources/validation/skip-old/parameter types.sdstest create mode 100644 tests/resources/validation/skip-old/prefixOperations.sdstest create mode 100644 tests/resources/validation/skip-old/purePropagates.sdstest create mode 100644 tests/resources/validation/skip-old/recursion.sdstest create mode 100644 tests/resources/validation/skip-old/schemaEffectArguments.sdstest create mode 100644 tests/resources/validation/skip-old/staticAnalysis/recursion.sdstest create mode 100644 tests/resources/validation/skip-old/staticAnalysis/sideEffects.sdstest create mode 100644 tests/resources/validation/skip-old/yields.sdstest diff --git a/tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest b/tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest new file mode 100644 index 000000000..2020d7ddc --- /dev/null +++ b/tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest @@ -0,0 +1,11 @@ +package tests.validation.other.annotationCalls.duplicateTarget + +@Target( + // $TEST$ warning "This annotation target is used multiple times." + »AnnotationTarget.Annotation«, + // $TEST$ warning "This annotation target is used multiple times." + »AnnotationTarget.Annotation«, + // $TEST$ no warning "This annotation target is used multiple times." + »AnnotationTarget.Class« +) +annotation TestAnnotation diff --git a/tests/resources/validation/builtins/annotations/target/wrong target/target.sdstest b/tests/resources/validation/builtins/annotations/target/wrong target/target.sdstest new file mode 100644 index 000000000..53c9716ba --- /dev/null +++ b/tests/resources/validation/builtins/annotations/target/wrong target/target.sdstest @@ -0,0 +1,151 @@ +// $TEST$ error "This annotation cannot be applied to a compilation unit." +»@AnnotationForEnums« +// $TEST$ no error "This annotation cannot be applied to a compilation unit." +»@AnnotationForCompilationUnits« +// $TEST$ no error "This annotation cannot be applied to a compilation unit." +»@AnnotationForMultipleTargets« +// $TEST$ no error "This annotation cannot be applied to a compilation unit." +»@AnnotationForAnything« +// $TEST$ no error "This annotation cannot be applied to a compilation unit." +»@UnresolvedAnnotation« + +package tests.validation.other.annotationCalls.target + +@Target(AnnotationTarget.Annotation) +annotation AnnotationForAnnotations + +@Target(AnnotationTarget.Attribute) +annotation AnnotationForAttributes + +@Target(AnnotationTarget.Class) +annotation AnnotationForClasses + +@Target(AnnotationTarget.CompilationUnit) +annotation AnnotationForCompilationUnits + +@Target(AnnotationTarget.Enum) +annotation AnnotationForEnums + +@Target(AnnotationTarget.EnumVariant) +annotation AnnotationForEnumVariants + +@Target(AnnotationTarget.Function) +annotation AnnotationForFunctions + +@Target(AnnotationTarget.Parameter) +annotation AnnotationForParameters + +@Target(AnnotationTarget.Result) +annotation AnnotationForResults + +@Target(AnnotationTarget.TypeParameter) +annotation AnnotationForTypeParameters + +@Target(AnnotationTarget.Pipeline) +annotation AnnotationForPipelines + +@Target(AnnotationTarget.Step) +annotation AnnotationForSteps + +@Target(AnnotationTarget.CompilationUnit, AnnotationTarget.Class) +annotation AnnotationForMultipleTargets + +annotation AnnotationForAnything + +/* Test declarations -------------------------------------------------------- */ + +// $TEST$ error "This annotation cannot be applied to an annotation." +»@AnnotationForAttributes« +// $TEST$ no error "This annotation cannot be applied to an annotation." +»@AnnotationForAnnotations« +// $TEST$ no error "This annotation cannot be applied to an annotation." +»@AnnotationForAnything« +annotation TestAnnotation + +// $TEST$ error "This annotation cannot be applied to a class." +»@AnnotationForCompilationUnits« +// $TEST$ no error "This annotation cannot be applied to a class." +»@AnnotationForClasses« +// $TEST$ no error "This annotation cannot be applied to a class." +»@AnnotationForMultipleTargets« +// $TEST$ no error "This annotation cannot be applied to a class." +»@AnnotationForAnything« +class TestClass< + + // $TEST$ error "This annotation cannot be applied to a type parameter." + »@AnnotationForPipelines« + // $TEST$ no error "This annotation cannot be applied to a type parameter." + »@AnnotationForTypeParameters« + // $TEST$ no error "This annotation cannot be applied to a type parameter." + »@AnnotationForAnything« + TEST_TYPE_PARAMETER +> { + + // $TEST$ error "This annotation cannot be applied to an attribute." + »@AnnotationForClasses« + // $TEST$ no error "This annotation cannot be applied to an attribute." + »@AnnotationForAttributes« + // $TEST$ no error "This annotation cannot be applied to an attribute." + »@AnnotationForAnything« + attr testAttribute: Int +} + +// $TEST$ error "This annotation cannot be applied to an enum." +»@AnnotationForEnumVariants« +// $TEST$ no error "This annotation cannot be applied to an enum." +»@AnnotationForEnums« +// $TEST$ no error "This annotation cannot be applied to an enum." +»@AnnotationForAnything« +enum TestEnum { + + // $TEST$ error "This annotation cannot be applied to an enum variant." + »@AnnotationForFunctions« + // $TEST$ no error "This annotation cannot be applied to an enum variant." + »@AnnotationForEnumVariants« + // $TEST$ no error "This annotation cannot be applied to an enum variant." + »@AnnotationForAnything« + TestEnumVariant +} + + +// $TEST$ error "This annotation cannot be applied to a function." +»@AnnotationForParameters« +// $TEST$ no error "This annotation cannot be applied to a function." +»@AnnotationForFunctions« +// $TEST$ no error "This annotation cannot be applied to a function." +»@AnnotationForAnything« +fun testFunction( + + // $TEST$ error "This annotation cannot be applied to a parameter." + »@AnnotationForResults« + // $TEST$ no error "This annotation cannot be applied to a parameter." + »@AnnotationForParameters« + // $TEST$ no error "This annotation cannot be applied to a parameter." + »@AnnotationForAnything« + testParameter: Int +) -> ( + + // $TEST$ error "This annotation cannot be applied to a result." + »@AnnotationForTypeParameters« + // $TEST$ no error "This annotation cannot be applied to a result." + »@AnnotationForResults« + // $TEST$ no error "This annotation cannot be applied to a result." + »@AnnotationForAnything« + testResult: Int +) + +// $TEST$ error "This annotation cannot be applied to a pipeline." +»@AnnotationForSteps« +// $TEST$ no error "This annotation cannot be applied to a pipeline." +»@AnnotationForPipelines« +// $TEST$ no error "This annotation cannot be applied to a pipeline." +»@AnnotationForAnything« +pipeline testPipeline {} + +// $TEST$ error "This annotation cannot be applied to a step." +»@AnnotationForAnnotations« +// $TEST$ no error "This annotation cannot be applied to a step." +»@AnnotationForSteps« +// $TEST$ no error "This annotation cannot be applied to a step." +»@AnnotationForAnything« +step testStep() {} diff --git a/tests/resources/validation/skip-old/arguments.sdstest b/tests/resources/validation/skip-old/arguments.sdstest new file mode 100644 index 000000000..75895a631 --- /dev/null +++ b/tests/resources/validation/skip-old/arguments.sdstest @@ -0,0 +1,336 @@ +package tests.validation.typeChecking.arguments + +step myStep(vararg variadicParam: Int) { + + // $TEST$ no error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»intToInt«); + // $TEST$ error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»f2«); + // $TEST$ error "An argument of type 'B' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»B()«); + // $TEST$ error "An argument of type 'C' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(callableType = »C()«); + // $TEST$ error "An argument of type 'D' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»maybeC()«); + // $TEST$ error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»someVariantOfMyEnum1()«); + // $TEST$ error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»someVariantOfMyEnum2()«); + // $TEST$ error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»MyEnum1.Variant1«); + // $TEST$ error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»MyEnum1.Variant2«); + // $TEST$ error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»MyEnum2.Variant1«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»aOrC()«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»bOrC()«); + // $TEST$ error "An argument of type 'vararg' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type '(Int) -> (Int)'." + f1(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f1(unresolved = »1«); + + // $TEST$ error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type 'C'." + f2(»intToInt«); + // $TEST$ error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type 'C'." + f2(»f2«); + // $TEST$ error "An argument of type 'B' cannot be assigned to a parameter of type 'C'." + f2(»B()«); + // $TEST$ no error "An argument of type 'C' cannot be assigned to a parameter of type 'C'." + f2(classType = »C()«); + // $TEST$ no error "An argument of type 'D' cannot be assigned to a parameter of type 'C'." + f2(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type 'C'." + f2(»maybeC()«); + // $TEST$ error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type 'C'." + f2(»someVariantOfMyEnum1()«); + // $TEST$ error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type 'C'." + f2(»someVariantOfMyEnum2()«); + // $TEST$ error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type 'C'." + f2(»MyEnum1.Variant1«); + // $TEST$ error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type 'C'." + f2(»MyEnum1.Variant2«); + // $TEST$ error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type 'C'." + f2(»MyEnum2.Variant1«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'C'." + f2(»aOrC()«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'C'." + f2(»bOrC()«); + // $TEST$ error "An argument of type 'vararg' cannot be assigned to a parameter of type 'C'." + f2(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type 'C'." + f2(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f2(unresolved = »1«); + + // $TEST$ error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»intToInt«); + // $TEST$ error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»f2«); + // $TEST$ error "An argument of type 'B' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»B()«); + // $TEST$ error "An argument of type 'C' cannot be assigned to a parameter of type 'MyEnum1'." + f3(enumType = »C()«); + // $TEST$ error "An argument of type 'D' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»maybeC()«); + // $TEST$ no error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»someVariantOfMyEnum1()«); + // $TEST$ error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»someVariantOfMyEnum2()«); + // $TEST$ no error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»MyEnum1.Variant1«); + // $TEST$ no error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»MyEnum1.Variant2«); + // $TEST$ error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»MyEnum2.Variant1«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»aOrC()«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»bOrC()«); + // $TEST$ error "An argument of type 'vararg' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type 'MyEnum1'." + f3(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f3(unresolved = »1«); + + // $TEST$ error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»intToInt«); + // $TEST$ error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»f2«); + // $TEST$ error "An argument of type 'B' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»B()«); + // $TEST$ error "An argument of type 'C' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(enumVariantType = »C()«); + // $TEST$ error "An argument of type 'D' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»maybeC()«); + // $TEST$ error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»someVariantOfMyEnum1()«); + // $TEST$ error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»someVariantOfMyEnum2()«); + // $TEST$ no error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»MyEnum1.Variant1«); + // $TEST$ error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»MyEnum1.Variant2«); + // $TEST$ error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»MyEnum2.Variant1«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»aOrC()«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»bOrC()«); + // $TEST$ error "An argument of type 'vararg' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type 'MyEnum1.Variant1'." + f4(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f4(unresolved = »1«); + + // $TEST$ error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type 'union'." + f5(»intToInt«); + // $TEST$ error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type 'union'." + f5(»f2«); + // $TEST$ no error "An argument of type 'B' cannot be assigned to a parameter of type 'union'." + f5(»B()«); + // $TEST$ no error "An argument of type 'C' cannot be assigned to a parameter of type 'union'." + f5(unionType = »C()«); + // $TEST$ no error "An argument of type 'D' cannot be assigned to a parameter of type 'union'." + f5(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type 'union'." + f5(»maybeC()«); + // $TEST$ error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type 'union'." + f5(»someVariantOfMyEnum1()«); + // $TEST$ error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type 'union'." + f5(»someVariantOfMyEnum2()«); + // $TEST$ error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type 'union'." + f5(»MyEnum1.Variant1«); + // $TEST$ error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type 'union'." + f5(»MyEnum1.Variant2«); + // $TEST$ error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type 'union'." + f5(»MyEnum2.Variant1«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'union'." + f5(»aOrC()«); + // $TEST$ no error "An argument of type 'union' cannot be assigned to a parameter of type 'union'." + f5(»bOrC()«); + // $TEST$ error "An argument of type 'vararg' cannot be assigned to a parameter of type 'union'." + f5(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type 'union'." + f5(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f5(unresolved = »1«); + + // $TEST$ error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type '$Unresolved'." + f6(»intToInt«); + // $TEST$ error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type '$Unresolved'." + f6(»f2«); + // $TEST$ error "An argument of type 'B' cannot be assigned to a parameter of type '$Unresolved'." + f6(»B()«); + // $TEST$ error "An argument of type 'C' cannot be assigned to a parameter of type '$Unresolved'." + f6(unresolvedType = »C()«); + // $TEST$ error "An argument of type 'D' cannot be assigned to a parameter of type '$Unresolved'." + f6(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type '$Unresolved'." + f6(»maybeC()«); + // $TEST$ error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type '$Unresolved'." + f6(»someVariantOfMyEnum1()«); + // $TEST$ error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type '$Unresolved'." + f6(»someVariantOfMyEnum2()«); + // $TEST$ error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type '$Unresolved'." + f6(»MyEnum1.Variant1«); + // $TEST$ error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type '$Unresolved'." + f6(»MyEnum1.Variant2«); + // $TEST$ error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type '$Unresolved'." + f6(»MyEnum2.Variant1«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type '$Unresolved'." + f6(»aOrC()«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type '$Unresolved'." + f6(»bOrC()«); + // $TEST$ error "An argument of type 'vararg' cannot be assigned to a parameter of type '$Unresolved'." + f6(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type '$Unresolved'." + f6(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f6(unresolved = »1«); + + // $TEST$ error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type 'vararg'." + f7(»intToInt«); + // $TEST$ error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type 'vararg'." + f7(»f2«); + // $TEST$ error "An argument of type 'B' cannot be assigned to a parameter of type 'vararg'." + f7(»B()«); + // $TEST$ no error "An argument of type 'C' cannot be assigned to a parameter of type 'vararg'." + f7(unresolvedType = »C()«); + // $TEST$ no error "An argument of type 'D' cannot be assigned to a parameter of type 'vararg'." + f7(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type 'vararg'." + f7(»maybeC()«); + // $TEST$ error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type 'vararg'." + f7(»someVariantOfMyEnum1()«); + // $TEST$ error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type 'vararg'." + f7(»someVariantOfMyEnum2()«); + // $TEST$ error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type 'vararg'." + f7(»MyEnum1.Variant1«); + // $TEST$ error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type 'vararg'." + f7(»MyEnum1.Variant2«); + // $TEST$ error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type 'vararg'." + f7(»MyEnum2.Variant1«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'vararg'." + f7(»aOrC()«); + // $TEST$ error "An argument of type 'union' cannot be assigned to a parameter of type 'vararg'." + f7(»bOrC()«); + // $TEST$ error "An argument of type 'vararg' cannot be assigned to a parameter of type 'vararg'." + f7(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type 'vararg'." + f7(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f7(unresolved = »1«); + + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f8(»(vararg a: Int) {}«); + + // $TEST$ no error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type 'Any'." + f9(»intToInt«); + // $TEST$ no error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type 'Any'." + f9(»f2«); + // $TEST$ no error "An argument of type 'B' cannot be assigned to a parameter of type 'Any'." + f9(»B()«); + // $TEST$ no error "An argument of type 'C' cannot be assigned to a parameter of type 'Any'." + f9(callableType = »C()«); + // $TEST$ no error "An argument of type 'D' cannot be assigned to a parameter of type 'Any'." + f9(»D()«); + // $TEST$ error "An argument of type 'C?' cannot be assigned to a parameter of type 'Any'." + f9(»maybeC()«); + // $TEST$ no error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type 'Any'." + f9(»someVariantOfMyEnum1()«); + // $TEST$ no error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type 'Any'." + f9(»someVariantOfMyEnum2()«); + // $TEST$ no error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type 'Any'." + f9(»MyEnum1.Variant1«); + // $TEST$ no error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type 'Any'." + f9(»MyEnum1.Variant2«); + // $TEST$ no error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type 'Any'." + f9(»MyEnum2.Variant1«); + // $TEST$ no error "An argument of type 'union' cannot be assigned to a parameter of type 'Any'." + f9(»aOrC()«); + // $TEST$ no error "An argument of type 'union' cannot be assigned to a parameter of type 'Any'." + f9(»bOrC()«); + // $TEST$ no error "An argument of type 'vararg' cannot be assigned to a parameter of type 'Any'." + f9(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type 'Any'." + f9(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f9(unresolved = »1«); + + // $TEST$ no error "An argument of type '(Int) -> (Int)' cannot be assigned to a parameter of type 'Any?'." + f10(»intToInt«); + // $TEST$ no error "An argument of type '(C) -> ()' cannot be assigned to a parameter of type 'Any?'." + f10(»f2«); + // $TEST$ no error "An argument of type 'B' cannot be assigned to a parameter of type 'Any?'." + f10(»B()«); + // $TEST$ no error "An argument of type 'C' cannot be assigned to a parameter of type 'Any?'." + f10(callableType = »C()«); + // $TEST$ no error "An argument of type 'D' cannot be assigned to a parameter of type 'Any?'." + f10(»D()«); + // $TEST$ no error "An argument of type 'C?' cannot be assigned to a parameter of type 'Any?'." + f10(»maybeC()«); + // $TEST$ no error "An argument of type 'MyEnum1' cannot be assigned to a parameter of type 'Any?'." + f10(»someVariantOfMyEnum1()«); + // $TEST$ no error "An argument of type 'MyEnum2' cannot be assigned to a parameter of type 'Any?'." + f10(»someVariantOfMyEnum2()«); + // $TEST$ no error "An argument of type 'MyEnum1.Variant1' cannot be assigned to a parameter of type 'Any?'." + f10(»MyEnum1.Variant1«); + // $TEST$ no error "An argument of type 'MyEnum1.Variant2' cannot be assigned to a parameter of type 'Any?'." + f10(»MyEnum1.Variant2«); + // $TEST$ no error "An argument of type 'MyEnum2.Variant1' cannot be assigned to a parameter of type 'Any?'." + f10(»MyEnum2.Variant1«); + // $TEST$ no error "An argument of type 'union' cannot be assigned to a parameter of type 'Any?'." + f10(»aOrC()«); + // $TEST$ no error "An argument of type 'union' cannot be assigned to a parameter of type 'Any?'." + f10(»bOrC()«); + // $TEST$ no error "An argument of type 'vararg' cannot be assigned to a parameter of type 'Any?'." + f10(»variadicParam«); + // $TEST$ no error "An argument of type '$Unresolved' cannot be assigned to a parameter of type 'Any?'." + f10(»unresolved«); + // $TEST$ no error r"An argument of type '[^']*' cannot be assigned to a parameter of type '[^']*'." + f10(unresolved = »1«); +} + +fun f1(callableType: (a: Int) -> (r: Int)) +fun f2(classType: C) +fun f3(enumType: MyEnum1) +fun f4(enumVariantType: MyEnum1.Variant1) +fun f5(unionType: union) +fun f6(unresolvedType: Unresolved) +fun f7(vararg variadicType: C) +fun f8(callableType: (vararg a: Int) -> ()) +fun f9(any: Any) +fun f10(anyOrNull: Any?) + +class A() +class B() +class C() +class D() sub C + +enum MyEnum1 { + Variant1 + Variant2 +} +enum MyEnum2 { + Variant1 + Variant2 +} + +fun maybeC() -> instanceOrNull: C? +fun aOrC() -> instance: union +fun bOrC() -> instance: union +fun someVariantOfMyEnum1() -> variant: MyEnum1 +fun someVariantOfMyEnum2() -> variant: MyEnum2 +fun intToInt(a: Int) -> (r: Int) diff --git a/tests/resources/validation/skip-old/assignments/hasNoEffect.sdstest b/tests/resources/validation/skip-old/assignments/hasNoEffect.sdstest new file mode 100644 index 000000000..729ecb48d --- /dev/null +++ b/tests/resources/validation/skip-old/assignments/hasNoEffect.sdstest @@ -0,0 +1,19 @@ +step myFunction() -> a: Int { + // $TEST$ warning "This statement does nothing." + »_ = 1 + 2;« + + // $TEST$ no warning "This statement does nothing." + »val a = 1;« + // $TEST$ no warning "This statement does nothing." + »yield a = 1;« + + () { + // $TEST$ warning "This statement does nothing." + »_ = 1 + 2;« + + // $TEST$ no warning "This statement does nothing." + »val a = 1;« + // $TEST$ no warning "This statement does nothing." + »yield a = 1;« + }; +} diff --git a/tests/resources/validation/skip-old/defaultValues.sdstest b/tests/resources/validation/skip-old/defaultValues.sdstest new file mode 100644 index 000000000..f1ce05cde --- /dev/null +++ b/tests/resources/validation/skip-old/defaultValues.sdstest @@ -0,0 +1,19 @@ +package tests.validation.typeChecking.defaultValues + +fun myFun( + // $TEST$ no error "An default value of type 'Int' cannot be assigned to a parameter of type 'Int'." + param1: Int = »1«, + + // $TEST$ error "A default value of type 'String' cannot be assigned to a parameter of type 'Int'." + param2: Int = »""«, +) + +fun myOtherFun(callback: (a: Int) -> ()) + +step myStep() { + // $TEST$ no error "An default value of type 'Int' cannot be assigned to a parameter of type 'Int'." + myOtherFun((a = »1«) {}); + + // $TEST$ error "A default value of type 'String' cannot be assigned to a parameter of type 'Int'." + myOtherFun((a = »""«) {}); +} diff --git a/tests/resources/validation/skip-old/expressionStatements/hasNoEffect.sdstest b/tests/resources/validation/skip-old/expressionStatements/hasNoEffect.sdstest new file mode 100644 index 000000000..9e2e40079 --- /dev/null +++ b/tests/resources/validation/skip-old/expressionStatements/hasNoEffect.sdstest @@ -0,0 +1,78 @@ +package tests.validation.statements.expressionStatements.hasNoEffect + +fun impureFunction() +@Pure fun pureFunction() -> a: Int + +class MyClass() { + fun impureFunction() + @Pure fun pureFunction() +} + +step pureStep() { + val a = pureFunction(); +} + +step impureStep() { + impureFunction(); +} + +step recursiveA() { + recursiveB(); +} + +step recursiveB() { + recursiveA(); +} + +step myStep() { + // $TEST$ warning "This statement does nothing." + »1 + 2;« + // $TEST$ warning "This statement does nothing." + »pureFunction();« + // $TEST$ warning "This statement does nothing." + »MyClass().pureFunction();« + + // $TEST$ no warning "This statement does nothing." + »impureFunction();« + // $TEST$ no warning "This statement does nothing." + »MyClass().impureFunction();« + + () { + // $TEST$ warning "This statement does nothing." + »1 + 2;« + // $TEST$ warning "This statement does nothing." + »pureFunction();« + // $TEST$ warning "This statement does nothing." + »MyClass().pureFunction();« + + // $TEST$ no warning "This statement does nothing." + »impureFunction();« + // $TEST$ no warning "This statement does nothing." + »MyClass().impureFunction();« + }; + + // $TEST$ warning "This statement does nothing." + »(() { + pureFunction(); + MyClass().pureFunction(); + })();« + + // $TEST$ warning "This statement does nothing." + »pureStep();« + + // $TEST$ no warning "This statement does nothing." + »(() { + impureFunction(); + })();« + + // $TEST$ no warning "This statement does nothing." + »(() { + MyClass().impureFunction(); + })();« + + // $TEST$ no warning "This statement does nothing." + »impureStep();« + + // $TEST$ no warning "This statement does nothing." + »recursiveA();« +} diff --git a/tests/resources/validation/skip-old/indexedAccesses.sdstest b/tests/resources/validation/skip-old/indexedAccesses.sdstest new file mode 100644 index 000000000..c741d5379 --- /dev/null +++ b/tests/resources/validation/skip-old/indexedAccesses.sdstest @@ -0,0 +1,39 @@ +package tests.validation.typeChecking.indexedAccesses + +step f(a: Int, vararg b: Int) { + // $TEST$ error "The receiver of an indexed access must refer to a variadic parameter." + »a«[0]; + + // $TEST$ no error "The receiver of an indexed access must refer to a variadic parameter." + »b«[0]; + + // $TEST$ no error "The receiver of an indexed access must refer to a variadic parameter." + »unresolved«[0]; + + // $TEST$ no error "The receiver of an indexed access must refer to a variadic parameter." + »C.unresolved«[0]; + + // $TEST$ no error "The index of an indexed access must be an instance of the class 'Int'." + b[»0«]; + + // $TEST$ error "The index of an indexed access must be an instance of the class 'Int'." + b[»""«]; + + // $TEST$ error "The index of an indexed access must be an instance of the class 'Int'." + b[»g«]; + + // $TEST$ error "The index of an indexed access must be an instance of the class 'Int'." + b[»h()«]; + + // $TEST$ error "The index of an indexed access must be an instance of the class 'Int'." + b[»b«]; + + // $TEST$ no error "The index of an indexed access must be an instance of the class 'Int'." + b[»unresolved«]; + + // $TEST$ no error "The index of an indexed access must be an instance of the class 'Int'." + b[»C.unresolved«]; +} + +fun g() +fun h() -> index: Int? diff --git a/tests/resources/validation/skip-old/infixOperations.sdstest b/tests/resources/validation/skip-old/infixOperations.sdstest new file mode 100644 index 000000000..418927427 --- /dev/null +++ b/tests/resources/validation/skip-old/infixOperations.sdstest @@ -0,0 +1,230 @@ +package tests.validation.typeChecking.infixOperations + +step f(vararg a: Int) { + + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »true« or »true« ; + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »false« or »false«; + // $TEST$ error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »i()« or »i()«; + // $TEST$ error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »0« or »0«; + // $TEST$ error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »a« or »a«; + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »unresolved« or »unresolved«; + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »C.unresolved« or »C.unresolved«; + + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »true« and »true«; + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »false« and »false«; + // $TEST$ error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »i()« and »i()«; + // $TEST$ error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »0« and »0«; + // $TEST$ error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »a« and »a«; + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »unresolved« and »unresolved«; + // $TEST$ no error "The left operand of a logical infix operation must be an instance of the class 'Boolean'." + // $TEST$ no error "The right operand of a logical infix operation must be an instance of the class 'Boolean'." + »C.unresolved« and »C.unresolved«; + + + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0.0« + »0.0«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0« + »0«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »h()« + »h()«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »""« + »""«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »a« + »a«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »unresolved« + »unresolved«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« + »C.unresolved«; + + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0.0« - »0.0«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0« - »0«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »h()« - »h()«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »""« - »""«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »a« - »a«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »unresolved« - »unresolved«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« - »C.unresolved«; + + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0.0« * »0.0«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0« * »0«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »h()« * »h()«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »""« * »""«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »a« * »a«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »unresolved« * »unresolved«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« * »C.unresolved«; + + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0.0« / »0.0«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »0« / »0«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »h()« / »h()«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »""« / »""«; + // $TEST$ error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »a« / »a«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »unresolved« / »unresolved«; + // $TEST$ no error "The left operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of an arithmetic infix operation must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« / »C.unresolved«; + + + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0.0« < »0.0«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0« < »0«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »h()« < »h()«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »""« < »""«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »a« < »a«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »unresolved« < »unresolved«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« < »C.unresolved«; + + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0.0« <= »0.0«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0« <= »0«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »h()« <= »h()«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »""« <= »""«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »a« <= »a«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »unresolved« <= »unresolved«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« <= »C.unresolved«; + + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0.0« >= »0.0«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0« >= »0«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »h()« >= »h()«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »""« >= »""«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »a« >= »a«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »unresolved« >= »unresolved«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« >= »C.unresolved«; + + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0.0« > »0.0«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »0« > »0«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »h()« > »h()«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »""« > »""«; + // $TEST$ error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »a« > »a«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »unresolved« > »unresolved«; + // $TEST$ no error "The left operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + // $TEST$ no error "The right operand of a comparison must be an instance of the class 'Float' or the class 'Int'." + »C.unresolved« > »C.unresolved«; +} + +fun g() +fun h() -> index: Int? +fun i() -> isTrue: Boolean? diff --git a/tests/resources/validation/skip-old/parameter types.sdstest b/tests/resources/validation/skip-old/parameter types.sdstest new file mode 100644 index 000000000..28f3f9237 --- /dev/null +++ b/tests/resources/validation/skip-old/parameter types.sdstest @@ -0,0 +1,52 @@ +package tests.validation.declarations.annotations.parameterTypes + +class MyClass + +enum ConstantEnum { + Variant1 + Variant2 +} + +enum NonConstantEnum { + Variant1(param: Int) + Variant2 +} + +annotation MyAnnotation( + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + booleanParam: »Boolean«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableBooleanParam: »Boolean?«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + floatParam: »Float«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableFloatParam: »Float?«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + intParam: »Int«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableIntParam: »Int?«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + stringParam: »String«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableStringParam: »String?«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + constantEnumParam: »ConstantEnum«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableConstantEnumParam: »ConstantEnum?«, + // $TEST$ error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nonConstantEnumParam: »NonConstantEnum«, + // $TEST$ error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableNonConstantEnumParam: »NonConstantEnum?«, + // $TEST$ error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + classParam: »MyClass«, + // $TEST$ error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableClassParam: »MyClass?«, + // $TEST$ error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + unresolvedParam: »Unresolved«, + // $TEST$ error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + nullableUnresolvedParam: »Unresolved?«, + // $TEST$ error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + callableParam: »() -> ()«, + // $TEST$ no error "Parameters of annotations must have type Boolean, Float, Int, String, or a constant enum." + vararg variadicParameter: »Int«, +) diff --git a/tests/resources/validation/skip-old/prefixOperations.sdstest b/tests/resources/validation/skip-old/prefixOperations.sdstest new file mode 100644 index 000000000..d2c43af31 --- /dev/null +++ b/tests/resources/validation/skip-old/prefixOperations.sdstest @@ -0,0 +1,38 @@ +package tests.validation.typeChecking.prefixOperations + +step f(vararg a: Int) { + + // $TEST$ no error "The operand of a logical negation must be an instance of the class 'Boolean'." + not »true«; + // $TEST$ no error "The operand of a logical negation must be an instance of the class 'Boolean'." + not »false«; + // $TEST$ error "The operand of a logical negation must be an instance of the class 'Boolean'." + not »i()«; + // $TEST$ error "The operand of a logical negation must be an instance of the class 'Boolean'." + not »0«; + // $TEST$ error "The operand of a logical negation must be an instance of the class 'Boolean'." + not »a«; + // $TEST$ no error "The operand of a logical negation must be an instance of the class 'Boolean'." + not »unresolved«; + // $TEST$ no error "The operand of a logical negation must be an instance of the class 'Boolean'." + not »C.unresolved«; + + // $TEST$ no error "The operand of an arithmetic negation must be an instance of the class 'Float' or the class 'Int'." + -»0.0«; + // $TEST$ no error "The operand of an arithmetic negation must be an instance of the class 'Float' or the class 'Int'." + -»0«; + // $TEST$ error "The operand of an arithmetic negation must be an instance of the class 'Float' or the class 'Int'." + -»h()«; + // $TEST$ error "The operand of an arithmetic negation must be an instance of the class 'Float' or the class 'Int'." + -»""«; + // $TEST$ error "The operand of an arithmetic negation must be an instance of the class 'Float' or the class 'Int'." + -»a«; + // $TEST$ no error "The operand of an arithmetic negation must be an instance of the class 'Float' or the class 'Int'." + -»unresolved«; + // $TEST$ no error "The operand of an arithmetic negation must be an instance of the class 'Float' or the class 'Int'." + -»C.unresolved«; +} + +fun g() +fun h() -> index: Int? +fun i() -> isTrue: Boolean? diff --git a/tests/resources/validation/skip-old/purePropagates.sdstest b/tests/resources/validation/skip-old/purePropagates.sdstest new file mode 100644 index 000000000..4f0f3706c --- /dev/null +++ b/tests/resources/validation/skip-old/purePropagates.sdstest @@ -0,0 +1,21 @@ +package tests.validation.declarations.functions.purePropagates + +class MyOpenClass { + @Pure fun pureFunction1() + @Pure fun pureFunction2() + fun impureFunction1() +} + +class MyClass sub MyOpenClass { + // $TEST$ no error "One of the supertypes of this class declares a pure function with this name, so this must be pure as well." + @Pure fun »ownPureFunction«() + // $TEST$ no error "One of the supertypes of this class declares a pure function with this name, so this must be pure as well." + fun »ownImpureFunction«() + + // $TEST$ error "One of the supertypes of this class declares a pure function with this name, so this must be pure as well." + fun »pureFunction1«() + // $TEST$ no error "One of the supertypes of this class declares a pure function with this name, so this must be pure as well." + @Pure fun »pureFunction2«() + // $TEST$ no error "One of the supertypes of this class declares a pure function with this name, so this must be pure as well." + @Pure fun »impureFunction1«() +} diff --git a/tests/resources/validation/skip-old/recursion.sdstest b/tests/resources/validation/skip-old/recursion.sdstest new file mode 100644 index 000000000..2f308d90d --- /dev/null +++ b/tests/resources/validation/skip-old/recursion.sdstest @@ -0,0 +1,68 @@ +package tests.validation.expressions.calls.recursion + + +pipeline p { + // $TEST$ error "Recursive calls are not allowed." + »a«(); + // $TEST$ error "Recursive calls are not allowed." + »b«(); + // $TEST$ error "Recursive calls are not allowed." + »c«(); + // $TEST$ no error "Recursive calls are not allowed." + »d«(); + // $TEST$ no error "Recursive calls are not allowed." + »f«(); +} + +step a() { + // $TEST$ error "Recursive calls are not allowed." + »a«(); + // $TEST$ error "Recursive calls are not allowed." + »b«(); + // $TEST$ error "Recursive calls are not allowed." + »c«(); + // $TEST$ no error "Recursive calls are not allowed." + »d«(); + // $TEST$ no error "Recursive calls are not allowed." + »f«(); + + () { + // $TEST$ error "Recursive calls are not allowed." + »a«(); + // $TEST$ error "Recursive calls are not allowed." + »b«(); + // $TEST$ error "Recursive calls are not allowed." + »c«(); + // $TEST$ no error "Recursive calls are not allowed." + »d«(); + // $TEST$ no error "Recursive calls are not allowed." + »f«(); + }; + + val lambda1 = () { + // $TEST$ no error "Recursive calls are not allowed." + »lambda1«(); + }; + + val lambda2 = () { + // $TEST$ no error "Recursive calls are not allowed." + »lambda3«(); + }; + + val lambda3 = () { + // $TEST$ no error "Recursive calls are not allowed." + »lambda2«(); + }; +} + +step b() { + // $TEST$ error "Recursive calls are not allowed." + »c«(); +} + +step c() { + // $TEST$ error "Recursive calls are not allowed." + »b«(); +} + +step d() {} diff --git a/tests/resources/validation/skip-old/schemaEffectArguments.sdstest b/tests/resources/validation/skip-old/schemaEffectArguments.sdstest new file mode 100644 index 000000000..c325a2ef5 --- /dev/null +++ b/tests/resources/validation/skip-old/schemaEffectArguments.sdstest @@ -0,0 +1,22 @@ +package tests.validation.typeChecking.schemaEffectArguments + +predicate schemaEffects (){ + + /* $ReadSchema ---------------------------------------------------------------------------------------------------*/ + // $TEST$ error "An argument of type 'Boolean' cannot be assigned to a parameter of type 'String'." + $readSchema(»false«), + + // $TEST$ no error "An argument of type 'String' cannot be assigned to a parameter of type 'String'." + $readSchema(»"datasetNameStr"«), + + /* $CheckColumn --------------------------------------------------------------------------------------------------*/ + // $TEST$ error "An argument of type 'Boolean' cannot be assigned to a parameter of type '::$SchemaType'." + // $TEST$ error "An argument of type 'Int' cannot be assigned to a parameter of type 'vararg'." + // $TEST$ no error "An argument of type 'safeds.lang.String' cannot be assigned to a parameter of type 'safeds.lang.String'." + $checkColumn(»false«, »0«, »"columnNameStr2"«), + + // $TEST$ no error "An argument of type '::$SchemaType' cannot be assigned to a parameter of type '::$SchemaType'." + // $TEST$ no error "An argument of type 'String' cannot be assigned to a parameter of type 'vararg'." + // $TEST$ no error "An argument of type 'String' cannot be assigned to a parameter of type 'String'." + $checkColumn(»::ASchema«, »"columnNameStr1"«, »"columnNameStr2"«) +} diff --git a/tests/resources/validation/skip-old/staticAnalysis/recursion.sdstest b/tests/resources/validation/skip-old/staticAnalysis/recursion.sdstest new file mode 100644 index 000000000..19e9248d8 --- /dev/null +++ b/tests/resources/validation/skip-old/staticAnalysis/recursion.sdstest @@ -0,0 +1,90 @@ +package tests.staticAnalysis.recursion + +// Positive examples ----------------------------------------------------------- + +annotation CallsShouldBeRecursive + +// Direct recursion + +@CallsShouldBeRecursive +step directRecursion(a: Any or directRecursion()) { + directRecursion(); + 1 + directRecursion(); + val a = directRecursion(); +} + +// Transitive recursion + +@CallsShouldBeRecursive +step transitiveRecursion1() { + transitiveRecursion2(); + val a = transitiveRecursion2(); +} + +@CallsShouldBeRecursive +step transitiveRecursion2() { + transitiveRecursion3(); + val a = transitiveRecursion3(); +} + +@CallsShouldBeRecursive +step transitiveRecursion3() { + transitiveRecursion2(); + val a = transitiveRecursion2(); +} + +// Deferred recursion in lambda + +@CallsShouldBeRecursive +step deferredRecursionInLambda() { + (() { directRecursion(); })(); + (() -> directRecursion())(); +} + +// Negative examples ----------------------------------------------------------- + +annotation CallsShouldNotBeRecursive + +// Normal calls + +@CallsShouldNotBeRecursive +step normalCall(f: () -> ()) { + f(); + (() {})(); + (() -> null)(); + + MyClass(); + MyEnum.Variant(); + myFun(); + myStep(); +} + +class MyClass() +enum MyEnum { + Variant() +} +fun myFun() +step myStep() {} + +// Uncalled lambda + +@CallsShouldNotBeRecursive +step uncalledLambda() { + () { uncalledLambda(); }; + () -> uncalledLambda(); +} + +// Lambda recursion (already handled by scoping) + +@CallsShouldNotBeRecursive +step lambdaRecursion() { + val a = () { a(); }; + val b = () -> b(); +} + +// Unresolved callable + +@CallsShouldNotBeRecursive +step unresolvedCallable() { + unresolved(); +} diff --git a/tests/resources/validation/skip-old/staticAnalysis/sideEffects.sdstest b/tests/resources/validation/skip-old/staticAnalysis/sideEffects.sdstest new file mode 100644 index 000000000..38ea9255a --- /dev/null +++ b/tests/resources/validation/skip-old/staticAnalysis/sideEffects.sdstest @@ -0,0 +1,147 @@ +package tests.staticAnalysis.sideEffects + +// Positive examples ----------------------------------------------------------- + +annotation ShouldHaveNoSideEffects + +// Call to class constructor + +class C() + +@ShouldHaveNoSideEffects +step callOfClassConstructor() { + C(); +} + +// Call to enum variant constructor + +enum MyEnum { + Variant +} + +@ShouldHaveNoSideEffects +step callOfEnumVariantConstructor() { + MyEnum.Variant(); +} + +// Function without side effects + +@Pure +fun pureFunction() + +@NoSideEffects +fun functionWithoutSideEffects() + +@ShouldHaveNoSideEffects +step callToPureFunction() { + pureFunction(); + functionWithoutSideEffects(); +} + +// Lambdas without side effects + +@ShouldHaveNoSideEffects +step callToPureLambdas() { + (() {})(); + (() -> null)(); + + () { + (() {})(); + }; + + () -> (() -> null)(); +} + +// Steps without side effects + +step pureStep() {} + +@ShouldHaveNoSideEffects +step callToPureSteps() { + pureStep(); +} + +// Uncalled lambdas + +step pureStepWithUncalledLambdas() { + () -> impureFunction(); +} + +@ShouldHaveNoSideEffects +step uncalledLambdas() { + pureStepWithUncalledLambdas(); +} + +// Function as result + +@ShouldHaveNoSideEffects +step pureFunctionAsResult() { + (() -> pureFunction)()(); +} + +// Negative examples ----------------------------------------------------------- + +annotation ShouldHaveSideEffects + +// Callable type + +@ShouldHaveSideEffects +step callToCallableType(f: () -> ()) { + f(); +} + +// Function with side effects + +fun impureFunction() + +@ShouldHaveSideEffects +step callToImpureFunction() { + impureFunction(); +} + +// Lambdas with side effects + +@ShouldHaveSideEffects +step callToImpureLambdas() { + (() { impureFunction(); })(); + (() -> impureFunction())(); + + () { + (() { impureFunction(); })(); + }; + + () -> (() -> impureFunction())(); +} + +// Steps with side effects + +step impureStep() { + impureFunction(); +} + +@ShouldHaveSideEffects +step callToImpureSteps() { + impureStep(); +} + +// Recursion + +@ShouldHaveSideEffects +step recursion() { + recursion(); +} + +// Unresolved callable + +@ShouldHaveSideEffects +step unresolvedCallable() { + unresolved(); +} + +// Function as parameter + +@ShouldHaveSideEffects +step impureFunctionAsParameter() { + ((f) -> f())(pureFunction); // This is actually pure, but we match in a conservative manner. Can be improved later. + ((f) -> f())(impureFunction); +} diff --git a/tests/resources/validation/skip-old/yields.sdstest b/tests/resources/validation/skip-old/yields.sdstest new file mode 100644 index 000000000..3cfeb4c78 --- /dev/null +++ b/tests/resources/validation/skip-old/yields.sdstest @@ -0,0 +1,13 @@ +package tests.validation.typeChecking.yields + +step myStep1() -> result: Int { + + // $TEST$ no error "A value of type 'Int' cannot be assigned to a result of type 'Int'." + yield result = »1«; +} + +step myStep2() -> result: Int { + + // $TEST$ error "A value of type 'String' cannot be assigned to a result of type 'Int'." + yield result = »""«; +} From f5e7e4186d1ddf1af98202c81aef9b2e963a2db9 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Sun, 22 Oct 2023 16:32:34 +0200 Subject: [PATCH 2/5] docs: add documentation comments to builtin stubs --- .../safeds/lang/annotationUsage.sdsstub | 64 ++++++++++++++----- .../safeds/lang/codeGeneration.sdsstub | 10 +-- .../builtins/safeds/lang/coreClasses.sdsstub | 36 ++++++++--- .../safeds/lang/documentation.sdsstub | 13 ---- .../safeds/lang/ideIntegration.sdsstub | 4 +- .../builtins/safeds/lang/maturity.sdsstub | 20 +++--- .../builtins/safeds/lang/purity.sdsstub | 13 ++-- 7 files changed, 102 insertions(+), 58 deletions(-) delete mode 100644 src/resources/builtins/safeds/lang/documentation.sdsstub diff --git a/src/resources/builtins/safeds/lang/annotationUsage.sdsstub b/src/resources/builtins/safeds/lang/annotationUsage.sdsstub index 82ce3d9d1..41e335416 100644 --- a/src/resources/builtins/safeds/lang/annotationUsage.sdsstub +++ b/src/resources/builtins/safeds/lang/annotationUsage.sdsstub @@ -1,51 +1,83 @@ package safeds.lang -@Description("The annotation can target these declaration types. If the @Target annotation is not used any declaration type can be targeted.") +/** + * The annotation must target only the specified declaration types. By default, any declaration type can be targeted. + * + * @param targets An exhaustive list of the valid targets. + */ @Target([AnnotationTarget.Annotation]) annotation Target( - @Description("The valid targets.") targets: List ) -@Description("The declaration types that can be targeted by annotations.") +/** + * The declaration types that can be targeted by annotations. + */ enum AnnotationTarget { - @Description("The annotation can be called on annotations.") + + /** + * The annotation can be called on annotations. + */ Annotation - @Description("The annotation can be called on attributes.") + /** + * The annotation can be called on attributes. + */ Attribute - @Description("The annotation can be called on classes.") + /** + * The annotation can be called on classes. + */ Class - @Description("The annotation can be called on enums.") + /** + * The annotation can be called on enums. + */ Enum - @Description("The annotation can be called on enum variants.") + /** + * The annotation can be called on enum variants. + */ EnumVariant - @Description("The annotation can be called on functions.") + /** + * The annotation can be called on functions. + */ Function - @Description("The annotation can be called on modules (i.e. files).") + /** + * The annotation can be called on modules (i.e. files). + */ Module - @Description("The annotation can be called on parameters.") + /** + * The annotation can be called on parameters. + */ Parameter - @Description("The annotation can be called on pipelines.") + /** + * The annotation can be called on pipelines. + */ Pipeline - @Description("The annotation can be called on results.") + /** + * The annotation can be called on results. + */ Result - @Description("The annotation can be called on segments.") + /** + * The annotation can be called on segments. + */ Segment - @Description("The annotation can be called on type parameters.") + /** + * The annotation can be called on type parameters. + */ TypeParameter } -@Description("The annotation can be called multiple times for the same declaration.") +/** + * The annotation can be called multiple times for the same declaration. + */ @Target([AnnotationTarget.Annotation]) annotation Repeatable diff --git a/src/resources/builtins/safeds/lang/codeGeneration.sdsstub b/src/resources/builtins/safeds/lang/codeGeneration.sdsstub index ca7ec40ce..83b09a0e1 100644 --- a/src/resources/builtins/safeds/lang/codeGeneration.sdsstub +++ b/src/resources/builtins/safeds/lang/codeGeneration.sdsstub @@ -1,13 +1,16 @@ package safeds.lang -@Description("The qualified name of the corresponding Python module (default is the qualified name of the package).") +/** + * The qualified name of the corresponding Python module. By default, this is the qualified name of the package. + */ @Target([AnnotationTarget.Module]) annotation PythonModule( - @Description("The qualified name of the corresponding Python module.") qualifiedName: String ) -@Description("The name of the corresponding API element in Python (default is the name of the declaration in the stubs).") +/** + * The name of the corresponding API element in Python. By default, this is the name of the declaration in the stubs. + */ @Target([ AnnotationTarget.Attribute, AnnotationTarget.Class, @@ -19,6 +22,5 @@ annotation PythonModule( AnnotationTarget.Segment, ]) annotation PythonName( - @Description("The name of the corresponding API element in Python.") name: String ) diff --git a/src/resources/builtins/safeds/lang/coreClasses.sdsstub b/src/resources/builtins/safeds/lang/coreClasses.sdsstub index 1d966c47e..a3fe9a769 100644 --- a/src/resources/builtins/safeds/lang/coreClasses.sdsstub +++ b/src/resources/builtins/safeds/lang/coreClasses.sdsstub @@ -1,28 +1,46 @@ package safeds.lang -@Description("The common superclass of all classes.") +/** + * The common superclass of all classes. + */ class Any -@Description("The common subclass of all classes.") +/** + * The common subclass of all classes. + */ class Nothing -@Description("A truth value.") +/** + * A truth value. + */ class Boolean -@Description("A number.") +/** + * A number. + */ class Number -@Description("An integer.") +/** + * An integer. + */ class Int sub Number -@Description("A floating-point number.") +/** + * A floating-point number. + */ class Float sub Number -@Description("A list of elements.") +/** + * A list of elements. + */ class List -@Description("A map of keys to values.") +/** + * A map of keys to values. + */ class Map -@Description("Some text.") +/** + * Some text. + */ class String diff --git a/src/resources/builtins/safeds/lang/documentation.sdsstub b/src/resources/builtins/safeds/lang/documentation.sdsstub deleted file mode 100644 index c94d885cc..000000000 --- a/src/resources/builtins/safeds/lang/documentation.sdsstub +++ /dev/null @@ -1,13 +0,0 @@ -package safeds.lang - -@Description("The purpose of a declaration.") -annotation Description( - @Description("The purpose of a declaration.") - description: String -) - -@Description("The version in which a declaration was added.") -annotation Since( - @Description("The version in which a declaration was added.") - version: String -) diff --git a/src/resources/builtins/safeds/lang/ideIntegration.sdsstub b/src/resources/builtins/safeds/lang/ideIntegration.sdsstub index 812c18e25..9eed1615d 100644 --- a/src/resources/builtins/safeds/lang/ideIntegration.sdsstub +++ b/src/resources/builtins/safeds/lang/ideIntegration.sdsstub @@ -1,6 +1,8 @@ package safeds.lang +/** + * This parameter should only be used by expert users. + */ @Experimental -@Description("This parameter should only be used by expert users.") @Target([AnnotationTarget.Parameter]) annotation Expert diff --git a/src/resources/builtins/safeds/lang/maturity.sdsstub b/src/resources/builtins/safeds/lang/maturity.sdsstub index 2b53d06a8..509f20d62 100644 --- a/src/resources/builtins/safeds/lang/maturity.sdsstub +++ b/src/resources/builtins/safeds/lang/maturity.sdsstub @@ -1,6 +1,13 @@ package safeds.lang -@Description("The declaration should no longer be used.") +/** + * The declaration should no longer be used. + * + * @param alternative What to use instead. + * @param reason Why the declaration was deprecated. + * @param sinceVersion When the declaration was deprecated. + * @param removalVersion When the declaration will be removed. + */ @Target([ AnnotationTarget.Annotation, AnnotationTarget.Attribute, @@ -13,20 +20,15 @@ package safeds.lang AnnotationTarget.Segment, ]) annotation Deprecated( - @Description("What to use instead.") alternative: String? = null, - - @Description("Why the declaration was deprecated.") reason: String? = null, - - @Description("When the declaration was deprecated.") sinceVersion: String? = null, - - @Description("When the declaration will be removed.") removalVersion: String? = null, ) -@Description("The declaration might change without a major version bump.") +/** + * The declaration might change without a major version bump. + */ @Target([ AnnotationTarget.Annotation, AnnotationTarget.Attribute, diff --git a/src/resources/builtins/safeds/lang/purity.sdsstub b/src/resources/builtins/safeds/lang/purity.sdsstub index 5ce277f46..8353c1610 100644 --- a/src/resources/builtins/safeds/lang/purity.sdsstub +++ b/src/resources/builtins/safeds/lang/purity.sdsstub @@ -1,11 +1,12 @@ package safeds.lang +/** + * Indicates that the function has no side effects and always returns the same results given the same arguments. + * + * Calls to such a function may be eliminated, if the result is not used. Moreover, the function can be memoized, i.e. + * we can remember its results for a set of arguments. Finally, a pure function can be called at any time, allowing + * reordering of calls or parallelization. + */ @Experimental -@Description("The function has no side effects and returns the same results for the same arguments.") @Target([AnnotationTarget.Function]) annotation Pure - -@Experimental -@Description("The function has no side effects.") -@Target([AnnotationTarget.Function]) -annotation NoSideEffects From d08fd5d0a6766687656a4dc146e2bdf5778d84f5 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Sun, 22 Oct 2023 17:46:39 +0200 Subject: [PATCH 3/5] feat: warning if targets are repeated in call of `@Target` annotation --- src/language/builtins/safe-ds-annotations.ts | 65 +++++++++++++++++-- src/language/builtins/safe-ds-enums.ts | 16 +++++ src/language/safe-ds-module.ts | 3 + src/language/validation/builtins/target.ts | 45 +++++++++++++ src/language/validation/safe-ds-validator.ts | 3 + .../duplicate entry/duplicateTarget.sdstest | 11 ---- .../target/duplicate target/main.sdstest | 48 ++++++++++++++ .../no target annotation.sdstest | 5 ++ .../{target.sdstest => main.sdstest} | 52 +++++++-------- 9 files changed, 204 insertions(+), 44 deletions(-) create mode 100644 src/language/builtins/safe-ds-enums.ts create mode 100644 src/language/validation/builtins/target.ts delete mode 100644 tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest create mode 100644 tests/resources/validation/builtins/annotations/target/duplicate target/main.sdstest create mode 100644 tests/resources/validation/builtins/annotations/target/duplicate target/no target annotation.sdstest rename tests/resources/validation/builtins/annotations/target/wrong target/{target.sdstest => main.sdstest} (68%) diff --git a/src/language/builtins/safe-ds-annotations.ts b/src/language/builtins/safe-ds-annotations.ts index 678098066..74212c980 100644 --- a/src/language/builtins/safe-ds-annotations.ts +++ b/src/language/builtins/safe-ds-annotations.ts @@ -1,12 +1,27 @@ -import { isSdsAnnotation, SdsAnnotatedObject, SdsAnnotation, SdsModule, SdsParameter } from '../generated/ast.js'; -import { getArguments, findFirstAnnotationCallOf, hasAnnotationCallOf } from '../helpers/nodeProperties.js'; +import { + isSdsAnnotation, + isSdsEnum, + SdsAnnotatedObject, + SdsAnnotation, + SdsEnumVariant, + SdsModule, + SdsParameter, +} from '../generated/ast.js'; +import { + findFirstAnnotationCallOf, + getArguments, + getEnumVariants, + getParameters, + hasAnnotationCallOf, +} from '../helpers/nodeProperties.js'; import { SafeDsModuleMembers } from './safe-ds-module-members.js'; import { resourceNameToUri } from '../../helpers/resources.js'; -import { URI } from 'langium'; +import { EMPTY_STREAM, getContainerOfType, Stream, stream, URI } from 'langium'; import { SafeDsServices } from '../safe-ds-module.js'; import { SafeDsNodeMapper } from '../helpers/safe-ds-node-mapper.js'; -import { EvaluatedNode, StringConstant } from '../partialEvaluation/model.js'; +import { EvaluatedEnumVariant, EvaluatedList, EvaluatedNode, StringConstant } from '../partialEvaluation/model.js'; import { SafeDsPartialEvaluator } from '../partialEvaluation/safe-ds-partial-evaluator.js'; +import { SafeDsEnums } from './safe-ds-enums.js'; const ANNOTATION_USAGE_URI = resourceNameToUri('builtins/safeds/lang/annotationUsage.sdsstub'); const CODE_GENERATION_URI = resourceNameToUri('builtins/safeds/lang/codeGeneration.sdsstub'); @@ -14,12 +29,14 @@ const IDE_INTEGRATION_URI = resourceNameToUri('builtins/safeds/lang/ideIntegrati const MATURITY_URI = resourceNameToUri('builtins/safeds/lang/maturity.sdsstub'); export class SafeDsAnnotations extends SafeDsModuleMembers { + private readonly builtinEnums: SafeDsEnums; private readonly nodeMapper: SafeDsNodeMapper; private readonly partialEvaluator: SafeDsPartialEvaluator; constructor(services: SafeDsServices) { super(services); + this.builtinEnums = services.builtins.Enums; this.nodeMapper = services.helpers.NodeMapper; this.partialEvaluator = services.evaluation.PartialEvaluator; } @@ -82,6 +99,32 @@ export class SafeDsAnnotations extends SafeDsModuleMembers { return this.getAnnotation(ANNOTATION_USAGE_URI, 'Repeatable'); } + streamValidTargets(node: SdsAnnotation | undefined): Stream { + // If no targets are specified, every target is valid + if (!hasAnnotationCallOf(node, this.Target)) { + return stream(getEnumVariants(this.builtinEnums.AnnotationTarget)); + } + + // If targets are specified, but we could not evaluate them to a list, no target is valid + const value = this.getArgumentValue(node, this.Target, 'targets'); + if (!(value instanceof EvaluatedList)) { + return EMPTY_STREAM; + } + + // Otherwise, filter the elements of the list and keep only variants of the AnnotationTarget enum + return stream(value.elements) + .filter( + (it) => + it instanceof EvaluatedEnumVariant && + getContainerOfType(it.variant, isSdsEnum) === this.builtinEnums.AnnotationTarget, + ) + .map((it) => (it).variant); + } + + get Target(): SdsAnnotation | undefined { + return this.getAnnotation(ANNOTATION_USAGE_URI, 'Target'); + } + private getAnnotation(uri: URI, name: string): SdsAnnotation | undefined { return this.getModuleMember(uri, name, isSdsAnnotation); } @@ -96,9 +139,17 @@ export class SafeDsAnnotations extends SafeDsModuleMembers { parameterName: string, ): EvaluatedNode { const annotationCall = findFirstAnnotationCallOf(node, annotation); - const argumentValue = getArguments(annotationCall).find( + + // Parameter is set explicitly + const argument = getArguments(annotationCall).find( (it) => this.nodeMapper.argumentToParameter(it)?.name === parameterName, - )?.value; - return this.partialEvaluator.evaluate(argumentValue); + ); + if (argument) { + return this.partialEvaluator.evaluate(argument.value); + } + + // Parameter is not set explicitly, so we use the default value + const parameter = getParameters(annotation).find((it) => it.name === parameterName); + return this.partialEvaluator.evaluate(parameter?.defaultValue); } } diff --git a/src/language/builtins/safe-ds-enums.ts b/src/language/builtins/safe-ds-enums.ts new file mode 100644 index 000000000..b4b251e56 --- /dev/null +++ b/src/language/builtins/safe-ds-enums.ts @@ -0,0 +1,16 @@ +import { isSdsEnum, SdsEnum } from '../generated/ast.js'; +import { SafeDsModuleMembers } from './safe-ds-module-members.js'; +import { resourceNameToUri } from '../../helpers/resources.js'; +import { URI } from 'langium'; + +const ANNOTATION_USAGE_URI = resourceNameToUri('builtins/safeds/lang/annotationUsage.sdsstub'); + +export class SafeDsEnums extends SafeDsModuleMembers { + get AnnotationTarget(): SdsEnum | undefined { + return this.getEnum(ANNOTATION_USAGE_URI, 'AnnotationTarget'); + } + + private getEnum(uri: URI, name: string): SdsEnum | undefined { + return this.getModuleMember(uri, name, isSdsEnum); + } +} diff --git a/src/language/safe-ds-module.ts b/src/language/safe-ds-module.ts index 31912ff63..5c82b6c82 100644 --- a/src/language/safe-ds-module.ts +++ b/src/language/safe-ds-module.ts @@ -29,6 +29,7 @@ import { SafeDsCoreTypes } from './typing/safe-ds-core-types.js'; import { SafeDsNodeKindProvider } from './lsp/safe-ds-node-kind-provider.js'; import { SafeDsDocumentSymbolProvider } from './lsp/safe-ds-document-symbol-provider.js'; import { SafeDsDocumentBuilder } from './workspace/safe-ds-document-builder.js'; +import { SafeDsEnums } from './builtins/safe-ds-enums.js'; /** * Declaration of custom services - add your own service classes here. @@ -37,6 +38,7 @@ export type SafeDsAddedServices = { builtins: { Annotations: SafeDsAnnotations; Classes: SafeDsClasses; + Enums: SafeDsEnums; }; evaluation: { PartialEvaluator: SafeDsPartialEvaluator; @@ -70,6 +72,7 @@ export const SafeDsModule: Module new SafeDsAnnotations(services), Classes: (services) => new SafeDsClasses(services), + Enums: (services) => new SafeDsEnums(services), }, evaluation: { PartialEvaluator: (services) => new SafeDsPartialEvaluator(services), diff --git a/src/language/validation/builtins/target.ts b/src/language/validation/builtins/target.ts new file mode 100644 index 000000000..9c13b4bcd --- /dev/null +++ b/src/language/validation/builtins/target.ts @@ -0,0 +1,45 @@ +import { ValidationAcceptor } from 'langium'; +import { SdsAnnotation, SdsAnnotationCall } from '../../generated/ast.js'; +import { SafeDsServices } from '../../safe-ds-module.js'; +import { duplicatesBy, isEmpty } from '../../../helpers/collectionUtils.js'; +import { pluralize } from '../../../helpers/stringUtils.js'; +import { findFirstAnnotationCallOf } from '../../helpers/nodeProperties.js'; + +export const CODE_TARGET_DUPLICATE_TARGET = 'target/duplicate-target'; +export const CODE_TARGET_WRONG_TARGET = 'target/wrong-target'; + +export const targetShouldNotHaveDuplicateEntries = (services: SafeDsServices) => { + const builtinAnnotations = services.builtins.Annotations; + + return (node: SdsAnnotation, accept: ValidationAcceptor) => { + const annotationCall = findFirstAnnotationCallOf(node, builtinAnnotations.Target); + if (!annotationCall) { + return; + } + + const validTargets = builtinAnnotations.streamValidTargets(node).map((it) => `'${it.name}'`); + const duplicateTargets = duplicatesBy(validTargets, (it) => it) + .distinct() + .toArray(); + + if (isEmpty(duplicateTargets)) { + return; + } + + const noun = pluralize(duplicateTargets.length, 'target'); + const duplicateTargetString = duplicateTargets.join(', '); + const verb = pluralize(duplicateTargets.length, 'occurs', 'occur'); + + accept('warning', `The ${noun} ${duplicateTargetString} ${verb} multiple times.`, { + node: annotationCall, + property: 'annotation', + code: CODE_TARGET_DUPLICATE_TARGET, + }); + }; +}; + +export const annotationCallMustHaveCorrectTarget = (services: SafeDsServices) => { + const builtinAnnotations = services.builtins.Annotations; + + return (node: SdsAnnotationCall, accept: ValidationAcceptor) => {}; +}; diff --git a/src/language/validation/safe-ds-validator.ts b/src/language/validation/safe-ds-validator.ts index 618b96196..a9ef8c3cc 100644 --- a/src/language/validation/safe-ds-validator.ts +++ b/src/language/validation/safe-ds-validator.ts @@ -126,6 +126,7 @@ import { literalTypeMustNotContainMapLiteral, literalTypeShouldNotHaveDuplicateLiteral, } from './other/types/literalTypes.js'; +import { annotationCallMustHaveCorrectTarget, targetShouldNotHaveDuplicateEntries } from './builtins/target.js'; /** * Register custom validation checks. @@ -150,12 +151,14 @@ export const registerValidationChecks = function (services: SafeDsServices) { annotationMustContainUniqueNames, annotationParameterListShouldNotBeEmpty, annotationParameterShouldNotHaveConstModifier, + targetShouldNotHaveDuplicateEntries(services), ], SdsAnnotationCall: [ annotationCallAnnotationShouldNotBeDeprecated(services), annotationCallAnnotationShouldNotBeExperimental(services), annotationCallArgumentListShouldBeNeeded, annotationCallArgumentsMustBeConstant(services), + annotationCallMustHaveCorrectTarget(services), annotationCallMustNotLackArgumentList, ], SdsArgument: [ diff --git a/tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest b/tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest deleted file mode 100644 index 2020d7ddc..000000000 --- a/tests/resources/validation/builtins/annotations/target/duplicate entry/duplicateTarget.sdstest +++ /dev/null @@ -1,11 +0,0 @@ -package tests.validation.other.annotationCalls.duplicateTarget - -@Target( - // $TEST$ warning "This annotation target is used multiple times." - »AnnotationTarget.Annotation«, - // $TEST$ warning "This annotation target is used multiple times." - »AnnotationTarget.Annotation«, - // $TEST$ no warning "This annotation target is used multiple times." - »AnnotationTarget.Class« -) -annotation TestAnnotation diff --git a/tests/resources/validation/builtins/annotations/target/duplicate target/main.sdstest b/tests/resources/validation/builtins/annotations/target/duplicate target/main.sdstest new file mode 100644 index 000000000..fed72a6d3 --- /dev/null +++ b/tests/resources/validation/builtins/annotations/target/duplicate target/main.sdstest @@ -0,0 +1,48 @@ +package tests.validation.builtins.annotations.target.duplicateTarget + +// $TEST$ no warning r"The targets? occurs? multiple times." +@»Target«([AnnotationTarget.Annotation]) + +/* + * We already show another error if the `@Target` annotation is called multiple times. + */ + +// $TEST$ no warning r"The targets? occurs? multiple times." +@»Target«([ + AnnotationTarget.Annotation, + AnnotationTarget.Annotation, +]) +annotation TestAnnotation1 + +// $TEST$ warning "The target 'Annotation' occurs multiple times." +@»Target«([ + AnnotationTarget.Annotation, + AnnotationTarget.Annotation, +]) +annotation TestAnnotation2 + +// $TEST$ warning "The targets 'Class', 'Annotation' occur multiple times." +@»Target«([ + AnnotationTarget.Class, + AnnotationTarget.Class, + AnnotationTarget.Class, + AnnotationTarget.Annotation, + AnnotationTarget.Annotation, + AnnotationTarget.Annotation, +]) +annotation TestAnnotation3 + +/* + * We already show another error if an annotation is called with arguments of invalid type. + */ + + // $TEST$ no warning r"The targets? occurs? multiple times." +@»Target«(1) +annotation TestAnnotation4 + +// $TEST$ no warning r"The targets? occurs? multiple times." +@»Target«([ + 1, + 1, +]) +annotation TestAnnotation5 diff --git a/tests/resources/validation/builtins/annotations/target/duplicate target/no target annotation.sdstest b/tests/resources/validation/builtins/annotations/target/duplicate target/no target annotation.sdstest new file mode 100644 index 000000000..8bf700aac --- /dev/null +++ b/tests/resources/validation/builtins/annotations/target/duplicate target/no target annotation.sdstest @@ -0,0 +1,5 @@ +package tests.validation.builtins.annotations.target.duplicateTarget + +// $TEST$ no warning r"The targets? occurs? multiple times." + +annotation TestAnnotation6 diff --git a/tests/resources/validation/builtins/annotations/target/wrong target/target.sdstest b/tests/resources/validation/builtins/annotations/target/wrong target/main.sdstest similarity index 68% rename from tests/resources/validation/builtins/annotations/target/wrong target/target.sdstest rename to tests/resources/validation/builtins/annotations/target/wrong target/main.sdstest index 53c9716ba..79e10f02a 100644 --- a/tests/resources/validation/builtins/annotations/target/wrong target/target.sdstest +++ b/tests/resources/validation/builtins/annotations/target/wrong target/main.sdstest @@ -1,15 +1,15 @@ // $TEST$ error "This annotation cannot be applied to a compilation unit." »@AnnotationForEnums« -// $TEST$ no error "This annotation cannot be applied to a compilation unit." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForCompilationUnits« -// $TEST$ no error "This annotation cannot be applied to a compilation unit." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForMultipleTargets« -// $TEST$ no error "This annotation cannot be applied to a compilation unit." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« -// $TEST$ no error "This annotation cannot be applied to a compilation unit." +// $TEST$ no error r"This annotation cannot be applied to .*" »@UnresolvedAnnotation« -package tests.validation.other.annotationCalls.target +package tests.validation.builtins.annotations.target.wrongTarget @Target(AnnotationTarget.Annotation) annotation AnnotationForAnnotations @@ -45,7 +45,7 @@ annotation AnnotationForTypeParameters annotation AnnotationForPipelines @Target(AnnotationTarget.Step) -annotation AnnotationForSteps +annotation AnnotationForSegments @Target(AnnotationTarget.CompilationUnit, AnnotationTarget.Class) annotation AnnotationForMultipleTargets @@ -64,19 +64,19 @@ annotation TestAnnotation // $TEST$ error "This annotation cannot be applied to a class." »@AnnotationForCompilationUnits« -// $TEST$ no error "This annotation cannot be applied to a class." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForClasses« -// $TEST$ no error "This annotation cannot be applied to a class." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForMultipleTargets« -// $TEST$ no error "This annotation cannot be applied to a class." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« class TestClass< - // $TEST$ error "This annotation cannot be applied to a type parameter." + // $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForPipelines« - // $TEST$ no error "This annotation cannot be applied to a type parameter." + // $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForTypeParameters« - // $TEST$ no error "This annotation cannot be applied to a type parameter." + // $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« TEST_TYPE_PARAMETER > { @@ -110,42 +110,42 @@ enum TestEnum { // $TEST$ error "This annotation cannot be applied to a function." »@AnnotationForParameters« -// $TEST$ no error "This annotation cannot be applied to a function." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForFunctions« -// $TEST$ no error "This annotation cannot be applied to a function." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« fun testFunction( // $TEST$ error "This annotation cannot be applied to a parameter." »@AnnotationForResults« - // $TEST$ no error "This annotation cannot be applied to a parameter." + // $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForParameters« - // $TEST$ no error "This annotation cannot be applied to a parameter." + // $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« testParameter: Int ) -> ( // $TEST$ error "This annotation cannot be applied to a result." »@AnnotationForTypeParameters« - // $TEST$ no error "This annotation cannot be applied to a result." + // $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForResults« - // $TEST$ no error "This annotation cannot be applied to a result." + // $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« testResult: Int ) // $TEST$ error "This annotation cannot be applied to a pipeline." -»@AnnotationForSteps« -// $TEST$ no error "This annotation cannot be applied to a pipeline." +»@AnnotationForSegments« +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForPipelines« -// $TEST$ no error "This annotation cannot be applied to a pipeline." +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« pipeline testPipeline {} -// $TEST$ error "This annotation cannot be applied to a step." +// $TEST$ error "This annotation cannot be applied to a segment." »@AnnotationForAnnotations« -// $TEST$ no error "This annotation cannot be applied to a step." -»@AnnotationForSteps« -// $TEST$ no error "This annotation cannot be applied to a step." +// $TEST$ no error r"This annotation cannot be applied to .*" +»@AnnotationForSegments« +// $TEST$ no error r"This annotation cannot be applied to .*" »@AnnotationForAnything« -step testStep() {} +segment testSegment() {} From 1ac85fd249f9c2bc8244739f654cfa98a4d866a4 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Sun, 22 Oct 2023 18:10:34 +0200 Subject: [PATCH 4/5] feat: error if annotation is used on incorrect target --- src/language/helpers/nodeProperties.ts | 4 + src/language/validation/builtins/target.ts | 115 +++++++++- .../target/wrong target/main.sdstest | 209 ++++++++++-------- 3 files changed, 231 insertions(+), 97 deletions(-) diff --git a/src/language/helpers/nodeProperties.ts b/src/language/helpers/nodeProperties.ts index a698142ad..1aa03d369 100644 --- a/src/language/helpers/nodeProperties.ts +++ b/src/language/helpers/nodeProperties.ts @@ -153,6 +153,10 @@ export const getAnnotationCalls = (node: SdsAnnotatedObject | undefined): SdsAnn } }; +export const getAnnotationCallTarget = (node: SdsAnnotationCall | undefined): SdsDeclaration | undefined => { + return getContainerOfType(node, isSdsDeclaration); +}; + export const findFirstAnnotationCallOf = ( node: SdsAnnotatedObject | undefined, expected: SdsAnnotation | undefined, diff --git a/src/language/validation/builtins/target.ts b/src/language/validation/builtins/target.ts index 9c13b4bcd..f562efcb2 100644 --- a/src/language/validation/builtins/target.ts +++ b/src/language/validation/builtins/target.ts @@ -1,9 +1,24 @@ import { ValidationAcceptor } from 'langium'; -import { SdsAnnotation, SdsAnnotationCall } from '../../generated/ast.js'; +import { + isSdsAnnotation, + isSdsAttribute, + isSdsClass, + isSdsEnum, + isSdsEnumVariant, + isSdsFunction, + isSdsModule, + isSdsParameter, + isSdsPipeline, + isSdsResult, + isSdsSegment, + isSdsTypeParameter, + SdsAnnotation, + SdsAnnotationCall, +} from '../../generated/ast.js'; import { SafeDsServices } from '../../safe-ds-module.js'; import { duplicatesBy, isEmpty } from '../../../helpers/collectionUtils.js'; import { pluralize } from '../../../helpers/stringUtils.js'; -import { findFirstAnnotationCallOf } from '../../helpers/nodeProperties.js'; +import { findFirstAnnotationCallOf, getAnnotationCallTarget } from '../../helpers/nodeProperties.js'; export const CODE_TARGET_DUPLICATE_TARGET = 'target/duplicate-target'; export const CODE_TARGET_WRONG_TARGET = 'target/wrong-target'; @@ -41,5 +56,99 @@ export const targetShouldNotHaveDuplicateEntries = (services: SafeDsServices) => export const annotationCallMustHaveCorrectTarget = (services: SafeDsServices) => { const builtinAnnotations = services.builtins.Annotations; - return (node: SdsAnnotationCall, accept: ValidationAcceptor) => {}; + return (node: SdsAnnotationCall, accept: ValidationAcceptor) => { + const annotation = node.annotation?.ref; + if (!annotation) { + return; + } + + const actualTarget = getActualTarget(node); + if (!actualTarget) { + return; + } + + const validTargets = builtinAnnotations + .streamValidTargets(annotation) + .map((it) => it.name) + .toSet(); + + if (!validTargets.has(actualTarget.enumVariantName)) { + accept('error', `The annotation '${annotation.name}' cannot be applied to ${actualTarget.prettyName}.`, { + node, + property: 'annotation', + code: CODE_TARGET_WRONG_TARGET, + }); + } + }; +}; + +const getActualTarget = (node: SdsAnnotationCall): GetActualTargetResult | void => { + const annotatedObject = getAnnotationCallTarget(node); + + if (isSdsAnnotation(annotatedObject)) { + return { + enumVariantName: 'Annotation', + prettyName: 'an annotation', + }; + } else if (isSdsAttribute(annotatedObject)) { + return { + enumVariantName: 'Attribute', + prettyName: 'an attribute', + }; + } else if (isSdsClass(annotatedObject)) { + return { + enumVariantName: 'Class', + prettyName: 'a class', + }; + } else if (isSdsEnum(annotatedObject)) { + return { + enumVariantName: 'Enum', + prettyName: 'an enum', + }; + } else if (isSdsEnumVariant(annotatedObject)) { + return { + enumVariantName: 'EnumVariant', + prettyName: 'an enum variant', + }; + } else if (isSdsFunction(annotatedObject)) { + return { + enumVariantName: 'Function', + prettyName: 'a function', + }; + } else if (isSdsModule(annotatedObject)) { + return { + enumVariantName: 'Module', + prettyName: 'a module', + }; + } else if (isSdsParameter(annotatedObject)) { + return { + enumVariantName: 'Parameter', + prettyName: 'a parameter', + }; + } else if (isSdsPipeline(annotatedObject)) { + return { + enumVariantName: 'Pipeline', + prettyName: 'a pipeline', + }; + } else if (isSdsResult(annotatedObject)) { + return { + enumVariantName: 'Result', + prettyName: 'a result', + }; + } else if (isSdsSegment(annotatedObject)) { + return { + enumVariantName: 'Segment', + prettyName: 'a segment', + }; + } else if (isSdsTypeParameter(annotatedObject)) { + return { + enumVariantName: 'TypeParameter', + prettyName: 'a type parameter', + }; + } }; + +interface GetActualTargetResult { + enumVariantName: string; + prettyName: string; +} diff --git a/tests/resources/validation/builtins/annotations/target/wrong target/main.sdstest b/tests/resources/validation/builtins/annotations/target/wrong target/main.sdstest index 79e10f02a..b506ff37c 100644 --- a/tests/resources/validation/builtins/annotations/target/wrong target/main.sdstest +++ b/tests/resources/validation/builtins/annotations/target/wrong target/main.sdstest @@ -1,151 +1,172 @@ -// $TEST$ error "This annotation cannot be applied to a compilation unit." -»@AnnotationForEnums« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForCompilationUnits« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForMultipleTargets« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForAnything« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@UnresolvedAnnotation« +// $TEST$ error "The annotation 'AnnotationForEnums' cannot be applied to a module." +@»AnnotationForEnums« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForModules« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForMultipleTargets« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnything« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»Unresolved« package tests.validation.builtins.annotations.target.wrongTarget -@Target(AnnotationTarget.Annotation) +@Target([AnnotationTarget.Annotation]) annotation AnnotationForAnnotations -@Target(AnnotationTarget.Attribute) +@Target([AnnotationTarget.Attribute]) annotation AnnotationForAttributes -@Target(AnnotationTarget.Class) +@Target([AnnotationTarget.Class]) annotation AnnotationForClasses -@Target(AnnotationTarget.CompilationUnit) -annotation AnnotationForCompilationUnits - -@Target(AnnotationTarget.Enum) +@Target([AnnotationTarget.Enum]) annotation AnnotationForEnums -@Target(AnnotationTarget.EnumVariant) +@Target([AnnotationTarget.EnumVariant]) annotation AnnotationForEnumVariants -@Target(AnnotationTarget.Function) +@Target([AnnotationTarget.Function]) annotation AnnotationForFunctions -@Target(AnnotationTarget.Parameter) +@Target([AnnotationTarget.Module]) +annotation AnnotationForModules + +@Target([AnnotationTarget.Parameter]) annotation AnnotationForParameters -@Target(AnnotationTarget.Result) +@Target([AnnotationTarget.Result]) annotation AnnotationForResults -@Target(AnnotationTarget.TypeParameter) +@Target([AnnotationTarget.TypeParameter]) annotation AnnotationForTypeParameters -@Target(AnnotationTarget.Pipeline) +@Target([AnnotationTarget.Pipeline]) annotation AnnotationForPipelines -@Target(AnnotationTarget.Step) +@Target([AnnotationTarget.Segment]) annotation AnnotationForSegments -@Target(AnnotationTarget.CompilationUnit, AnnotationTarget.Class) +@Target([AnnotationTarget.Module, AnnotationTarget.Class]) annotation AnnotationForMultipleTargets annotation AnnotationForAnything /* Test declarations -------------------------------------------------------- */ -// $TEST$ error "This annotation cannot be applied to an annotation." -»@AnnotationForAttributes« -// $TEST$ no error "This annotation cannot be applied to an annotation." -»@AnnotationForAnnotations« -// $TEST$ no error "This annotation cannot be applied to an annotation." -»@AnnotationForAnything« +// $TEST$ error "The annotation 'AnnotationForAttributes' cannot be applied to an annotation." +@»AnnotationForAttributes« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnnotations« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnything« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»Unresolved« annotation TestAnnotation -// $TEST$ error "This annotation cannot be applied to a class." -»@AnnotationForCompilationUnits« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForClasses« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForMultipleTargets« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForAnything« +// $TEST$ error "The annotation 'AnnotationForModules' cannot be applied to a class." +@»AnnotationForModules« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForClasses« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForMultipleTargets« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnything« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»Unresolved« class TestClass< - // $TEST$ no error r"This annotation cannot be applied to .*" - »@AnnotationForPipelines« - // $TEST$ no error r"This annotation cannot be applied to .*" - »@AnnotationForTypeParameters« - // $TEST$ no error r"This annotation cannot be applied to .*" - »@AnnotationForAnything« + // $TEST$ error "The annotation 'AnnotationForPipelines' cannot be applied to a type parameter." + @»AnnotationForPipelines« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForTypeParameters« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForAnything« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»Unresolved« TEST_TYPE_PARAMETER > { - // $TEST$ error "This annotation cannot be applied to an attribute." - »@AnnotationForClasses« - // $TEST$ no error "This annotation cannot be applied to an attribute." - »@AnnotationForAttributes« - // $TEST$ no error "This annotation cannot be applied to an attribute." - »@AnnotationForAnything« + // $TEST$ error "The annotation 'AnnotationForClasses' cannot be applied to an attribute." + @»AnnotationForClasses« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForAttributes« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForAnything« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»Unresolved« attr testAttribute: Int } -// $TEST$ error "This annotation cannot be applied to an enum." -»@AnnotationForEnumVariants« -// $TEST$ no error "This annotation cannot be applied to an enum." -»@AnnotationForEnums« -// $TEST$ no error "This annotation cannot be applied to an enum." -»@AnnotationForAnything« +// $TEST$ error "The annotation 'AnnotationForEnumVariants' cannot be applied to an enum." +@»AnnotationForEnumVariants« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForEnums« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnything« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»Unresolved« enum TestEnum { - // $TEST$ error "This annotation cannot be applied to an enum variant." - »@AnnotationForFunctions« - // $TEST$ no error "This annotation cannot be applied to an enum variant." - »@AnnotationForEnumVariants« - // $TEST$ no error "This annotation cannot be applied to an enum variant." - »@AnnotationForAnything« + // $TEST$ error "The annotation 'AnnotationForFunctions' cannot be applied to an enum variant." + @»AnnotationForFunctions« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForEnumVariants« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForAnything« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»Unresolved« TestEnumVariant } - -// $TEST$ error "This annotation cannot be applied to a function." -»@AnnotationForParameters« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForFunctions« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForAnything« +// $TEST$ error "The annotation 'AnnotationForParameters' cannot be applied to a function." +@»AnnotationForParameters« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForFunctions« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnything« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»Unresolved« fun testFunction( - // $TEST$ error "This annotation cannot be applied to a parameter." - »@AnnotationForResults« - // $TEST$ no error r"This annotation cannot be applied to .*" - »@AnnotationForParameters« - // $TEST$ no error r"This annotation cannot be applied to .*" - »@AnnotationForAnything« + // $TEST$ error "The annotation 'AnnotationForResults' cannot be applied to a parameter." + @»AnnotationForResults« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForParameters« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForAnything« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»Unresolved« testParameter: Int ) -> ( - // $TEST$ error "This annotation cannot be applied to a result." - »@AnnotationForTypeParameters« - // $TEST$ no error r"This annotation cannot be applied to .*" - »@AnnotationForResults« - // $TEST$ no error r"This annotation cannot be applied to .*" - »@AnnotationForAnything« + // $TEST$ error "The annotation 'AnnotationForTypeParameters' cannot be applied to a result." + @»AnnotationForTypeParameters« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForResults« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»AnnotationForAnything« + // $TEST$ no error r"This annotation '.*' cannot be applied to .*" + @»Unresolved« testResult: Int ) -// $TEST$ error "This annotation cannot be applied to a pipeline." -»@AnnotationForSegments« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForPipelines« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForAnything« +// $TEST$ error "The annotation 'AnnotationForSegments' cannot be applied to a pipeline." +@»AnnotationForSegments« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForPipelines« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnything« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»Unresolved« pipeline testPipeline {} -// $TEST$ error "This annotation cannot be applied to a segment." -»@AnnotationForAnnotations« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForSegments« -// $TEST$ no error r"This annotation cannot be applied to .*" -»@AnnotationForAnything« +// $TEST$ error "The annotation 'AnnotationForAnnotations' cannot be applied to a segment." +@»AnnotationForAnnotations« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForSegments« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»AnnotationForAnything« +// $TEST$ no error r"This annotation '.*' cannot be applied to .*" +@»Unresolved« segment testSegment() {} From af383a47bc8eb8e61c927a2a5f636ea4bdd7a310 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Sun, 22 Oct 2023 18:16:28 +0200 Subject: [PATCH 5/5] test: ignore line for coverage --- src/language/validation/builtins/target.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/language/validation/builtins/target.ts b/src/language/validation/builtins/target.ts index f562efcb2..08c5f8153 100644 --- a/src/language/validation/builtins/target.ts +++ b/src/language/validation/builtins/target.ts @@ -63,9 +63,11 @@ export const annotationCallMustHaveCorrectTarget = (services: SafeDsServices) => } const actualTarget = getActualTarget(node); + /* c8 ignore start */ if (!actualTarget) { return; } + /* c8 ignore stop */ const validTargets = builtinAnnotations .streamValidTargets(annotation)