1 /** 2 typedef translations 3 */ 4 module dpp.cursor.typedef_; 5 6 import dpp.from; 7 8 string[] translateTypedef(in from!"clang".Cursor typedef_, 9 ref from!"dpp.runtime.context".Context context) 10 @safe 11 { 12 import dpp.type: translate; 13 import dpp.cursor.aggregate: isAggregateC; 14 import clang: Cursor, Type; 15 import std.conv: text; 16 import std.typecons: No; 17 import std.algorithm: filter; 18 import std.array: array; 19 20 const children = () @trusted { 21 return typedef_ 22 .children 23 .filter!(a => !a.isInvalid) 24 .filter!(a => a.kind != Cursor.Kind.FirstAttr) 25 .array; 26 }(); 27 28 const nonCanonicalUnderlyingType = typedef_.underlyingType; 29 const underlyingType = nonCanonicalUnderlyingType.canonical; 30 31 context.log("Children: ", children); 32 context.log(" Underlying type: ", nonCanonicalUnderlyingType); 33 context.log("Canonical underlying type: ", underlyingType); 34 35 if(isSomeFunction(underlyingType)) 36 return translateFunctionTypeDef(typedef_, context.indent); 37 38 const isOnlyAggregateChild = children.length == 1 && isAggregateC(children[0]); 39 const isTopLevelAnonymous = 40 isOnlyAggregateChild && 41 children[0].spelling == "" && // anonymous 42 children[0].lexicalParent.kind == Cursor.Kind.TranslationUnit; // top-level 43 44 // if the child is a top-level anonymous struct, it's pointless to alias 45 // it and give the struct a silly name, instead just define a struct with 46 // the typedef name instead. e.g. 47 // typedef struct { int dummy; } Foo -> struct Foo { int dummy; } 48 if(isTopLevelAnonymous) return translateTopLevelAnonymous(children[0], context); 49 50 // FIXME - still not sure I understand this 51 const underlyingSpelling = isOnlyAggregateChild 52 ? context.spellingOrNickname(children[0]) 53 : translate(underlyingType, context, No.translatingFunction); 54 55 // If the two spellings are the same, it's a `typedef struct foo { } foo` 56 // situration, and there's no reason to alias to anything, so we return nothing. 57 return typedef_.spelling == underlyingSpelling 58 ? [] 59 : [`alias ` ~ typedef_.spelling ~ ` = ` ~ underlyingSpelling ~ `;`]; 60 } 61 62 private string[] translateFunctionTypeDef(in from!"clang".Cursor typedef_, 63 ref from!"dpp.runtime.context".Context context) 64 @safe 65 { 66 import dpp.type: translate; 67 import dpp.cursor.function_: translateParamTypes; 68 import clang: Cursor, Type; 69 import std.algorithm: map, filter; 70 import std.array: join; 71 72 const underlyingType = typedef_.underlyingType.canonical; 73 const returnType = underlyingType.kind == Type.Kind.Pointer 74 ? underlyingType.pointee.returnType 75 : underlyingType.returnType; 76 context.log("Function typedef return type: ", returnType); 77 const returnTypeTransl = translate(returnType, context); 78 79 const params = translateParamTypes(typedef_, context.indent).join(", "); 80 return [`alias ` ~ typedef_.spelling ~ ` = ` ~ returnTypeTransl ~ ` function(` ~ params ~ `);`]; 81 82 } 83 84 private bool isSomeFunction(in from!"clang".Type type) @safe @nogc pure nothrow { 85 import clang: Type; 86 87 const isFunctionPointer = 88 type.kind == Type.Kind.Pointer && 89 type.pointee.kind == Type.Kind.FunctionProto; 90 const isFunction = type.kind == Type.Kind.FunctionProto; 91 92 return isFunctionPointer || isFunction; 93 } 94 95 private string[] translateTopLevelAnonymous(in from!"clang".Cursor cursor, 96 ref from!"dpp.runtime.context".Context context) 97 @safe 98 { 99 import dpp.cursor.translation: translate; 100 import clang: Cursor; 101 102 // the old cursor has no spelling, so construct a new one 103 auto newCursor = Cursor(cursor.cx); 104 105 // the type spelling will be the name of the struct, union, or enum 106 newCursor.spelling = cursor.type.spelling; 107 108 // delegate to whoever knows what they're doing 109 return translate(newCursor, context); 110 }