[LLD] [COFF] Handle undefined weak symbols in LTO (#70430)
[llvm-project.git] / clang-tools-extra / clangd / refactor / tweaks / DumpAST.cpp
blobe126e72ef253280720919f46b870628820104b66
1 //===--- DumpAST.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // Defines a few tweaks that expose AST and related information.
9 // Some of these are fairly clang-specific and hidden (e.g. textual AST dumps).
10 // Others are more generally useful (class layout) and are exposed by default.
11 //===----------------------------------------------------------------------===//
12 #include "XRefs.h"
13 #include "refactor/Tweak.h"
14 #include "clang/AST/ASTTypeTraits.h"
15 #include "clang/AST/Type.h"
16 #include "llvm/Support/FormatVariadic.h"
17 #include "llvm/Support/ScopedPrinter.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include <optional>
21 namespace clang {
22 namespace clangd {
23 namespace {
25 /// Dumps the AST of the selected node.
26 /// Input:
27 /// fcall("foo");
28 /// ^^^^^
29 /// Message:
30 /// CallExpr
31 /// |-DeclRefExpr fcall
32 /// `-StringLiteral "foo"
33 class DumpAST : public Tweak {
34 public:
35 const char *id() const final;
37 bool prepare(const Selection &Inputs) override {
38 for (auto *N = Inputs.ASTSelection.commonAncestor(); N && !Node;
39 N = N->Parent)
40 if (dumpable(N->ASTNode))
41 Node = N->ASTNode;
42 return Node.has_value();
44 Expected<Effect> apply(const Selection &Inputs) override;
45 std::string title() const override {
46 return std::string(
47 llvm::formatv("Dump {0} AST", Node->getNodeKind().asStringRef()));
49 llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
50 bool hidden() const override { return true; }
52 private:
53 static bool dumpable(const DynTypedNode &N) {
54 // Sadly not all node types can be dumped, and there's no API to check.
55 // See DynTypedNode::dump().
56 return N.get<Decl>() || N.get<Stmt>() || N.get<Type>();
59 std::optional<DynTypedNode> Node;
61 REGISTER_TWEAK(DumpAST)
63 llvm::Expected<Tweak::Effect> DumpAST::apply(const Selection &Inputs) {
64 std::string Str;
65 llvm::raw_string_ostream OS(Str);
66 Node->dump(OS, Inputs.AST->getASTContext());
67 return Effect::showMessage(std::move(OS.str()));
70 /// Dumps the SelectionTree.
71 /// Input:
72 /// int fcall(int);
73 /// void foo() {
74 /// fcall(2 + 2);
75 /// ^^^^^
76 /// }
77 /// Message:
78 /// TranslationUnitDecl
79 /// FunctionDecl void foo()
80 /// CompoundStmt {}
81 /// .CallExpr fcall(2 + 2)
82 /// ImplicitCastExpr fcall
83 /// .DeclRefExpr fcall
84 /// BinaryOperator 2 + 2
85 /// *IntegerLiteral 2
86 class ShowSelectionTree : public Tweak {
87 public:
88 const char *id() const final;
90 bool prepare(const Selection &Inputs) override { return true; }
91 Expected<Effect> apply(const Selection &Inputs) override {
92 return Effect::showMessage(llvm::to_string(Inputs.ASTSelection));
94 std::string title() const override { return "Show selection tree"; }
95 llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
96 bool hidden() const override { return true; }
98 REGISTER_TWEAK(ShowSelectionTree)
100 /// Dumps the symbol under the cursor.
101 /// Inputs:
102 /// void foo();
103 /// ^^^
104 /// Message:
105 /// foo -
106 /// {"containerName":null,"id":"CA2EBE44A1D76D2A","name":"foo","usr":"c:@F@foo#"}
107 class DumpSymbol : public Tweak {
108 const char *id() const final;
109 bool prepare(const Selection &Inputs) override { return true; }
110 Expected<Effect> apply(const Selection &Inputs) override {
111 std::string Storage;
112 llvm::raw_string_ostream Out(Storage);
114 for (auto &Sym : getSymbolInfo(
115 *Inputs.AST, sourceLocToPosition(Inputs.AST->getSourceManager(),
116 Inputs.Cursor)))
117 Out << Sym;
118 return Effect::showMessage(Out.str());
120 std::string title() const override { return "Dump symbol under the cursor"; }
121 llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
122 bool hidden() const override { return true; }
124 REGISTER_TWEAK(DumpSymbol)
126 /// Shows the layout of the RecordDecl under the cursor.
127 /// Input:
128 /// struct X { int foo; };
129 /// ^^^^^^^^
130 /// Message:
131 /// 0 | struct S
132 /// 0 | int foo
133 /// | [sizeof=4, dsize=4, align=4,
134 /// | nvsize=4, nvalign=4]
135 class DumpRecordLayout : public Tweak {
136 public:
137 const char *id() const final;
139 bool prepare(const Selection &Inputs) override {
140 if (auto *Node = Inputs.ASTSelection.commonAncestor())
141 if (auto *D = Node->ASTNode.get<Decl>())
142 Record = dyn_cast<RecordDecl>(D);
143 return Record && Record->isThisDeclarationADefinition() &&
144 !Record->isDependentType();
146 Expected<Effect> apply(const Selection &Inputs) override {
147 std::string Str;
148 llvm::raw_string_ostream OS(Str);
149 Inputs.AST->getASTContext().DumpRecordLayout(Record, OS);
150 return Effect::showMessage(std::move(OS.str()));
152 std::string title() const override {
153 return std::string(llvm::formatv(
154 "Show {0} layout",
155 TypeWithKeyword::getTagTypeKindName(Record->getTagKind())));
157 llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
158 // FIXME: this is interesting to most users. However:
159 // - triggering is too broad (e.g. triggers on comments within a class)
160 // - showMessage has inconsistent UX (e.g. newlines are stripped in VSCode)
161 // - the output itself is a bit hard to decipher.
162 bool hidden() const override { return true; }
164 private:
165 const RecordDecl *Record = nullptr;
167 REGISTER_TWEAK(DumpRecordLayout)
169 } // namespace
170 } // namespace clangd
171 } // namespace clang