Stephen Kelly | d8744a7 | 2018-12-05 21:12:39 +0000 | [diff] [blame] | 1 | //===--- TextNodeDumper.cpp - Printing of AST nodes -----------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file implements AST dumping of components of individual AST nodes. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "clang/AST/TextNodeDumper.h" |
| 15 | |
| 16 | using namespace clang; |
| 17 | |
| 18 | TextNodeDumper::TextNodeDumper(raw_ostream &OS, bool ShowColors, |
| 19 | const SourceManager *SM, |
Stephen Kelly | e26a88a | 2018-12-09 13:30:17 +0000 | [diff] [blame] | 20 | const PrintingPolicy &PrintPolicy, |
| 21 | const comments::CommandTraits *Traits) |
| 22 | : OS(OS), ShowColors(ShowColors), SM(SM), PrintPolicy(PrintPolicy), |
| 23 | Traits(Traits) {} |
| 24 | |
| 25 | void TextNodeDumper::Visit(const comments::Comment *C, |
| 26 | const comments::FullComment *FC) { |
| 27 | if (!C) { |
| 28 | ColorScope Color(OS, ShowColors, NullColor); |
| 29 | OS << "<<<NULL>>>"; |
| 30 | return; |
| 31 | } |
| 32 | |
| 33 | { |
| 34 | ColorScope Color(OS, ShowColors, CommentColor); |
| 35 | OS << C->getCommentKindName(); |
| 36 | } |
| 37 | dumpPointer(C); |
| 38 | dumpSourceRange(C->getSourceRange()); |
| 39 | |
| 40 | ConstCommentVisitor<TextNodeDumper, void, |
| 41 | const comments::FullComment *>::visit(C, FC); |
| 42 | } |
Stephen Kelly | d8744a7 | 2018-12-05 21:12:39 +0000 | [diff] [blame] | 43 | |
| 44 | void TextNodeDumper::dumpPointer(const void *Ptr) { |
| 45 | ColorScope Color(OS, ShowColors, AddressColor); |
| 46 | OS << ' ' << Ptr; |
| 47 | } |
| 48 | |
| 49 | void TextNodeDumper::dumpLocation(SourceLocation Loc) { |
| 50 | if (!SM) |
| 51 | return; |
| 52 | |
| 53 | ColorScope Color(OS, ShowColors, LocationColor); |
| 54 | SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); |
| 55 | |
| 56 | // The general format we print out is filename:line:col, but we drop pieces |
| 57 | // that haven't changed since the last loc printed. |
| 58 | PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); |
| 59 | |
| 60 | if (PLoc.isInvalid()) { |
| 61 | OS << "<invalid sloc>"; |
| 62 | return; |
| 63 | } |
| 64 | |
| 65 | if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { |
| 66 | OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' |
| 67 | << PLoc.getColumn(); |
| 68 | LastLocFilename = PLoc.getFilename(); |
| 69 | LastLocLine = PLoc.getLine(); |
| 70 | } else if (PLoc.getLine() != LastLocLine) { |
| 71 | OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); |
| 72 | LastLocLine = PLoc.getLine(); |
| 73 | } else { |
| 74 | OS << "col" << ':' << PLoc.getColumn(); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | void TextNodeDumper::dumpSourceRange(SourceRange R) { |
| 79 | // Can't translate locations if a SourceManager isn't available. |
| 80 | if (!SM) |
| 81 | return; |
| 82 | |
| 83 | OS << " <"; |
| 84 | dumpLocation(R.getBegin()); |
| 85 | if (R.getBegin() != R.getEnd()) { |
| 86 | OS << ", "; |
| 87 | dumpLocation(R.getEnd()); |
| 88 | } |
| 89 | OS << ">"; |
| 90 | |
| 91 | // <t2.c:123:421[blah], t2.c:412:321> |
| 92 | } |
| 93 | |
| 94 | void TextNodeDumper::dumpBareType(QualType T, bool Desugar) { |
| 95 | ColorScope Color(OS, ShowColors, TypeColor); |
| 96 | |
| 97 | SplitQualType T_split = T.split(); |
| 98 | OS << "'" << QualType::getAsString(T_split, PrintPolicy) << "'"; |
| 99 | |
| 100 | if (Desugar && !T.isNull()) { |
| 101 | // If the type is sugared, also dump a (shallow) desugared type. |
| 102 | SplitQualType D_split = T.getSplitDesugaredType(); |
| 103 | if (T_split != D_split) |
| 104 | OS << ":'" << QualType::getAsString(D_split, PrintPolicy) << "'"; |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | void TextNodeDumper::dumpType(QualType T) { |
| 109 | OS << ' '; |
| 110 | dumpBareType(T); |
| 111 | } |
| 112 | |
| 113 | void TextNodeDumper::dumpBareDeclRef(const Decl *D) { |
| 114 | if (!D) { |
| 115 | ColorScope Color(OS, ShowColors, NullColor); |
| 116 | OS << "<<<NULL>>>"; |
| 117 | return; |
| 118 | } |
| 119 | |
| 120 | { |
| 121 | ColorScope Color(OS, ShowColors, DeclKindNameColor); |
| 122 | OS << D->getDeclKindName(); |
| 123 | } |
| 124 | dumpPointer(D); |
| 125 | |
| 126 | if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { |
| 127 | ColorScope Color(OS, ShowColors, DeclNameColor); |
| 128 | OS << " '" << ND->getDeclName() << '\''; |
| 129 | } |
| 130 | |
| 131 | if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) |
| 132 | dumpType(VD->getType()); |
| 133 | } |
| 134 | |
| 135 | void TextNodeDumper::dumpName(const NamedDecl *ND) { |
| 136 | if (ND->getDeclName()) { |
| 137 | ColorScope Color(OS, ShowColors, DeclNameColor); |
| 138 | OS << ' ' << ND->getNameAsString(); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) { |
| 143 | switch (AS) { |
| 144 | case AS_none: |
| 145 | break; |
| 146 | case AS_public: |
| 147 | OS << "public"; |
| 148 | break; |
| 149 | case AS_protected: |
| 150 | OS << "protected"; |
| 151 | break; |
| 152 | case AS_private: |
| 153 | OS << "private"; |
| 154 | break; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | void TextNodeDumper::dumpCXXTemporary(const CXXTemporary *Temporary) { |
| 159 | OS << "(CXXTemporary"; |
| 160 | dumpPointer(Temporary); |
| 161 | OS << ")"; |
| 162 | } |
Stephen Kelly | e26a88a | 2018-12-09 13:30:17 +0000 | [diff] [blame] | 163 | |
| 164 | const char *TextNodeDumper::getCommandName(unsigned CommandID) { |
| 165 | if (Traits) |
| 166 | return Traits->getCommandInfo(CommandID)->Name; |
| 167 | const comments::CommandInfo *Info = |
| 168 | comments::CommandTraits::getBuiltinCommandInfo(CommandID); |
| 169 | if (Info) |
| 170 | return Info->Name; |
| 171 | return "<not a builtin command>"; |
| 172 | } |
| 173 | |
| 174 | void TextNodeDumper::visitTextComment(const comments::TextComment *C, |
| 175 | const comments::FullComment *) { |
| 176 | OS << " Text=\"" << C->getText() << "\""; |
| 177 | } |
| 178 | |
| 179 | void TextNodeDumper::visitInlineCommandComment( |
| 180 | const comments::InlineCommandComment *C, const comments::FullComment *) { |
| 181 | OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; |
| 182 | switch (C->getRenderKind()) { |
| 183 | case comments::InlineCommandComment::RenderNormal: |
| 184 | OS << " RenderNormal"; |
| 185 | break; |
| 186 | case comments::InlineCommandComment::RenderBold: |
| 187 | OS << " RenderBold"; |
| 188 | break; |
| 189 | case comments::InlineCommandComment::RenderMonospaced: |
| 190 | OS << " RenderMonospaced"; |
| 191 | break; |
| 192 | case comments::InlineCommandComment::RenderEmphasized: |
| 193 | OS << " RenderEmphasized"; |
| 194 | break; |
| 195 | } |
| 196 | |
| 197 | for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) |
| 198 | OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; |
| 199 | } |
| 200 | |
| 201 | void TextNodeDumper::visitHTMLStartTagComment( |
| 202 | const comments::HTMLStartTagComment *C, const comments::FullComment *) { |
| 203 | OS << " Name=\"" << C->getTagName() << "\""; |
| 204 | if (C->getNumAttrs() != 0) { |
| 205 | OS << " Attrs: "; |
| 206 | for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) { |
| 207 | const comments::HTMLStartTagComment::Attribute &Attr = C->getAttr(i); |
| 208 | OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\""; |
| 209 | } |
| 210 | } |
| 211 | if (C->isSelfClosing()) |
| 212 | OS << " SelfClosing"; |
| 213 | } |
| 214 | |
| 215 | void TextNodeDumper::visitHTMLEndTagComment( |
| 216 | const comments::HTMLEndTagComment *C, const comments::FullComment *) { |
| 217 | OS << " Name=\"" << C->getTagName() << "\""; |
| 218 | } |
| 219 | |
| 220 | void TextNodeDumper::visitBlockCommandComment( |
| 221 | const comments::BlockCommandComment *C, const comments::FullComment *) { |
| 222 | OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; |
| 223 | for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) |
| 224 | OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; |
| 225 | } |
| 226 | |
| 227 | void TextNodeDumper::visitParamCommandComment( |
| 228 | const comments::ParamCommandComment *C, const comments::FullComment *FC) { |
| 229 | OS << " " |
| 230 | << comments::ParamCommandComment::getDirectionAsString(C->getDirection()); |
| 231 | |
| 232 | if (C->isDirectionExplicit()) |
| 233 | OS << " explicitly"; |
| 234 | else |
| 235 | OS << " implicitly"; |
| 236 | |
| 237 | if (C->hasParamName()) { |
| 238 | if (C->isParamIndexValid()) |
| 239 | OS << " Param=\"" << C->getParamName(FC) << "\""; |
| 240 | else |
| 241 | OS << " Param=\"" << C->getParamNameAsWritten() << "\""; |
| 242 | } |
| 243 | |
| 244 | if (C->isParamIndexValid() && !C->isVarArgParam()) |
| 245 | OS << " ParamIndex=" << C->getParamIndex(); |
| 246 | } |
| 247 | |
| 248 | void TextNodeDumper::visitTParamCommandComment( |
| 249 | const comments::TParamCommandComment *C, const comments::FullComment *FC) { |
| 250 | if (C->hasParamName()) { |
| 251 | if (C->isPositionValid()) |
| 252 | OS << " Param=\"" << C->getParamName(FC) << "\""; |
| 253 | else |
| 254 | OS << " Param=\"" << C->getParamNameAsWritten() << "\""; |
| 255 | } |
| 256 | |
| 257 | if (C->isPositionValid()) { |
| 258 | OS << " Position=<"; |
| 259 | for (unsigned i = 0, e = C->getDepth(); i != e; ++i) { |
| 260 | OS << C->getIndex(i); |
| 261 | if (i != e - 1) |
| 262 | OS << ", "; |
| 263 | } |
| 264 | OS << ">"; |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | void TextNodeDumper::visitVerbatimBlockComment( |
| 269 | const comments::VerbatimBlockComment *C, const comments::FullComment *) { |
| 270 | OS << " Name=\"" << getCommandName(C->getCommandID()) |
| 271 | << "\"" |
| 272 | " CloseName=\"" |
| 273 | << C->getCloseName() << "\""; |
| 274 | } |
| 275 | |
| 276 | void TextNodeDumper::visitVerbatimBlockLineComment( |
| 277 | const comments::VerbatimBlockLineComment *C, |
| 278 | const comments::FullComment *) { |
| 279 | OS << " Text=\"" << C->getText() << "\""; |
| 280 | } |
| 281 | |
| 282 | void TextNodeDumper::visitVerbatimLineComment( |
| 283 | const comments::VerbatimLineComment *C, const comments::FullComment *) { |
| 284 | OS << " Text=\"" << C->getText() << "\""; |
| 285 | } |