Author: mydeveloperday Date: 2022-01-06T19:40:39Z New Revision: 031d3ece3f2eb6bd785dcf7484e88cc6a306db94
URL: https://github.com/llvm/llvm-project/commit/031d3ece3f2eb6bd785dcf7484e88cc6a306db94 DIFF: https://github.com/llvm/llvm-project/commit/031d3ece3f2eb6bd785dcf7484e88cc6a306db94.diff LOG: [clang-format] Fix a crash (assertion) in qualifier alignment when matching template closer is null https://github.com/llvm/llvm-project/issues/53008 ``` template <class Id> using A = quantity /**/<kind<Id>, 1>; ``` the presence of the comment between identifier and template opener seems to be causing the qualifier alignment to fail Reviewed By: curdeius Fixes: #53008 Differential Revision: https://reviews.llvm.org/D116726 Added: Modified: clang/lib/Format/QualifierAlignmentFixer.cpp clang/lib/Format/QualifierAlignmentFixer.h clang/unittests/Format/QualifierFixerTest.cpp Removed: ################################################################################ diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index 5a89225c7fc86..ec19a38537683 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -204,9 +204,9 @@ static void rotateTokens(const SourceManager &SourceMgr, replaceToken(SourceMgr, Fixes, Range, NewText); } -FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( +const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, + tooling::Replacements &Fixes, const 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)) @@ -281,16 +281,16 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( return Tok; } -FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( +const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, + tooling::Replacements &Fixes, const 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; + const FormatToken *Qual = Tok; + const FormatToken *LastQual = Qual; while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { LastQual = Qual; Qual = Qual->Next; @@ -326,7 +326,7 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) { return Tok; } - FormatToken *Next = Tok->Next; + const 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; @@ -334,6 +334,8 @@ FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( 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; + if (Next->is(tok::comment) && Next->getNextNonComment()) + Next = Next->getNextNonComment(); assert(Next->MatchingParen && "Missing template closer"); Next = Next->MatchingParen->Next; @@ -398,7 +400,8 @@ LeftRightQualifierAlignmentFixer::analyze( FormatToken *First = AnnotatedLines[I]->First; const auto *Last = AnnotatedLines[I]->Last; - for (auto *Tok = First; Tok && Tok != Last && Tok->Next; Tok = Tok->Next) { + for (const auto *Tok = First; Tok && Tok != Last && Tok->Next; + Tok = Tok->Next) { if (Tok->is(tok::comment)) continue; if (RightAlign) diff --git a/clang/lib/Format/QualifierAlignmentFixer.h b/clang/lib/Format/QualifierAlignmentFixer.h index 7abd25687564b..30ef96b8b0a7c 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.h +++ b/clang/lib/Format/QualifierAlignmentFixer.h @@ -72,17 +72,19 @@ class LeftRightQualifierAlignmentFixer : public TokenAnalyzer { static tok::TokenKind getTokenFromQualifier(const std::string &Qualifier); - FormatToken *analyzeRight(const SourceManager &SourceMgr, - const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, - const std::string &Qualifier, - tok::TokenKind QualifierType); - - FormatToken *analyzeLeft(const SourceManager &SourceMgr, - const AdditionalKeywords &Keywords, - tooling::Replacements &Fixes, FormatToken *Tok, - const std::string &Qualifier, - tok::TokenKind QualifierType); + const FormatToken *analyzeRight(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, + const FormatToken *Tok, + const std::string &Qualifier, + tok::TokenKind QualifierType); + + const FormatToken *analyzeLeft(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, + const FormatToken *Tok, + const std::string &Qualifier, + tok::TokenKind QualifierType); // is the Token a simple or qualifier type static bool isQualifierOrType(const FormatToken *Tok, diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp index e3d0a9a0e2607..0517de2820d9d 100755 --- a/clang/unittests/Format/QualifierFixerTest.cpp +++ b/clang/unittests/Format/QualifierFixerTest.cpp @@ -818,5 +818,45 @@ TEST_F(QualifierFixerTest, NoOpQualifierReplacements) { EXPECT_EQ(ReplacementCount, 0); } +TEST_F(QualifierFixerTest, QualifierTemplates) { + FormatStyle Style = getLLVMStyle(); + Style.QualifierAlignment = FormatStyle::QAS_Custom; + Style.QualifierOrder = {"static", "const", "type"}; + + ReplacementCount = 0; + EXPECT_EQ(ReplacementCount, 0); + verifyFormat("using A = B<>;", Style); + verifyFormat("using A = B /**/<>;", Style); + verifyFormat("template <class C> using A = B<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /**/<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /* */<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /*foo*/<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /**/ /**/<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B<Foo</**/ C>, 1>;", Style); + verifyFormat("template <class C> using A = /**/ B<Foo<C>, 1>;", Style); + EXPECT_EQ(ReplacementCount, 0); + verifyFormat("template <class C>\n" + "using A = B // foo\n" + " <Foo<C>, 1>;", + Style); + + ReplacementCount = 0; + Style.QualifierOrder = {"type", "static", "const"}; + verifyFormat("using A = B<>;", Style); + verifyFormat("using A = B /**/<>;", Style); + verifyFormat("template <class C> using A = B<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /**/<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /* */<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /*foo*/<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B /**/ /**/<Foo<C>, 1>;", Style); + verifyFormat("template <class C> using A = B<Foo</**/ C>, 1>;", Style); + verifyFormat("template <class C> using A = /**/ B<Foo<C>, 1>;", Style); + EXPECT_EQ(ReplacementCount, 0); + verifyFormat("template <class C>\n" + "using A = B // foo\n" + " <Foo<C>, 1>;", + Style); +} + } // namespace format } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits