[clang] 02fd002 - [clang-format] Fix bugs in parsing C++20 module import statements

Owen Pan via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 23 14:35:24 PST 2023


Author: Owen Pan
Date: 2023-01-23T14:35:15-08:00
New Revision: 02fd0020e5771b2850f892712b8fa51d3b98e270

URL: https://github.com/llvm/llvm-project/commit/02fd0020e5771b2850f892712b8fa51d3b98e270
DIFF: https://github.com/llvm/llvm-project/commit/02fd0020e5771b2850f892712b8fa51d3b98e270.diff

LOG: [clang-format] Fix bugs in parsing C++20 module import statements

Also fixes #60145.

Differential Revision: https://reviews.llvm.org/D142296

Added: 
    

Modified: 
    clang/lib/Format/UnwrappedLineParser.cpp
    clang/lib/Format/UnwrappedLineParser.h
    clang/unittests/Format/FormatTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index effb0ecb368bb..6d5b92c61c78b 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -41,7 +41,7 @@ class FormatTokenSource {
 
   // Returns the token that would be returned by the next call to
   // getNextToken().
-  virtual FormatToken *peekNextToken() = 0;
+  virtual FormatToken *peekNextToken(bool SkipComment = false) = 0;
 
   // Returns whether we are at the end of the file.
   // This can be 
diff erent from whether getNextToken() returned an eof token
@@ -169,10 +169,10 @@ class ScopedMacroState : public FormatTokenSource {
     return PreviousTokenSource->getPreviousToken();
   }
 
-  FormatToken *peekNextToken() override {
+  FormatToken *peekNextToken(bool SkipComment) override {
     if (eof())
       return &FakeEOF;
-    return PreviousTokenSource->peekNextToken();
+    return PreviousTokenSource->peekNextToken(SkipComment);
   }
 
   bool isEOF() override { return PreviousTokenSource->isEOF(); }
@@ -288,8 +288,11 @@ class IndexedTokenSource : public FormatTokenSource {
     return Position > 0 ? Tokens[Position - 1] : nullptr;
   }
 
-  FormatToken *peekNextToken() override {
+  FormatToken *peekNextToken(bool SkipComment) override {
     int Next = Position + 1;
+    if (SkipComment)
+      while (Tokens[Next]->is(tok::comment))
+        ++Next;
     LLVM_DEBUG({
       llvm::dbgs() << "Peeking ";
       dbgToken(Next);
@@ -1435,7 +1438,15 @@ static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next,
   return Tok->Previous && Tok->Previous->isOneOf(tok::l_paren, tok::comma);
 }
 
-void UnwrappedLineParser::parseModuleImport() {
+bool UnwrappedLineParser::parseModuleImport() {
+  assert(FormatTok->is(Keywords.kw_import) && "'import' expected");
+
+  if (auto Token = Tokens->peekNextToken(/*SkipComment=*/true);
+      !Token->Tok.getIdentifierInfo() &&
+      !Token->isOneOf(tok::colon, tok::less, tok::string_literal)) {
+    return false;
+  }
+
   nextToken();
   while (!eof()) {
     if (FormatTok->is(tok::colon)) {
@@ -1462,6 +1473,7 @@ void UnwrappedLineParser::parseModuleImport() {
   }
 
   addUnwrappedLine();
+  return true;
 }
 
 // readTokenWithJavaScriptASI reads the next token and terminates the current
@@ -1682,14 +1694,12 @@ void UnwrappedLineParser::parseStructuralElement(
     }
     if (Style.isCpp()) {
       nextToken();
-      if (FormatTok->is(Keywords.kw_import)) {
-        parseModuleImport();
-        return;
-      }
       if (FormatTok->is(tok::kw_namespace)) {
         parseNamespace();
         return;
       }
+      if (FormatTok->is(Keywords.kw_import) && parseModuleImport())
+        return;
     }
     break;
   case tok::kw_inline:
@@ -1726,10 +1736,8 @@ void UnwrappedLineParser::parseStructuralElement(
         addUnwrappedLine();
         return;
       }
-      if (Style.isCpp()) {
-        parseModuleImport();
+      if (Style.isCpp() && parseModuleImport())
         return;
-      }
     }
     if (Style.isCpp() &&
         FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,

diff  --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 97c5baf152fef..f043e567eb733 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -153,7 +153,7 @@ class UnwrappedLineParser {
   void parseCaseLabel();
   void parseSwitch();
   void parseNamespace();
-  void parseModuleImport();
+  bool parseModuleImport();
   void parseNew();
   void parseAccessSpecifier();
   bool parseEnum();

diff  --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index aa7ae12b6502c..b7d0a398dd432 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -12810,6 +12810,7 @@ TEST_F(FormatTest, HandlesIncludeDirectives) {
   // But 'import' might also be a regular C++ namespace.
   verifyFormat("import::SomeFunction(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
                "                     aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+  verifyFormat("import::Bar foo(val ? 2 : 1);");
 }
 
 //===----------------------------------------------------------------------===//
@@ -24628,6 +24629,7 @@ TEST_F(FormatTest, Cpp20ModulesSupport) {
   verifyFormat("import foo.bar;", Style);
   verifyFormat("import foo:bar;", Style);
   verifyFormat("import :bar;", Style);
+  verifyFormat("import /* module partition */ :bar;", Style);
   verifyFormat("import <ctime>;", Style);
   verifyFormat("import \"header\";", Style);
 
@@ -24654,6 +24656,8 @@ TEST_F(FormatTest, Cpp20ModulesSupport) {
   verifyFormat("import", Style);
   verifyFormat("module", Style);
   verifyFormat("export", Style);
+
+  verifyFormat("import /* not keyword */ = val ? 2 : 1;");
 }
 
 TEST_F(FormatTest, CoroutineForCoawait) {


        


More information about the cfe-commits mailing list