arichardson updated this revision to Diff 289180.
arichardson added a comment.
- Add test for config parsing
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D86782/new/
https://reviews.llvm.org/D86782
Files:
clang/docs/ClangFormatStyleOptions.rst
clang/include/clang/Format/Format.h
clang/lib/Format/Format.cpp
clang/lib/Format/FormatToken.h
clang/lib/Format/FormatTokenLexer.cpp
clang/lib/Format/TokenAnnotator.cpp
clang/unittests/Format/FormatTest.cpp
Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -8030,7 +8030,20 @@
verifyFormat("vector<a *_Null_unspecified> v;");
verifyFormat("vector<a *__ptr32> v;");
verifyFormat("vector<a *__ptr64> v;");
+ verifyFormat("vector<a *__capability> v;");
+ FormatStyle CustomQualifier = getLLVMStyle();
+ // Add indentifers that should not be parsed as a qualifier by default.
+ CustomQualifier.AttributeMacros.push_back("__my_qualifier");
+ CustomQualifier.AttributeMacros.push_back("_My_qualifier");
+ CustomQualifier.AttributeMacros.push_back("my_other_qualifier");
+ verifyFormat("vector<a * __my_qualifier> parse_as_multiply;");
+ verifyFormat("vector<a *__my_qualifier> v;", CustomQualifier);
+ verifyFormat("vector<a * _My_qualifier> parse_as_multiply;");
+ verifyFormat("vector<a *_My_qualifier> v;", CustomQualifier);
+ verifyFormat("vector<a * my_other_qualifier> parse_as_multiply;");
+ verifyFormat("vector<a *my_other_qualifier> v;", CustomQualifier);
verifyFormat("vector<a * _NotAQualifier> v;");
+ verifyFormat("vector<a * __not_a_qualifier> v;");
verifyFormat("vector<a * b> v;");
verifyFormat("foo<b && false>();");
verifyFormat("foo<b & 1>();");
@@ -8074,10 +8087,23 @@
verifyIndependentOfContext("MACRO(A *[[clang::attr(\"foo\")]] a);");
verifyIndependentOfContext("MACRO(A *__ptr32 a);");
verifyIndependentOfContext("MACRO(A *__ptr64 a);");
+ verifyIndependentOfContext("MACRO(A *__capability);");
+ verifyIndependentOfContext("MACRO(A &__capability);");
+ verifyFormat("MACRO(A *__my_qualifier);"); // type declaration
+ verifyFormat("void f() { MACRO(A * __my_qualifier); }"); // multiplication
+ // If we add __my_qualifier to AttributeMacros it should always be parsed as
+ // a type declaration:
+ verifyFormat("MACRO(A *__my_qualifier);", CustomQualifier);
+ verifyFormat("void f() { MACRO(A *__my_qualifier); }", CustomQualifier);
+
verifyIndependentOfContext("MACRO('0' <= c && c <= '9');");
verifyFormat("void f() { f(float{1}, a * a); }");
// FIXME: Is there a way to make this work?
// verifyIndependentOfContext("MACRO(A *a);");
+ verifyFormat("MACRO(A &B);");
+ verifyFormat("MACRO(A *B);");
+ verifyFormat("void f() { MACRO(A * B); }");
+ verifyFormat("void f() { MACRO(A & B); }");
verifyFormat("DatumHandle const *operator->() const { return input_; }");
verifyFormat("return options != nullptr && operator==(*options);");
@@ -8127,10 +8153,47 @@
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa __attribute__((unused))\n"
"aaaaaaaaaaaaaaaaaaaaaaa(int i);");
FormatStyle AfterType = getLLVMStyle();
- AfterType.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
+ AfterType.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All;
verifyFormat("__attribute__((nodebug)) void\n"
"foo() {}\n",
AfterType);
+ verifyFormat("__unused void\n"
+ "foo() {}",
+ AfterType);
+
+ FormatStyle CustomAttrs = getLLVMStyle();
+ CustomAttrs.AttributeMacros.push_back("__unused");
+ CustomAttrs.AttributeMacros.push_back("__attr1");
+ CustomAttrs.AttributeMacros.push_back("__attr2");
+ CustomAttrs.AttributeMacros.push_back("no_underscore_attr");
+ verifyFormat("vector<SomeType *__attribute((foo))> v;");
+ verifyFormat("vector<SomeType *__attribute__((foo))> v;");
+ verifyFormat("vector<SomeType * __not_attribute__((foo))> v;");
+ // Check that it is parsed as a multiplication without AttributeMacros and
+ // as a pointer qualifier when we add __attr1/__attr2 to AttributeMacros.
+ verifyFormat("vector<SomeType * __attr1> v;");
+ verifyFormat("vector<SomeType __attr1 *> v;");
+ verifyFormat("vector<SomeType __attr1 *const> v;");
+ verifyFormat("vector<SomeType __attr1 * __attr2> v;");
+ verifyFormat("vector<SomeType *__attr1> v;", CustomAttrs);
+ verifyFormat("vector<SomeType *__attr2> v;", CustomAttrs);
+ verifyFormat("vector<SomeType *no_underscore_attr> v;", CustomAttrs);
+ verifyFormat("vector<SomeType __attr1 *> v;", CustomAttrs);
+ verifyFormat("vector<SomeType __attr1 *const> v;", CustomAttrs);
+ verifyFormat("vector<SomeType __attr1 *__attr2> v;", CustomAttrs);
+ verifyFormat("vector<SomeType __attr1 *no_underscore_attr> v;", CustomAttrs);
+
+ // Check that these are not parsed as function declarations:
+ CustomAttrs.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ CustomAttrs.BreakBeforeBraces = FormatStyle::BS_Allman;
+ verifyFormat("SomeType s(InitValue);", CustomAttrs);
+ verifyFormat("SomeType s{InitValue};", CustomAttrs);
+ verifyFormat("SomeType *__unused s(InitValue);", CustomAttrs);
+ verifyFormat("SomeType *__unused s{InitValue};", CustomAttrs);
+ verifyFormat("SomeType s __unused(InitValue);", CustomAttrs);
+ verifyFormat("SomeType s __unused{InitValue};", CustomAttrs);
+ verifyFormat("SomeType *__capability s(InitValue);", CustomAttrs);
+ verifyFormat("SomeType *__capability s{InitValue};", CustomAttrs);
}
TEST_F(FormatTest, UnderstandsPointerQualifiersInCast) {
@@ -8147,6 +8210,7 @@
verifyFormat("x = (foo *[[clang::attr(\"foo\")]])*v;");
verifyFormat("x = (foo *__ptr32)*v;");
verifyFormat("x = (foo *__ptr64)*v;");
+ verifyFormat("x = (foo *__capability)*v;");
// Check that we handle multiple trailing qualifiers and skip them all to
// determine that the expression is a cast to a pointer type.
@@ -8155,7 +8219,7 @@
LongPointerLeft.PointerAlignment = FormatStyle::PAS_Left;
StringRef AllQualifiers =
"const volatile restrict __attribute__((foo)) _Nonnull _Null_unspecified "
- "_Nonnull [[clang::attr]] __ptr32 __ptr64";
+ "_Nonnull [[clang::attr]] __ptr32 __ptr64 __capability";
verifyFormat(("x = (foo *" + AllQualifiers + ")*v;").str(), LongPointerRight);
verifyFormat(("x = (foo* " + AllQualifiers + ")*v;").str(), LongPointerLeft);
@@ -8163,6 +8227,20 @@
verifyFormat("x = (foo *const)&v;");
verifyFormat(("x = (foo *" + AllQualifiers + ")&v;").str(), LongPointerRight);
verifyFormat(("x = (foo* " + AllQualifiers + ")&v;").str(), LongPointerLeft);
+
+ // Check custom qualifiers:
+ FormatStyle CustomQualifier = getLLVMStyleWithColumns(999);
+ CustomQualifier.AttributeMacros.push_back("__my_qualifier");
+ verifyFormat("x = (foo * __my_qualifier) * v;"); // not parsed as qualifier.
+ verifyFormat("x = (foo *__my_qualifier)*v;", CustomQualifier);
+ verifyFormat(("x = (foo *" + AllQualifiers + " __my_qualifier)*v;").str(),
+ CustomQualifier);
+ verifyFormat(("x = (foo *" + AllQualifiers + " __my_qualifier)&v;").str(),
+ CustomQualifier);
+
+ // Check that unknown identifiers result in binary operator parsing:
+ verifyFormat("x = (foo * __unknown_qualifier) * v;");
+ verifyFormat("x = (foo * __unknown_qualifier) & v;");
}
TEST_F(FormatTest, UnderstandsSquareAttributes) {
@@ -14152,6 +14230,11 @@
CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros,
BoostAndQForeach);
+ Style = getLLVMStyle();
+ CHECK_PARSE("", AttributeMacros, std::vector<std::string>({"__capability"}));
+ CHECK_PARSE("AttributeMacros: [attr1, attr2]", AttributeMacros,
+ std::vector<std::string>({"attr1", "attr2"}));
+
Style.StatementMacros.clear();
CHECK_PARSE("StatementMacros: [QUNUSED]", StatementMacros,
std::vector<std::string>{"QUNUSED"});
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1333,11 +1333,12 @@
// Reset token type in case we have already looked at it and then
// recovered from an error (e.g. failure to find the matching >).
if (!CurrentToken->isOneOf(
- TT_LambdaLSquare, TT_LambdaLBrace, TT_ForEachMacro,
- TT_TypenameMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral,
- TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, TT_NamespaceMacro,
- TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString,
- TT_ObjCStringLiteral, TT_UntouchableMacroFunc))
+ TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro,
+ TT_ForEachMacro, TT_TypenameMacro, TT_FunctionLBrace,
+ TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow,
+ TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator,
+ TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral,
+ TT_UntouchableMacroFunc))
CurrentToken->setType(TT_Unknown);
CurrentToken->Role.reset();
CurrentToken->MatchingParen = nullptr;
Index: clang/lib/Format/FormatTokenLexer.cpp
===================================================================
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -39,6 +39,8 @@
for (const std::string &ForEachMacro : Style.ForEachMacros)
Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro});
+ for (const std::string &AttributeMacro : Style.AttributeMacros)
+ Macros.insert({&IdentTable.get(AttributeMacro), TT_AttributeMacro});
for (const std::string &StatementMacro : Style.StatementMacros)
Macros.insert({&IdentTable.get(StatementMacro), TT_StatementMacro});
for (const std::string &TypenameMacro : Style.TypenameMacros)
Index: clang/lib/Format/FormatToken.h
===================================================================
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -29,6 +29,7 @@
TYPE(ArrayInitializerLSquare) \
TYPE(ArraySubscriptLSquare) \
TYPE(AttributeColon) \
+ TYPE(AttributeMacro) \
TYPE(AttributeParen) \
TYPE(AttributeSquare) \
TYPE(BinaryOperator) \
@@ -442,7 +443,8 @@
bool canBePointerOrReferenceQualifier() const {
return isOneOf(tok::kw_const, tok::kw_restrict, tok::kw_volatile,
tok::kw___attribute, tok::kw__Nonnull, tok::kw__Nullable,
- tok::kw__Null_unspecified, tok::kw___ptr32, tok::kw___ptr64);
+ tok::kw__Null_unspecified, tok::kw___ptr32, tok::kw___ptr64,
+ TT_AttributeMacro);
}
/// Determine whether the token is a simple-type-specifier.
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -475,6 +475,7 @@
Style.AlwaysBreakBeforeMultilineStrings);
IO.mapOptional("AlwaysBreakTemplateDeclarations",
Style.AlwaysBreakTemplateDeclarations);
+ IO.mapOptional("AttributeMacros", Style.AttributeMacros);
IO.mapOptional("BinPackArguments", Style.BinPackArguments);
IO.mapOptional("BinPackParameters", Style.BinPackParameters);
IO.mapOptional("BraceWrapping", Style.BraceWrapping);
@@ -842,6 +843,7 @@
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_MultiLine;
+ LLVMStyle.AttributeMacros.push_back("__capability");
LLVMStyle.BinPackArguments = true;
LLVMStyle.BinPackParameters = true;
LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -583,6 +583,24 @@
/// The template declaration breaking style to use.
BreakTemplateDeclarationsStyle AlwaysBreakTemplateDeclarations;
+ /// A vector of strings that should be interpreted as attributes/qualifiers
+ /// instead of identifiers. This can be useful for language extensions or
+ /// static analyzer annotations.
+ ///
+ /// For example:
+ /// \code
+ /// x = (char *__capability)&y;
+ /// int function(void) __ununsed;
+ /// void only_writes_to_buffer(char *__output buffer);
+ /// \endcode
+ ///
+ /// In the .clang-format configuration file, this can be configured like:
+ /// \code{.yaml}
+ /// AttributeMacros: ['__capability', '__output', '__ununsed']
+ /// \endcode
+ ///
+ std::vector<std::string> AttributeMacros;
+
/// If ``false``, a function call's arguments will either be all on the
/// same line or will have one line each.
/// \code
@@ -2351,6 +2369,7 @@
R.AlwaysBreakBeforeMultilineStrings &&
AlwaysBreakTemplateDeclarations ==
R.AlwaysBreakTemplateDeclarations &&
+ AttributeMacros == R.AttributeMacros &&
BinPackArguments == R.BinPackArguments &&
BinPackParameters == R.BinPackParameters &&
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -758,7 +758,24 @@
int bbbbbbbbbbbbbbbbbbbbb) {
}
+**AttributeMacros** (``std::vector<std::string>``)
+ A vector of strings that should be interpreted as attributes/qualifiers
+ instead of identifiers. This can be useful for language extensions or
+ static analyzer annotations:
+ .. code-block:: c++
+
+ x = (char *__capability)&y;
+ int function(void) __ununsed;
+ void only_writes_to_buffer(char *__output buffer);
+
+ In the .clang-format configuration file, this can be configured like:
+
+ .. code-block:: yaml
+
+ AttributeMacros: ['__capability', '__output', '__ununsed']
+
+ For example: __capability.
**BinPackArguments** (``bool``)
If ``false``, a function call's arguments will either be all on the
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits