File: Tweak.cpp

package info (click to toggle)
llvm-toolchain-14 1%3A14.0.6-16
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,496,368 kB
  • sloc: cpp: 5,593,980; ansic: 986,873; asm: 585,869; python: 184,223; objc: 72,530; lisp: 31,119; f90: 27,793; javascript: 9,780; pascal: 9,762; sh: 9,482; perl: 7,468; ml: 5,432; awk: 3,523; makefile: 2,547; xml: 953; cs: 573; fortran: 567
file content (127 lines) | stat: -rw-r--r-- 4,279 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//===--- 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 "FeatureModule.h"
#include "SourceCode.h"
#include "index/Index.h"
#include "support/Logger.h"
#include "support/Path.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Registry.h"
#include <functional>
#include <memory>
#include <utility>
#include <vector>

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
}

std::vector<std::unique_ptr<Tweak>>
getAllTweaks(const FeatureModuleSet *Modules) {
  std::vector<std::unique_ptr<Tweak>> All;
  for (const auto &E : TweakRegistry::entries())
    All.emplace_back(E.instantiate());
  if (Modules) {
    for (auto &M : *Modules)
      M.contributeTweaks(All);
  }
  return All;
}
} // namespace

Tweak::Selection::Selection(const SymbolIndex *Index, ParsedAST &AST,
                            unsigned RangeBegin, unsigned RangeEnd,
                            SelectionTree ASTSelection,
                            llvm::vfs::FileSystem *FS)
    : Index(Index), AST(&AST), SelectionBegin(RangeBegin),
      SelectionEnd(RangeEnd), ASTSelection(std::move(ASTSelection)), FS(FS) {
  auto &SM = AST.getSourceManager();
  Code = SM.getBufferData(SM.getMainFileID());
  Cursor = SM.getComposedLoc(SM.getMainFileID(), RangeBegin);
}

std::vector<std::unique_ptr<Tweak>>
prepareTweaks(const Tweak::Selection &S,
              llvm::function_ref<bool(const Tweak &)> Filter,
              const FeatureModuleSet *Modules) {
  validateRegistry();

  std::vector<std::unique_ptr<Tweak>> Available;
  for (auto &T : getAllTweaks(Modules)) {
    if (!Filter(*T) || !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,
             const FeatureModuleSet *Modules) {
  for (auto &T : getAllTweaks(Modules)) {
    if (T->id() != ID)
      continue;
    if (!T->prepare(S))
      return error("failed to prepare() tweak {0}", ID);
    return std::move(T);
  }
  return error("tweak ID {0} is invalid", ID);
}

llvm::Expected<std::pair<Path, Edit>>
Tweak::Effect::fileEdit(const SourceManager &SM, FileID FID,
                        tooling::Replacements Replacements) {
  Edit Ed(SM.getBufferData(FID), std::move(Replacements));
  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
    return std::make_pair(*FilePath, std::move(Ed));
  return error("Failed to get absolute path for edited file: {0}",
               SM.getFileEntryForID(FID)->getName());
}

llvm::Expected<Tweak::Effect>
Tweak::Effect::mainFileEdit(const SourceManager &SM,
                            tooling::Replacements Replacements) {
  auto PathAndEdit = fileEdit(SM, SM.getMainFileID(), std::move(Replacements));
  if (!PathAndEdit)
    return PathAndEdit.takeError();
  Tweak::Effect E;
  E.ApplyEdits.try_emplace(PathAndEdit->first, PathAndEdit->second);
  return E;
}

} // namespace clangd
} // namespace clang