Skip to content

Commit

Permalink
feat: unique names withing declarations (#575)
Browse files Browse the repository at this point in the history
Closes partially #543

### Summary of Changes

Ensure that names are unique within declarations. I'll port the checks
for uniqueness on the file level in a future PR.

---------

Co-authored-by: megalinter-bot <[email protected]>
lars-reimann and megalinter-bot authored Sep 21, 2023
1 parent 4ba7873 commit 47ce782
Showing 19 changed files with 670 additions and 54 deletions.
6 changes: 6 additions & 0 deletions src/language/ast/checks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { SdsImport } from '../generated/ast.js';

export const isWildcardImport = function (node: SdsImport): boolean {
const importedNamespace = node.importedNamespace ?? '';
return importedNamespace.endsWith('*');
};
96 changes: 96 additions & 0 deletions src/language/ast/shortcuts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
isSdsAssignment,
isSdsBlockLambdaResult,
isSdsDeclaration,
isSdsPlaceholder,
SdsAnnotatedObject,
SdsAnnotationCall,
SdsAssignee,
SdsAssignment,
SdsBlock,
SdsBlockLambda,
SdsBlockLambdaResult,
SdsClass,
SdsClassMember,
SdsEnum,
SdsEnumVariant,
SdsLiteral,
SdsLiteralType,
SdsParameter,
SdsParameterList,
SdsPlaceholder,
SdsResult,
SdsResultList,
SdsStatement,
SdsTypeArgument,
SdsTypeArgumentList,
SdsTypeParameter,
SdsTypeParameterList,
} from '../generated/ast.js';
import { stream } from 'langium';

export const annotationCallsOrEmpty = function (node: SdsAnnotatedObject | undefined): SdsAnnotationCall[] {
if (!node) {
/* c8 ignore next 2 */
return [];
}

if (isSdsDeclaration(node)) {
return node?.annotationCallList?.annotationCalls ?? node?.annotationCalls ?? [];
} else {
/* c8 ignore next 2 */
return node?.annotationCalls ?? [];
}
};

export const assigneesOrEmpty = function (node: SdsAssignment | undefined): SdsAssignee[] {
return node?.assigneeList?.assignees ?? [];
};

export const blockLambdaResultsOrEmpty = function (node: SdsBlockLambda | undefined): SdsBlockLambdaResult[] {
return stream(statementsOrEmpty(node?.body))
.filter(isSdsAssignment)
.flatMap(assigneesOrEmpty)
.filter(isSdsBlockLambdaResult)
.toArray();
};

export const literalsOrEmpty = function (node: SdsLiteralType | undefined): SdsLiteral[] {
return node?.literalList?.literals ?? [];
};

export const classMembersOrEmpty = function (node: SdsClass | undefined): SdsClassMember[] {
return node?.body?.members ?? [];
};

export const parametersOrEmpty = function (node: SdsParameterList | undefined): SdsParameter[] {
return node?.parameters ?? [];
};

export const placeholdersOrEmpty = function (node: SdsBlock | undefined): SdsPlaceholder[] {
return stream(statementsOrEmpty(node))
.filter(isSdsAssignment)
.flatMap(assigneesOrEmpty)
.filter(isSdsPlaceholder)
.toArray();
};

export const resultsOrEmpty = function (node: SdsResultList | undefined): SdsResult[] {
return node?.results ?? [];
};

export const statementsOrEmpty = function (node: SdsBlock | undefined): SdsStatement[] {
return node?.statements ?? [];
};

export const typeArgumentsOrEmpty = function (node: SdsTypeArgumentList | undefined): SdsTypeArgument[] {
return node?.typeArguments ?? [];
};

export const typeParametersOrEmpty = function (node: SdsTypeParameterList | undefined): SdsTypeParameter[] {
return node?.typeParameters ?? [];
};

