clang-tools  14.0.0git
Tweak.cpp
Go to the documentation of this file.
1 //===--- Tweak.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "Tweak.h"
9 #include "FeatureModule.h"
10 #include "SourceCode.h"
11 #include "index/Index.h"
12 #include "support/Logger.h"
13 #include "support/Path.h"
14 #include "llvm/ADT/None.h"
15 #include "llvm/ADT/Optional.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/Registry.h"
21 #include <functional>
22 #include <memory>
23 #include <utility>
24 #include <vector>
25 
26 LLVM_INSTANTIATE_REGISTRY(llvm::Registry<clang::clangd::Tweak>)
27 
28 namespace clang {
29 namespace clangd {
30 
31 /// A handy typedef to save some typing.
32 typedef llvm::Registry<Tweak> TweakRegistry;
33 
34 namespace {
35 /// Asserts invariants on TweakRegistry. No-op with assertion disabled.
36 void validateRegistry() {
37 #ifndef NDEBUG
38  llvm::StringSet<> Seen;
39  for (const auto &E : TweakRegistry::entries()) {
40  // REGISTER_TWEAK ensures E.getName() is equal to the tweak class name.
41  // We check that id() matches it.
42  assert(E.instantiate()->id() == E.getName() &&
43  "id should be equal to class name");
44  assert(Seen.try_emplace(E.getName()).second && "duplicate check id");
45  }
46 #endif
47 }
48 
49 std::vector<std::unique_ptr<Tweak>>
50 getAllTweaks(const FeatureModuleSet *Modules) {
51  std::vector<std::unique_ptr<Tweak>> All;
52  for (const auto &E : TweakRegistry::entries())
53  All.emplace_back(E.instantiate());
54  if (Modules) {
55  for (auto &M : *Modules)
56  M.contributeTweaks(All);
57  }
58  return All;
59 }
60 } // namespace
61 
63  unsigned RangeBegin, unsigned RangeEnd,
64  SelectionTree ASTSelection,
65  llvm::vfs::FileSystem *FS)
66  : Index(Index), AST(&AST), SelectionBegin(RangeBegin),
67  SelectionEnd(RangeEnd), ASTSelection(std::move(ASTSelection)), FS(FS) {
68  auto &SM = AST.getSourceManager();
69  Code = SM.getBufferData(SM.getMainFileID());
70  Cursor = SM.getComposedLoc(SM.getMainFileID(), RangeBegin);
71 }
72 
73 std::vector<std::unique_ptr<Tweak>>
75  llvm::function_ref<bool(const Tweak &)> Filter,
76  const FeatureModuleSet *Modules) {
77  validateRegistry();
78 
79  std::vector<std::unique_ptr<Tweak>> Available;
80  for (auto &T : getAllTweaks(Modules)) {
81  if (!Filter(*T) || !T->prepare(S))
82  continue;
83  Available.push_back(std::move(T));
84  }
85  // Ensure deterministic order of the results.
86  llvm::sort(Available,
87  [](const std::unique_ptr<Tweak> &L,
88  const std::unique_ptr<Tweak> &R) { return L->id() < R->id(); });
89  return Available;
90 }
91 
92 llvm::Expected<std::unique_ptr<Tweak>>
93 prepareTweak(StringRef ID, const Tweak::Selection &S,
94  const FeatureModuleSet *Modules) {
95  for (auto &T : getAllTweaks(Modules)) {
96  if (T->id() != ID)
97  continue;
98  if (!T->prepare(S))
99  return error("failed to prepare() tweak {0}", ID);
100  return std::move(T);
101  }
102  return error("tweak ID {0} is invalid", ID);
103 }
104 
105 llvm::Expected<std::pair<Path, Edit>>
106 Tweak::Effect::fileEdit(const SourceManager &SM, FileID FID,
107  tooling::Replacements Replacements) {
108  Edit Ed(SM.getBufferData(FID), std::move(Replacements));
109  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
110  return std::make_pair(*FilePath, std::move(Ed));
111  return error("Failed to get absolute path for edited file: {0}",
112  SM.getFileEntryForID(FID)->getName());
113 }
114 
115 llvm::Expected<Tweak::Effect>
116 Tweak::Effect::mainFileEdit(const SourceManager &SM,
117  tooling::Replacements Replacements) {
118  auto PathAndEdit = fileEdit(SM, SM.getMainFileID(), std::move(Replacements));
119  if (!PathAndEdit)
120  return PathAndEdit.takeError();
122  E.ApplyEdits.try_emplace(PathAndEdit->first, PathAndEdit->second);
123  return E;
124 }
125 
126 } // namespace clangd
127 } // namespace clang
clang::clangd::TweakRegistry
llvm::Registry< Tweak > TweakRegistry
A handy typedef to save some typing.
Definition: Tweak.cpp:32
clang::clangd::FeatureModuleSet
A FeatureModuleSet is a collection of feature modules installed in clangd.
Definition: FeatureModule.h:145
clang::clangd::Edit
A set of edits generated for a single file.
Definition: SourceCode.h:180
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::clangd::error
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
Definition: Logger.h:80
Path.h
Index.h
clang::clangd::Tweak::Selection::Cursor
SourceLocation Cursor
A location of the cursor in the editor.
Definition: Tweak.h:64
clang::clangd::Tweak::Selection::AST
ParsedAST * AST
The parsed active file. Never null. (Pointer so Selection is movable).
Definition: Tweak.h:61
clang::clangd::Tweak::Effect
Definition: Tweak.h:77
clang::clangd::Tweak::Selection::Code
llvm::StringRef Code
The text of the active document.
Definition: Tweak.h:57
M
const google::protobuf::Message & M
Definition: Server.cpp:309
clang::clangd::prepareTweaks
std::vector< std::unique_ptr< Tweak > > prepareTweaks(const Tweak::Selection &S, llvm::function_ref< bool(const Tweak &)> Filter, const FeatureModuleSet *Modules)
Calls prepare() on all tweaks that satisfy the filter, returning those that can run on the selection.
Definition: Tweak.cpp:74
clang::clangd::getCanonicalPath
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:507
Tweak.h
Logger.h
clang::clangd::SelectionTree
Definition: Selection.h:76
SourceCode.h
Index
const SymbolIndex * Index
Definition: Dexp.cpp:99
clang::clangd::SymbolIndex
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:111
clang::clangd::Tweak::Effect::fileEdit
static llvm::Expected< std::pair< Path, Edit > > fileEdit(const SourceManager &SM, FileID FID, tooling::Replacements Replacements)
Path is the absolute, symlink-resolved path for the file pointed by FID in SM.
Definition: Tweak.cpp:106
FeatureModule.h
clang::clangd::Tweak::Effect::mainFileEdit
static llvm::Expected< Tweak::Effect > mainFileEdit(const SourceManager &SM, tooling::Replacements Replacements)
Creates an effect with an Edit for the main file.
Definition: Tweak.cpp:116
clang::clangd::Tweak::Selection
Input to prepare and apply tweaks.
Definition: Tweak.h:52
ID
static char ID
Definition: Logger.cpp:74
clang::clangd::Tweak::Selection::Selection
Selection(const SymbolIndex *Index, ParsedAST &AST, unsigned RangeBegin, unsigned RangeEnd, SelectionTree ASTSelection, llvm::vfs::FileSystem *VFS)
Definition: Tweak.cpp:62
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::prepareTweak
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S, const FeatureModuleSet *Modules)
Definition: Tweak.cpp:93
clang::clangd::Tweak
An interface base for small context-sensitive refactoring actions.
Definition: Tweak.h:49
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ParsedAST.h:49
clang::clangd::ParsedAST::getSourceManager
SourceManager & getSourceManager()
Definition: ParsedAST.h:75