- Notifications
You must be signed in to change notification settings - Fork 15.3k
[clang-format] Add basic support for C++/CLI (#27126) #112689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
* This only looks for ^ as a pointer/reference token, which is the main issue when trying to format C++/CLI.
| Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
| @llvm/pr-subscribers-clang-format Author: Calum Robinson (calumr) Changes
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. Full diff: https://github.com/llvm/llvm-project/pull/112689.diff 7 Files Affected:
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; }; |
| @llvm/pr-subscribers-clang Author: Calum Robinson (calumr) Changes
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. Full diff: https://github.com/llvm/llvm-project/pull/112689.diff 7 Files Affected:
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; }; |
mydeveloperday left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change needs tests, documentation changes and a git hub issue
mydeveloperday left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would a user specify to use CLI?
getFormattingLangOpts seems to turn on MicrosoftExt and some other options by default, so I just copied that. |
| My point was that mostly this change is about changing the call isPointerOrReference call, its an invasive change for little extra. Can you give me an example of what it was doing wrong (hence the github issue), My code base contains both c++,c# and (some) managed c++ and its all clang-formatted already. So I'm trying to understand why we need the change. (i.e. where is it broken) as you set CPlusPlusCLI to 1 then I don't see how anyone can ever turn it off. How does this impact the ObjC tests, (did you run the unit tests) Whilst we welcome changes, we need unit tests to ensure we don't break anything but also someone doesn't break you later. |
| #27126 was the issue. I've added a comment there with a clearer example of what clang-format is currently doing to C++/CLI code. I appreciate this PR is not complete & I need to add tests. |
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.