|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 let dumpTypes = options['dump-types'].split(','); |
|
6 |
|
7 let interestingList = {}; |
|
8 let typelist = {}; |
|
9 |
|
10 function interestingType(t) |
|
11 { |
|
12 let name = t.name; |
|
13 |
|
14 if (dumpTypes.some(function(n) n == name)) { |
|
15 interestingList[name] = t; |
|
16 typelist[name] = t; |
|
17 return true; |
|
18 } |
|
19 |
|
20 for each (let base in t.bases) { |
|
21 if (base.access == 'public' && interestingType(base.type)) { |
|
22 typelist[name] = t; |
|
23 return true; |
|
24 } |
|
25 } |
|
26 |
|
27 return false; |
|
28 } |
|
29 |
|
30 function addSubtype(t, subt) |
|
31 { |
|
32 if (subt.typedef === undefined && |
|
33 subt.kind === undefined) |
|
34 throw Error("Unexpected subtype: not class or typedef: " + subt); |
|
35 |
|
36 if (t.subtypes === undefined) |
|
37 t.subtypes = []; |
|
38 |
|
39 t.subtypes.push(subt); |
|
40 } |
|
41 |
|
42 function process_type(t) |
|
43 { |
|
44 interestingType(t); |
|
45 |
|
46 for each (let base in t.bases) |
|
47 addSubtype(base.type, t); |
|
48 } |
|
49 |
|
50 function process_decl(d) |
|
51 { |
|
52 if (d.typedef !== undefined && d.memberOf) |
|
53 addSubtype(d.memberOf, d); |
|
54 } |
|
55 |
|
56 function publicBases(t) |
|
57 { |
|
58 yield t; |
|
59 |
|
60 for each (let base in t.bases) |
|
61 if (base.access == "public") |
|
62 for each (let gbase in publicBases(base.type)) |
|
63 yield gbase; |
|
64 } |
|
65 |
|
66 function publicMembers(t) |
|
67 { |
|
68 for each (let base in publicBases(t)) { |
|
69 for each (let member in base.members) { |
|
70 if (member.access === undefined) |
|
71 throw Error("Harumph: member without access? " + member); |
|
72 |
|
73 if (member.access != "public") |
|
74 continue; |
|
75 |
|
76 yield member; |
|
77 } |
|
78 } |
|
79 } |
|
80 |
|
81 /** |
|
82 * Get the short name of a decl name. E.g. turn |
|
83 * "MyNamespace::MyClass::Method(int j) const" into |
|
84 * "Method" |
|
85 */ |
|
86 function getShortName(decl) |
|
87 { |
|
88 let name = decl.name; |
|
89 let lp = name.lastIndexOf('('); |
|
90 if (lp != -1) |
|
91 name = name.slice(0, lp); |
|
92 |
|
93 lp = name.lastIndexOf('::'); |
|
94 if (lp != -1) |
|
95 name = name.slice(lp + 2); |
|
96 |
|
97 return name; |
|
98 } |
|
99 |
|
100 /** |
|
101 * Remove functions in a base class which were overridden in a derived |
|
102 * class. |
|
103 * |
|
104 * Although really, we should perhaps do this the other way around, or even |
|
105 * group the two together, but that can come later. |
|
106 */ |
|
107 function removeOverrides(members) |
|
108 { |
|
109 let overrideMap = {}; |
|
110 for (let i = members.length - 1; i >= 0; --i) { |
|
111 let m = members[i]; |
|
112 if (!m.isFunction) |
|
113 continue; |
|
114 |
|
115 let shortName = getShortName(m); |
|
116 |
|
117 let overrides = overrideMap[shortName]; |
|
118 if (overrides === undefined) { |
|
119 overrideMap[shortName] = [m]; |
|
120 continue; |
|
121 } |
|
122 |
|
123 let found = false; |
|
124 for each (let override in overrides) { |
|
125 if (signaturesMatch(override, m)) { |
|
126 // remove members[i], it was overridden |
|
127 members.splice(i, 1); |
|
128 found = true; |
|
129 } |
|
130 } |
|
131 if (found) |
|
132 continue; |
|
133 |
|
134 overrides.push(m); |
|
135 } |
|
136 } |
|
137 |
|
138 /** |
|
139 * Generates the starting position of lines within a file. |
|
140 */ |
|
141 function getLineLocations(fdata) |
|
142 { |
|
143 yield 0; |
|
144 |
|
145 let r = /\n/y; |
|
146 let pos = 0; |
|
147 let i = 1; |
|
148 for (;;) { |
|
149 pos = fdata.indexOf('\n', pos) + 1; |
|
150 if (pos == 0) |
|
151 break; |
|
152 |
|
153 yield pos; |
|
154 i++; |
|
155 } |
|
156 } |
|
157 |
|
158 /** |
|
159 * Find and return the doxygen comment immediately prior to the location |
|
160 * object that was passed in. |
|
161 * |
|
162 * @todo: parse doccomment data such as @param, @returns |
|
163 * @todo: parse comments for markup |
|
164 */ |
|
165 function getDocComment(loc) |
|
166 { |
|
167 let fdata = read_file(loc.file); |
|
168 let linemap = [l for (l in getLineLocations(fdata))]; |
|
169 |
|
170 if (loc.line >= linemap.length) { |
|
171 warning("Location larger than actual header: " + loc); |
|
172 return <></>; |
|
173 } |
|
174 |
|
175 let endpos = linemap[loc.line - 1] + loc.column - 1; |
|
176 let semipos = fdata.lastIndexOf(';', endpos); |
|
177 let bracepos = fdata.lastIndexOf('}', endpos); |
|
178 let searchslice = fdata.slice(Math.max(semipos, bracepos) + 1, endpos); |
|
179 |
|
180 let m = searchslice.match(/\/\*\*[\s\S]*?\*\//gm); |
|
181 if (m === null) |
|
182 return <></>; |
|
183 |
|
184 let dc = m[m.length - 1].slice(3, -2); |
|
185 dc = dc.replace(/^\s*(\*+[ \t]*)?/gm, ""); |
|
186 |
|
187 return <pre class="doccomment">{dc}</pre>; |
|
188 } |
|
189 |
|
190 function typeName(t) |
|
191 { |
|
192 if (t.name !== undefined) |
|
193 return t.name; |
|
194 |
|
195 if (t.isPointer) |
|
196 return "%s%s*".format(t.isConst ? "const " : "", typeName(t.type)); |
|
197 |
|
198 if (t.isReference) |
|
199 return "%s%s&".format(t.isConst ? "const " : "", typeName(t.type)); |
|
200 |
|
201 return t.toString(); |
|
202 } |
|
203 |
|
204 function publicBaseList(t) |
|
205 { |
|
206 let l = <ul/>; |
|
207 for each (let b in t.bases) { |
|
208 if (b.access == 'public') |
|
209 l.* += <li><a href={"/en/%s".format(b.type.name)}>{b.type.name}</a></li>; |
|
210 } |
|
211 |
|
212 if (l.*.length() == 0) |
|
213 return <></>; |
|
214 |
|
215 return <> |
|
216 <h2>Base Classes</h2> |
|
217 {l} |
|
218 </>; |
|
219 } |
|
220 |
|
221 /** |
|
222 * Get a source-link for a given location. |
|
223 */ |
|
224 function getLocLink(loc, text) |
|
225 { |
|
226 return <a class="loc" |
|
227 href={"http://hg.mozilla.org/mozilla-central/file/%s/[LOC%s]#l%i".format(options.rev, loc.file, loc.line)}>{text}</a>; |
|
228 } |
|
229 |
|
230 function dumpType(t) |
|
231 { |
|
232 print("DUMP-TYPE(%s)".format(t.name)); |
|
233 |
|
234 let methodOverview = <tbody />; |
|
235 let methodList = <div/>; |
|
236 let memberList = <></>; |
|
237 |
|
238 let shortNameMap = {}; |
|
239 |
|
240 let members = [m for (m in publicMembers(t))]; |
|
241 |
|
242 removeOverrides(members); |
|
243 |
|
244 for each (let m in members) { |
|
245 let qname = m.memberOf.name + '::'; |
|
246 |
|
247 // we don't inherit constructors from base classes |
|
248 if (m.isConstructor && m.memberOf !== t) |
|
249 continue; |
|
250 |
|
251 if (m.name.indexOf(qname) != 0) |
|
252 throw Error("Member name not qualified?"); |
|
253 |
|
254 let name = m.name.slice(qname.length); |
|
255 |
|
256 if (name.indexOf('~') == 0) |
|
257 continue; |
|
258 |
|
259 if (m.isFunction) { |
|
260 let innerList; |
|
261 |
|
262 let shortName = getShortName(m); |
|
263 if (m.isConstructor) |
|
264 shortName = 'Constructors'; |
|
265 |
|
266 if (shortNameMap.hasOwnProperty(shortName)) { |
|
267 innerList = shortNameMap[shortName]; |
|
268 } |
|
269 else { |
|
270 let overview = |
|
271 <tr><td> |
|
272 <a href={'#%s'.format(escape(shortName))}>{shortName}</a> |
|
273 </td></tr>; |
|
274 |
|
275 if (m.isConstructor) |
|
276 methodOverview.insertChildAfter(null, overview); |
|
277 else |
|
278 methodOverview.appendChild(overview); |
|
279 |
|
280 let shortMarkup = |
|
281 <div> |
|
282 <h3 id={shortName}>{shortName}</h3> |
|
283 <dl/> |
|
284 </div>; |
|
285 |
|
286 |
|
287 if (m.isConstructor) |
|
288 methodList.insertChildAfter(null, shortMarkup); |
|
289 else |
|
290 methodList.appendChild(shortMarkup); |
|
291 |
|
292 innerList = shortMarkup.dl; |
|
293 shortNameMap[shortName] = innerList; |
|
294 } |
|
295 |
|
296 let parameters = <ul/>; |
|
297 for each (p in m.parameters) { |
|
298 let name = p.name; |
|
299 if (name == 'this') |
|
300 continue; |
|
301 |
|
302 if (/^D_\d+$/.test(name)) |
|
303 name = '<anonymous>'; |
|
304 |
|
305 parameters.* += <li>{typeName(p.type)} {name}</li>; |
|
306 } |
|
307 |
|
308 innerList.* += |
|
309 <> |
|
310 <dt id={name} class="methodName"> |
|
311 <code>{typeName(m.type.type)} {name}</code> - {getLocLink(m.loc, "source")} |
|
312 </dt> |
|
313 <dd> |
|
314 {getDocComment(m.loc)} |
|
315 {parameters.*.length() > 0 ? |
|
316 <> |
|
317 <h4>Parameters</h4> |
|
318 {parameters} |
|
319 </> : <></>} |
|
320 </dd> |
|
321 </>; |
|
322 } |
|
323 else { |
|
324 memberList += <li class="member">{name}</li>; |
|
325 } |
|
326 } |
|
327 |
|
328 let r = |
|
329 <body> |
|
330 <p>{getLocLink(t.loc, "Class Declaration")}</p> |
|
331 |
|
332 {getDocComment(t.loc)} |
|
333 |
|
334 {dumpTypes.some(function(n) n == t.name) ? |
|
335 <> |
|
336 [MAP{t.name}-graph.map] |
|
337 <img src={"/@api/deki/pages/=en%%252F%s/files/=%s-graph.png".format(t.name, t.name)} usemap="#classes" /> |
|
338 </> : <></> |
|
339 } |
|
340 |
|
341 {methodOverview.*.length() > 0 ? |
|
342 <> |
|
343 <h2>Method Overview</h2> |
|
344 <table class="standard-table">{methodOverview}</table> |
|
345 </> : |
|
346 "" |
|
347 } |
|
348 |
|
349 {publicBaseList(t)} |
|
350 |
|
351 <h2>Data Members</h2> |
|
352 |
|
353 {memberList.*.length() > 0 ? |
|
354 memberList : |
|
355 <p><em>No public members.</em></p> |
|
356 } |
|
357 |
|
358 <h2>Methods</h2> |
|
359 |
|
360 {methodList.*.length() > 0 ? |
|
361 methodList : |
|
362 <p><em>No public methods.</em></p> |
|
363 } |
|
364 |
|
365 </body>; |
|
366 |
|
367 write_file(t.name + ".html", r.toXMLString()); |
|
368 } |
|
369 |
|
370 function graphType(t) |
|
371 { |
|
372 print("GRAPH-TYPE(%s)".format(t.name)); |
|
373 |
|
374 let contents = "digraph classes {\n" |
|
375 + " node [shape=rectangle fontsize=11]\n" |
|
376 + " %s;\n".format(t.name); |
|
377 |
|
378 function graphClass(c) |
|
379 { |
|
380 contents += '%s [URL="http://developer.mozilla.org/en/%s"]\n'.format(c.name, c.name); |
|
381 |
|
382 for each (let st in c.subtypes) { |
|
383 contents += " %s -> %s;\n".format(c.name, st.name); |
|
384 graphClass(st); |
|
385 } |
|
386 } |
|
387 |
|
388 graphClass(t); |
|
389 |
|
390 contents += "}\n"; |
|
391 |
|
392 write_file(t.name + "-graph.gv", contents); |
|
393 } |
|
394 |
|
395 function input_end() |
|
396 { |
|
397 for (let p in typelist) |
|
398 dumpType(typelist[p]); |
|
399 |
|
400 for (let n in interestingList) |
|
401 graphType(interestingList[n]); |
|
402 } |