Author: mydeveloperday Date: 2021-11-25T11:51:21Z New Revision: c2fe2b5a63bb7ec82d0a221bd144f6ce04661f90
URL: https://github.com/llvm/llvm-project/commit/c2fe2b5a63bb7ec82d0a221bd144f6ce04661f90 DIFF: https://github.com/llvm/llvm-project/commit/c2fe2b5a63bb7ec82d0a221bd144f6ce04661f90.diff LOG: [clang-format] [C++20] [Module] clang-format couldn't recognize partitions https://bugs.llvm.org/show_bug.cgi?id=52517 clang-format is butchering modules, this could easily become a barrier to entry for modules given clang-formats wide spread use. Prevent the following from adding spaces around the `:` (cf was considering the ':' as an InheritanceColon) Reviewed By: HazardyKnusperkeks, owenpan, ChuanqiXu Differential Revision: https://reviews.llvm.org/D114151 Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/Format/FormatToken.h clang/lib/Format/TokenAnnotator.cpp clang/lib/Format/UnwrappedLineParser.cpp clang/lib/Format/UnwrappedLineParser.h clang/unittests/Format/FormatTest.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index df2a6e71c534b..20e99fbf2e136 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -265,6 +265,8 @@ clang-format space before parentheses. The custom options can be set using ``SpaceBeforeParensOptions``. +- Improved Cpp20 Modules support. + libclang -------- diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 06d51dd95f50f..1a2858018fde5 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -76,6 +76,7 @@ namespace format { TYPE(LineComment) \ TYPE(MacroBlockBegin) \ TYPE(MacroBlockEnd) \ + TYPE(ModulePartitionColon) \ TYPE(NamespaceMacro) \ TYPE(NonNullAssertion) \ TYPE(NullCoalescingEqual) \ diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index e6564a3511de2..fba55fb32da2d 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -903,9 +903,13 @@ class AnnotatingParser { break; } } - if (Contexts.back().ColonIsDictLiteral || - Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) { + if (Line.First->isOneOf(Keywords.kw_module, Keywords.kw_import) || + Line.First->startsSequence(tok::kw_export, Keywords.kw_module) || + Line.First->startsSequence(tok::kw_export, Keywords.kw_import)) { + Tok->setType(TT_ModulePartitionColon); + } else if (Contexts.back().ColonIsDictLiteral || + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { Tok->setType(TT_DictLiteral); if (Style.Language == FormatStyle::LK_TextProto) { if (FormatToken *Previous = Tok->getPreviousNonComment()) @@ -3244,6 +3248,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, auto HasExistingWhitespace = [&Right]() { return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); }; + if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo()) return true; // Never ever merge two identifiers. @@ -3253,6 +3258,25 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; if (Style.isCpp()) { + // Space between import <iostream>. + // or import .....; + if (Left.is(Keywords.kw_import) && Right.isOneOf(tok::less, tok::ellipsis)) + return true; + // No space between module :. + if (Left.isOneOf(Keywords.kw_module, Keywords.kw_import) && + Right.is(TT_ModulePartitionColon)) + return true; + // No space between import foo:bar but keep a space between import :bar; + if (Left.is(tok::identifier) && Right.is(TT_ModulePartitionColon)) + return false; + // No space between :bar; + if (Left.is(TT_ModulePartitionColon) && + Right.isOneOf(tok::identifier, tok::kw_private)) + return false; + if (Left.is(tok::ellipsis) && Right.is(tok::identifier) && + Line.First->is(Keywords.kw_import)) + return false; + if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 12f912305f590..da35648ef1ca0 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1114,6 +1114,35 @@ static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next, return Tok->Previous && Tok->Previous->isOneOf(tok::l_paren, tok::comma); } +void UnwrappedLineParser::parseModuleImport() { + nextToken(); + while (!eof()) { + if (FormatTok->is(tok::colon)) { + FormatTok->setType(TT_ModulePartitionColon); + } + // Handle import <foo/bar.h> as we would an include statement. + else if (FormatTok->is(tok::less)) { + nextToken(); + while (!FormatTok->isOneOf(tok::semi, tok::greater, tok::eof)) { + // Mark tokens up to the trailing line comments as implicit string + // literals. + if (FormatTok->isNot(tok::comment) && + !FormatTok->TokenText.startswith("//")) + FormatTok->setType(TT_ImplicitStringLiteral); + nextToken(); + } + } + if (FormatTok->is(tok::semi)) { + nextToken(); + break; + } + nextToken(); + } + + addUnwrappedLine(); + return; +} + // readTokenWithJavaScriptASI reads the next token and terminates the current // line if JavaScript Automatic Semicolon Insertion must // happen between the current token and the next token. @@ -1312,6 +1341,10 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { addUnwrappedLine(); return; } + 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 bcae0f3ad2587..b4c0826545971 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -110,6 +110,7 @@ class UnwrappedLineParser { void parseCaseLabel(); void parseSwitch(); void parseNamespace(); + void parseModuleImport(); void parseNew(); void parseAccessSpecifier(); bool parseEnum(); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index fb04b4f359859..79a74b5141e82 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -22616,6 +22616,71 @@ TEST_F(FormatTest, FormatDecayCopy) { verifyFormat("auto(*p)() = f;"); // actually a declaration; TODO FIXME } +TEST_F(FormatTest, Cpp20ModulesSupport) { + FormatStyle Style = getLLVMStyle(); + Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; + + verifyFormat("export import foo;", Style); + verifyFormat("export import foo:bar;", Style); + verifyFormat("export import foo.bar;", Style); + verifyFormat("export import foo.bar:baz;", Style); + verifyFormat("export import :bar;", Style); + verifyFormat("export module foo:bar;", Style); + verifyFormat("export module foo;", Style); + verifyFormat("export module foo.bar;", Style); + verifyFormat("export module foo.bar:baz;", Style); + verifyFormat("export import <string_view>;", Style); + + verifyFormat("export type_name var;", Style); + verifyFormat("template <class T> export using A = B<T>;", Style); + verifyFormat("export using A = B;", Style); + verifyFormat("export int func() {\n" + " foo();\n" + "}", + Style); + verifyFormat("export struct {\n" + " int foo;\n" + "};", + Style); + verifyFormat("export {\n" + " int foo;\n" + "};", + Style); + verifyFormat("export export char const *hello() { return \"hello\"; }"); + + verifyFormat("import bar;", Style); + verifyFormat("import foo.bar;", Style); + verifyFormat("import foo:bar;", Style); + verifyFormat("import :bar;", Style); + verifyFormat("import <ctime>;", Style); + verifyFormat("import \"header\";", Style); + + verifyFormat("module foo;", Style); + verifyFormat("module foo:bar;", Style); + verifyFormat("module foo.bar;", Style); + verifyFormat("module;", Style); + + verifyFormat("export namespace hi {\n" + "const char *sayhi();\n" + "}", + Style); + + verifyFormat("module :private;", Style); + verifyFormat("import <foo/bar.h>;", Style); + verifyFormat("import foo...bar;", Style); + verifyFormat("import ..........;", Style); + verifyFormat("module foo:private;", Style); + verifyFormat("import a", Style); + verifyFormat("module a", Style); + verifyFormat("export import a", Style); + verifyFormat("export module a", Style); + + verifyFormat("import", Style); + verifyFormat("module", Style); + verifyFormat("export", Style); +} + } // namespace } // namespace format } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits