diff options
Diffstat (limited to 'clangd/refactor/Tweak.cpp')
-rw-r--r-- | clangd/refactor/Tweak.cpp | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/clangd/refactor/Tweak.cpp b/clangd/refactor/Tweak.cpp new file mode 100644 index 00000000..34634e64 --- /dev/null +++ b/clangd/refactor/Tweak.cpp @@ -0,0 +1,82 @@ +//===--- Tweak.cpp -----------------------------------------------*- C++-*-===// +// +// 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 "Tweak.h" +#include "Logger.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Registry.h" +#include <functional> +#include <memory> + +LLVM_INSTANTIATE_REGISTRY(llvm::Registry<clang::clangd::Tweak>) + +namespace clang { +namespace clangd { + +/// A handy typedef to save some typing. +typedef llvm::Registry<Tweak> TweakRegistry; + +namespace { +/// Asserts invariants on TweakRegistry. No-op with assertion disabled. +void validateRegistry() { +#ifndef NDEBUG + llvm::StringSet<> Seen; + for (const auto &E : TweakRegistry::entries()) { + // REGISTER_TWEAK ensures E.getName() is equal to the tweak class name. + // We check that id() matches it. + assert(E.instantiate()->id() == E.getName() && + "id should be equal to class name"); + assert(Seen.try_emplace(E.getName()).second && "duplicate check id"); + } +#endif +} +} // namespace + +Tweak::Selection::Selection(ParsedAST &AST, unsigned RangeBegin, + unsigned RangeEnd) + : AST(AST), ASTSelection(AST.getASTContext(), RangeBegin, RangeEnd) { + auto &SM = AST.getASTContext().getSourceManager(); + Code = SM.getBufferData(SM.getMainFileID()); + Cursor = SM.getComposedLoc(SM.getMainFileID(), RangeBegin); +} + +std::vector<std::unique_ptr<Tweak>> prepareTweaks(const Tweak::Selection &S) { + validateRegistry(); + + std::vector<std::unique_ptr<Tweak>> Available; + for (const auto &E : TweakRegistry::entries()) { + std::unique_ptr<Tweak> T = E.instantiate(); + if (!T->prepare(S)) + continue; + Available.push_back(std::move(T)); + } + // Ensure deterministic order of the results. + llvm::sort(Available, + [](const std::unique_ptr<Tweak> &L, + const std::unique_ptr<Tweak> &R) { return L->id() < R->id(); }); + return Available; +} + +llvm::Expected<std::unique_ptr<Tweak>> prepareTweak(StringRef ID, + const Tweak::Selection &S) { + auto It = llvm::find_if( + TweakRegistry::entries(), + [ID](const TweakRegistry::entry &E) { return E.getName() == ID; }); + if (It == TweakRegistry::end()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "id of the tweak is invalid"); + std::unique_ptr<Tweak> T = It->instantiate(); + if (!T->prepare(S)) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "failed to prepare() a check"); + return std::move(T); +} + +} // namespace clangd +} // namespace clang |