export const variantsOrEmpty = function (node: SdsEnum | undefined): SdsEnumVariant[] {
return node?.body?.variants ?? [];
};
14 changes: 12 additions & 2 deletions src/language/formatting/safe-ds-formatter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { AbstractFormatter, AstNode, CstNode, findCommentNode, Formatting, isAstNode, FormattingAction, FormattingActionOptions } from 'langium';
import {
AbstractFormatter,
AstNode,
CstNode,
findCommentNode,
Formatting,
isAstNode,
FormattingAction,
FormattingActionOptions,
} from 'langium';
import * as ast from '../generated/ast.js';
import { SdsImport, SdsImportAlias, SdsModule } from '../generated/ast.js';
import { annotationCallsOrEmpty, literalsOrEmpty, typeArgumentsOrEmpty } from '../helpers/astShortcuts.js';
import { annotationCallsOrEmpty, literalsOrEmpty, typeArgumentsOrEmpty } from '../ast/shortcuts.js';
import noSpace = Formatting.noSpace;
import newLine = Formatting.newLine;
import newLines = Formatting.newLines;
@@ -876,6 +885,7 @@ export class SafeDsFormatter extends AbstractFormatter {
} else if (ast.isSdsUnionType(node)) {
return typeArgumentsOrEmpty(node.typeArgumentList).length > 0;
} else {
/* c8 ignore next 2 */
return false;
}
}
12 changes: 6 additions & 6 deletions src/language/grammar/safe-ds.langium
Original file line number Diff line number Diff line change
@@ -81,7 +81,7 @@ QualifiedName returns string:

interface SdsModuleMember extends SdsDeclaration {}

SdsAnnotatedModuleMember returns SdsAnnotatedObject:
SdsAnnotatedModuleMember returns SdsModuleMember:
{SdsAnnotationCallList}
annotationCalls+=SdsAnnotationCall+
(
@@ -108,7 +108,7 @@ SdsAnnotatedModuleMember returns SdsAnnotatedObject:
)
;

SdsUnannotatedModuleMember returns SdsAnnotatedObject:
SdsUnannotatedModuleMember returns SdsModuleMember:
{SdsAnnotation}
SdsAnnotationFragment

@@ -170,7 +170,7 @@ SdsParentTypeList returns SdsParentTypeList:
;

interface SdsClassBody extends SdsObject {
members: SdsAnnotatedObject[]
members: SdsClassMember[]
}

SdsClassBody returns SdsClassBody:
@@ -179,12 +179,12 @@ SdsClassBody returns SdsClassBody:

interface SdsClassMember extends SdsDeclaration {}

SdsClassMember returns SdsAnnotatedObject:
SdsClassMember returns SdsClassMember:
SdsAnnotatedClassMember
| SdsUnannotatedClassMember
;

SdsAnnotatedClassMember returns SdsAnnotatedObject:
SdsAnnotatedClassMember returns SdsClassMember:
{SdsAnnotationCallList}
annotationCalls+=SdsAnnotationCall+
(
@@ -203,7 +203,7 @@ SdsAnnotatedClassMember returns SdsAnnotatedObject:
)
;

SdsUnannotatedClassMember returns SdsAnnotatedObject:
SdsUnannotatedClassMember returns SdsClassMember:
{SdsAttribute}
SdsAttributeFragment

38 changes: 0 additions & 38 deletions src/language/helpers/astShortcuts.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/language/scoping/safe-ds-scope-provider.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ import {
SdsType,
SdsYield,
} from '../generated/ast.js';
import { resultsOrEmpty } from '../helpers/astShortcuts.js';
import { resultsOrEmpty } from '../ast/shortcuts.js';

