Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1521,13 +1521,13 @@ /// Returns the ``Replacements`` necessary to make all \p Ranges comply with /// \p Style. /// -/// If ``IncompleteFormat`` is non-null, its value will be set to true if any -/// of the affected ranges were not formatted due to a non-recoverable syntax -/// error. +/// If ``IncompleteFormat`` is non-null, its value will be set to an error +/// message if any of the affected ranges were not formatted due to a +/// non-recoverable syntax error. tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName = "", - bool *IncompleteFormat = nullptr); + std::string *IncompleteFormat = nullptr); /// \brief Clean up any erroneous/redundant code in the given \p Ranges in \p /// Code. Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -908,7 +908,7 @@ class Formatter : public TokenAnalyzer { public: Formatter(const Environment &Env, const FormatStyle &Style, - bool *IncompleteFormat) + std::string *IncompleteFormat) : TokenAnalyzer(Env, Style), IncompleteFormat(IncompleteFormat) {} tooling::Replacements @@ -931,7 +931,7 @@ Env.getSourceManager(), Whitespaces, Encoding, BinPackInconclusiveFunctions); UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(), - IncompleteFormat) + Env.getSourceManager(), IncompleteFormat) .format(AnnotatedLines); for (const auto &R : Whitespaces.generateReplacements()) if (Result.add(R)) @@ -1013,7 +1013,7 @@ } bool BinPackInconclusiveFunctions; - bool *IncompleteFormat; + std::string *IncompleteFormat; }; // This class clean up the erroneous/redundant code around the given ranges in @@ -1830,7 +1830,8 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, - StringRef FileName, bool *IncompleteFormat) { + StringRef FileName, + std::string *IncompleteFormat) { FormatStyle Expanded = expandPresets(Style); if (Expanded.DisableFormat) return tooling::Replacements(); Index: lib/Format/UnwrappedLineFormatter.h =================================================================== --- lib/Format/UnwrappedLineFormatter.h +++ lib/Format/UnwrappedLineFormatter.h @@ -32,9 +32,11 @@ WhitespaceManager *Whitespaces, const FormatStyle &Style, const AdditionalKeywords &Keywords, - bool *IncompleteFormat) + const SourceManager &SourceMgr, + std::string *IncompleteFormat) : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style), - Keywords(Keywords), IncompleteFormat(IncompleteFormat) {} + Keywords(Keywords), SourceMgr(SourceMgr), + IncompleteFormat(IncompleteFormat) {} /// \brief Format the current block and return the penalty. unsigned format(const SmallVectorImpl &Lines, @@ -63,7 +65,8 @@ WhitespaceManager *Whitespaces; const FormatStyle &Style; const AdditionalKeywords &Keywords; - bool *IncompleteFormat; + const SourceManager &SourceMgr; + std::string *IncompleteFormat; }; } // end namespace format } // end namespace clang Index: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -835,8 +835,16 @@ bool ShouldFormat = TheLine.Affected || FixIndentation; // We cannot format this line; if the reason is that the line had a // parsing error, remember that. - if (ShouldFormat && TheLine.Type == LT_Invalid && IncompleteFormat) - *IncompleteFormat = true; + if (ShouldFormat && TheLine.Type == LT_Invalid && IncompleteFormat) { + llvm::raw_string_ostream os(*IncompleteFormat); + os << "Formatting failed."; + bool Invalid; + unsigned LineNumber = SourceMgr.getSpellingLineNumber( + TheLine.First->Tok.getLocation(), &Invalid); + if (!Invalid) + os << " This might be due to a syntax error at line " << LineNumber + << "."; + } if (ShouldFormat && TheLine.Type != LT_Invalid) { if (!DryRun) Index: test/Format/incomplete.cpp =================================================================== --- test/Format/incomplete.cpp +++ test/Format/incomplete.cpp @@ -1,6 +1,6 @@ // RUN: grep -Ev "// *[A-Z-]+:" %s | clang-format -style=LLVM -cursor=0 \ // RUN: | FileCheck -strict-whitespace %s -// CHECK: {{"IncompleteFormat": true}} +// CHECK: {{"IncompleteFormat": "Formatting failed. This might be due to a syntax error at line 2."}} // CHECK: {{^int\ \i;$}} int i; // CHECK: {{^f \( g \(;$}} Index: test/Format/xmloutput.cpp =================================================================== --- test/Format/xmloutput.cpp +++ test/Format/xmloutput.cpp @@ -2,7 +2,7 @@ // RUN: | FileCheck -strict-whitespace %s // CHECK: #include <b><}} // CHECK-NEXT: {{ <}} // CHECK-NEXT: {{ <}} Index: tools/clang-format/ClangFormat.cpp =================================================================== --- tools/clang-format/ClangFormat.cpp +++ tools/clang-format/ClangFormat.cpp @@ -276,14 +276,15 @@ } // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); - bool IncompleteFormat = false; + std::string IncompleteFormat; Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &IncompleteFormat); Replaces = Replaces.merge(FormatChanges); if (OutputXML) { outs() << "\n\n"; + "xml:space='preserve' incomplete_format='"; + outs().write_escaped(IncompleteFormat); + outs() << "'>\n"; if (Cursor.getNumOccurrences() != 0) outs() << "" << FormatChanges.getShiftedCodePosition(CursorPosition) @@ -310,8 +311,9 @@ if (Cursor.getNumOccurrences() != 0) outs() << "{ \"Cursor\": " << FormatChanges.getShiftedCodePosition(CursorPosition) - << ", \"IncompleteFormat\": " - << (IncompleteFormat ? "true" : "false") << " }\n"; + << ", \"IncompleteFormat\": \""; + outs().write_escaped(IncompleteFormat); + outs() << "\" }\n"; Rewrite.getEditBuffer(ID).write(outs()); } } Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -42,12 +42,13 @@ DEBUG(llvm::errs() << "---\n"); DEBUG(llvm::errs() << Code << "\n\n"); std::vector Ranges(1, tooling::Range(0, Code.size())); - bool IncompleteFormat = false; + std::string IncompleteFormat; tooling::Replacements Replaces = reformat(Style, Code, Ranges, "", &IncompleteFormat); if (CheckIncomplete != IC_DoNotCheck) { bool ExpectedIncompleteFormat = CheckIncomplete == IC_ExpectIncomplete; - EXPECT_EQ(ExpectedIncompleteFormat, IncompleteFormat) << Code << "\n\n"; + EXPECT_EQ(ExpectedIncompleteFormat, !IncompleteFormat.empty()) + << Code << "\n\n"; } ReplacementCount = Replaces.size(); auto Result = applyAllReplacements(Code, Replaces); Index: unittests/Format/FormatTestComments.cpp =================================================================== --- unittests/Format/FormatTestComments.cpp +++ unittests/Format/FormatTestComments.cpp @@ -41,12 +41,13 @@ DEBUG(llvm::errs() << "---\n"); DEBUG(llvm::errs() << Code << "\n\n"); std::vector Ranges(1, tooling::Range(0, Code.size())); - bool IncompleteFormat = false; + std::string IncompleteFormat; tooling::Replacements Replaces = reformat(Style, Code, Ranges, "", &IncompleteFormat); if (CheckIncomplete != IC_DoNotCheck) { bool ExpectedIncompleteFormat = CheckIncomplete == IC_ExpectIncomplete; - EXPECT_EQ(ExpectedIncompleteFormat, IncompleteFormat) << Code << "\n\n"; + EXPECT_EQ(ExpectedIncompleteFormat, !IncompleteFormat.empty()) + << Code << "\n\n"; } ReplacementCount = Replaces.size(); auto Result = applyAllReplacements(Code, Replaces); Index: unittests/Format/FormatTestJS.cpp =================================================================== --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -24,10 +24,10 @@ DEBUG(llvm::errs() << "---\n"); DEBUG(llvm::errs() << Code << "\n\n"); std::vector Ranges(1, tooling::Range(Offset, Length)); - bool IncompleteFormat = false; + std::string IncompleteFormat; tooling::Replacements Replaces = reformat(Style, Code, Ranges, "", &IncompleteFormat); - EXPECT_FALSE(IncompleteFormat); + EXPECT_TRUE(IncompleteFormat.empty()); auto Result = applyAllReplacements(Code, Replaces); EXPECT_TRUE(static_cast(Result)); DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); Index: unittests/Format/FormatTestObjC.cpp =================================================================== --- unittests/Format/FormatTestObjC.cpp +++ unittests/Format/FormatTestObjC.cpp @@ -44,12 +44,13 @@ DEBUG(llvm::errs() << "---\n"); DEBUG(llvm::errs() << Code << "\n\n"); std::vector Ranges(1, tooling::Range(0, Code.size())); - bool IncompleteFormat = false; + std::string IncompleteFormat; tooling::Replacements Replaces = reformat(Style, Code, Ranges, "", &IncompleteFormat); if (CheckIncomplete != IC_DoNotCheck) { bool ExpectedIncompleteFormat = CheckIncomplete == IC_ExpectIncomplete; - EXPECT_EQ(ExpectedIncompleteFormat, IncompleteFormat) << Code << "\n\n"; + EXPECT_EQ(ExpectedIncompleteFormat, !IncompleteFormat.empty()) + << Code << "\n\n"; } auto Result = applyAllReplacements(Code, Replaces); EXPECT_TRUE(static_cast(Result)); Index: unittests/Format/FormatTestSelective.cpp =================================================================== --- unittests/Format/FormatTestSelective.cpp +++ unittests/Format/FormatTestSelective.cpp @@ -24,10 +24,10 @@ DEBUG(llvm::errs() << "---\n"); DEBUG(llvm::errs() << Code << "\n\n"); std::vector Ranges(1, tooling::Range(Offset, Length)); - bool IncompleteFormat = false; + std::string IncompleteFormat; tooling::Replacements Replaces = reformat(Style, Code, Ranges, "", &IncompleteFormat); - EXPECT_FALSE(IncompleteFormat) << Code << "\n\n"; + EXPECT_TRUE(IncompleteFormat.empty()) << Code << "\n\n"; auto Result = applyAllReplacements(Code, Replaces); EXPECT_TRUE(static_cast(Result)); DEBUG(llvm::errs() << "\n" << *Result << "\n\n");