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" 31 class ExpandMacro :
public Tweak {
33 const char *id() const override final;
34 Intent intent()
const override {
return Intent::Refactor; }
36 bool prepare(
const Selection &Inputs)
override;
37 Expected<Tweak::Effect> apply(
const Selection &Inputs)
override;
38 std::string title()
const override;
41 syntax::TokenBuffer::Expansion Expansion;
42 std::string MacroName;
48 static const syntax::Token *
49 findTokenUnderCursor(
const SourceManager &SM,
50 llvm::ArrayRef<syntax::Token> Spelled,
51 unsigned CursorOffset) {
53 auto It = llvm::partition_point(Spelled, [&](
const syntax::Token &T) {
54 assert(T.location().isFileID());
55 return SM.getFileOffset(T.location()) <= CursorOffset;
57 if (It == Spelled.begin())
61 return It->range(SM).touches(CursorOffset) ? It :
nullptr;
64 static const syntax::Token *
65 findIdentifierUnderCursor(
const syntax::TokenBuffer &
Tokens,
66 SourceLocation Cursor) {
67 assert(Cursor.isFileID());
69 auto &SM = Tokens.sourceManager();
70 auto Spelled = Tokens.spelledTokens(SM.getFileID(Cursor));
72 auto *T = findTokenUnderCursor(SM, Spelled, SM.getFileOffset(Cursor));
75 if (T->kind() == tok::identifier)
80 if (T == Spelled.begin())
83 if (T->endLocation() != Cursor || T->kind() != tok::identifier)
88 bool ExpandMacro::prepare(
const Selection &Inputs) {
93 auto *T = findIdentifierUnderCursor(Inputs.AST.getTokens(), Inputs.Cursor);
98 auto Expansion = Inputs.AST.getTokens().expansionStartingAt(T);
101 this->MacroName = T->text(Inputs.AST.getSourceManager());
102 this->Expansion = *Expansion;
106 Expected<Tweak::Effect> ExpandMacro::apply(
const Selection &Inputs) {
107 auto &SM = Inputs.AST.getASTContext().getSourceManager();
109 std::string Replacement;
110 for (
const syntax::Token &T : Expansion.Expanded) {
111 Replacement += T.text(SM);
114 if (!Replacement.empty()) {
115 assert(Replacement.back() ==
' ');
116 Replacement.pop_back();
119 CharSourceRange MacroRange =
120 CharSourceRange::getCharRange(Expansion.Spelled.front().location(),
121 Expansion.Spelled.back().endLocation());
124 E.ApplyEdit.emplace();
126 E.ApplyEdit->add(tooling::Replacement(SM, MacroRange, Replacement)));
130 std::string ExpandMacro::title()
const {
131 return llvm::formatv(
"Expand macro '{0}'", MacroName);
#define REGISTER_TWEAK(Subclass)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//