[clang] d1aed48 - [clang-format] Handle C variables with name that matches c++ access specifier
Marek Kurdej via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 30 11:56:55 PST 2022
Author: Philip Sigillito
Date: 2022-01-30T20:56:50+01:00
New Revision: d1aed486efc6d35a81ca4acbabb4203c4b91cda9
URL: https://github.com/llvm/llvm-project/commit/d1aed486efc6d35a81ca4acbabb4203c4b91cda9
DIFF: https://github.com/llvm/llvm-project/commit/d1aed486efc6d35a81ca4acbabb4203c4b91cda9.diff
LOG: [clang-format] Handle C variables with name that matches c++ access specifier
Reviewed By: MyDeveloperDay, curdeius, HazardyKnusperkeks
Differential Revision: https://reviews.llvm.org/D117416
Added:
Modified:
clang/lib/Format/FormatToken.h
clang/lib/Format/UnwrappedLineFormatter.cpp
clang/lib/Format/UnwrappedLineParser.cpp
clang/unittests/Format/FormatTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index a64329802ee32..f116a89ac6440 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -123,6 +123,34 @@ namespace format {
TYPE(CSharpGenericTypeConstraintComma) \
TYPE(Unknown)
+/// Sorted operators that can follow a C variable.
+static const std::vector<clang::tok::TokenKind> COperatorsFollowingVar = [] {
+ std::vector<clang::tok::TokenKind> ReturnVal = {
+ tok::l_square, tok::r_square,
+ tok::l_paren, tok::r_paren,
+ tok::r_brace, tok::period,
+ tok::ellipsis, tok::ampamp,
+ tok::ampequal, tok::star,
+ tok::starequal, tok::plus,
+ tok::plusplus, tok::plusequal,
+ tok::minus, tok::arrow,
+ tok::minusminus, tok::minusequal,
+ tok::exclaim, tok::exclaimequal,
+ tok::slash, tok::slashequal,
+ tok::percent, tok::percentequal,
+ tok::less, tok::lessless,
+ tok::lessequal, tok::lesslessequal,
+ tok::greater, tok::greatergreater,
+ tok::greaterequal, tok::greatergreaterequal,
+ tok::caret, tok::caretequal,
+ tok::pipe, tok::pipepipe,
+ tok::pipeequal, tok::question,
+ tok::semi, tok::equal,
+ tok::equalequal, tok::comma};
+ assert(std::is_sorted(ReturnVal.begin(), ReturnVal.end()));
+ return ReturnVal;
+}();
+
/// Determines the semantic type of a syntactic token, e.g. whether "<" is a
/// template opener or binary operator.
enum TokenType : uint8_t {
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 0172a224335c8..01c151fec132c 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -100,10 +100,27 @@ class LevelIndentTracker {
if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() ||
Style.isCSharp())
return 0;
- if (RootToken.isAccessSpecifier(false) ||
- RootToken.isObjCAccessSpecifier() ||
- (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
- RootToken.Next && RootToken.Next->is(tok::colon))) {
+
+ auto IsAccessModifier = [this, &RootToken]() {
+ if (RootToken.isAccessSpecifier(Style.isCpp()))
+ return true;
+ else if (RootToken.isObjCAccessSpecifier())
+ return true;
+ // Handle Qt signals.
+ else if ((RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
+ RootToken.Next && RootToken.Next->is(tok::colon)))
+ return true;
+ else if (RootToken.Next &&
+ RootToken.Next->isOneOf(Keywords.kw_slots, Keywords.kw_qslots) &&
+ RootToken.Next->Next && RootToken.Next->Next->is(tok::colon))
+ return true;
+ // Handle malformed access specifier e.g. 'private' without trailing ':'.
+ else if (!RootToken.Next && RootToken.isAccessSpecifier(false))
+ return true;
+ return false;
+ };
+
+ if (IsAccessModifier()) {
// The AccessModifierOffset may be overridden by IndentAccessModifiers,
// in which case we take a negative value of the IndentWidth to simulate
// the upper indent level.
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 35be2fa3eb62f..2297d98850103 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2708,14 +2708,25 @@ void UnwrappedLineParser::parseSwitch() {
}
void UnwrappedLineParser::parseAccessSpecifier() {
+ FormatToken *AccessSpecifierCandidate = FormatTok;
nextToken();
// Understand Qt's slots.
if (FormatTok->isOneOf(Keywords.kw_slots, Keywords.kw_qslots))
nextToken();
// Otherwise, we don't know what it is, and we'd better keep the next token.
- if (FormatTok->Tok.is(tok::colon))
+ if (FormatTok->Tok.is(tok::colon)) {
nextToken();
- addUnwrappedLine();
+ addUnwrappedLine();
+ } else if (!FormatTok->Tok.is(tok::coloncolon) &&
+ !std::binary_search(COperatorsFollowingVar.begin(),
+ COperatorsFollowingVar.end(),
+ FormatTok->Tok.getKind())) {
+ // Not a variable name nor namespace name.
+ addUnwrappedLine();
+ } else if (AccessSpecifierCandidate) {
+ // Consider the access specifier to be a C identifier.
+ AccessSpecifierCandidate->Tok.setKind(tok::identifier);
+ }
}
void UnwrappedLineParser::parseConcept() {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 40db603a49416..cf20a70e6cdf3 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -3123,6 +3123,46 @@ TEST_F(FormatTest, UnderstandsAccessSpecifiers) {
"label:\n"
" signals.baz();\n"
"}");
+ verifyFormat("private[1];");
+ verifyFormat("testArray[public] = 1;");
+ verifyFormat("public();");
+ verifyFormat("myFunc(public);");
+ verifyFormat("std::vector<int> testVec = {private};");
+ verifyFormat("private.p = 1;");
+ verifyFormat("void function(private...){};");
+ verifyFormat("if (private && public)\n");
+ verifyFormat("private &= true;");
+ verifyFormat("int x = private * public;");
+ verifyFormat("public *= private;");
+ verifyFormat("int x = public + private;");
+ verifyFormat("private++;");
+ verifyFormat("++private;");
+ verifyFormat("public += private;");
+ verifyFormat("public = public - private;");
+ verifyFormat("public->foo();");
+ verifyFormat("private--;");
+ verifyFormat("--private;");
+ verifyFormat("public -= 1;");
+ verifyFormat("if (!private && !public)\n");
+ verifyFormat("public != private;");
+ verifyFormat("int x = public / private;");
+ verifyFormat("public /= 2;");
+ verifyFormat("public = public % 2;");
+ verifyFormat("public %= 2;");
+ verifyFormat("if (public < private)\n");
+ verifyFormat("public << private;");
+ verifyFormat("public <<= private;");
+ verifyFormat("if (public > private)\n");
+ verifyFormat("public >> private;");
+ verifyFormat("public >>= private;");
+ verifyFormat("public ^ private;");
+ verifyFormat("public ^= private;");
+ verifyFormat("public | private;");
+ verifyFormat("public |= private;");
+ verifyFormat("auto x = private ? 1 : 2;");
+ verifyFormat("if (public == private)\n");
+ verifyFormat("void foo(public, private)");
+ verifyFormat("public::foo();");
}
TEST_F(FormatTest, SeparatesLogicalBlocks) {
More information about the cfe-commits
mailing list