|
1 | 1 | import {
|
| 2 | + isSdsEnumVariant, |
2 | 3 | isSdsWildcard,
|
3 | 4 | SdsAnnotation,
|
| 5 | + SdsAnnotationCall, |
4 | 6 | SdsAssignment,
|
| 7 | + SdsCall, |
5 | 8 | SdsClassBody,
|
6 | 9 | SdsConstraintList,
|
7 | 10 | SdsEnumBody,
|
8 | 11 | SdsEnumVariant,
|
9 | 12 | SdsFunction,
|
| 13 | + SdsMemberAccess, |
| 14 | + SdsNamedType, |
10 | 15 | SdsSegment,
|
11 | 16 | SdsTypeParameterList,
|
12 | 17 | SdsUnionType,
|
13 | 18 | } from '../generated/ast.js';
|
14 | 19 | import { ValidationAcceptor } from 'langium';
|
15 | 20 | import { isEmpty } from 'radash';
|
| 21 | +import { isRequiredParameter, parametersOrEmpty, typeParametersOrEmpty } from '../helpers/nodeProperties.js'; |
| 22 | +import { SafeDsServices } from '../safe-ds-module.js'; |
| 23 | +import { UnknownType } from '../typing/model.js'; |
16 | 24 |
|
17 | 25 | export const CODE_STYLE_UNNECESSARY_ASSIGNMENT = 'style/unnecessary-assignment';
|
18 | 26 | export const CODE_STYLE_UNNECESSARY_ARGUMENT_LIST = 'style/unnecessary-argument-list';
|
19 | 27 | export const CODE_STYLE_UNNECESSARY_BODY = 'style/unnecessary-body';
|
20 | 28 | export const CODE_STYLE_UNNECESSARY_CONSTRAINT_LIST = 'style/unnecessary-constraint-list';
|
21 | 29 | export const CODE_STYLE_UNNECESSARY_ELVIS_OPERATOR = 'style/unnecessary-elvis-operator';
|
22 |
| -export const CODE_STYLE_UNNECESSARY_SAFE_ACCESS = 'style/unnecessary-safe-access'; |
23 | 30 | export const CODE_STYLE_UNNECESSARY_PARAMETER_LIST = 'style/unnecessary-parameter-list';
|
24 | 31 | export const CODE_STYLE_UNNECESSARY_RESULT_LIST = 'style/unnecessary-result-list';
|
| 32 | +export const CODE_STYLE_UNNECESSARY_SAFE_ACCESS = 'style/unnecessary-safe-access'; |
25 | 33 | export const CODE_STYLE_UNNECESSARY_TYPE_ARGUMENT_LIST = 'style/unnecessary-type-argument-list';
|
26 | 34 | export const CODE_STYLE_UNNECESSARY_TYPE_PARAMETER_LIST = 'style/unnecessary-type-parameter-list';
|
27 | 35 | export const CODE_STYLE_UNNECESSARY_UNION_TYPE = 'style/unnecessary-union-type';
|
28 | 36 |
|
29 | 37 | // -----------------------------------------------------------------------------
|
30 |
| -// Unnecessary assignment |
| 38 | +// Unnecessary argument lists |
| 39 | +// ----------------------------------------------------------------------------- |
| 40 | + |
| 41 | +export const annotationCallArgumentListShouldBeNeeded = (node: SdsAnnotationCall, accept: ValidationAcceptor): void => { |
| 42 | + const argumentList = node.argumentList; |
| 43 | + if (!argumentList || !isEmpty(argumentList.arguments)) { |
| 44 | + // If there are arguments, they are either needed or erroneous (i.e. we already show an error) |
| 45 | + return; |
| 46 | + } |
| 47 | + |
| 48 | + const annotation = node.annotation?.ref; |
| 49 | + if (!annotation) { |
| 50 | + return; |
| 51 | + } |
| 52 | + |
| 53 | + const hasRequiredParameters = parametersOrEmpty(annotation).some(isRequiredParameter); |
| 54 | + if (!hasRequiredParameters) { |
| 55 | + accept('info', 'This argument list can be removed.', { |
| 56 | + node: argumentList, |
| 57 | + code: CODE_STYLE_UNNECESSARY_ARGUMENT_LIST, |
| 58 | + }); |
| 59 | + } |
| 60 | +}; |
| 61 | + |
| 62 | +export const callArgumentListShouldBeNeeded = |
| 63 | + (services: SafeDsServices) => |
| 64 | + (node: SdsCall, accept: ValidationAcceptor): void => { |
| 65 | + const argumentList = node.argumentList; |
| 66 | + if (!argumentList || !isEmpty(argumentList.arguments)) { |
| 67 | + // If there are arguments, they are either needed or erroneous (i.e. we already show an error) |
| 68 | + return; |
| 69 | + } |
| 70 | + |
| 71 | + const callable = services.helpers.NodeMapper.callToCallableOrUndefined(node); |
| 72 | + if (!isSdsEnumVariant(callable)) { |
| 73 | + return; |
| 74 | + } |
| 75 | + |
| 76 | + if (isEmpty(parametersOrEmpty(callable))) { |
| 77 | + accept('info', 'This argument list can be removed.', { |
| 78 | + node: argumentList, |
| 79 | + code: CODE_STYLE_UNNECESSARY_ARGUMENT_LIST, |
| 80 | + }); |
| 81 | + } |
| 82 | + }; |
| 83 | + |
| 84 | +// ----------------------------------------------------------------------------- |
| 85 | +// Unnecessary assignments |
31 | 86 | // -----------------------------------------------------------------------------
|
32 | 87 |
|
33 | 88 | export const assignmentShouldHaveMoreThanWildcardsAsAssignees = (
|
@@ -66,7 +121,7 @@ export const enumBodyShouldNotBeEmpty = (node: SdsEnumBody, accept: ValidationAc
|
66 | 121 | };
|
67 | 122 |
|
68 | 123 | // -----------------------------------------------------------------------------
|
69 |
| -// Unnecessary constraint list |
| 124 | +// Unnecessary constraint lists |
70 | 125 | // -----------------------------------------------------------------------------
|
71 | 126 |
|
72 | 127 | export const constraintListShouldNotBeEmpty = (node: SdsConstraintList, accept: ValidationAcceptor) => {
|
@@ -126,6 +181,54 @@ export const segmentResultListShouldNotBeEmpty = (node: SdsSegment, accept: Vali
|
126 | 181 | }
|
127 | 182 | };
|
128 | 183 |
|
| 184 | +// ----------------------------------------------------------------------------- |
| 185 | +// Unnecessary safe access |
| 186 | +// ----------------------------------------------------------------------------- |
| 187 | + |
| 188 | +export const memberAccessNullSafetyShouldBeNeeded = |
| 189 | + (services: SafeDsServices) => |
| 190 | + (node: SdsMemberAccess, accept: ValidationAcceptor): void => { |
| 191 | + if (!node.isNullSafe) { |
| 192 | + return; |
| 193 | + } |
| 194 | + |
| 195 | + const receiverType = services.types.TypeComputer.computeType(node.receiver); |
| 196 | + if (receiverType === UnknownType) { |
| 197 | + return; |
| 198 | + } |
| 199 | + |
| 200 | + if (!receiverType.isNullable) { |
| 201 | + accept('info', 'The receiver is never null, so the safe access is unnecessary.', { |
| 202 | + node, |
| 203 | + code: CODE_STYLE_UNNECESSARY_SAFE_ACCESS, |
| 204 | + }); |
| 205 | + } |
| 206 | + }; |
| 207 | + |
| 208 | +// ----------------------------------------------------------------------------- |
| 209 | +// Unnecessary type argument lists |
| 210 | +// ----------------------------------------------------------------------------- |
| 211 | + |
| 212 | +export const namedTypeTypeArgumentListShouldBeNeeded = (node: SdsNamedType, accept: ValidationAcceptor): void => { |
| 213 | + const typeArgumentList = node.typeArgumentList; |
| 214 | + if (!typeArgumentList || !isEmpty(typeArgumentList.typeArguments)) { |
| 215 | + // If there are type arguments, they are either needed or erroneous (i.e. we already show an error) |
| 216 | + return; |
| 217 | + } |
| 218 | + |
| 219 | + const namedTypeDeclaration = node.declaration?.ref; |
| 220 | + if (!namedTypeDeclaration) { |
| 221 | + return; |
| 222 | + } |
| 223 | + |
| 224 | + if (isEmpty(typeParametersOrEmpty(namedTypeDeclaration))) { |
| 225 | + accept('info', 'This type argument list can be removed.', { |
| 226 | + node: typeArgumentList, |
| 227 | + code: CODE_STYLE_UNNECESSARY_ARGUMENT_LIST, |
| 228 | + }); |
| 229 | + } |
| 230 | +}; |
| 231 | + |
129 | 232 | // -----------------------------------------------------------------------------
|
130 | 233 | // Unnecessary type parameter lists
|
131 | 234 | // -----------------------------------------------------------------------------
|
|
0 commit comments