export class SafeDsScopeProvider extends DefaultScopeProvider {
override getScope(context: ReferenceInfo): Scope {
2 changes: 1 addition & 1 deletion src/language/validation/imports.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ValidationAcceptor } from 'langium';
import { SdsImportAlias } from '../generated/ast.js';
import { isWildcardImport } from '../helpers/astShortcuts.js';
import { isWildcardImport } from '../ast/checks.js';

export const CODE_IMPORT_WILDCARD_IMPORT_WITH_ALIAS = 'import/wildcard-import-with-alias';

178 changes: 177 additions & 1 deletion src/language/validation/names.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
import { SdsDeclaration } from '../generated/ast.js';
import {
SdsAnnotation,
SdsBlockLambda,
SdsCallableType,
SdsClass,
SdsDeclaration,
SdsEnum,
SdsEnumVariant,
SdsExpressionLambda,
SdsFunction,
SdsPipeline,
SdsSegment,
} from '../generated/ast.js';
import { ValidationAcceptor } from 'langium';
import {
blockLambdaResultsOrEmpty,
classMembersOrEmpty,
parametersOrEmpty,
placeholdersOrEmpty,
resultsOrEmpty,
typeParametersOrEmpty,
variantsOrEmpty,
} from '../ast/shortcuts.js';

export const CODE_NAME_BLOCK_LAMBDA_PREFIX = 'name/block-lambda-prefix';
export const CODE_NAME_CASING = 'name/casing';
export const CODE_NAME_DUPLICATE = 'name/duplicate';

// -----------------------------------------------------------------------------
// Block lambda prefix
// -----------------------------------------------------------------------------

export const nameMustNotStartWithBlockLambdaPrefix = (node: SdsDeclaration, accept: ValidationAcceptor) => {
const name = node.name ?? '';
@@ -20,6 +46,10 @@ export const nameMustNotStartWithBlockLambdaPrefix = (node: SdsDeclaration, acce
}
};

// -----------------------------------------------------------------------------
// Casing
// -----------------------------------------------------------------------------

export const nameShouldHaveCorrectCasing = (node: SdsDeclaration, accept: ValidationAcceptor): void => {
switch (node.$type) {
case 'SdsAnnotation':
@@ -62,6 +92,7 @@ export const nameShouldHaveCorrectCasing = (node: SdsDeclaration, accept: Valida
case 'SdsTypeParameter':
return nameShouldBeUpperCamelCase(node, 'type parameters', accept);
}
/* c8 ignore next */
};

const nameShouldBeLowerCamelCase = (node: SdsDeclaration, nodeName: string, accept: ValidationAcceptor): void => {
@@ -98,3 +129,148 @@ const acceptCasingWarning = (
code: CODE_NAME_CASING,
});
};

// -----------------------------------------------------------------------------
// Uniqueness
// -----------------------------------------------------------------------------

export const annotationMustContainUniqueNames = (node: SdsAnnotation, accept: ValidationAcceptor): void => {
namesMustBeUnique(
parametersOrEmpty(node.parameterList),
(name) => `A parameter with name '${name}' exists already.`,
accept,
);
};

export const blockLambdaMustContainUniqueNames = (node: SdsBlockLambda, accept: ValidationAcceptor): void => {
const parametersAndPlaceholders = [...parametersOrEmpty(node.parameterList), ...placeholdersOrEmpty(node.body)];
namesMustBeUnique(
parametersAndPlaceholders,
(name) => `A parameter or placeholder with name '${name}' exists already.`,
accept,
);

namesMustBeUnique(
blockLambdaResultsOrEmpty(node),
(name) => `A result with name '${name}' exists already.`,
accept,
);
};

export const callableTypeMustContainUniqueNames = (node: SdsCallableType, accept: ValidationAcceptor): void => {
namesMustBeUnique(
parametersOrEmpty(node.parameterList),
(name) => `A parameter with name '${name}' exists already.`,
accept,
);
namesMustBeUnique(
resultsOrEmpty(node.resultList),
(name) => `A result with name '${name}' exists already.`,
accept,
);
};

export const classMustContainUniqueNames = (node: SdsClass, accept: ValidationAcceptor): void => {
const typeParametersAndParameters = [
...typeParametersOrEmpty(node.typeParameterList),
...parametersOrEmpty(node.parameterList),
];
namesMustBeUnique(
typeParametersAndParameters,
(name) => `A type parameter or parameter with name '${name}' exists already.`,
accept,
);

namesMustBeUnique(classMembersOrEmpty(node), (name) => `A member with name '${name}' exists already.`, accept);
};

export const enumMustContainUniqueNames = (node: SdsEnum, accept: ValidationAcceptor): void => {
namesMustBeUnique(variantsOrEmpty(node), (name) => `A variant with name '${name}' exists already.`, accept);
};

export const enumVariantMustContainUniqueNames = (node: SdsEnumVariant, accept: ValidationAcceptor): void => {
const typeParametersAndParameters = [
...typeParametersOrEmpty(node.typeParameterList),
...parametersOrEmpty(node.parameterList),
];
namesMustBeUnique(
typeParametersAndParameters,
(name) => `A type parameter or parameter with name '${name}' exists already.`,
accept,
);
};

export const expressionLambdaMustContainUniqueNames = (node: SdsExpressionLambda, accept: ValidationAcceptor): void => {
namesMustBeUnique(
parametersOrEmpty(node.parameterList),
(name) => `A parameter with name '${name}' exists already.`,
accept,
);
};

export const functionMustContainUniqueNames = (node: SdsFunction, accept: ValidationAcceptor): void => {
const typeParametersAndParameters = [
...typeParametersOrEmpty(node.typeParameterList),
...parametersOrEmpty(node.parameterList),
];
namesMustBeUnique(
typeParametersAndParameters,
(name) => `A type parameter or parameter with name '${name}' exists already.`,
accept,
);

namesMustBeUnique(
resultsOrEmpty(node.resultList),
(name) => `A result with name '${name}' exists already.`,
accept,
);
};

export const pipelineMustContainUniqueNames = (node: SdsPipeline, accept: ValidationAcceptor): void => {
namesMustBeUnique(
placeholdersOrEmpty(node.body),
(name) => `A placeholder with name '${name}' exists already.`,
accept,
);
};

export const segmentMustContainUniqueNames = (node: SdsSegment, accept: ValidationAcceptor): void => {
const parametersAndPlaceholder = [...parametersOrEmpty(node.parameterList), ...placeholdersOrEmpty(node.body)];
namesMustBeUnique(
parametersAndPlaceholder,
(name) => `A parameter or placeholder with name '${name}' exists already.`,
accept,
);

namesMustBeUnique(
resultsOrEmpty(node.resultList),
(name) => `A result with name '${name}' exists already.`,
accept,
);
};

const namesMustBeUnique = (
nodes: Iterable<SdsDeclaration>,
createMessage: (name: string) => string,
accept: ValidationAcceptor,
): void => {
const knownNames = new Set<string>();

for (const node of nodes) {
const name = node.name;
if (!name) {
/* c8 ignore next 2 */
continue;
}

if (knownNames.has(name)) {
accept('error', createMessage(name), {
node,
property: 'name',
code: CODE_NAME_DUPLICATE,
});
} else {
knownNames.add(name);
}
}
};
29 changes: 24 additions & 5 deletions src/language/validation/safe-ds-validator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { ValidationChecks } from 'langium';
import { SafeDsAstType } from '../generated/ast.js';
import type { SafeDsServices } from '../safe-ds-module.js';
import { nameMustNotStartWithBlockLambdaPrefix, nameShouldHaveCorrectCasing } from './names.js';
import {
annotationMustContainUniqueNames,
blockLambdaMustContainUniqueNames,
callableTypeMustContainUniqueNames,
classMustContainUniqueNames,
enumMustContainUniqueNames,
enumVariantMustContainUniqueNames,
expressionLambdaMustContainUniqueNames,
functionMustContainUniqueNames,
nameMustNotStartWithBlockLambdaPrefix,
nameShouldHaveCorrectCasing,
pipelineMustContainUniqueNames,
segmentMustContainUniqueNames,
} from './names.js';
import {
annotationParameterListShouldNotBeEmpty,
assignmentShouldHaveMoreThanWildcardsAsAssignees,
@@ -34,14 +47,19 @@ export const registerValidationChecks = function (services: SafeDsServices) {
const validator = services.validation.SafeDsValidator;
const checks: ValidationChecks<SafeDsAstType> = {
SdsAssignment: [assignmentShouldHaveMoreThanWildcardsAsAssignees],
SdsAnnotation: [annotationParameterListShouldNotBeEmpty],
SdsAnnotation: [annotationMustContainUniqueNames, annotationParameterListShouldNotBeEmpty],
SdsAttribute: [attributeMustHaveTypeHint],
SdsBlockLambda: [blockLambdaMustContainUniqueNames],
SdsCallableType: [callableTypeMustContainUniqueNames],
SdsClass: [classMustContainUniqueNames],
SdsClassBody: [classBodyShouldNotBeEmpty],
SdsConstraintList: [constraintListShouldNotBeEmpty],
SdsDeclaration: [nameMustNotStartWithBlockLambdaPrefix, nameShouldHaveCorrectCasing],
SdsEnum: [enumMustContainUniqueNames],
SdsEnumBody: [enumBodyShouldNotBeEmpty],
SdsEnumVariant: [enumVariantParameterListShouldNotBeEmpty],
SdsFunction: [functionResultListShouldNotBeEmpty],
SdsEnumVariant: [enumVariantMustContainUniqueNames, enumVariantParameterListShouldNotBeEmpty],
SdsExpressionLambda: [expressionLambdaMustContainUniqueNames],
SdsFunction: [functionMustContainUniqueNames, functionResultListShouldNotBeEmpty],
SdsImportAlias: [importAliasMustNotBeUsedForWildcardImports],
SdsModule: [moduleDeclarationsMustMatchFileKind, moduleWithDeclarationsMustStatePackage],
SdsParameter: [parameterMustHaveTypeHint],
@@ -50,8 +68,9 @@ export const registerValidationChecks = function (services: SafeDsServices) {
parameterListMustNotHaveRequiredParametersAfterOptionalParameters,
parameterListVariadicParameterMustBeLast,
],
SdsPipeline: [pipelineMustContainUniqueNames],
SdsResult: [resultMustHaveTypeHint],
SdsSegment: [segmentResultListShouldNotBeEmpty],
SdsSegment: [segmentMustContainUniqueNames, segmentResultListShouldNotBeEmpty],
SdsTemplateString: [templateStringMustHaveExpressionBetweenTwoStringParts],
SdsTypeParameterConstraint: [typeParameterConstraintLeftOperandMustBeOwnTypeParameter],
SdsTypeParameterList: [typeParameterListShouldNotBeEmpty],
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tests.validation.names.duplicates.inAnnotation

annotation A(
// $TEST$ no error r"A parameter with name '\w*' exists already\."
»duplicateParameter«: Int,
// $TEST$ error "A parameter with name 'duplicateParameter' exists already."
»duplicateParameter«: Int,
// $TEST$ no error r"A parameter with name '\w*' exists already\."
»uniqueParameter«: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package tests.validation.names.duplicates.inBlockLambda

pipeline p {
(
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»duplicateParameter«,
// $TEST$ error "A parameter or placeholder with name 'duplicateParameter' exists already."
»duplicateParameter«,
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»uniqueParameter«,
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»parameterAndPlaceholder«,
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»parameterAndResult«
) {
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »duplicatePlaceholder« = 1;
// $TEST$ error "A parameter or placeholder with name 'duplicatePlaceholder' exists already."
val »duplicatePlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »uniquePlaceholder« = 1;
// $TEST$ error "A parameter or placeholder with name 'parameterAndPlaceholder' exists already."
val »parameterAndPlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »placeholderAndResult« = 1;

// $TEST$ no error r"A result with name '\w*' exists already\."
yield »duplicateResult« = 0;
// $TEST$ error "A result with name 'duplicateResult' exists already."
yield »duplicateResult« = 0;
// $TEST$ no error r"A result with name '\w*' exists already\."
yield »uniqueResult« = 0;
// $TEST$ no error r"A result with name '\w*' exists already\."
yield »parameterAndResult« = 0;
//$TEST$ no error r"A result with name '\w*' exists already\."
yield »placeholderAndResult« = 0;
//$TEST$ no error r"A result with name '\w*' exists already\."
yield »resultAndPlaceholder« = 0;

// $TEST$ no error "A parameter or placeholder with name '\w*' exists already\."
val »resultAndPlaceholder« = 1;

() {
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »duplicatePlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »parameterAndPlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »placeholderAndResult« = 1;
};
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tests.validation.names.duplicates.inCallableType

segment s(
f: (
// $TEST$ no error r"A parameter with name '\w*' exists already\."
»duplicateParameter«: Int,
// $TEST$ error "A parameter with name 'duplicateParameter' exists already."
»duplicateParameter«: Int,
// $TEST$ no error r"A parameter with name '\w*' exists already\."
»uniqueParameter«: Int,
// $TEST$ no error r"A parameter with name '\w*' exists already\."
»parameterAndResult«: Int
) -> (
// $TEST$ no error r"A result with name '\w*' exists already\."
»duplicateResult«: Int,
// $TEST$ error "A result with name 'duplicateResult' exists already."
»duplicateResult«: Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»uniqueResult«: Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»parameterAndResult«: Int
)
) {}
126 changes: 126 additions & 0 deletions tests/resources/validation/names/duplicates/in class/main.sdstest
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package tests.validation.names.duplicates.inClass

class MyClass1<
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»DuplicateTypeParameter«,
// $TEST$ error "A type parameter or parameter with name 'DuplicateTypeParameter' exists already."
»DuplicateTypeParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»UniqueTypeParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndMember«,
>(
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»duplicateParameter«: Int,
// $TEST$ error "A type parameter or parameter with name 'duplicateParameter' exists already."
»duplicateParameter«: Int,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»uniqueParameter«: Int,
// $TEST$ error "A type parameter or parameter with name 'TypeParameterAndParameter' exists already."
»TypeParameterAndParameter«: Int,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»parameterAndMember«: Int,
) {
// $TEST$ no error r"A member with name '\w*' exists already\."
attr »duplicateAttribute«: Int
// $TEST$ error "A member with name 'duplicateAttribute' exists already."
attr »duplicateAttribute«: Int
// $TEST$ no error r"A member with name '\w*' exists already\."
attr »uniqueAttribute«: Int

// $TEST$ no error r"A member with name '\w*' exists already\."
class »DuplicateClass«
// $TEST$ error "A member with name 'DuplicateClass' exists already."
class »DuplicateClass«
// $TEST$ no error r"A member with name '\w*' exists already\."
class »UniqueClass«

// $TEST$ no error r"A member with name '\w*' exists already\."
enum »DuplicateEnum«
// $TEST$ error "A member with name 'DuplicateEnum' exists already."
enum »DuplicateEnum«
// $TEST$ no error r"A member with name '\w*' exists already\."
enum »UniqueEnum«

// $TEST$ no error r"A member with name '\w*' exists already\."
fun »duplicateFun«()
// $TEST$ error "A member with name 'duplicateFun' exists already."
fun »duplicateFun«()
// $TEST$ no error r"A member with name '\w*' exists already\."
fun »uniqueFun«()

// $TEST$ no error r"A member with name '\w*' exists already\."
attr »duplicateMember«: Int
// $TEST$ error "A member with name 'duplicateMember' exists already."
class »duplicateMember«
// $TEST$ error "A member with name 'duplicateMember' exists already."
enum »duplicateMember«
// $TEST$ error "A member with name 'duplicateMember' exists already."
fun »duplicateMember«()
}

class MyClass2<
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndMember«,
> {
// $TEST$ no error r"A member with name '\w*' exists already\."
attr »TypeParameterAndMember«: Int
}

class MyClass3<
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndMember«,
> {
// $TEST$ no error r"A member with name '\w*' exists already\."
class »TypeParameterAndMember«
}

class MyClass4<
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndMember«,
> {
// $TEST$ no error r"A member with name '\w*' exists already\."
enum »TypeParameterAndMember«
}

class MyClass5<
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndMember«,
> {
// $TEST$ no error r"A member with name '\w*' exists already\."
fun »TypeParameterAndMember«()
}

class MyClass6(
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»parameterAndMember«: Int,
) {
// $TEST$ no error r"A member with name '\w*' exists already\."
attr »parameterAndMember«: Int
}

class MyClass7(
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»parameterAndMember«: Int,
) {
// $TEST$ no error r"A member with name '\w*' exists already\."
class »parameterAndMember«
}

class MyClass8(
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»parameterAndMember«: Int,
) {
// $TEST$ no error r"A member with name '\w*' exists already\."
enum »parameterAndMember«
}

class MyClass9(
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»parameterAndMember«: Int,
) {
// $TEST$ no error r"A member with name '\w*' exists already\."
fun »parameterAndMember«()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tests.validation.names.duplicates.inEnumVariant

enum MyEnum {
MyEnumVariant<
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»DuplicateTypeParameter«,
// $TEST$ error "A type parameter or parameter with name 'DuplicateTypeParameter' exists already."
»DuplicateTypeParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»UniqueTypeParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndParameter«,
>(
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»duplicateParameter«: Int,
// $TEST$ error "A type parameter or parameter with name 'duplicateParameter' exists already."
»duplicateParameter«: Int,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»uniqueParameter«: Int,
// $TEST$ error "A type parameter or parameter with name 'TypeParameterAndParameter' exists already."
»TypeParameterAndParameter«: Int,
)
}
10 changes: 10 additions & 0 deletions tests/resources/validation/names/duplicates/in enum/main.sdstest
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tests.validation.names.duplicates.inEnum

enum MyEnum {
// $TEST$ no error r"A variant with name '\w*' exists already\."
»MyVariant1«
// $TEST$ error "A variant with name 'MyVariant1' exists already."
»MyVariant1«
// $TEST$ no error r"A variant with name '\w*' exists already\."
»MyVariant2«
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package tests.validation.names.duplicates.inExpressionLambda

pipeline p {
(
// $TEST$ no error r"A parameter with name '\w*' exists already\."
»duplicateParameter«,
// $TEST$ error "A parameter with name 'duplicateParameter' exists already."
»duplicateParameter«,
// $TEST$ no error r"A parameter with name '\w*' exists already\."
»uniqueParameter«,
) -> 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package tests.validation.names.duplicates.inFunction

fun myFunction<
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»DuplicateTypeParameter«,
// $TEST$ error "A type parameter or parameter with name 'DuplicateTypeParameter' exists already."
»DuplicateTypeParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»UniqueTypeParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndParameter«,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»TypeParameterAndResult«,
>(
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»duplicateParameter«: Int,
// $TEST$ error "A type parameter or parameter with name 'duplicateParameter' exists already."
»duplicateParameter«: Int,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»uniqueParameter«: Int,
// $TEST$ error "A type parameter or parameter with name 'TypeParameterAndParameter' exists already."
»TypeParameterAndParameter«: Int,
// $TEST$ no error r"A type parameter or parameter with name '\w*' exists already\."
»parameterAndResult«: Int,
) -> (
// $TEST$ no error r"A result with name '\w*' exists already\."
»duplicateResult« : Int,
// $TEST$ error "A result with name 'duplicateResult' exists already."
»duplicateResult« : Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»uniqueResult« : Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»parameterAndResult« : Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»TypeParameterAndResult« : Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tests.validation.names.duplicates.inPipeline

pipeline p {
// $TEST$ no error r"A placeholder with name '\w*' exists already\."
val »duplicatePlaceholder« = 1;
// $TEST$ error "A placeholder with name 'duplicatePlaceholder' exists already."
val »duplicatePlaceholder« = 1;
// $TEST$ no error r"A placeholder with name '\w*' exists already\."
val »uniquePlaceholder« = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package tests.validation.names.duplicates.inSegment

segment mySegment(
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»duplicateParameter«: Int,
// $TEST$ error "A parameter or placeholder with name 'duplicateParameter' exists already."
»duplicateParameter«: Int,
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»uniqueParameter«: Int,
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»parameterAndPlaceholder«: Int,
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
»parameterAndResult«: Int,
) -> (
// $TEST$ no error r"A result with name '\w*' exists already\."
»duplicateResult« : Int,
// $TEST$ error "A result with name 'duplicateResult' exists already."
»duplicateResult« : Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»uniqueResult« : Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»parameterAndResult« : Int,
// $TEST$ no error r"A result with name '\w*' exists already\."
»placeholderAndResult« : Int,
) {
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »duplicatePlaceholder« = 1;
// $TEST$ error "A parameter or placeholder with name 'duplicatePlaceholder' exists already."
val »duplicatePlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »uniquePlaceholder« = 1;
// $TEST$ error "A parameter or placeholder with name 'parameterAndPlaceholder' exists already."
val »parameterAndPlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »placeholderAndResult« = 1;

() {
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »duplicatePlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »parameterAndPlaceholder« = 1;
// $TEST$ no error r"A parameter or placeholder with name '\w*' exists already\."
val »placeholderAndResult« = 1;
};
}

0 comments on commit 47ce782

Please sign in to comment.