clang-tools  12.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 "SourceCode.h"
10 #include "index/Index.h"
11 #include "support/Logger.h"
12 #include "support/Path.h"
13 #include "llvm/ADT/None.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/Support/Registry.h"
20 #include <functional>
21 #include <memory>
22 #include <utility>
23 
24 LLVM_INSTANTIATE_REGISTRY(llvm::Registry<clang::clangd::Tweak>)
25 
26 namespace clang {
27 namespace clangd {
28 
29 /// A handy typedef to save some typing.
30 typedef llvm::Registry<Tweak> TweakRegistry;
31 
32 namespace {
33 /// Asserts invariants on TweakRegistry. No-op with assertion disabled.
34 void validateRegistry() {
35 #ifndef NDEBUG
36  llvm::StringSet<> Seen;
37  for (const auto &E : TweakRegistry::entries()) {
38  // REGISTER_TWEAK ensures E.getName() is equal to the tweak class name.
39  // We check that id() matches it.
40  assert(E.instantiate()->id() == E.getName() &&
41  "id should be equal to class name");
42  assert(Seen.try_emplace(E.getName()).second && "duplicate check id");
43  }
44 #endif
45 }
46 } // namespace
47 
49  unsigned RangeBegin, unsigned RangeEnd,
50  SelectionTree ASTSelection)
51  : Index(Index), AST(&AST), SelectionBegin(RangeBegin),
52  SelectionEnd(RangeEnd), ASTSelection(std::move(ASTSelection)) {
53  auto &SM = AST.getSourceManager();
54  Code = SM.getBufferData(SM.getMainFileID());
55  Cursor = SM.getComposedLoc(SM.getMainFileID(), RangeBegin);
56 }
57 
58 std::vector<std::unique_ptr<Tweak>>
60  llvm::function_ref<bool(const Tweak &)> Filter) {
61  validateRegistry();
62 
63  std::vector<std::unique_ptr<Tweak>> Available;
64  for (const auto &E : TweakRegistry::entries()) {
65  std::unique_ptr<Tweak> T = E.instantiate();
66  if (!Filter(*T) || !T->prepare(S))
67  continue;
68  Available.push_back(std::move(T));
69  }
70  // Ensure deterministic order of the results.
71  llvm::sort(Available,
72  [](const std::unique_ptr<Tweak> &L,
73  const std::unique_ptr<Tweak> &R) { return L->id() < R->id(); });
74  return Available;
75 }
76 
77 llvm::Expected<std::unique_ptr<Tweak>> prepareTweak(StringRef ID,
78  const Tweak::Selection &S) {
79  auto It = llvm::find_if(
80  TweakRegistry::entries(),
81  [ID](const TweakRegistry::entry &E) { return E.getName() == ID; });
82  if (It == TweakRegistry::end())
83  return llvm::createStringError(llvm::inconvertibleErrorCode(),
84  "id of the tweak is invalid");
85  std::unique_ptr<Tweak> T = It->instantiate();
86  if (!T->prepare(S))
87  return llvm::createStringError(llvm::inconvertibleErrorCode(),
88  "failed to prepare() a check");
89  return std::move(T);
90 }
91 
92 llvm::Expected<std::pair<Path, Edit>>
93 Tweak::Effect::fileEdit(const SourceManager &SM, FileID FID,
94  tooling::Replacements Replacements) {
95  Edit Ed(SM.getBufferData(FID), std::move(Replacements));
96  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
97  return std::make_pair(*FilePath, std::move(Ed));
98  return llvm::createStringError(
99  llvm::inconvertibleErrorCode(),
100  "Failed to get absolute path for edited file: " +
101  SM.getFileEntryForID(FID)->getName());
102 }
103 
104 llvm::Expected<Tweak::Effect>
105 Tweak::Effect::mainFileEdit(const SourceManager &SM,
106  tooling::Replacements Replacements) {
107  auto PathAndEdit = fileEdit(SM, SM.getMainFileID(), std::move(Replacements));
108  if (!PathAndEdit)
109  return PathAndEdit.takeError();
111  E.ApplyEdits.try_emplace(PathAndEdit->first, PathAndEdit->second);
112  return E;
113 }
114 
115 } // namespace clangd
116 } // namespace clang
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S)
Definition: Tweak.cpp:77
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:85
llvm::StringRef Code
The text of the active document.
Definition: Tweak.h:53
llvm::Registry< Tweak > TweakRegistry
A handy typedef to save some typing.
Definition: Tweak.cpp:30
SourceLocation Cursor
A location of the cursor in the editor.
Definition: Tweak.h:60
Input to prepare and apply tweaks.
Definition: Tweak.h:49
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:105
Stores and provides access to parsed AST.
Definition: ParsedAST.h:48
SourceManager & getSourceManager()
Definition: ParsedAST.h:74
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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:93
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:512
const Expr * E
An interface base for small context-sensitive refactoring actions.
Definition: Tweak.h:46
Selection(const SymbolIndex *Index, ParsedAST &AST, unsigned RangeBegin, unsigned RangeEnd, SelectionTree ASTSelection)
Definition: Tweak.cpp:48
A set of edits generated for a single file.
Definition: SourceCode.h:180
std::vector< std::unique_ptr< Tweak > > prepareTweaks(const Tweak::Selection &S, llvm::function_ref< bool(const Tweak &)> Filter)
Calls prepare() on all tweaks that satisfy the filter, returning those that can run on the selection...
Definition: Tweak.cpp:59
const SymbolIndex * Index
Definition: Dexp.cpp:95