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