• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- CXTypes.cpp - Implements 'CXTypes' aspect of libclang ------------===//
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 the 'CXTypes' API hooks in the Clang-C library.
11 //
12 //===--------------------------------------------------------------------===//
13 
14 #include "CIndexer.h"
15 #include "CXCursor.h"
16 #include "CXString.h"
17 #include "CXTranslationUnit.h"
18 #include "CXType.h"
19 #include "clang/AST/Decl.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/DeclTemplate.h"
22 #include "clang/AST/Expr.h"
23 #include "clang/AST/Type.h"
24 #include "clang/Frontend/ASTUnit.h"
25 
26 using namespace clang;
27 
GetBuiltinTypeKind(const BuiltinType * BT)28 static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
29 #define BTCASE(K) case BuiltinType::K: return CXType_##K
30   switch (BT->getKind()) {
31     BTCASE(Void);
32     BTCASE(Bool);
33     BTCASE(Char_U);
34     BTCASE(UChar);
35     BTCASE(Char16);
36     BTCASE(Char32);
37     BTCASE(UShort);
38     BTCASE(UInt);
39     BTCASE(ULong);
40     BTCASE(ULongLong);
41     BTCASE(UInt128);
42     BTCASE(Char_S);
43     BTCASE(SChar);
44     case BuiltinType::WChar_S: return CXType_WChar;
45     case BuiltinType::WChar_U: return CXType_WChar;
46     BTCASE(Short);
47     BTCASE(Int);
48     BTCASE(Long);
49     BTCASE(LongLong);
50     BTCASE(Int128);
51     BTCASE(Float);
52     BTCASE(Double);
53     BTCASE(LongDouble);
54     BTCASE(NullPtr);
55     BTCASE(Overload);
56     BTCASE(Dependent);
57     BTCASE(ObjCId);
58     BTCASE(ObjCClass);
59     BTCASE(ObjCSel);
60   default:
61     return CXType_Unexposed;
62   }
63 #undef BTCASE
64 }
65 
GetTypeKind(QualType T)66 static CXTypeKind GetTypeKind(QualType T) {
67   const Type *TP = T.getTypePtrOrNull();
68   if (!TP)
69     return CXType_Invalid;
70 
71 #define TKCASE(K) case Type::K: return CXType_##K
72   switch (TP->getTypeClass()) {
73     case Type::Builtin:
74       return GetBuiltinTypeKind(cast<BuiltinType>(TP));
75     TKCASE(Complex);
76     TKCASE(Pointer);
77     TKCASE(BlockPointer);
78     TKCASE(LValueReference);
79     TKCASE(RValueReference);
80     TKCASE(Record);
81     TKCASE(Enum);
82     TKCASE(Typedef);
83     TKCASE(ObjCInterface);
84     TKCASE(ObjCObjectPointer);
85     TKCASE(FunctionNoProto);
86     TKCASE(FunctionProto);
87     TKCASE(ConstantArray);
88     TKCASE(Vector);
89     default:
90       return CXType_Unexposed;
91   }
92 #undef TKCASE
93 }
94 
95 
MakeCXType(QualType T,CXTranslationUnit TU)96 CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) {
97   CXTypeKind TK = CXType_Invalid;
98 
99   if (TU && !T.isNull()) {
100     ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext();
101     if (Ctx.getLangOpts().ObjC1) {
102       QualType UnqualT = T.getUnqualifiedType();
103       if (Ctx.isObjCIdType(UnqualT))
104         TK = CXType_ObjCId;
105       else if (Ctx.isObjCClassType(UnqualT))
106         TK = CXType_ObjCClass;
107       else if (Ctx.isObjCSelType(UnqualT))
108         TK = CXType_ObjCSel;
109     }
110   }
111   if (TK == CXType_Invalid)
112     TK = GetTypeKind(T);
113 
114   CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }};
115   return CT;
116 }
117 
118 using cxtype::MakeCXType;
119 
GetQualType(CXType CT)120 static inline QualType GetQualType(CXType CT) {
121   return QualType::getFromOpaquePtr(CT.data[0]);
122 }
123 
GetTU(CXType CT)124 static inline CXTranslationUnit GetTU(CXType CT) {
125   return static_cast<CXTranslationUnit>(CT.data[1]);
126 }
127 
128 extern "C" {
129 
clang_getCursorType(CXCursor C)130 CXType clang_getCursorType(CXCursor C) {
131   using namespace cxcursor;
132 
133   CXTranslationUnit TU = cxcursor::getCursorTU(C);
134   if (!TU)
135     return MakeCXType(QualType(), TU);
136 
137   ASTContext &Context = cxtu::getASTUnit(TU)->getASTContext();
138   if (clang_isExpression(C.kind)) {
139     QualType T = cxcursor::getCursorExpr(C)->getType();
140     return MakeCXType(T, TU);
141   }
142 
143   if (clang_isDeclaration(C.kind)) {
144     const Decl *D = cxcursor::getCursorDecl(C);
145     if (!D)
146       return MakeCXType(QualType(), TU);
147 
148     if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
149       return MakeCXType(Context.getTypeDeclType(TD), TU);
150     if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
151       return MakeCXType(Context.getObjCInterfaceType(ID), TU);
152     if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
153       return MakeCXType(VD->getType(), TU);
154     if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
155       return MakeCXType(PD->getType(), TU);
156     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
157       return MakeCXType(FD->getType(), TU);
158     return MakeCXType(QualType(), TU);
159   }
160 
161   if (clang_isReference(C.kind)) {
162     switch (C.kind) {
163     case CXCursor_ObjCSuperClassRef: {
164       QualType T
165         = Context.getObjCInterfaceType(getCursorObjCSuperClassRef(C).first);
166       return MakeCXType(T, TU);
167     }
168 
169     case CXCursor_ObjCClassRef: {
170       QualType T = Context.getObjCInterfaceType(getCursorObjCClassRef(C).first);
171       return MakeCXType(T, TU);
172     }
173 
174     case CXCursor_TypeRef: {
175       QualType T = Context.getTypeDeclType(getCursorTypeRef(C).first);
176       return MakeCXType(T, TU);
177 
178     }
179 
180     case CXCursor_CXXBaseSpecifier:
181       return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU);
182 
183     case CXCursor_MemberRef:
184       return cxtype::MakeCXType(getCursorMemberRef(C).first->getType(), TU);
185 
186     case CXCursor_VariableRef:
187       return cxtype::MakeCXType(getCursorVariableRef(C).first->getType(), TU);
188 
189     case CXCursor_ObjCProtocolRef:
190     case CXCursor_TemplateRef:
191     case CXCursor_NamespaceRef:
192     case CXCursor_OverloadedDeclRef:
193     default:
194       break;
195     }
196 
197     return MakeCXType(QualType(), TU);
198   }
199 
200   return MakeCXType(QualType(), TU);
201 }
202 
clang_getTypeSpelling(CXType CT)203 CXString clang_getTypeSpelling(CXType CT) {
204   QualType T = GetQualType(CT);
205   if (T.isNull())
206     return cxstring::createEmpty();
207 
208   CXTranslationUnit TU = GetTU(CT);
209   SmallString<64> Str;
210   llvm::raw_svector_ostream OS(Str);
211   PrintingPolicy PP(cxtu::getASTUnit(TU)->getASTContext().getLangOpts());
212 
213   T.print(OS, PP);
214 
215   return cxstring::createDup(OS.str());
216 }
217 
clang_getTypedefDeclUnderlyingType(CXCursor C)218 CXType clang_getTypedefDeclUnderlyingType(CXCursor C) {
219   using namespace cxcursor;
220   CXTranslationUnit TU = cxcursor::getCursorTU(C);
221 
222   if (clang_isDeclaration(C.kind)) {
223     const Decl *D = cxcursor::getCursorDecl(C);
224 
225     if (const TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) {
226       QualType T = TD->getUnderlyingType();
227       return MakeCXType(T, TU);
228     }
229 
230     return MakeCXType(QualType(), TU);
231   }
232 
233   return MakeCXType(QualType(), TU);
234 }
235 
clang_getEnumDeclIntegerType(CXCursor C)236 CXType clang_getEnumDeclIntegerType(CXCursor C) {
237   using namespace cxcursor;
238   CXTranslationUnit TU = cxcursor::getCursorTU(C);
239 
240   if (clang_isDeclaration(C.kind)) {
241     const Decl *D = cxcursor::getCursorDecl(C);
242 
243     if (const EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) {
244       QualType T = TD->getIntegerType();
245       return MakeCXType(T, TU);
246     }
247 
248     return MakeCXType(QualType(), TU);
249   }
250 
251   return MakeCXType(QualType(), TU);
252 }
253 
clang_getEnumConstantDeclValue(CXCursor C)254 long long clang_getEnumConstantDeclValue(CXCursor C) {
255   using namespace cxcursor;
256 
257   if (clang_isDeclaration(C.kind)) {
258     const Decl *D = cxcursor::getCursorDecl(C);
259 
260     if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
261       return TD->getInitVal().getSExtValue();
262     }
263 
264     return LLONG_MIN;
265   }
266 
267   return LLONG_MIN;
268 }
269 
clang_getEnumConstantDeclUnsignedValue(CXCursor C)270 unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) {
271   using namespace cxcursor;
272 
273   if (clang_isDeclaration(C.kind)) {
274     const Decl *D = cxcursor::getCursorDecl(C);
275 
276     if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
277       return TD->getInitVal().getZExtValue();
278     }
279 
280     return ULLONG_MAX;
281   }
282 
283   return ULLONG_MAX;
284 }
285 
clang_getFieldDeclBitWidth(CXCursor C)286 int clang_getFieldDeclBitWidth(CXCursor C) {
287   using namespace cxcursor;
288 
289   if (clang_isDeclaration(C.kind)) {
290     const Decl *D = getCursorDecl(C);
291 
292     if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) {
293       if (FD->isBitField())
294         return FD->getBitWidthValue(getCursorContext(C));
295     }
296   }
297 
298   return -1;
299 }
300 
clang_getCanonicalType(CXType CT)301 CXType clang_getCanonicalType(CXType CT) {
302   if (CT.kind == CXType_Invalid)
303     return CT;
304 
305   QualType T = GetQualType(CT);
306   CXTranslationUnit TU = GetTU(CT);
307 
308   if (T.isNull())
309     return MakeCXType(QualType(), GetTU(CT));
310 
311   return MakeCXType(cxtu::getASTUnit(TU)->getASTContext()
312                         .getCanonicalType(T),
313                     TU);
314 }
315 
clang_isConstQualifiedType(CXType CT)316 unsigned clang_isConstQualifiedType(CXType CT) {
317   QualType T = GetQualType(CT);
318   return T.isLocalConstQualified();
319 }
320 
clang_isVolatileQualifiedType(CXType CT)321 unsigned clang_isVolatileQualifiedType(CXType CT) {
322   QualType T = GetQualType(CT);
323   return T.isLocalVolatileQualified();
324 }
325 
clang_isRestrictQualifiedType(CXType CT)326 unsigned clang_isRestrictQualifiedType(CXType CT) {
327   QualType T = GetQualType(CT);
328   return T.isLocalRestrictQualified();
329 }
330 
clang_getPointeeType(CXType CT)331 CXType clang_getPointeeType(CXType CT) {
332   QualType T = GetQualType(CT);
333   const Type *TP = T.getTypePtrOrNull();
334 
335   if (!TP)
336     return MakeCXType(QualType(), GetTU(CT));
337 
338   switch (TP->getTypeClass()) {
339     case Type::Pointer:
340       T = cast<PointerType>(TP)->getPointeeType();
341       break;
342     case Type::BlockPointer:
343       T = cast<BlockPointerType>(TP)->getPointeeType();
344       break;
345     case Type::LValueReference:
346     case Type::RValueReference:
347       T = cast<ReferenceType>(TP)->getPointeeType();
348       break;
349     case Type::ObjCObjectPointer:
350       T = cast<ObjCObjectPointerType>(TP)->getPointeeType();
351       break;
352     default:
353       T = QualType();
354       break;
355   }
356   return MakeCXType(T, GetTU(CT));
357 }
358 
clang_getTypeDeclaration(CXType CT)359 CXCursor clang_getTypeDeclaration(CXType CT) {
360   if (CT.kind == CXType_Invalid)
361     return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
362 
363   QualType T = GetQualType(CT);
364   const Type *TP = T.getTypePtrOrNull();
365 
366   if (!TP)
367     return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
368 
369   Decl *D = 0;
370 
371 try_again:
372   switch (TP->getTypeClass()) {
373   case Type::Typedef:
374     D = cast<TypedefType>(TP)->getDecl();
375     break;
376   case Type::ObjCObject:
377     D = cast<ObjCObjectType>(TP)->getInterface();
378     break;
379   case Type::ObjCInterface:
380     D = cast<ObjCInterfaceType>(TP)->getDecl();
381     break;
382   case Type::Record:
383   case Type::Enum:
384     D = cast<TagType>(TP)->getDecl();
385     break;
386   case Type::TemplateSpecialization:
387     if (const RecordType *Record = TP->getAs<RecordType>())
388       D = Record->getDecl();
389     else
390       D = cast<TemplateSpecializationType>(TP)->getTemplateName()
391                                                          .getAsTemplateDecl();
392     break;
393 
394   case Type::InjectedClassName:
395     D = cast<InjectedClassNameType>(TP)->getDecl();
396     break;
397 
398   // FIXME: Template type parameters!
399 
400   case Type::Elaborated:
401     TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull();
402     goto try_again;
403 
404   default:
405     break;
406   }
407 
408   if (!D)
409     return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
410 
411   return cxcursor::MakeCXCursor(D, GetTU(CT));
412 }
413 
clang_getTypeKindSpelling(enum CXTypeKind K)414 CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
415   const char *s = 0;
416 #define TKIND(X) case CXType_##X: s = ""  #X  ""; break
417   switch (K) {
418     TKIND(Invalid);
419     TKIND(Unexposed);
420     TKIND(Void);
421     TKIND(Bool);
422     TKIND(Char_U);
423     TKIND(UChar);
424     TKIND(Char16);
425     TKIND(Char32);
426     TKIND(UShort);
427     TKIND(UInt);
428     TKIND(ULong);
429     TKIND(ULongLong);
430     TKIND(UInt128);
431     TKIND(Char_S);
432     TKIND(SChar);
433     case CXType_WChar: s = "WChar"; break;
434     TKIND(Short);
435     TKIND(Int);
436     TKIND(Long);
437     TKIND(LongLong);
438     TKIND(Int128);
439     TKIND(Float);
440     TKIND(Double);
441     TKIND(LongDouble);
442     TKIND(NullPtr);
443     TKIND(Overload);
444     TKIND(Dependent);
445     TKIND(ObjCId);
446     TKIND(ObjCClass);
447     TKIND(ObjCSel);
448     TKIND(Complex);
449     TKIND(Pointer);
450     TKIND(BlockPointer);
451     TKIND(LValueReference);
452     TKIND(RValueReference);
453     TKIND(Record);
454     TKIND(Enum);
455     TKIND(Typedef);
456     TKIND(ObjCInterface);
457     TKIND(ObjCObjectPointer);
458     TKIND(FunctionNoProto);
459     TKIND(FunctionProto);
460     TKIND(ConstantArray);
461     TKIND(Vector);
462   }
463 #undef TKIND
464   return cxstring::createRef(s);
465 }
466 
clang_equalTypes(CXType A,CXType B)467 unsigned clang_equalTypes(CXType A, CXType B) {
468   return A.data[0] == B.data[0] && A.data[1] == B.data[1];;
469 }
470 
clang_isFunctionTypeVariadic(CXType X)471 unsigned clang_isFunctionTypeVariadic(CXType X) {
472   QualType T = GetQualType(X);
473   if (T.isNull())
474     return 0;
475 
476   if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>())
477     return (unsigned)FD->isVariadic();
478 
479   if (T->getAs<FunctionNoProtoType>())
480     return 1;
481 
482   return 0;
483 }
484 
clang_getFunctionTypeCallingConv(CXType X)485 CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
486   QualType T = GetQualType(X);
487   if (T.isNull())
488     return CXCallingConv_Invalid;
489 
490   if (const FunctionType *FD = T->getAs<FunctionType>()) {
491 #define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
492     switch (FD->getCallConv()) {
493       TCALLINGCONV(Default);
494       TCALLINGCONV(C);
495       TCALLINGCONV(X86StdCall);
496       TCALLINGCONV(X86FastCall);
497       TCALLINGCONV(X86ThisCall);
498       TCALLINGCONV(X86Pascal);
499       TCALLINGCONV(AAPCS);
500       TCALLINGCONV(AAPCS_VFP);
501       TCALLINGCONV(PnaclCall);
502       TCALLINGCONV(IntelOclBicc);
503     }
504 #undef TCALLINGCONV
505   }
506 
507   return CXCallingConv_Invalid;
508 }
509 
clang_getNumArgTypes(CXType X)510 int clang_getNumArgTypes(CXType X) {
511   QualType T = GetQualType(X);
512   if (T.isNull())
513     return -1;
514 
515   if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) {
516     return FD->getNumArgs();
517   }
518 
519   if (T->getAs<FunctionNoProtoType>()) {
520     return 0;
521   }
522 
523   return -1;
524 }
525 
clang_getArgType(CXType X,unsigned i)526 CXType clang_getArgType(CXType X, unsigned i) {
527   QualType T = GetQualType(X);
528   if (T.isNull())
529     return MakeCXType(QualType(), GetTU(X));
530 
531   if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) {
532     unsigned numArgs = FD->getNumArgs();
533     if (i >= numArgs)
534       return MakeCXType(QualType(), GetTU(X));
535 
536     return MakeCXType(FD->getArgType(i), GetTU(X));
537   }
538 
539   return MakeCXType(QualType(), GetTU(X));
540 }
541 
clang_getResultType(CXType X)542 CXType clang_getResultType(CXType X) {
543   QualType T = GetQualType(X);
544   if (T.isNull())
545     return MakeCXType(QualType(), GetTU(X));
546 
547   if (const FunctionType *FD = T->getAs<FunctionType>())
548     return MakeCXType(FD->getResultType(), GetTU(X));
549 
550   return MakeCXType(QualType(), GetTU(X));
551 }
552 
clang_getCursorResultType(CXCursor C)553 CXType clang_getCursorResultType(CXCursor C) {
554   if (clang_isDeclaration(C.kind)) {
555     const Decl *D = cxcursor::getCursorDecl(C);
556     if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
557       return MakeCXType(MD->getResultType(), cxcursor::getCursorTU(C));
558 
559     return clang_getResultType(clang_getCursorType(C));
560   }
561 
562   return MakeCXType(QualType(), cxcursor::getCursorTU(C));
563 }
564 
clang_isPODType(CXType X)565 unsigned clang_isPODType(CXType X) {
566   QualType T = GetQualType(X);
567   if (T.isNull())
568     return 0;
569 
570   CXTranslationUnit TU = GetTU(X);
571 
572   return T.isPODType(cxtu::getASTUnit(TU)->getASTContext()) ? 1 : 0;
573 }
574 
clang_getElementType(CXType CT)575 CXType clang_getElementType(CXType CT) {
576   QualType ET = QualType();
577   QualType T = GetQualType(CT);
578   const Type *TP = T.getTypePtrOrNull();
579 
580   if (TP) {
581     switch (TP->getTypeClass()) {
582     case Type::ConstantArray:
583       ET = cast<ConstantArrayType> (TP)->getElementType();
584       break;
585     case Type::Vector:
586       ET = cast<VectorType> (TP)->getElementType();
587       break;
588     case Type::Complex:
589       ET = cast<ComplexType> (TP)->getElementType();
590       break;
591     default:
592       break;
593     }
594   }
595   return MakeCXType(ET, GetTU(CT));
596 }
597 
clang_getNumElements(CXType CT)598 long long clang_getNumElements(CXType CT) {
599   long long result = -1;
600   QualType T = GetQualType(CT);
601   const Type *TP = T.getTypePtrOrNull();
602 
603   if (TP) {
604     switch (TP->getTypeClass()) {
605     case Type::ConstantArray:
606       result = cast<ConstantArrayType> (TP)->getSize().getSExtValue();
607       break;
608     case Type::Vector:
609       result = cast<VectorType> (TP)->getNumElements();
610       break;
611     default:
612       break;
613     }
614   }
615   return result;
616 }
617 
clang_getArrayElementType(CXType CT)618 CXType clang_getArrayElementType(CXType CT) {
619   QualType ET = QualType();
620   QualType T = GetQualType(CT);
621   const Type *TP = T.getTypePtrOrNull();
622 
623   if (TP) {
624     switch (TP->getTypeClass()) {
625     case Type::ConstantArray:
626       ET = cast<ConstantArrayType> (TP)->getElementType();
627       break;
628     default:
629       break;
630     }
631   }
632   return MakeCXType(ET, GetTU(CT));
633 }
634 
clang_getArraySize(CXType CT)635 long long clang_getArraySize(CXType CT) {
636   long long result = -1;
637   QualType T = GetQualType(CT);
638   const Type *TP = T.getTypePtrOrNull();
639 
640   if (TP) {
641     switch (TP->getTypeClass()) {
642     case Type::ConstantArray:
643       result = cast<ConstantArrayType> (TP)->getSize().getSExtValue();
644       break;
645     default:
646       break;
647     }
648   }
649   return result;
650 }
651 
clang_getDeclObjCTypeEncoding(CXCursor C)652 CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
653   if (!clang_isDeclaration(C.kind))
654     return cxstring::createEmpty();
655 
656   const Decl *D = cxcursor::getCursorDecl(C);
657   ASTContext &Ctx = cxcursor::getCursorContext(C);
658   std::string encoding;
659 
660   if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))  {
661     if (Ctx.getObjCEncodingForMethodDecl(OMD, encoding))
662       return cxstring::createRef("?");
663   } else if (const ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D))
664     Ctx.getObjCEncodingForPropertyDecl(OPD, NULL, encoding);
665   else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
666     Ctx.getObjCEncodingForFunctionDecl(FD, encoding);
667   else {
668     QualType Ty;
669     if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
670       Ty = Ctx.getTypeDeclType(TD);
671     if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
672       Ty = VD->getType();
673     else return cxstring::createRef("?");
674     Ctx.getObjCEncodingForType(Ty, encoding);
675   }
676 
677   return cxstring::createDup(encoding);
678 }
679 
680 } // end: extern "C"
681