bool ClangExpressionParser::RewriteExpression(DiagnosticManager &diagnostic_manager) { clang::SourceManager &source_manager = m_compiler->getSourceManager(); clang::edit::EditedSource editor(source_manager, m_compiler->getLangOpts(), nullptr); clang::edit::Commit commit(editor); clang::Rewriter rewriter(source_manager, m_compiler->getLangOpts()); class RewritesReceiver : public edit::EditsReceiver { Rewriter &rewrite; public: RewritesReceiver(Rewriter &in_rewrite) : rewrite(in_rewrite) { } void insert(SourceLocation loc, StringRef text) override { rewrite.InsertText(loc, text); } void replace(CharSourceRange range, StringRef text) override { rewrite.ReplaceText(range.getBegin(), rewrite.getRangeSize(range), text); } }; RewritesReceiver rewrites_receiver(rewriter); const DiagnosticList &diagnostics = diagnostic_manager.Diagnostics(); size_t num_diags = diagnostics.size(); if (num_diags == 0) return false; for (const Diagnostic *diag : diagnostic_manager.Diagnostics()) { const ClangDiagnostic *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag); if (diagnostic && diagnostic->HasFixIts()) { for (const FixItHint &fixit : diagnostic->FixIts()) { // This is cobbed from clang::Rewrite::FixItRewriter. if (fixit.CodeToInsert.empty()) { if (fixit.InsertFromRange.isValid()) { commit.insertFromRange(fixit.RemoveRange.getBegin(), fixit.InsertFromRange, /*afterToken=*/false, fixit.BeforePreviousInsertions); } else commit.remove(fixit.RemoveRange); } else { if (fixit.RemoveRange.isTokenRange() || fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) commit.replace(fixit.RemoveRange, fixit.CodeToInsert); else commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert, /*afterToken=*/false, fixit.BeforePreviousInsertions); } } } } // FIXME - do we want to try to propagate specific errors here? if (!commit.isCommitable()) return false; else if (!editor.commit(commit)) return false; // Now play all the edits, and stash the result in the diagnostic manager. editor.applyRewrites(rewrites_receiver); RewriteBuffer &main_file_buffer = rewriter.getEditBuffer(source_manager.getMainFileID()); std::string fixed_expression; llvm::raw_string_ostream out_stream(fixed_expression); main_file_buffer.write(out_stream); out_stream.flush(); diagnostic_manager.SetFixedExpression(fixed_expression); return true; }