MyDeveloperDay updated this revision to Diff 372430.
MyDeveloperDay added a comment.

Allow more QualifierFixer functions to be directly tested, remove some older 
commented code.


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/Format.cpp
  clang/lib/Format/QualifierAlignmentFixer.cpp
  clang/lib/Format/QualifierAlignmentFixer.h
  clang/tools/clang-format/ClangFormat.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/FormatTest.cpp
  clang/unittests/Format/QualifierFixerTest.cpp

Index: clang/unittests/Format/QualifierFixerTest.cpp
===================================================================
--- /dev/null
+++ clang/unittests/Format/QualifierFixerTest.cpp
@@ -0,0 +1,803 @@
+//===- unittest/Format/QualifierFixerTest.cpp - Formatting unit tests -----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Format/Format.h"
+
+#include "FormatTestUtils.h"
+#include "TestLexer.h"
+#include "gtest/gtest.h"
+
+#include "../../lib/Format/QualifierAlignmentFixer.h"
+
+#define DEBUG_TYPE "format-qualifier-fixer-test"
+
+using testing::ScopedTrace;
+
+namespace clang {
+namespace format {
+namespace {
+
+#define CHECK_PARSE(TEXT, FIELD, VALUE)                                        \
+  EXPECT_NE(VALUE, Style.FIELD) << "Initial value already the same!";          \
+  EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
+
+#define FAIL_PARSE(TEXT, FIELD, VALUE)                                         \
+  EXPECT_NE(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
+
+class QualifierFixerTest : public ::testing::Test {
+protected:
+  enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck };
+
+  TokenList annotate(llvm::StringRef Code,
+                     const FormatStyle &Style = getLLVMStyle()) {
+    return TestLexer(Allocator, Buffers, Style).annotate(Code);
+  }
+  llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
+  std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
+
+  std::string format(llvm::StringRef Code,
+                     const FormatStyle &Style = getLLVMStyle(),
+                     StatusCheck CheckComplete = SC_ExpectComplete) {
+    LLVM_DEBUG(llvm::errs() << "---\n");
+    LLVM_DEBUG(llvm::errs() << Code << "\n\n");
+    std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+    FormattingAttemptStatus Status;
+    tooling::Replacements Replaces =
+        reformat(Style, Code, Ranges, "<stdin>", &Status);
+    if (CheckComplete != SC_DoNotCheck) {
+      bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
+      EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
+          << Code << "\n\n";
+    }
+    ReplacementCount = Replaces.size();
+    auto Result = applyAllReplacements(Code, Replaces);
+    EXPECT_TRUE(static_cast<bool>(Result));
+    LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+    return *Result;
+  }
+
+  FormatStyle getStyleWithColumns(FormatStyle Style, unsigned ColumnLimit) {
+    Style.ColumnLimit = ColumnLimit;
+    return Style;
+  }
+
+  FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
+    return getStyleWithColumns(getLLVMStyle(), ColumnLimit);
+  }
+
+  void _verifyFormat(const char *File, int Line, llvm::StringRef Expected,
+                     llvm::StringRef Code,
+                     const FormatStyle &Style = getLLVMStyle()) {
+    ScopedTrace t(File, Line, ::testing::Message() << Code.str());
+    EXPECT_EQ(Expected.str(), format(Expected, Style))
+        << "Expected code is not stable";
+    EXPECT_EQ(Expected.str(), format(Code, Style));
+    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.
+      FormatStyle ObjCStyle = Style;
+      ObjCStyle.Language = FormatStyle::LK_ObjC;
+      EXPECT_EQ(Expected.str(), format(test::messUp(Code), ObjCStyle));
+    }
+  }
+
+  void _verifyFormat(const char *File, int Line, llvm::StringRef Code,
+                     const FormatStyle &Style = getLLVMStyle()) {
+    _verifyFormat(File, Line, Code, test::messUp(Code), Style);
+  }
+
+  void _verifyIncompleteFormat(const char *File, int Line, llvm::StringRef Code,
+                               const FormatStyle &Style = getLLVMStyle()) {
+    ScopedTrace t(File, Line, ::testing::Message() << Code.str());
+    EXPECT_EQ(Code.str(),
+              format(test::messUp(Code), Style, SC_ExpectIncomplete));
+  }
+
+  void _verifyIndependentOfContext(const char *File, int Line,
+                                   llvm::StringRef Text,
+                                   const FormatStyle &Style = getLLVMStyle()) {
+    _verifyFormat(File, Line, Text, Style);
+    _verifyFormat(File, Line, llvm::Twine("void f() { " + Text + " }").str(),
+                  Style);
+  }
+
+  /// \brief Verify that clang-format does not crash on the given input.
+  void verifyNoCrash(llvm::StringRef Code,
+                     const FormatStyle &Style = getLLVMStyle()) {
+    format(Code, Style, SC_DoNotCheck);
+  }
+
+  int ReplacementCount;
+};
+
+#define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)
+
+}; // namespace
+
+TEST_F(QualifierFixerTest, RotateTokens) {
+  // TODO add test
+  EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("const"),
+            tok::kw_const);
+  EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("volatile"),
+            tok::kw_volatile);
+  EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("inline"),
+            tok::kw_inline);
+  EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("static"),
+            tok::kw_static);
+  EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("restrict"),
+            tok::kw_restrict);
+}
+
+TEST_F(QualifierFixerTest, FailQualifierInvalidConfiguration) {
+  FormatStyle Style = {};
+  Style.Language = FormatStyle::LK_Cpp;
+  FAIL_PARSE("QualifierAlignment: Custom\n"
+             "QualifierOrder: [const, volatile, apples, type]",
+             QualifierOrder,
+             std::vector<std::string>({"const", "volatile", "apples", "type"}));
+}
+
+TEST_F(QualifierFixerTest, FailQualifierDuplicateConfiguration) {
+  FormatStyle Style = {};
+  Style.Language = FormatStyle::LK_Cpp;
+  FAIL_PARSE("QualifierAlignment: Custom\n"
+             "QualifierOrder: [const, volatile, const, type]",
+             QualifierOrder,
+             std::vector<std::string>({"const", "volatile", "const", "type"}));
+}
+
+TEST_F(QualifierFixerTest, FailQualifierMissingType) {
+  FormatStyle Style = {};
+  Style.Language = FormatStyle::LK_Cpp;
+  FAIL_PARSE("QualifierAlignment: Custom\n"
+             "QualifierOrder: [const, volatile ]",
+             QualifierOrder,
+             std::vector<std::string>({
+                 "const",
+                 "volatile",
+             }));
+}
+
+TEST_F(QualifierFixerTest, FailQualifierEmptyOrder) {
+  FormatStyle Style = {};
+  Style.Language = FormatStyle::LK_Cpp;
+  FAIL_PARSE("QualifierAlignment: Custom\nQualifierOrder: []", QualifierOrder,
+             std::vector<std::string>({}));
+}
+
+TEST_F(QualifierFixerTest, FailQualifierMissingOrder) {
+  FormatStyle Style = {};
+  Style.Language = FormatStyle::LK_Cpp;
+  FAIL_PARSE("QualifierAlignment: Custom", QualifierOrder,
+             std::vector<std::string>());
+}
+
+TEST_F(QualifierFixerTest, QualifierLeft) {
+  FormatStyle Style = {};
+  Style.Language = FormatStyle::LK_Cpp;
+  CHECK_PARSE("QualifierAlignment: Left", QualifierOrder,
+              std::vector<std::string>({"const", "volatile", "type"}));
+}
+
+TEST_F(QualifierFixerTest, QualifierRight) {
+  FormatStyle Style = {};
+  Style.Language = FormatStyle::LK_Cpp;
+  CHECK_PARSE("QualifierAlignment: Right", QualifierOrder,
+              std::vector<std::string>({"type", "const", "volatile"}));
+}
+
+TEST_F(QualifierFixerTest, QualifiersCustomOrder) {
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Left;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("inline");
+  Style.QualifierOrder.push_back("constexpr");
+  Style.QualifierOrder.push_back("static");
+  Style.QualifierOrder.push_back("const");
+  Style.QualifierOrder.push_back("volatile");
+  Style.QualifierOrder.push_back("type");
+
+  verifyFormat("const volatile int a;", "const volatile int a;", Style);
+  verifyFormat("const volatile int a;", "volatile const int a;", Style);
+  verifyFormat("const volatile int a;", "int const volatile a;", Style);
+  verifyFormat("const volatile int a;", "int volatile const a;", Style);
+  verifyFormat("const volatile int a;", "const int volatile a;", Style);
+
+  verifyFormat("static const volatile int a;", "const static int volatile a;",
+               Style);
+  verifyFormat("inline static const volatile int a;",
+               "const static inline int volatile a;", Style);
+
+  verifyFormat("constexpr static int a;", "static constexpr int a;", Style);
+  verifyFormat("constexpr static int A;", "static constexpr int A;", Style);
+  verifyFormat("constexpr static int Bar;", "static constexpr int Bar;", Style);
+  verifyFormat("constexpr static LPINT Bar;", "static constexpr LPINT Bar;",
+               Style);
+  verifyFormat("const const int a;", "const int const a;", Style);
+}
+
+TEST_F(QualifierFixerTest, LeftRightQualifier) {
+  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);
+}
+
+TEST_F(QualifierFixerTest, RightQualifier) {
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Right;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("const");
+  Style.QualifierOrder.push_back("volatile");
+
+  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);
+  verifyFormat(
+      "template <typename Func> explicit Action(Action<Func> const &action);",
+      "template <typename Func> explicit Action(const Action<Func>& action);",
+      Style);
+  verifyFormat(
+      "template <typename Func> explicit Action(Action<Func> const &action);",
+      "template <typename Func>\nexplicit Action(const Action<Func>& action);",
+      Style);
+
+  verifyFormat("int const a;", "const int a;", Style);
+  verifyFormat("int const *a;", "const int *a;", Style);
+  verifyFormat("int const &a;", "const int &a;", Style);
+  verifyFormat("foo(int const &a)", "foo(const int &a)", Style);
+  verifyFormat("unsigned char *a;", "unsigned char *a;", Style);
+  verifyFormat("unsigned char const *a;", "const unsigned char *a;", Style);
+  verifyFormat("vector<int, int const, int &, int const &> args1",
+               "vector<int, const int, int &, const int &> args1", Style);
+  verifyFormat("unsigned int const &get_nu() const",
+               "const unsigned int &get_nu() const", Style);
+  verifyFormat("Foo<int> const &a", "const Foo<int> &a", Style);
+  verifyFormat("Foo<int>::iterator const &a", "const Foo<int>::iterator &a",
+               Style);
+
+  verifyFormat("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);
+
+  verifyFormat("int const volatile;", "volatile const int;", Style);
+  verifyFormat("int const volatile;", "const volatile int;", Style);
+  verifyFormat("int const volatile;", "const int volatile;", Style);
+  verifyFormat("int const volatile *restrict;", "volatile const int *restrict;",
+               Style);
+  verifyFormat("int const volatile *restrict;", "const volatile int *restrict;",
+               Style);
+  verifyFormat("int const volatile *restrict;", "const int volatile *restrict;",
+               Style);
+
+  verifyFormat("static int const bat;", "static const int bat;", Style);
+  verifyFormat("static int const bat;", "static int const bat;", Style);
+
+  verifyFormat("int const Foo<int>::bat = 0;", "const int Foo<int>::bat = 0;",
+               Style);
+  verifyFormat("int const Foo<int>::bat = 0;", "int const Foo<int>::bat = 0;",
+               Style);
+  verifyFormat("void fn(Foo<T> const &i);", "void fn(const Foo<T> &i);", Style);
+  verifyFormat("int const Foo<int>::fn() {", "int const Foo<int>::fn() {",
+               Style);
+  verifyFormat("Foo<Foo<int>> const *p;", "const Foo<Foo<int>> *p;", Style);
+  verifyFormat(
+      "Foo<Foo<int>> const *p = const_cast<Foo<Foo<int>> const *>(&ffi);",
+      "const Foo<Foo<int>> *p = const_cast<const Foo<Foo<int>> *>(&ffi);",
+      Style);
+
+  verifyFormat("void fn(Foo<T> const &i);", "void fn(const Foo<T> &i);", Style);
+  verifyFormat("void fns(ns::S const &s);", "void fns(const ns::S &s);", Style);
+  verifyFormat("void fn(ns::Foo<T> const &i);", "void fn(const ns::Foo<T> &i);",
+               Style);
+  verifyFormat("void fns(ns::ns2::S const &s);",
+               "void fns(const ns::ns2::S &s);", Style);
+  verifyFormat("void fn(ns::Foo<Bar<T>> const &i);",
+               "void fn(const ns::Foo<Bar<T>> &i);", Style);
+  verifyFormat("void fn(ns::ns2::Foo<Bar<T>> const &i);",
+               "void fn(const ns::ns2::Foo<Bar<T>> &i);", Style);
+  verifyFormat("void fn(ns::ns2::Foo<Bar<T, U>> const &i);",
+               "void fn(const ns::ns2::Foo<Bar<T, U>> &i);", Style);
+
+  verifyFormat("LocalScope const *Scope = nullptr;",
+               "const LocalScope* Scope = nullptr;", Style);
+  verifyFormat("struct DOTGraphTraits<Stmt const *>",
+               "struct DOTGraphTraits<const Stmt *>", Style);
+
+  verifyFormat(
+      "bool tools::addXRayRuntime(ToolChain const &TC, ArgList const &Args) {",
+      "bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args) {",
+      Style);
+  verifyFormat("Foo<Foo<int> const> P;", "Foo<const Foo<int>> P;", Style);
+  verifyFormat("Foo<Foo<int> const> P;\n", "Foo<const Foo<int>> P;\n", Style);
+  verifyFormat("Foo<Foo<int> const> P;\n#if 0\n#else\n#endif",
+               "Foo<const Foo<int>> P;\n#if 0\n#else\n#endif", Style);
+
+  verifyFormat("auto const i = 0;", "const auto i = 0;", Style);
+  verifyFormat("auto const &ir = i;", "const auto &ir = i;", Style);
+  verifyFormat("auto const *ip = &i;", "const auto *ip = &i;", Style);
+
+  verifyFormat("Foo<Foo<int> const> P;\n#if 0\n#else\n#endif",
+               "Foo<const Foo<int>> P;\n#if 0\n#else\n#endif", Style);
+
+  verifyFormat("Bar<Bar<int const> const> P;\n#if 0\n#else\n#endif",
+               "Bar<Bar<const int> const> P;\n#if 0\n#else\n#endif", Style);
+
+  verifyFormat("Baz<Baz<int const> const> P;\n#if 0\n#else\n#endif",
+               "Baz<const Baz<const int>> P;\n#if 0\n#else\n#endif", Style);
+
+  // verifyFormat("#if 0\nBoo<Boo<int const> const> P;\n#else\n#endif",
+  //             "#if 0\nBoo<const Boo<const int>> P;\n#else\n#endif", Style);
+
+  verifyFormat("int const P;\n#if 0\n#else\n#endif",
+               "const int P;\n#if 0\n#else\n#endif", Style);
+
+  verifyFormat("unsigned long const a;", "const unsigned long a;", Style);
+  verifyFormat("unsigned long long const a;", "const unsigned long long a;",
+               Style);
+
+  // don't adjust macros
+  verifyFormat("const INTPTR a;", "const INTPTR a;", Style);
+}
+
+TEST_F(QualifierFixerTest, LeftQualifier) {
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_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);
+  verifyFormat("const unsigned char *a;", "unsigned char const *a;", Style);
+  verifyFormat("const Foo<int> &a", "Foo<int> const &a", Style);
+  verifyFormat("const Foo<int>::iterator &a", "Foo<int>::iterator const &a",
+               Style);
+
+  verifyFormat("const int a;", "int const a;", Style);
+  verifyFormat("const int *a;", "int const *a;", Style);
+  verifyFormat("const int &a;", "int const &a;", Style);
+  verifyFormat("foo(const int &a)", "foo(int const &a)", Style);
+  verifyFormat("unsigned char *a;", "unsigned char *a;", Style);
+  verifyFormat("const unsigned int &get_nu() const",
+               "unsigned int const &get_nu() const", Style);
+
+  verifyFormat("const volatile int;", "volatile const int;", Style);
+  verifyFormat("const volatile int;", "const volatile int;", Style);
+  verifyFormat("const volatile int;", "const int volatile;", Style);
+
+  verifyFormat("const volatile int *restrict;", "volatile const int *restrict;",
+               Style);
+  verifyFormat("const volatile int *restrict;", "const volatile int *restrict;",
+               Style);
+  verifyFormat("const volatile int *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);
+  verifyFormat(
+      "template <typename Func> explicit Action(const Action<Func> &action);",
+      "template <typename Func> explicit Action(Action<Func> const &action);",
+      Style);
+
+  verifyFormat("static const int bat;", "static const int bat;", Style);
+  verifyFormat("static const int bat;", "static int const bat;", Style);
+
+  verifyFormat("static const int Foo<int>::bat = 0;",
+               "static const int Foo<int>::bat = 0;", Style);
+  verifyFormat("static const int Foo<int>::bat = 0;",
+               "static int const Foo<int>::bat = 0;", Style);
+
+  verifyFormat("void fn(const Foo<T> &i);");
+
+  verifyFormat("const int Foo<int>::bat = 0;", "const int Foo<int>::bat = 0;",
+               Style);
+  verifyFormat("const int Foo<int>::bat = 0;", "int const Foo<int>::bat = 0;",
+               Style);
+  verifyFormat("void fn(const Foo<T> &i);", "void fn( Foo<T> const &i);",
+               Style);
+  verifyFormat("const int Foo<int>::fn() {", "int const Foo<int>::fn() {",
+               Style);
+  verifyFormat("const Foo<Foo<int>> *p;", "Foo<Foo<int>> const *p;", Style);
+  verifyFormat(
+      "const Foo<Foo<int>> *p = const_cast<const Foo<Foo<int>> *>(&ffi);",
+      "const Foo<Foo<int>> *p = const_cast<Foo<Foo<int>> const *>(&ffi);",
+      Style);
+
+  verifyFormat("void fn(const Foo<T> &i);", "void fn(Foo<T> const &i);", Style);
+  verifyFormat("void fns(const ns::S &s);", "void fns(ns::S const &s);", Style);
+  verifyFormat("void fn(const ns::Foo<T> &i);", "void fn(ns::Foo<T> const &i);",
+               Style);
+  verifyFormat("void fns(const ns::ns2::S &s);",
+               "void fns(ns::ns2::S const &s);", Style);
+  verifyFormat("void fn(const ns::Foo<Bar<T>> &i);",
+               "void fn(ns::Foo<Bar<T>> const &i);", Style);
+  verifyFormat("void fn(const ns::ns2::Foo<Bar<T>> &i);",
+               "void fn(ns::ns2::Foo<Bar<T>> const &i);", Style);
+  verifyFormat("void fn(const ns::ns2::Foo<Bar<T, U>> &i);",
+               "void fn(ns::ns2::Foo<Bar<T, U>> const &i);", Style);
+
+  verifyFormat("const auto i = 0;", "auto const i = 0;", Style);
+  verifyFormat("const auto &ir = i;", "auto const &ir = i;", Style);
+  verifyFormat("const auto *ip = &i;", "auto const *ip = &i;", Style);
+
+  verifyFormat("Foo<const Foo<int>> P;\n#if 0\n#else\n#endif",
+               "Foo<Foo<int> const> P;\n#if 0\n#else\n#endif", Style);
+
+  verifyFormat("Foo<Foo<const int>> P;\n#if 0\n#else\n#endif",
+               "Foo<Foo<int const>> P;\n#if 0\n#else\n#endif", Style);
+
+  verifyFormat("const int P;\n#if 0\n#else\n#endif",
+               "int const P;\n#if 0\n#else\n#endif", Style);
+
+  verifyFormat("const unsigned long a;", "unsigned long const a;", Style);
+  verifyFormat("const unsigned long long a;", "unsigned long long const a;",
+               Style);
+
+  verifyFormat("const long long unsigned a;", "long const long unsigned a;",
+               Style);
+
+  verifyFormat("const std::Foo", "const std::Foo", Style);
+  verifyFormat("const std::Foo<>", "const std::Foo<>", Style);
+  verifyFormat("const std::Foo < int", "const std::Foo<int", Style);
+  verifyFormat("const std::Foo<int>", "const std::Foo<int>", Style);
+
+  // don't adjust macros
+  verifyFormat("INTPTR const a;", "INTPTR const a;", Style);
+}
+
+TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) {
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Left;
+
+  // the Default
+  EXPECT_EQ(Style.QualifierOrder.size(), 5);
+  EXPECT_EQ(Style.QualifierOrder[0], "inline");
+  EXPECT_EQ(Style.QualifierOrder[1], "static");
+  EXPECT_EQ(Style.QualifierOrder[2], "const");
+  EXPECT_EQ(Style.QualifierOrder[3], "volatile");
+  EXPECT_EQ(Style.QualifierOrder[4], "type");
+
+  verifyFormat("const volatile int a;", "const volatile int a;", Style);
+  verifyFormat("const volatile int a;", "volatile const int a;", Style);
+  verifyFormat("const volatile int a;", "int const volatile a;", Style);
+  verifyFormat("const volatile int a;", "int volatile const a;", Style);
+  verifyFormat("const volatile int a;", "const int volatile a;", Style);
+
+  Style.QualifierAlignment = FormatStyle::QAS_Right;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("const");
+  Style.QualifierOrder.push_back("volatile");
+
+  verifyFormat("int const volatile a;", "const volatile int a;", Style);
+  verifyFormat("int const volatile a;", "volatile const int a;", Style);
+  verifyFormat("int const volatile a;", "int const volatile a;", Style);
+  verifyFormat("int const volatile a;", "int volatile const a;", Style);
+  verifyFormat("int const volatile a;", "const int volatile a;", Style);
+
+  Style.QualifierAlignment = FormatStyle::QAS_Left;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("volatile");
+  Style.QualifierOrder.push_back("const");
+  Style.QualifierOrder.push_back("type");
+
+  verifyFormat("volatile const int a;", "const volatile int a;", Style);
+  verifyFormat("volatile const int a;", "volatile const int a;", Style);
+  verifyFormat("volatile const int a;", "int const volatile a;", Style);
+  verifyFormat("volatile const int a;", "int volatile const a;", Style);
+  verifyFormat("volatile const int a;", "const int volatile a;", Style);
+
+  Style.QualifierAlignment = FormatStyle::QAS_Right;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("volatile");
+  Style.QualifierOrder.push_back("const");
+
+  verifyFormat("int volatile const a;", "const volatile int a;", Style);
+  verifyFormat("int volatile const a;", "volatile const int a;", Style);
+  verifyFormat("int volatile const a;", "int const volatile a;", Style);
+  verifyFormat("int volatile const a;", "int volatile const a;", Style);
+  verifyFormat("int volatile const a;", "const int volatile a;", Style);
+
+  Style.QualifierAlignment = FormatStyle::QAS_Custom;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("volatile");
+  Style.QualifierOrder.push_back("const");
+
+  verifyFormat("int volatile const a;", "const volatile int a;", Style);
+  verifyFormat("int volatile const a;", "volatile const int a;", Style);
+  verifyFormat("int volatile const a;", "int const volatile a;", Style);
+  verifyFormat("int volatile const a;", "int volatile const a;", Style);
+  verifyFormat("int volatile const a;", "const int volatile a;", Style);
+}
+
+TEST_F(QualifierFixerTest, InlineStatics) {
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Left;
+
+  // the Default
+  EXPECT_EQ(Style.QualifierOrder.size(), 5);
+  EXPECT_EQ(Style.QualifierOrder[0], "inline");
+  EXPECT_EQ(Style.QualifierOrder[1], "static");
+  EXPECT_EQ(Style.QualifierOrder[2], "const");
+  EXPECT_EQ(Style.QualifierOrder[3], "volatile");
+  EXPECT_EQ(Style.QualifierOrder[4], "type");
+
+  verifyFormat("inline static const volatile int a;",
+               "const inline static volatile int a;", Style);
+  verifyFormat("inline static const volatile int a;",
+               "volatile inline static const int a;", Style);
+  verifyFormat("inline static const volatile int a;",
+               "int const inline static  volatile a;", Style);
+  verifyFormat("inline static const volatile int a;",
+               "int volatile inline static  const a;", Style);
+  verifyFormat("inline static const volatile int a;",
+               "const int inline static  volatile a;", Style);
+}
+
+TEST_F(QualifierFixerTest, AmpEqual) {
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Custom;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("static");
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("const");
+  EXPECT_EQ(Style.QualifierOrder.size(), 3);
+
+  verifyFormat("foo(std::string const & = std::string()) const",
+               "foo(const std::string & = std::string()) const", Style);
+  verifyFormat("foo(std::string const & = std::string())",
+               "foo(const std::string & = std::string())", Style);
+}
+
+TEST_F(QualifierFixerTest, MoveConstBeyondTypeSmall) {
+
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Custom;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("const");
+  EXPECT_EQ(Style.QualifierOrder.size(), 2);
+
+  verifyFormat("int const a;", "const int a;", Style);
+  verifyFormat("int const *a;", "const int*a;", Style);
+  verifyFormat("int const *a;", "const int *a;", Style);
+  verifyFormat("int const &a;", "const int &a;", Style);
+  verifyFormat("int const &&a;", "const int &&a;", Style);
+}
+
+TEST_F(QualifierFixerTest, MoveConstBeforeTypeSmall) {
+
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Custom;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("const");
+  Style.QualifierOrder.push_back("type");
+  EXPECT_EQ(Style.QualifierOrder.size(), 2);
+
+  verifyFormat("const int a;", "int const a;", Style);
+  verifyFormat("const int *a;", "int const *a;", Style);
+  verifyFormat("const int *a const;", "int const *a const;", Style);
+
+  verifyFormat("const int a = foo();", "int const a = foo();", Style);
+  verifyFormat("const int *a = foo();", "int const *a = foo();", Style);
+  verifyFormat("const int *a const = foo();", "int const *a const = foo();",
+               Style);
+
+  verifyFormat("const auto a = foo();", "auto const a = foo();", Style);
+  verifyFormat("const auto *a = foo();", "auto const *a = foo();", Style);
+  verifyFormat("const auto *a const = foo();", "auto const *a const = foo();",
+               Style);
+}
+
+TEST_F(QualifierFixerTest, MoveConstBeyondType) {
+
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Custom;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("static");
+  Style.QualifierOrder.push_back("inline");
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("const");
+  Style.QualifierOrder.push_back("volatile");
+  EXPECT_EQ(Style.QualifierOrder.size(), 5);
+
+  verifyFormat("static inline int const volatile a;",
+               "const inline static volatile int a;", Style);
+  verifyFormat("static inline int const volatile a;",
+               "volatile inline static const int a;", Style);
+  verifyFormat("static inline int const volatile a;",
+               "int const inline static  volatile a;", Style);
+  verifyFormat("static inline int const volatile a;",
+               "int volatile inline static  const a;", Style);
+  verifyFormat("static inline int const volatile a;",
+               "const int inline static  volatile a;", Style);
+
+  verifyFormat("static inline int const volatile *a const;",
+               "const int inline static  volatile *a const;", Style);
+}
+
+TEST_F(QualifierFixerTest, PrepareLeftRightOrdering) {
+  FormatStyle Style = getLLVMStyle();
+  Style.QualifierAlignment = FormatStyle::QAS_Custom;
+  Style.QualifierOrder.clear();
+  Style.QualifierOrder.push_back("static");
+  Style.QualifierOrder.push_back("inline");
+  Style.QualifierOrder.push_back("type");
+  Style.QualifierOrder.push_back("const");
+  Style.QualifierOrder.push_back("volatile");
+
+  std::vector<std::string> Left;
+  std::vector<std::string> Right;
+  QualifierAlignmentFixer::PrepareLeftRightOrdering(Style.QualifierOrder, Left,
+                                                    Right);
+
+  EXPECT_EQ(Left.size(), 2);
+  EXPECT_EQ(Right.size(), 2);
+
+  std::vector<std::string> LeftResult;
+  std::vector<std::string> RightResult;
+  LeftResult.push_back("inline");
+  LeftResult.push_back("static");
+
+  RightResult.push_back("const");
+  RightResult.push_back("volatile");
+
+  EXPECT_EQ(Left, LeftResult);
+  EXPECT_EQ(Right, RightResult);
+}
+
+TEST_F(QualifierFixerTest, IsQualifierType) {
+
+  auto Tokens =
+      annotate("const static inline auto restrict int double long constexpr");
+
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[0]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[1]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[2]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[3]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[4]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[5]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[6]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[7]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(Tokens[8]));
+
+  auto NotTokens = annotate("for while do Foo Bar ");
+
+  EXPECT_FALSE(
+      LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[0]));
+  EXPECT_FALSE(
+      LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[1]));
+  EXPECT_FALSE(
+      LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[2]));
+  EXPECT_FALSE(
+      LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[3]));
+  EXPECT_FALSE(
+      LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[4]));
+  EXPECT_FALSE(
+      LeftRightQualifierAlignmentFixer::isQualifierOrType(NotTokens[5]));
+}
+
+TEST_F(QualifierFixerTest, IsMacro) {
+
+  auto Tokens = annotate("INT INTPR Foo int");
+
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isPossibleMacro(Tokens[0]));
+  EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isPossibleMacro(Tokens[1]));
+  EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isPossibleMacro(Tokens[2]));
+  EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isPossibleMacro(Tokens[3]));
+}
+
+} // namespace format
+} // namespace clang
Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -18230,6 +18230,10 @@
   EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value());                      \
   EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
 
