brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.2 KiB · 840843d Raw
127 lines · cpp
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-exception6//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/STLExtras.h"15#include "llvm/ADT/StringMap.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/Support/Error.h"18#include "llvm/Support/Registry.h"19#include <functional>20#include <memory>21#include <utility>22#include <vector>23 24LLVM_INSTANTIATE_REGISTRY(llvm::Registry<clang::clangd::Tweak>)25 26namespace clang {27namespace clangd {28 29/// A handy typedef to save some typing.30typedef llvm::Registry<Tweak> TweakRegistry;31 32namespace {33/// Asserts invariants on TweakRegistry. No-op with assertion disabled.34void validateRegistry() {35#ifndef NDEBUG36  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#endif45}46 47std::vector<std::unique_ptr<Tweak>>48getAllTweaks(const FeatureModuleSet *Modules) {49  std::vector<std::unique_ptr<Tweak>> All;50  for (const auto &E : TweakRegistry::entries())51    All.emplace_back(E.instantiate());52  if (Modules) {53    for (auto &M : *Modules)54      M.contributeTweaks(All);55  }56  return All;57}58} // namespace59 60Tweak::Selection::Selection(const SymbolIndex *Index, ParsedAST &AST,61                            unsigned RangeBegin, unsigned RangeEnd,62                            SelectionTree ASTSelection,63                            llvm::vfs::FileSystem *FS)64    : Index(Index), AST(&AST), SelectionBegin(RangeBegin),65      SelectionEnd(RangeEnd), ASTSelection(std::move(ASTSelection)), FS(FS) {66  auto &SM = AST.getSourceManager();67  Code = SM.getBufferData(SM.getMainFileID());68  Cursor = SM.getComposedLoc(SM.getMainFileID(), RangeBegin);69}70 71std::vector<std::unique_ptr<Tweak>>72prepareTweaks(const Tweak::Selection &S,73              llvm::function_ref<bool(const Tweak &)> Filter,74              const FeatureModuleSet *Modules) {75  validateRegistry();76 77  std::vector<std::unique_ptr<Tweak>> Available;78  for (auto &T : getAllTweaks(Modules)) {79    if (!Filter(*T) || !T->prepare(S))80      continue;81    Available.push_back(std::move(T));82  }83  // Ensure deterministic order of the results.84  llvm::sort(Available,85             [](const std::unique_ptr<Tweak> &L,86                const std::unique_ptr<Tweak> &R) { return L->id() < R->id(); });87  return Available;88}89 90llvm::Expected<std::unique_ptr<Tweak>>91prepareTweak(StringRef ID, const Tweak::Selection &S,92             const FeatureModuleSet *Modules) {93  for (auto &T : getAllTweaks(Modules)) {94    if (T->id() != ID)95      continue;96    if (!T->prepare(S))97      return error("failed to prepare() tweak {0}", ID);98    return std::move(T);99  }100  return error("tweak ID {0} is invalid", ID);101}102 103llvm::Expected<std::pair<Path, Edit>>104Tweak::Effect::fileEdit(const SourceManager &SM, FileID FID,105                        tooling::Replacements Replacements) {106  Edit Ed(SM.getBufferData(FID), std::move(Replacements));107  if (const auto FE = SM.getFileEntryRefForID(FID))108    if (auto FilePath = getCanonicalPath(*FE, SM.getFileManager()))109      return std::make_pair(*FilePath, std::move(Ed));110  return error("Failed to get absolute path for edited file: {0}",111               SM.getFileEntryRefForID(FID)->getName());112}113 114llvm::Expected<Tweak::Effect>115Tweak::Effect::mainFileEdit(const SourceManager &SM,116                            tooling::Replacements Replacements) {117  auto PathAndEdit = fileEdit(SM, SM.getMainFileID(), std::move(Replacements));118  if (!PathAndEdit)119    return PathAndEdit.takeError();120  Tweak::Effect E;121  E.ApplyEdits.try_emplace(PathAndEdit->first, PathAndEdit->second);122  return E;123}124 125} // namespace clangd126} // namespace clang127