Skip to content

Commit d097048

Browse files
authored
Add no_out_params_in_out_events rule (#53)
* Add no_out_params_in_out_events * also disallow inout * also mention inout in readme
1 parent 4d0122f commit d097048

9 files changed

Lines changed: 108 additions & 6 deletions

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ In interface behaviors, events should not mention any parameters, this is invali
181181

182182
---
183183

184+
## no_out_params_in_out_events
185+
186+
For `out` events, parameters cannot be `out` or `inout`, this will be rejected by Dezyne. Instead, the parameter should be marked `in`.
187+
188+
**Possible values:** "hint" | "warning" | **"error"**
189+
190+
---
191+
184192
## no_recursive_system
185193

186194
Systems cannot contain instances of themself.

src/config/default-config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const DEFAULT_DZNLINT_CONFIG: DefaultDznLintConfig = {
2121
no_empty_defer_capture: "warning",
2222
no_interface_event_parameters: "error",
2323
no_mismatching_binding_types: "error",
24+
no_out_params_in_out_events: "error",
2425
no_recursive_system: "error",
2526
no_shadowing: "warning",
2627
no_unconnected_ports: "error",

src/config/dznlint-configuration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface DznLintConfiguration {
3232
no_empty_defer_capture: ConfigValue;
3333
no_interface_event_parameters: ConfigValue;
3434
no_mismatching_binding_types: ConfigValue;
35+
no_out_params_in_out_events: ConfigValue;
3536
no_recursive_system: ConfigValue;
3637
no_shadowing: ConfigValue;
3738
no_unconnected_ports: ConfigValue;

src/grammar/ast.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export interface FunctionDefinition extends AstNode<SyntaxKind.FunctionDefinitio
207207
body: Compound | Expression;
208208
}
209209

210-
export type ParameterDirection = Keyword<"in"> | Keyword<"out">;
210+
export type ParameterDirection = Keyword<"in"> | Keyword<"out"> | Keyword<"inout">;
211211
export interface FunctionParameter extends AstNode<SyntaxKind.FunctionParameter> {
212212
direction?: ParameterDirection;
213213
type: TypeReference;

src/linting-rule.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import no_duplicate_port_binding from "./rules/no-duplicate-port-binding";
2828
import no_empty_defer_capture from "./rules/no-empty-defer-capture";
2929
import no_interface_event_parameters from "./rules/no-interface-event-parameters";
3030
import no_mismatching_binding_types from "./rules/no-mismatching-binding-types";
31+
import no_out_params_in_out_events from "./rules/no-out-params-in-out-events";
3132
import no_unconnected_ports from "./rules/no-unconnected-ports";
3233
import no_unknown_imports from "./rules/no-unknown-imports";
3334
import no_unknown_variables from "./rules/no-unknown-variables";
@@ -58,6 +59,7 @@ export function loadLinters(config: DznLintUserConfiguration) {
5859
no_empty_defer_capture,
5960
no_interface_event_parameters,
6061
no_mismatching_binding_types,
62+
no_out_params_in_out_events,
6163
no_recursive_system,
6264
no_shadowing,
6365
no_unconnected_ports,

src/rules/never-fired-event.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as ast from "../grammar/ast";
44
import { getRuleConfig } from "../config/util";
55
import { createDiagnosticsFactory, Diagnostic } from "../diagnostic";
66
import { RuleFactory } from "../linting-rule";
7-
import { isCallExpression, isIdentifier } from "../util";
7+
import { isCallExpression, isIdentifier, isOutEvent } from "../util";
88

99
export const neverFiredEvent = createDiagnosticsFactory();
1010

@@ -51,7 +51,3 @@ export const never_fired_event: RuleFactory = factoryContext => {
5151
});
5252
}
5353
};
54-
55-
function isOutEvent(node: ast.Event | ast.TypeDefinition): node is ast.Event {
56-
return node.kind === ast.SyntaxKind.Event && node.direction.text === "out";
57-
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// no identifiers used for bindings that are unknown
2+
3+
import * as ast from "../grammar/ast";
4+
import { Diagnostic } from "..";
5+
import { getRuleConfig } from "../config/util";
6+
import { createDiagnosticsFactory } from "../diagnostic";
7+
import { RuleFactory } from "../linting-rule";
8+
import { isInOutKeyword, isOutEvent, isOutKeyword } from "../util";
9+
10+
export const outParamInOutEvent = createDiagnosticsFactory();
11+
12+
export const no_out_params_in_out_events: RuleFactory = factoryContext => {
13+
const config = getRuleConfig("no_out_params_in_out_events", factoryContext.userConfig);
14+
15+
if (config.isEnabled) {
16+
factoryContext.registerRule<ast.Event>(ast.SyntaxKind.Event, (node, context) => {
17+
const diagnostics: Diagnostic[] = [];
18+
19+
if (isOutEvent(node)) {
20+
for (const param of node.parameters) {
21+
if (param.direction && isOutKeyword(param.direction)) {
22+
diagnostics.push(
23+
outParamInOutEvent(
24+
config.severity,
25+
"Not allowed to use 'out' parameters in out events, use 'in' instead",
26+
context.source,
27+
param.direction.position
28+
)
29+
);
30+
}
31+
if (param.direction && isInOutKeyword(param.direction)) {
32+
diagnostics.push(
33+
outParamInOutEvent(
34+
config.severity,
35+
"Not allowed to use 'inout' parameters in out events, use 'in' instead",
36+
context.source,
37+
param.direction.position
38+
)
39+
);
40+
}
41+
}
42+
}
43+
44+
return diagnostics;
45+
});
46+
}
47+
};
48+
49+
export default no_out_params_in_out_events;

src/util.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ export function isReplyKeyword(node: ast.AnyAstNode): node is ast.Keyword<"reply
211211
return isKeyword(node) && node.text === "reply";
212212
}
213213

214+
export function isInKeyword(node: ast.AnyAstNode): node is ast.Keyword<"in"> {
215+
return isKeyword(node) && node.text === "in";
216+
}
217+
218+
export function isOutKeyword(node: ast.AnyAstNode): node is ast.Keyword<"out"> {
219+
return isKeyword(node) && node.text === "out";
220+
}
221+
222+
export function isInOutKeyword(node: ast.AnyAstNode): node is ast.Keyword<"inout"> {
223+
return isKeyword(node) && node.text === "inout";
224+
}
225+
214226
// eslint-disable-next-line @typescript-eslint/no-explicit-any
215227
export function isKeyword(node: ast.AnyAstNode): node is ast.Keyword<any> {
216228
return node.kind === ast.SyntaxKind.Keyword;
@@ -272,6 +284,10 @@ export function isErrorNode(node: ast.AnyAstNode): node is ast.Error {
272284
return node.kind === ast.SyntaxKind.ERROR;
273285
}
274286

287+
export function isOutEvent(node: ast.AnyAstNode): node is ast.Event {
288+
return isEvent(node) && isOutKeyword(node.direction);
289+
}
290+
275291
export type ScopedBlock = ast.AnyAstNode &
276292
(
277293
| ast.Behavior
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { outParamInOutEvent } from "../src/rules/no-out-params-in-out-events";
2+
import { testdznlint } from "./util";
3+
4+
test("not allowed to have out params in out events", async () => {
5+
await testdznlint({
6+
diagnostic: outParamInOutEvent.code,
7+
pass: `
8+
extern MyExternType $$;
9+
interface I {
10+
out void ev(in MyExternType a);
11+
}`,
12+
fail: `
13+
extern MyExternType $$;
14+
interface I {
15+
out void ev(out MyExternType a);
16+
}`,
17+
});
18+
});
19+
20+
test("not allowed to have inout params in out events", async () => {
21+
await testdznlint({
22+
diagnostic: outParamInOutEvent.code,
23+
fail: `
24+
extern MyExternType $$;
25+
interface I {
26+
out void ev(inout MyExternType a);
27+
}`,
28+
});
29+
});

0 commit comments

Comments
 (0)