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