Skip to content

Commit

Permalink
[clang-format] Annotate noexcept, explicit specifiers as containing e…
Browse files Browse the repository at this point in the history
…xpressions

The noexcept specifier and explicit specifier can optionally include a
boolean expression to make these specifiers apply conditionally,
however, clang-format didn't set the context for the parenthesized
content of these specifiers, meaning they inherited the parent context,
which usually isn't an expressions, leading to misannotated binary
operators.

This patch applies expression context to the content of these
specifiers, making them similar to the static_assert keyword.

Fixes #44543

Reviewed By: owenpan, MyDeveloperDay

Differential Revision: https://reviews.llvm.org/D146284
  • Loading branch information
rymiel committed Mar 22, 2023
1 parent 16b7cf2 commit ead9644
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 3 deletions.
7 changes: 4 additions & 3 deletions clang/lib/Format/TokenAnnotator.cpp
Expand Up @@ -318,9 +318,10 @@ class AnnotatingParser {
// export type X = (...);
Contexts.back().IsExpression = false;
} else if (OpeningParen.Previous &&
(OpeningParen.Previous->isOneOf(tok::kw_static_assert,
tok::kw_while, tok::l_paren,
tok::comma, TT_BinaryOperator) ||
(OpeningParen.Previous->isOneOf(
tok::kw_static_assert, tok::kw_noexcept, tok::kw_explicit,
tok::kw_while, tok::l_paren, tok::comma,
TT_BinaryOperator) ||
OpeningParen.Previous->isIf())) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
Expand Down
4 changes: 4 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Expand Up @@ -11592,6 +11592,10 @@ TEST_F(FormatTest, UnderstandsRvalueReferences) {
verifyFormat("template <bool B, bool C> class A {\n"
" static_assert(B && C, \"Something is wrong\");\n"
"};");
verifyFormat("template <typename T> void swap() noexcept(Bar<T> && Foo<T>);");
verifyFormat("template <typename T> struct S {\n"
" explicit(Bar<T> && Foo<T>) S(const S &);\n"
"};");
verifyGoogleFormat("#define IF(a, b, c) if (a && (b == c))");
verifyGoogleFormat("#define WHILE(a, b, c) while (a && (b == c))");
verifyFormat("#define A(a, b) (a && b)");
Expand Down
11 changes: 11 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Expand Up @@ -242,6 +242,17 @@ TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmp) {
"}");
ASSERT_EQ(Tokens.size(), 12u) << Tokens;
EXPECT_TOKEN(Tokens[7], tok::amp, TT_BinaryOperator);

Tokens =
annotate("template <typename T> void swap() noexcept(Bar<T> && Foo<T>);");
ASSERT_EQ(Tokens.size(), 23u) << Tokens;
EXPECT_TOKEN(Tokens[15], tok::ampamp, TT_BinaryOperator);

Tokens = annotate("template <typename T> struct S {\n"
" explicit(Bar<T> && Foo<T>) S(const S &);\n"
"};");
ASSERT_EQ(Tokens.size(), 30u) << Tokens;
EXPECT_TOKEN(Tokens[14], tok::ampamp, TT_BinaryOperator);
}

TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) {
Expand Down

0 comments on commit ead9644

Please sign in to comment.