+#define FAIL_PARSE(TEXT, FIELD, VALUE)                                         \
+  EXPECT_NE(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
+
 TEST_F(FormatTest, ParsesConfigurationBools) {
   FormatStyle Style = {};
   Style.Language = FormatStyle::LK_Cpp;
@@ -18325,6 +18329,26 @@
   CHECK_PARSE("ContinuationIndentWidth: 11", ContinuationIndentWidth, 11u);
   CHECK_PARSE("CommentPragmas: '// abc$'", CommentPragmas, "// abc$");
 
+  Style.QualifierAlignment = FormatStyle::QAS_Right;
+  CHECK_PARSE("QualifierAlignment: Leave", QualifierAlignment,
+              FormatStyle::QAS_Leave);
+  CHECK_PARSE("QualifierAlignment: Right", QualifierAlignment,
+              FormatStyle::QAS_Right);
+  CHECK_PARSE("QualifierAlignment: Left", QualifierAlignment,
+              FormatStyle::QAS_Left);
+  CHECK_PARSE("QualifierAlignment: Custom", QualifierAlignment,
+              FormatStyle::QAS_Custom);
+
+  Style.QualifierOrder.clear();
+  CHECK_PARSE("QualifierOrder: [ const, volatile, type ]", QualifierOrder,
+              std::vector<std::string>({"const", "volatile", "type"}));
+  Style.QualifierOrder.clear();
+  CHECK_PARSE("QualifierOrder: [const, type]", QualifierOrder,
+              std::vector<std::string>({"const", "type"}));
+  Style.QualifierOrder.clear();
+  CHECK_PARSE("QualifierOrder: [volatile, type]", QualifierOrder,
+              std::vector<std::string>({"volatile", "type"}));
+
   Style.AlignConsecutiveAssignments = FormatStyle::ACS_Consecutive;
   CHECK_PARSE("AlignConsecutiveAssignments: None", AlignConsecutiveAssignments,
               FormatStyle::ACS_None);
@@ -18992,8 +19016,6 @@
   EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);
 }
 
-#undef CHECK_PARSE
-
 TEST_F(FormatTest, UsesLanguageForBasedOnStyle) {
   FormatStyle Style = {};
   Style.Language = FormatStyle::LK_JavaScript;
@@ -22294,6 +22316,7 @@
       "}";
   EXPECT_EQ(Code, format(Code, Style));
 }
+
 } // namespace
 } // namespace format
 } // namespace clang
Index: clang/unittests/Format/CMakeLists.txt
===================================================================
--- clang/unittests/Format/CMakeLists.txt
+++ clang/unittests/Format/CMakeLists.txt
@@ -18,6 +18,7 @@
   FormatTestTextProto.cpp
   MacroExpanderTest.cpp
   NamespaceEndCommentsFixerTest.cpp
+  QualifierFixerTest.cpp
   SortImportsTestJS.cpp
   SortImportsTestJava.cpp
   SortIncludesTest.cpp
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,13 @@
              "SortIncludes style flag"),
     cl::cat(ClangFormatCategory));
 
+static cl::opt<std::string> QualifierAlignment(
+    "qualifier-aligment",
+    cl::desc(
+        "If set, overrides the cvqualifier style behavior determined by the "
+        "QualifierAlignment 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));
@@ -402,6 +410,14 @@
     return true;
   }
 
+  StringRef ConstAlignment = QualifierAlignment;
+
+  FormatStyle->QualifierAlignment =
+      StringSwitch<FormatStyle::QualifierAlignmentStyle>(ConstAlignment.lower())
+          .Case("right", FormatStyle::QAS_Right)
+          .Case("left", FormatStyle::QAS_Left)
+          .Default(FormatStyle->QualifierAlignment);
+
   if (SortIncludes.getNumOccurrences() != 0) {
     if (SortIncludes)
       FormatStyle->SortIncludes = FormatStyle::SI_CaseSensitive;
Index: clang/lib/Format/QualifierAlignmentFixer.h
===================================================================
--- /dev/null
+++ clang/lib/Format/QualifierAlignmentFixer.h
@@ -0,0 +1,97 @@
+//===--- LeftRightQualifierAlignmentFixer.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 LeftRightQualifierAlignmentFixer, a TokenAnalyzer that
+/// enforces either east or west const depending on the style.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_LeftRightQualifierAlignmentFixer_H
+#define LLVM_CLANG_LIB_FORMAT_LeftRightQualifierAlignmentFixer_H
+
+#include "TokenAnalyzer.h"
+
+namespace clang {
+namespace format {
+
+typedef std::function<std::pair<tooling::Replacements, unsigned>(
+    const Environment &)>
+    AnalyzerPass;
+
+class QualifierAlignmentFixer : public TokenAnalyzer {
+  // Left to Right ordering requires multiple passes
+  SmallVector<AnalyzerPass, 8> Passes;
+  StringRef &Code;
+  ArrayRef<tooling::Range> Ranges;
+  unsigned FirstStartColumn;
+  unsigned NextStartColumn;
+  unsigned LastStartColumn;
+  StringRef FileName;
+
+public:
+  QualifierAlignmentFixer(const Environment &Env, const FormatStyle &Style,
+                          StringRef &Code, ArrayRef<tooling::Range> Ranges,
+                          unsigned FirstStartColumn, unsigned NextStartColumn,
+                          unsigned LastStartColumn, StringRef FileName);
+
+  std::pair<tooling::Replacements, unsigned>
+  analyze(TokenAnnotator &Annotator,
+          SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+          FormatTokenLexer &Tokens) override;
+
+  static void QualifierAlignmentFixer::PrepareLeftRightOrdering(
+      const std::vector<std::string> &Order,
+      std::vector<std::string> &LeftOrder,
+      std::vector<std::string> &RightOrder);
+};
+
+class LeftRightQualifierAlignmentFixer : public TokenAnalyzer {
+  std::string Qualifier;
+  FormatStyle::QualifierAlignmentStyle Alignment;
+  SmallVector<tok::TokenKind, 8> QualifierTokens;
+
+public:
+  LeftRightQualifierAlignmentFixer(
+      const Environment &Env, const FormatStyle &Style,
+      const std::string &Qualifier,
+      const FormatStyle::QualifierAlignmentStyle &Alignment);
+
+  std::pair<tooling::Replacements, unsigned>
+  analyze(TokenAnnotator &Annotator,
+          SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+          FormatTokenLexer &Tokens) override;
+
+  static tok::TokenKind getTokenFromQualifier(const std::string &Qualifier);
+
+  static FormatToken *analyzeRight(const SourceManager &SourceMgr,
+                                   const AdditionalKeywords &Keywords,
+                                   tooling::Replacements &Fixes,
+                                   FormatToken *Tok,
+                                   const std::string &Qualifier,
+                                   tok::TokenKind QualifierType);
+
+  static FormatToken *analyzeLeft(const SourceManager &SourceMgr,
+                                  const AdditionalKeywords &Keywords,
+                                  tooling::Replacements &Fixes,
+                                  FormatToken *Tok,
+                                  const std::string &Qualifier,
+                                  tok::TokenKind QualifierType);
+
+  // is the Token a simple or qualifier type
+  static bool isQualifierOrType(const FormatToken *Tok);
+
+  // is the Token likely a Macro
+  static bool isPossibleMacro(const FormatToken *Tok);
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif
Index: clang/lib/Format/QualifierAlignmentFixer.cpp
===================================================================
--- /dev/null
+++ clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -0,0 +1,446 @@
+//===--- LeftRightQualifierAlignmentFixer.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 LeftRightQualifierAlignmentFixer, a TokenAnalyzer that
+/// enforces either east or west const depending on the style.
+///
+//===----------------------------------------------------------------------===//
+
+#include "QualifierAlignmentFixer.h"
+#include "FormatToken.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Regex.h"
+
+#include <algorithm>
+
+#define DEBUG_TYPE "format-qualifier-alignment-fixer"
+
+namespace clang {
+namespace format {
+
+static void replaceToken(const SourceManager &SourceMgr,
+                         tooling::Replacements &Fixes,
+                         const CharSourceRange &Range, std::string NewText) {
+  auto Replacement = tooling::Replacement(SourceMgr, Range, NewText);
+  auto Err = Fixes.add(Replacement);
+
+  if (Err)
+    llvm::errs() << "Error while rearranging qualifier : "
+                 << llvm::toString(std::move(Err)) << "\n";
+}
+
+static void removeToken(const SourceManager &SourceMgr,
+                        tooling::Replacements &Fixes,
+                        const FormatToken *First) {
+  auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
+                                             First->Tok.getEndLoc());
+  replaceToken(SourceMgr, Fixes, Range, "");
+}
+
+static void insertQualifierAfter(const SourceManager &SourceMgr,
+                                 tooling::Replacements &Fixes,
+                                 const FormatToken *First,
+                                 const std::string &Qualifier) {
+  FormatToken *Next = First->Next;
+  if (!Next)
+    return;
+  auto Range = CharSourceRange::getCharRange(Next->getStartOfNonWhitespace(),
+                                             Next->Tok.getEndLoc());
+
+  std::string NewText = " " + Qualifier + " ";
+  NewText += Next->TokenText;
+
+  replaceToken(SourceMgr, Fixes, Range, NewText);
+}
+
+static void insertQualifierBefore(const SourceManager &SourceMgr,
+                                  tooling::Replacements &Fixes,
+                                  const FormatToken *First,
+                                  const std::string &Qualifier) {
+  auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
+                                             First->Tok.getEndLoc());
+
+  std::string NewText = " " + Qualifier + " ";
+  NewText += First->TokenText;
+
+  replaceToken(SourceMgr, Fixes, Range, NewText);
+}
+static void rotateTokens(const SourceManager &SourceMgr,
+                         tooling::Replacements &Fixes, const FormatToken *First,
+                         const FormatToken *Last, bool Left) {
+  auto *End = Last;
+  auto *Begin = First;
+  if (!Left) {
+    End = Last->Next;
+    Begin = First->Next;
+  }
+
+  std::string NewText;
+  // If we are rotating to the left we move the Last token to the front.
+  if (Left) {
+    NewText += Last->TokenText;
+    NewText += " ";
+  }
+
+  // Then move through the other tokens.
+  auto *Tok = Begin;
+  while (Tok != End) {
+    if (!NewText.empty()) {
+      NewText += " ";
+    }
+
+    NewText += Tok->TokenText;
+    Tok = Tok->Next;
+  }
+
+  // If we are rotating to the right we move the first token to the back.
+  if (!Left) {
+    NewText += " ";
+    NewText += First->TokenText;
+  }
+
+  auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
+                                             Last->Tok.getEndLoc());
+
+  replaceToken(SourceMgr, Fixes, Range, NewText);
+}
+
+bool LeftRightQualifierAlignmentFixer::isQualifierOrType(
+    const FormatToken *Tok) {
+  return Tok && (Tok->isSimpleTypeSpecifier() ||
+                 Tok->isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_auto,
+                              tok::kw_static, tok::kw_inline, tok::kw_constexpr,
+                              tok::kw_restrict));
+}
+
+// If a token is an identifier and it's upper case, it could
+// be a macro and hence we need to be able to ignore it.
+bool LeftRightQualifierAlignmentFixer::isPossibleMacro(const FormatToken *Tok) {
+  if (!Tok)
+    return false;
+  if (!Tok->is(tok::identifier))
+    return false;
+  if (Tok->TokenText.upper() == Tok->TokenText.str())
+    return true;
+  return false;
+}
+
+FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
+    const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
+    tooling::Replacements &Fixes, FormatToken *Tok,
+    const std::string &Qualifier, tok::TokenKind QualifierType) {
+  // We only need to think about streams that begin with const.
+  if (!Tok->is(QualifierType))
+    return Tok;
+  // Don't concern yourself if nothing follows const.
+  if (!Tok->Next)
+    return Tok;
+  if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok->Next))
+    return Tok;
+  FormatToken *Const = Tok;
+
+  FormatToken *Qual = Tok->Next;
+  FormatToken *LastQual = Qual;
+  while (Qual && isQualifierOrType(Qual)) {
+    LastQual = Qual;
+    Qual = Qual->Next;
+  }
+  if (LastQual && Qual != LastQual) {
+    rotateTokens(SourceMgr, Fixes, Const, LastQual, /*Left=*/false);
+    Tok = LastQual;
+  } else if (Tok->startsSequence(QualifierType, tok::identifier,
+                                 TT_TemplateOpener)) {
+    // Read from the TemplateOpener to
+    // TemplateCloser as in 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;
+    }
+    if (EndTemplate && EndTemplate->Next &&
+        !EndTemplate->Next->isOneOf(tok::equal, tok::l_paren)) {
+      // Remove the const.
+      insertQualifierAfter(SourceMgr, Fixes, EndTemplate, Qualifier);
+      removeToken(SourceMgr, Fixes, Tok);
+      return Tok;
+    }
+  } else if (Tok->startsSequence(QualifierType, tok::identifier)) {
+    FormatToken *Next = Tok->Next;
+    // The case  `const Foo` -> `Foo const`
+    // The case  `const Foo *` -> `Foo const *`
+    // The case  `const Foo &` -> `Foo const &`
+    // The case  `const Foo &&` -> `Foo const &&`
+    // The case  `const std::Foo &&` -> `std::Foo const &&`
+    // The case  `const std::Foo<T> &&` -> `std::Foo<T> const &&`
+    while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) {
+      Next = Next->Next;
+    }
+    if (Next && Next->is(TT_TemplateOpener)) {
+      Next = Next->MatchingParen;
+      // Move to the end of any template class members e.g.
+      // `Foo<int>::iterator`.
+      if (Next && Next->startsSequence(TT_TemplateCloser, tok::coloncolon,
+                                       tok::identifier)) {
+        Next = Next->Next->Next;
+        return Tok;
+      }
+      assert(Next && "Missing template opener");
+      Next = Next->Next;
+    }
+    if (Next && Next->isOneOf(tok::star, tok::amp, tok::ampamp) &&
+        !Tok->Next->isOneOf(Keywords.kw_override, Keywords.kw_final)) {
+      if (Next->Previous && !Next->Previous->is(QualifierType)) {
+        insertQualifierAfter(SourceMgr, Fixes, Next->Previous, Qualifier);
+        removeToken(SourceMgr, Fixes, Const);
+      }
+      return Next;
+    }
+  }
+
+  return Tok;
+}
+
+FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
+    const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
+    tooling::Replacements &Fixes, FormatToken *Tok,
+    const std::string &Qualifier, tok::TokenKind QualifierType) {
+  // if Tok is an identifier and possibly a macro then don't convert
+  if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok))
+    return Tok;
+
+  FormatToken *Qual = Tok;
+  FormatToken *LastQual = Qual;
+  while (Qual && isQualifierOrType(Qual)) {
+    LastQual = Qual;
+    Qual = Qual->Next;
+    if (Qual && Qual->is(QualifierType))
+      break;
+  }
+
+  if (!Qual) {
+    return Tok;
+  }
+
+  if (LastQual && Qual != LastQual && Qual->is(QualifierType)) {
+    rotateTokens(SourceMgr, Fixes, Tok, Qual, /*Left=*/true);
+    Tok = Qual->Next;
+  } else if (Tok->startsSequence(tok::identifier, QualifierType)) {
+    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)))
+        rotateTokens(SourceMgr, Fixes, Tok, Tok->Next, /*Left=*/true);
+    }
+  }
+  if (Tok->is(TT_TemplateOpener) && Tok->Next &&
+      (Tok->Next->is(tok::identifier) || Tok->Next->isSimpleTypeSpecifier()) &&
+      Tok->Next->Next && Tok->Next->Next->is(QualifierType)) {
+    rotateTokens(SourceMgr, Fixes, Tok->Next, Tok->Next->Next, /*Left=*/true);
+  }
+  if (Tok->startsSequence(tok::identifier) && Tok->Next) {
+    if (Tok->Previous &&
+        Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) {
+      return Tok;
+    }
+    FormatToken *Next = Tok->Next;
+    // The case  `std::Foo<T> const` -> `const std::Foo<T> &&`
+    while (Next && Next->isOneOf(tok::identifier, tok::coloncolon))
+      Next = Next->Next;
+    if (Next && Next->Previous &&
+        Next->Previous->startsSequence(tok::identifier, TT_TemplateOpener)) {
+      // Read from to the end of the TemplateOpener to
+      // TemplateCloser const ArrayRef<int> a; const ArrayRef<int> &a;
+      assert(Next->MatchingParen && "Missing template closer");
+      Next = Next->MatchingParen->Next;
+
+      // Move to the end of any template class members e.g.
+      // `Foo<int>::iterator`.
+      if (Next && Next->startsSequence(tok::coloncolon, tok::identifier))
+        Next = Next->Next->Next;
+      if (Next && Next->is(QualifierType)) {
+        // Remove the const.
+        removeToken(SourceMgr, Fixes, Next);
+        insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier);
+        return Next;
+      }
+    }
+    if (Next && Next->Next &&
+        Next->Next->isOneOf(tok::amp, tok::ampamp, tok::star)) {
+      if (Next->is(QualifierType)) {
+        // Remove the const.
+        removeToken(SourceMgr, Fixes, Next);
+        insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier);
+        return Next;
+      }
+    }
+  }
+  return Tok;
+}
+
+tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
+    const std::string &Qualifier) {
+  // don't let 'type' be an indentifier steal typeof token
+  return llvm::StringSwitch<tok::TokenKind>(Qualifier)
+      .Case("type", tok::kw_typeof)
+      .Case("const", tok::kw_const)
+      .Case("volatile", tok::kw_volatile)
+      .Case("static", tok::kw_static)
+      .Case("inline", tok::kw_inline)
+      .Case("constexpr", tok::kw_constexpr)
+      .Case("restrict", tok::kw_restrict)
+      .Default(tok::identifier);
+}
+
+LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer(
+    const Environment &Env, const FormatStyle &Style,
+    const std::string &Qualifier,
+    const FormatStyle::QualifierAlignmentStyle &Alignment)
+    : TokenAnalyzer(Env, Style), Qualifier(Qualifier), Alignment(Alignment) {}
+
+std::pair<tooling::Replacements, unsigned>
+LeftRightQualifierAlignmentFixer::analyze(
+    TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+    FormatTokenLexer &Tokens) {
+  tooling::Replacements Fixes;
+  const AdditionalKeywords &Keywords = Tokens.getKeywords();
+  const SourceManager &SourceMgr = Env.getSourceManager();
+  AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
+
+  tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier);
+  assert(QualifierToken != tok::identifier && "Unrecognised Qualifier");
+
+  for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
+    FormatToken *First = AnnotatedLines[I]->First;
+    const auto *Last = AnnotatedLines[I]->Last;
+
+    for (auto *Tok = First; Tok && Tok != Last && Tok->Next; Tok = Tok->Next) {
+      if (Tok->is(tok::comment))
+        continue;
+      if (Alignment == FormatStyle::QAS_Right)
+        Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier,
+                           QualifierToken);
+      else if (Alignment == FormatStyle::QAS_Left)
+        Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier,
+                          QualifierToken);
+    }
+  }
+  return {Fixes, 0};
+}
+
+void QualifierAlignmentFixer::PrepareLeftRightOrdering(
+    const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder,
+    std::vector<std::string> &RightOrder) {
+
+  // Depending on the position of type in the order you need
+  // To iterate forward or backward through the order list as qualifier
+  // can push through each other.
+  auto type = std::find(Order.begin(), Order.end(), "type");
+  // The Order list must define the position of "type" to signify
+  assert(type != Order.end() && "QualifierOrder must contain type");
+  // Split the Order list by type and reverse the left side
+  bool left = true;
+  for (const auto &s : Order) {
+    if (s == "type") {
+      left = false;
+      continue;
+    }
+    if (left) {
+      // Reverse the order for left aligned items.
+      LeftOrder.insert(LeftOrder.begin(), s);
+    } else {
+      RightOrder.push_back(s);
+    }
+  }
+}
+
+QualifierAlignmentFixer::QualifierAlignmentFixer(
+    const Environment &Env, const FormatStyle &Style, StringRef &Code,
+    ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
+    unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName)
+    : TokenAnalyzer(Env, Style), Code(Code), Ranges(Ranges),
+      FirstStartColumn(FirstStartColumn), NextStartColumn(NextStartColumn),
+      LastStartColumn(LastStartColumn), FileName(FileName) {
+  std::vector<std::string> LeftOrder;
+  std::vector<std::string> RightOrder;
+  PrepareLeftRightOrdering(Style.QualifierOrder, LeftOrder, RightOrder);
+
+  // Handle the left and right Alignment Seperately
+  for (const auto &Qualifier : LeftOrder) {
+    Passes.emplace_back([&, Qualifier](const Environment &Env) {
+      return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
+                                              FormatStyle::QAS_Left)
+          .process();
+    });
+  }
+  for (const auto &Qualifier : RightOrder) {
+    Passes.emplace_back([&, Qualifier](const Environment &Env) {
+      return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
+                                              FormatStyle::QAS_Right)
+          .process();
+    });
+  }
+}
+
+std::pair<tooling::Replacements, unsigned> QualifierAlignmentFixer::analyze(
+    TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+    FormatTokenLexer &Tokens) {
+
+  auto Env =
+      std::make_unique<Environment>(Code, FileName, Ranges, FirstStartColumn,
+                                    NextStartColumn, LastStartColumn);
+  llvm::Optional<std::string> CurrentCode = None;
+  tooling::Replacements Fixes;
+  unsigned Penalty = 0;
+  for (size_t I = 0, E = Passes.size(); I < E; ++I) {
+    std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
+    auto NewCode = applyAllReplacements(
+        CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
+    if (NewCode) {
+      Fixes = Fixes.merge(PassFixes.first);
+      Penalty += PassFixes.second;
+      if (I + 1 < E) {
+        CurrentCode = std::move(*NewCode);
+        Env = std::make_unique<Environment>(
+            *CurrentCode, FileName,
+            tooling::calculateRangesAfterReplacements(Fixes, Ranges),
+            FirstStartColumn, NextStartColumn, LastStartColumn);
+      }
+    }
+  }
+
+  // Don't make replacements that replace nothing
+  tooling::Replacements NonNoOpFixes;
+
+  for (auto I = Fixes.begin(), E = Fixes.end(); I != E; ++I) {
+
+    StringRef OriginalCode = Code.substr(I->getOffset(), I->getLength());
+
+    LLVM_DEBUG(llvm::dbgs() << "Replacement:[" << OriginalCode << "]["
+                            << I->getReplacementText() << "]\n");
+
+    if (!OriginalCode.equals(I->getReplacementText())) {
+      auto Err = NonNoOpFixes.add(*I);
+      if (Err)
+        llvm::errs() << "Error removing no op replacements : "
+                     << llvm::toString(std::move(Err)) << "\n";
+    } else {
+      LLVM_DEBUG(llvm::dbgs() << "No Op Fix:" << OriginalCode);
+    }
+  }
+
+  return {NonNoOpFixes, 0};
+}
+
+} // namespace format
+} // namespace clang
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -19,6 +19,7 @@
 #include "FormatInternal.h"
 #include "FormatTokenLexer.h"
 #include "NamespaceEndCommentsFixer.h"
+#include "QualifierAlignmentFixer.h"
 #include "SortJavaScriptImports.h"
 #include "TokenAnalyzer.h"
 #include "TokenAnnotator.h"
@@ -126,6 +127,16 @@
   }
 };
 
+template <>
+struct ScalarEnumerationTraits<FormatStyle::QualifierAlignmentStyle> {
+  static void enumeration(IO &IO, FormatStyle::QualifierAlignmentStyle &Value) {
+    IO.enumCase(Value, "Leave", FormatStyle::QAS_Leave);
+    IO.enumCase(Value, "Left", FormatStyle::QAS_Left);
+    IO.enumCase(Value, "Right", FormatStyle::QAS_Right);
+    IO.enumCase(Value, "Custom", FormatStyle::QAS_Custom);
+  }
+};
+
 template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
   static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
     IO.enumCase(Value, "None", FormatStyle::SFS_None);
@@ -641,6 +652,23 @@
     IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
     IO.mapOptional("ColumnLimit", Style.ColumnLimit);
     IO.mapOptional("CommentPragmas", Style.CommentPragmas);
+    IO.mapOptional("QualifierAlignment", Style.QualifierAlignment);
+
+    // Default Order for Left/Right based Qualifier alignment.
+    if (Style.QualifierAlignment == FormatStyle::QAS_Right) {
+      Style.QualifierOrder.clear();
+      Style.QualifierOrder.push_back("type");
+      Style.QualifierOrder.push_back("const");
+      Style.QualifierOrder.push_back("volatile");
+    } else if (Style.QualifierAlignment == FormatStyle::QAS_Left) {
+      Style.QualifierOrder.clear();
+      Style.QualifierOrder.push_back("const");
+      Style.QualifierOrder.push_back("volatile");
+      Style.QualifierOrder.push_back("type");
+    }
+
+    IO.mapOptional("QualifierOrder", Style.QualifierOrder);
+
     IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
     IO.mapOptional("ConstructorInitializerIndentWidth",
                    Style.ConstructorInitializerIndentWidth);
@@ -905,6 +933,14 @@
     return "Unsuitable";
   case ParseError::BinPackTrailingCommaConflict:
     return "trailing comma insertion cannot be used with bin packing";
+  case ParseError::InvalidQualifierSpecified:
+    return "Invalid qualifier specified in QualifierOrder";
+  case ParseError::DuplicateQualifierSpecified:
+    return "Duplicate qualifier specified in QualfierOrder";
+  case ParseError::MissingQualifierType:
+    return "Missing type in QualfierOrder";
+  case ParseError::MissingQualifierOrder:
+    return "Missing QualfierOrder";
   }
   llvm_unreachable("unexpected parse error");
 }
@@ -1078,6 +1114,16 @@
   LLVMStyle.ConstructorInitializerIndentWidth = 4;
   LLVMStyle.ContinuationIndentWidth = 4;
   LLVMStyle.Cpp11BracedListStyle = true;
+
+  // Off by default Qualifier ordering
+  LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
+  // Default 'Left' qualifier order but off by default.
+  LLVMStyle.QualifierOrder.push_back("inline");
+  LLVMStyle.QualifierOrder.push_back("static");
+  LLVMStyle.QualifierOrder.push_back("const");
+  LLVMStyle.QualifierOrder.push_back("volatile");
+  LLVMStyle.QualifierOrder.push_back("type");
+
   LLVMStyle.DeriveLineEnding = true;
   LLVMStyle.DerivePointerAlignment = false;
   LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never;
