[clang] 031d3ec - [clang-format] Fix a crash (assertion) in qualifier alignment when matching template closer is null

via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 6 11:45:47 PST 2022


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


        


More information about the cfe-commits mailing list