diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2682,7 +2682,7 @@ namespace { const char CppIncludeRegexPattern[] = - R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))"; + R"(^[\t\ ]*[@#][\t\ ]*(import|include)[^"<]*("[^"]+"|<[^>]+>|[^"<>;]+;))"; } // anonymous namespace @@ -2752,6 +2752,15 @@ if (!FormattingOff && !MergeWithNextLine) { if (IncludeRegex.match(Line, &Matches)) { StringRef IncludeName = Matches[2]; + SmallString<0> IncludeNameStr; + // HACK(kkleine): Sort C++ module includes/imports that are not enclosed + // in "" or <> as if they are enclosed with <. + if (!IncludeName.startswith("\"") && !IncludeName.startswith("<")) { + IncludeName = Twine("<", IncludeName) + .concat(Twine(">")) + .toStringRef(IncludeNameStr); + } + if (Line.contains("/*") && !Line.contains("*/")) { // #include with a start of a block comment, but without the end. // Need to keep all the lines until the end of the comment together. diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp --- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -170,11 +170,11 @@ } inline StringRef trimInclude(StringRef IncludeName) { - return IncludeName.trim("\"<>"); + return IncludeName.trim("\"<>;"); } const char IncludeRegexPattern[] = - R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))"; + R"(^[\t\ ]*[@#][\t\ ]*(import|include)[^"<]*("[^"]+"|<[^>]+>|[^"<>;]+;))"; // The filename of Path excluding extension. // Used to match implementation with headers, this differs from sys::path::stem: diff --git a/clang/unittests/Format/SortIncludesTest.cpp b/clang/unittests/Format/SortIncludesTest.cpp --- a/clang/unittests/Format/SortIncludesTest.cpp +++ b/clang/unittests/Format/SortIncludesTest.cpp @@ -458,6 +458,19 @@ "#include \"b.h\"\n")); } +TEST_F(SortIncludesTest, SupportAtImportLines) { + EXPECT_EQ("#import \"a.h\"\n" + "#import \"b.h\"\n" + "#import \"c.h\"\n" + "#import \n" + "@import Foundation;\n", + sort("#import \"b.h\"\n" + "#import \"c.h\"\n" + "#import \n" + "@import Foundation;\n" + "#import \"a.h\"\n")); +} + TEST_F(SortIncludesTest, LeavesMainHeaderFirst) { Style.IncludeIsMainRegex = "([-_](test|unittest))?$"; EXPECT_EQ("#include \"llvm/a.h\"\n"