Skip to content

Commit ce70be9

Browse files
committed
Enhance the 'positional_parameters' rule
Now the rule flags sole actuals when all other formals have a default value.
1 parent 111e1bc commit ce70be9

File tree

7 files changed

+92
-39
lines changed

7 files changed

+92
-39
lines changed

lkql_checker/doc/generated/predefined_rules.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4055,6 +4055,9 @@ except for the following:
40554055
* Parameters of prefix or infix calls to operator functions are not flagged;
40564056
* If the called subprogram or entry has only one formal parameter,
40574057
the parameter of the call is not flagged;
4058+
* If call expression only carries one actual parameter, corresponding formal
4059+
parameter doesn't have a default value, and all other formal parameters do,
4060+
then the sole actual is not flagged.
40584061
* If a subprogram call uses the *Object.Operation* notation, then
40594062
* the first parameter (that is, *Object*) is not flagged;
40604063

lkql_checker/share/lkql/positional_parameters.lkql

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1-
fun check_actual_param(spec, check_dot) =
2-
match spec
3-
| SubpSpec => {
4-
val num_params = (
5-
from spec.f_subp_params?.f_params select DefiningName
6-
).length;
7-
num_params > 2 or (num_params > 1 and not check_dot)
1+
import stdlib
2+
3+
fun should_be_named(param_assoc, call_expr, check_dot) = {
4+
val formals = stdlib.get_formals(call_expr.p_called_subp_spec());
5+
if formals.length > 2 or (formals.length > 1 and not check_dot)
6+
then {
7+
val param_defining_name = stdlib.get_parameter(call_expr.p_call_params(), param_assoc.f_r_expr);
8+
call_expr.f_suffix.children.length > 1
9+
or stdlib.any([
10+
{
11+
val default_expr = formal.param_spec.f_default_expr;
12+
if formal.name == param_defining_name
13+
then default_expr != null
14+
else default_expr == null
15+
}
16+
for formal in formals
17+
])
818
}
9-
| EntrySpec => spec.f_entry_params.f_params[2] != null
10-
| * => false
19+
else false
20+
}
1121

1222
fun add_param_name(param, ctx) =
1323
ctx.set_child(
@@ -27,6 +37,9 @@ fun positional_parameters(node, all=false) =
2737
|" * Parameters of prefix or infix calls to operator functions are not flagged;
2838
|" * If the called subprogram or entry has only one formal parameter,
2939
|" the parameter of the call is not flagged;
40+
|" * If call expression only carries one actual parameter, corresponding formal
41+
|" parameter doesn't have a default value, and all other formal parameters do,
42+
|" then the sole actual is not flagged.
3043
|" * If a subprogram call uses the *Object.Operation* notation, then
3144
|" * the first parameter (that is, *Object*) is not flagged;
3245
|"
@@ -74,10 +87,6 @@ fun positional_parameters(node, all=false) =
7487
p_is_call(): true,
7588
f_name: not AttributeRef,
7689
f_name: id@*(p_is_operator_name(): false) when (
77-
all
78-
or check_actual_param(
79-
c.p_called_subp_spec(),
80-
id.p_is_dot_call()
81-
)
90+
all or should_be_named(node, c, id.p_is_dot_call())
8291
)
8392
)

lkql_checker/share/lkql/stdlib.lkql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,17 @@ fun get_parameter(params, actual) =
644644
find(params, actual, params.length)
645645
}
646646

647+
fun get_formals(subp_spec) =
648+
|" Given a SubpSpec node, return a list of all its formal parameter
649+
|" defining names, each one associated to its ParamSpec node.
650+
concat([
651+
[
652+
{name: name, param_spec: param_spec}
653+
for name in from param_spec select DefiningName
654+
].to_list
655+
for param_spec in subp_spec.p_params()
656+
].to_list)
657+
647658
@memoized
648659
fun strip_conversions(node) =
649660
|" Strip ``ParenExpr``, ``QualExpr`` and type conversions

