summaryrefslogtreecommitdiffstats
path: root/clangd/refactor/Tweak.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clangd/refactor/Tweak.cpp')
-rw-r--r--clangd/refactor/Tweak.cpp82
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