Skip to content

Commit 516923e

Browse files
hoe-jocastler
authored andcommitted
[plantuml] enable default template
1 parent 8bac4c9 commit 516923e

8 files changed

Lines changed: 312 additions & 1 deletion

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
' *******************************************************************************
2+
' Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
'
4+
' See the NOTICE file(s) distributed with this work for additional
5+
' information regarding copyright ownership.
6+
'
7+
' This program and the accompanying materials are made available under the
8+
' terms of the Apache License Version 2.0 which is available at
9+
' https://www.apache.org/licenses/LICENSE-2.0
10+
'
11+
' SPDX-License-Identifier: Apache-2.0
12+
' *******************************************************************************
13+
@startuml empty_template_args
14+
15+
class Skeleton {
16+
+ OnFinished(const safecpp::Scope<>& scope, std::less<> comparator): Result<void>
17+
+ scope : safecpp::Scope<>
18+
}
19+
20+
@enduml
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"empty_template_args.puml": {
3+
"name": "empty_template_args",
4+
"entities": [
5+
{
6+
"id": "Skeleton",
7+
"name": "Skeleton",
8+
"enclosing_namespace_id": null,
9+
"entity_type": "Class",
10+
"type_aliases": [],
11+
"methods": [
12+
{
13+
"name": "OnFinished",
14+
"return_type": "Result<void>",
15+
"visibility": "public",
16+
"parameters": [
17+
{
18+
"name": "scope",
19+
"param_type": "const safecpp::Scope<>&",
20+
"is_variadic": false,
21+
"is_pack_expansion": false
22+
},
23+
{
24+
"name": "comparator",
25+
"param_type": "std::less<>",
26+
"is_variadic": false,
27+
"is_pack_expansion": false
28+
}
29+
],
30+
"template_parameters": null,
31+
"modifiers": [],
32+
"source_location": {
33+
"file": "",
34+
"line": 16
35+
}
36+
}
37+
],
38+
"template_parameters": null,
39+
"enum_literals": [],
40+
"variables": [
41+
{
42+
"name": "scope",
43+
"data_type": "safecpp::Scope<>",
44+
"visibility": "public",
45+
"is_static": false,
46+
"source_location": {
47+
"file": "",
48+
"line": 17
49+
}
50+
}
51+
],
52+
"relationships": [],
53+
"source_location": {
54+
"file": "plantuml/parser/integration_test/class_diagram/empty_template_args/empty_template_args.puml",
55+
"line": 15
56+
}
57+
}
58+
]
59+
}
60+
}

‎plantuml/parser/puml_parser/src/class_diagram/src/class_parser.rs‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,71 @@ mod tests {
13351335
assert_eq!(class_def.attributes[0].source_location.line, 3);
13361336
}
13371337

1338+
fn parse_single_class_member_file(member: &str) -> Result<ClassUmlFile, ClassError> {
1339+
let input = format!("@startuml\nclass A {{\n {member}\n}}\n@enduml\n");
1340+
let mut parser = PumlClassParser;
1341+
parser.parse_file(
1342+
&std::rc::Rc::new(std::path::PathBuf::from("test.puml")),
1343+
&input,
1344+
LogLevel::Info,
1345+
)
1346+
}
1347+
1348+
#[test]
1349+
fn test_parse_empty_template_args_in_types() {
1350+
let result = parse_single_class_member_file(
1351+
"+Run(const safecpp::Scope<>& scope, std::vector<Foo<>> items): Bar<>",
1352+
)
1353+
.unwrap();
1354+
1355+
let ClassUmlTopLevel::Types(Element::ClassDef(class_def)) = &result.elements[0] else {
1356+
panic!("expected class element");
1357+
};
1358+
1359+
let method = &class_def.methods[0];
1360+
assert_eq!(
1361+
method.params[0].param_type.as_deref(),
1362+
Some("const safecpp::Scope<>&")
1363+
);
1364+
assert_eq!(
1365+
method.params[1].param_type.as_deref(),
1366+
Some("std::vector<Foo<>>")
1367+
);
1368+
assert_eq!(method.r#type.as_deref(), Some("Bar<>"));
1369+
}
1370+
1371+
#[test]
1372+
fn test_parse_empty_template_args_in_attribute() {
1373+
let result = parse_single_class_member_file("+scope : safecpp::Scope<>").unwrap();
1374+
1375+
let ClassUmlTopLevel::Types(Element::ClassDef(class_def)) = &result.elements[0] else {
1376+
panic!("expected class element");
1377+
};
1378+
1379+
assert_eq!(
1380+
class_def.attributes[0].r#type.as_deref(),
1381+
Some("safecpp::Scope<>")
1382+
);
1383+
}
1384+
1385+
#[test]
1386+
fn test_parse_const_qualifier_after_empty_template_args() {
1387+
let result = parse_single_class_member_file("+Get(): Foo<> <<const>>").unwrap();
1388+
1389+
let ClassUmlTopLevel::Types(Element::ClassDef(class_def)) = &result.elements[0] else {
1390+
panic!("expected class element");
1391+
};
1392+
1393+
assert_eq!(class_def.methods[0].r#type.as_deref(), Some("Foo<>"));
1394+
assert_eq!(class_def.methods[0].modifiers, vec!["<<const>>"]);
1395+
}
1396+
1397+
#[test]
1398+
fn test_parse_malformed_template_args_rejected() {
1399+
assert!(parse_single_class_member_file("+f(Foo<int, > a)").is_err());
1400+
assert!(parse_single_class_member_file("+f(Foo<<int>> a)").is_err());
1401+
}
1402+
13381403
#[test]
13391404
fn test_parse_type_alias_source_location() {
13401405
let input = r#"@startuml

‎plantuml/parser/puml_parser/src/class_diagram/test/integration_test.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ fn test_param_templete() {
220220
run_class_diagram_parser_case("param_templete");
221221
}
222222

223+
#[test]
224+
fn test_empty_template_args() {
225+
run_class_diagram_parser_case("empty_template_args");
226+
}
227+
223228
#[test]
224229
fn test_relationship_arrows() {
225230
run_class_diagram_parser_case("relationship_arrows");

‎plantuml/parser/puml_parser/src/grammar/class.pest‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type_expr = { brace_enclosed_type | const_prefix* ~ prefix_array_prefix* ~ quali
3030

3131
qualified_type = @{ ("::")? ~ identifier ~ (("::" | (!".." ~ ".")) ~ identifier)* }
3232

33-
generic_type_args = { "<" ~ !"<" ~ type_arg ~ ("," ~ type_arg)* ~ ">" }
33+
generic_type_args = { "<" ~ !"<" ~ (type_arg ~ ("," ~ type_arg)*)? ~ ">" }
3434

3535
type_arg = { type_expr | NUMBER }
3636
type_expr_list = { type_expr ~ ("," ~ type_expr)* }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
' *******************************************************************************
2+
' Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
'
4+
' See the NOTICE file(s) distributed with this work for additional
5+
' information regarding copyright ownership.
6+
'
7+
' This program and the accompanying materials are made available under the
8+
' terms of the Apache License Version 2.0 which is available at
9+
' https://www.apache.org/licenses/LICENSE-2.0
10+
'
11+
' SPDX-License-Identifier: Apache-2.0
12+
' *******************************************************************************
13+
@startuml empty_template_args
14+
15+
class "lola::SkeletonMethod" as lola_SkeletonMethod {
16+
+OnProxyMethodSubscribeFinished(std::optional<span<std::byte>>, const safecpp::Scope<>&, uid_t uid): Result<void>
17+
+Compare(std::less<> comparator)
18+
+GetScope(): safecpp::Scope<>
19+
+Wrap(std::vector<Foo<>> items, Bar<Baz<>, int>* ptr)
20+
+Stop() <<const>>
21+
+scope : safecpp::Scope<>
22+
}
23+
24+
@enduml
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
{
2+
"empty_template_args.puml": {
3+
"name": "empty_template_args",
4+
"elements": [
5+
{
6+
"Types": {
7+
"ClassDef": {
8+
"name": {
9+
"internal": "lola::SkeletonMethod",
10+
"display": "lola_SkeletonMethod"
11+
},
12+
"namespace": "",
13+
"package": "",
14+
"source_location": {
15+
"file": "",
16+
"line": 15
17+
},
18+
"is_abstract": false,
19+
"type_aliases": [],
20+
"attributes": [
21+
{
22+
"visibility": "Public",
23+
"name": "scope",
24+
"type": "safecpp::Scope<>",
25+
"modifiers": [],
26+
"source_location": {
27+
"file": "",
28+
"line": 21
29+
}
30+
}
31+
],
32+
"methods": [
33+
{
34+
"visibility": "Public",
35+
"name": "OnProxyMethodSubscribeFinished",
36+
"template_parameters": null,
37+
"params": [
38+
{
39+
"name": null,
40+
"param_type": "std::optional<span<std::byte>>"
41+
},
42+
{
43+
"name": null,
44+
"param_type": "const safecpp::Scope<>&"
45+
},
46+
{
47+
"name": "uid",
48+
"param_type": "uid_t"
49+
}
50+
],
51+
"type": "Result<void>",
52+
"modifiers": [],
53+
"source_location": {
54+
"file": "",
55+
"line": 16
56+
}
57+
},
58+
{
59+
"visibility": "Public",
60+
"name": "Compare",
61+
"template_parameters": null,
62+
"params": [
63+
{
64+
"name": "comparator",
65+
"param_type": "std::less<>"
66+
}
67+
],
68+
"type": null,
69+
"modifiers": [],
70+
"source_location": {
71+
"file": "",
72+
"line": 17
73+
}
74+
},
75+
{
76+
"visibility": "Public",
77+
"name": "GetScope",
78+
"template_parameters": null,
79+
"params": [],
80+
"type": "safecpp::Scope<>",
81+
"modifiers": [],
82+
"source_location": {
83+
"file": "",
84+
"line": 18
85+
}
86+
},
87+
{
88+
"visibility": "Public",
89+
"name": "Wrap",
90+
"template_parameters": null,
91+
"params": [
92+
{
93+
"name": "items",
94+
"param_type": "std::vector<Foo<>>"
95+
},
96+
{
97+
"name": "ptr",
98+
"param_type": "Bar<Baz<>, int>*"
99+
}
100+
],
101+
"type": null,
102+
"modifiers": [],
103+
"source_location": {
104+
"file": "",
105+
"line": 19
106+
}
107+
},
108+
{
109+
"visibility": "Public",
110+
"name": "Stop",
111+
"template_parameters": null,
112+
"params": [],
113+
"type": null,
114+
"modifiers": [
115+
"<<const>>"
116+
],
117+
"source_location": {
118+
"file": "",
119+
"line": 20
120+
}
121+
}
122+
],
123+
"template_parameters": null,
124+
"extends": [],
125+
"implements": []
126+
}
127+
}
128+
}
129+
],
130+
"relationships": []
131+
}
132+
}

‎plantuml/parser/puml_resolver/src/class_diagram/test/class_resolver_test.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,8 @@ fn test_c_variadic_method() {
126126
fn test_class_template_pack() {
127127
run_class_resolver_case("class_template_pack");
128128
}
129+
130+
#[test]
131+
fn test_empty_template_args() {
132+
run_class_resolver_case("empty_template_args");
133+
}

0 commit comments

Comments
 (0)