Author: Jonathan Coe Date: 2020-02-05T17:30:24Z New Revision: ca1fd460f1f5bc4c200f557b63d69a93e3722175
URL: https://github.com/llvm/llvm-project/commit/ca1fd460f1f5bc4c200f557b63d69a93e3722175 DIFF: https://github.com/llvm/llvm-project/commit/ca1fd460f1f5bc4c200f557b63d69a93e3722175.diff LOG: [clang-format] Do not treat C# attribute targets as labels Summary: Merge '[', 'target' , ':' into a single token for C# attributes to prevent the target from being seen as a label. Reviewers: MyDeveloperDay, krasimir Reviewed By: krasimir Tags: #clang-format Differential Revision: https://reviews.llvm.org/D74043 Added: Modified: clang/lib/Format/FormatTokenLexer.cpp clang/lib/Format/FormatTokenLexer.h clang/unittests/Format/FormatTestCSharp.cpp Removed: ################################################################################ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 98650951c7d0..e76d74571ebc 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -76,6 +76,8 @@ void FormatTokenLexer::tryMergePreviousTokens() { return; if (Style.isCSharp()) { + if (tryMergeCSharpAttributeAndTarget()) + return; if (tryMergeCSharpKeywordVariables()) return; if (tryMergeCSharpStringLiteral()) @@ -275,6 +277,41 @@ bool FormatTokenLexer::tryMergeCSharpStringLiteral() { return true; } +// Valid C# attribute targets: +// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets +const llvm::StringSet<> FormatTokenLexer::CSharpAttributeTargets = { + "assembly", "module", "field", "event", "method", + "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/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h index be13ac8f6735..4fffb36272f7 100644 --- a/clang/lib/Format/FormatTokenLexer.h +++ b/clang/lib/Format/FormatTokenLexer.h @@ -21,6 +21,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Regex.h" #include <stack> @@ -54,6 +55,7 @@ class FormatTokenLexer { bool tryMergeCSharpNullConditionals(); bool tryMergeCSharpDoubleQuestion(); bool tryTransformCSharpForEach(); + bool tryMergeCSharpAttributeAndTarget(); bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType); @@ -115,6 +117,9 @@ class FormatTokenLexer { llvm::Regex MacroBlockBeginRegex; llvm::Regex MacroBlockEndRegex; + // Targets that may appear inside a C# attribute. + static const llvm::StringSet<> CSharpAttributeTargets; + void readRawToken(FormatToken &Tok); void resetLexer(unsigned Offset); diff --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp index 86a44d0f9eb3..dba76b521614 100644 --- a/clang/unittests/Format/FormatTestCSharp.cpp +++ b/clang/unittests/Format/FormatTestCSharp.cpp @@ -233,6 +233,15 @@ TEST_F(FormatTestCSharp, Attributes) { "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n" "// The const char* returned by hello_world must not be deleted.\n" "private static extern IntPtr HelloFromCpp();)"); + + // Unwrappable lines go on a line of their own. + // 'target:' is not treated as a label. + // Modify Style to enforce a column limit. + FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); + Style.ColumnLimit = 10; + verifyFormat(R"([assembly:InternalsVisibleTo( + "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])", + Style); } TEST_F(FormatTestCSharp, CSharpUsing) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits