[clang-format] Add support for C++17 structured bindings.

Summary:
Before:
```
    auto[a, b] = f();
```

After:
```
    auto [a, b] = f();
```
or, if SpacesInSquareBrackets is true:
```
    auto [ a, b ] = f();
```

Reviewers: djasper

Reviewed By: djasper

Subscribers: cfe-commits, klimek

Differential Revision: https://reviews.llvm.org/D37132

llvm-svn: 312723
This commit is contained in:
Marek Kurdej 2017-09-07 14:28:32 +00:00
parent 5a385940d3
commit ceeb8b91e7
3 changed files with 46 additions and 5 deletions

View File

@ -84,6 +84,7 @@ namespace format {
TYPE(RegexLiteral) \
TYPE(SelectorName) \
TYPE(StartOfName) \
TYPE(StructuredBindingLSquare) \
TYPE(TemplateCloser) \
TYPE(TemplateOpener) \
TYPE(TemplateString) \

View File

@ -310,6 +310,16 @@ private:
return false;
}
bool isCppStructuredBinding(const FormatToken *Tok) {
if (!Style.isCpp() || !Tok->is(tok::l_square))
return false;
do {
Tok = Tok->getPreviousNonComment();
} while (Tok && Tok->isOneOf(tok::kw_const, tok::kw_volatile, tok::amp,
tok::ampamp));
return Tok && Tok->is(tok::kw_auto);
}
bool parseSquare() {
if (!CurrentToken)
return false;
@ -344,7 +354,9 @@ private:
unsigned BindingIncrease = 1;
if (Left->is(TT_Unknown)) {
if (StartsObjCMethodExpr) {
if (isCppStructuredBinding(Left)) {
Left->Type = TT_StructuredBindingLSquare;
} else if (StartsObjCMethodExpr) {
Left->Type = TT_ObjCMethodExpr;
} else if (Style.Language == FormatStyle::LK_JavaScript && Parent &&
Contexts.back().ContextKind == tok::l_brace &&
@ -2261,17 +2273,20 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.is(tok::l_square))
return (Left.is(TT_ArrayInitializerLSquare) &&
Style.SpacesInContainerLiterals && Right.isNot(tok::r_square)) ||
(Left.is(TT_ArraySubscriptLSquare) && Style.SpacesInSquareBrackets &&
Right.isNot(tok::r_square));
(Left.isOneOf(TT_ArraySubscriptLSquare,
TT_StructuredBindingLSquare) &&
Style.SpacesInSquareBrackets && Right.isNot(tok::r_square));
if (Right.is(tok::r_square))
return Right.MatchingParen &&
((Style.SpacesInContainerLiterals &&
Right.MatchingParen->is(TT_ArrayInitializerLSquare)) ||
(Style.SpacesInSquareBrackets &&
Right.MatchingParen->is(TT_ArraySubscriptLSquare)));
Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare,
TT_StructuredBindingLSquare)));
if (Right.is(tok::l_square) &&
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
TT_DesignatedInitializerLSquare) &&
TT_DesignatedInitializerLSquare,
TT_StructuredBindingLSquare) &&
!Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))

View File

@ -11452,6 +11452,31 @@ TEST_F(FormatTest, DoNotFormatLikelyXml) {
format(" <!-- >; -->", getGoogleStyle()));
}
TEST_F(FormatTest, StructuredBindings) {
// Structured bindings is a C++17 feature.
// all modes, including C++11, C++14 and C++17
verifyFormat("auto [a, b] = f();");
EXPECT_EQ("auto [a, b] = f();", format("auto[a, b] = f();"));
EXPECT_EQ("const auto [a, b] = f();", format("const auto[a, b] = f();"));
EXPECT_EQ("auto const [a, b] = f();", format("auto const[a, b] = f();"));
EXPECT_EQ("auto const volatile [a, b] = f();",
format("auto const volatile[a, b] = f();"));
EXPECT_EQ("auto [a, b, c] = f();", format("auto [ a , b,c ] = f();"));
EXPECT_EQ("auto & [a, b, c] = f();",
format("auto &[ a , b,c ] = f();"));
EXPECT_EQ("auto && [a, b, c] = f();",
format("auto &&[ a , b,c ] = f();"));
EXPECT_EQ("auto const & [a, b] = f();", format("auto const&[a, b] = f();"));
EXPECT_EQ("auto const volatile && [a, b] = f();",
format("auto const volatile &&[a, b] = f();"));
EXPECT_EQ("auto && [a, b] = f();", format("auto &&[a, b] = f();"));
format::FormatStyle Spaces = format::getLLVMStyle();
Spaces.SpacesInSquareBrackets = true;
verifyFormat("auto [ a, b ] = f();", Spaces);
verifyFormat("auto && [ a, b ] = f();", Spaces);
}
} // end namespace
} // end namespace format
} // end namespace clang