10#include "clang/Basic/SourceLocation.h"
11#include "clang/Basic/SourceManager.h"
12#include "clang/Basic/TokenKinds.h"
13#include "clang/Tooling/Core/Replacement.h"
14#include "clang/Tooling/Syntax/Tokens.h"
15#include "llvm/ADT/ArrayRef.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/Support/Error.h"
31class ExpandMacro :
public Tweak {
33 const char *id() const final;
34 llvm::StringLiteral kind()
const override {
38 bool prepare(
const Selection &Inputs)
override;
39 Expected<Tweak::Effect> apply(
const Selection &Inputs)
override;
40 std::string title()
const override;
43 syntax::TokenBuffer::Expansion Expansion;
50static const syntax::Token *
51findTokenUnderCursor(
const SourceManager &SM,
52 llvm::ArrayRef<syntax::Token>
Spelled,
53 unsigned CursorOffset) {
55 auto *It = llvm::partition_point(
Spelled, [&](
const syntax::Token &T) {
56 assert(
T.location().isFileID());
57 return SM.getFileOffset(
T.location()) <= CursorOffset;
63 return It->range(SM).touches(CursorOffset) ? It :
nullptr;
66static const syntax::Token *
67findIdentifierUnderCursor(
const syntax::TokenBuffer &Tokens,
68 SourceLocation Cursor) {
69 assert(Cursor.isFileID());
71 auto &SM = Tokens.sourceManager();
72 auto Spelled = Tokens.spelledTokens(SM.getFileID(Cursor));
74 auto *
T = findTokenUnderCursor(SM,
Spelled, SM.getFileOffset(Cursor));
77 if (
T->kind() == tok::identifier)
85 if (
T->endLocation() != Cursor ||
T->kind() != tok::identifier)
90bool ExpandMacro::prepare(
const Selection &Inputs) {
95 auto *
T = findIdentifierUnderCursor(Inputs.AST->getTokens(), Inputs.Cursor);
100 auto Expansion = Inputs.AST->getTokens().expansionStartingAt(T);
103 this->
MacroName = std::string(
T->text(Inputs.AST->getSourceManager()));
104 this->Expansion = *Expansion;
108Expected<Tweak::Effect> ExpandMacro::apply(
const Selection &Inputs) {
109 auto &SM = Inputs.AST->getSourceManager();
111 std::string Replacement;
112 for (
const syntax::Token &T : Expansion.Expanded) {
113 Replacement +=
T.text(SM);
116 if (!Replacement.empty()) {
117 assert(Replacement.back() ==
' ');
118 Replacement.pop_back();
121 CharSourceRange MacroRange =
122 CharSourceRange::getCharRange(Expansion.Spelled.front().location(),
123 Expansion.Spelled.back().endLocation());
125 tooling::Replacements Reps;
126 llvm::cantFail(Reps.add(tooling::Replacement(SM, MacroRange, Replacement)));
127 return Effect::mainFileEdit(SM, std::move(Reps));
130std::string ExpandMacro::title()
const {
131 return std::string(llvm::formatv(
"Expand macro '{0}'",
MacroName));
#define REGISTER_TWEAK(Subclass)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
static const llvm::StringLiteral REFACTOR_KIND