Index: cfe/trunk/include/clang/AST/ASTDumperUtils.h =================================================================== --- cfe/trunk/include/clang/AST/ASTDumperUtils.h +++ cfe/trunk/include/clang/AST/ASTDumperUtils.h @@ -0,0 +1,181 @@ +//===--- ASTDumperUtils.h - Printing of AST nodes -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements AST utilities for traversal down the tree. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTDUMPERUTILS_H +#define LLVM_CLANG_AST_ASTDUMPERUTILS_H + +#include "clang/AST/ASTContext.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +// Colors used for various parts of the AST dump +// Do not use bold yellow for any text. It is hard to read on white screens. + +struct TerminalColor { + raw_ostream::Colors Color; + bool Bold; +}; + +// Red - CastColor +// Green - TypeColor +// Bold Green - DeclKindNameColor, UndeserializedColor +// Yellow - AddressColor, LocationColor +// Blue - CommentColor, NullColor, IndentColor +// Bold Blue - AttrColor +// Bold Magenta - StmtColor +// Cyan - ValueKindColor, ObjectKindColor +// Bold Cyan - ValueColor, DeclNameColor + +// Decl kind names (VarDecl, FunctionDecl, etc) +static const TerminalColor DeclKindNameColor = {raw_ostream::GREEN, true}; +// Attr names (CleanupAttr, GuardedByAttr, etc) +static const TerminalColor AttrColor = {raw_ostream::BLUE, true}; +// Statement names (DeclStmt, ImplicitCastExpr, etc) +static const TerminalColor StmtColor = {raw_ostream::MAGENTA, true}; +// Comment names (FullComment, ParagraphComment, TextComment, etc) +static const TerminalColor CommentColor = {raw_ostream::BLUE, false}; + +// Type names (int, float, etc, plus user defined types) +static const TerminalColor TypeColor = {raw_ostream::GREEN, false}; + +// Pointer address +static const TerminalColor AddressColor = {raw_ostream::YELLOW, false}; +// Source locations +static const TerminalColor LocationColor = {raw_ostream::YELLOW, false}; + +// lvalue/xvalue +static const TerminalColor ValueKindColor = {raw_ostream::CYAN, false}; +// bitfield/objcproperty/objcsubscript/vectorcomponent +static const TerminalColor ObjectKindColor = {raw_ostream::CYAN, false}; + +// Null statements +static const TerminalColor NullColor = {raw_ostream::BLUE, false}; + +// Undeserialized entities +static const TerminalColor UndeserializedColor = {raw_ostream::GREEN, true}; + +// CastKind from CastExpr's +static const TerminalColor CastColor = {raw_ostream::RED, false}; + +// Value of the statement +static const TerminalColor ValueColor = {raw_ostream::CYAN, true}; +// Decl names +static const TerminalColor DeclNameColor = {raw_ostream::CYAN, true}; + +// Indents ( `, -. | ) +static const TerminalColor IndentColor = {raw_ostream::BLUE, false}; + +class ColorScope { + raw_ostream &OS; + const bool ShowColors; + +public: + ColorScope(raw_ostream &OS, bool ShowColors, TerminalColor Color) + : OS(OS), ShowColors(ShowColors) { + if (ShowColors) + OS.changeColor(Color.Color, Color.Bold); + } + ~ColorScope() { + if (ShowColors) + OS.resetColor(); + } +}; + +class TextTreeStructure { + raw_ostream &OS; + const bool ShowColors; + + /// Pending[i] is an action to dump an entity at level i. + llvm::SmallVector, 32> Pending; + + /// Indicates whether we're at the top level. + bool TopLevel = true; + + /// Indicates if we're handling the first child after entering a new depth. + bool FirstChild = true; + + /// Prefix for currently-being-dumped entity. + std::string Prefix; + +public: + /// Add a child of the current node. Calls doAddChild without arguments + template void addChild(Fn doAddChild) { + // If we're at the top level, there's nothing interesting to do; just + // run the dumper. + if (TopLevel) { + TopLevel = false; + doAddChild(); + while (!Pending.empty()) { + Pending.back()(true); + Pending.pop_back(); + } + Prefix.clear(); + OS << "\n"; + TopLevel = true; + return; + } + + auto dumpWithIndent = [this, doAddChild](bool isLastChild) { + // Print out the appropriate tree structure and work out the prefix for + // children of this node. For instance: + // + // A Prefix = "" + // |-B Prefix = "| " + // | `-C Prefix = "| " + // `-D Prefix = " " + // |-E Prefix = " | " + // `-F Prefix = " " + // G Prefix = "" + // + // Note that the first level gets no prefix. + { + OS << '\n'; + ColorScope Color(OS, ShowColors, IndentColor); + OS << Prefix << (isLastChild ? '`' : '|') << '-'; + this->Prefix.push_back(isLastChild ? ' ' : '|'); + this->Prefix.push_back(' '); + } + + FirstChild = true; + unsigned Depth = Pending.size(); + + doAddChild(); + + // If any children are left, they're the last at their nesting level. + // Dump those ones out now. + while (Depth < Pending.size()) { + Pending.back()(true); + this->Pending.pop_back(); + } + + // Restore the old prefix. + this->Prefix.resize(Prefix.size() - 2); + }; + + if (FirstChild) { + Pending.push_back(std::move(dumpWithIndent)); + } else { + Pending.back()(false); + Pending.back() = std::move(dumpWithIndent); + } + FirstChild = false; + } + + TextTreeStructure(raw_ostream &OS, bool ShowColors) + : OS(OS), ShowColors(ShowColors) {} +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTDUMPERUTILS_H Index: cfe/trunk/lib/AST/ASTDumper.cpp =================================================================== --- cfe/trunk/lib/AST/ASTDumper.cpp +++ cfe/trunk/lib/AST/ASTDumper.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDumperUtils.h" #include "clang/AST/Attr.h" #include "clang/AST/CommentVisitor.h" #include "clang/AST/DeclCXX.h" @@ -35,78 +36,6 @@ //===----------------------------------------------------------------------===// namespace { - // Colors used for various parts of the AST dump - // Do not use bold yellow for any text. It is hard to read on white screens. - - struct TerminalColor { - raw_ostream::Colors Color; - bool Bold; - }; - - // Red - CastColor - // Green - TypeColor - // Bold Green - DeclKindNameColor, UndeserializedColor - // Yellow - AddressColor, LocationColor - // Blue - CommentColor, NullColor, IndentColor - // Bold Blue - AttrColor - // Bold Magenta - StmtColor - // Cyan - ValueKindColor, ObjectKindColor - // Bold Cyan - ValueColor, DeclNameColor - - // Decl kind names (VarDecl, FunctionDecl, etc) - static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true }; - // Attr names (CleanupAttr, GuardedByAttr, etc) - static const TerminalColor AttrColor = { raw_ostream::BLUE, true }; - // Statement names (DeclStmt, ImplicitCastExpr, etc) - static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true }; - // Comment names (FullComment, ParagraphComment, TextComment, etc) - static const TerminalColor CommentColor = { raw_ostream::BLUE, false }; - - // Type names (int, float, etc, plus user defined types) - static const TerminalColor TypeColor = { raw_ostream::GREEN, false }; - - // Pointer address - static const TerminalColor AddressColor = { raw_ostream::YELLOW, false }; - // Source locations - static const TerminalColor LocationColor = { raw_ostream::YELLOW, false }; - - // lvalue/xvalue - static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false }; - // bitfield/objcproperty/objcsubscript/vectorcomponent - static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false }; - - // Null statements - static const TerminalColor NullColor = { raw_ostream::BLUE, false }; - - // Undeserialized entities - static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true }; - - // CastKind from CastExpr's - static const TerminalColor CastColor = { raw_ostream::RED, false }; - - // Value of the statement - static const TerminalColor ValueColor = { raw_ostream::CYAN, true }; - // Decl names - static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true }; - - // Indents ( `, -. | ) - static const TerminalColor IndentColor = { raw_ostream::BLUE, false }; - - class ColorScope { - raw_ostream &OS; - const bool ShowColors; - - public: - ColorScope(raw_ostream &OS, bool ShowColors, TerminalColor Color) - : OS(OS), ShowColors(ShowColors) { - if (ShowColors) - OS.changeColor(Color.Color, Color.Bold); - } - ~ColorScope() { - if (ShowColors) - OS.resetColor(); - } - }; class ASTDumper : public ConstDeclVisitor, @@ -114,6 +43,8 @@ public ConstCommentVisitor, public TypeVisitor { + TextTreeStructure TreeStructure; + raw_ostream &OS; const CommandTraits *Traits; const SourceManager *SM; @@ -121,22 +52,10 @@ /// The policy to use for printing; can be defaulted. PrintingPolicy PrintPolicy; - /// Pending[i] is an action to dump an entity at level i. - llvm::SmallVector, 32> Pending; - /// Indicates whether we should trigger deserialization of nodes that had /// not already been loaded. bool Deserialize = false; - /// Indicates whether we're at the top level. - bool TopLevel = true; - - /// Indicates if we're handling the first child after entering a new depth. - bool FirstChild = true; - - /// Prefix for currently-being-dumped entity. - std::string Prefix; - /// Keep track of the last location we print out so that we can /// print out deltas from then on out. const char *LastLocFilename = ""; @@ -146,65 +65,7 @@ /// Dump a child of the current node. template void dumpChild(Fn doDumpChild) { - // If we're at the top level, there's nothing interesting to do; just - // run the dumper. - if (TopLevel) { - TopLevel = false; - doDumpChild(); - while (!Pending.empty()) { - Pending.back()(true); - Pending.pop_back(); - } - Prefix.clear(); - OS << "\n"; - TopLevel = true; - return; - } - - auto dumpWithIndent = [this, doDumpChild](bool isLastChild) { - // Print out the appropriate tree structure and work out the prefix for - // children of this node. For instance: - // - // A Prefix = "" - // |-B Prefix = "| " - // | `-C Prefix = "| " - // `-D Prefix = " " - // |-E Prefix = " | " - // `-F Prefix = " " - // G Prefix = "" - // - // Note that the first level gets no prefix. - { - OS << '\n'; - ColorScope Color(OS, ShowColors, IndentColor); - OS << Prefix << (isLastChild ? '`' : '|') << '-'; - this->Prefix.push_back(isLastChild ? ' ' : '|'); - this->Prefix.push_back(' '); - } - - FirstChild = true; - unsigned Depth = Pending.size(); - - doDumpChild(); - - // If any children are left, they're the last at their nesting level. - // Dump those ones out now. - while (Depth < Pending.size()) { - Pending.back()(true); - this->Pending.pop_back(); - } - - // Restore the old prefix. - this->Prefix.resize(Prefix.size() - 2); - }; - - if (FirstChild) { - Pending.push_back(std::move(dumpWithIndent)); - } else { - Pending.back()(false); - Pending.back() = std::move(dumpWithIndent); - } - FirstChild = false; + TreeStructure.addChild(doDumpChild); } public: @@ -219,8 +80,8 @@ ASTDumper(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM, bool ShowColors, const PrintingPolicy &PrintPolicy) - : OS(OS), Traits(Traits), SM(SM), PrintPolicy(PrintPolicy), - ShowColors(ShowColors) {} + : TreeStructure(OS, ShowColors), OS(OS), Traits(Traits), SM(SM), + PrintPolicy(PrintPolicy), ShowColors(ShowColors) {} void setDeserialize(bool D) { Deserialize = D; }