diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h --- a/clang/lib/Format/FormatTokenLexer.h +++ b/clang/lib/Format/FormatTokenLexer.h @@ -55,7 +55,6 @@ bool tryMergeCSharpDoubleQuestion(); bool tryMergeCSharpNullConditional(); bool tryTransformCSharpForEach(); - bool tryMergeCSharpAttributeAndTarget(); bool tryMergeTokens(ArrayRef Kinds, TokenType NewType); diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -76,8 +76,6 @@ return; if (Style.isCSharp()) { - if (tryMergeCSharpAttributeAndTarget()) - return; if (tryMergeCSharpKeywordVariables()) return; if (tryMergeCSharpStringLiteral()) @@ -284,34 +282,6 @@ "param", "property", "return", "type", }; -bool FormatTokenLexer::tryMergeCSharpAttributeAndTarget() { - // Treat '[assembly:' and '[field:' as tokens in their own right. - if (Tokens.size() < 3) - return false; - - auto &SquareBracket = *(Tokens.end() - 3); - auto &Target = *(Tokens.end() - 2); - auto &Colon = *(Tokens.end() - 1); - - if (!SquareBracket->Tok.is(tok::l_square)) - return false; - - if (CSharpAttributeTargets.find(Target->TokenText) == - CSharpAttributeTargets.end()) - return false; - - if (!Colon->Tok.is(tok::colon)) - return false; - - SquareBracket->TokenText = - StringRef(SquareBracket->TokenText.begin(), - Colon->TokenText.end() - SquareBracket->TokenText.begin()); - SquareBracket->ColumnWidth += (Target->ColumnWidth + Colon->ColumnWidth); - Tokens.erase(Tokens.end() - 2); - Tokens.erase(Tokens.end() - 1); - return true; -} - bool FormatTokenLexer::tryMergeCSharpDoubleQuestion() { if (Tokens.size() < 2) return false; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -384,11 +384,11 @@ if (!AttrTok) return false; - - // Move past the end of ']'. + + // Allow an attribute to be the only content of a file. AttrTok = AttrTok->Next; if (!AttrTok) - return false; + return true; // Limit this to being an access modifier that follows. if (AttrTok->isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected, @@ -460,7 +460,7 @@ Contexts.back().InCpp11AttributeSpecifier; // Treat C# Attributes [STAThread] much like C++ attributes [[...]]. - bool IsCSharp11AttributeSpecifier = + bool IsCSharpAttributeSpecifier = isCSharpAttributeSpecifier(*Left) || Contexts.back().InCSharpAttributeSpecifier; @@ -469,7 +469,8 @@ bool StartsObjCMethodExpr = !IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates && Style.isCpp() && !IsCpp11AttributeSpecifier && - Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && + !IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression && + Left->isNot(TT_LambdaLSquare) && !CurrentToken->isOneOf(tok::l_brace, tok::r_square) && (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, @@ -496,7 +497,7 @@ } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace && Parent && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->Type = TT_DesignatedInitializerLSquare; - } else if (IsCSharp11AttributeSpecifier) { + } else if (IsCSharpAttributeSpecifier) { Left->Type = TT_AttributeSquare; } else if (CurrentToken->is(tok::r_square) && Parent && Parent->is(TT_TemplateCloser)) { @@ -559,13 +560,13 @@ Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr; Contexts.back().InCpp11AttributeSpecifier = IsCpp11AttributeSpecifier; - Contexts.back().InCSharpAttributeSpecifier = IsCSharp11AttributeSpecifier; + Contexts.back().InCSharpAttributeSpecifier = IsCSharpAttributeSpecifier; while (CurrentToken) { if (CurrentToken->is(tok::r_square)) { if (IsCpp11AttributeSpecifier) CurrentToken->Type = TT_AttributeSquare; - if (IsCSharp11AttributeSpecifier) + if (IsCSharpAttributeSpecifier) CurrentToken->Type = TT_AttributeSquare; else if (((CurrentToken->Next && CurrentToken->Next->is(tok::l_paren)) || @@ -777,6 +778,10 @@ break; } } else if (Style.isCSharp()) { + if (Contexts.back().InCSharpAttributeSpecifier) { + Tok->Type = TT_AttributeColon; + break; + } if (Contexts.back().ContextKind == tok::l_paren) { Tok->Type = TT_CSharpNamedArgumentColon; break; @@ -2922,6 +2927,10 @@ if (Left.is(TT_JsFatArrow) || Right.is(TT_JsFatArrow)) return true; + // No spaces around attribute target colons + if (Left.is(TT_AttributeColon) || Right.is(TT_AttributeColon)) + return false; + // space between type and variable e.g. Dictionary foo; if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName)) return true; @@ -3550,8 +3559,8 @@ const FormatToken &Left = *Right.Previous; // Language-specific stuff. if (Style.isCSharp()) { - if (Left.is(TT_CSharpNamedArgumentColon) || - Right.is(TT_CSharpNamedArgumentColon)) + if (Left.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon) || + Right.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon)) return false; } else if (Style.Language == FormatStyle::LK_Java) { if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,