diff options
author | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
commit | 6ffe9e53658409f212834330e13564e4952558f6 (patch) | |
tree | 85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang14/lib/Tooling/RefactoringCallbacks.cpp | |
parent | 726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff) | |
download | ydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz |
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/clang14/lib/Tooling/RefactoringCallbacks.cpp')
-rw-r--r-- | contrib/libs/clang14/lib/Tooling/RefactoringCallbacks.cpp | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/contrib/libs/clang14/lib/Tooling/RefactoringCallbacks.cpp b/contrib/libs/clang14/lib/Tooling/RefactoringCallbacks.cpp new file mode 100644 index 0000000000..e3fc91afeb --- /dev/null +++ b/contrib/libs/clang14/lib/Tooling/RefactoringCallbacks.cpp @@ -0,0 +1,240 @@ +//===--- RefactoringCallbacks.cpp - Structural query framework ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// +#include "clang/Tooling/RefactoringCallbacks.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Lexer.h" + +using llvm::StringError; +using llvm::make_error; + +namespace clang { +namespace tooling { + +RefactoringCallback::RefactoringCallback() {} +tooling::Replacements &RefactoringCallback::getReplacements() { + return Replace; +} + +ASTMatchRefactorer::ASTMatchRefactorer( + std::map<std::string, Replacements> &FileToReplaces) + : FileToReplaces(FileToReplaces) {} + +void ASTMatchRefactorer::addDynamicMatcher( + const ast_matchers::internal::DynTypedMatcher &Matcher, + RefactoringCallback *Callback) { + MatchFinder.addDynamicMatcher(Matcher, Callback); + Callbacks.push_back(Callback); +} + +class RefactoringASTConsumer : public ASTConsumer { +public: + explicit RefactoringASTConsumer(ASTMatchRefactorer &Refactoring) + : Refactoring(Refactoring) {} + + void HandleTranslationUnit(ASTContext &Context) override { + // The ASTMatchRefactorer is re-used between translation units. + // Clear the matchers so that each Replacement is only emitted once. + for (const auto &Callback : Refactoring.Callbacks) { + Callback->getReplacements().clear(); + } + Refactoring.MatchFinder.matchAST(Context); + for (const auto &Callback : Refactoring.Callbacks) { + for (const auto &Replacement : Callback->getReplacements()) { + llvm::Error Err = + Refactoring.FileToReplaces[std::string(Replacement.getFilePath())] + .add(Replacement); + if (Err) { + llvm::errs() << "Skipping replacement " << Replacement.toString() + << " due to this error:\n" + << toString(std::move(Err)) << "\n"; + } + } + } + } + +private: + ASTMatchRefactorer &Refactoring; +}; + +std::unique_ptr<ASTConsumer> ASTMatchRefactorer::newASTConsumer() { + return std::make_unique<RefactoringASTConsumer>(*this); +} + +static Replacement replaceStmtWithText(SourceManager &Sources, const Stmt &From, + StringRef Text) { + return tooling::Replacement( + Sources, CharSourceRange::getTokenRange(From.getSourceRange()), Text); +} +static Replacement replaceStmtWithStmt(SourceManager &Sources, const Stmt &From, + const Stmt &To) { + return replaceStmtWithText( + Sources, From, + Lexer::getSourceText(CharSourceRange::getTokenRange(To.getSourceRange()), + Sources, LangOptions())); +} + +ReplaceStmtWithText::ReplaceStmtWithText(StringRef FromId, StringRef ToText) + : FromId(std::string(FromId)), ToText(std::string(ToText)) {} + +void ReplaceStmtWithText::run( + const ast_matchers::MatchFinder::MatchResult &Result) { + if (const Stmt *FromMatch = Result.Nodes.getNodeAs<Stmt>(FromId)) { + auto Err = Replace.add(tooling::Replacement( + *Result.SourceManager, + CharSourceRange::getTokenRange(FromMatch->getSourceRange()), ToText)); + // FIXME: better error handling. For now, just print error message in the + // release version. + if (Err) { + llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } + } +} + +ReplaceStmtWithStmt::ReplaceStmtWithStmt(StringRef FromId, StringRef ToId) + : FromId(std::string(FromId)), ToId(std::string(ToId)) {} + +void ReplaceStmtWithStmt::run( + const ast_matchers::MatchFinder::MatchResult &Result) { + const Stmt *FromMatch = Result.Nodes.getNodeAs<Stmt>(FromId); + const Stmt *ToMatch = Result.Nodes.getNodeAs<Stmt>(ToId); + if (FromMatch && ToMatch) { + auto Err = Replace.add( + replaceStmtWithStmt(*Result.SourceManager, *FromMatch, *ToMatch)); + // FIXME: better error handling. For now, just print error message in the + // release version. + if (Err) { + llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } + } +} + +ReplaceIfStmtWithItsBody::ReplaceIfStmtWithItsBody(StringRef Id, + bool PickTrueBranch) + : Id(std::string(Id)), PickTrueBranch(PickTrueBranch) {} + +void ReplaceIfStmtWithItsBody::run( + const ast_matchers::MatchFinder::MatchResult &Result) { + if (const IfStmt *Node = Result.Nodes.getNodeAs<IfStmt>(Id)) { + const Stmt *Body = PickTrueBranch ? Node->getThen() : Node->getElse(); + if (Body) { + auto Err = + Replace.add(replaceStmtWithStmt(*Result.SourceManager, *Node, *Body)); + // FIXME: better error handling. For now, just print error message in the + // release version. + if (Err) { + llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } + } else if (!PickTrueBranch) { + // If we want to use the 'else'-branch, but it doesn't exist, delete + // the whole 'if'. + auto Err = + Replace.add(replaceStmtWithText(*Result.SourceManager, *Node, "")); + // FIXME: better error handling. For now, just print error message in the + // release version. + if (Err) { + llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } + } + } +} + +ReplaceNodeWithTemplate::ReplaceNodeWithTemplate( + llvm::StringRef FromId, std::vector<TemplateElement> Template) + : FromId(std::string(FromId)), Template(std::move(Template)) {} + +llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>> +ReplaceNodeWithTemplate::create(StringRef FromId, StringRef ToTemplate) { + std::vector<TemplateElement> ParsedTemplate; + for (size_t Index = 0; Index < ToTemplate.size();) { + if (ToTemplate[Index] == '$') { + if (ToTemplate.substr(Index, 2) == "$$") { + Index += 2; + ParsedTemplate.push_back( + TemplateElement{TemplateElement::Literal, "$"}); + } else if (ToTemplate.substr(Index, 2) == "${") { + size_t EndOfIdentifier = ToTemplate.find("}", Index); + if (EndOfIdentifier == std::string::npos) { + return make_error<StringError>( + "Unterminated ${...} in replacement template near " + + ToTemplate.substr(Index), + llvm::inconvertibleErrorCode()); + } + std::string SourceNodeName = std::string( + ToTemplate.substr(Index + 2, EndOfIdentifier - Index - 2)); + ParsedTemplate.push_back( + TemplateElement{TemplateElement::Identifier, SourceNodeName}); + Index = EndOfIdentifier + 1; + } else { + return make_error<StringError>( + "Invalid $ in replacement template near " + + ToTemplate.substr(Index), + llvm::inconvertibleErrorCode()); + } + } else { + size_t NextIndex = ToTemplate.find('$', Index + 1); + ParsedTemplate.push_back(TemplateElement{ + TemplateElement::Literal, + std::string(ToTemplate.substr(Index, NextIndex - Index))}); + Index = NextIndex; + } + } + return std::unique_ptr<ReplaceNodeWithTemplate>( + new ReplaceNodeWithTemplate(FromId, std::move(ParsedTemplate))); +} + +void ReplaceNodeWithTemplate::run( + const ast_matchers::MatchFinder::MatchResult &Result) { + const auto &NodeMap = Result.Nodes.getMap(); + + std::string ToText; + for (const auto &Element : Template) { + switch (Element.Type) { + case TemplateElement::Literal: + ToText += Element.Value; + break; + case TemplateElement::Identifier: { + auto NodeIter = NodeMap.find(Element.Value); + if (NodeIter == NodeMap.end()) { + llvm::errs() << "Node " << Element.Value + << " used in replacement template not bound in Matcher \n"; + llvm::report_fatal_error("Unbound node in replacement template."); + } + CharSourceRange Source = + CharSourceRange::getTokenRange(NodeIter->second.getSourceRange()); + ToText += Lexer::getSourceText(Source, *Result.SourceManager, + Result.Context->getLangOpts()); + break; + } + } + } + if (NodeMap.count(FromId) == 0) { + llvm::errs() << "Node to be replaced " << FromId + << " not bound in query.\n"; + llvm::report_fatal_error("FromId node not bound in MatchResult"); + } + auto Replacement = + tooling::Replacement(*Result.SourceManager, &NodeMap.at(FromId), ToText, + Result.Context->getLangOpts()); + llvm::Error Err = Replace.add(Replacement); + if (Err) { + llvm::errs() << "Query and replace failed in " << Replacement.getFilePath() + << "! " << llvm::toString(std::move(Err)) << "\n"; + llvm::report_fatal_error("Replacement failed"); + } +} + +} // end namespace tooling +} // end namespace clang |