#include "XRefs.h"
#include "refactor/Tweak.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Type.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
namespace clang {
namespace clangd {
namespace {
class DumpAST : public Tweak {
public:
const char *id() const final;
bool prepare(const Selection &Inputs) override {
for (auto *N = Inputs.ASTSelection.commonAncestor(); N && !Node;
N = N->Parent)
if (dumpable(N->ASTNode))
Node = N->ASTNode;
return Node.has_value();
}
Expected<Effect> apply(const Selection &Inputs) override;
std::string title() const override {
return std::string(
llvm::formatv("Dump {0} AST", Node->getNodeKind().asStringRef()));
}
llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
bool hidden() const override { return true; }
private:
static bool dumpable(const DynTypedNode &N) {
return N.get<Decl>() || N.get<Stmt>() || N.get<Type>();
}
std::optional<DynTypedNode> Node;
};
REGISTER_TWEAK(DumpAST)
llvm::Expected<Tweak::Effect> DumpAST::apply(const Selection &Inputs) {
std::string Str;
llvm::raw_string_ostream OS(Str);
Node->dump(OS, Inputs.AST->getASTContext());
return Effect::showMessage(std::move(OS.str()));
}
class ShowSelectionTree : public Tweak {
public:
const char *id() const final;
bool prepare(const Selection &Inputs) override { return true; }
Expected<Effect> apply(const Selection &Inputs) override {
return Effect::showMessage(llvm::to_string(Inputs.ASTSelection));
}
std::string title() const override { return "Show selection tree"; }
llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
bool hidden() const override { return true; }
};
REGISTER_TWEAK(ShowSelectionTree)
class DumpSymbol : public Tweak {
const char *id() const final;
bool prepare(const Selection &Inputs) override { return true; }
Expected<Effect> apply(const Selection &Inputs) override {
std::string Storage;
llvm::raw_string_ostream Out(Storage);
for (auto &Sym : getSymbolInfo(
*Inputs.AST, sourceLocToPosition(Inputs.AST->getSourceManager(),
Inputs.Cursor)))
Out << Sym;
return Effect::showMessage(Out.str());
}
std::string title() const override { return "Dump symbol under the cursor"; }
llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
bool hidden() const override { return true; }
};
REGISTER_TWEAK(DumpSymbol)
class DumpRecordLayout : public Tweak {
public:
const char *id() const final;
bool prepare(const Selection &Inputs) override {
if (auto *Node = Inputs.ASTSelection.commonAncestor())
if (auto *D = Node->ASTNode.get<Decl>())
Record = dyn_cast<RecordDecl>(D);
return Record && Record->isThisDeclarationADefinition() &&
!Record->isDependentType();
}
Expected<Effect> apply(const Selection &Inputs) override {
std::string Str;
llvm::raw_string_ostream OS(Str);
Inputs.AST->getASTContext().DumpRecordLayout(Record, OS);
return Effect::showMessage(std::move(OS.str()));
}
std::string title() const override {
return std::string(llvm::formatv(
"Show {0} layout",
TypeWithKeyword::getTagTypeKindName(Record->getTagKind())));
}
llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
bool hidden() const override { return true; }
private:
const RecordDecl *Record = nullptr;
};
REGISTER_TWEAK(DumpRecordLayout)
}
}
}