diff --git a/src/language/ast/shortcuts.ts b/src/language/ast/shortcuts.ts index 840ac6fcc..25f318313 100644 --- a/src/language/ast/shortcuts.ts +++ b/src/language/ast/shortcuts.ts @@ -63,6 +63,10 @@ export const classMembersOrEmpty = function (node: SdsClass | undefined): SdsCla return node?.body?.members ?? []; }; +export const enumVariantsOrEmpty = function (node: SdsEnum | undefined): SdsEnumVariant[] { + return node?.body?.variants ?? []; +}; + export const parametersOrEmpty = function (node: SdsParameterList | undefined): SdsParameter[] { return node?.parameters ?? []; }; @@ -90,7 +94,3 @@ export const typeArgumentsOrEmpty = function (node: SdsTypeArgumentList | undefi export const typeParametersOrEmpty = function (node: SdsTypeParameterList | undefined): SdsTypeParameter[] { return node?.typeParameters ?? []; }; - -export const variantsOrEmpty = function (node: SdsEnum | undefined): SdsEnumVariant[] { - return node?.body?.variants ?? []; -}; diff --git a/src/language/ast/utils.ts b/src/language/ast/utils.ts new file mode 100644 index 000000000..8a82b3865 --- /dev/null +++ b/src/language/ast/utils.ts @@ -0,0 +1,8 @@ +import { AstNode, hasContainerOfType } from 'langium'; + +/** + * Returns whether the inner node is contained in the outer node. If the nodes are equal, this function returns `true`. + */ +export const isContainedIn = (inner: AstNode | undefined, outer: AstNode | undefined): boolean => { + return hasContainerOfType(inner, (it) => it === outer); +}; diff --git a/src/language/grammar/safe-ds.langium b/src/language/grammar/safe-ds.langium index f96eeb57f..425197a1c 100644 --- a/src/language/grammar/safe-ds.langium +++ b/src/language/grammar/safe-ds.langium @@ -757,11 +757,11 @@ SdsString returns SdsString: ; interface SdsReference extends SdsExpression { - declaration?: @SdsDeclaration + target?: @SdsDeclaration } SdsReference returns SdsReference: - declaration=[SdsDeclaration:ID] + target=[SdsDeclaration:ID] ; interface SdsParenthesizedExpression extends SdsExpression { diff --git a/src/language/partialEvaluation/model.ts b/src/language/partialEvaluation/model.ts index 23f211d15..0dcee9084 100644 --- a/src/language/partialEvaluation/model.ts +++ b/src/language/partialEvaluation/model.ts @@ -61,7 +61,7 @@ export class SdsIntermediateRecord extends SdsIntermediateExpression { } getSubstitutionByReferenceOrNull(reference: SdsReference): SdsSimplifiedExpression | null { - const referencedDeclaration = reference.declaration; + const referencedDeclaration = reference.target; if (!isSdsAbstractResult(referencedDeclaration)) { return null; } diff --git a/src/language/scoping/safe-ds-scope-provider.ts b/src/language/scoping/safe-ds-scope-provider.ts index 418c95895..0ebf4be55 100644 --- a/src/language/scoping/safe-ds-scope-provider.ts +++ b/src/language/scoping/safe-ds-scope-provider.ts @@ -1,31 +1,59 @@ -import { DefaultScopeProvider, EMPTY_SCOPE, getContainerOfType, ReferenceInfo, Scope } from 'langium'; import { + AstNode, + DefaultScopeProvider, + EMPTY_SCOPE, + getContainerOfType, + getDocument, + ReferenceInfo, + Scope, +} from 'langium'; +import { + isSdsAssignment, + isSdsBlock, + isSdsCallable, isSdsClass, isSdsEnum, + isSdsLambda, + isSdsMemberAccess, isSdsMemberType, + isSdsModule, isSdsNamedType, isSdsNamedTypeDeclaration, + isSdsPlaceholder, + isSdsReference, isSdsSegment, + isSdsStatement, isSdsYield, + SdsMemberAccess, SdsMemberType, SdsNamedTypeDeclaration, + SdsPlaceholder, + SdsReference, + SdsStatement, SdsType, SdsYield, } from '../generated/ast.js'; -import { resultsOrEmpty } from '../ast/shortcuts.js'; +import { assigneesOrEmpty, parametersOrEmpty, resultsOrEmpty, statementsOrEmpty } from '../ast/shortcuts.js'; +import { isContainedIn } from '../ast/utils.js'; export class SafeDsScopeProvider extends DefaultScopeProvider { override getScope(context: ReferenceInfo): Scope { - if (isSdsNamedType(context.container) && context.property === 'declaration') { - const node = context.container; + const node = context.container; + if (isSdsNamedType(node) && context.property === 'declaration') { if (isSdsMemberType(node.$container) && node.$containerProperty === 'member') { return this.getScopeForMemberTypeMember(node.$container); } else { return super.getScope(context); } - } else if (isSdsYield(context.container) && context.property === 'result') { - return this.getScopeForYieldResult(context.container); + } else if (isSdsReference(node) && context.property === 'target') { + if (isSdsMemberAccess(node.$container) && node.$containerProperty === 'member') { + return this.getScopeForMemberAccessMember(node.$container); + } else { + return this.getScopeForDirectReferenceTarget(node); + } + } else if (isSdsYield(node) && context.property === 'result') { + return this.getScopeForYieldResult(node); } else { return super.getScope(context); } @@ -65,6 +93,196 @@ export class SafeDsScopeProvider extends DefaultScopeProvider { } } + private getScopeForMemberAccessMember(_node: SdsMemberAccess): Scope { + return EMPTY_SCOPE; + } + + private getScopeForDirectReferenceTarget(node: SdsReference): Scope { + // Declarations in this file + const currentScope = this.globalDeclarationsInSameFile(node, EMPTY_SCOPE); + + // Declarations in containing blocks + return this.localDeclarations(node, currentScope); + } + + private globalDeclarationsInSameFile(node: AstNode, outerScope: Scope): Scope { + const module = getContainerOfType(node, isSdsModule); + if (!module) { + /* c8 ignore next 2 */ + return outerScope; + } + + const precomputed = getDocument(module).precomputedScopes?.get(module); + if (!precomputed) { + /* c8 ignore next 2 */ + return outerScope; + } + + return this.createScope(precomputed, outerScope); + } + + private localDeclarations(node: AstNode, outerScope: Scope): Scope { + // Parameters + const containingCallable = getContainerOfType(node.$container, isSdsCallable); + const parameters = parametersOrEmpty(containingCallable?.parameterList); + + // Placeholders up to the containing statement + const containingStatement = getContainerOfType(node.$container, isSdsStatement); + + let placeholders: Iterable; + if (!containingCallable || isContainedIn(containingStatement, containingCallable)) { + placeholders = this.placeholdersUpToStatement(containingStatement); + } else { + // Placeholders are further away than the parameters + placeholders = []; + } + + // Local declarations + const localDeclarations = [...parameters, ...placeholders]; + + // Lambdas can be nested + if (isSdsLambda(containingCallable)) { + return this.createScopeForNodes(localDeclarations, this.localDeclarations(containingCallable, outerScope)); + } else { + return this.createScopeForNodes(localDeclarations, outerScope); + } + } + + private *placeholdersUpToStatement( + statement: SdsStatement | undefined, + ): Generator { + if (!statement) { + return; + } + + const containingBlock = getContainerOfType(statement, isSdsBlock); + for (const current of statementsOrEmpty(containingBlock)) { + if (current === statement) { + return; + } + + if (isSdsAssignment(current)) { + yield* assigneesOrEmpty(current).filter(isSdsPlaceholder); + } + } + } + + // private fun scopeForReferenceDeclaration(context: SdsReference): IScope { + // val resource = context.eResource() + // val packageName = context.containingCompilationUnitOrNull()?.qualifiedNameOrNull() + // + // // Declarations in other files + // var result: IScope = FilteringScope( + // super.delegateGetScope(context, SafeDSPackage.Literals.SDS_REFERENCE__DECLARATION), + // ) { + // it.isReferencableExternalDeclaration(resource, packageName) + // } + // + // // Declarations in this file + // result = declarationsInSameFile(resource, result) + // + // // Declarations in containing classes + // context.containingClassOrNull()?.let { + // result = classMembers(it, result) + // } + // + // // Declarations in containing blocks + // localDeclarations(context, result) + // } + // } + // } + // + // /** + // * Removes declarations in this [Resource], [SdsAnnotation]s, and internal [SdsStep]s located in other + // * [SdsCompilationUnit]s. + // */ + // private fun IEObjectDescription?.isReferencableExternalDeclaration( + // fromResource: Resource, + // fromPackageWithQualifiedName: QualifiedName?, + // ): Boolean { + // // Resolution failed in delegate scope + // if (this == null) return false + // + // val obj = this.eObjectOrProxy + // + // // Local declarations are added later using custom scoping rules + // if (obj.eResource() == fromResource) return false + // + // // Annotations cannot be referenced + // if (obj is SdsAnnotation) return false + // + // // Internal steps in another package cannot be referenced + // return !( + // obj is SdsStep && + // obj.visibility() == SdsVisibility.Internal && + // obj.containingCompilationUnitOrNull()?.qualifiedNameOrNull() != fromPackageWithQualifiedName + // ) + // } + // + // private fun scopeForMemberAccessDeclaration(context: SdsMemberAccess): IScope { + // val receiver = context.receiver + // + // // Static access + // val receiverDeclaration = when (receiver) { + // is SdsReference -> receiver.declaration + // is SdsMemberAccess -> receiver.member.declaration + // else -> null + // } + // if (receiverDeclaration != null) { + // when (receiverDeclaration) { + // is SdsClass -> { + // val members = receiverDeclaration.classMembersOrEmpty().filter { it.isStatic() } + // val superTypeMembers = receiverDeclaration.superClassMembers() + // .filter { it.isStatic() } + // .toList() + // + // return Scopes.scopeFor(members, Scopes.scopeFor(superTypeMembers)) + // } + // is SdsEnum -> { + // return Scopes.scopeFor(receiverDeclaration.variantsOrEmpty()) + // } + // } + // } + // + // // Call results + // var resultScope = IScope.NULLSCOPE + // if (receiver is SdsCall) { + // val results = receiver.resultsOrNull() + // when { + // results == null -> return IScope.NULLSCOPE + // results.size > 1 -> return Scopes.scopeFor(results) + // results.size == 1 -> resultScope = Scopes.scopeFor(results) + // } + // } + // + // // Members + // val type = (receiver.type() as? NamedType) ?: return resultScope + // + // return when { + // type.isNullable && !context.isNullSafe -> resultScope + // type is ClassType -> { + // val members = type.sdsClass.classMembersOrEmpty().filter { !it.isStatic() } + // val superTypeMembers = type.sdsClass.superClassMembers() + // .filter { !it.isStatic() } + // .toList() + // + // Scopes.scopeFor(members, Scopes.scopeFor(superTypeMembers, resultScope)) + // } + // type is EnumVariantType -> Scopes.scopeFor(type.sdsEnumVariant.parametersOrEmpty()) + // else -> resultScope + // } + // } + // + // private fun classMembers(context: SdsClass, parentScope: IScope): IScope { + // return when (val containingClassOrNull = context.containingClassOrNull()) { + // is SdsClass -> Scopes.scopeFor( + // context.classMembersOrEmpty(), + // classMembers(containingClassOrNull, parentScope), + // ) + // else -> Scopes.scopeFor(context.classMembersOrEmpty(), parentScope) + // } + // } + private getScopeForYieldResult(node: SdsYield): Scope { const containingSegment = getContainerOfType(node, isSdsSegment); if (!containingSegment) { diff --git a/src/language/validation/names.ts b/src/language/validation/names.ts index 1ac0f4205..1295d5153 100644 --- a/src/language/validation/names.ts +++ b/src/language/validation/names.ts @@ -19,7 +19,7 @@ import { placeholdersOrEmpty, resultsOrEmpty, typeParametersOrEmpty, - variantsOrEmpty, + enumVariantsOrEmpty, } from '../ast/shortcuts.js'; export const CODE_NAME_BLOCK_LAMBDA_PREFIX = 'name/block-lambda-prefix'; @@ -185,7 +185,7 @@ export const classMustContainUniqueNames = (node: SdsClass, accept: ValidationAc }; export const enumMustContainUniqueNames = (node: SdsEnum, accept: ValidationAcceptor): void => { - namesMustBeUnique(variantsOrEmpty(node), (name) => `A variant with name '${name}' exists already.`, accept); + namesMustBeUnique(enumVariantsOrEmpty(node), (name) => `A variant with name '${name}' exists already.`, accept); }; export const enumVariantMustContainUniqueNames = (node: SdsEnumVariant, accept: ValidationAcceptor): void => { diff --git a/src/language/validation/other/expressions/references.ts b/src/language/validation/other/expressions/references.ts new file mode 100644 index 000000000..1bb04dd27 --- /dev/null +++ b/src/language/validation/other/expressions/references.ts @@ -0,0 +1,28 @@ +import { isSdsAnnotation, isSdsPipeline, isSdsSchema, SdsReference } from '../../../generated/ast.js'; +import { ValidationAcceptor } from 'langium'; + +export const CODE_REFERENCE_TARGET = 'reference/target'; + +export const referenceTargetMustNotBeAnnotationPipelineOrSchema = ( + node: SdsReference, + accept: ValidationAcceptor, +): void => { + const target = node.target?.ref; + + if (isSdsAnnotation(target)) { + accept('error', 'An annotation must not be the target of a reference.', { + node, + code: CODE_REFERENCE_TARGET, + }); + } else if (isSdsPipeline(target)) { + accept('error', 'A pipeline must not be the target of a reference.', { + node, + code: CODE_REFERENCE_TARGET, + }); + } else if (isSdsSchema(target)) { + accept('error', 'A schema must not be the target of a reference.', { + node, + code: CODE_REFERENCE_TARGET, + }); + } +}; diff --git a/src/language/validation/safe-ds-validator.ts b/src/language/validation/safe-ds-validator.ts index f71886c6c..3297075e2 100644 --- a/src/language/validation/safe-ds-validator.ts +++ b/src/language/validation/safe-ds-validator.ts @@ -43,6 +43,7 @@ import { callableTypeMustNotHaveOptionalParameters } from './other/types/callabl import { typeArgumentListMustNotHavePositionalArgumentsAfterNamedArguments } from './other/types/typeArgumentLists.js'; import { argumentListMustNotHavePositionalArgumentsAfterNamedArguments } from './other/argumentLists.js'; import { parameterMustNotBeVariadicAndOptional } from './other/declarations/parameters.js'; +import { referenceTargetMustNotBeAnnotationPipelineOrSchema } from './other/expressions/references.js'; /** * Register custom validation checks. @@ -75,6 +76,7 @@ export const registerValidationChecks = function (services: SafeDsServices) { parameterListVariadicParameterMustBeLast, ], SdsPipeline: [pipelineMustContainUniqueNames], + SdsReference: [referenceTargetMustNotBeAnnotationPipelineOrSchema], SdsResult: [resultMustHaveTypeHint], SdsSegment: [segmentMustContainUniqueNames, segmentResultListShouldNotBeEmpty], SdsTemplateString: [templateStringMustHaveExpressionBetweenTwoStringParts], diff --git a/tests/helpers/location.ts b/tests/helpers/location.ts index 2300bcbc2..ef18fc5ed 100644 --- a/tests/helpers/location.ts +++ b/tests/helpers/location.ts @@ -73,7 +73,7 @@ export const getNodeByLocation = (services: SafeDsServices, location: Location): }); } - for (const node of streamAllContents(root)) { + for (const node of streamAllContents(root, { range: location.range })) { // Entire node matches the range const actualRange = node.$cstNode?.range; if (actualRange && isRangeEqual(actualRange, location.range)) { diff --git a/tests/resources/partial evaluation/base cases/string literal (with interpolation)/main.sdstest b/tests/resources/partial evaluation/simple recursive cases/template string/main.sdstest similarity index 83% rename from tests/resources/partial evaluation/base cases/string literal (with interpolation)/main.sdstest rename to tests/resources/partial evaluation/simple recursive cases/template string/main.sdstest index c3ae42683..421f84124 100644 --- a/tests/resources/partial evaluation/base cases/string literal (with interpolation)/main.sdstest +++ b/tests/resources/partial evaluation/simple recursive cases/template string/main.sdstest @@ -1,4 +1,4 @@ -package tests.partialValidation.baseCases.stringLiteralWithInterpolation +package tests.partialValidation.simpleRecursiveCases.templateString pipeline test { // $TEST$ constant serialization "start 1 inner1 true inner2 test end" diff --git a/tests/resources/scoping/references/direct/to annotations/main.sdstest b/tests/resources/scoping/references/direct/to annotations/main.sdstest new file mode 100644 index 000000000..2a84b526a --- /dev/null +++ b/tests/resources/scoping/references/direct/to annotations/main.sdstest @@ -0,0 +1,15 @@ +package tests.scoping.references.direct.toAnnotations + +// $TEST$ target before +annotation »Before« + +segment mySegment() { + // $TEST$ references before + »Before«; + + // $TEST$ references after + »After«; +} + +// $TEST$ target after +annotation »After« diff --git a/tests/resources/scoping/references/direct/to block lambda results/from outside/main.sdstest b/tests/resources/scoping/references/direct/to block lambda results/from outside/main.sdstest new file mode 100644 index 000000000..bd29bbb5e --- /dev/null +++ b/tests/resources/scoping/references/direct/to block lambda results/from outside/main.sdstest @@ -0,0 +1,10 @@ +package test.scoping.references.direct.toBlockLambdaResults.fromOutside + +pipeline myPipeline { + () { + yield myBlockLambdaResult = 1; + }; + + // $TEST$ unresolved + »myBlockLambdaResult«; +} diff --git a/tests/resources/scoping/references/direct/to block lambda results/of containing block lambda/main.sdstest b/tests/resources/scoping/references/direct/to block lambda results/of containing block lambda/main.sdstest new file mode 100644 index 000000000..04943a836 --- /dev/null +++ b/tests/resources/scoping/references/direct/to block lambda results/of containing block lambda/main.sdstest @@ -0,0 +1,9 @@ +package tests.scoping.references.direct.toBlockLambdaResults.ofContainingBlockLambda + +pipeline myPipeline { + () { + yield lambdaResult = 1; + // $TEST$ unresolved + »lambdaResult«; + }; +} diff --git a/tests/resources/scoping/references/direct/to class members/main.sdstest b/tests/resources/scoping/references/direct/to class members/main.sdstest new file mode 100644 index 000000000..9cc185a1a --- /dev/null +++ b/tests/resources/scoping/references/direct/to class members/main.sdstest @@ -0,0 +1,33 @@ +package test.scoping.references.direct.toClassMembers + +class MyClass { + static attr staticAttribute: Int + attr instanceAttribute: Int + + class NestedClass + + enum NestedEnum + + static fun staticMethod() + fun instanceMethod() +} + +pipeline myPipeline { + // $TEST$ unresolved + »staticAttribute«; + + // $TEST$ unresolved + »instanceAttribute«; + + // $TEST$ unresolved + »NestedClass«; + + // $TEST$ unresolved + »NestedEnum«; + + // $TEST$ unresolved + »staticMethod«; + + // $TEST$ unresolved + »instanceMethod«; +} diff --git a/tests/resources/scoping/references/direct/to enum variants/main.sdstest b/tests/resources/scoping/references/direct/to enum variants/main.sdstest new file mode 100644 index 000000000..ca0a54d2e --- /dev/null +++ b/tests/resources/scoping/references/direct/to enum variants/main.sdstest @@ -0,0 +1,10 @@ +package test.scoping.references.direct.toEnumVariants + +enum MyEnum { + MyEnumVariant +} + +pipeline myPipeline { + // $TEST$ unresolved + »MyEnumVariant«; +} diff --git a/tests/resources/scoping/references/direct/to global classes/main.sdstest b/tests/resources/scoping/references/direct/to global classes/main.sdstest new file mode 100644 index 000000000..03d62b0a0 --- /dev/null +++ b/tests/resources/scoping/references/direct/to global classes/main.sdstest @@ -0,0 +1,15 @@ +package test.scoping.references.direct.toGlobalClasses + +// $TEST$ target before +class »Before«() + +pipeline myPipeline { + // $TEST$ references before + »Before«; + + // $TEST$ references after + »After«; +} + +// $TEST$ target after +class »After«() diff --git a/tests/resources/scoping/references/direct/to global enums/main.sdstest b/tests/resources/scoping/references/direct/to global enums/main.sdstest new file mode 100644 index 000000000..c627bd5a8 --- /dev/null +++ b/tests/resources/scoping/references/direct/to global enums/main.sdstest @@ -0,0 +1,15 @@ +package test.scoping.references.direct.toGlobalEnums + +// $TEST$ target before +enum »Before« + +pipeline myPipeline { + // $TEST$ references before + »Before«(); + + // $TEST$ references after + »After«(); +} + +// $TEST$ target after +enum »After« diff --git a/tests/resources/scoping/references/direct/to global functions/main.sdstest b/tests/resources/scoping/references/direct/to global functions/main.sdstest new file mode 100644 index 000000000..412f0f6d1 --- /dev/null +++ b/tests/resources/scoping/references/direct/to global functions/main.sdstest @@ -0,0 +1,15 @@ +package test.scoping.references.direct.toGlobalFunctions + +// $TEST$ target before +fun »before«() + +pipeline myPipeline { + // $TEST$ references before + »before«(); + + // $TEST$ references after + »after«(); +} + +// $TEST$ target after +fun »after«() diff --git a/tests/resources/scoping/references/direct/to parameters/from outside/main.sdstest b/tests/resources/scoping/references/direct/to parameters/from outside/main.sdstest new file mode 100644 index 000000000..e925c55e2 --- /dev/null +++ b/tests/resources/scoping/references/direct/to parameters/from outside/main.sdstest @@ -0,0 +1,44 @@ +package test.scoping.references.direct.toParameters.fromOutside + +annotation MyAnnotation(myAnnotationParameter: String) + +class MyClass(myClassParameter: String) + +enum MyEnum { + MyEnumVariant(myEnumVariantParameter: String) +} + +fun myFunction(myFunctionParameter: String) + +segment mySegment1(mySegmentParameter: String) {} + +segment mySegment2( + p: (myCallableTypeParameter: String) -> () +) { + (myBlockLambdaParameter) {}; + (myExpressionLambdaParameter) -> 1; + + // $TEST$ unresolved + »myAnnotationParameter«; + + // $TEST$ unresolved + »myClassParameter«; + + // $TEST$ unresolved + »myEnumVariantParameter«; + + // $TEST$ unresolved + »myFunctionParameter«; + + // $TEST$ unresolved + »mySegmentParameter«; + + // $TEST$ unresolved + »myCallableTypeParameter«; + + // $TEST$ unresolved + »myBlockLambdaParameter«; + + // $TEST$ unresolved + »myExpressionLambdaParameter«; +} diff --git a/tests/resources/scoping/references/direct/to parameters/of containing block lambda/main.sdstest b/tests/resources/scoping/references/direct/to parameters/of containing block lambda/main.sdstest new file mode 100644 index 000000000..b3e01b85b --- /dev/null +++ b/tests/resources/scoping/references/direct/to parameters/of containing block lambda/main.sdstest @@ -0,0 +1,80 @@ +package test.scoping.references.direct.toParameters.ofContainingBlockLambda + +segment mySegment(myShadowedSegmentParameter: Int) { + val myShadowedPlaceholder = 0; + + ( + // $TEST$ target outer_myOuterBlockLambdaParameter + »myOuterBlockLambdaParameter«, + + // $TEST$ target outer_myShadowedSegmentParameter + »myShadowedSegmentParameter«, + + // $TEST$ target outer_myShadowedBlockLambdaParameter + »myShadowedBlockLambdaParameter«, + + // $TEST$ target outer_myShadowedPlaceholder + »myShadowedPlaceholder«, + + // $TEST$ target redeclaredAsParameter + »redeclaredAsParameter«, + redeclaredAsParameter, + + // $TEST$ target redeclaredAsPlaceholder + »redeclaredAsPlaceholder«, + ) { + val redeclaredAsPlaceholder = 0; + + // $TEST$ references outer_myOuterBlockLambdaParameter + »myOuterBlockLambdaParameter«; + + // $TEST$ references outer_myShadowedSegmentParameter + »myShadowedSegmentParameter«; + + // $TEST$ references outer_myShadowedBlockLambdaParameter + »myShadowedBlockLambdaParameter«; + + // $TEST$ references outer_myShadowedPlaceholder + »myShadowedPlaceholder«; + + // $TEST$ references redeclaredAsParameter + »redeclaredAsParameter«; + + // $TEST$ references redeclaredAsPlaceholder + »redeclaredAsPlaceholder«; + + // $TEST$ unresolved + »myInnerBlockLambdaParameter«; + + ( + // $TEST$ target inner_myInnerBlockLambdaParameter + »myInnerBlockLambdaParameter«, + + // $TEST$ target inner_myShadowedBlockLambdaParameter + »myShadowedBlockLambdaParameter« + ) { + () -> + // $TEST$ references outer_myOuterBlockLambdaParameter + »myOuterBlockLambdaParameter« + + + // $TEST$ references outer_myShadowedSegmentParameter + »myShadowedSegmentParameter« + + + // $TEST$ references inner_myShadowedBlockLambdaParameter + »myShadowedBlockLambdaParameter«; + + // $TEST$ references outer_myShadowedPlaceholder + »myShadowedPlaceholder« + + + // $TEST$ references redeclaredAsParameter + »redeclaredAsParameter« + + + // $TEST$ references redeclaredAsPlaceholder + »redeclaredAsPlaceholder« + + + // $TEST$ references inner_myInnerBlockLambdaParameter + »myInnerBlockLambdaParameter«; + + }; + }; +} diff --git a/tests/resources/scoping/references/direct/to parameters/of containing expression lambda/main.sdstest b/tests/resources/scoping/references/direct/to parameters/of containing expression lambda/main.sdstest new file mode 100644 index 000000000..d5ac1180f --- /dev/null +++ b/tests/resources/scoping/references/direct/to parameters/of containing expression lambda/main.sdstest @@ -0,0 +1,69 @@ +package test.scoping.references.direct.toParameters.ofContainingExpressionLambda + +segment mySegment(myShadowedSegmentParameter: Int) { + val myShadowedPlaceholder = 0; + + ( + // $TEST$ target outer_myOuterExpressionLambdaParameter + »myOuterExpressionLambdaParameter«, + + // $TEST$ target outer_myShadowedSegmentParameter + »myShadowedSegmentParameter«, + + // $TEST$ target outer_myShadowedExpressionLambdaParameter + »myShadowedExpressionLambdaParameter«, + + // $TEST$ target outer_myShadowedPlaceholder + »myShadowedPlaceholder«, + + // $TEST$ target outer_redeclaredAsParameter + »redeclaredAsParameter«, + redeclaredAsParameter + ) -> + // $TEST$ references outer_myOuterExpressionLambdaParameter + »myOuterExpressionLambdaParameter« + + + // $TEST$ references outer_myShadowedSegmentParameter + »myShadowedSegmentParameter« + + + // $TEST$ references outer_myShadowedPlaceholder + »myShadowedPlaceholder« + + + // $TEST$ references outer_redeclaredAsParameter + »redeclaredAsParameter« + + + // $TEST$ unresolved + »myInnerExpressionLambdaParameter« + + + // $TEST$ references outer_myShadowedExpressionLambdaParameter + »myShadowedExpressionLambdaParameter« + + + (( + // $TEST$ target inner_myInnerExpressionLambdaParameter + »myInnerExpressionLambdaParameter«, + + // $TEST$ target inner_myShadowedExpressionLambdaParameter + »myShadowedExpressionLambdaParameter«, + ) -> + () { + // $TEST$ references outer_myOuterExpressionLambdaParameter + »myOuterExpressionLambdaParameter«; + + // $TEST$ references outer_myShadowedSegmentParameter + »myShadowedSegmentParameter«; + + // $TEST$ references outer_myShadowedPlaceholder + »myShadowedPlaceholder«; + + // $TEST$ references outer_redeclaredAsParameter + »redeclaredAsParameter«; + + // $TEST$ references inner_myInnerExpressionLambdaParameter + »myInnerExpressionLambdaParameter«; + + // $TEST$ references inner_myShadowedExpressionLambdaParameter + »myShadowedExpressionLambdaParameter«; + } + ) + ; +} diff --git a/tests/resources/scoping/references/direct/to parameters/of containing segment/main.sdstest b/tests/resources/scoping/references/direct/to parameters/of containing segment/main.sdstest new file mode 100644 index 000000000..71039c787 --- /dev/null +++ b/tests/resources/scoping/references/direct/to parameters/of containing segment/main.sdstest @@ -0,0 +1,45 @@ +package test.scoping.references.direct.toParameters.ofContainingExpressionLambda + +segment mySegment( + // $TEST$ target parameter + »myParameter«: Int, + + // $TEST$ target redeclaredAsParameter + »redeclaredAsParameter«: Int, + redeclaredAsParameter: Int, + + // $TEST$ target redeclaredAsPlaceholder + »redeclaredAsPlaceholder«: Int +) { + val redeclaredAsPlaceholder = 0; + + // $TEST$ references parameter + »myParameter«; + + // $TEST$ references redeclaredAsParameter + »redeclaredAsParameter«; + + // $TEST$ references redeclaredAsPlaceholder + »redeclaredAsPlaceholder«; + + () { + // $TEST$ references parameter + »myParameter«; + + // $TEST$ references redeclaredAsParameter + »redeclaredAsParameter«; + + // $TEST$ references redeclaredAsPlaceholder + »redeclaredAsPlaceholder«; + }; + + () -> + // $TEST$ references parameter + »myParameter« + + + // $TEST$ references redeclaredAsParameter + »redeclaredAsParameter« + + + // $TEST$ references redeclaredAsPlaceholder + »redeclaredAsPlaceholder«; +} diff --git a/tests/resources/scoping/references/direct/to pipelines/main.sdstest b/tests/resources/scoping/references/direct/to pipelines/main.sdstest new file mode 100644 index 000000000..3c900d1d1 --- /dev/null +++ b/tests/resources/scoping/references/direct/to pipelines/main.sdstest @@ -0,0 +1,15 @@ +package tests.scoping.references.direct.toPipelines + +// $TEST$ target before +pipeline »before« {} + +segment mySegment() { + // $TEST$ references before + »before«; + + // $TEST$ references after + »after«; +} + +// $TEST$ target after +pipeline »after« {} diff --git a/tests/resources/scoping/references/direct/to placeholders/from outside/main.sdstest b/tests/resources/scoping/references/direct/to placeholders/from outside/main.sdstest new file mode 100644 index 000000000..334bf8704 --- /dev/null +++ b/tests/resources/scoping/references/direct/to placeholders/from outside/main.sdstest @@ -0,0 +1,24 @@ +package test.scoping.references.direct.toPlaceholders.fromOutside + +pipeline myPipeline1 { + val pipelinePlaceholder = 1; +} + +segment mySegment(mySegmentParameter: String) { + val segmentPlaceholder = 1; +} + +pipeline myPipeline2 { + () { + val blockLambdaPlaceholder = 1; + }; + + // $TEST$ unresolved + »pipelinePlaceholder«; + + // $TEST$ unresolved + »segmentPlaceholder«; + + // $TEST$ unresolved + »blockLambdaPlaceholder«; +} diff --git a/tests/resources/scoping/references/direct/to placeholders/of containing block lambda/main.sdstest b/tests/resources/scoping/references/direct/to placeholders/of containing block lambda/main.sdstest new file mode 100644 index 000000000..53311ab8f --- /dev/null +++ b/tests/resources/scoping/references/direct/to placeholders/of containing block lambda/main.sdstest @@ -0,0 +1,129 @@ +package test.scoping.references.direct.toPlaceholders.ofContainingBlockLambda + +segment mySegment(mySegmentParameter: Int) { + val mySegmentPlaceholder = 0; + + (myOuterBlockLambdaParameter) { + // $TEST$ target outer_mySegmentParameter + val »mySegmentParameter« = 0; + + // $TEST$ target outer_mySegmentPlaceholder + val »mySegmentPlaceholder« = 0; + + // $TEST$ target outer_myOuterBlockLambdaPlaceholderBefore + val »myOuterBlockLambdaPlaceholderBefore« = 0; + + // $TEST$ target outer_redeclared + val »redeclared« = 0; + val redeclared = 0; + + + // $TEST$ references outer_mySegmentParameter + »mySegmentParameter«; + + // $TEST$ references outer_mySegmentPlaceholder + »mySegmentPlaceholder«; + + // $TEST$ references outer_myOuterBlockLambdaPlaceholderBefore + »myOuterBlockLambdaPlaceholderBefore«; + + // $TEST$ references outer_redeclared + »redeclared«; + + // $TEST$ unresolved + »myOuterBlockLambdaPlaceholderAfter«; + + val blockLambda = () { + // $TEST$ target inner_mySegmentParameter + val »mySegmentParameter« = 0; + + // $TEST$ target inner_mySegmentPlaceholder + val »mySegmentPlaceholder« = 0; + + // $TEST$ target inner_myOuterBlockLambdaParameter + val »myOuterBlockLambdaParameter« = 0; + + // $TEST$ target inner_myOuterBlockLambdaPlaceholderBefore + val »myOuterBlockLambdaPlaceholderBefore« = 0; + + + // $TEST$ references inner_mySegmentParameter + »mySegmentParameter«; + + // $TEST$ references inner_mySegmentPlaceholder + »mySegmentPlaceholder«; + + // $TEST$ references inner_myOuterBlockLambdaParameter + »myOuterBlockLambdaParameter«; + + // $TEST$ references inner_myOuterBlockLambdaPlaceholderBefore + »myOuterBlockLambdaPlaceholderBefore«; + + // $TEST$ references outer_redeclared + »redeclared«; + + // $TEST$ unresolved + »blockLambda«; + + // $TEST$ unresolved + »myOuterBlockLambdaPlaceholderAfter«; + + val expressionLambda = () -> + // $TEST$ references inner_mySegmentParameter + »mySegmentParameter« + + + // $TEST$ references inner_mySegmentPlaceholder + »mySegmentPlaceholder« + + + // $TEST$ references inner_myOuterBlockLambdaParameter + »myOuterBlockLambdaParameter« + + + // $TEST$ references inner_myOuterBlockLambdaPlaceholderBefore + »myOuterBlockLambdaPlaceholderBefore« + + + // $TEST$ references outer_redeclared + »redeclared« + + + // $TEST$ unresolved + »blockLambda« + + + // $TEST$ unresolved + »expressionLambda« + + + // $TEST$ unresolved + »myOuterBlockLambdaPlaceholderAfter«; + }; + + () -> () { + // $TEST$ target blockLambdaInExpressionLambda_mySegmentParameter + val »mySegmentParameter« = 0; + + // $TEST$ target blockLambdaInExpressionLambda_mySegmentPlaceholder + val »mySegmentPlaceholder« = 0; + + // $TEST$ target blockLambdaInExpressionLambda_myOuterBlockLambdaParameter + val »myOuterBlockLambdaParameter« = 0; + + // $TEST$ target blockLambdaInExpressionLambda_myOuterBlockLambdaPlaceholderBefore + val »myOuterBlockLambdaPlaceholderBefore« = 0; + + + // $TEST$ references blockLambdaInExpressionLambda_mySegmentParameter + »mySegmentParameter«; + + // $TEST$ references blockLambdaInExpressionLambda_mySegmentPlaceholder + »mySegmentPlaceholder«; + + // $TEST$ references blockLambdaInExpressionLambda_myOuterBlockLambdaPlaceholderBefore + »myOuterBlockLambdaPlaceholderBefore«; + + // $TEST$ references outer_redeclared + »redeclared«; + + // $TEST$ unresolved + »myOuterBlockLambdaPlaceholderAfter«; + }; + + val myOuterBlockLambdaPlaceholderAfter = 0; + }; +} diff --git a/tests/resources/scoping/references/direct/to placeholders/of containing pipeline/main.sdstest b/tests/resources/scoping/references/direct/to placeholders/of containing pipeline/main.sdstest new file mode 100644 index 000000000..96899d56b --- /dev/null +++ b/tests/resources/scoping/references/direct/to placeholders/of containing pipeline/main.sdstest @@ -0,0 +1,62 @@ +package test.scoping.references.direct.toPlaceholders.ofContainingPipeline + +pipeline myPipeline { + // $TEST$ target before + val »before« = 0; + + // $TEST$ target redeclared + val »redeclared« = 0; + val redeclared = 0; + + // $TEST$ references before + »before«; + + // $TEST$ references redeclared + »redeclared«; + + // $TEST$ unresolved + »after«; + + val blockLambda = () { + // $TEST$ references before + »before«; + + // $TEST$ references redeclared + »redeclared«; + + // $TEST$ unresolved + »blockLambda«; + + // $TEST$ unresolved + »after«; + + () { + // $TEST$ references before + »before«; + + // $TEST$ references redeclared + »redeclared«; + + // $TEST$ unresolved + »blockLambda«; + + // $TEST$ unresolved + »after«; + }; + }; + + val expressionLambda = () -> + // $TEST$ references before + »before« + + + // $TEST$ references redeclared + »redeclared« + + + // $TEST$ unresolved + »expressionLambda« + + + // $TEST$ unresolved + »after«; + + val after = 1; +} diff --git a/tests/resources/scoping/references/direct/to placeholders/of containing segment/main.sdstest b/tests/resources/scoping/references/direct/to placeholders/of containing segment/main.sdstest new file mode 100644 index 000000000..82e1ce365 --- /dev/null +++ b/tests/resources/scoping/references/direct/to placeholders/of containing segment/main.sdstest @@ -0,0 +1,62 @@ +package test.scoping.references.direct.toPlaceholders.ofContainingSegment + +segment mySegment() { + // $TEST$ target before + val »before« = 0; + + // $TEST$ target redeclared + val »redeclared« = 0; + val redeclared = 0; + + // $TEST$ references before + »before«; + + // $TEST$ references redeclared + »redeclared«; + + // $TEST$ unresolved + »after«; + + val blockLambda = () { + // $TEST$ references before + »before«; + + // $TEST$ references redeclared + »redeclared«; + + // $TEST$ unresolved + »blockLambda«; + + // $TEST$ unresolved + »after«; + + () { + // $TEST$ references before + »before«; + + // $TEST$ references redeclared + »redeclared«; + + // $TEST$ unresolved + »blockLambda«; + + // $TEST$ unresolved + »after«; + }; + }; + + val expressionLambda = () -> + // $TEST$ references before + »before« + + + // $TEST$ references redeclared + »redeclared« + + + // $TEST$ unresolved + »expressionLambda« + + + // $TEST$ unresolved + »after«; + + val after = 1; +} diff --git a/tests/resources/scoping/references/direct/to redeclared module member/main.sdstest b/tests/resources/scoping/references/direct/to redeclared module member/main.sdstest new file mode 100644 index 000000000..e9c37ae45 --- /dev/null +++ b/tests/resources/scoping/references/direct/to redeclared module member/main.sdstest @@ -0,0 +1,19 @@ +package tests.scoping.references.direct.toRedeclaredModuleMember + +// $TEST$ target before +class »Before« + +class Before + +segment mySegment() { + // $TEST$ references before + »Before«; + + // $TEST$ references after + »after«; +} + +// $TEST$ target after +fun »after«() + +fun after() diff --git a/tests/resources/scoping/references/direct/to results/from outside/main.sdstest b/tests/resources/scoping/references/direct/to results/from outside/main.sdstest new file mode 100644 index 000000000..55c1927f8 --- /dev/null +++ b/tests/resources/scoping/references/direct/to results/from outside/main.sdstest @@ -0,0 +1,18 @@ +package test.scoping.references.direct.toResults.fromOutside + +fun myFunction() -> (myFunctionResult: String) + +segment mySegment1() -> (mySegmentResult: String) {} + +segment mySegment2( + p: () -> (myCallableTypeResult: String) +) { + // $TEST$ unresolved + »myFunctionResult«; + + // $TEST$ unresolved + »mySegmentResult«; + + // $TEST$ unresolved + »myCallableTypeResult«; +} diff --git a/tests/resources/scoping/references/direct/to results/of containing segment/main.sdstest b/tests/resources/scoping/references/direct/to results/of containing segment/main.sdstest new file mode 100644 index 000000000..14fdb2bd9 --- /dev/null +++ b/tests/resources/scoping/references/direct/to results/of containing segment/main.sdstest @@ -0,0 +1,6 @@ +package tests.scoping.references.direct.toResults.ofContainingSegment + +segment mySegment() -> myResult: Int { + // $TEST$ unresolved + »myResult«; +} diff --git a/tests/resources/scoping/references/direct/to schemas/main.sdstest b/tests/resources/scoping/references/direct/to schemas/main.sdstest new file mode 100644 index 000000000..440b03af1 --- /dev/null +++ b/tests/resources/scoping/references/direct/to schemas/main.sdstest @@ -0,0 +1,15 @@ +package tests.scoping.references.direct.toSchemas + +// $TEST$ target before +schema »Before« {} + +segment mySegment() { + // $TEST$ references before + »Before«; + + // $TEST$ references after + »After«; +} + +// $TEST$ target after +schema »After« {} diff --git a/tests/resources/scoping/references/direct/to segments/main.sdstest b/tests/resources/scoping/references/direct/to segments/main.sdstest new file mode 100644 index 000000000..f27c97bfc --- /dev/null +++ b/tests/resources/scoping/references/direct/to segments/main.sdstest @@ -0,0 +1,32 @@ +package test.scoping.references.direct.toSegments + +// $TEST$ target privateBefore +private segment »privateBefore«() {} +// $TEST$ target internalBefore +internal segment »internalBefore«() {} +// $TEST$ target publicBefore +segment »publicBefore«() {} + +pipeline myPipeline { + // $TEST$ references privateBefore + »privateBefore«(); + + // $TEST$ references internalBefore + »internalBefore«(); + + // $TEST$ references publicBefore + »publicBefore«(); + + // $TEST$ references privateAfter + »privateAfter«(); + + // $TEST$ references internalAfter + »internalAfter«(); +} + +// $TEST$ target privateAfter +private segment »privateAfter«() {} +// $TEST$ target internalAfter +internal segment »internalAfter«() {} +// $TEST$ target publicAfter +segment »publicAfter«() {} diff --git a/tests/resources/scoping/references/direct/to type parameters/main.sdstest b/tests/resources/scoping/references/direct/to type parameters/main.sdstest new file mode 100644 index 000000000..97b7997b2 --- /dev/null +++ b/tests/resources/scoping/references/direct/to type parameters/main.sdstest @@ -0,0 +1,8 @@ +package test.scoping.references.direct.toTypeParameters + +class MyClass() + +pipeline myPipeline { + // $TEST$ unresolved + »T«; +} diff --git a/tests/resources/scoping/references/direct/unresolved/main.sdstest b/tests/resources/scoping/references/direct/unresolved/main.sdstest new file mode 100644 index 000000000..14c213971 --- /dev/null +++ b/tests/resources/scoping/references/direct/unresolved/main.sdstest @@ -0,0 +1,6 @@ +package tests.scoping.references.direct.unresolved + +segment mySegment() { + // $TEST$ unresolved + »unresolved«; +} diff --git a/tests/resources/scoping/references/skip-main.sdstest b/tests/resources/scoping/references/skip-main.sdstest new file mode 100644 index 000000000..4538a0c61 --- /dev/null +++ b/tests/resources/scoping/references/skip-main.sdstest @@ -0,0 +1,842 @@ +package tests.scoping.references + +import tests.languageTests.scoping.reference2.AnnotationInOtherPackage1 +import tests.languageTests.scoping.reference2.ClassInOtherPackage1 +import tests.languageTests.scoping.reference2.EnumInOtherPackage1 +import tests.languageTests.scoping.reference2.globalFunctionInOtherPackage1 +import tests.languageTests.scoping.reference2.internalStepInOtherPackage +import tests.languageTests.scoping.reference2.privateStepInOtherPackage +import tests.languageTests.scoping.reference2.stepInOtherPackage1 +import tests.languageTests.scoping.reference2.pipelineInOtherPackage1 + +/* +inner class Reference { + + @Nested + inner class MemberAccess { + + @Test + fun `should resolve static class attribute accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToClassMembers") + val classStaticAttributeInSameFile = + findUniqueDeclarationOrFail("classStaticAttributeInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(classStaticAttributeInSameFile) + } + + @Test + fun `should resolve instance class attribute accessed from class instance`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToClassMembers") + val classInstanceAttributeInSameFile = + findUniqueDeclarationOrFail("classInstanceAttributeInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[3].declaration + declaration.shouldBeResolved() + declaration.shouldBe(classInstanceAttributeInSameFile) + } + + @Test + fun `should resolve nested class accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToClassMembers") + val classInClassInSameFile = + findUniqueDeclarationOrFail("ClassInClassInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[5].declaration + declaration.shouldBeResolved() + declaration.shouldBe(classInClassInSameFile) + } + + @Test + fun `should resolve nested enum accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToClassMembers") + val enumInClassInSameFile = + findUniqueDeclarationOrFail("EnumInClassInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[7].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumInClassInSameFile) + } + + @Test + fun `should resolve static class method accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToClassMembers") + val classStaticMethodInSameFile = + findUniqueDeclarationOrFail("classStaticMethodInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[9].declaration + declaration.shouldBeResolved() + declaration.shouldBe(classStaticMethodInSameFile) + } + + @Test + fun `should resolve instance class method accessed from class instance`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToClassMembers") + val classInstanceMethodInSameFile = + findUniqueDeclarationOrFail("classInstanceMethodInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[11].declaration + declaration.shouldBeResolved() + declaration.shouldBe(classInstanceMethodInSameFile) + } + + @Test + fun `should resolve enum variants`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToEnumVariants") + val enumVariantInSameFile = + findUniqueDeclarationOrFail("EnumVariantInSameFile") + + val references = step.body.descendants().toList() + references.shouldHaveSize(2) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumVariantInSameFile) + } + + @Test + fun `should resolve enum variants from step annotation`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToEnumVariants") + val enumVariantInSameFile = + findUniqueDeclarationOrFail("EnumVariantInSameFile") + + val annotations = step.annotationCallsOrEmpty() + annotations.shouldHaveSize(1) + + val references = annotations[0].descendants().toList() + references.shouldHaveSize(2) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumVariantInSameFile) + } + + @Test + fun `should resolve enum variants from parameter annotation`() = withResource(REFERENCE) { + val parameter = + findUniqueDeclarationOrFail("referenceToEnumVariantFromParameterAnnotation") + val enumVariantInSameFile = + findUniqueDeclarationOrFail("EnumVariantInSameFile") + + val annotations = parameter.annotationCallsOrEmpty() + annotations.shouldHaveSize(1) + + val references = annotations[0].descendants().toList() + references.shouldHaveSize(2) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumVariantInSameFile) + } + + @Test + fun `should resolve enum variants of nested enum from class annotation`() = withResource(REFERENCE) { + val parameter = findUniqueDeclarationOrFail("ReferencesToEnumVariantsInnerClass") + val enumVariantInSameFile = + findUniqueDeclarationOrFail("EnumVariantInSameClass") + + val annotations = parameter.annotationCallsOrEmpty() + annotations.shouldHaveSize(2) + + val references = annotations[0].descendants().toList() + references.shouldHaveSize(2) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumVariantInSameFile) + } + + @Test + fun `should resolve enum variants of global enum from class annotation`() = withResource(REFERENCE) { + val parameter = findUniqueDeclarationOrFail("ReferencesToEnumVariantsInnerClass") + val enumVariantInSameClass = + findUniqueDeclarationOrFail("EnumVariantInSameFile") + + val annotations = parameter.annotationCallsOrEmpty() + annotations.shouldHaveSize(2) + + val references = annotations[1].descendants().toList() + references.shouldHaveSize(2) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumVariantInSameClass) + } + + @Test + fun `should resolve parameters of enum variants`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToEnumVariantParameters") + val enumVariantParameterInSameFile = + findUniqueDeclarationOrFail("enumVariantParameterInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(3) + + val declaration = references[2].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumVariantParameterInSameFile) + } + + @Test + fun `should resolve inherited static class attribute accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToInheritedClassMembers") + val superClassStaticAttribute = + findUniqueDeclarationOrFail("superClassStaticAttribute") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(superClassStaticAttribute) + } + + @Test + fun `should resolve inherited instance class attribute accessed from class instance`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToInheritedClassMembers") + val superClassInstanceAttribute = + findUniqueDeclarationOrFail("superClassInstanceAttribute") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[3].declaration + declaration.shouldBeResolved() + declaration.shouldBe(superClassInstanceAttribute) + } + + @Test + fun `should resolve inherited nested class accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToInheritedClassMembers") + val classInSuperClass = + findUniqueDeclarationOrFail("ClassInSuperClass") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[5].declaration + declaration.shouldBeResolved() + declaration.shouldBe(classInSuperClass) + } + + @Test + fun `should resolve inherited nested enum accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToInheritedClassMembers") + val enumInSuperClass = + findUniqueDeclarationOrFail("EnumInSuperClass") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[7].declaration + declaration.shouldBeResolved() + declaration.shouldBe(enumInSuperClass) + } + + @Test + fun `should resolve inherited static class method accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToInheritedClassMembers") + val superClassStaticMethod = + findUniqueDeclarationOrFail("superClassStaticMethod") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[9].declaration + declaration.shouldBeResolved() + declaration.shouldBe(superClassStaticMethod) + } + + @Test + fun `should resolve inherited instance class method accessed from class instance`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToInheritedClassMembers") + val superClassInstanceMethod = + findUniqueDeclarationOrFail("superClassInstanceMethod") + + val references = step.descendants().toList() + references.shouldHaveSize(12) + + val declaration = references[11].declaration + declaration.shouldBeResolved() + declaration.shouldBe(superClassInstanceMethod) + } + + @Test + fun `should resolve overridden instance attribute`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToOverriddenMembers") + val subClassForOverriding = findUniqueDeclarationOrFail("SubClassForOverriding") + val instanceAttributeForOverriding = + subClassForOverriding.findUniqueDeclarationOrFail("instanceAttributeForOverriding") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[5].declaration + declaration.shouldBeResolved() + declaration.shouldBe(instanceAttributeForOverriding) + } + + @Test + fun `should resolve overridden instance method`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToOverriddenMembers") + val subClassForOverriding = findUniqueDeclarationOrFail("SubClassForOverriding") + val instanceMethodForOverriding = + subClassForOverriding.findUniqueDeclarationOrFail("instanceMethodForOverriding") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[7].declaration + declaration.shouldBeResolved() + declaration.shouldBe(instanceMethodForOverriding) + } + + @Test + fun `should resolve hidden static attribute`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToHiddenMembers") + val subClassForHiding = findUniqueDeclarationOrFail("SubClassForHiding") + val staticAttributeForHiding = + subClassForHiding.findUniqueDeclarationOrFail("staticAttributeForHiding") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(staticAttributeForHiding) + } + + @Test + fun `should resolve hidden nested class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToHiddenMembers") + val subClassForHiding = findUniqueDeclarationOrFail("SubClassForHiding") + val nestedClassForHiding = + subClassForHiding.findUniqueDeclarationOrFail("NestedClassForHiding") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[3].declaration + declaration.shouldBeResolved() + declaration.shouldBe(nestedClassForHiding) + } + + @Test + fun `should resolve hidden nested enum`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToHiddenMembers") + val subClassForHiding = findUniqueDeclarationOrFail("SubClassForHiding") + val nestedEnumForHiding = + subClassForHiding.findUniqueDeclarationOrFail("NestedEnumForHiding") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[5].declaration + declaration.shouldBeResolved() + declaration.shouldBe(nestedEnumForHiding) + } + + @Test + fun `should resolve hidden static method`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToHiddenMembers") + val subClassForHiding = findUniqueDeclarationOrFail("SubClassForHiding") + val staticMethodForHiding = + subClassForHiding.findUniqueDeclarationOrFail("staticMethodForHiding") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[7].declaration + declaration.shouldBeResolved() + declaration.shouldBe(staticMethodForHiding) + } + + @Test + fun `should not resolve static class members accessed from instance`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToStaticClassMembersFromInstance") + val classInSameFile = findUniqueDeclarationOrFail("ClassInSameFile") + + val references = step.descendants() + .filter { it.declaration != classInSameFile } + .toList() + references.shouldHaveSize(8) + references.forEachAsClue { + it.declaration.shouldNotBeResolved() + } + } + + @Test + fun `should not resolve instance class members accessed from class`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToInstanceClassMembersFromClass") + val classInSameFile = findUniqueDeclarationOrFail("ClassInSameFile") + + val references = step.descendants() + .filter { it.declaration != classInSameFile } + .toList() + references.shouldHaveSize(4) + references.forEachAsClue { + it.declaration.shouldNotBeResolved() + } + } + + @Test + fun `should not resolve class members with unqualified access`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("unqualifiedReferencesToClassMembers") + + val references = step.descendants().toList() + references.shouldHaveSize(6) + references.forEachAsClue { + it.declaration.shouldNotBeResolved() + } + } + + @Test + fun `should not resolve enum variants with unqualified access`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("unqualifiedReferencesToEnumVariants") + + val references = step.descendants().toList() + references.shouldHaveSize(1) + references[0].declaration.shouldNotBeResolved() + } + + @Test + fun `should not resolve parameters of enum variants with unqualified access`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("unqualifiedReferencesToEnumVariantParameters") + + val references = step.descendants().toList() + references.shouldHaveSize(1) + references[0].declaration.shouldNotBeResolved() + } + + @Test + fun `should resolve result of callable type with one result without matching member`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToCallableTypeResults") + val singleResult = step.findUniqueDeclarationOrFail("singleResult") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(singleResult) + } + + @Test + fun `should resolve attribute for callable type with one result with matching class attribute`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToCallableTypeResults") + val classForResultMemberAccess = findUniqueDeclarationOrFail("ClassForResultMemberAccess") + val result = classForResultMemberAccess.findUniqueDeclarationOrFail("result") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[3].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result) + } + + @Test + fun `should resolve result for callable type with one result with matching enum variant`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToCallableTypeResults") + val callableWithOneResultWithIdenticalEnumVariant = + step.findUniqueDeclarationOrFail("callableWithOneResultWithIdenticalEnumVariant") + val result = + callableWithOneResultWithIdenticalEnumVariant.findUniqueDeclarationOrFail("result") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[5].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result) + } + + @Test + fun `should resolve result of callable type with multiple results`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToCallableTypeResults") + val result1 = step.findUniqueDeclarationOrFail("result1") + + val references = step.descendants().toList() + references.shouldHaveSize(8) + + val declaration = references[7].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result1) + } + + @Test + fun `should resolve result of function with one result without matching member`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToFunctionResults") + val globalFunctionResultInSameFile = + findUniqueDeclarationOrFail("globalFunctionResultInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(6) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(globalFunctionResultInSameFile) + } + + @Test + fun `should resolve member for function with one result with matching member`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToFunctionResults") + val classForResultMemberAccess = findUniqueDeclarationOrFail("ClassForResultMemberAccess") + val result = classForResultMemberAccess.findUniqueDeclarationOrFail("result") + + val references = step.descendants().toList() + references.shouldHaveSize(6) + + val declaration = references[3].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result) + } + + @Test + fun `should resolve result of function with multiple results`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToFunctionResults") + val globalFunctionWithTwoResults = + findUniqueDeclarationOrFail("globalFunctionWithTwoResults") + val result1 = globalFunctionWithTwoResults.findUniqueDeclarationOrFail("result1") + + val references = step.descendants().toList() + references.shouldHaveSize(6) + + val declaration = references[5].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result1) + } + + @Test + fun `should resolve result of lambda with one result without matching member`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToLambdaResults") + val singleResult = step.findUniqueDeclarationOrFail("singleResult") + + val references = step.descendants().toList() + references.shouldHaveSize(7) + + val declaration = references[2].declaration + declaration.shouldBeResolved() + declaration.shouldBe(singleResult) + } + + @Test + fun `should resolve member for lambda with one result with matching member`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToLambdaResults") + val classForResultMemberAccess = findUniqueDeclarationOrFail("ClassForResultMemberAccess") + val result = classForResultMemberAccess.findUniqueDeclarationOrFail("result") + + val references = step.descendants().toList() + references.shouldHaveSize(7) + + val declaration = references[4].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result) + } + + @Test + fun `should resolve result of lambda with multiple results`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToLambdaResults") + val result1 = step.findUniqueDeclarationOrFail("result1") + + val references = step.descendants().toList() + references.shouldHaveSize(7) + + val declaration = references[6].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result1) + } + + @Test + fun `should resolve result of step with one result without matching member`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToStepResults") + val stepResultInSameFile = findUniqueDeclarationOrFail("stepResultInSameFile") + + val references = step.descendants().toList() + references.shouldHaveSize(6) + + val declaration = references[1].declaration + declaration.shouldBeResolved() + declaration.shouldBe(stepResultInSameFile) + } + + @Test + fun `should resolve member for step with one result with matching member`() = + withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToStepResults") + val classForResultMemberAccess = findUniqueDeclarationOrFail("ClassForResultMemberAccess") + val result = classForResultMemberAccess.findUniqueDeclarationOrFail("result") + + val references = step.descendants().toList() + references.shouldHaveSize(6) + + val declaration = references[3].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result) + } + + @Test + fun `should resolve result of step with multiple results`() = withResource(REFERENCE) { + val step = findUniqueDeclarationOrFail("referencesToStepResults") + val stepInSameFileWithTwoResults = + findUniqueDeclarationOrFail("stepWithTwoResults") + val result1 = stepInSameFileWithTwoResults.findUniqueDeclarationOrFail("result1") + + val references = step.descendants().toList() + references.shouldHaveSize(6) + + val declaration = references[5].declaration + declaration.shouldBeResolved() + declaration.shouldBe(result1) + } + } + } +*/ + +annotation AnnotationInSameFile + +class SuperClass { + static attr superClassStaticAttribute: Int + attr superClassInstanceAttribute: Int + + class ClassInSuperClass + + enum EnumInSuperClass + + static fun superClassStaticMethod() + fun superClassInstanceMethod() +} +class ClassInSameFile() sub SuperClass { + static attr classStaticAttributeInSameFile: Int + attr classInstanceAttributeInSameFile: Int + + class ClassInClassInSameFile + + enum EnumInClassInSameFile + + static fun classStaticMethodInSameFile() -> classStaticMethodResultInSameFile: Int + fun classInstanceMethodInSameFile() -> classInstanceMethodResultInSameFile: Int +} + +enum EnumInSameFile { + EnumVariantInSameFile(enumVariantParameterInSameFile: Int) +} + +fun globalFunctionInSameFile(globalFunctionParameterInSameFile: Int) -> globalFunctionResultInSameFile: Int +fun globalFunctionWithOneResultWithIdenticalMember() -> result: ClassForResultMemberAccess +fun globalFunctionWithTwoResults() -> (result1: Int, result2: Int) + + +step stepInSameFile(stepParameterInSameFile: Int) -> stepResultInSameFile: Int { + val placeholderInSameFile = 1; +} +step stepWithOneResultWithIdenticalMember() -> result: ClassForResultMemberAccess {} +step stepWithTwoResults() -> (result1: Int, result2: Int) {} + +step internalStepInSameFile() {} +step privateStepInSameFile() {} + +pipeline pipelineInSameFile {} + +class SuperClassForOverriding() { + attr instanceAttributeForOverriding: Int + fun instanceMethodForOverriding() +} +class SubClassForOverriding() +sub SuperClassForOverriding { + attr instanceAttributeForOverriding: Int + fun instanceMethodForOverriding() +} + +class SuperClassForHiding { + static attr staticAttributeForHiding: Int + class NestedClassForHiding + enum NestedEnumForHiding + static fun staticMethodForHiding() +} +class SubClassForHiding sub SuperClassForHiding { + static attr staticAttributeForHiding: Int + class NestedClassForHiding + enum NestedEnumForHiding + static fun staticMethodForHiding() +} + +class ClassForResultMemberAccess() { + attr result: Int +} +enum EnumForResultMemberAccess { + result +} + + +// Access to own members ------------------------------------------------------- + +step referencesToClassMembers() { + ClassInSameFile.classStaticAttributeInSameFile; + ClassInSameFile<*>().classInstanceAttributeInSameFile; + ClassInSameFile.ClassInClassInSameFile; + ClassInSameFile.EnumInClassInSameFile; + ClassInSameFile.classStaticMethodInSameFile; + ClassInSameFile<*>().classInstanceMethodInSameFile(); +} + +@Target(EnumInSameFile.EnumVariantInSameFile) +step referencesToEnumVariants(@Target(EnumInSameFile.EnumVariantInSameFile) referenceToEnumVariantFromParameterAnnotation: Int) { + EnumInSameFile.EnumVariantInSameFile; +} + +class ReferencesToEnumVariants { + @Target(EnumInSameClass.EnumVariantInSameClass) + @Target(EnumInSameFile.EnumVariantInSameFile) + class ReferencesToEnumVariantsInnerClass + + enum EnumInSameClass { + EnumVariantInSameClass + } +} + +step referencesToEnumVariantParameters() { + EnumInSameFile.EnumVariantInSameFile.enumVariantParameterInSameFile; +} + + +// Access to inherited members ------------------------------------------------- + +step referencesToInheritedClassMembers() { + ClassInSameFile.superClassStaticAttribute; + ClassInSameFile<*>().superClassInstanceAttribute; + ClassInSameFile.ClassInSuperClass; + ClassInSameFile.EnumInSuperClass; + ClassInSameFile.superClassStaticMethod; + ClassInSameFile<*>().superClassInstanceMethod(); +} + + +// Overriding ------------------------------------------------------------------ +step referencesToOverriddenMembers() { + SuperClassForOverriding().instanceAttributeForOverriding; + SuperClassForOverriding().instanceMethodForOverriding(); + + SubClassForOverriding().instanceAttributeForOverriding; + SubClassForOverriding().instanceMethodForOverriding(); +} + +// Hiding ---------------------------------------------------------------------- +step referencesToHiddenMembers() { + SubClassForHiding.staticAttributeForHiding; + SubClassForHiding.NestedClassForHiding; + SubClassForHiding.NestedEnumForHiding; + SubClassForHiding.staticMethodForHiding; +} + +// Access to static members from instance -------------------------------------- + +step referencesToStaticClassMembersFromInstance() { + ClassInSameFile<*>().classStaticAttributeInSameFile; + ClassInSameFile<*>().ClassInClassInSameFile; + ClassInSameFile<*>().EnumInClassInSameFile; + ClassInSameFile<*>().classStaticMethodInSameFile; + + ClassInSameFile<*>().superClassStaticAttribute; + ClassInSameFile<*>().ClassInSuperClass; + ClassInSameFile<*>().EnumInSuperClass; + ClassInSameFile<*>().superClassStaticMethod; +} + + +// Access to instance members from class --------------------------------------- + +step referencesToInstanceClassMembersFromClass() { + ClassInSameFile.classInstanceAttributeInSameFile; + ClassInSameFile.classInstanceMethodInSameFile(); + + ClassInSameFile.superClassInstanceAttribute; + ClassInSameFile.superClassInstanceMethod(); +} + + +// Access to results of callable ----------------------------------------------- + +step referencesToCallableTypeResults( + callableWithOneResult: () -> (singleResult: Int), + callableWithOneResultWithIdenticalClassAttribute: () -> (result: ClassForResultMemberAccess), + callableWithOneResultWithIdenticalEnumVariant: () -> (result: EnumForResultMemberAccess), + callableWithTwoResults: () -> (result1: Int, result2: Int) +) { + callableWithOneResult().singleResult; + callableWithOneResultWithIdenticalClassAttribute().result; + callableWithOneResultWithIdenticalEnumVariant().result; + callableWithTwoResults().result1; +} + +step referencesToFunctionResults() { + globalFunctionInSameFile(1).globalFunctionResultInSameFile; + globalFunctionWithOneResultWithIdenticalMember().result; + globalFunctionWithTwoResults().result1; +} + +step referencesToLambdaResults() { + val lambdaWithOneResult = () { + yield singleResult = 1; + }; + val lambdaWithOneResultWithIdenticalMember = () { + yield result = ClassForResultMemberAccess(); + }; + val lambdaWithTwoResults = () { + yield result1 = 1; + yield result2 = 1; + }; + + lambdaWithOneResult().singleResult; + lambdaWithOneResultWithIdenticalMember().result; + lambdaWithTwoResults().result1; +} + +step referencesToStepResults() { + stepInSameFile(1).stepResultInSameFile; + stepWithOneResultWithIdenticalMember().result; + stepWithTwoResults().result1; +} + +// Access to locals from outside ----------------------------------------------- + +step referencesToLambdaLocals() { + val f = (lambdaParameter) { + val lambdaPlaceholder = 1; + yield lambdaYield = 1; + }; + + lambdaPlaceholder; +} + +step referencesToStepLocals() { + placeholderInSameFile; +} diff --git a/tests/resources/scoping/yields/in segment/main.sdstest b/tests/resources/scoping/yields/in segment/main.sdstest index 9369df4c0..bafe0a4ea 100644 --- a/tests/resources/scoping/yields/in segment/main.sdstest +++ b/tests/resources/scoping/yields/in segment/main.sdstest @@ -4,11 +4,18 @@ segment mySegment1() -> before: Int {} segment mySegment() -> ( // $TEST$ target result - »result«: Int + »result«: Int, + + // $TEST$ target redeclared + »redeclared«: Int, + redeclared: Int, ) { // $TEST$ references result yield »result« = 1; + // $TEST$ references redeclared + yield »redeclared« = 1; + // $TEST$ unresolved yield »before« = 1; diff --git a/tests/resources/validation/other/expressions/references/target/main.sdstest b/tests/resources/validation/other/expressions/references/target/main.sdstest new file mode 100644 index 000000000..1d2b7fac2 --- /dev/null +++ b/tests/resources/validation/other/expressions/references/target/main.sdstest @@ -0,0 +1,18 @@ +package tests.validation.other.expressions.references.target + +annotation MyAnnotation + +pipeline myPipeline {} + +schema MySchema {} + +segment mySegment() { + // $TEST$ error "An annotation must not be the target of a reference." + »MyAnnotation«; + + // $TEST$ error "A pipeline must not be the target of a reference." + »myPipeline«; + + // $TEST$ error "A schema must not be the target of a reference." + »MySchema«; +}