diff --git a/clang/include/clang/Tooling/Refactoring/Transformer.h b/clang/include/clang/Tooling/Refactoring/Transformer.h --- a/clang/include/clang/Tooling/Refactoring/Transformer.h +++ b/clang/include/clang/Tooling/Refactoring/Transformer.h @@ -44,12 +44,21 @@ Name, }; -using TextGenerator = - std::function; +// \c TextGenerator may fail, because it processes dynamically-bound match +// results. For example, a typo in the name of a bound node or a mismatch in +// the node's type can lead to a failure in the string generation code. We +// allow the generator to return \c Expected, rather than assert on such +// failures, so that the Transformer client can choose how to handle the error. +// For example, if used in a UI (for example, clang-query or a web app), in +// which the user specifies the rewrite rule, the backend might choose to return +// a diagnostic error, rather than crash. +using TextGenerator = std::function( + const ast_matchers::MatchFinder::MatchResult &)>; -/// Wraps a string as a TextGenerator. +/// Wraps a string as a (trivially successful) TextGenerator. inline TextGenerator text(std::string M) { - return [M](const ast_matchers::MatchFinder::MatchResult &) { return M; }; + return [M](const ast_matchers::MatchFinder::MatchResult &) + -> Expected { return M; }; } // Description of a source-code edit, expressed in terms of an AST node. diff --git a/clang/lib/Tooling/Refactoring/Transformer.cpp b/clang/lib/Tooling/Refactoring/Transformer.cpp --- a/clang/lib/Tooling/Refactoring/Transformer.cpp +++ b/clang/lib/Tooling/Refactoring/Transformer.cpp @@ -157,12 +157,16 @@ Edit.Target, It->second, Edit.Kind, Edit.Part, *Result.Context); if (auto Err = RangeOrErr.takeError()) return std::move(Err); - Transformation T; - T.Range = *RangeOrErr; - if (T.Range.isInvalid() || - isOriginMacroBody(*Result.SourceManager, T.Range.getBegin())) + auto &Range = *RangeOrErr; + if (Range.isInvalid() || + isOriginMacroBody(*Result.SourceManager, Range.getBegin())) return SmallVector(); - T.Replacement = Edit.Replacement(Result); + auto ReplacementOrErr = Edit.Replacement(Result); + if (auto Err = ReplacementOrErr.takeError()) + return std::move(Err); + Transformation T; + T.Range = Range; + T.Replacement = std::move(*ReplacementOrErr); Transformations.push_back(std::move(T)); } return Transformations;