MyDeveloperDay updated this revision to Diff 230124.
MyDeveloperDay added a comment.
-update with missing files
-clang-format test
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D69764/new/
https://reviews.llvm.org/D69764
Files:
clang/docs/ClangFormatStyleOptions.rst
clang/docs/ReleaseNotes.rst
clang/include/clang/Format/Format.h
clang/lib/Format/CMakeLists.txt
clang/lib/Format/EastWestConstFixer.cpp
clang/lib/Format/EastWestConstFixer.h
clang/lib/Format/Format.cpp
clang/tools/clang-format/ClangFormat.cpp
clang/unittests/Format/FormatTest.cpp
Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -27,6 +27,10 @@
FormatStyle getGoogleStyle() { return getGoogleStyle(FormatStyle::LK_Cpp); }
+#define VERIFYFORMAT(expect, style) verifyFormat(expect, style, __LINE__)
+#define VERIFYFORMAT2(expect, actual, style) \
+ verifyFormat(expect, actual, style, __LINE__)
+
class FormatTest : public ::testing::Test {
protected:
enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck };
@@ -66,10 +70,12 @@
}
void verifyFormat(llvm::StringRef Expected, llvm::StringRef Code,
- const FormatStyle &Style = getLLVMStyle()) {
+ const FormatStyle &Style = getLLVMStyle(),
+ int line = __LINE__) {
EXPECT_EQ(Expected.str(), format(Expected, Style))
- << "Expected code is not stable";
- EXPECT_EQ(Expected.str(), format(Code, Style));
+ << "Expected code is not stable at " << __FILE__ << ":" << line;
+ EXPECT_EQ(Expected.str(), format(Code, Style))
+ << " at " << __FILE__ << ":" << line;
if (Style.Language == FormatStyle::LK_Cpp) {
// Objective-C++ is a superset of C++, so everything checked for C++
// needs to be checked for Objective-C++ as well.
@@ -80,8 +86,9 @@
}
void verifyFormat(llvm::StringRef Code,
- const FormatStyle &Style = getLLVMStyle()) {
- verifyFormat(Code, test::messUp(Code), Style);
+ const FormatStyle &Style = getLLVMStyle(),
+ int line = __LINE__) {
+ verifyFormat(Code, test::messUp(Code), Style, line);
}
void verifyIncompleteFormat(llvm::StringRef Code,
@@ -12609,6 +12616,15 @@
CHECK_PARSE("ContinuationIndentWidth: 11", ContinuationIndentWidth, 11u);
CHECK_PARSE("CommentPragmas: '// abc$'", CommentPragmas, "// abc$");
+ Style.ConstStyle = FormatStyle::CS_Left;
+ CHECK_PARSE("ConstStyle: Leave", ConstStyle, FormatStyle::CS_Leave);
+ CHECK_PARSE("ConstStyle: East", ConstStyle, FormatStyle::CS_Right);
+ CHECK_PARSE("ConstStyle: West", ConstStyle, FormatStyle::CS_Left);
+ CHECK_PARSE("ConstStyle: Right", ConstStyle, FormatStyle::CS_Right);
+ CHECK_PARSE("ConstStyle: Left", ConstStyle, FormatStyle::CS_Left);
+ CHECK_PARSE("ConstStyle: After", ConstStyle, FormatStyle::CS_Right);
+ CHECK_PARSE("ConstStyle: Before", ConstStyle, FormatStyle::CS_Left);
+
Style.PointerAlignment = FormatStyle::PAS_Middle;
CHECK_PARSE("PointerAlignment: Left", PointerAlignment,
FormatStyle::PAS_Left);
@@ -14994,6 +15010,194 @@
verifyFormat("operator&&(int(&&)(), class Foo);", Style);
}
+TEST_F(FormatTest, EastWestConst) {
+ FormatStyle Style = getLLVMStyle();
+
+ // keep the const style unaltered
+ VERIFYFORMAT("const int a;", Style);
+ VERIFYFORMAT("const int *a;", Style);
+ VERIFYFORMAT("const int &a;", Style);
+ VERIFYFORMAT("const int &&a;", Style);
+ VERIFYFORMAT("int const b;", Style);
+ VERIFYFORMAT("int const *b;", Style);
+ VERIFYFORMAT("int const &b;", Style);
+ VERIFYFORMAT("int const &&b;", Style);
+ VERIFYFORMAT("int const *b const;", Style);
+ VERIFYFORMAT("int *const c;", Style);
+
+ VERIFYFORMAT("const Foo a;", Style);
+ VERIFYFORMAT("const Foo *a;", Style);
+ VERIFYFORMAT("const Foo &a;", Style);
+ VERIFYFORMAT("const Foo &&a;", Style);
+ VERIFYFORMAT("Foo const b;", Style);
+ VERIFYFORMAT("Foo const *b;", Style);
+ VERIFYFORMAT("Foo const &b;", Style);
+ VERIFYFORMAT("Foo const &&b;", Style);
+ VERIFYFORMAT("Foo const *b const;", Style);
+
+ VERIFYFORMAT("LLVM_NODISCARD const int &Foo();", Style);
+ VERIFYFORMAT("LLVM_NODISCARD int const &Foo();", Style);
+
+ VERIFYFORMAT("volatile const int *restrict;", Style);
+ VERIFYFORMAT("const volatile int *restrict;", Style);
+ VERIFYFORMAT("const int volatile *restrict;", Style);
+
+ Style.ConstStyle = FormatStyle::CS_Right;
+
+ VERIFYFORMAT("int const a;", Style);
+ VERIFYFORMAT("int const *a;", Style);
+ VERIFYFORMAT("int const &a;", Style);
+ VERIFYFORMAT("int const &&a;", Style);
+ VERIFYFORMAT("int const b;", Style);
+ VERIFYFORMAT("int const *b;", Style);
+ VERIFYFORMAT("int const &b;", Style);
+ VERIFYFORMAT("int const &&b;", Style);
+ VERIFYFORMAT("int const *b const;", Style);
+ VERIFYFORMAT("int *const c;", Style);
+
+ VERIFYFORMAT("Foo const a;", Style);
+ VERIFYFORMAT("Foo const *a;", Style);
+ VERIFYFORMAT("Foo const &a;", Style);
+ VERIFYFORMAT("Foo const &&a;", Style);
+ VERIFYFORMAT("Foo const b;", Style);
+ VERIFYFORMAT("Foo const *b;", Style);
+ VERIFYFORMAT("Foo const &b;", Style);
+ VERIFYFORMAT("Foo const &&b;", Style);
+ VERIFYFORMAT("Foo const *b const;", Style);
+ VERIFYFORMAT("Foo *const b;", Style);
+ VERIFYFORMAT("Foo const *const b;", Style);
+ VERIFYFORMAT("auto const v = get_value();", Style);
+ VERIFYFORMAT("long long const &a;", Style);
+ VERIFYFORMAT("unsigned char const *a;", Style);
+ VERIFYFORMAT("int main(int const argc, char const *const *const argv)",
+ Style);
+
+ VERIFYFORMAT("LLVM_NODISCARD int const &Foo();", Style);
+ VERIFYFORMAT("SourceRange getSourceRange() const override LLVM_READONLY",
+ Style);
+ VERIFYFORMAT("void foo() const override;", Style);
+ VERIFYFORMAT("void foo() const override LLVM_READONLY;", Style);
+ VERIFYFORMAT("void foo() const final;", Style);
+ VERIFYFORMAT("void foo() const final LLVM_READONLY;", Style);
+ VERIFYFORMAT("void foo() const LLVM_READONLY;", Style);
+
+ VERIFYFORMAT(
+ "template <typename Func> explicit Action(Action<Func> const &action);",
+ Style);
+ VERIFYFORMAT2(
+ "template <typename Func> explicit Action(Action<Func> const &action);",
+ "template <typename Func> explicit Action(const Action<Func>& action);",
+ Style);
+ VERIFYFORMAT2(
+ "template <typename Func> explicit Action(Action<Func> const &action);",
+ "template <typename Func>\nexplicit Action(const Action<Func>& action);",
+ Style);
+
+ VERIFYFORMAT2("int const a;", "const int a;", Style);
+ VERIFYFORMAT2("int const *a;", "const int *a;", Style);
+ VERIFYFORMAT2("int const &a;", "const int &a;", Style);
+ VERIFYFORMAT2("foo(int const &a)", "foo(const int &a)", Style);
+ VERIFYFORMAT2("unsigned char *a;", "unsigned char *a;", Style);
+ VERIFYFORMAT2("unsigned char const *a;", "const unsigned char *a;", Style);
+ VERIFYFORMAT2("vector<int, int const, int &, int const &> args1",
+ "vector<int, const int, int &, const int &> args1", Style);
+ VERIFYFORMAT2("unsigned int const &get_nu() const",
+ "const unsigned int &get_nu() const", Style);
+ VERIFYFORMAT2("Foo<int> const &a", "const Foo<int> &a", Style);
+ VERIFYFORMAT2("Foo<int>::iterator const &a", "const Foo<int>::iterator &a",
+ Style);
+
+ VERIFYFORMAT2("Foo(int a, "
+ "unsigned b, // c-style args\n"
+ " Bar const &c);",
+ "Foo(int a, "
+ "unsigned b, // c-style args\n"
+ " const Bar &c);",
+ Style);
+
+ VERIFYFORMAT2("volatile int const;", "volatile const int;", Style);
+ VERIFYFORMAT2("volatile int const;", "const volatile int;", Style);
+ VERIFYFORMAT2("int volatile const;", "const int volatile;", Style);
+ VERIFYFORMAT2("volatile int const *restrict;",
+ "volatile const int *restrict;", Style);
+ VERIFYFORMAT2("volatile int const *restrict;",
+ "const volatile int *restrict;", Style);
+ VERIFYFORMAT2("int volatile const *restrict;",
+ "const int volatile *restrict;", Style);
+
+ Style.ConstStyle = FormatStyle::CS_Left;
+
+ VERIFYFORMAT("const int a;", Style);
+ VERIFYFORMAT("const int *a;", Style);
+ VERIFYFORMAT("const int &a;", Style);
+ VERIFYFORMAT("const int &&a;", Style);
+ VERIFYFORMAT("const int b;", Style);
+ VERIFYFORMAT("const int *b;", Style);
+ VERIFYFORMAT("const int &b;", Style);
+ VERIFYFORMAT("const int &&b;", Style);
+ VERIFYFORMAT("const int *b const;", Style);
+ VERIFYFORMAT("int *const c;", Style);
+
+ VERIFYFORMAT("const Foo a;", Style);
+ VERIFYFORMAT("const Foo *a;", Style);
+ VERIFYFORMAT("const Foo &a;", Style);
+ VERIFYFORMAT("const Foo &&a;", Style);
+ VERIFYFORMAT("const Foo b;", Style);
+ VERIFYFORMAT("const Foo *b;", Style);
+ VERIFYFORMAT("const Foo &b;", Style);
+ VERIFYFORMAT("const Foo &&b;", Style);
+ VERIFYFORMAT("const Foo *b const;", Style);
+ VERIFYFORMAT("Foo *const b;", Style);
+ VERIFYFORMAT("const Foo *const b;", Style);
+
+ VERIFYFORMAT("LLVM_NODISCARD const int &Foo();", Style);
+
+ VERIFYFORMAT("const char a[];", Style);
+ VERIFYFORMAT("const auto v = get_value();", Style);
+ VERIFYFORMAT("const long long &a;", Style);
+ VERIFYFORMAT("const unsigned char *a;", Style);
+ VERIFYFORMAT2("const unsigned char *a;", "unsigned char const *a;", Style);
+ VERIFYFORMAT2("const Foo<int> &a", "Foo<int> const &a", Style);
+ VERIFYFORMAT2("const Foo<int>::iterator &a", "Foo<int>::iterator const &a",
+ Style);
+
+ VERIFYFORMAT2("const int a;", "int const a;", Style);
+ VERIFYFORMAT2("const int *a;", "int const *a;", Style);
+ VERIFYFORMAT2("const int &a;", "int const &a;", Style);
+ VERIFYFORMAT2("foo(const int &a)", "foo(int const &a)", Style);
+ VERIFYFORMAT2("unsigned char *a;", "unsigned char *a;", Style);
+ VERIFYFORMAT2("const unsigned int &get_nu() const",
+ "unsigned int const &get_nu() const", Style);
+
+ VERIFYFORMAT2("volatile const int;", "volatile const int;", Style);
+ VERIFYFORMAT2("const volatile int;", "const volatile int;", Style);
+ VERIFYFORMAT2("const int volatile;", "const int volatile;", Style);
+
+ VERIFYFORMAT2("volatile const int *restrict;",
+ "volatile const int *restrict;", Style);
+ VERIFYFORMAT2("const volatile int *restrict;",
+ "const volatile int *restrict;", Style);
+ VERIFYFORMAT2("const int volatile *restrict;",
+ "const int volatile *restrict;", Style);
+
+ VERIFYFORMAT("SourceRange getSourceRange() const override LLVM_READONLY;",
+ Style);
+
+ VERIFYFORMAT("void foo() const override;", Style);
+ VERIFYFORMAT("void foo() const override LLVM_READONLY;", Style);
+ VERIFYFORMAT("void foo() const final;", Style);
+ VERIFYFORMAT("void foo() const final LLVM_READONLY;", Style);
+ VERIFYFORMAT("void foo() const LLVM_READONLY;", Style);
+
+ VERIFYFORMAT(
+ "template <typename Func> explicit Action(const Action<Func> &action);",
+ Style);
+ VERIFYFORMAT2(
+ "template <typename Func> explicit Action(const Action<Func> &action);",
+ "template <typename Func> explicit Action(Action<Func> const &action);",
+ Style);
+}
+
} // namespace
} // namespace format
} // namespace clang
Index: clang/tools/clang-format/ClangFormat.cpp
===================================================================
--- clang/tools/clang-format/ClangFormat.cpp
+++ clang/tools/clang-format/ClangFormat.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/Version.h"
#include "clang/Format/Format.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
@@ -104,6 +105,12 @@
"SortIncludes style flag"),
cl::cat(ClangFormatCategory));
+static cl::opt<std::string> ConstStyle(
+ "const-style",
+ cl::desc("If set, overrides the const style behavior determined by the "
+ "ConstStyle style flag"),
+ cl::init(""), cl::cat(ClangFormatCategory));
+
static cl::opt<bool>
Verbose("verbose", cl::desc("If set, shows the list of processed files"),
cl::cat(ClangFormatCategory));
@@ -384,6 +391,14 @@
return true;
}
+ StringRef ConstAlignment = ConstStyle;
+
+ FormatStyle->ConstStyle =
+ StringSwitch<FormatStyle::ConstAlignmentStyle>(ConstAlignment.lower())
+ .Cases("right", "east", "after", FormatStyle::CS_Right)
+ .Cases("left", "west", "before", FormatStyle::CS_Left)
+ .Default(FormatStyle->ConstStyle);
+
if (SortIncludes.getNumOccurrences() != 0)
FormatStyle->SortIncludes = SortIncludes;
unsigned CursorPosition = Cursor;
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -15,6 +15,7 @@
#include "clang/Format/Format.h"
#include "AffectedRangeManager.h"
#include "ContinuationIndenter.h"
+#include "EastWestConstFixer.h"
#include "FormatInternal.h"
#include "FormatTokenLexer.h"
#include "NamespaceEndCommentsFixer.h"
@@ -114,6 +115,20 @@
}
};
+template <> struct ScalarEnumerationTraits<FormatStyle::ConstAlignmentStyle> {
+ static void enumeration(IO &IO, FormatStyle::ConstAlignmentStyle &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::CS_Leave);
+ IO.enumCase(Value, "Left", FormatStyle::CS_Left);
+ IO.enumCase(Value, "Right", FormatStyle::CS_Right);
+
+ // Other allowed names following community conventions.
+ IO.enumCase(Value, "Before", FormatStyle::CS_Left);
+ IO.enumCase(Value, "After", FormatStyle::CS_Right);
+ IO.enumCase(Value, "East", FormatStyle::CS_Right);
+ IO.enumCase(Value, "West", FormatStyle::CS_Left);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
IO.enumCase(Value, "None", FormatStyle::SFS_None);
@@ -460,6 +475,7 @@
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
+ IO.mapOptional("ConstStyle", Style.ConstStyle);
IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
@@ -761,6 +777,7 @@
LLVMStyle.BreakStringLiterals = true;
LLVMStyle.ColumnLimit = 80;
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
+ LLVMStyle.ConstStyle = FormatStyle::CS_Leave;
LLVMStyle.CompactNamespaces = false;
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
LLVMStyle.ConstructorInitializerIndentWidth = 4;
@@ -939,6 +956,7 @@
// taze:, triple slash directives (`/// <...`), @see, which is commonly
// followed by overlong URLs.
GoogleStyle.CommentPragmas = "(taze:|^/[ \t]*<|@see)";
+ GoogleStyle.ConstStyle = FormatStyle::CS_Leave;
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
GoogleStyle.SpacesInContainerLiterals = false;
@@ -990,6 +1008,7 @@
// _prepend that with a comment_ to prevent it" before changing behavior.
ChromiumStyle.IncludeStyle.IncludeBlocks =
tooling::IncludeStyle::IBS_Preserve;
+ ChromiumStyle.ConstStyle = FormatStyle::CS_Leave;
if (Language == FormatStyle::LK_Java) {
ChromiumStyle.AllowShortIfStatementsOnASingleLine =
@@ -1051,6 +1070,7 @@
MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
MozillaStyle.SpaceAfterTemplateKeyword = false;
+ MozillaStyle.ConstStyle = FormatStyle::CS_Leave;
return MozillaStyle;
}
@@ -1074,6 +1094,7 @@
Style.PointerAlignment = FormatStyle::PAS_Left;
Style.SpaceBeforeCpp11BracedList = true;
Style.SpaceInEmptyBlock = true;
+ Style.ConstStyle = FormatStyle::CS_Leave;
return Style;
}
@@ -1089,6 +1110,7 @@
Style.FixNamespaceComments = false;
Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Style.Standard = FormatStyle::LS_Cpp03;
+ Style.ConstStyle = FormatStyle::CS_Leave;
return Style;
}
@@ -1116,6 +1138,7 @@
Style.AllowShortLoopsOnASingleLine = false;
Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
+ Style.ConstStyle = FormatStyle::CS_Leave;
return Style;
}
@@ -1124,6 +1147,7 @@
NoStyle.DisableFormat = true;
NoStyle.SortIncludes = false;
NoStyle.SortUsingDeclarations = false;
+ NoStyle.ConstStyle = FormatStyle::CS_Leave;
return NoStyle;
}
@@ -2418,6 +2442,13 @@
});
}
+ if (Style.isCpp() || Style.Language == FormatStyle::LK_ObjC) {
+ if (Style.ConstStyle != FormatStyle::CS_Leave)
+ Passes.emplace_back([&](const Environment &Env) {
+ return EastWestConstFixer(Env, Expanded).process();
+ });
+ }
+
if (Style.Language == FormatStyle::LK_JavaScript &&
Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
Passes.emplace_back([&](const Environment &Env) {
Index: clang/lib/Format/EastWestConstFixer.h
===================================================================
--- /dev/null
+++ clang/lib/Format/EastWestConstFixer.h
@@ -0,0 +1,36 @@
+//===--- EastWwestConstFixer.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares EastWestConstFixer, a TokenAnalyzer that
+/// enforces either east or west const depending on the style.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_EASTWESTCONSTFIXER_H
+#define LLVM_CLANG_LIB_FORMAT_EASTWESTCONSTFIXER_H
+
+#include "TokenAnalyzer.h"
+
+namespace clang {
+namespace format {
+
+class EastWestConstFixer : public TokenAnalyzer {
+public:
+ EastWestConstFixer(const Environment &Env, const FormatStyle &Style);
+
+ std::pair<tooling::Replacements, unsigned>
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif
Index: clang/lib/Format/EastWestConstFixer.cpp
===================================================================
--- /dev/null
+++ clang/lib/Format/EastWestConstFixer.cpp
@@ -0,0 +1,249 @@
+//===--- EastWestConstFixer.cpp ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements EastWestConstFixer, a TokenAnalyzer that
+/// enforces either east or west const depending on the style.
+///
+//===----------------------------------------------------------------------===//
+
+#include "EastWestConstFixer.h"
+#include "FormatToken.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Regex.h"
+
+#include <algorithm>
+
+#define DEBUG_TYPE "using-declarations-sorter"
+
+namespace clang {
+namespace format {
+
+static void removeToken(const SourceManager &SourceMgr,
+ tooling::Replacements &Fixes,
+ const FormatToken *First) {
+ // Change `const int` to be `int const`.
+ auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
+ First->Tok.getEndLoc());
+
+ auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, ""));
+
+ if (Err) {
+ llvm::errs() << "Error while rearranging const : "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+}
+
+static void insertConstAfter(const SourceManager &SourceMgr,
+ tooling::Replacements &Fixes,
+ const FormatToken *First) {
+ FormatToken *Next = First->Next;
+ if (!Next) {
+ return;
+ }
+ // Change `const int` to be `int const`.
+ auto Range = CharSourceRange::getCharRange(First->Tok.getEndLoc(),
+ Next->getStartOfNonWhitespace());
+
+ auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, " const "));
+
+ if (Err) {
+ llvm::errs() << "Error while rearranging const : "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+}
+
+static void insertConstBefore(const SourceManager &SourceMgr,
+ tooling::Replacements &Fixes,
+ const FormatToken *First) {
+ // Change `const int` to be `int const`.
+ auto Range = CharSourceRange::getCharRange(
+ First->getStartOfNonWhitespace(), First->Next->getStartOfNonWhitespace());
+
+ std::string NewText = " const ";
+ NewText += First->TokenText;
+
+ auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, NewText));
+
+ if (Err) {
+ llvm::errs() << "Error while rearranging const : "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+}
+
+static void swapFirstTwoTokens(const SourceManager &SourceMgr,
+ tooling::Replacements &Fixes,
+ const FormatToken *First,
+ const FormatToken *Second) {
+ // Change `const int` to be `int const`.
+ std::string NewType = Second->TokenText;
+ NewType += " ";
+ NewType += First->TokenText;
+ auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
+ Second->Tok.getEndLoc());
+
+ auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, NewType));
+
+ if (Err) {
+ llvm::errs() << "Error while rearranging const : "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+}
+
+static void swapFirstThreeTokens(const SourceManager &SourceMgr,
+ tooling::Replacements &Fixes,
+ const FormatToken *First,
+ const FormatToken *Second,
+ const FormatToken *Third, bool West) {
+ // Change `const unsigned char` to be `unsigned char const`.
+ std::string NewType;
+ if (West) {
+ NewType = Third->TokenText;
+ NewType += " ";
+ NewType += First->TokenText;
+ NewType += " ";
+ NewType += Second->TokenText;
+ } else {
+ NewType = Second->TokenText;
+ NewType += " ";
+ NewType += Third->TokenText;
+ NewType += " ";
+ NewType += First->TokenText;
+ }
+
+ auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
+ Third->Tok.getEndLoc());
+
+ auto Err = Fixes.add(tooling::Replacement(SourceMgr, Range, NewType));
+
+ if (Err) {
+ llvm::errs() << "Error while rearranging const : "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+}
+
+static bool IsCVQualifierOrType(const FormatToken *Tok) {
+ if (!Tok)
+ return false;
+ return (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_volatile));
+}
+
+EastWestConstFixer::EastWestConstFixer(const Environment &Env,
+ const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+std::pair<tooling::Replacements, unsigned>
+EastWestConstFixer::analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) {
+ const AdditionalKeywords &Keywords = Tokens.getKeywords();
+ const SourceManager &SourceMgr = Env.getSourceManager();
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
+ tooling::Replacements Fixes;
+ for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
+ const auto *Tok = AnnotatedLines[I]->First;
+ const auto *Last = AnnotatedLines[I]->Last;
+
+ while (Tok && Tok != Last) {
+ if (!Tok->Next) {
+ break;
+ }
+ if (Tok->is(tok::comment)) {
+ Tok = Tok->Next;
+ continue;
+ }
+ if (Style.ConstStyle == FormatStyle::CS_Right) {
+ if (Tok->is(tok::kw_const) && IsCVQualifierOrType(Tok->Next) &&
+ Tok->Next->Next && IsCVQualifierOrType(Tok->Next->Next)) {
+ // The unsigned/signed case `const unsigned int` -> `unsigned int
+ // const`
+ swapFirstThreeTokens(SourceMgr, Fixes, Tok, Tok->Next,
+ Tok->Next->Next, /*West=*/false);
+ Tok = Tok->Next->Next;
+ continue;
+ } else if (Tok->is(tok::kw_const) &&
+ Tok->Next->isSimpleTypeSpecifier()) {
+ // The basic case `const int` -> `int const`
+ swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next);
+
+ } else if (Tok->startsSequence(tok::kw_const, tok::identifier)) {
+ // The case `const Foo` -> `Foo const`
+ // The case `const Foo *` -> `Foo const *`
+ if (Tok->Next->Next &&
+ Tok->Next->Next->isOneOf(tok::identifier, tok::star, tok::amp,
+ tok::ampamp) &&
+ !Tok->Next->isOneOf(Keywords.kw_override, Keywords.kw_final)) {
+ swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next);
+ } else if (Tok->startsSequence(tok::kw_const, tok::identifier,
+ TT_TemplateOpener)) {
+ // Read from to the end of the TemplateOpener to
+ // TemplateCloser const ArrayRef<int> a; const ArrayRef<int> &a;
+ FormatToken *EndTemplate = Tok->Next->Next->MatchingParen;
+ if (EndTemplate) {
+ // Move to the end of any template class members e.g.
+ // `Foo<int>::iterator`.
+ if (EndTemplate->startsSequence(
+ TT_TemplateCloser, tok::coloncolon, tok::identifier)) {
+ EndTemplate = EndTemplate->Next->Next;
+ }
+ // remove the const
+ removeToken(SourceMgr, Fixes, Tok);
+ insertConstAfter(SourceMgr, Fixes, EndTemplate);
+ }
+ }
+ }
+ } else if (Style.ConstStyle == FormatStyle::CS_Left) {
+ if (IsCVQualifierOrType(Tok) && IsCVQualifierOrType(Tok->Next) &&
+ Tok->Next->Next && Tok->Next->Next->is(tok::kw_const)) {
+ // The unsigned/signed case `unsigned int const` -> `const unsigned
+ // int`
+ swapFirstThreeTokens(SourceMgr, Fixes, Tok, Tok->Next,
+ Tok->Next->Next, /*West=*/true);
+ Tok = Tok->Next->Next;
+ continue;
+ } else if (Tok->isSimpleTypeSpecifier() &&
+ Tok->Next->is(tok::kw_const)) {
+ // The basic case `int const` -> `const int`
+ swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next);
+ } else if (Tok->startsSequence(tok::identifier, tok::kw_const)) {
+ if (Tok->Next->Next &&
+ Tok->Next->Next->isOneOf(tok::identifier, tok::star, tok::amp,
+ tok::ampamp)) {
+ // Don't swap `::iterator const` to `::const iterator`
+ if (!Tok->Previous ||
+ (Tok->Previous && !Tok->Previous->is(tok::coloncolon))) {
+ swapFirstTwoTokens(SourceMgr, Fixes, Tok, Tok->Next);
+ }
+ }
+ } else if (Tok->startsSequence(tok::identifier, TT_TemplateOpener)) {
+ // Read from to the end of the TemplateOpener to
+ // TemplateCloser const ArrayRef<int> a; const ArrayRef<int> &a;
+ FormatToken *EndTemplate = Tok->Next->MatchingParen;
+
+ // Move to the end of any template class members e.g.
+ // `Foo<int>::iterator`.
+ if (EndTemplate->startsSequence(TT_TemplateCloser, tok::coloncolon,
+ tok::identifier)) {
+ EndTemplate = EndTemplate->Next->Next;
+ }
+
+ if (EndTemplate && EndTemplate->Next &&
+ EndTemplate->Next->is(tok::kw_const)) {
+ // remove the const
+ removeToken(SourceMgr, Fixes, EndTemplate->Next);
+ insertConstBefore(SourceMgr, Fixes, Tok);
+ }
+ }
+ }
+ Tok = Tok->Next;
+ }
+ }
+ return {Fixes, 0};
+}
+} // namespace format
+} // namespace clang
Index: clang/lib/Format/CMakeLists.txt
===================================================================
--- clang/lib/Format/CMakeLists.txt
+++ clang/lib/Format/CMakeLists.txt
@@ -14,6 +14,7 @@
UnwrappedLineFormatter.cpp
UnwrappedLineParser.cpp
UsingDeclarationsSorter.cpp
+ EastWestConstFixer.cpp
WhitespaceManager.cpp
LINK_LIBS
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -1106,6 +1106,31 @@
/// \endcode
std::string CommentPragmas;
+ /// Different const alignment styles.
+ enum ConstAlignmentStyle {
+ /// Don't change const to either East const or West const.
+ /// \code
+ /// int const a;
+ /// const int *a;
+ /// \endcode
+ CS_Leave,
+ /// Change type decorations to be Left/Before/West const.
+ /// \code
+ /// const int a;
+ /// const int *a;
+ /// \endcode
+ CS_Left,
+ /// Change type decorations to be Right/After/East const.
+ /// \code
+ /// int const a;
+ /// int const *a;
+ /// \endcode
+ CS_Right
+ };
+
+ /// Different ways to arrange const.
+ ConstAlignmentStyle ConstStyle;
+
/// Different ways to break inheritance list.
enum BreakInheritanceListStyle {
/// Break inheritance list before the colon and after the commas.
@@ -2089,6 +2114,7 @@
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
BreakStringLiterals == R.BreakStringLiterals &&
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
+ ConstStyle == R.ConstStyle &&
BreakInheritanceList == R.BreakInheritanceList &&
ConstructorInitializerAllOnOneLineOrOnePerLine ==
R.ConstructorInitializerAllOnOneLineOrOnePerLine &&
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -340,6 +340,10 @@
const x = foo ?? default;
const z = foo?.bar?.baz;
+- Option ``ConstStyle`` has been added auto-arrange the positioning of const
+ in variable and parameter declarations to be ``East`` const or ``West``
+ const .
+
libclang
--------
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -1375,6 +1375,37 @@
namespace Extra {
}}}
+**ConstStyle** (``ConstAlignmentStyle``)
+ Different ways to arrange const.
+
+ Possible values:
+
+ * ``CS_Leave`` (in configuration: ``Leave``)
+ Don't change const to either East const or West const.
+
+ .. code-block:: c++
+
+ int const a;
+ const int *a;
+
+ * ``CS_Left`` (in configuration: ``Left``)
+ Change type decorations to be Left/Before/West const.
+
+ .. code-block:: c++
+
+ const int a;
+ const int *a;
+
+ * ``CS_Right`` (in configuration: ``Right``)
+ Change type decorations to be Right/After/East const.
+
+ .. code-block:: c++
+
+ int const a;
+ int const *a;
+
+
+
**ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``)
If the constructor initializers don't fit on a line, put each
initializer on its own line.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits