--- /dev/null
+//===--- 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 left or right 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 {
+
+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;
+ std::vector<tok::TokenKind> ConfiguredQualifierTokens;
+ PrepareLeftRightOrdering(Style.QualifierOrder, LeftOrder, RightOrder,
+ ConfiguredQualifierTokens);
+
+ // Handle the left and right Alignment Seperately
+ for (const auto &Qualifier : LeftOrder) {
+ Passes.emplace_back(
+ [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) {
+ return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
+ ConfiguredQualifierTokens,
+ /*RightAlign=*/false)
+ .process();
+ });
+ }
+ for (const auto &Qualifier : RightOrder) {
+ Passes.emplace_back(
+ [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) {
+ return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier,
+ ConfiguredQualifierTokens,
+ /*RightAlign=*/true)
+ .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);
+ }
+ }
+ }
+ return {Fixes, 0};
+}
+
+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 bool endsWithSpace(const std::string &s) {
+ if (s.empty()) {
+ return false;
+ }
+ return isspace(s.back());
+}
+
+static bool startsWithSpace(const std::string &s) {
+ if (s.empty()) {
+ return false;
+ }
+ return isspace(s.front());
+}
+
+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() && !endsWithSpace(NewText)) {
+ NewText += " ";
+ }
+
+ NewText += Tok->TokenText;
+ Tok = Tok->Next;
+ }
+
+ // If we are rotating to the right we move the first token to the back.
+ if (!Left) {
+ if (!NewText.empty() && !startsWithSpace(NewText)) {
+ NewText += " ";
+ }
+ NewText += First->TokenText;
+ }
+
+ auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(),
+ Last->Tok.getEndLoc());
+
+ replaceToken(SourceMgr, Fixes, Range, NewText);
+}
+
+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 a qualifier.
+ if (!Tok->is(QualifierType))
+ return Tok;
+ // Don't concern yourself if nothing follows the qualifier.
+ if (!Tok->Next)
+ return Tok;
+ if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok->Next))
+ return Tok;
+
+ FormatToken *Qual = Tok->Next;
+ FormatToken *LastQual = Qual;
+ while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) {
+ LastQual = Qual;
+ Qual = Qual->Next;
+ }
+ if (LastQual && Qual != LastQual) {
+ rotateTokens(SourceMgr, Fixes, Tok, 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)) {
+ insertQualifierAfter(SourceMgr, Fixes, EndTemplate, Qualifier);
+ // Remove the 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, Tok);
+ }
+ 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, ConfiguredQualifierTokens)) {
+ 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);
+ Tok = Tok->Next;
+ }
+ }
+ }
+ 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.
+ insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier);
+ removeToken(SourceMgr, Fixes, Next);
+ return Next;
+ }
+ }
+ if (Next && Next->Next &&
+ Next->Next->isOneOf(tok::amp, tok::ampamp, tok::star)) {
+ if (Next->is(QualifierType)) {
+ // Remove the qualifier.
+ insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier);
+ removeToken(SourceMgr, Fixes, Next);
+ 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 std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign)
+ : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign),
+ ConfiguredQualifierTokens(QualifierTokens) {}
+
+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 (RightAlign)
+ Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier,
+ QualifierToken);
+ else
+ 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,
+ std::vector<tok::TokenKind> &Qualifiers) {
+
+ // 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;
+ }
+
+ tok::TokenKind QualifierToken =
+ LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s);
+ if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) {
+ Qualifiers.push_back(QualifierToken);
+ }
+
+ if (left)
+ // Reverse the order for left aligned items.
+ LeftOrder.insert(LeftOrder.begin(), s);
+ else
+ RightOrder.push_back(s);
+ }
+}
+
+bool LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ const FormatToken *Tok, const std::vector<tok::TokenKind> &specifiedTypes) {
+ return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) ||
+ (std::find(specifiedTypes.begin(), specifiedTypes.end(),
+ Tok->Tok.getKind()) != specifiedTypes.end()));
+}
+
+// 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;
+}
+
+} // namespace format
+} // namespace clang
--- /dev/null
+//===- 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 = {"inline", "constexpr", "static",
+ "const", "volatile", "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 = {"type", "const", "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;
+ Style.QualifierOrder = {"inline", "static", "const", "volatile", "type"};
+
+ 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;
+ Style.QualifierOrder = {"inline", "static", "const", "volatile", "type"};
+
+ // The Default
+ EXPECT_EQ(Style.QualifierOrder.size(), 5);
+
+ 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 = {"type", "const", "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 = {"volatile", "const", "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 = {"type", "volatile", "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 = {"type", "volatile", "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;
+ Style.QualifierOrder = {"inline", "static", "const", "volatile", "type"};
+ EXPECT_EQ(Style.QualifierOrder.size(), 5);
+
+ 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 = {"static", "type", "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 = {"type", "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 = {"const", "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 = {"static", "inline", "type", "const", "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 = {"static", "inline", "type", "const", "volatile"};
+
+ std::vector<std::string> Left;
+ std::vector<std::string> Right;
+ std::vector<tok::TokenKind> ConfiguredTokens;
+ QualifierAlignmentFixer::PrepareLeftRightOrdering(Style.QualifierOrder, Left,
+ Right, ConfiguredTokens);
+
+ EXPECT_EQ(Left.size(), 2);
+ EXPECT_EQ(Right.size(), 2);
+
+ std::vector<std::string> LeftResult = {"inline", "static"};
+ std::vector<std::string> RightResult = {"const", "volatile"};
+ EXPECT_EQ(Left, LeftResult);
+ EXPECT_EQ(Right, RightResult);
+}
+
+TEST_F(QualifierFixerTest, IsQualifierType) {
+
+ std::vector<tok::TokenKind> ConfiguredTokens;
+ ConfiguredTokens.push_back(tok::kw_const);
+ ConfiguredTokens.push_back(tok::kw_static);
+ ConfiguredTokens.push_back(tok::kw_inline);
+ ConfiguredTokens.push_back(tok::kw_restrict);
+ ConfiguredTokens.push_back(tok::kw_constexpr);
+
+ auto Tokens =
+ annotate("const static inline auto restrict int double long constexpr");
+
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[0], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[1], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[2], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[3], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[4], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[5], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[6], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[7], ConfiguredTokens));
+ EXPECT_TRUE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ Tokens[8], ConfiguredTokens));
+
+ auto NotTokens = annotate("for while do Foo Bar ");
+
+ EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ NotTokens[0], ConfiguredTokens));
+ EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ NotTokens[1], ConfiguredTokens));
+ EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ NotTokens[2], ConfiguredTokens));
+ EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ NotTokens[3], ConfiguredTokens));
+ EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ NotTokens[4], ConfiguredTokens));
+ EXPECT_FALSE(LeftRightQualifierAlignmentFixer::isQualifierOrType(
+ NotTokens[5], ConfiguredTokens));
+}
+
+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]));
+}
+
+TEST_F(QualifierFixerTest, OverlappingQualifier) {
+
+ FormatStyle Style = getLLVMStyle();
+ Style.QualifierAlignment = FormatStyle::QAS_Left;
+ Style.QualifierOrder = {"const", "type"};
+
+ verifyFormat("Foo(const Bar &name);", "Foo(Bar const &name);", Style);
+}
+
+TEST_F(QualifierFixerTest, DontPushQualifierThroughNonSpecifiedTypes) {
+
+ FormatStyle Style = getLLVMStyle();
+ Style.QualifierAlignment = FormatStyle::QAS_Left;
+ Style.QualifierOrder = {"const", "type"};
+
+ verifyFormat("inline static const int a;", Style);
+
+ Style.QualifierOrder = {"static", "const", "type"};
+
+ verifyFormat("inline static const int a;", Style);
+ verifyFormat("static inline const int a;", "static inline const int a;",
+ Style);
+
+ verifyFormat("static const int a;", "const static int a;", Style);
+}
+
+TEST_F(QualifierFixerTest, UnsignedQualifier) {
+
+ FormatStyle Style = getLLVMStyle();
+ Style.QualifierAlignment = FormatStyle::QAS_Left;
+ Style.QualifierOrder = {"const", "type"};
+
+ verifyFormat("Foo(const unsigned char *bytes)",
+ "Foo(unsigned const char *bytes)", Style);
+
+ Style.QualifierAlignment = FormatStyle::QAS_Right;
+ Style.QualifierOrder = {"type", "const"};
+
+ verifyFormat("Foo(unsigned char const *bytes)",
+ "Foo(unsigned const char *bytes)", Style);
+}
+
+} // namespace format
+} // namespace clang