@@ -1512,6 +1558,37 @@
   return true;
 }
 
+ParseError validateQualifierOrder(FormatStyle *Style) {
+  // If its empty then it means don't do anything.
+  if (Style->QualifierOrder.empty())
+    return ParseError::MissingQualifierOrder;
+
+  // Ensure the list contains only currently valid qualifiers.
+  for (const auto &Qualifier : Style->QualifierOrder) {
+    if (Qualifier == "type")
+      continue;
+    auto token =
+        LeftRightQualifierAlignmentFixer::getTokenFromQualifier(Qualifier);
+    if (token == tok::identifier)
+      return ParseError::InvalidQualifierSpecified;
+  }
+  // Ensure the list is unqiue (no duplicates).
+  std::set<std::string> UniqueQualifiers(Style->QualifierOrder.begin(),
+                                         Style->QualifierOrder.end());
+  if (Style->QualifierOrder.size() != UniqueQualifiers.size()) {
+    LLVM_DEBUG(llvm::dbgs()
+               << "Duplicate Qualifiers " << Style->QualifierOrder.size()
+               << " vs " << UniqueQualifiers.size() << "\n");
+    return ParseError::DuplicateQualifierSpecified;
+  }
+
+  auto type = std::find(Style->QualifierOrder.begin(),
+                        Style->QualifierOrder.end(), "type");
+  if (type == Style->QualifierOrder.end())
+    return ParseError::MissingQualifierType;
+  return ParseError::Success;
+}
+
 std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
                                    FormatStyle *Style, bool AllowUnknownOptions,
                                    llvm::SourceMgr::DiagHandlerTy DiagHandler,
