[clang] [clang-format] Add basic support for C++/CLI (#27126) (PR #112689)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 17 03:50:05 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-format
Author: Calum Robinson (calumr)
<details>
<summary>Changes</summary>
* 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.
---
Full diff: https://github.com/llvm/llvm-project/pull/112689.diff
7 Files Affected:
- (modified) clang/include/clang/Basic/LangOptions.def (+1)
- (modified) clang/lib/Format/Format.cpp (+1)
- (modified) clang/lib/Format/FormatToken.h (+3-1)
- (modified) clang/lib/Format/QualifierAlignmentFixer.cpp (+1-1)
- (modified) clang/lib/Format/TokenAnnotator.cpp (+18-16)
- (modified) clang/lib/Format/WhitespaceManager.cpp (+13-11)
- (modified) clang/lib/Format/WhitespaceManager.h (+3-1)
``````````diff
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;
};
``````````
</details>
https://github.com/llvm/llvm-project/pull/112689
More information about the cfe-commits
mailing list