[clang] ca1fd46 - [clang-format] Do not treat C# attribute targets as labels
Jonathan Coe via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 5 09:30:37 PST 2020
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) {
More information about the cfe-commits
mailing list