1 /** 2 Date: 2015-2017, Joakim Brännström 3 License: MPL-2, Mozilla Public License 2.0 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 Extracted information of types. 7 */ 8 module cpptooling.data.kind_type; 9 10 import std.conv : to; 11 import std..string : format; 12 import std.traits; 13 import std.typecons : Tuple, Flag, Nullable; 14 import logger = std.experimental.logger; 15 16 import sumtype; 17 18 import cpptooling.data.symbol.types : USRType; 19 import cpptooling.data.type : LocationTag; 20 21 public import cpptooling.data.kind; 22 23 struct TypeKindAttr { 24 TypeKind kind; 25 TypeAttr attr; 26 } 27 28 struct TypeResult { 29 TypeKindAttr type; 30 LocationTag location; 31 } 32 33 struct TypeResults { 34 TypeResult primary; 35 TypeResult[] extra; 36 } 37 38 /** Merge rhs into lhs. 39 */ 40 ref TypeResults mergeExtra(ref return TypeResults lhs, ref TypeResults rhs) { 41 lhs.extra ~= rhs.extra; 42 return lhs; 43 } 44 45 /// Pretty loggning with indentation. 46 void logTypeAttr(TypeAttr attr, const uint indent = 0, in uint extra_space = 0, 47 in string func = __FUNCTION__, in uint line = __LINE__) @safe pure { 48 import std.array : array; 49 import std.range : repeat; 50 import logger = std.experimental.logger; 51 import clang.info; 52 53 // dfmt off 54 debug { 55 string indent_ = repeat(' ', indent + extra_space).array(); 56 logger.logf!(-1, "", "", "", "") 57 (logger.LogLevel.trace, 58 "%d%s %s [%s:%d]", 59 indent, 60 indent_, 61 attr, 62 func, 63 line); 64 } 65 // dfmt on 66 } 67 68 /// Pretty loggning with indentation. 69 void logTypeResult(const TypeResult result, in uint indent, 70 in string func = __FUNCTION__, in uint line = __LINE__) @safe pure nothrow { 71 import std.array : array; 72 import std.conv : to; 73 import std.range : repeat; 74 import logger = std.experimental.logger; 75 76 // dfmt off 77 try { 78 debug { 79 string indent_ = repeat(' ', indent).array(); 80 string extra; 81 result.type.kind.info.match!((const TypeKind.TypeRefInfo t) { 82 extra = "|ex ref:" ~ t.typeRef ~ "|ex canonical:" ~ t.canonicalRef; 83 }, 84 (const TypeKind.FuncPtrInfo t) { 85 extra = "|ex usr:" ~ t.pointee; 86 }, 87 (const TypeKind.PointerInfo t) { 88 extra = "|ex usr:" ~ t.pointee; 89 }, 90 (const TypeKind.ArrayInfo t) { 91 extra = "|ex elem:" ~ t.element; 92 }, 93 (_) {}); 94 95 logger.logf!(-1, "", "", "", "") 96 (logger.LogLevel.trace, 97 "%d%s %s|%s|repr:%s|loc:%s %s|usr:%s|%s%s [%s:%d]", 98 indent, 99 indent_, 100 result.type.kind.info.match!(a => typeof(a).stringof), 101 result.type.kind.splitTypeId, 102 result.type.toStringDecl("x"), 103 (result.location.kind == LocationTag.Kind.loc) ? (result.location.file.length == 0 ? "no" : "yes") : "noloc", 104 (result.type.attr.isDefinition ? "def" : "decl"), 105 result.type.kind.usr, 106 result.type.attr, 107 extra, 108 func, 109 line); 110 111 result.type.kind.info.match!((const TypeKind.FuncInfo t) { 112 foreach (r; t.params) { 113 logTypeAttr(r.attr, indent, 1, func, line); 114 } 115 }, 116 (const TypeKind.PointerInfo t) { 117 foreach (r; t.attrs) { 118 logTypeAttr(r, indent, 1, func, line); 119 } 120 }, (_) {}); 121 } 122 } catch (Exception ex) { 123 } 124 // dfmt on 125 } 126 127 /// Pretty loggning with indentation. 128 void logTypeResult(const TypeResults results, in uint indent = 0, 129 in string func = __FUNCTION__, in uint line = __LINE__) @safe pure nothrow { 130 // dfmt off 131 debug { 132 logTypeResult(results.primary, indent, func, line); 133 foreach (ref result; results.extra) { 134 logTypeResult(result, indent, func, line); 135 } 136 } 137 // dfmt on 138 } 139 140 /// Pretty loggning with indentation. 141 void logTypeResult(const Nullable!TypeResults results, in uint indent = 0, 142 in string func = __FUNCTION__, in uint line = __LINE__) @safe pure nothrow { 143 debug { 144 if (!results.isNull) { 145 logTypeResult(results.get, indent, func, line); 146 } 147 } 148 } 149 150 //TODO remove, this is not good. keep it focused on SimleInfo. 151 TypeKindAttr makeSimple(string txt, TypeAttr attr = TypeAttr.init) pure @trusted nothrow { 152 import cpptooling.data : SimpleFmt, TypeId; 153 154 TypeKind t; 155 t.info = TypeKind.Info(TypeKind.SimpleInfo(SimpleFmt(TypeId(txt)))); 156 157 return TypeKindAttr(t, attr); 158 } 159 160 private auto toCvPtrQ(T)(ref T app, const(TypeAttr)[] attrs) { 161 import cpptooling.data; 162 163 foreach (attr; attrs) { 164 // TODO merge isPtr/isRef to an enum in the data structure for 165 // attributes 166 // should be either, never both 167 assert(!(attr.isPtr && attr.isRef)); 168 169 CvPtrQ a; 170 a.cvQual = attr.isConst ? CvQ.const_ : CvQ(); 171 if (attr.isPtr) 172 a.ptrQual = PtrQ.ptr; 173 else if (attr.isRef) 174 a.ptrQual = PtrQ.ref_; 175 176 app.put(a); 177 } 178 } 179 180 /** Combine type attributes, kind and identifier to produce a declaration. 181 * TODO reconsider the function name. 182 * - Don't encode the return type in the name (?) 183 * - Is it really a Decl-> declaration? Maybe more appropriate would be 184 * "merge", of type and attributes? 185 * 186 * trusted: shouldn't be needed but because of changes to dmd-2.094.0 187 */ 188 auto toStringDecl(const TypeKind t, TypeAttr ta, string id) @safe pure { 189 import std.array : appender, Appender; 190 import cpptooling.data; 191 192 auto buf = appender!(char[])(); 193 void txt(const(char)[] s) @safe pure { 194 buf.put(s); 195 } 196 197 void oneArg(T)(ref T fmt, ref const TypeAttr ta, DeclId id) { 198 fmt.toString(&txt, ta.isConst ? CvQ.const_ : CvQ(), id); 199 } 200 201 void twoArg(T0, T1)(ref T0 fmt, ref const TypeAttr ta, DeclId id, T1 data1) { 202 fmt.toString(&txt, &txt, ta.isConst ? CvQ.const_ : CvQ(), data1, id); 203 } 204 205 t.info.match!((const TypeKind.PrimitiveInfo t) => oneArg(t.fmt, ta, 206 DeclId(id)), (const TypeKind.RecordInfo t) => oneArg(t.fmt, ta, 207 DeclId(id)), (const TypeKind.SimpleInfo t) => oneArg(t.fmt, ta, 208 DeclId(id)), (const TypeKind.TypeRefInfo t) => oneArg(t.fmt, ta, 209 DeclId(id)), (const TypeKind.ArrayInfo t) { 210 ArraySize sz; 211 212 foreach (a; t.indexes) { 213 if (a.isNull) { 214 sz ~= ArraySize.Size(); 215 } else { 216 sz ~= ArraySize.Size(ArraySize.Kind.const_, a.get); 217 } 218 } 219 220 t.fmt.toString(&txt, &txt, ta.isConst ? CvQ.const_ : CvQ(), DeclId(id), sz); 221 }, (const TypeKind.FuncInfo t) => t.fmt.toString(&txt, &txt, DeclId(id)), 222 (const TypeKind.FuncSignatureInfo t) => t.fmt.toString(&txt, 223 &txt), (const TypeKind.FuncPtrInfo t) { 224 auto ptrs = appender!(CvPtrQ[])(); 225 toCvPtrQ(ptrs, t.attrs); 226 227 twoArg(t.fmt, ta, DeclId(id), ptrs.data); 228 }, (const TypeKind.PointerInfo t) { 229 auto ptrs = appender!(CvPtrQ[])(); 230 toCvPtrQ(ptrs, t.attrs); 231 232 twoArg(t.fmt, ta, DeclId(id), ptrs.data); 233 }, (const TypeKind.CtorInfo t) => t.fmt.toString(&txt, DeclId(id)), 234 (const TypeKind.DtorInfo t) => t.fmt.toString(&txt, DeclId(id)), (Void t) { 235 debug { 236 logger.error("Type is null. Identifier ", id); 237 } 238 txt(id); 239 }); 240 241 return buf.data.idup; 242 } 243 244 /// ditto 245 auto toStringDecl(const TypeKind t, const TypeAttr ta) @safe { 246 import std..string : strip; 247 248 // TODO consider changing the implementation of to NOT take an id. 249 // Would avoid the strip.... 250 return t.toStringDecl(ta, "").strip; 251 } 252 253 /// if a type can be cast to a TypeKindAttr. 254 auto toStringDecl(T)(T value, string id) @safe 255 if (is(typeof(cast(TypeKindAttr) value) == TypeKindAttr)) { 256 return (cast(const TypeKindAttr) value).kind.toStringDecl(value.attr, id); 257 } 258 259 /// ditto 260 auto toStringDecl(T)(T value) @safe 261 if (is(typeof(cast(TypeKindAttr) value) == TypeKindAttr)) { 262 return (cast(const TypeKindAttr) value).kind.toStringDecl(value.attr); 263 } 264 265 /** Split the TypeId from the formatter in a Left/Right. 266 * 267 * TODO duplicate code between this and toStringDecl. 268 */ 269 auto splitTypeId(const TypeKind t) @safe pure { 270 import std.array : appender, Appender; 271 import cpptooling.data; 272 273 TypeIdLR rval; 274 275 auto bufWl = appender!(char[])(); 276 void wl(const(char)[] s) @safe pure { 277 bufWl.put(s); 278 } 279 280 auto bufWr = appender!(char[])(); 281 void wr(const(char)[] s) @safe pure { 282 bufWr.put(s); 283 } 284 285 t.info.match!((const TypeKind.PrimitiveInfo t) { rval.left = t.fmt.typeId; }, 286 (const TypeKind.RecordInfo t) { rval.left = t.fmt.typeId; }, 287 (const TypeKind.SimpleInfo t) { rval.left = t.fmt.typeId; }, 288 (const TypeKind.TypeRefInfo t) { rval.left = t.fmt.typeId; }, 289 (const TypeKind.ArrayInfo t) { 290 ArraySize sz; 291 292 foreach (a; t.indexes) { 293 if (a.isNull) { 294 sz ~= ArraySize.Size(); 295 } else { 296 sz ~= ArraySize.Size(ArraySize.Kind.const_, a.get); 297 } 298 } 299 300 t.fmt.toString(&wl, &wr, CvQ(), DeclId(null), sz); 301 rval = TypeIdLR(Left(bufWl.data.idup), Right(bufWr.data.idup)); 302 }, (const TypeKind.FuncSignatureInfo t) { 303 t.fmt.toString(&wl, &wr); 304 rval = TypeIdLR(Left(bufWl.data.idup), Right(bufWr.data.idup)); 305 }, (const TypeKind.FuncInfo t) { 306 t.fmt.toString(&wl, &wr, DeclId(null)); 307 rval = TypeIdLR(Left(bufWl.data.idup), Right(bufWr.data.idup)); 308 }, (const TypeKind.FuncPtrInfo t) { 309 auto ptrs = appender!(CvPtrQ[])(); 310 toCvPtrQ(ptrs, t.attrs); 311 312 t.fmt.toString(&wl, &wr, CvQ(), ptrs.data, DeclId(null)); 313 rval = TypeIdLR(Left(bufWl.data.idup), Right(bufWr.data.idup)); 314 }, (const TypeKind.PointerInfo t) { 315 auto ptrs = appender!(CvPtrQ[])(); 316 toCvPtrQ(ptrs, t.attrs); 317 318 t.fmt.toString(&wl, &wr, CvQ(), ptrs.data, DeclId(null)); 319 rval = TypeIdLR(Left(bufWl.data.idup), Right(bufWr.data.idup)); 320 }, (_) {}); 321 322 return rval; 323 } 324 325 /// ditto 326 auto splitTypeId(const TypeKind t, in uint indent = 0) @safe pure 327 out (result) { 328 import std.conv : to; 329 330 debug { 331 logger.trace(result.to!string(), indent); 332 } 333 } 334 do { 335 return splitTypeId(t); 336 }