@@ -1573,6 +1650,8 @@
     // See comment on FormatStyle::TSC_Wrapped.
     return make_error_code(ParseError::BinPackTrailingCommaConflict);
   }
+  if (Style->QualifierAlignment != FormatStyle::QAS_Leave)
+    return make_error_code(validateQualifierOrder(Style));
   return make_error_code(ParseError::Success);
 }
 
@@ -2857,6 +2936,7 @@
 }
 
 namespace internal {
+
 std::pair<tooling::Replacements, unsigned>
 reformat(const FormatStyle &Style, StringRef Code,
          ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
@@ -2894,6 +2974,15 @@
       AnalyzerPass;
   SmallVector<AnalyzerPass, 4> Passes;
 
+  if (Style.isCpp() && Style.QualifierAlignment != FormatStyle::QAS_Leave) {
+    Passes.emplace_back([&](const Environment &Env) {
+      return QualifierAlignmentFixer(Env, Expanded, Code, Ranges,
+                                     FirstStartColumn, NextStartColumn,
+                                     LastStartColumn, FileName)
+          .process();
+    });
+  }
+
   if (Style.Language == FormatStyle::LK_Cpp) {
     if (Style.FixNamespaceComments)
       Passes.emplace_back([&](const Environment &Env) {
Index: clang/lib/Format/CMakeLists.txt
===================================================================
--- clang/lib/Format/CMakeLists.txt
+++ clang/lib/Format/CMakeLists.txt
@@ -9,6 +9,7 @@
   FormatTokenLexer.cpp
   MacroExpander.cpp
   NamespaceEndCommentsFixer.cpp
+  QualifierAlignmentFixer.cpp
   SortJavaScriptImports.cpp
   TokenAnalyzer.cpp
   TokenAnnotator.cpp
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -40,7 +40,11 @@
   Success = 0,
   Error,
   Unsuitable,
-  BinPackTrailingCommaConflict
+  BinPackTrailingCommaConflict,
+  InvalidQualifierSpecified,
+  DuplicateQualifierSpecified,
+  MissingQualifierType,
+  MissingQualifierOrder
 };
 class ParseErrorCategory final : public std::error_category {
 public:
@@ -1819,6 +1823,63 @@
   /// \endcode
   std::string CommentPragmas;
 
+  /// Different const/volatile qualifier alignment styles.
+  enum QualifierAlignmentStyle {
+    /// Don't change specifiers/qualifier to either Left or Right alignment
+    /// \code
+    ///    int const a;
+    ///    const int *a;
+    /// \endcode
+    QAS_Leave,
+    /// Change specifiers/qualifiers to be Left aligned.
+    /// \code
+    ///    const int a;
+    ///    const int *a;
+    /// \endcode
+    QAS_Left,
+    /// Change specifiers/qualifiers to be Right aligned.
+    /// \code
+    ///    int const a;
+    ///    int const *a;
+    /// \endcode
+    QAS_Right,
+    /// Change specifiers/qualifiers to be aligned based on QualfierOrder.
+    /// With:
+    /// \code{.yaml}
+    ///   QualifierOrder: ['inline', 'static' , '<type>', 'const']
+    /// \endcode
+    ///
+    /// \code
+    ///
+    ///    int const a;
+    ///    int const *a;
+    /// \endcode
+    QAS_Custom
+  };
+
+  /// Different ways to arrange const/volatile qualifiers.
+  QualifierAlignmentStyle QualifierAlignment;
+
+  /// The Order in which the qualifiers appear.
+  /// Order is a an array can contain any of the following
+  ///
+  ///   * const
+  ///   * inline
+  ///   * static
+  ///   * constexpr
+  ///   * volatile
+  ///   * restrict
+  ///   * type
+  ///
+  /// Note: it MUST contain 'type'.
+  /// Items to the left of type will be aligned in the order supplied.
+  /// Items to the right of type will be aligned  in the order supplied.
+  ///
+  /// \code{.yaml}
+  ///   QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ]
+  /// \endcode
+  std::vector<std::string> QualifierOrder;
+
   /// Different ways to break inheritance list.
   enum BreakInheritanceListStyle : unsigned char {
     /// Break inheritance list before the colon and after the commas.
@@ -3496,6 +3557,8 @@
            PenaltyBreakTemplateDeclaration ==
                R.PenaltyBreakTemplateDeclaration &&
            PointerAlignment == R.PointerAlignment &&
+           QualifierAlignment == R.QualifierAlignment &&
+           QualifierOrder == R.QualifierOrder &&
            RawStringFormats == R.RawStringFormats &&
            ReferenceAlignment == R.ReferenceAlignment &&
            ShortNamespaceLines == R.ShortNamespaceLines &&
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -188,6 +188,16 @@
 - Option ``AllowShortEnumsOnASingleLine: false`` has been improved, it now
   correctly places the opening brace according to ``BraceWrapping.AfterEnum``.
 
+- Option ``QualifierAligment`` has been added in order to auto-arrange the
+  positioning of specifiers/qualifiers
+  `const` `volatile` `static` `inline` `constexpr` `restrict`
+  in variable and parameter declarations to be either ``Right`` aligned
+  or ``Left`` aligned or ``Custom`` using ``QualifierOrder``.
+
+- Option ``QualifierOrder`` has been added to allow the order
+  `const` `volatile` `static` `inline` `constexpr` `restrict`
+  to be controlled relative to the `<type>`.
+
 libclang
 --------
 
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -3225,6 +3225,73 @@
 
 
 
+**QualifierAlignment** (``QualifierAlignmentStyle``)
+  Different ways to arrange const/volatile qualifiers.
+
+  Possible values:
+
+  * ``QAS_Leave`` (in configuration: ``Leave``)
+    Don't change specifiers/qualifier to either Left or Right alignment
+
+    .. code-block:: c++
+
+       int const a;
+       const int *a;
+
+  * ``QAS_Left`` (in configuration: ``Left``)
+    Change specifiers/qualifiers to be Left aligned.
+
+    .. code-block:: c++
+
+       const int a;
+       const int *a;
+
+  * ``QAS_Right`` (in configuration: ``Right``)
+    Change specifiers/qualifiers to be Right aligned.
+
+    .. code-block:: c++
+
+       int const a;
+       int const *a;
+
+  * ``QAS_Custom`` (in configuration: ``Custom``)
+    Change specifiers/qualifiers to be aligned based on QualfierOrder.
+    With:
+
+    .. code-block:: yaml
+
+      QualifierOrder: ['inline', 'static' , '<type>', 'const']
+
+
+    .. code-block:: c++
+
+
+       int const a;
+       int const *a;
+
+
+
+**QualifierOrder** (``std::vector<std::string>``)
+  The Order in which the qualifiers appear.
+  Order is a an array can contain any of the following
+
+    * const
+    * inline
+    * static
+    * constexpr
+    * volatile
+    * restrict
+    * type
+
+  Note: it MUST contain 'type'.
+  Items to the left of type will be aligned in the order supplied.
+  Items to the right of type will be aligned  in the order supplied.
+
+
+  .. code-block:: yaml
+
+    QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ]
+
 **RawStringFormats** (``std::vector<RawStringFormat>``)
   Defines hints for detecting supported languages code blocks in raw
   strings.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to