clang-tools  9.0.0
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 "refactor/Tweak.h"
13 #include "clang/AST/ASTTypeTraits.h"
14 #include "clang/AST/Type.h"
15 #include "llvm/Support/FormatVariadic.h"
16 #include "llvm/Support/ScopedPrinter.h"
17 #include "llvm/Support/raw_ostream.h"
18 
19 namespace clang {
20 namespace clangd {
21 namespace {
22 
23 /// Dumps the AST of the selected node.
24 /// Input:
25 /// fcall("foo");
26 /// ^^^^^
27 /// Message:
28 /// CallExpr
29 /// |-DeclRefExpr fcall
30 /// `-StringLiteral "foo"
31 class DumpAST : public Tweak {
32 public:
33  const char *id() const override final;
34 
35  bool prepare(const Selection &Inputs) override {
36  for (auto N = Inputs.ASTSelection.commonAncestor(); N && !Node;
37  N = N->Parent)
38  if (dumpable(N->ASTNode))
39  Node = N->ASTNode;
40  return Node.hasValue();
41  }
42  Expected<Effect> apply(const Selection &Inputs) override;
43  std::string title() const override {
44  return llvm::formatv("Dump {0} AST", Node->getNodeKind().asStringRef());
45  }
46  Intent intent() const override { return Info; }
47  bool hidden() const override { return true; }
48 
49 private:
50  static bool dumpable(const ast_type_traits::DynTypedNode &N) {
51  // Sadly not all node types can be dumped, and there's no API to check.
52  // See DynTypedNode::dump().
53  return N.get<Decl>() || N.get<Stmt>() || N.get<Type>();
54  }
55 
56  llvm::Optional<ast_type_traits::DynTypedNode> Node;
57 };
58 REGISTER_TWEAK(DumpAST)
59 
60 llvm::Expected<Tweak::Effect> DumpAST::apply(const Selection &Inputs) {
61  std::string Str;
62  llvm::raw_string_ostream OS(Str);
63  Node->dump(OS, Inputs.AST.getASTContext().getSourceManager());
64  return Effect::showMessage(std::move(OS.str()));
65 }
66 
67 /// Dumps the SelectionTree.
68 /// Input:
69 /// int fcall(int);
70 /// void foo() {
71 /// fcall(2 + 2);
72 /// ^^^^^
73 /// }
74 /// Message:
75 /// TranslationUnitDecl
76 /// FunctionDecl void foo()
77 /// CompoundStmt {}
78 /// .CallExpr fcall(2 + 2)
79 /// ImplicitCastExpr fcall
80 /// .DeclRefExpr fcall
81 /// BinaryOperator 2 + 2
82 /// *IntegerLiteral 2
83 class ShowSelectionTree : public Tweak {
84 public:
85  const char *id() const override final;
86 
87  bool prepare(const Selection &Inputs) override {
88  return Inputs.ASTSelection.root() != nullptr;
89  }
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  Intent intent() const override { return Info; }
95  bool hidden() const override { return true; }
96 };
97 REGISTER_TWEAK(ShowSelectionTree)
98 
99 /// Shows the layout of the RecordDecl under the cursor.
100 /// Input:
101 /// struct X { int foo; };
102 /// ^^^^^^^^
103 /// Message:
104 /// 0 | struct S
105 /// 0 | int foo
106 /// | [sizeof=4, dsize=4, align=4,
107 /// | nvsize=4, nvalign=4]
108 class DumpRecordLayout : public Tweak {
109 public:
110  const char *id() const override final;
111 
112  bool prepare(const Selection &Inputs) override {
113  if (auto *Node = Inputs.ASTSelection.commonAncestor())
114  if (auto *D = Node->ASTNode.get<Decl>())
115  Record = dyn_cast<RecordDecl>(D);
116  return Record && Record->isThisDeclarationADefinition() &&
117  !Record->isDependentType();
118  }
119  Expected<Effect> apply(const Selection &Inputs) override {
120  std::string Str;
121  llvm::raw_string_ostream OS(Str);
122  Inputs.AST.getASTContext().DumpRecordLayout(Record, OS);
123  return Effect::showMessage(std::move(OS.str()));
124  }
125  std::string title() const override {
126  return llvm::formatv(
127  "Show {0} layout",
128  TypeWithKeyword::getTagTypeKindName(Record->getTagKind()));
129  }
130  Intent intent() const override { return Info; }
131  // FIXME: this is interesting to most users. However:
132  // - triggering is too broad (e.g. triggers on comments within a class)
133  // - showMessage has inconsistent UX (e.g. newlines are stripped in VSCode)
134  // - the output itself is a bit hard to decipher.
135  bool hidden() const override { return true; }
136 
137 private:
138  const RecordDecl *Record = nullptr;
139 };
140 REGISTER_TWEAK(DumpRecordLayout)
141 
142 } // namespace
143 } // namespace clangd
144 } // namespace clang
llvm::SmallVector< uint64_t, 1024 > Record
#define REGISTER_TWEAK(Subclass)
Definition: Tweak.h:113
const Decl * D
Definition: XRefs.cpp:868
An information message.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
NodeType Type