diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index d4f1d7bb60..4c326dec6d 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -469,6 +469,9 @@ struct FormatStyle { /// Pointer and reference alignment style. PointerAlignmentStyle PointerAlignment; + /// \brief If true, clang-format will sort #includes. + bool SortIncludes; + /// \brief If \c true, a space may be inserted after C style casts. bool SpaceAfterCStyleCast; diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index c1a3019415..4bc12f88cb 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -284,6 +284,7 @@ template <> struct MappingTraits { IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter); IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", Style.PenaltyReturnTypeOnItsOwnLine); + IO.mapOptional("SortIncludes", Style.SortIncludes); IO.mapOptional("PointerAlignment", Style.PointerAlignment); IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast); IO.mapOptional("SpaceBeforeAssignmentOperators", @@ -507,6 +508,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; LLVMStyle.DisableFormat = false; + LLVMStyle.SortIncludes = true; return LLVMStyle; } @@ -635,6 +637,7 @@ FormatStyle getGNUStyle() { FormatStyle getNoStyle() { FormatStyle NoStyle = getLLVMStyle(); NoStyle.DisableFormat = true; + NoStyle.SortIncludes = false; return NoStyle; } @@ -1743,6 +1746,9 @@ tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName) { tooling::Replacements Replaces; + if (!Style.SortIncludes) + return Replaces; + unsigned Prev = 0; unsigned SearchFrom = 0; llvm::Regex IncludeRegex( diff --git a/test/Format/disable-include-sorting.cpp b/test/Format/disable-include-sorting.cpp new file mode 100644 index 0000000000..875a0af400 --- /dev/null +++ b/test/Format/disable-include-sorting.cpp @@ -0,0 +1,10 @@ +// RUN: clang-format %s | FileCheck %s +// RUN: clang-format %s -sort-includes -style="{SortIncludes: false}" | FileCheck %s +// RUN: clang-format %s -sort-includes=false | FileCheck %s -check-prefix=NOT-SORTED + +#include +#include +// CHECK: +// CHECK-NEXT: +// NOT-SORTED: +// NOT-SORTED-NEXT: diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index 7cdb823f36..43eded20fa 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -98,9 +98,11 @@ static cl::opt "clang-format from an editor integration"), cl::init(0), cl::cat(ClangFormatCategory)); -static cl::opt SortIncludes("sort-includes", - cl::desc("Sort touched include lines"), - cl::cat(ClangFormatCategory)); +static cl::opt SortIncludes( + "sort-includes", + cl::desc("If set, overrides the include sorting behavior determined by the " + "SortIncludes style flag"), + cl::cat(ClangFormatCategory)); static cl::list FileNames(cl::Positional, cl::desc("[ ...]"), cl::cat(ClangFormatCategory)); @@ -252,17 +254,14 @@ static bool format(StringRef FileName) { return true; StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName; FormatStyle FormatStyle = getStyle(Style, AssumedFileName, FallbackStyle); - Replacements Replaces; - std::string ChangedCode; - if (SortIncludes) { - Replaces = - sortIncludes(FormatStyle, Code->getBuffer(), Ranges, AssumedFileName); - ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces); - for (const auto &R : Replaces) - Ranges.push_back({R.getOffset(), R.getLength()}); - } else { - ChangedCode = Code->getBuffer().str(); - } + if (SortIncludes.getNumOccurrences() != 0) + FormatStyle.SortIncludes = SortIncludes; + Replacements Replaces = + sortIncludes(FormatStyle, Code->getBuffer(), Ranges, AssumedFileName); + std::string ChangedCode = + tooling::applyAllReplacements(Code->getBuffer(), Replaces); + for (const auto &R : Replaces) + Ranges.push_back({R.getOffset(), R.getLength()}); bool IncompleteFormat = false; Replaces = tooling::mergeReplacements( diff --git a/tools/clang-format/clang-format-sublime.py b/tools/clang-format/clang-format-sublime.py index 1cffcecc39..16ff56e502 100644 --- a/tools/clang-format/clang-format-sublime.py +++ b/tools/clang-format/clang-format-sublime.py @@ -32,7 +32,7 @@ class ClangFormatCommand(sublime_plugin.TextCommand): if encoding == 'Undefined': encoding = 'utf-8' regions = [] - command = [binary, '-sort-includes', '-style', style] + command = [binary, '-style', style] for region in self.view.sel(): regions.append(region) region_offset = min(region.a, region.b) diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el index 6de45de70a..ca461444e2 100644 --- a/tools/clang-format/clang-format.el +++ b/tools/clang-format/clang-format.el @@ -126,7 +126,6 @@ is no active region. If no style is given uses `clang-format-style'." nil `(,temp-buffer ,temp-file) nil "-output-replacements-xml" - "-sort-includes" "-assume-filename" (or (buffer-file-name) "") "-style" style "-offset" (number-to-string start) diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py index 1725e8659a..5cb41fcfa3 100644 --- a/tools/clang-format/clang-format.py +++ b/tools/clang-format/clang-format.py @@ -72,7 +72,7 @@ def main(): startupinfo.wShowWindow = subprocess.SW_HIDE # Call formatter. - command = [binary, '-style', style, '-cursor', str(cursor), '-sort-includes'] + command = [binary, '-style', style, '-cursor', str(cursor)] if lines != 'all': command.extend(['-lines', lines]) if fallback_style: diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 1c68d67956..1c5e63b3e0 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -9563,12 +9563,14 @@ TEST_F(FormatTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine); CHECK_PARSE_BOOL(DerivePointerAlignment); CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); + CHECK_PARSE_BOOL(DisableFormat); CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks); CHECK_PARSE_BOOL(ObjCSpaceAfterProperty); CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); CHECK_PARSE_BOOL(Cpp11BracedListStyle); + CHECK_PARSE_BOOL(SortIncludes); CHECK_PARSE_BOOL(SpacesInParentheses); CHECK_PARSE_BOOL(SpacesInSquareBrackets); CHECK_PARSE_BOOL(SpacesInAngles); diff --git a/unittests/Format/SortIncludesTest.cpp b/unittests/Format/SortIncludesTest.cpp index 84bc554edd..30109ffb72 100644 --- a/unittests/Format/SortIncludesTest.cpp +++ b/unittests/Format/SortIncludesTest.cpp @@ -40,6 +40,16 @@ TEST_F(SortIncludesTest, BasicSorting) { "#include \"b.h\"\n")); } +TEST_F(SortIncludesTest, IncludeSortingCanBeDisabled) { + Style.SortIncludes = false; + EXPECT_EQ("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n", + sort("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n")); +} + TEST_F(SortIncludesTest, MixIncludeAndImport) { EXPECT_EQ("#include \"a.h\"\n" "#import \"b.h\"\n"