Skip to content

Commit 34e7bb4

Browse files
committed
Fix unmunch for template arguments
Fixes #147.
1 parent 4c40bb7 commit 34e7bb4

10 files changed

+67
-36
lines changed

src/libclang/class_parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ void add_base_class(cpp_class::builder& builder, const detail::parse_context& co
115115
else
116116
detail::skip_if(stream, to_string(access));
117117

118-
auto name = detail::to_string(stream, stream.end()).as_string();
118+
auto name = detail::to_string(stream, stream.end(), false).as_string();
119119

120120
auto type = detail::parse_type(context, class_cur, clang_getCursorType(cur));
121121
auto& base = builder.base_class(std::move(name), std::move(type), access, is_virtual);

src/libclang/concept_parser.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ std::unique_ptr<cpp_entity> detail::try_parse_cpp_concept(const detail::parse_co
2424
if (stream.peek() != "<")
2525
return nullptr;
2626

27-
28-
auto closing_bracket_iter = detail::find_closing_bracket(stream);
29-
auto params = to_string(stream, closing_bracket_iter);
27+
auto closing_bracket = detail::find_closing_bracket(stream);
28+
auto params = to_string(stream, closing_bracket.bracket, closing_bracket.unmunch);
3029

3130
if (!detail::skip_if(stream, ">"))
3231
return nullptr;

src/libclang/cxtokenizer.cpp

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
#include "libclang_visitor.hpp"
99
#include "parse_error.hpp"
1010

11-
#include <iostream> // TODO
12-
1311
using namespace cppast;
1412

1513
detail::cxtoken::cxtoken(const CXTranslationUnit& tu_unit, const CXToken& token)
@@ -474,7 +472,7 @@ bool is_comparison(CXTokenKind last_kind, const detail::cxtoken& cur, CXTokenKin
474472
}
475473
} // namespace
476474

477-
detail::cxtoken_iterator detail::find_closing_bracket(detail::cxtoken_stream stream)
475+
detail::closing_bracket_pos detail::find_closing_bracket(detail::cxtoken_stream stream)
478476
{
479477
auto template_bracket = false;
480478
auto open_bracket = stream.peek().c_str();
@@ -494,11 +492,14 @@ detail::cxtoken_iterator detail::find_closing_bracket(detail::cxtoken_stream str
494492
DEBUG_UNREACHABLE(parse_error_handler{}, stream.cursor(),
495493
format("expected a bracket, got '", stream.peek().c_str(), "'"));
496494

497-
auto bracket_count = 1;
498-
auto paren_count = 0; // internal nested parenthesis
499-
auto last_token = CXToken_Comment;
495+
auto bracket_count = 1;
496+
auto paren_count = 0; // internal nested parenthesis
497+
auto last_token = CXToken_Comment;
498+
auto last_was_double_angle = false;
500499
while (!stream.done() && bracket_count != 0)
501500
{
501+
last_was_double_angle = false;
502+
502503
auto& cur = stream.get();
503504
if (paren_count == 0 && cur == open_bracket
504505
&& !is_comparison(last_token, cur, stream.peek().kind()))
@@ -507,28 +508,37 @@ detail::cxtoken_iterator detail::find_closing_bracket(detail::cxtoken_stream str
507508
&& !is_comparison(last_token, cur, stream.peek().kind()))
508509
--bracket_count;
509510
else if (paren_count == 0 && template_bracket && cur == ">>")
511+
{
510512
// maximal munch
511513
bracket_count -= 2;
514+
last_was_double_angle = true;
515+
}
512516
else if (cur == "(" || cur == "{" || cur == "[")
513517
++paren_count;
514518
else if (cur == ")" || cur == "}" || cur == "]")
515519
--paren_count;
516520

517521
last_token = cur.kind();
518522
}
519-
stream.bump_back();
520-
// only check first parameter, token might be ">>"
521-
DEBUG_ASSERT(bracket_count == 0 && paren_count == 0
522-
&& stream.peek().value()[0] == close_bracket[0],
523-
parse_error_handler{}, stream.cursor(),
523+
DEBUG_ASSERT(bracket_count == 0 && paren_count == 0, parse_error_handler{}, stream.cursor(),
524524
"find_closing_bracket() internal parse error");
525-
return stream.cur();
525+
526+
if (last_was_double_angle)
527+
{
528+
return {stream.cur(), stream.cur(), true};
529+
}
530+
else
531+
{
532+
auto after = stream.cur();
533+
stream.bump_back();
534+
return {stream.cur(), after, false};
535+
}
526536
}
527537

528538
void detail::skip_brackets(detail::cxtoken_stream& stream)
529539
{
530540
auto closing = find_closing_bracket(stream);
531-
stream.set_cur(std::next(closing));
541+
stream.set_cur(closing.after);
532542
}
533543

534544
detail::cxtoken_iterator detail::find_sequence(detail::cxtoken_stream stream,
@@ -605,9 +615,9 @@ cpp_token_string parse_attribute_arguments(detail::cxtoken_stream& stream)
605615
auto end = find_closing_bracket(stream);
606616
skip(stream, "(");
607617

608-
auto arguments = detail::to_string(stream, end);
618+
auto arguments = detail::to_string(stream, end.bracket, end.unmunch);
619+
stream.set_cur(end.bracket);
609620

610-
stream.set_cur(end);
611621
skip(stream, ")");
612622

613623
return arguments;
@@ -769,7 +779,7 @@ cpp_token_kind get_kind(const detail::cxtoken& token)
769779
}
770780
} // namespace
771781

772-
cpp_token_string detail::to_string(cxtoken_stream& stream, cxtoken_iterator end)
782+
cpp_token_string detail::to_string(cxtoken_stream& stream, cxtoken_iterator end, bool unmunch)
773783
{
774784
cpp_token_string::builder builder;
775785

@@ -779,6 +789,9 @@ cpp_token_string detail::to_string(cxtoken_stream& stream, cxtoken_iterator end)
779789
builder.add_token(cpp_token(get_kind(token), token.c_str()));
780790
}
781791

792+
if (unmunch)
793+
builder.unmunch();
794+
782795
return builder.finish();
783796
}
784797

@@ -800,8 +813,8 @@ bool detail::append_scope(detail::cxtoken_stream& stream, std::string& scope)
800813
}
801814
else if (stream.peek() == "<")
802815
{
803-
auto iter = detail::find_closing_bracket(stream);
804-
scope += detail::to_string(stream, iter).as_string();
816+
auto pos = detail::find_closing_bracket(stream);
817+
scope += detail::to_string(stream, pos.bracket, pos.unmunch).as_string();
805818
if (!detail::skip_if(stream, ">>"))
806819
detail::skip(stream, ">");
807820
scope += ">";

src/libclang/cxtokenizer.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,19 @@ namespace detail
158158
// if multi_token == true, str can consist of multiple tokens optionally separated by whitespace
159159
bool skip_if(cxtoken_stream& stream, const char* str, bool multi_token = false);
160160

161+
struct closing_bracket_pos
162+
{
163+
// If unmunch == false: bracket points to the closing bracket, after is the iterator after
164+
// that. If unmunch == true: bracket points to >>, after points to the same >>; only one
165+
// bracket is part of the matching closing one.
166+
cxtoken_iterator bracket, after;
167+
bool unmunch;
168+
};
169+
161170
// returns the location of the closing bracket
162171
// the current token must be (,[,{ or <
163172
// note: < might not work in the arguments of a template specialization
164-
cxtoken_iterator find_closing_bracket(cxtoken_stream stream);
173+
closing_bracket_pos find_closing_bracket(cxtoken_stream stream);
165174

166175
// skips brackets
167176
// the current token must be (,[,{ or <
@@ -178,7 +187,7 @@ namespace detail
178187
cpp_attribute_list parse_attributes(cxtoken_stream& stream, bool skip_anyway = false);
179188

180189
// converts a token range to a string
181-
cpp_token_string to_string(cxtoken_stream& stream, cxtoken_iterator end);
190+
cpp_token_string to_string(cxtoken_stream& stream, cxtoken_iterator end, bool unmunch);
182191

183192
// appends token to scope, if it is still valid
184193
// else clears it

src/libclang/expression_parser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ std::unique_ptr<cpp_expression> detail::parse_expression(const detail::parse_con
1717
detail::cxtoken_stream stream(tokenizer, cur);
1818

1919
auto type = parse_type(context, cur, clang_getCursorType(cur));
20-
auto expr = to_string(stream, stream.end());
20+
auto expr = to_string(stream, stream.end(), false);
2121
if (kind == CXCursor_CallExpr && (expr.empty() || expr.back().spelling != ")"))
2222
{
2323
// we have a call expression that doesn't end in a closing parentheses
@@ -42,6 +42,6 @@ std::unique_ptr<cpp_expression> detail::parse_raw_expression(const parse_context
4242
if (stream.done())
4343
return nullptr;
4444

45-
auto expr = to_string(stream, std::prev(end)->value() == ";" ? std::prev(end) : end);
45+
auto expr = to_string(stream, std::prev(end)->value() == ";" ? std::prev(end) : end, false);
4646
return cpp_unexposed_expression::build(std::move(type), std::move(expr));
4747
}

src/libclang/function_parser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ std::unique_ptr<cpp_expression> parse_noexcept(detail::cxtoken_stream& stre
368368
auto closing = detail::find_closing_bracket(stream);
369369

370370
detail::skip(stream, "(");
371-
auto expr = detail::parse_raw_expression(context, stream, closing, std::move(type));
371+
auto expr = detail::parse_raw_expression(context, stream, closing.bracket, std::move(type));
372372
detail::skip(stream, ")");
373373

374374
return expr;
@@ -745,7 +745,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_
745745

746746
// read the type
747747
stream.set_cur(type_start);
748-
auto type_spelling = detail::to_string(stream, type_end).as_string();
748+
auto type_spelling = detail::to_string(stream, type_end, false).as_string();
749749

750750
// parse arguments again
751751
detail::skip(stream, "(");

src/libclang/parse_functions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ try
210210
// build unexposed entity
211211
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
212212
detail::cxtoken_stream stream(tokenizer, cur);
213-
auto spelling = detail::to_string(stream, stream.end());
213+
auto spelling = detail::to_string(stream, stream.end(), false);
214214
if (spelling.begin() + 1 == spelling.end() && spelling.front().spelling == ";")
215215
// unnecessary semicolon
216216
return nullptr;

src/libclang/template_parser.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ cpp_token_string extract_parameter_constraint(const detail::parse_context& conte
5454
detail::cxtoken_iterator found_start
5555
= detail::find_sequence(stream, target_range_start, target_range_end);
5656
if (found_start == stream.end())
57-
return detail::to_string(stream, stream.cur() + 1);
57+
return detail::to_string(stream, stream.cur() + 1, false);
5858

5959
stream.set_cur(found_start);
6060
stream.bump();
@@ -70,7 +70,7 @@ cpp_token_string extract_parameter_constraint(const detail::parse_context& conte
7070
stream.bump_back();
7171
}
7272
stream.bump();
73-
return detail::to_string(stream, constraint_end);
73+
return detail::to_string(stream, constraint_end, false);
7474
}
7575

7676
std::unique_ptr<cpp_template_parameter> parse_type_parameter(const detail::parse_context& context,
@@ -316,10 +316,10 @@ void parse_arguments(Builder& b, const detail::parse_context& context, const CXC
316316

317317
if (stream.peek() == "<")
318318
{
319-
auto iter = detail::find_closing_bracket(stream);
319+
auto closing = detail::find_closing_bracket(stream);
320320
stream.bump();
321321

322-
auto args = detail::to_string(stream, iter);
322+
auto args = detail::to_string(stream, closing.bracket, closing.unmunch);
323323
b.add_unexposed_arguments(std::move(args));
324324
}
325325
else

src/libclang/type_parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ std::unique_ptr<cpp_type> detail::parse_raw_type(const detail::parse_context&,
724724
detail::cxtoken_stream& stream,
725725
detail::cxtoken_iterator end)
726726
{
727-
auto result = detail::to_string(stream, end);
727+
auto result = detail::to_string(stream, end, false);
728728
return cpp_unexposed_type::build(result.as_string());
729729
}
730730

test/cpp_class_template.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ struct e
7373
template <>
7474
class a<int> {};
7575
76+
// full specialization with munch
77+
/// template<>
78+
/// class a<a<int>>{
79+
/// };
80+
template <>
81+
class a<a<int>> {};
82+
7683
/// template<>
7784
/// struct b<0,int>{
7885
/// };
@@ -245,7 +252,10 @@ template class a<int>;
245252
if (templ.is_full_specialization())
246253
{
247254
check_template_parameters(templ, {});
248-
REQUIRE(templ.unexposed_arguments().as_string() == "int");
255+
256+
auto args = templ.unexposed_arguments().as_string();
257+
if (args != "int" && args != "a<int>")
258+
FAIL("invalid args for specialization");
249259
}
250260
else
251261
{
@@ -273,5 +283,5 @@ template class a<int>;
273283
else
274284
REQUIRE(false);
275285
});
276-
REQUIRE(count == 6u);
286+
REQUIRE(count == 7u);
277287
}

0 commit comments

Comments
 (0)