Skip to content

Commit 5a9dcbb

Browse files
feat: check @PythonName and @PythonModule (#641)
Closes partially #543 ### Summary of Changes Show an info if * `@PythonName` is identical to the Safe-DS name of a declaration, * `@PythonModule` is identical to the Safe-DS package. In those cases, the annotations could be removed. --------- Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com>
1 parent 38d1181 commit 5a9dcbb

File tree

14 files changed

+243
-69
lines changed

14 files changed

+243
-69
lines changed
+61-13
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,102 @@
1-
import { isSdsAnnotation, SdsAnnotatedObject, SdsAnnotation, SdsParameter } from '../generated/ast.js';
2-
import { annotationCallsOrEmpty } from '../helpers/nodeProperties.js';
1+
import { isSdsAnnotation, SdsAnnotatedObject, SdsAnnotation, SdsModule, SdsParameter } from '../generated/ast.js';
2+
import { argumentsOrEmpty, findFirstAnnotationCallOf, hasAnnotationCallOf } from '../helpers/nodeProperties.js';
33
import { SafeDsModuleMembers } from './safe-ds-module-members.js';
44
import { resourceNameToUri } from '../../helpers/resources.js';
55
import { URI } from 'langium';
6+
import { SafeDsServices } from '../safe-ds-module.js';
7+
import { SafeDsNodeMapper } from '../helpers/safe-ds-node-mapper.js';
8+
import { toConstantExpressionOrUndefined } from '../partialEvaluation/toConstantExpressionOrUndefined.js';
9+
import { SdsConstantExpression, SdsConstantString } from '../partialEvaluation/model.js';
610

711
const ANNOTATION_USAGE_URI = resourceNameToUri('builtins/safeds/lang/annotationUsage.sdsstub');
12+
const CODE_GENERATION_URI = resourceNameToUri('builtins/safeds/lang/codeGeneration.sdsstub');
813
const IDE_INTEGRATION_URI = resourceNameToUri('builtins/safeds/lang/ideIntegration.sdsstub');
914
const MATURITY_URI = resourceNameToUri('builtins/safeds/lang/maturity.sdsstub');
1015

1116
export class SafeDsAnnotations extends SafeDsModuleMembers<SdsAnnotation> {
17+
private readonly nodeMapper: SafeDsNodeMapper;
18+
19+
constructor(services: SafeDsServices) {
20+
super(services);
21+
22+
this.nodeMapper = services.helpers.NodeMapper;
23+
}
24+
1225
isDeprecated(node: SdsAnnotatedObject | undefined): boolean {
13-
return this.hasAnnotationCallOf(node, this.Deprecated);
26+
return hasAnnotationCallOf(node, this.Deprecated);
1427
}
1528

1629
private get Deprecated(): SdsAnnotation | undefined {
1730
return this.getAnnotation(MATURITY_URI, 'Deprecated');
1831
}
1932

2033
isExperimental(node: SdsAnnotatedObject | undefined): boolean {
21-
return this.hasAnnotationCallOf(node, this.Experimental);
34+
return hasAnnotationCallOf(node, this.Experimental);
2235
}
2336

2437
private get Experimental(): SdsAnnotation | undefined {
2538
return this.getAnnotation(MATURITY_URI, 'Experimental');
2639
}
2740

2841
isExpert(node: SdsParameter | undefined): boolean {
29-
return this.hasAnnotationCallOf(node, this.Expert);
42+
return hasAnnotationCallOf(node, this.Expert);
3043
}
3144

3245
private get Expert(): SdsAnnotation | undefined {
3346
return this.getAnnotation(IDE_INTEGRATION_URI, 'Expert');
3447
}
3548

49+
getPythonModule(node: SdsModule | undefined): string | undefined {
50+
const value = this.getArgumentValue(node, this.PythonModule, 'qualifiedName');
51+
if (value instanceof SdsConstantString) {
52+
return value.value;
53+
} else {
54+
return undefined;
55+
}
56+
}
57+
58+
get PythonModule(): SdsAnnotation | undefined {
59+
return this.getAnnotation(CODE_GENERATION_URI, 'PythonModule');
60+
}
61+
62+
getPythonName(node: SdsAnnotatedObject | undefined): string | undefined {
63+
const value = this.getArgumentValue(node, this.PythonName, 'name');
64+
if (value instanceof SdsConstantString) {
65+
return value.value;
66+
} else {
67+
return undefined;
68+
}
69+
}
70+
71+
get PythonName(): SdsAnnotation | undefined {
72+
return this.getAnnotation(CODE_GENERATION_URI, 'PythonName');
73+
}
74+
3675
isRepeatable(node: SdsAnnotation | undefined): boolean {
37-
return this.hasAnnotationCallOf(node, this.Repeatable);
76+
return hasAnnotationCallOf(node, this.Repeatable);
3877
}
3978

4079
private get Repeatable(): SdsAnnotation | undefined {
4180
return this.getAnnotation(ANNOTATION_USAGE_URI, 'Repeatable');
4281
}
4382

44-
private hasAnnotationCallOf(node: SdsAnnotatedObject | undefined, expected: SdsAnnotation | undefined): boolean {
45-
return annotationCallsOrEmpty(node).some((it) => {
46-
const actual = it.annotation?.ref;
47-
return actual === expected;
48-
});
49-
}
50-
5183
private getAnnotation(uri: URI, name: string): SdsAnnotation | undefined {
5284
return this.getModuleMember(uri, name, isSdsAnnotation);
5385
}
86+
87+
/**
88+
* Finds the first call of the given annotation on the given node and returns the value that is assigned to the
89+
* parameter with the given name.
90+
*/
91+
private getArgumentValue(
92+
node: SdsAnnotatedObject | undefined,
93+
annotation: SdsAnnotation | undefined,
94+
parameterName: string,
95+
): SdsConstantExpression | undefined {
96+
const annotationCall = findFirstAnnotationCallOf(node, annotation);
97+
const expression = argumentsOrEmpty(annotationCall).find(
98+
(it) => this.nodeMapper.argumentToParameterOrUndefined(it)?.name === parameterName,
99+
)?.value;
100+
return toConstantExpressionOrUndefined(expression);
101+
}
54102
}

src/language/helpers/nodeProperties.ts

+22
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
SdsAbstractCall,
1818
SdsAbstractResult,
1919
SdsAnnotatedObject,
20+
SdsAnnotation,
2021
SdsAnnotationCall,
2122
SdsArgument,
2223
SdsAssignee,
@@ -57,6 +58,16 @@ import { AstNode, getContainerOfType, stream } from 'langium';
5758
// Checks
5859
// -------------------------------------------------------------------------------------------------
5960

61+
export const hasAnnotationCallOf = (
62+
node: SdsAnnotatedObject | undefined,
63+
expected: SdsAnnotation | undefined,
64+
): boolean => {
65+
return annotationCallsOrEmpty(node).some((it) => {
66+
const actual = it.annotation?.ref;
67+
return actual === expected;
68+
});
69+
};
70+
6071
export const isInternal = (node: SdsDeclaration): boolean => {
6172
return isSdsSegment(node) && node.visibility === 'internal';
6273
};
@@ -121,6 +132,17 @@ export const annotationCallsOrEmpty = (node: SdsAnnotatedObject | undefined): Sd
121132
return node?.annotationCalls ?? [];
122133
}
123134
};
135+
136+
export const findFirstAnnotationCallOf = (
137+
node: SdsAnnotatedObject | undefined,
138+
expected: SdsAnnotation | undefined,
139+
): SdsAnnotationCall | undefined => {
140+
return annotationCallsOrEmpty(node).find((it) => {
141+
const actual = it.annotation?.ref;
142+
return actual === expected;
143+
});
144+
};
145+
124146
export const argumentsOrEmpty = (node: SdsAbstractCall | undefined): SdsArgument[] => {
125147
return node?.argumentList?.arguments ?? [];
126148
};

0 commit comments

Comments
 (0)