testsuite/tests/checks/positional_parameters/pack.ads

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package Pack is
1515
entry E1 (I : Integer; J : Integer);
1616
entry E2 (Boolean) (I : Integer; J : Integer);
1717
entry E3 (Boolean);
18+
entry E4 (I : Integer; J : Integer := 5);
1819
end T;
1920

2021
end Pack;

testsuite/tests/checks/positional_parameters/pos.adb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ procedure Pos is
1010

1111
procedure Proc1 (I : Integer) with Import;
1212
procedure Proc2 (I : Integer; B : Boolean := True) with Import;
13+
procedure Proc3 (X, Y : Integer := 0) with Import;
14+
procedure Proc4 (X : Integer; Y, Z : Integer := 0) with Import;
15+
procedure Proc5 (X : Integer; Y : Integer := 0) with Import;
1316

1417
function Fun1 (I : Integer) return Integer with Import;
1518
function Fun2 (I : Integer; J : Integer) return Integer with Import;
@@ -33,17 +36,23 @@ begin
3336
T.E1 (10, 11); -- FLAG (2)
3437
T.E2 (True) (10, 11); -- FLAG (2)
3538
T.E3 (True); -- NOFLAG
39+
T.E4 (10); -- NOFLAG
40+
T.E4 (10, 11); -- FLAG (2)
3641

3742
-- Function calls
3843
I := Fun1 (J); -- NOFLAG because ALL is not set
3944
I := Fun2 (J, K); -- FLAG (2)
40-
I := Fun2_Default (J); -- FLAG
45+
I := Fun2_Default (J); -- NOFLAG
4146
I := Fun2 (I => 1, J => 2); -- NOFLAG
4247

4348
-- Procedure calls
4449
Proc1 (I); -- NOFLAG because ALL is not set
45-
Proc2 (I); -- FLAG
50+
Proc2 (I); -- NOFLAG
4651
Proc2 (I => 1, B => A); -- NOFLAG
52+
Proc3 (I); -- FLAG
53+
Proc4 (1); -- NOFLAG
54+
Proc4 (1, Y => 2); -- FLAG
55+
Proc5 (1); -- NOFLAG
4756

4857
-- Prefix notation
4958
Var_T.T_Proc1; -- NOFLAG
@@ -54,4 +63,3 @@ begin
5463
Var_T.T_Proc3 (10); -- FLAG
5564
Var_T.T_Proc3 (Y => 10); -- NOFLAG
5665
end Pos;
57-

testsuite/tests/checks/positional_parameters/test.out

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,45 @@
1-
pos.adb:33:10: rule violation: positional parameter association
2-
33 | T.E1 (10, 11); -- FLAG (2)
1+
pos.adb:36:10: rule violation: positional parameter association
2+
36 | T.E1 (10, 11); -- FLAG (2)
33
| ^^
44

5-
pos.adb:33:14: rule violation: positional parameter association
6-
33 | T.E1 (10, 11); -- FLAG (2)
5+
pos.adb:36:14: rule violation: positional parameter association
6+
36 | T.E1 (10, 11); -- FLAG (2)
77
| ^^
88

9-
pos.adb:34:17: rule violation: positional parameter association
10-
34 | T.E2 (True) (10, 11); -- FLAG (2)
9+
pos.adb:37:17: rule violation: positional parameter association
10+
37 | T.E2 (True) (10, 11); -- FLAG (2)
1111
| ^^
1212

13-
pos.adb:34:21: rule violation: positional parameter association
14-
34 | T.E2 (True) (10, 11); -- FLAG (2)
13+
pos.adb:37:21: rule violation: positional parameter association
14+
37 | T.E2 (True) (10, 11); -- FLAG (2)
1515
| ^^
1616

17-
pos.adb:39:15: rule violation: positional parameter association
18-
39 | I := Fun2 (J, K); -- FLAG (2)
17+
pos.adb:40:10: rule violation: positional parameter association
18+
40 | T.E4 (10, 11); -- FLAG (2)
19+
| ^^
20+
21+
pos.adb:40:14: rule violation: positional parameter association
22+
40 | T.E4 (10, 11); -- FLAG (2)
23+
| ^^
24+
25+
pos.adb:44:15: rule violation: positional parameter association
26+
44 | I := Fun2 (J, K); -- FLAG (2)
1927
| ^
2028

