TypePrinter.cpp revision 218893
1199482Srdivacky//===--- TypePrinter.cpp - Pretty-Print Clang Types -----------------------===//
2199482Srdivacky//
3199482Srdivacky//                     The LLVM Compiler Infrastructure
4199482Srdivacky//
5199482Srdivacky// This file is distributed under the University of Illinois Open Source
6199482Srdivacky// License. See LICENSE.TXT for details.
7199482Srdivacky//
8199482Srdivacky//===----------------------------------------------------------------------===//
9199482Srdivacky//
10199482Srdivacky// This contains code to print types from Clang's type system.
11199482Srdivacky//
12199482Srdivacky//===----------------------------------------------------------------------===//
13199482Srdivacky
14199482Srdivacky#include "clang/AST/Decl.h"
15199482Srdivacky#include "clang/AST/DeclObjC.h"
16199482Srdivacky#include "clang/AST/DeclTemplate.h"
17199482Srdivacky#include "clang/AST/Expr.h"
18199482Srdivacky#include "clang/AST/Type.h"
19199482Srdivacky#include "clang/AST/PrettyPrinter.h"
20199482Srdivacky#include "clang/Basic/LangOptions.h"
21205408Srdivacky#include "clang/Basic/SourceManager.h"
22199482Srdivacky#include "llvm/ADT/StringExtras.h"
23199482Srdivacky#include "llvm/Support/raw_ostream.h"
24199482Srdivackyusing namespace clang;
25199482Srdivacky
26199482Srdivackynamespace {
27199482Srdivacky  class TypePrinter {
28199482Srdivacky    PrintingPolicy Policy;
29199482Srdivacky
30199482Srdivacky  public:
31199482Srdivacky    explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
32207619Srdivacky
33218893Sdim    void print(const Type *ty, Qualifiers qs, std::string &buffer);
34218893Sdim    void print(QualType T, std::string &S);
35204962Srdivacky    void AppendScope(DeclContext *DC, std::string &S);
36218893Sdim    void printTag(TagDecl *T, std::string &S);
37199482Srdivacky#define ABSTRACT_TYPE(CLASS, PARENT)
38199482Srdivacky#define TYPE(CLASS, PARENT) \
39218893Sdim    void print##CLASS(const CLASS##Type *T, std::string &S);
40199482Srdivacky#include "clang/AST/TypeNodes.def"
41199482Srdivacky  };
42199482Srdivacky}
43199482Srdivacky
44199482Srdivackystatic void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
45199482Srdivacky  if (TypeQuals & Qualifiers::Const) {
46199482Srdivacky    if (!S.empty()) S += ' ';
47199482Srdivacky    S += "const";
48199482Srdivacky  }
49199482Srdivacky  if (TypeQuals & Qualifiers::Volatile) {
50199482Srdivacky    if (!S.empty()) S += ' ';
51199482Srdivacky    S += "volatile";
52199482Srdivacky  }
53199482Srdivacky  if (TypeQuals & Qualifiers::Restrict) {
54199482Srdivacky    if (!S.empty()) S += ' ';
55199482Srdivacky    S += "restrict";
56199482Srdivacky  }
57199482Srdivacky}
58199482Srdivacky
59218893Sdimvoid TypePrinter::print(QualType t, std::string &buffer) {
60218893Sdim  SplitQualType split = t.split();
61218893Sdim  print(split.first, split.second, buffer);
62218893Sdim}
63218893Sdim
64218893Sdimvoid TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
65218893Sdim  if (!T) {
66218893Sdim    buffer += "NULL TYPE";
67199482Srdivacky    return;
68199482Srdivacky  }
69199482Srdivacky
70199482Srdivacky  if (Policy.SuppressSpecifiers && T->isSpecifierType())
71199482Srdivacky    return;
72199482Srdivacky
73199482Srdivacky  // Print qualifiers as appropriate.
74218893Sdim
75218893Sdim  // CanPrefixQualifiers - We prefer to print type qualifiers before the type,
76218893Sdim  // so that we get "const int" instead of "int const", but we can't do this if
77218893Sdim  // the type is complex.  For example if the type is "int*", we *must* print
78218893Sdim  // "int * const", printing "const int *" is different.  Only do this when the
79218893Sdim  // type expands to a simple string.
80218893Sdim  bool CanPrefixQualifiers = false;
81218893Sdim
82218893Sdim  Type::TypeClass TC = T->getTypeClass();
83218893Sdim  if (const AutoType *AT = dyn_cast<AutoType>(T))
84218893Sdim    TC = AT->desugar()->getTypeClass();
85218893Sdim  if (const SubstTemplateTypeParmType *Subst
86218893Sdim                                      = dyn_cast<SubstTemplateTypeParmType>(T))
87218893Sdim    TC = Subst->getReplacementType()->getTypeClass();
88218893Sdim
89218893Sdim  switch (TC) {
90218893Sdim    case Type::Builtin:
91218893Sdim    case Type::Complex:
92218893Sdim    case Type::UnresolvedUsing:
93218893Sdim    case Type::Typedef:
94218893Sdim    case Type::TypeOfExpr:
95218893Sdim    case Type::TypeOf:
96218893Sdim    case Type::Decltype:
97218893Sdim    case Type::Record:
98218893Sdim    case Type::Enum:
99218893Sdim    case Type::Elaborated:
100218893Sdim    case Type::TemplateTypeParm:
101218893Sdim    case Type::SubstTemplateTypeParmPack:
102218893Sdim    case Type::TemplateSpecialization:
103218893Sdim    case Type::InjectedClassName:
104218893Sdim    case Type::DependentName:
105218893Sdim    case Type::DependentTemplateSpecialization:
106218893Sdim    case Type::ObjCObject:
107218893Sdim    case Type::ObjCInterface:
108218893Sdim      CanPrefixQualifiers = true;
109218893Sdim      break;
110218893Sdim
111218893Sdim    case Type::ObjCObjectPointer:
112218893Sdim      CanPrefixQualifiers = T->isObjCIdType() || T->isObjCClassType() ||
113218893Sdim        T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType();
114218893Sdim      break;
115218893Sdim
116218893Sdim    case Type::Pointer:
117218893Sdim    case Type::BlockPointer:
118218893Sdim    case Type::LValueReference:
119218893Sdim    case Type::RValueReference:
120218893Sdim    case Type::MemberPointer:
121218893Sdim    case Type::ConstantArray:
122218893Sdim    case Type::IncompleteArray:
123218893Sdim    case Type::VariableArray:
124218893Sdim    case Type::DependentSizedArray:
125218893Sdim    case Type::DependentSizedExtVector:
126218893Sdim    case Type::Vector:
127218893Sdim    case Type::ExtVector:
128218893Sdim    case Type::FunctionProto:
129218893Sdim    case Type::FunctionNoProto:
130218893Sdim    case Type::Paren:
131218893Sdim    case Type::Attributed:
132218893Sdim    case Type::PackExpansion:
133218893Sdim    case Type::SubstTemplateTypeParm:
134218893Sdim    case Type::Auto:
135218893Sdim      CanPrefixQualifiers = false;
136218893Sdim      break;
137218893Sdim  }
138218893Sdim
139218893Sdim  if (!CanPrefixQualifiers && !Quals.empty()) {
140218893Sdim    std::string qualsBuffer;
141218893Sdim    Quals.getAsStringInternal(qualsBuffer, Policy);
142199482Srdivacky
143218893Sdim    if (!buffer.empty()) {
144218893Sdim      qualsBuffer += ' ';
145218893Sdim      qualsBuffer += buffer;
146199482Srdivacky    }
147218893Sdim    std::swap(buffer, qualsBuffer);
148199482Srdivacky  }
149199482Srdivacky
150199482Srdivacky  switch (T->getTypeClass()) {
151199482Srdivacky#define ABSTRACT_TYPE(CLASS, PARENT)
152218893Sdim#define TYPE(CLASS, PARENT) case Type::CLASS: \
153218893Sdim    print##CLASS(cast<CLASS##Type>(T), buffer); \
154199482Srdivacky    break;
155199482Srdivacky#include "clang/AST/TypeNodes.def"
156199482Srdivacky  }
157218893Sdim
158218893Sdim  // If we're adding the qualifiers as a prefix, do it now.
159218893Sdim  if (CanPrefixQualifiers && !Quals.empty()) {
160218893Sdim    std::string qualsBuffer;
161218893Sdim    Quals.getAsStringInternal(qualsBuffer, Policy);
162218893Sdim
163218893Sdim    if (!buffer.empty()) {
164218893Sdim      qualsBuffer += ' ';
165218893Sdim      qualsBuffer += buffer;
166218893Sdim    }
167218893Sdim    std::swap(buffer, qualsBuffer);
168218893Sdim  }
169199482Srdivacky}
170199482Srdivacky
171218893Sdimvoid TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) {
172199482Srdivacky  if (S.empty()) {
173199482Srdivacky    S = T->getName(Policy.LangOpts);
174199482Srdivacky  } else {
175199482Srdivacky    // Prefix the basic type, e.g. 'int X'.
176199482Srdivacky    S = ' ' + S;
177199482Srdivacky    S = T->getName(Policy.LangOpts) + S;
178199482Srdivacky  }
179199482Srdivacky}
180199482Srdivacky
181218893Sdimvoid TypePrinter::printComplex(const ComplexType *T, std::string &S) {
182218893Sdim  print(T->getElementType(), S);
183199482Srdivacky  S = "_Complex " + S;
184199482Srdivacky}
185199482Srdivacky
186218893Sdimvoid TypePrinter::printPointer(const PointerType *T, std::string &S) {
187199482Srdivacky  S = '*' + S;
188199482Srdivacky
189199482Srdivacky  // Handle things like 'int (*A)[4];' correctly.
190199482Srdivacky  // FIXME: this should include vectors, but vectors use attributes I guess.
191199482Srdivacky  if (isa<ArrayType>(T->getPointeeType()))
192199482Srdivacky    S = '(' + S + ')';
193199482Srdivacky
194218893Sdim  print(T->getPointeeType(), S);
195199482Srdivacky}
196199482Srdivacky
197218893Sdimvoid TypePrinter::printBlockPointer(const BlockPointerType *T, std::string &S) {
198199482Srdivacky  S = '^' + S;
199218893Sdim  print(T->getPointeeType(), S);
200199482Srdivacky}
201199482Srdivacky
202218893Sdimvoid TypePrinter::printLValueReference(const LValueReferenceType *T,
203199482Srdivacky                                       std::string &S) {
204199482Srdivacky  S = '&' + S;
205199482Srdivacky
206199482Srdivacky  // Handle things like 'int (&A)[4];' correctly.
207199482Srdivacky  // FIXME: this should include vectors, but vectors use attributes I guess.
208199482Srdivacky  if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
209199482Srdivacky    S = '(' + S + ')';
210199482Srdivacky
211218893Sdim  print(T->getPointeeTypeAsWritten(), S);
212199482Srdivacky}
213199482Srdivacky
214218893Sdimvoid TypePrinter::printRValueReference(const RValueReferenceType *T,
215199482Srdivacky                                       std::string &S) {
216199482Srdivacky  S = "&&" + S;
217199482Srdivacky
218199482Srdivacky  // Handle things like 'int (&&A)[4];' correctly.
219199482Srdivacky  // FIXME: this should include vectors, but vectors use attributes I guess.
220199482Srdivacky  if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
221199482Srdivacky    S = '(' + S + ')';
222199482Srdivacky
223218893Sdim  print(T->getPointeeTypeAsWritten(), S);
224199482Srdivacky}
225199482Srdivacky
226218893Sdimvoid TypePrinter::printMemberPointer(const MemberPointerType *T,
227199482Srdivacky                                     std::string &S) {
228199482Srdivacky  std::string C;
229218893Sdim  print(QualType(T->getClass(), 0), C);
230199482Srdivacky  C += "::*";
231199482Srdivacky  S = C + S;
232199482Srdivacky
233199482Srdivacky  // Handle things like 'int (Cls::*A)[4];' correctly.
234199482Srdivacky  // FIXME: this should include vectors, but vectors use attributes I guess.
235199482Srdivacky  if (isa<ArrayType>(T->getPointeeType()))
236199482Srdivacky    S = '(' + S + ')';
237199482Srdivacky
238218893Sdim  print(T->getPointeeType(), S);
239199482Srdivacky}
240199482Srdivacky
241218893Sdimvoid TypePrinter::printConstantArray(const ConstantArrayType *T,
242199482Srdivacky                                     std::string &S) {
243199482Srdivacky  S += '[';
244199482Srdivacky  S += llvm::utostr(T->getSize().getZExtValue());
245199482Srdivacky  S += ']';
246199482Srdivacky
247218893Sdim  print(T->getElementType(), S);
248199482Srdivacky}
249199482Srdivacky
250218893Sdimvoid TypePrinter::printIncompleteArray(const IncompleteArrayType *T,
251199482Srdivacky                                       std::string &S) {
252199482Srdivacky  S += "[]";
253218893Sdim  print(T->getElementType(), S);
254199482Srdivacky}
255199482Srdivacky
256218893Sdimvoid TypePrinter::printVariableArray(const VariableArrayType *T,
257199482Srdivacky                                     std::string &S) {
258199482Srdivacky  S += '[';
259199482Srdivacky
260199482Srdivacky  if (T->getIndexTypeQualifiers().hasQualifiers()) {
261199482Srdivacky    AppendTypeQualList(S, T->getIndexTypeCVRQualifiers());
262199482Srdivacky    S += ' ';
263199482Srdivacky  }
264199482Srdivacky
265199482Srdivacky  if (T->getSizeModifier() == VariableArrayType::Static)
266199482Srdivacky    S += "static";
267199482Srdivacky  else if (T->getSizeModifier() == VariableArrayType::Star)
268199482Srdivacky    S += '*';
269199482Srdivacky
270199482Srdivacky  if (T->getSizeExpr()) {
271199482Srdivacky    std::string SStr;
272199482Srdivacky    llvm::raw_string_ostream s(SStr);
273199482Srdivacky    T->getSizeExpr()->printPretty(s, 0, Policy);
274199482Srdivacky    S += s.str();
275199482Srdivacky  }
276199482Srdivacky  S += ']';
277199482Srdivacky
278218893Sdim  print(T->getElementType(), S);
279199482Srdivacky}
280199482Srdivacky
281218893Sdimvoid TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T,
282199482Srdivacky                                           std::string &S) {
283199482Srdivacky  S += '[';
284199482Srdivacky
285199482Srdivacky  if (T->getSizeExpr()) {
286199482Srdivacky    std::string SStr;
287199482Srdivacky    llvm::raw_string_ostream s(SStr);
288199482Srdivacky    T->getSizeExpr()->printPretty(s, 0, Policy);
289199482Srdivacky    S += s.str();
290199482Srdivacky  }
291199482Srdivacky  S += ']';
292199482Srdivacky
293218893Sdim  print(T->getElementType(), S);
294199482Srdivacky}
295199482Srdivacky
296218893Sdimvoid TypePrinter::printDependentSizedExtVector(
297199482Srdivacky                                          const DependentSizedExtVectorType *T,
298199482Srdivacky                                               std::string &S) {
299218893Sdim  print(T->getElementType(), S);
300199482Srdivacky
301199482Srdivacky  S += " __attribute__((ext_vector_type(";
302199482Srdivacky  if (T->getSizeExpr()) {
303199482Srdivacky    std::string SStr;
304199482Srdivacky    llvm::raw_string_ostream s(SStr);
305199482Srdivacky    T->getSizeExpr()->printPretty(s, 0, Policy);
306199482Srdivacky    S += s.str();
307199482Srdivacky  }
308199482Srdivacky  S += ")))";
309199482Srdivacky}
310199482Srdivacky
311218893Sdimvoid TypePrinter::printVector(const VectorType *T, std::string &S) {
312218893Sdim  switch (T->getVectorKind()) {
313218893Sdim  case VectorType::AltiVecPixel:
314218893Sdim    S = "__vector __pixel " + S;
315218893Sdim    break;
316218893Sdim  case VectorType::AltiVecBool:
317218893Sdim    print(T->getElementType(), S);
318218893Sdim    S = "__vector __bool " + S;
319218893Sdim    break;
320218893Sdim  case VectorType::AltiVecVector:
321218893Sdim    print(T->getElementType(), S);
322218893Sdim    S = "__vector " + S;
323218893Sdim    break;
324218893Sdim  case VectorType::NeonVector:
325218893Sdim    print(T->getElementType(), S);
326218893Sdim    S = ("__attribute__((neon_vector_type(" +
327218893Sdim         llvm::utostr_32(T->getNumElements()) + "))) " + S);
328218893Sdim    break;
329218893Sdim  case VectorType::NeonPolyVector:
330218893Sdim    print(T->getElementType(), S);
331218893Sdim    S = ("__attribute__((neon_polyvector_type(" +
332218893Sdim         llvm::utostr_32(T->getNumElements()) + "))) " + S);
333218893Sdim    break;
334218893Sdim  case VectorType::GenericVector: {
335203955Srdivacky    // FIXME: We prefer to print the size directly here, but have no way
336203955Srdivacky    // to get the size of the type.
337218893Sdim    print(T->getElementType(), S);
338203955Srdivacky    std::string V = "__attribute__((__vector_size__(";
339203955Srdivacky    V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
340203955Srdivacky    std::string ET;
341218893Sdim    print(T->getElementType(), ET);
342203955Srdivacky    V += " * sizeof(" + ET + ")))) ";
343203955Srdivacky    S = V + S;
344218893Sdim    break;
345203955Srdivacky  }
346218893Sdim  }
347199482Srdivacky}
348199482Srdivacky
349218893Sdimvoid TypePrinter::printExtVector(const ExtVectorType *T, std::string &S) {
350199482Srdivacky  S += " __attribute__((ext_vector_type(";
351199482Srdivacky  S += llvm::utostr_32(T->getNumElements());
352199482Srdivacky  S += ")))";
353218893Sdim  print(T->getElementType(), S);
354199482Srdivacky}
355199482Srdivacky
356218893Sdimvoid TypePrinter::printFunctionProto(const FunctionProtoType *T,
357199482Srdivacky                                     std::string &S) {
358199482Srdivacky  // If needed for precedence reasons, wrap the inner part in grouping parens.
359199482Srdivacky  if (!S.empty())
360199482Srdivacky    S = "(" + S + ")";
361199482Srdivacky
362199482Srdivacky  S += "(";
363199482Srdivacky  std::string Tmp;
364199482Srdivacky  PrintingPolicy ParamPolicy(Policy);
365199482Srdivacky  ParamPolicy.SuppressSpecifiers = false;
366199482Srdivacky  for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
367199482Srdivacky    if (i) S += ", ";
368218893Sdim    print(T->getArgType(i), Tmp);
369199482Srdivacky    S += Tmp;
370199482Srdivacky    Tmp.clear();
371199482Srdivacky  }
372199482Srdivacky
373199482Srdivacky  if (T->isVariadic()) {
374199482Srdivacky    if (T->getNumArgs())
375199482Srdivacky      S += ", ";
376199482Srdivacky    S += "...";
377199482Srdivacky  } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) {
378199482Srdivacky    // Do not emit int() if we have a proto, emit 'int(void)'.
379199482Srdivacky    S += "void";
380199482Srdivacky  }
381199482Srdivacky
382199482Srdivacky  S += ")";
383200583Srdivacky
384206084Srdivacky  FunctionType::ExtInfo Info = T->getExtInfo();
385206084Srdivacky  switch(Info.getCC()) {
386203955Srdivacky  case CC_Default:
387203955Srdivacky  default: break;
388203955Srdivacky  case CC_C:
389203955Srdivacky    S += " __attribute__((cdecl))";
390203955Srdivacky    break;
391203955Srdivacky  case CC_X86StdCall:
392203955Srdivacky    S += " __attribute__((stdcall))";
393203955Srdivacky    break;
394203955Srdivacky  case CC_X86FastCall:
395203955Srdivacky    S += " __attribute__((fastcall))";
396203955Srdivacky    break;
397208600Srdivacky  case CC_X86ThisCall:
398208600Srdivacky    S += " __attribute__((thiscall))";
399208600Srdivacky    break;
400212904Sdim  case CC_X86Pascal:
401212904Sdim    S += " __attribute__((pascal))";
402212904Sdim    break;
403203955Srdivacky  }
404206084Srdivacky  if (Info.getNoReturn())
405202379Srdivacky    S += " __attribute__((noreturn))";
406206084Srdivacky  if (Info.getRegParm())
407206084Srdivacky    S += " __attribute__((regparm (" +
408206084Srdivacky        llvm::utostr_32(Info.getRegParm()) + ")))";
409202379Srdivacky
410218893Sdim  AppendTypeQualList(S, T->getTypeQuals());
411218893Sdim
412218893Sdim  switch (T->getRefQualifier()) {
413218893Sdim  case RQ_None:
414218893Sdim    break;
415218893Sdim
416218893Sdim  case RQ_LValue:
417218893Sdim    S += " &";
418218893Sdim    break;
419218893Sdim
420218893Sdim  case RQ_RValue:
421218893Sdim    S += " &&";
422218893Sdim    break;
423218893Sdim  }
424218893Sdim
425200583Srdivacky  if (T->hasExceptionSpec()) {
426200583Srdivacky    S += " throw(";
427200583Srdivacky    if (T->hasAnyExceptionSpec())
428200583Srdivacky      S += "...";
429200583Srdivacky    else
430200583Srdivacky      for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) {
431200583Srdivacky        if (I)
432200583Srdivacky          S += ", ";
433200583Srdivacky
434200583Srdivacky        std::string ExceptionType;
435218893Sdim        print(T->getExceptionType(I), ExceptionType);
436200583Srdivacky        S += ExceptionType;
437200583Srdivacky      }
438200583Srdivacky    S += ")";
439200583Srdivacky  }
440200583Srdivacky
441218893Sdim  print(T->getResultType(), S);
442199482Srdivacky}
443199482Srdivacky
444218893Sdimvoid TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T,
445199482Srdivacky                                       std::string &S) {
446199482Srdivacky  // If needed for precedence reasons, wrap the inner part in grouping parens.
447199482Srdivacky  if (!S.empty())
448199482Srdivacky    S = "(" + S + ")";
449199482Srdivacky
450199482Srdivacky  S += "()";
451199482Srdivacky  if (T->getNoReturnAttr())
452199482Srdivacky    S += " __attribute__((noreturn))";
453218893Sdim  print(T->getResultType(), S);
454199482Srdivacky}
455199482Srdivacky
456218893Sdimstatic void printTypeSpec(const NamedDecl *D, std::string &S) {
457204962Srdivacky  IdentifierInfo *II = D->getIdentifier();
458200583Srdivacky  if (S.empty())
459200583Srdivacky    S = II->getName().str();
460200583Srdivacky  else
461200583Srdivacky    S = II->getName().str() + ' ' + S;
462200583Srdivacky}
463200583Srdivacky
464218893Sdimvoid TypePrinter::printUnresolvedUsing(const UnresolvedUsingType *T,
465204962Srdivacky                                       std::string &S) {
466218893Sdim  printTypeSpec(T->getDecl(), S);
467204962Srdivacky}
468204962Srdivacky
469218893Sdimvoid TypePrinter::printTypedef(const TypedefType *T, std::string &S) {
470218893Sdim  printTypeSpec(T->getDecl(), S);
471199482Srdivacky}
472199482Srdivacky
473218893Sdimvoid TypePrinter::printTypeOfExpr(const TypeOfExprType *T, std::string &S) {
474199482Srdivacky  if (!S.empty())    // Prefix the basic type, e.g. 'typeof(e) X'.
475199482Srdivacky    S = ' ' + S;
476199482Srdivacky  std::string Str;
477199482Srdivacky  llvm::raw_string_ostream s(Str);
478199482Srdivacky  T->getUnderlyingExpr()->printPretty(s, 0, Policy);
479199482Srdivacky  S = "typeof " + s.str() + S;
480199482Srdivacky}
481199482Srdivacky
482218893Sdimvoid TypePrinter::printTypeOf(const TypeOfType *T, std::string &S) {
483199482Srdivacky  if (!S.empty())    // Prefix the basic type, e.g. 'typeof(t) X'.
484199482Srdivacky    S = ' ' + S;
485199482Srdivacky  std::string Tmp;
486218893Sdim  print(T->getUnderlyingType(), Tmp);
487199482Srdivacky  S = "typeof(" + Tmp + ")" + S;
488199482Srdivacky}
489199482Srdivacky
490218893Sdimvoid TypePrinter::printDecltype(const DecltypeType *T, std::string &S) {
491199482Srdivacky  if (!S.empty())    // Prefix the basic type, e.g. 'decltype(t) X'.
492199482Srdivacky    S = ' ' + S;
493199482Srdivacky  std::string Str;
494199482Srdivacky  llvm::raw_string_ostream s(Str);
495199482Srdivacky  T->getUnderlyingExpr()->printPretty(s, 0, Policy);
496199482Srdivacky  S = "decltype(" + s.str() + ")" + S;
497199482Srdivacky}
498199482Srdivacky
499218893Sdimvoid TypePrinter::printAuto(const AutoType *T, std::string &S) {
500218893Sdim  // If the type has been deduced, do not print 'auto'.
501218893Sdim  if (T->isDeduced()) {
502218893Sdim    print(T->getDeducedType(), S);
503218893Sdim  } else {
504218893Sdim    if (!S.empty())    // Prefix the basic type, e.g. 'auto X'.
505218893Sdim      S = ' ' + S;
506218893Sdim    S = "auto" + S;
507218893Sdim  }
508218893Sdim}
509218893Sdim
510204962Srdivacky/// Appends the given scope to the end of a string.
511204962Srdivackyvoid TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
512204962Srdivacky  if (DC->isTranslationUnit()) return;
513204962Srdivacky  AppendScope(DC->getParent(), Buffer);
514204962Srdivacky
515204962Srdivacky  unsigned OldSize = Buffer.size();
516204962Srdivacky
517204962Srdivacky  if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
518204962Srdivacky    if (NS->getIdentifier())
519204962Srdivacky      Buffer += NS->getNameAsString();
520204962Srdivacky    else
521204962Srdivacky      Buffer += "<anonymous>";
522204962Srdivacky  } else if (ClassTemplateSpecializationDecl *Spec
523204962Srdivacky               = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
524204962Srdivacky    const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
525204962Srdivacky    std::string TemplateArgsStr
526204962Srdivacky      = TemplateSpecializationType::PrintTemplateArgumentList(
527218893Sdim                                            TemplateArgs.data(),
528218893Sdim                                            TemplateArgs.size(),
529204962Srdivacky                                            Policy);
530204962Srdivacky    Buffer += Spec->getIdentifier()->getName();
531204962Srdivacky    Buffer += TemplateArgsStr;
532204962Srdivacky  } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
533204962Srdivacky    if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
534204962Srdivacky      Buffer += Typedef->getIdentifier()->getName();
535204962Srdivacky    else if (Tag->getIdentifier())
536204962Srdivacky      Buffer += Tag->getIdentifier()->getName();
537204962Srdivacky  }
538204962Srdivacky
539204962Srdivacky  if (Buffer.size() != OldSize)
540204962Srdivacky    Buffer += "::";
541204962Srdivacky}
542204962Srdivacky
543218893Sdimvoid TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
544199482Srdivacky  if (Policy.SuppressTag)
545199482Srdivacky    return;
546204962Srdivacky
547204962Srdivacky  std::string Buffer;
548205408Srdivacky  bool HasKindDecoration = false;
549204962Srdivacky
550204962Srdivacky  // We don't print tags unless this is an elaborated type.
551204962Srdivacky  // In C, we just assume every RecordType is an elaborated type.
552204962Srdivacky  if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) {
553205408Srdivacky    HasKindDecoration = true;
554204962Srdivacky    Buffer += D->getKindName();
555204962Srdivacky    Buffer += ' ';
556204962Srdivacky  }
557204962Srdivacky
558212904Sdim  // Compute the full nested-name-specifier for this type.
559212904Sdim  // In C, this will always be empty except when the type
560212904Sdim  // being printed is anonymous within other Record.
561204962Srdivacky  if (!Policy.SuppressScope)
562204962Srdivacky    AppendScope(D->getDeclContext(), Buffer);
563204962Srdivacky
564204962Srdivacky  if (const IdentifierInfo *II = D->getIdentifier())
565205408Srdivacky    Buffer += II->getNameStart();
566204962Srdivacky  else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) {
567199482Srdivacky    assert(Typedef->getIdentifier() && "Typedef without identifier?");
568205408Srdivacky    Buffer += Typedef->getIdentifier()->getNameStart();
569205408Srdivacky  } else {
570205408Srdivacky    // Make an unambiguous representation for anonymous types, e.g.
571205408Srdivacky    //   <anonymous enum at /usr/include/string.h:120:9>
572205408Srdivacky    llvm::raw_string_ostream OS(Buffer);
573205408Srdivacky    OS << "<anonymous";
574204962Srdivacky
575206275Srdivacky    if (Policy.AnonymousTagLocations) {
576206275Srdivacky      // Suppress the redundant tag keyword if we just printed one.
577206275Srdivacky      // We don't have to worry about ElaboratedTypes here because you can't
578206275Srdivacky      // refer to an anonymous type with one.
579206275Srdivacky      if (!HasKindDecoration)
580206275Srdivacky        OS << " " << D->getKindName();
581205408Srdivacky
582218893Sdim      PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
583210299Sed          D->getLocation());
584218893Sdim      if (PLoc.isValid()) {
585210299Sed        OS << " at " << PLoc.getFilename()
586210299Sed           << ':' << PLoc.getLine()
587210299Sed           << ':' << PLoc.getColumn();
588210299Sed      }
589206275Srdivacky    }
590206275Srdivacky
591206275Srdivacky    OS << '>';
592205408Srdivacky  }
593205408Srdivacky
594199482Srdivacky  // If this is a class template specialization, print the template
595199482Srdivacky  // arguments.
596199482Srdivacky  if (ClassTemplateSpecializationDecl *Spec
597204962Srdivacky        = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
598204962Srdivacky    const TemplateArgument *Args;
599204962Srdivacky    unsigned NumArgs;
600204962Srdivacky    if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
601204962Srdivacky      const TemplateSpecializationType *TST =
602204962Srdivacky        cast<TemplateSpecializationType>(TAW->getType());
603204962Srdivacky      Args = TST->getArgs();
604204962Srdivacky      NumArgs = TST->getNumArgs();
605204962Srdivacky    } else {
606204962Srdivacky      const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
607218893Sdim      Args = TemplateArgs.data();
608218893Sdim      NumArgs = TemplateArgs.size();
609204962Srdivacky    }
610204962Srdivacky    Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
611204962Srdivacky                                                                    NumArgs,
612204962Srdivacky                                                                    Policy);
613199482Srdivacky  }
614204962Srdivacky
615204962Srdivacky  if (!InnerString.empty()) {
616204962Srdivacky    Buffer += ' ';
617204962Srdivacky    Buffer += InnerString;
618204962Srdivacky  }
619204962Srdivacky
620204962Srdivacky  std::swap(Buffer, InnerString);
621199482Srdivacky}
622199482Srdivacky
623218893Sdimvoid TypePrinter::printRecord(const RecordType *T, std::string &S) {
624218893Sdim  printTag(T->getDecl(), S);
625199482Srdivacky}
626199482Srdivacky
627218893Sdimvoid TypePrinter::printEnum(const EnumType *T, std::string &S) {
628218893Sdim  printTag(T->getDecl(), S);
629199482Srdivacky}
630199482Srdivacky
631218893Sdimvoid TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T,
632199482Srdivacky                                        std::string &S) {
633199482Srdivacky  if (!S.empty())    // Prefix the basic type, e.g. 'parmname X'.
634199482Srdivacky    S = ' ' + S;
635199482Srdivacky
636199482Srdivacky  if (!T->getName())
637199482Srdivacky    S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' +
638199482Srdivacky        llvm::utostr_32(T->getIndex()) + S;
639199482Srdivacky  else
640199482Srdivacky    S = T->getName()->getName().str() + S;
641199482Srdivacky}
642199482Srdivacky
643218893Sdimvoid TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
644199482Srdivacky                                             std::string &S) {
645218893Sdim  print(T->getReplacementType(), S);
646199482Srdivacky}
647199482Srdivacky
648218893Sdimvoid TypePrinter::printSubstTemplateTypeParmPack(
649218893Sdim                                        const SubstTemplateTypeParmPackType *T,
650218893Sdim                                             std::string &S) {
651218893Sdim  printTemplateTypeParm(T->getReplacedParameter(), S);
652218893Sdim}
653218893Sdim
654218893Sdimvoid TypePrinter::printTemplateSpecialization(
655199482Srdivacky                                            const TemplateSpecializationType *T,
656199482Srdivacky                                              std::string &S) {
657199482Srdivacky  std::string SpecString;
658199482Srdivacky
659199482Srdivacky  {
660199482Srdivacky    llvm::raw_string_ostream OS(SpecString);
661199482Srdivacky    T->getTemplateName().print(OS, Policy);
662199482Srdivacky  }
663199482Srdivacky
664199482Srdivacky  SpecString += TemplateSpecializationType::PrintTemplateArgumentList(
665199482Srdivacky                                                                  T->getArgs(),
666199482Srdivacky                                                                T->getNumArgs(),
667199482Srdivacky                                                                      Policy);
668199482Srdivacky  if (S.empty())
669199482Srdivacky    S.swap(SpecString);
670199482Srdivacky  else
671199482Srdivacky    S = SpecString + ' ' + S;
672199482Srdivacky}
673199482Srdivacky
674218893Sdimvoid TypePrinter::printInjectedClassName(const InjectedClassNameType *T,
675204962Srdivacky                                         std::string &S) {
676218893Sdim  printTemplateSpecialization(T->getInjectedTST(), S);
677204962Srdivacky}
678204962Srdivacky
679218893Sdimvoid TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) {
680199482Srdivacky  std::string MyString;
681199482Srdivacky
682199482Srdivacky  {
683199482Srdivacky    llvm::raw_string_ostream OS(MyString);
684208600Srdivacky    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
685208600Srdivacky    if (T->getKeyword() != ETK_None)
686208600Srdivacky      OS << " ";
687208600Srdivacky    NestedNameSpecifier* Qualifier = T->getQualifier();
688208600Srdivacky    if (Qualifier)
689208600Srdivacky      Qualifier->print(OS, Policy);
690199482Srdivacky  }
691199482Srdivacky
692199482Srdivacky  std::string TypeStr;
693199482Srdivacky  PrintingPolicy InnerPolicy(Policy);
694199482Srdivacky  InnerPolicy.SuppressScope = true;
695218893Sdim  TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr);
696199482Srdivacky
697199482Srdivacky  MyString += TypeStr;
698199482Srdivacky  if (S.empty())
699199482Srdivacky    S.swap(MyString);
700199482Srdivacky  else
701199482Srdivacky    S = MyString + ' ' + S;
702199482Srdivacky}
703199482Srdivacky
704218893Sdimvoid TypePrinter::printParen(const ParenType *T, std::string &S) {
705218893Sdim  if (!S.empty() && !isa<FunctionType>(T->getInnerType()))
706218893Sdim    S = '(' + S + ')';
707218893Sdim  print(T->getInnerType(), S);
708218893Sdim}
709218893Sdim
710218893Sdimvoid TypePrinter::printDependentName(const DependentNameType *T, std::string &S) {
711199482Srdivacky  std::string MyString;
712199482Srdivacky
713199482Srdivacky  {
714199482Srdivacky    llvm::raw_string_ostream OS(MyString);
715208600Srdivacky    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
716208600Srdivacky    if (T->getKeyword() != ETK_None)
717208600Srdivacky      OS << " ";
718206084Srdivacky
719199482Srdivacky    T->getQualifier()->print(OS, Policy);
720199482Srdivacky
721210299Sed    OS << T->getIdentifier()->getName();
722210299Sed  }
723210299Sed
724210299Sed  if (S.empty())
725210299Sed    S.swap(MyString);
726210299Sed  else
727210299Sed    S = MyString + ' ' + S;
728210299Sed}
729210299Sed
730218893Sdimvoid TypePrinter::printDependentTemplateSpecialization(
731210299Sed        const DependentTemplateSpecializationType *T, std::string &S) {
732210299Sed  std::string MyString;
733210299Sed  {
734210299Sed    llvm::raw_string_ostream OS(MyString);
735210299Sed
736210299Sed    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
737210299Sed    if (T->getKeyword() != ETK_None)
738210299Sed      OS << " ";
739210299Sed
740210299Sed    T->getQualifier()->print(OS, Policy);
741210299Sed    OS << T->getIdentifier()->getName();
742210299Sed    OS << TemplateSpecializationType::PrintTemplateArgumentList(
743210299Sed                                                            T->getArgs(),
744210299Sed                                                            T->getNumArgs(),
745199482Srdivacky                                                            Policy);
746199482Srdivacky  }
747199482Srdivacky
748199482Srdivacky  if (S.empty())
749199482Srdivacky    S.swap(MyString);
750199482Srdivacky  else
751199482Srdivacky    S = MyString + ' ' + S;
752199482Srdivacky}
753199482Srdivacky
754218893Sdimvoid TypePrinter::printPackExpansion(const PackExpansionType *T,
755218893Sdim                                     std::string &S) {
756218893Sdim  print(T->getPattern(), S);
757218893Sdim  S += "...";
758218893Sdim}
759218893Sdim
760218893Sdimvoid TypePrinter::printAttributed(const AttributedType *T,
761218893Sdim                                  std::string &S) {
762218893Sdim  print(T->getModifiedType(), S);
763218893Sdim
764218893Sdim  // TODO: not all attributes are GCC-style attributes.
765218893Sdim  S += "__attribute__((";
766218893Sdim  switch (T->getAttrKind()) {
767218893Sdim  case AttributedType::attr_address_space:
768218893Sdim    S += "address_space(";
769218893Sdim    S += T->getEquivalentType().getAddressSpace();
770218893Sdim    S += ")";
771218893Sdim    break;
772218893Sdim
773218893Sdim  case AttributedType::attr_vector_size: {
774218893Sdim    S += "__vector_size__(";
775218893Sdim    if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) {
776218893Sdim      S += vector->getNumElements();
777218893Sdim      S += " * sizeof(";
778218893Sdim
779218893Sdim      std::string tmp;
780218893Sdim      print(vector->getElementType(), tmp);
781218893Sdim      S += tmp;
782218893Sdim      S += ")";
783218893Sdim    }
784218893Sdim    S += ")";
785218893Sdim    break;
786218893Sdim  }
787218893Sdim
788218893Sdim  case AttributedType::attr_neon_vector_type:
789218893Sdim  case AttributedType::attr_neon_polyvector_type: {
790218893Sdim    if (T->getAttrKind() == AttributedType::attr_neon_vector_type)
791218893Sdim      S += "neon_vector_type(";
792218893Sdim    else
793218893Sdim      S += "neon_polyvector_type(";
794218893Sdim    const VectorType *vector = T->getEquivalentType()->getAs<VectorType>();
795218893Sdim    S += llvm::utostr_32(vector->getNumElements());
796218893Sdim    S += ")";
797218893Sdim    break;
798218893Sdim  }
799218893Sdim
800218893Sdim  case AttributedType::attr_regparm: {
801218893Sdim    S += "regparm(";
802218893Sdim    QualType t = T->getEquivalentType();
803218893Sdim    while (!t->isFunctionType())
804218893Sdim      t = t->getPointeeType();
805218893Sdim    S += t->getAs<FunctionType>()->getRegParmType();
806218893Sdim    S += ")";
807218893Sdim    break;
808218893Sdim  }
809218893Sdim
810218893Sdim  case AttributedType::attr_objc_gc: {
811218893Sdim    S += "objc_gc(";
812218893Sdim
813218893Sdim    QualType tmp = T->getEquivalentType();
814218893Sdim    while (tmp.getObjCGCAttr() == Qualifiers::GCNone) {
815218893Sdim      QualType next = tmp->getPointeeType();
816218893Sdim      if (next == tmp) break;
817218893Sdim      tmp = next;
818218893Sdim    }
819218893Sdim
820218893Sdim    if (tmp.isObjCGCWeak())
821218893Sdim      S += "weak";
822218893Sdim    else
823218893Sdim      S += "strong";
824218893Sdim    S += ")";
825218893Sdim    break;
826218893Sdim  }
827218893Sdim
828218893Sdim  case AttributedType::attr_noreturn: S += "noreturn"; break;
829218893Sdim  case AttributedType::attr_cdecl: S += "cdecl"; break;
830218893Sdim  case AttributedType::attr_fastcall: S += "fastcall"; break;
831218893Sdim  case AttributedType::attr_stdcall: S += "stdcall"; break;
832218893Sdim  case AttributedType::attr_thiscall: S += "thiscall"; break;
833218893Sdim  case AttributedType::attr_pascal: S += "pascal"; break;
834218893Sdim  }
835218893Sdim  S += "))";
836218893Sdim}
837218893Sdim
838218893Sdimvoid TypePrinter::printObjCInterface(const ObjCInterfaceType *T,
839199482Srdivacky                                     std::string &S) {
840199482Srdivacky  if (!S.empty())    // Prefix the basic type, e.g. 'typedefname X'.
841199482Srdivacky    S = ' ' + S;
842208600Srdivacky
843199482Srdivacky  std::string ObjCQIString = T->getDecl()->getNameAsString();
844199482Srdivacky  S = ObjCQIString + S;
845199482Srdivacky}
846199482Srdivacky
847218893Sdimvoid TypePrinter::printObjCObject(const ObjCObjectType *T,
848208600Srdivacky                                  std::string &S) {
849208600Srdivacky  if (T->qual_empty())
850218893Sdim    return print(T->getBaseType(), S);
851208600Srdivacky
852208600Srdivacky  std::string tmp;
853218893Sdim  print(T->getBaseType(), tmp);
854208600Srdivacky  tmp += '<';
855208600Srdivacky  bool isFirst = true;
856208600Srdivacky  for (ObjCObjectType::qual_iterator
857208600Srdivacky         I = T->qual_begin(), E = T->qual_end(); I != E; ++I) {
858208600Srdivacky    if (isFirst)
859208600Srdivacky      isFirst = false;
860208600Srdivacky    else
861208600Srdivacky      tmp += ',';
862208600Srdivacky    tmp += (*I)->getNameAsString();
863208600Srdivacky  }
864208600Srdivacky  tmp += '>';
865208600Srdivacky
866208600Srdivacky  if (!S.empty()) {
867208600Srdivacky    tmp += ' ';
868208600Srdivacky    tmp += S;
869208600Srdivacky  }
870208600Srdivacky  std::swap(tmp, S);
871208600Srdivacky}
872208600Srdivacky
873218893Sdimvoid TypePrinter::printObjCObjectPointer(const ObjCObjectPointerType *T,
874199482Srdivacky                                         std::string &S) {
875199482Srdivacky  std::string ObjCQIString;
876199482Srdivacky
877218893Sdim  T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString,
878218893Sdim                                                               Policy);
879218893Sdim  if (!ObjCQIString.empty())
880218893Sdim    ObjCQIString += ' ';
881218893Sdim
882199482Srdivacky  if (T->isObjCIdType() || T->isObjCQualifiedIdType())
883218893Sdim    ObjCQIString += "id";
884199482Srdivacky  else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
885218893Sdim    ObjCQIString += "Class";
886199990Srdivacky  else if (T->isObjCSelType())
887218893Sdim    ObjCQIString += "SEL";
888199482Srdivacky  else
889218893Sdim    ObjCQIString += T->getInterfaceDecl()->getNameAsString();
890199482Srdivacky
891199482Srdivacky  if (!T->qual_empty()) {
892199482Srdivacky    ObjCQIString += '<';
893199482Srdivacky    for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(),
894199482Srdivacky                                              E = T->qual_end();
895199482Srdivacky         I != E; ++I) {
896199482Srdivacky      ObjCQIString += (*I)->getNameAsString();
897199482Srdivacky      if (I+1 != E)
898199482Srdivacky        ObjCQIString += ',';
899199482Srdivacky    }
900199482Srdivacky    ObjCQIString += '>';
901199482Srdivacky  }
902199482Srdivacky
903199482Srdivacky  if (!T->isObjCIdType() && !T->isObjCQualifiedIdType())
904199482Srdivacky    ObjCQIString += " *"; // Don't forget the implicit pointer.
905199482Srdivacky  else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
906199482Srdivacky    S = ' ' + S;
907199482Srdivacky
908199482Srdivacky  S = ObjCQIString + S;
909199482Srdivacky}
910199482Srdivacky
911199990Srdivackystd::string TemplateSpecializationType::
912199990Srdivacky  PrintTemplateArgumentList(const TemplateArgumentListInfo &Args,
913199990Srdivacky                            const PrintingPolicy &Policy) {
914199990Srdivacky  return PrintTemplateArgumentList(Args.getArgumentArray(),
915199990Srdivacky                                   Args.size(),
916199990Srdivacky                                   Policy);
917199990Srdivacky}
918199990Srdivacky
919199482Srdivackystd::string
920199482SrdivackyTemplateSpecializationType::PrintTemplateArgumentList(
921199482Srdivacky                                                const TemplateArgument *Args,
922199482Srdivacky                                                unsigned NumArgs,
923218893Sdim                                                  const PrintingPolicy &Policy,
924218893Sdim                                                      bool SkipBrackets) {
925199482Srdivacky  std::string SpecString;
926218893Sdim  if (!SkipBrackets)
927218893Sdim    SpecString += '<';
928218893Sdim
929199482Srdivacky  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
930218893Sdim    if (SpecString.size() > !SkipBrackets)
931199482Srdivacky      SpecString += ", ";
932199482Srdivacky
933199482Srdivacky    // Print the argument into a string.
934199482Srdivacky    std::string ArgString;
935218893Sdim    if (Args[Arg].getKind() == TemplateArgument::Pack) {
936218893Sdim      ArgString = PrintTemplateArgumentList(Args[Arg].pack_begin(),
937218893Sdim                                            Args[Arg].pack_size(),
938218893Sdim                                            Policy, true);
939218893Sdim    } else {
940218893Sdim      llvm::raw_string_ostream ArgOut(ArgString);
941218893Sdim      Args[Arg].print(Policy, ArgOut);
942218893Sdim    }
943218893Sdim
944199482Srdivacky    // If this is the first argument and its string representation
945199482Srdivacky    // begins with the global scope specifier ('::foo'), add a space
946199482Srdivacky    // to avoid printing the diagraph '<:'.
947199482Srdivacky    if (!Arg && !ArgString.empty() && ArgString[0] == ':')
948199482Srdivacky      SpecString += ' ';
949199482Srdivacky
950199482Srdivacky    SpecString += ArgString;
951199482Srdivacky  }
952199482Srdivacky
953199482Srdivacky  // If the last character of our string is '>', add another space to
954199482Srdivacky  // keep the two '>''s separate tokens. We don't *have* to do this in
955199482Srdivacky  // C++0x, but it's still good hygiene.
956218893Sdim  if (!SpecString.empty() && SpecString[SpecString.size() - 1] == '>')
957199482Srdivacky    SpecString += ' ';
958199482Srdivacky
959218893Sdim  if (!SkipBrackets)
960218893Sdim    SpecString += '>';
961199482Srdivacky
962199482Srdivacky  return SpecString;
963199482Srdivacky}
964199482Srdivacky
965199482Srdivacky// Sadly, repeat all that with TemplateArgLoc.
966199482Srdivackystd::string TemplateSpecializationType::
967199482SrdivackyPrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
968199482Srdivacky                          const PrintingPolicy &Policy) {
969199482Srdivacky  std::string SpecString;
970199482Srdivacky  SpecString += '<';
971199482Srdivacky  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
972218893Sdim    if (SpecString.size() > 1)
973199482Srdivacky      SpecString += ", ";
974199482Srdivacky
975199482Srdivacky    // Print the argument into a string.
976199482Srdivacky    std::string ArgString;
977218893Sdim    if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) {
978218893Sdim      ArgString = PrintTemplateArgumentList(
979218893Sdim                                           Args[Arg].getArgument().pack_begin(),
980218893Sdim                                            Args[Arg].getArgument().pack_size(),
981218893Sdim                                            Policy, true);
982218893Sdim    } else {
983218893Sdim      llvm::raw_string_ostream ArgOut(ArgString);
984218893Sdim      Args[Arg].getArgument().print(Policy, ArgOut);
985218893Sdim    }
986199482Srdivacky
987199482Srdivacky    // If this is the first argument and its string representation
988199482Srdivacky    // begins with the global scope specifier ('::foo'), add a space
989199482Srdivacky    // to avoid printing the diagraph '<:'.
990199482Srdivacky    if (!Arg && !ArgString.empty() && ArgString[0] == ':')
991199482Srdivacky      SpecString += ' ';
992199482Srdivacky
993199482Srdivacky    SpecString += ArgString;
994199482Srdivacky  }
995199482Srdivacky
996199482Srdivacky  // If the last character of our string is '>', add another space to
997199482Srdivacky  // keep the two '>''s separate tokens. We don't *have* to do this in
998199482Srdivacky  // C++0x, but it's still good hygiene.
999199482Srdivacky  if (SpecString[SpecString.size() - 1] == '>')
1000199482Srdivacky    SpecString += ' ';
1001199482Srdivacky
1002199482Srdivacky  SpecString += '>';
1003199482Srdivacky
1004199482Srdivacky  return SpecString;
1005199482Srdivacky}
1006199482Srdivacky
1007199482Srdivackyvoid QualType::dump(const char *msg) const {
1008199482Srdivacky  std::string R = "identifier";
1009199482Srdivacky  LangOptions LO;
1010199482Srdivacky  getAsStringInternal(R, PrintingPolicy(LO));
1011199482Srdivacky  if (msg)
1012200583Srdivacky    llvm::errs() << msg << ": ";
1013200583Srdivacky  llvm::errs() << R << "\n";
1014199482Srdivacky}
1015199482Srdivackyvoid QualType::dump() const {
1016199482Srdivacky  dump("");
1017199482Srdivacky}
1018199482Srdivacky
1019199482Srdivackyvoid Type::dump() const {
1020199482Srdivacky  QualType(this, 0).dump();
1021199482Srdivacky}
1022199482Srdivacky
1023199482Srdivackystd::string Qualifiers::getAsString() const {
1024199482Srdivacky  LangOptions LO;
1025199482Srdivacky  return getAsString(PrintingPolicy(LO));
1026199482Srdivacky}
1027199482Srdivacky
1028199482Srdivacky// Appends qualifiers to the given string, separated by spaces.  Will
1029199482Srdivacky// prefix a space if the string is non-empty.  Will not append a final
1030199482Srdivacky// space.
1031199482Srdivackyvoid Qualifiers::getAsStringInternal(std::string &S,
1032199482Srdivacky                                     const PrintingPolicy&) const {
1033199482Srdivacky  AppendTypeQualList(S, getCVRQualifiers());
1034199482Srdivacky  if (unsigned AddressSpace = getAddressSpace()) {
1035199482Srdivacky    if (!S.empty()) S += ' ';
1036199482Srdivacky    S += "__attribute__((address_space(";
1037199482Srdivacky    S += llvm::utostr_32(AddressSpace);
1038199482Srdivacky    S += ")))";
1039199482Srdivacky  }
1040199482Srdivacky  if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
1041199482Srdivacky    if (!S.empty()) S += ' ';
1042199482Srdivacky    S += "__attribute__((objc_gc(";
1043199482Srdivacky    if (GCAttrType == Qualifiers::Weak)
1044199482Srdivacky      S += "weak";
1045199482Srdivacky    else
1046199482Srdivacky      S += "strong";
1047199482Srdivacky    S += ")))";
1048199482Srdivacky  }
1049199482Srdivacky}
1050199482Srdivacky
1051218893Sdimstd::string QualType::getAsString(const Type *ty, Qualifiers qs) {
1052218893Sdim  std::string buffer;
1053218893Sdim  LangOptions options;
1054218893Sdim  getAsStringInternal(ty, qs, buffer, PrintingPolicy(options));
1055218893Sdim  return buffer;
1056199482Srdivacky}
1057199482Srdivacky
1058218893Sdimvoid QualType::getAsStringInternal(const Type *ty, Qualifiers qs,
1059218893Sdim                                   std::string &buffer,
1060218893Sdim                                   const PrintingPolicy &policy) {
1061218893Sdim  TypePrinter(policy).print(ty, qs, buffer);
1062199482Srdivacky}
1063