clang-tools  14.0.0git
refactor/tweaks/DumpAST.cpp
Go to the documentation of this file.
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 
20 namespace clang {
21 namespace clangd {
22 namespace {
23 
24 /// Dumps the AST of the selected node.
25 /// Input:
26 /// fcall("foo");
27 /// ^^^^^
28 /// Message:
29 /// CallExpr
30 /// |-DeclRefExpr fcall
31 /// `-StringLiteral "foo"
32 class DumpAST : public Tweak {
33 public:
34  const char *id() const override final;
35 
36  bool prepare(const Selection &Inputs) override {
37  for (auto N = Inputs.ASTSelection.commonAncestor(); N && !Node;
38  N = N->Parent)
39  if (dumpable(N->ASTNode))
40  Node = N->ASTNode;
41  return Node.hasValue();
42  }
43  Expected<Effect> apply(const Selection &Inputs) override;
44  std::string title() const override {
45  return std::string(
46  llvm::formatv("Dump {0} AST", Node->getNodeKind().asStringRef()));
47  }
48  llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
49  bool hidden() const override { return true; }
50 
51 private:
52  static bool dumpable(const DynTypedNode &N) {
53  // Sadly not all node types can be dumped, and there's no API to check.
54  // See DynTypedNode::dump().
55  return N.get<Decl>() || N.get<Stmt>() || N.get<Type>();
56  }
57 
58  llvm::Optional<DynTypedNode> Node;
59 };
60 REGISTER_TWEAK(DumpAST)
61 
62 llvm::Expected<Tweak::Effect> DumpAST::apply(const Selection &Inputs) {
63  std::string Str;
64  llvm::raw_string_ostream OS(Str);
65  Node->dump(OS, Inputs.AST->getASTContext());
66  return Effect::showMessage(std::move(OS.str()));
67 }
68 
69 /// Dumps the SelectionTree.
70 /// Input:
71 /// int fcall(int);
72 /// void foo() {
73 /// fcall(2 + 2);
74 /// ^^^^^
75 /// }
76 /// Message:
77 /// TranslationUnitDecl
78 /// FunctionDecl void foo()
79 /// CompoundStmt {}
80 /// .CallExpr fcall(2 + 2)
81 /// ImplicitCastExpr fcall
82 /// .DeclRefExpr fcall
83 /// BinaryOperator 2 + 2
84 /// *IntegerLiteral 2
85 class ShowSelectionTree : public Tweak {
86 public:
87  const char *id() const override final;
88 
89  bool prepare(const Selection &Inputs) override { return true; }
90  Expected<Effect> apply(const Selection &Inputs) override {
91  return Effect::showMessage(llvm::to_string(Inputs.ASTSelection));
92  }
93  std::string title() const override { return "Show selection tree"; }
94  llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
95  bool hidden() const override { return true; }
96 };
97 REGISTER_TWEAK(ShowSelectionTree)
98 
99 /// Dumps the symbol under the cursor.
100 /// Inputs:
101 /// void foo();
102 /// ^^^
103 /// Message:
104 /// foo -
105 /// {"containerName":null,"id":"CA2EBE44A1D76D2A","name":"foo","usr":"c:@F@foo#"}
106 class DumpSymbol : public Tweak {
107  const char *id() const override final;
108  bool prepare(const Selection &Inputs) override { return true; }
109  Expected<Effect> apply(const Selection &Inputs) override {
110  std::string Storage;
111  llvm::raw_string_ostream Out(Storage);
112 
113  for (auto &Sym : getSymbolInfo(
114  *Inputs.AST, sourceLocToPosition(Inputs.AST->getSourceManager(),
115  Inputs.Cursor)))
116  Out << Sym;
117  return Effect::showMessage(Out.str());
118  }
119  std::string title() const override { return "Dump symbol under the cursor"; }
120  llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
121  bool hidden() const override { return true; }
122 };
123 REGISTER_TWEAK(DumpSymbol)
124 
125 /// Shows the layout of the RecordDecl under the cursor.
126 /// Input:
127 /// struct X { int foo; };
128 /// ^^^^^^^^
129 /// Message:
130 /// 0 | struct S
131 /// 0 | int foo
132 /// | [sizeof=4, dsize=4, align=4,
133 /// | nvsize=4, nvalign=4]
134 class DumpRecordLayout : public Tweak {
135 public:
136  const char *id() const override final;
137 
138  bool prepare(const Selection &Inputs) override {
139  if (auto *Node = Inputs.ASTSelection.commonAncestor())
140  if (auto *D = Node->ASTNode.get<Decl>())
141  Record = dyn_cast<RecordDecl>(D);
142  return Record && Record->isThisDeclarationADefinition() &&
143  !Record->isDependentType();
144  }
145  Expected<Effect> apply(const Selection &Inputs) override {
146  std::string Str;
147  llvm::raw_string_ostream OS(Str);
148  Inputs.AST->getASTContext().DumpRecordLayout(Record, OS);
149  return Effect::showMessage(std::move(OS.str()));
150  }
151  std::string title() const override {
152  return std::string(llvm::formatv(
153  "Show {0} layout",
154  TypeWithKeyword::getTagTypeKindName(Record->getTagKind())));
155  }
156  llvm::StringLiteral kind() const override { return CodeAction::INFO_KIND; }
157  // FIXME: this is interesting to most users. However:
158  // - triggering is too broad (e.g. triggers on comments within a class)
159  // - showMessage has inconsistent UX (e.g. newlines are stripped in VSCode)
160  // - the output itself is a bit hard to decipher.
161  bool hidden() const override { return true; }
162 
163 private:
164  const RecordDecl *Record = nullptr;
165 };
166 REGISTER_TWEAK(DumpRecordLayout)
167 
168 } // namespace
169 } // namespace clangd
170 } // namespace clang
XRefs.h
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::clangd::sourceLocToPosition
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:216
Inputs
ParseInputs Inputs
Definition: TUScheduler.cpp:457
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
Tweak.h
clang::clangd::getSymbolInfo
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:1512
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:163
clang::doc::Record
llvm::SmallVector< uint64_t, 1024 > Record
Definition: BitcodeReader.cpp:18
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:100
clang::clangd::CodeAction::INFO_KIND
const static llvm::StringLiteral INFO_KIND
Definition: Protocol.h:986
REGISTER_TWEAK
#define REGISTER_TWEAK(Subclass)
Definition: Tweak.h:132