21-
pos.adb:39:18: rule violation: positional parameter association
22-
39 | I := Fun2 (J, K); -- FLAG (2)
29+
pos.adb:44:18: rule violation: positional parameter association
30+
44 | I := Fun2 (J, K); -- FLAG (2)
2331
| ^
2432

25-
pos.adb:40:23: rule violation: positional parameter association
26-
40 | I := Fun2_Default (J); -- FLAG
27-
| ^
33+
pos.adb:52:11: rule violation: positional parameter association
34+
52 | Proc3 (I); -- FLAG
35+
| ^
2836

29-
pos.adb:45:11: rule violation: positional parameter association
30-
45 | Proc2 (I); -- FLAG
37+
pos.adb:54:11: rule violation: positional parameter association
38+
54 | Proc4 (1, Y => 2); -- FLAG
3139
| ^
3240

33-
pos.adb:54:19: rule violation: positional parameter association
34-
54 | Var_T.T_Proc3 (10); -- FLAG
41+
pos.adb:63:19: rule violation: positional parameter association
42+
63 | Var_T.T_Proc3 (10); -- FLAG
3543
| ^^
3644

3745
Patched "pos.adb":
@@ -49,6 +57,9 @@ procedure Pos is
4957

5058
procedure Proc1 (I : Integer) with Import;
5159
procedure Proc2 (I : Integer; B : Boolean := True) with Import;
60+
procedure Proc3 (X, Y : Integer := 0) with Import;
61+
procedure Proc4 (X : Integer; Y, Z : Integer := 0) with Import;
62+
procedure Proc5 (X : Integer; Y : Integer := 0) with Import;
5263

5364
function Fun1 (I : Integer) return Integer with Import;
5465
function Fun2 (I : Integer; J : Integer) return Integer with Import;
@@ -72,17 +83,23 @@ begin
7283
T.E1 (I=>10, J=>11); -- FLAG (2)
7384
T.E2 (True) (I=>10, J=>11); -- FLAG (2)
7485
T.E3 (True); -- NOFLAG
86+
T.E4 (10); -- NOFLAG
87+
T.E4 (I=>10, J=>11); -- FLAG (2)
7588

7689
-- Function calls
7790
I := Fun1 (J); -- NOFLAG because ALL is not set
7891
I := Fun2 (I=>J, J=>K); -- FLAG (2)
79-
I := Fun2_Default (I=>J); -- FLAG
92+
I := Fun2_Default (J); -- NOFLAG
8093
I := Fun2 (I => 1, J => 2); -- NOFLAG
8194

8295
-- Procedure calls
8396
Proc1 (I); -- NOFLAG because ALL is not set
84-
Proc2 (I=>I); -- FLAG
97+
Proc2 (I); -- NOFLAG
8598
Proc2 (I => 1, B => A); -- NOFLAG
99+
Proc3 (X=>I); -- FLAG
100+
Proc4 (1); -- NOFLAG
101+
Proc4 (X=>1, Y => 2); -- FLAG
102+
Proc5 (1); -- NOFLAG
86103

87104
-- Prefix notation
88105
Var_T.T_Proc1; -- NOFLAG
@@ -94,4 +111,3 @@ begin
94111
Var_T.T_Proc3 (Y => 10); -- NOFLAG
95112
end Pos;
96113

97-

user_manual/generated/stdlib.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ Functions
6161
Return the full view of the root type of ``t``, traversing subtypes,
6262
derivations and privacy.
6363

64+
.. function:: get_formals(subp_spec)
65+
66+
Given a SubpSpec node, return a list of all its formal parameter
67+
defining names, each one associated to its ParamSpec node.
68+
6469
.. function:: get_parameter(params, actual)
6570

6671
Given a ``List[ParamActual]``, return the parameter corresponding to

0 commit comments

Comments
 (0)