https://github.com/calumr created https://github.com/llvm/llvm-project/pull/112689
* This only looks for ^ as a pointer/reference token, which is the main issue when trying to format C++/CLI. Obviously there's more to C++/CLI than this minor change, but it's extremely useful to be able to clang-format our whole codebase now without a ^ mangling the output. >From 40f665adce7d32aa194f8500746d0bfbc2d5f2d6 Mon Sep 17 00:00:00 2001 From: Calum Robinson <calum.robin...@sias.com> Date: Thu, 17 Oct 2024 10:11:41 +0100 Subject: [PATCH] [clang-format] Add basic support for C++/CLI (#27126) * This only looks for ^ as a pointer/reference token, which is the main issue when trying to format C++/CLI. --- clang/include/clang/Basic/LangOptions.def | 1 + clang/lib/Format/Format.cpp | 1 + clang/lib/Format/FormatToken.h | 4 ++- clang/lib/Format/QualifierAlignmentFixer.cpp | 2 +- clang/lib/Format/TokenAnnotator.cpp | 34 +++++++++++--------- clang/lib/Format/WhitespaceManager.cpp | 24 +++++++------- clang/lib/Format/WhitespaceManager.h | 4 ++- 7 files changed, 40 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 68db400c22e6c1..1285ce06d845f3 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -101,6 +101,7 @@ LANGOPT(CPlusPlus17 , 1, 0, "C++17") LANGOPT(CPlusPlus20 , 1, 0, "C++20") LANGOPT(CPlusPlus23 , 1, 0, "C++23") LANGOPT(CPlusPlus26 , 1, 0, "C++26") +LANGOPT(CPlusPlusCLI , 1, 0, "C++/CLI") LANGOPT(ObjC , 1, 0, "Objective-C") BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0, "Objective-C auto-synthesized properties") diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 148270795c562f..4344b5b2ad4c26 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3914,6 +3914,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) { LangOpts.Bool = 1; LangOpts.ObjC = 1; LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally. + LangOpts.CPlusPlusCLI = 1; LangOpts.DeclSpecKeyword = 1; // To get __declspec. LangOpts.C99 = 1; // To get kw_restrict for non-underscore-prefixed restrict. return LangOpts; diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 7d342a7dcca01d..cdf613774fa6bc 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -731,7 +731,9 @@ struct FormatToken { TT_LambdaArrow, TT_LeadingJavaAnnotation); } - bool isPointerOrReference() const { + bool isPointerOrReference(const LangOptions &LangOpts) const { + if (LangOpts.CPlusPlusCLI && is(tok::caret)) + return true; return isOneOf(tok::star, tok::amp, tok::ampamp); } diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index 593f8efff25aa9..f07c8913b907ac 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -385,7 +385,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( // For left qualifiers preceeded by nothing, a template declaration, or *,&,&& // we only perform sorting. - if (!TypeToken || TypeToken->isPointerOrReference() || + if (!TypeToken || TypeToken->isPointerOrReference(LangOpts) || TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration) { // Don't sort past a non-configured qualifier token. diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index fcefaa7bb298ea..5a33c1c00c8b24 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -468,8 +468,8 @@ class AnnotatingParser { // void (&&FunctionReference)(void); // void (^ObjCBlock)(void); bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression; - bool ProbablyFunctionType = - CurrentToken->isPointerOrReference() || CurrentToken->is(tok::caret); + bool ProbablyFunctionType = CurrentToken->isPointerOrReference(LangOpts) || + CurrentToken->is(tok::caret); bool HasMultipleLines = false; bool HasMultipleParametersOnALine = false; bool MightBeObjCForRangeLoop = @@ -507,7 +507,8 @@ class AnnotatingParser { // auto my_lambda = MACRO((Type *type, int i) { .. body .. }); for (FormatToken *Tok = &OpeningParen; Tok != CurrentToken; Tok = Tok->Next) { - if (Tok->is(TT_BinaryOperator) && Tok->isPointerOrReference()) + if (Tok->is(TT_BinaryOperator) && + Tok->isPointerOrReference(LangOpts)) Tok->setType(TT_PointerOrReference); } } @@ -578,7 +579,7 @@ class AnnotatingParser { Tok != CurrentToken && !Tok->isOneOf(tok::equal, tok::l_paren, tok::l_brace); Tok = Tok->Next) { - if (Tok->isPointerOrReference()) + if (Tok->isPointerOrReference(LangOpts)) Tok->setFinalizedType(TT_PointerOrReference); } } @@ -1411,7 +1412,7 @@ class AnnotatingParser { for (auto *Prev = Tok->Previous; Prev && !Prev->isOneOf(tok::semi, tok::l_paren); Prev = Prev->Previous) { - if (Prev->isPointerOrReference()) + if (Prev->isPointerOrReference(LangOpts)) Prev->setFinalizedType(TT_PointerOrReference); } } else if (Contexts.back().ContextType == Context::C11GenericSelection) { @@ -2244,7 +2245,7 @@ class AnnotatingParser { if (Previous->opensScope()) break; if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) && - Previous->isPointerOrReference() && Previous->Previous && + Previous->isPointerOrReference(LangOpts) && Previous->Previous && Previous->Previous->isNot(tok::equal)) { Previous->setType(TT_PointerOrReference); } @@ -2410,7 +2411,7 @@ class AnnotatingParser { } else if (isDeductionGuide(Current)) { // Deduction guides trailing arrow " A(...) -> A<T>;". Current.setType(TT_TrailingReturnArrow); - } else if (Current.isPointerOrReference()) { + } else if (Current.isPointerOrReference(LangOpts)) { Current.setType(determineStarAmpUsage( Current, Contexts.back().CanBeExpression && Contexts.back().IsExpression, @@ -2580,7 +2581,7 @@ class AnnotatingParser { if (const auto *NextNonComment = Tok.getNextNonComment(); (!NextNonComment && !Line.InMacroBody) || (NextNonComment && - (NextNonComment->isPointerOrReference() || + (NextNonComment->isPointerOrReference(LangOpts) || NextNonComment->is(tok::string_literal) || (Line.InPragmaDirective && NextNonComment->is(tok::identifier))))) { return false; @@ -3767,7 +3768,7 @@ static bool isFunctionDeclarationName(const LangOptions &LangOpts, continue; } if ((Next->isTypeName(LangOpts) || Next->is(tok::identifier)) && - Next->Next && Next->Next->isPointerOrReference()) { + Next->Next && Next->Next->isPointerOrReference(LangOpts)) { // For operator void*(), operator char*(), operator Foo*(). Next = Next->Next; continue; @@ -3797,7 +3798,8 @@ static bool isFunctionDeclarationName(const LangOptions &LangOpts, assert(Previous.MatchingParen->is(TT_TypeDeclarationParen)); return true; } - if (!Previous.isPointerOrReference() && Previous.isNot(TT_TemplateCloser)) + if (!Previous.isPointerOrReference(LangOpts) && + Previous.isNot(TT_TemplateCloser)) return false; Next = skipOperatorName(Next); } else { @@ -3983,7 +3985,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { continue; auto *Next = Tok->Next; const bool NextIsBinaryOperator = - Next && Next->isPointerOrReference() && Next->Next && + Next && Next->isPointerOrReference(LangOpts) && Next->Next && Next->Next->is(tok::identifier); if (!NextIsBinaryOperator) continue; @@ -4632,15 +4634,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, } // Ensure right pointer alignment with ellipsis e.g. int *...P if (Left.is(tok::ellipsis) && BeforeLeft && - BeforeLeft->isPointerOrReference()) { + BeforeLeft->isPointerOrReference(LangOpts)) { return Style.PointerAlignment != FormatStyle::PAS_Right; } if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; - if (Left.is(tok::star) && Right.isPointerOrReference()) + if (Left.is(tok::star) && Right.isPointerOrReference(LangOpts)) return false; - if (Right.isPointerOrReference()) { + if (Right.isPointerOrReference(LangOpts)) { const FormatToken *Previous = &Left; while (Previous && Previous->isNot(tok::kw_operator)) { if (Previous->is(tok::identifier) || Previous->isTypeName(LangOpts)) { @@ -5877,7 +5879,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, } if (Style.BraceWrapping.BeforeLambdaBody && Right.is(TT_LambdaLBrace) && - (Left.isPointerOrReference() || Left.is(TT_TemplateCloser))) { + (Left.isPointerOrReference(LangOpts) || Left.is(TT_TemplateCloser))) { return true; } @@ -6431,7 +6433,7 @@ TokenAnnotator::getTokenPointerOrReferenceAlignment( return FormatStyle::PAS_Middle; } } - assert(PointerOrReference.is(tok::star)); + assert(LangOpts.CPlusPlusCLI ? PointerOrReference.isOneOf(tok::star, tok::caret) : PointerOrReference.is(tok::star)); return Style.PointerAlignment; } diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index b6b24672f6a39d..ae2284528f9fc0 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -284,8 +284,9 @@ void WhitespaceManager::calculateLineBreakInformation() { // moved to that column. template <typename F> static void -AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, - unsigned Column, bool RightJustify, F &&Matches, +AlignTokenSequence(const FormatStyle &Style, const LangOptions &LangOpts, + unsigned Start, unsigned End, unsigned Column, + bool RightJustify, F &&Matches, SmallVector<WhitespaceManager::Change, 16> &Changes) { bool FoundMatchOnLine = false; int Shift = 0; @@ -478,7 +479,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, for (int Previous = i - 1; Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference); --Previous) { - assert(Changes[Previous].Tok->isPointerOrReference()); + assert(Changes[Previous].Tok->isPointerOrReference(LangOpts)); if (Changes[Previous].Tok->isNot(tok::star)) { if (ReferenceNotRightAligned) continue; @@ -525,7 +526,8 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, // When RightJustify and ACS.PadOperators are true, operators in each block to // be aligned will be padded on the left to the same length before aligning. template <typename F> -static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, +static unsigned AlignTokens(const FormatStyle &Style, + const LangOptions &LangOpts, F &&Matches, SmallVector<WhitespaceManager::Change, 16> &Changes, unsigned StartAt, const FormatStyle::AlignConsecutiveStyle &ACS = {}, @@ -577,7 +579,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, // containing any matching token to be aligned and located after such token. auto AlignCurrentSequence = [&] { if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { - AlignTokenSequence(Style, StartOfSequence, EndOfSequence, + AlignTokenSequence(Style, LangOpts, StartOfSequence, EndOfSequence, WidthLeft + WidthAnchor, RightJustify, Matches, Changes); } @@ -627,7 +629,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, } else if (CurrentChange.indentAndNestingLevel() > IndentAndNestingLevel) { // Call AlignTokens recursively, skipping over this scope block. unsigned StoppedAt = - AlignTokens(Style, Matches, Changes, i, ACS, RightJustify); + AlignTokens(Style, LangOpts, Matches, Changes, i, ACS, RightJustify); i = StoppedAt - 1; continue; } @@ -828,7 +830,7 @@ void WhitespaceManager::alignConsecutiveAssignments() { return; AlignTokens( - Style, + Style, LangOpts, [&](const Change &C) { // Do not align on equal signs that are first on a line. if (C.NewlinesBefore > 0) @@ -866,7 +868,7 @@ void WhitespaceManager::alignConsecutiveColons( return; AlignTokens( - Style, + Style, LangOpts, [&](Change const &C) { // Do not align on ':' that is first on a line. if (C.NewlinesBefore > 0) @@ -1010,7 +1012,7 @@ void WhitespaceManager::alignConsecutiveDeclarations() { return; AlignTokens( - Style, + Style, LangOpts, [&](Change const &C) { if (Style.AlignConsecutiveDeclarations.AlignFunctionPointers) { for (const auto *Prev = C.Tok->Previous; Prev; Prev = Prev->Previous) @@ -1047,7 +1049,7 @@ void WhitespaceManager::alignConsecutiveDeclarations() { void WhitespaceManager::alignChainedConditionals() { if (Style.BreakBeforeTernaryOperators) { AlignTokens( - Style, + Style, LangOpts, [](Change const &C) { // Align question operators and last colon return C.Tok->is(TT_ConditionalExpr) && @@ -1072,7 +1074,7 @@ void WhitespaceManager::alignChainedConditionals() { if (AlignWrappedOperand(C)) C.StartOfTokenColumn -= 2; AlignTokens( - Style, + Style, LangOpts, [this](Change const &C) { // Align question operators if next operand is not wrapped, as // well as wrapped operands after question operator or last diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index 7b91d8bf4db72b..b2bf2690230a98 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -36,7 +36,8 @@ class WhitespaceManager { public: WhitespaceManager(const SourceManager &SourceMgr, const FormatStyle &Style, bool UseCRLF) - : SourceMgr(SourceMgr), Style(Style), UseCRLF(UseCRLF) {} + : SourceMgr(SourceMgr), Style(Style), + LangOpts(getFormattingLangOpts(Style)), UseCRLF(UseCRLF) {} bool useCRLF() const { return UseCRLF; } @@ -363,6 +364,7 @@ class WhitespaceManager { const SourceManager &SourceMgr; tooling::Replacements Replaces; const FormatStyle &Style; + const LangOptions LangOpts; bool UseCRLF; }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits