1 /**
2    libclang utility code
3  */
4 module dpp.clang;
5 
6 
7 import dpp.from;
8 
9 
10 from!"clang".Cursor namespace(in from!"clang".Cursor cursor) @safe {
11     import clang: Cursor;
12 
13     auto ret = Cursor(cursor.cx);
14 
15     while(!ret.isInvalid && ret.kind != Cursor.Kind.Namespace)
16         ret = ret.semanticParent;
17 
18     return ret;
19 }
20 
21 
22 /**
23    Returns the type name without namespaces.
24  */
25 string typeNameNoNs(in from!"clang".Cursor cursor) @safe {
26     import clang: Cursor;
27     import std.array: join;
28     import std.algorithm: reverse;
29 
30     string[] parts;
31 
32     auto c = Cursor(cursor.cx);
33 
34     bool isWanted(in Cursor c) {
35         return
36             !c.isInvalid
37             && c.kind != Cursor.Kind.Namespace
38             && c.kind != Cursor.Kind.TranslationUnit
39             ;
40     }
41 
42     while(isWanted(c.semanticParent)) {
43         c = c.semanticParent;
44         parts ~= c.spelling.idup;
45     }
46 
47     parts = parts.reverse ~ cursor.spelling;
48 
49     return parts.join("::");
50 }
51 
52 
53 /**
54    If the cursor is a virtual function that overrides
55    another virtual function.
56  */
57 bool isOverride(in from!"clang".Cursor cursor) @safe {
58     import clang: Cursor;
59     import std.algorithm: any, map, filter, joiner;
60 
61     bool hasOverrideAttr(in Cursor cursor) {
62         return cursor
63             .children
64             .any!(a => a.kind == Cursor.Kind.CXXOverrideAttr)
65             ;
66     }
67 
68     if(hasOverrideAttr(cursor)) return true;
69 
70     auto parents = baseClasses(cursor.semanticParent);
71     const virtualWithSameName = parents
72         .map!(a => a.children)
73         .joiner
74         .filter!(a => a.spelling == cursor.spelling)
75         .any!(a => a.isVirtual)
76         ;
77 
78     return virtualWithSameName;
79 }
80 
81 
82 /**
83    If the cursor is a `final` member function.
84  */
85 bool isFinal(in from!"clang".Cursor cursor) @safe nothrow {
86     import clang: Cursor;
87     import std.algorithm: any;
88 
89     return cursor
90         .children
91         .any!(a => a.kind == Cursor.Kind.CXXFinalAttr)
92         ;
93 }
94 
95 
96 /**
97    All base classes this cursor derives from
98  */
99 from!"clang".Cursor[] baseClasses(in from!"clang".Cursor cursor) @safe nothrow {
100     import clang: Cursor;
101     import std.algorithm: map, filter, joiner;
102     import std.array: array;
103     import std.range: chain;
104 
105     auto baseSpecifiers = cursor
106         .children
107         .filter!(a => a.kind == Cursor.Kind.CXXBaseSpecifier);
108     if(baseSpecifiers.empty) return [];
109 
110     auto baseCursors = baseSpecifiers.map!(a => a.children[0].referencedCursor);
111     return chain(
112         baseCursors,
113         baseCursors.map!baseClasses.joiner,
114     ).array;
115 }