Doxygen
Loading...
Searching...
No Matches
sqlite3gen.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2015 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16// own header
17#include "sqlite3gen.h"
18
19// standard includes
20#include <sys/stat.h>
21#include <string.h>
22#include <sqlite3.h>
23
24// other includes
25#include "arguments.h"
26#include "classlist.h"
27#include "conceptdef.h"
28#include "config.h"
29#include "datetime.h"
30#include "dir.h"
31#include "docnode.h"
32#include "docparser.h"
33#include "doxygen.h"
34#include "filedef.h"
35#include "fileinfo.h"
36#include "filename.h"
37#include "groupdef.h"
38#include "memberdef.h"
39#include "membername.h"
40#include "message.h"
41#include "moduledef.h"
42#include "namespacedef.h"
43#include "outputlist.h"
44#include "pagedef.h"
45#include "util.h"
46#include "version.h"
47#include "xmldocvisitor.h"
48
49
50// enable to show general debug messages
51// #define SQLITE3_DEBUG
52
53// enable to print all executed SQL statements.
54// I recommend using the smallest possible input list.
55// #define SQLITE3_DEBUG_SQL
56
57# ifdef SQLITE3_DEBUG
58# define DBG_CTX(x) printf x
59# else // SQLITE3_DEBUG
60# define DBG_CTX(x) do { } while(0)
61# endif
62
63# ifdef SQLITE3_DEBUG_SQL
64// used by sqlite3_trace in generateSqlite3()
65static void sqlLog(void *dbName, const char *sql){
66 msg("SQL: '{}'\n", sql);
67}
68# endif
69
70const char * table_schema[][2] = {
71 /* TABLES */
72 { "meta",
73 "CREATE TABLE IF NOT EXISTS meta (\n"
74 "\t-- Information about this db and how it was generated.\n"
75 "\t-- Doxygen info\n"
76 "\tdoxygen_version TEXT PRIMARY KEY NOT NULL,\n"
77 /*
78 Doxygen's version is likely to rollover much faster than the schema, and
79 at least until it becomes a core output format, we might want to make
80 fairly large schema changes even on minor iterations for Doxygen itself.
81 If these tools just track a predefined semver schema version that can
82 iterate independently, it *might* not be as hard to keep them in sync?
83 */
84 "\tschema_version TEXT NOT NULL, -- Schema-specific semver\n"
85 "\t-- run info\n"
86 "\tgenerated_at TEXT NOT NULL,\n"
87 "\tgenerated_on TEXT NOT NULL,\n"
88 "\t-- project info\n"
89 "\tproject_name TEXT NOT NULL,\n"
90 "\tproject_number TEXT,\n"
91 "\tproject_brief TEXT\n"
92 ");"
93 },
94 { "includes",
95 "CREATE TABLE IF NOT EXISTS includes (\n"
96 "\t-- #include relations.\n"
97 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
98 "\tlocal INTEGER NOT NULL,\n"
99 "\tsrc_id INTEGER NOT NULL REFERENCES path, -- File id of the includer.\n"
100 "\tdst_id INTEGER NOT NULL REFERENCES path, -- File id of the includee.\n"
101 /*
102 In theory we could include name here to be informationally equivalent
103 with the XML, but I don't see an obvious use for it.
104 */
105 "\tUNIQUE(local, src_id, dst_id) ON CONFLICT IGNORE\n"
106 ");"
107 },
108 { "contains",
109 "CREATE TABLE IF NOT EXISTS contains (\n"
110 "\t-- inner/outer relations (file, namespace, dir, class, group, page)\n"
111 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
112 "\tinner_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
113 "\touter_rowid INTEGER NOT NULL REFERENCES compounddef\n"
114 ");"
115 },
116 /* TODO: Path can also share rowids with refid/compounddef/def. (It could
117 * even collapse into that table...)
118 *
119 * I took a first swing at this by changing insertPath() to:
120 * - accept a FileDef
121 * - make its own call to insertRefid
122 * - return a refid struct.
123 *
124 * I rolled this back when I had trouble getting a FileDef for all types
125 * (PageDef in particular).
126 *
127 * Note: all columns referencing path would need an update.
128 */
129 { "path",
130 "CREATE TABLE IF NOT EXISTS path (\n"
131 "\t-- Paths of source files and includes.\n"
132 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
133 "\ttype INTEGER NOT NULL, -- 1:file 2:dir\n"
134 "\tlocal INTEGER NOT NULL,\n"
135 "\tfound INTEGER NOT NULL,\n"
136 "\tname TEXT NOT NULL\n"
137 ");"
138 },
139 { "refid",
140 "CREATE TABLE IF NOT EXISTS refid (\n"
141 "\t-- Distinct refid for all documented entities.\n"
142 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
143 "\trefid TEXT NOT NULL UNIQUE\n"
144 ");"
145 },
146 { "xrefs",
147 "CREATE TABLE IF NOT EXISTS xrefs (\n"
148 "\t-- Cross-reference relation\n"
149 "\t-- (combines xml <referencedby> and <references> nodes).\n"
150 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
151 "\tsrc_rowid INTEGER NOT NULL REFERENCES refid, -- referrer id.\n"
152 "\tdst_rowid INTEGER NOT NULL REFERENCES refid, -- referee id.\n"
153 "\tcontext TEXT NOT NULL, -- inline, argument, initializer\n"
154 "\t-- Just need to know they link; ignore duplicates.\n"
155 "\tUNIQUE(src_rowid, dst_rowid, context) ON CONFLICT IGNORE\n"
156 ");\n"
157 },
158 { "memberdef",
159 "CREATE TABLE IF NOT EXISTS memberdef (\n"
160 "\t-- All processed identifiers.\n"
161 "\trowid INTEGER PRIMARY KEY NOT NULL,\n"
162 "\tname TEXT NOT NULL,\n"
163 "\tdefinition TEXT,\n"
164 "\ttype TEXT,\n"
165 "\targsstring TEXT,\n"
166 "\tscope TEXT,\n"
167 "\tinitializer TEXT,\n"
168 "\tbitfield TEXT,\n"
169 "\tread TEXT,\n"
170 "\twrite TEXT,\n"
171 "\tprot INTEGER DEFAULT 0, -- 0:public 1:protected 2:private 3:package\n"
172 "\tstatic INTEGER DEFAULT 0, -- 0:no 1:yes\n"
173 "\textern INTEGER DEFAULT 0, -- 0:no 1:yes\n"
174 "\tconst INTEGER DEFAULT 0, -- 0:no 1:yes\n"
175 "\texplicit INTEGER DEFAULT 0, -- 0:no 1:yes\n"
176 "\tinline INTEGER DEFAULT 0, -- 0:no 1:yes 2:both (set after encountering inline and not-inline)\n"
177 "\tfinal INTEGER DEFAULT 0, -- 0:no 1:yes\n"
178 "\tsealed INTEGER DEFAULT 0, -- 0:no 1:yes\n"
179 "\tnew INTEGER DEFAULT 0, -- 0:no 1:yes\n"
180 "\toptional INTEGER DEFAULT 0, -- 0:no 1:yes\n"
181 "\trequired INTEGER DEFAULT 0, -- 0:no 1:yes\n"
182 "\tvolatile INTEGER DEFAULT 0, -- 0:no 1:yes\n"
183 "\tvirt INTEGER DEFAULT 0, -- 0:no 1:virtual 2:pure-virtual\n"
184 "\tmutable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
185 "\tthread_local INTEGER DEFAULT 0, -- 0:no 1:yes\n"
186 "\tinitonly INTEGER DEFAULT 0, -- 0:no 1:yes\n"
187 "\tattribute INTEGER DEFAULT 0, -- 0:no 1:yes\n"
188 "\tproperty INTEGER DEFAULT 0, -- 0:no 1:yes\n"
189 "\treadonly INTEGER DEFAULT 0, -- 0:no 1:yes\n"
190 "\tbound INTEGER DEFAULT 0, -- 0:no 1:yes\n"
191 "\tconstrained INTEGER DEFAULT 0, -- 0:no 1:yes\n"
192 "\ttransient INTEGER DEFAULT 0, -- 0:no 1:yes\n"
193 "\tmaybevoid INTEGER DEFAULT 0, -- 0:no 1:yes\n"
194 "\tmaybedefault INTEGER DEFAULT 0, -- 0:no 1:yes\n"
195 "\tmaybeambiguous INTEGER DEFAULT 0, -- 0:no 1:yes\n"
196 "\treadable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
197 "\twritable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
198 "\tgettable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
199 "\tprivategettable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
200 "\tprotectedgettable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
201 "\tsettable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
202 "\tprivatesettable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
203 "\tprotectedsettable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
204 "\taccessor INTEGER DEFAULT 0, -- 0:no 1:assign 2:copy 3:retain 4:string 5:weak\n"
205 "\taddable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
206 "\tremovable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
207 "\traisable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
208 "\tkind TEXT NOT NULL, -- 'macro definition' 'function' 'variable' 'typedef' 'enumeration' 'enumvalue' 'signal' 'slot' 'friend' 'dcop' 'property' 'event' 'interface' 'service'\n"
209 "\tbodystart INTEGER DEFAULT 0, -- starting line of definition\n"
210 "\tbodyend INTEGER DEFAULT 0, -- ending line of definition\n"
211 "\tbodyfile_id INTEGER REFERENCES path, -- file of definition\n"
212 "\tfile_id INTEGER NOT NULL REFERENCES path, -- file where this identifier is located\n"
213 "\tline INTEGER NOT NULL, -- line where this identifier is located\n"
214 "\tcolumn INTEGER NOT NULL, -- column where this identifier is located\n"
215 "\tdetaileddescription TEXT,\n"
216 "\tbriefdescription TEXT,\n"
217 "\tinbodydescription TEXT,\n"
218 "\tFOREIGN KEY (rowid) REFERENCES refid (rowid)\n"
219 ");"
220 },
221 { "member",
222 "CREATE TABLE IF NOT EXISTS member (\n"
223 "\t-- Memberdef <-> containing compound relation.\n"
224 "\t-- Similar to XML listofallmembers.\n"
225 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
226 "\tscope_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
227 "\tmemberdef_rowid INTEGER NOT NULL REFERENCES memberdef,\n"
228 "\tprot INTEGER NOT NULL,\n"
229 "\tvirt INTEGER NOT NULL,\n"
230 "\tUNIQUE(scope_rowid, memberdef_rowid)\n"
231 ");"
232 },
233 { "reimplements",
234 "CREATE TABLE IF NOT EXISTS reimplements (\n"
235 "\t-- Inherited member reimplementation relations.\n"
236 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
237 "\tmemberdef_rowid INTEGER NOT NULL REFERENCES memberdef, -- reimplementing memberdef id.\n"
238 "\treimplemented_rowid INTEGER NOT NULL REFERENCES memberdef, -- reimplemented memberdef id.\n"
239 "\tUNIQUE(memberdef_rowid, reimplemented_rowid) ON CONFLICT IGNORE\n"
240 ");\n"
241 },
242 { "compounddef",
243 "CREATE TABLE IF NOT EXISTS compounddef (\n"
244 "\t-- Class/struct definitions.\n"
245 "\trowid INTEGER PRIMARY KEY NOT NULL,\n"
246 "\tname TEXT NOT NULL,\n"
247 "\ttitle TEXT,\n"
248 // probably won't be empty '' or unknown, but the source *could* return them...
249 "\tkind TEXT NOT NULL, -- 'category' 'class' 'constants' 'dir' 'enum' 'example' 'exception' 'file' 'group' 'interface' 'library' 'module' 'namespace' 'package' 'page' 'protocol' 'service' 'singleton' 'struct' 'type' 'union' 'unknown' ''\n"
250 "\tprot INTEGER,\n"
251 "\tfile_id INTEGER NOT NULL REFERENCES path,\n"
252 "\tline INTEGER NOT NULL,\n"
253 "\tcolumn INTEGER NOT NULL,\n"
254 "\theader_id INTEGER REFERENCES path,\n"
255 "\tdetaileddescription TEXT,\n"
256 "\tbriefdescription TEXT,\n"
257 "\tFOREIGN KEY (rowid) REFERENCES refid (rowid)\n"
258 ");"
259 },
260 { "compoundref",
261 "CREATE TABLE IF NOT EXISTS compoundref (\n"
262 "\t-- Inheritance relation.\n"
263 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
264 "\tbase_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
265 "\tderived_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
266 "\tprot INTEGER NOT NULL,\n"
267 "\tvirt INTEGER NOT NULL,\n"
268 "\tUNIQUE(base_rowid, derived_rowid)\n"
269 ");"
270 },
271 { "param",
272 "CREATE TABLE IF NOT EXISTS param (\n"
273 "\t-- All processed parameters.\n"
274 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
275 "\tattributes TEXT,\n"
276 "\ttype TEXT,\n"
277 "\tdeclname TEXT,\n"
278 "\tdefname TEXT,\n"
279 "\tarray TEXT,\n"
280 "\tdefval TEXT,\n"
281 "\tbriefdescription TEXT\n"
282 ");"
283 "CREATE UNIQUE INDEX idx_param ON param\n"
284 "\t(type, defname);"
285 },
286 { "memberdef_param",
287 "CREATE TABLE IF NOT EXISTS memberdef_param (\n"
288 "\t-- Junction table for memberdef parameters.\n"
289 "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
290 "\tmemberdef_id INTEGER NOT NULL REFERENCES memberdef,\n"
291 "\tparam_id INTEGER NOT NULL REFERENCES param\n"
292 ");"
293 },
294};
295 const char * view_schema[][2] = {
296 /* VIEWS *
297 We'll set these up AFTER we build the database, so that they can be indexed,
298 but so we don't have to pay a performance penalty for inserts as we build.
299 */
300 {
301 /*
302 Makes all reference/relation tables easier to use. For example:
303 1. query xrefs and join this view on either xrefs.dst_rowid=def.rowid or
304 xrefs.src_rowid=def.rowid
305 2. get everything you need to output a list of references to/from an entity
306
307 Also supports simple name search/lookup for both compound and member types.
308
309 NOTES:
310 - summary for compounds generalizes title and briefdescription because
311 there's no single field that works as a quick introduction for both
312 pages and classes
313 - May be value in eventually extending this to fulltext or levenshtein
314 distance-driven lookup/search, but I'm avoiding these for now as it
315 takes some effort to enable them.
316 */
317 "def",
318 "CREATE VIEW IF NOT EXISTS def (\n"
319 "\t-- Combined summary of all -def types for easier joins.\n"
320 "\trowid,\n"
321 "\trefid,\n"
322 "\tkind,\n"
323 "\tname,\n"
324 "\tsummary"
325 ")\n"
326 "as SELECT \n"
327 "\trefid.rowid,\n"
328 "\trefid.refid,\n"
329 "\tmemberdef.kind,\n"
330 "\tmemberdef.name,\n"
331 "\tmemberdef.briefdescription \n"
332 "FROM refid \n"
333 "JOIN memberdef ON refid.rowid=memberdef.rowid \n"
334 "UNION ALL \n"
335 "SELECT \n"
336 "\trefid.rowid,\n"
337 "\trefid.refid,\n"
338 "\tcompounddef.kind,\n"
339 "\tcompounddef.name,\n"
340 "\tCASE \n"
341 "\t\tWHEN briefdescription IS NOT NULL \n"
342 "\t\tTHEN briefdescription \n"
343 "\t\tELSE title \n"
344 "\tEND summary\n"
345 "FROM refid \n"
346 "JOIN compounddef ON refid.rowid=compounddef.rowid;"
347 },
348 {
349 "local_file",
350 "CREATE VIEW IF NOT EXISTS local_file (\n"
351 "\t-- File paths found within the project.\n"
352 "\trowid,\n"
353 "\tfound,\n"
354 "\tname\n"
355 ")\n"
356 "as SELECT \n"
357 "\tpath.rowid,\n"
358 "\tpath.found,\n"
359 "\tpath.name\n"
360 "FROM path WHERE path.type=1 AND path.local=1 AND path.found=1;\n"
361 },
362 {
363 "external_file",
364 "CREATE VIEW IF NOT EXISTS external_file (\n"
365 "\t-- File paths outside the project (found or not).\n"
366 "\trowid,\n"
367 "\tfound,\n"
368 "\tname\n"
369 ")\n"
370 "as SELECT \n"
371 "\tpath.rowid,\n"
372 "\tpath.found,\n"
373 "\tpath.name\n"
374 "FROM path WHERE path.type=1 AND path.local=0;\n"
375 },
376 {
377 "inline_xrefs",
378 "CREATE VIEW IF NOT EXISTS inline_xrefs (\n"
379 "\t-- Crossrefs from inline member source.\n"
380 "\trowid,\n"
381 "\tsrc_rowid,\n"
382 "\tdst_rowid\n"
383 ")\n"
384 "as SELECT \n"
385 "\txrefs.rowid,\n"
386 "\txrefs.src_rowid,\n"
387 "\txrefs.dst_rowid\n"
388 "FROM xrefs WHERE xrefs.context='inline';\n"
389 },
390 {
391 "argument_xrefs",
392 "CREATE VIEW IF NOT EXISTS argument_xrefs (\n"
393 "\t-- Crossrefs from member def/decl arguments\n"
394 "\trowid,\n"
395 "\tsrc_rowid,\n"
396 "\tdst_rowid\n"
397 ")\n"
398 "as SELECT \n"
399 "\txrefs.rowid,\n"
400 "\txrefs.src_rowid,\n"
401 "\txrefs.dst_rowid\n"
402 "FROM xrefs WHERE xrefs.context='argument';\n"
403 },
404 {
405 "initializer_xrefs",
406 "CREATE VIEW IF NOT EXISTS initializer_xrefs (\n"
407 "\t-- Crossrefs from member initializers\n"
408 "\trowid,\n"
409 "\tsrc_rowid,\n"
410 "\tdst_rowid\n"
411 ")\n"
412 "as SELECT \n"
413 "\txrefs.rowid,\n"
414 "\txrefs.src_rowid,\n"
415 "\txrefs.dst_rowid\n"
416 "FROM xrefs WHERE xrefs.context='initializer';\n"
417 },
418 {
419 "inner_outer",
420 "CREATE VIEW IF NOT EXISTS inner_outer\n"
421 "\t-- Joins 'contains' relations to simplify inner/outer 'rel' queries.\n"
422 "as SELECT \n"
423 "\tinner.*,\n"
424 "\touter.*\n"
425 "FROM def as inner\n"
426 "\tJOIN contains ON inner.rowid=contains.inner_rowid\n"
427 "\tJOIN def AS outer ON outer.rowid=contains.outer_rowid;\n"
428 },
429 {
430 "rel",
431 "CREATE VIEW IF NOT EXISTS rel (\n"
432 "\t-- Boolean indicator of relations available for a given entity.\n"
433 "\t-- Join to (compound-|member-)def to find fetch-worthy relations.\n"
434 "\trowid,\n"
435 "\treimplemented,\n"
436 "\treimplements,\n"
437 "\tinnercompounds,\n"
438 "\toutercompounds,\n"
439 "\tinnerpages,\n"
440 "\touterpages,\n"
441 "\tinnerdirs,\n"
442 "\touterdirs,\n"
443 "\tinnerfiles,\n"
444 "\touterfiles,\n"
445 "\tinnerclasses,\n"
446 "\touterclasses,\n"
447 "\tinnernamespaces,\n"
448 "\touternamespaces,\n"
449 "\tinnergroups,\n"
450 "\toutergroups,\n"
451 "\tmembers,\n"
452 "\tcompounds,\n"
453 "\tsubclasses,\n"
454 "\tsuperclasses,\n"
455 "\tlinks_in,\n"
456 "\tlinks_out,\n"
457 "\targument_links_in,\n"
458 "\targument_links_out,\n"
459 "\tinitializer_links_in,\n"
460 "\tinitializer_links_out\n"
461 ")\n"
462 "as SELECT \n"
463 "\tdef.rowid,\n"
464 "\tEXISTS (SELECT rowid FROM reimplements WHERE reimplemented_rowid=def.rowid),\n"
465 "\tEXISTS (SELECT rowid FROM reimplements WHERE memberdef_rowid=def.rowid),\n"
466 "\t-- rowid/kind for inner, [rowid:1/kind:1] for outer\n"
467 "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid),\n"
468 "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid),\n"
469 "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='page'),\n"
470 "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='page'),\n"
471 "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='dir'),\n"
472 "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='dir'),\n"
473 "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='file'),\n"
474 "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='file'),\n"
475 "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind in (\n"
476 "'category','class','enum','exception','interface','module','protocol',\n"
477 "'service','singleton','struct','type','union'\n"
478 ")),\n"
479 "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1] in (\n"
480 "'category','class','enum','exception','interface','module','protocol',\n"
481 "'service','singleton','struct','type','union'\n"
482 ")),\n"
483 "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='namespace'),\n"
484 "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='namespace'),\n"
485 "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='group'),\n"
486 "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='group'),\n"
487 "\tEXISTS (SELECT rowid FROM member WHERE scope_rowid=def.rowid),\n"
488 "\tEXISTS (SELECT rowid FROM member WHERE memberdef_rowid=def.rowid),\n"
489 "\tEXISTS (SELECT rowid FROM compoundref WHERE base_rowid=def.rowid),\n"
490 "\tEXISTS (SELECT rowid FROM compoundref WHERE derived_rowid=def.rowid),\n"
491 "\tEXISTS (SELECT rowid FROM inline_xrefs WHERE dst_rowid=def.rowid),\n"
492 "\tEXISTS (SELECT rowid FROM inline_xrefs WHERE src_rowid=def.rowid),\n"
493 "\tEXISTS (SELECT rowid FROM argument_xrefs WHERE dst_rowid=def.rowid),\n"
494 "\tEXISTS (SELECT rowid FROM argument_xrefs WHERE src_rowid=def.rowid),\n"
495 "\tEXISTS (SELECT rowid FROM initializer_xrefs WHERE dst_rowid=def.rowid),\n"
496 "\tEXISTS (SELECT rowid FROM initializer_xrefs WHERE src_rowid=def.rowid)\n"
497 "FROM def ORDER BY def.rowid;"
498 }
499};
500
501//////////////////////////////////////////////////////
502struct SqlStmt {
503 const char *query = nullptr;
504 sqlite3_stmt *stmt = nullptr;
505 sqlite3 *db = nullptr;
506};
507//////////////////////////////////////////////////////
508/* If you add a new statement below, make sure to add it to
509 prepareStatements(). If sqlite3 is segfaulting (especially in
510 sqlite3_clear_bindings()), using an un-prepared statement may
511 be the cause. */
513 "INSERT INTO meta "
514 "( doxygen_version, schema_version, generated_at, generated_on, project_name, project_number, project_brief )"
515 "VALUES "
516 "(:doxygen_version,:schema_version,:generated_at,:generated_on,:project_name,:project_number,:project_brief )"
517 ,nullptr
518};
519//////////////////////////////////////////////////////
521 "INSERT INTO includes "
522 "( local, src_id, dst_id ) "
523 "VALUES "
524 "(:local,:src_id,:dst_id )"
525 ,nullptr
526};
528 "SELECT COUNT(*) FROM includes WHERE "
529 "local=:local AND src_id=:src_id AND dst_id=:dst_id"
530 ,nullptr
531};
532//////////////////////////////////////////////////////
534 "INSERT INTO contains "
535 "( inner_rowid, outer_rowid )"
536 "VALUES "
537 "(:inner_rowid,:outer_rowid )"
538 ,nullptr
539};
540//////////////////////////////////////////////////////
542 "SELECT rowid FROM path WHERE name=:name"
543 ,nullptr
544};
546 "INSERT INTO path "
547 "( type, local, found, name )"
548 "VALUES "
549 "(:type,:local,:found,:name )"
550 ,nullptr
551};
552//////////////////////////////////////////////////////
554 "SELECT rowid FROM refid WHERE refid=:refid"
555 ,nullptr
556};
558 "INSERT INTO refid "
559 "( refid )"
560 "VALUES "
561 "(:refid )"
562 ,nullptr
563};
564//////////////////////////////////////////////////////
566 "INSERT INTO xrefs "
567 "( src_rowid, dst_rowid, context )"
568 "VALUES "
569 "(:src_rowid,:dst_rowid,:context )"
570 ,nullptr
571};//////////////////////////////////////////////////////
573 "INSERT INTO reimplements "
574 "( memberdef_rowid, reimplemented_rowid )"
575 "VALUES "
576 "(:memberdef_rowid,:reimplemented_rowid )"
577 ,nullptr
578};
579//////////////////////////////////////////////////////
581 "SELECT EXISTS (SELECT * FROM memberdef WHERE rowid = :rowid)"
582 ,nullptr
583};
584
586 "SELECT EXISTS ("
587 "SELECT * FROM memberdef WHERE "
588 "rowid = :rowid AND inline != 2 AND inline != :new_inline"
589 ")"
590 ,nullptr
591};
592
594 "INSERT INTO memberdef "
595 "("
596 "rowid,"
597 "name,"
598 "definition,"
599 "type,"
600 "argsstring,"
601 "scope,"
602 "initializer,"
603 "bitfield,"
604 "read,"
605 "write,"
606 "prot,"
607 "static,"
608 "extern,"
609 "const,"
610 "explicit,"
611 "inline,"
612 "final,"
613 "sealed,"
614 "new,"
615 "optional,"
616 "required,"
617 "volatile,"
618 "virt,"
619 "mutable,"
620 "thread_local,"
621 "initonly,"
622 "attribute,"
623 "property,"
624 "readonly,"
625 "bound,"
626 "constrained,"
627 "transient,"
628 "maybevoid,"
629 "maybedefault,"
630 "maybeambiguous,"
631 "readable,"
632 "writable,"
633 "gettable,"
634 "protectedsettable,"
635 "protectedgettable,"
636 "settable,"
637 "privatesettable,"
638 "privategettable,"
639 "accessor,"
640 "addable,"
641 "removable,"
642 "raisable,"
643 "kind,"
644 "bodystart,"
645 "bodyend,"
646 "bodyfile_id,"
647 "file_id,"
648 "line,"
649 "column,"
650 "detaileddescription,"
651 "briefdescription,"
652 "inbodydescription"
653 ")"
654 "VALUES "
655 "("
656 ":rowid,"
657 ":name,"
658 ":definition,"
659 ":type,"
660 ":argsstring,"
661 ":scope,"
662 ":initializer,"
663 ":bitfield,"
664 ":read,"
665 ":write,"
666 ":prot,"
667 ":static,"
668 ":extern,"
669 ":const,"
670 ":explicit,"
671 ":inline,"
672 ":final,"
673 ":sealed,"
674 ":new,"
675 ":optional,"
676 ":required,"
677 ":volatile,"
678 ":virt,"
679 ":mutable,"
680 ":thread_local,"
681 ":initonly,"
682 ":attribute,"
683 ":property,"
684 ":readonly,"
685 ":bound,"
686 ":constrained,"
687 ":transient,"
688 ":maybevoid,"
689 ":maybedefault,"
690 ":maybeambiguous,"
691 ":readable,"
692 ":writable,"
693 ":gettable,"
694 ":protectedsettable,"
695 ":protectedgettable,"
696 ":settable,"
697 ":privatesettable,"
698 ":privategettable,"
699 ":accessor,"
700 ":addable,"
701 ":removable,"
702 ":raisable,"
703 ":kind,"
704 ":bodystart,"
705 ":bodyend,"
706 ":bodyfile_id,"
707 ":file_id,"
708 ":line,"
709 ":column,"
710 ":detaileddescription,"
711 ":briefdescription,"
712 ":inbodydescription"
713 ")"
714 ,nullptr
715};
716/*
717We have a slightly different need than the XML here. The XML can have two
718memberdef nodes with the same refid to document the declaration and the
719definition. This doesn't play very nice with a referential model. It isn't a
720big issue if only one is documented, but in case both are, we'll fall back on
721this kludge to combine them in a single row...
722*/
724 "UPDATE memberdef SET "
725 "inline = :inline,"
726 "file_id = :file_id,"
727 "line = :line,"
728 "column = :column,"
729 "detaileddescription = 'Declaration: ' || :detaileddescription || 'Definition: ' || detaileddescription,"
730 "briefdescription = 'Declaration: ' || :briefdescription || 'Definition: ' || briefdescription,"
731 "inbodydescription = 'Declaration: ' || :inbodydescription || 'Definition: ' || inbodydescription "
732 "WHERE rowid = :rowid"
733 ,nullptr
734};
736 "UPDATE memberdef SET "
737 "inline = :inline,"
738 "bodystart = :bodystart,"
739 "bodyend = :bodyend,"
740 "bodyfile_id = :bodyfile_id,"
741 "detaileddescription = 'Declaration: ' || detaileddescription || 'Definition: ' || :detaileddescription,"
742 "briefdescription = 'Declaration: ' || briefdescription || 'Definition: ' || :briefdescription,"
743 "inbodydescription = 'Declaration: ' || inbodydescription || 'Definition: ' || :inbodydescription "
744 "WHERE rowid = :rowid"
745 ,nullptr
746};
747//////////////////////////////////////////////////////
749 "INSERT INTO member "
750 "( scope_rowid, memberdef_rowid, prot, virt ) "
751 "VALUES "
752 "(:scope_rowid,:memberdef_rowid,:prot,:virt )"
753 ,nullptr
754};
755//////////////////////////////////////////////////////
757 "INSERT INTO compounddef "
758 "("
759 "rowid,"
760 "name,"
761 "title,"
762 "kind,"
763 "prot,"
764 "file_id,"
765 "line,"
766 "column,"
767 "header_id,"
768 "briefdescription,"
769 "detaileddescription"
770 ")"
771 "VALUES "
772 "("
773 ":rowid,"
774 ":name,"
775 ":title,"
776 ":kind,"
777 ":prot,"
778 ":file_id,"
779 ":line,"
780 ":column,"
781 ":header_id,"
782 ":briefdescription,"
783 ":detaileddescription"
784 ")"
785 ,nullptr
786};
788 "SELECT EXISTS ("
789 "SELECT * FROM compounddef WHERE rowid = :rowid"
790 ")"
791 ,nullptr
792};
793//////////////////////////////////////////////////////
795 "INSERT INTO compoundref "
796 "( base_rowid, derived_rowid, prot, virt ) "
797 "VALUES "
798 "(:base_rowid,:derived_rowid,:prot,:virt )"
799 ,nullptr
800};
801//////////////////////////////////////////////////////
803 "SELECT rowid FROM param WHERE "
804 "(attributes IS NULL OR attributes=:attributes) AND "
805 "(type IS NULL OR type=:type) AND "
806 "(declname IS NULL OR declname=:declname) AND "
807 "(defname IS NULL OR defname=:defname) AND "
808 "(array IS NULL OR array=:array) AND "
809 "(defval IS NULL OR defval=:defval) AND "
810 "(briefdescription IS NULL OR briefdescription=:briefdescription)"
811 ,nullptr
812};
814 "INSERT INTO param "
815 "( attributes, type, declname, defname, array, defval, briefdescription ) "
816 "VALUES "
817 "(:attributes,:type,:declname,:defname,:array,:defval,:briefdescription)"
818 ,nullptr
819};
820//////////////////////////////////////////////////////
822 "INSERT INTO memberdef_param "
823 "( memberdef_id, param_id)"
824 "VALUES "
825 "(:memberdef_id,:param_id)"
826 ,nullptr
827};
828
830{
831 public:
833 void writeString(std::string_view /*s*/,bool /*keepSpaces*/) const override
834 {
835 }
836 void writeBreak(int) const override
837 {
838 DBG_CTX(("writeBreak\n"));
839 }
840 void writeLink(const DString & /*extRef*/,const DString &file,
841 const DString &anchor,std::string_view /*text*/
842 ) const override
843 {
844 std::string rs = file.str();
845 if (!anchor.empty())
846 {
847 rs+="_1";
848 rs+=anchor.str();
849 }
850 m_list.push_back(rs);
851 }
852 private:
854 // the list is filled by linkifyText and consumed by the caller
855};
856
857
858static bool bindTextParameter(SqlStmt &s,const char *name,const DString &value)
859{
860 int idx = sqlite3_bind_parameter_index(s.stmt, name);
861 if (idx==0) {
862 err("sqlite3_bind_parameter_index({})[{}] failed: {}\n", name, s.query, sqlite3_errmsg(s.db));
863 return false;
864 }
865 int rv = sqlite3_bind_text(s.stmt, idx, value.data(), -1, SQLITE_TRANSIENT);
866 if (rv!=SQLITE_OK) {
867 err("sqlite3_bind_text({})[{}] failed: {}\n", name, s.query, sqlite3_errmsg(s.db));
868 return false;
869 }
870 return true;
871}
872
873static bool bindIntParameter(SqlStmt &s,const char *name,int value)
874{
875 int idx = sqlite3_bind_parameter_index(s.stmt, name);
876 if (idx==0) {
877 err("sqlite3_bind_parameter_index({})[{}] failed to find column: {}\n", name, s.query, sqlite3_errmsg(s.db));
878 return false;
879 }
880 int rv = sqlite3_bind_int(s.stmt, idx, value);
881 if (rv!=SQLITE_OK) {
882 err("sqlite3_bind_int({})[{}] failed: {}\n", name, s.query, sqlite3_errmsg(s.db));
883 return false;
884 }
885 return true;
886}
887
888static bool bindIntParameter(SqlStmt &s,const char *name,size_t value)
889{
890 return bindIntParameter(s,name,static_cast<int>(value));
891}
892
893static int step(SqlStmt &s,bool getRowId=false, bool select=false)
894{
895 int rowid=-1;
896 int rc = sqlite3_step(s.stmt);
897 if (rc!=SQLITE_DONE && rc!=SQLITE_ROW)
898 {
899 DBG_CTX(("sqlite3_step: %s (rc: %d)\n", sqlite3_errmsg(s.db), rc));
900 sqlite3_reset(s.stmt);
901 sqlite3_clear_bindings(s.stmt);
902 return -1;
903 }
904 if (getRowId && select) rowid = sqlite3_column_int(s.stmt, 0); // works on selects, doesn't on inserts
905 if (getRowId && !select) rowid = static_cast<int>(sqlite3_last_insert_rowid(s.db)); //works on inserts, doesn't on selects
906 sqlite3_reset(s.stmt);
907 sqlite3_clear_bindings(s.stmt); // XXX When should this really be called
908 return rowid;
909}
910
911static int insertPath(DString name, bool local=true, bool found=true, int type=1)
912{
913 int rowid=-1;
914 if (name==nullptr) return rowid;
915
916 name = stripFromPath(name);
917
918 bindTextParameter(path_select,":name",name.data());
919 rowid=step(path_select,true,true);
920 if (rowid==0)
921 {
922 bindTextParameter(path_insert,":name",name.data());
923 bindIntParameter(path_insert,":type",type);
924 bindIntParameter(path_insert,":local",local?1:0);
925 bindIntParameter(path_insert,":found",found?1:0);
926 rowid=step(path_insert,true);
927 }
928 return rowid;
929}
930
931static void recordMetadata()
932{
933 bindTextParameter(meta_insert,":doxygen_version",getFullVersion());
934 bindTextParameter(meta_insert,":schema_version","0.2.1"); //TODO: this should be a constant somewhere; not sure where
937 bindTextParameter(meta_insert,":project_name",Config_getString(PROJECT_NAME));
938 bindTextParameter(meta_insert,":project_number",Config_getString(PROJECT_NUMBER));
939 bindTextParameter(meta_insert,":project_brief",Config_getString(PROJECT_BRIEF));
941}
942
943struct Refid {
944 int rowid;
947};
948
950{
951 Refid ret;
952 ret.rowid=-1;
953 ret.refid=refid;
954 ret.created = false;
955 if (refid.empty()) return ret;
956
958 ret.rowid=step(refid_select,true,true);
959 if (ret.rowid==0)
960 {
962 ret.rowid=step(refid_insert,true);
963 ret.created = true;
964 }
965
966 return ret;
967}
968
969static bool memberdefExists(struct Refid refid)
970{
972 int test = step(memberdef_exists,true,true);
973 return test ? true : false;
974}
975
976static bool memberdefIncomplete(struct Refid refid, const MemberDef* md)
977{
980 int test = step(memberdef_incomplete,true,true);
981 return test ? true : false;
982}
983
984static bool compounddefExists(struct Refid refid)
985{
987 int test = step(compounddef_exists,true,true);
988 return test ? true : false;
989}
990
991static bool insertMemberReference(struct Refid src_refid, struct Refid dst_refid, const char *context)
992{
993 if (src_refid.rowid==-1||dst_refid.rowid==-1)
994 return false;
995
996 if (
997 !bindIntParameter(xrefs_insert,":src_rowid",src_refid.rowid) ||
998 !bindIntParameter(xrefs_insert,":dst_rowid",dst_refid.rowid)
999 )
1000 {
1001 return false;
1002 }
1003 else
1004 {
1005 bindTextParameter(xrefs_insert,":context",context);
1006 }
1007
1009 return true;
1010}
1011
1012static void insertMemberReference(const MemberDef *src, const MemberDef *dst, const char *context)
1013{
1014 DString qdst_refid = dst->getOutputFileBase() + "_1" + dst->anchor();
1015 DString qsrc_refid = src->getOutputFileBase() + "_1" + src->anchor();
1016
1017 struct Refid src_refid = insertRefid(qsrc_refid);
1018 struct Refid dst_refid = insertRefid(qdst_refid);
1019 insertMemberReference(src_refid,dst_refid,context);
1020}
1021
1022static void insertMemberFunctionParams(int memberdef_id, const MemberDef *md, const Definition *def)
1023{
1024 LinkifyTextOptions options;
1025 options.setScope(def).setFileScope(md->getBodyDef()).setSelf(md);
1026 const ArgumentList &declAl = md->declArgumentList();
1027 const ArgumentList &defAl = md->argumentList();
1028 if (declAl.size()>0)
1029 {
1030 auto defIt = defAl.begin();
1031 for (const Argument &a : declAl)
1032 {
1033 //const Argument *defArg = defAli.current();
1034 const Argument *defArg = nullptr;
1035 if (defIt!=defAl.end())
1036 {
1037 defArg = &(*defIt);
1038 ++defIt;
1039 }
1040
1041 if (!a.attrib.empty())
1042 {
1043 bindTextParameter(param_select,":attributes",a.attrib);
1044 bindTextParameter(param_insert,":attributes",a.attrib);
1045 }
1046 if (!a.type.empty())
1047 {
1048 StringVector list;
1049 linkifyText(TextGeneratorSqlite3Impl(list),a.type,options);
1050
1051 for (const auto &s : list)
1052 {
1053 DString qsrc_refid = md->getOutputFileBase() + "_1" + md->anchor();
1054 struct Refid src_refid = insertRefid(qsrc_refid);
1055 struct Refid dst_refid = insertRefid(s);
1056 insertMemberReference(src_refid,dst_refid, "argument");
1057 }
1058 bindTextParameter(param_select,":type",a.type);
1059 bindTextParameter(param_insert,":type",a.type);
1060 }
1061 if (!a.name.empty())
1062 {
1063 bindTextParameter(param_select,":declname",a.name);
1064 bindTextParameter(param_insert,":declname",a.name);
1065 }
1066 if (defArg && !defArg->name.empty() && defArg->name!=a.name)
1067 {
1068 bindTextParameter(param_select,":defname",defArg->name);
1069 bindTextParameter(param_insert,":defname",defArg->name);
1070 }
1071 if (!a.array.empty())
1072 {
1073 bindTextParameter(param_select,":array",a.array);
1074 bindTextParameter(param_insert,":array",a.array);
1075 }
1076 if (!a.defval.empty())
1077 {
1078 StringVector list;
1079 linkifyText(TextGeneratorSqlite3Impl(list),a.defval,options);
1080 bindTextParameter(param_select,":defval",a.defval);
1081 bindTextParameter(param_insert,":defval",a.defval);
1082 }
1083
1084 int param_id=step(param_select,true,true);
1085 if (param_id==0) {
1086 param_id=step(param_insert,true);
1087 }
1088 if (param_id==-1) {
1089 DBG_CTX(("error INSERT params failed\n"));
1090 continue;
1091 }
1092
1093 bindIntParameter(memberdef_param_insert,":memberdef_id",memberdef_id);
1094 bindIntParameter(memberdef_param_insert,":param_id",param_id);
1096 }
1097 }
1098}
1099
1100static void insertMemberDefineParams(int memberdef_id,const MemberDef *md, const Definition *def)
1101{
1102 if (md->argumentList().empty()) // special case for "foo()" to
1103 // distinguish it from "foo".
1104 {
1105 DBG_CTX(("no params\n"));
1106 }
1107 else
1108 {
1109 for (const Argument &a : md->argumentList())
1110 {
1111 bindTextParameter(param_insert,":defname",a.type);
1112 int param_id=step(param_insert,true);
1113 if (param_id==-1) {
1114 continue;
1115 }
1116
1117 bindIntParameter(memberdef_param_insert,":memberdef_id",memberdef_id);
1118 bindIntParameter(memberdef_param_insert,":param_id",param_id);
1120 }
1121 }
1122}
1123
1124static void associateMember(const MemberDef *md, struct Refid member_refid, struct Refid scope_refid)
1125{
1126 // TODO: skip EnumValue only to guard against recording refids and member records
1127 // for enumvalues until we can support documenting them as entities.
1128 if (md->memberType()==MemberType::EnumValue) return;
1129 if (!md->isAnonymous()) // skip anonymous members
1130 {
1131 bindIntParameter(member_insert, ":scope_rowid", scope_refid.rowid);
1132 bindIntParameter(member_insert, ":memberdef_rowid", member_refid.rowid);
1133
1134 bindIntParameter(member_insert, ":prot", static_cast<int>(md->protection()));
1135 bindIntParameter(member_insert, ":virt", static_cast<int>(md->virtualness()));
1137 }
1138}
1139
1140static void stripQualifiers(DString &typeStr)
1141{
1142 bool done=false;
1143 while (!done)
1144 {
1145 if (typeStr.stripPrefix("static "));
1146 else if (typeStr.stripPrefix("virtual "));
1147 else if (typeStr=="virtual") typeStr="";
1148 else done=true;
1149 }
1150}
1151
1152static int prepareStatement(sqlite3 *db, SqlStmt &s)
1153{
1154 int rc = sqlite3_prepare_v2(db,s.query,-1,&s.stmt,nullptr);
1155 if (rc!=SQLITE_OK)
1156 {
1157 err("prepare failed for:\n {}\n {}\n", s.query, sqlite3_errmsg(db));
1158 s.db = nullptr;
1159 return -1;
1160 }
1161 s.db = db;
1162 return rc;
1163}
1164
1165static int prepareStatements(sqlite3 *db)
1166{
1167 if (
1168 -1==prepareStatement(db, meta_insert) ||
1175 -1==prepareStatement(db, path_insert) ||
1176 -1==prepareStatement(db, path_select) ||
1177 -1==prepareStatement(db, refid_insert) ||
1178 -1==prepareStatement(db, refid_select) ||
1179 -1==prepareStatement(db, incl_insert)||
1180 -1==prepareStatement(db, incl_select)||
1181 -1==prepareStatement(db, param_insert) ||
1182 -1==prepareStatement(db, param_select) ||
1183 -1==prepareStatement(db, xrefs_insert) ||
1190 )
1191 {
1192 return -1;
1193 }
1194 return 0;
1195}
1196
1197static void beginTransaction(sqlite3 *db)
1198{
1199 char * sErrMsg = nullptr;
1200 sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, &sErrMsg);
1201}
1202
1203static void endTransaction(sqlite3 *db)
1204{
1205 char * sErrMsg = nullptr;
1206 sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, &sErrMsg);
1207}
1208
1209static void pragmaTuning(sqlite3 *db)
1210{
1211 char * sErrMsg = nullptr;
1212 sqlite3_exec(db, "PRAGMA synchronous = OFF", nullptr, nullptr, &sErrMsg);
1213 sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", nullptr, nullptr, &sErrMsg);
1214 sqlite3_exec(db, "PRAGMA temp_store = MEMORY;", nullptr, nullptr, &sErrMsg);
1215}
1216
1217static int initializeTables(sqlite3* db)
1218{
1219 msg("Initializing DB schema (tables)...\n");
1220 for (unsigned int k = 0; k < sizeof(table_schema) / sizeof(table_schema[0]); k++)
1221 {
1222 const char *q = table_schema[k][1];
1223 char *errmsg = nullptr;
1224 int rc = sqlite3_exec(db, q, nullptr, nullptr, &errmsg);
1225 if (rc != SQLITE_OK)
1226 {
1227 err("failed to execute query: {}\n\t{}\n", q, errmsg);
1228 return -1;
1229 }
1230 }
1231 return 0;
1232}
1233
1234static int initializeViews(sqlite3* db)
1235{
1236 msg("Initializing DB schema (views)...\n");
1237 for (unsigned int k = 0; k < sizeof(view_schema) / sizeof(view_schema[0]); k++)
1238 {
1239 const char *q = view_schema[k][1];
1240 char *errmsg = nullptr;
1241 int rc = sqlite3_exec(db, q, nullptr, nullptr, &errmsg);
1242 if (rc != SQLITE_OK)
1243 {
1244 err("failed to execute query: {}\n\t{}\n", q, errmsg);
1245 return -1;
1246 }
1247 }
1248 return 0;
1249}
1250
1251////////////////////////////////////////////
1252/* TODO:
1253I collapsed all innerX tables into 'contains', which raises the prospect that
1254all of these very similar writeInnerX funcs could be refactored into a one,
1255or a small set of common parts.
1256
1257I think the hurdles are:
1258- picking a first argument that every call location can pass
1259- which yields a consistent iterator
1260- accommodates PageDef's slightly different rules for generating the
1261 inner_refid (unless I'm missing a method that would uniformly return
1262 the correct refid for all types).
1263*/
1264static void writeInnerClasses(const ClassLinkedRefMap &cl, struct Refid outer_refid)
1265{
1266 for (const auto &cd : cl)
1267 {
1268 if (!cd->isHidden() && !cd->isAnonymous())
1269 {
1270 struct Refid inner_refid = insertRefid(cd->getOutputFileBase());
1271
1272 bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
1273 bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
1275 }
1276 }
1277}
1278
1279static void writeInnerConcepts(const ConceptLinkedRefMap &cl, struct Refid outer_refid)
1280{
1281 for (const auto &cd : cl)
1282 {
1283 struct Refid inner_refid = insertRefid(cd->getOutputFileBase());
1284
1285 bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
1286 bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
1288 }
1289}
1290
1291static void writeInnerModules(const ModuleLinkedRefMap &ml, struct Refid outer_refid)
1292{
1293 for (const auto &mod : ml)
1294 {
1295 struct Refid inner_refid = insertRefid(mod->getOutputFileBase());
1296
1297 bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
1298 bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
1300 }
1301}
1302
1303
1304static void writeInnerPages(const PageLinkedRefMap &pl, struct Refid outer_refid)
1305{
1306 for (const auto &pd : pl)
1307 {
1308 struct Refid inner_refid = insertRefid(
1309 pd->getGroupDef() ? pd->getOutputFileBase()+"_"+pd->name() : pd->getOutputFileBase()
1310 );
1311
1312 bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
1313 bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
1315 }
1316}
1317
1318static void writeInnerGroups(const GroupList &gl, struct Refid outer_refid)
1319{
1320 for (const auto &sgd : gl)
1321 {
1322 struct Refid inner_refid = insertRefid(sgd->getOutputFileBase());
1323
1324 bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
1325 bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
1327 }
1328}
1329
1330static void writeInnerFiles(const FileList &fl, struct Refid outer_refid)
1331{
1332 for (const auto &fd: fl)
1333 {
1334 struct Refid inner_refid = insertRefid(fd->getOutputFileBase());
1335
1336 bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
1337 bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
1339 }
1340}
1341
1342static void writeInnerDirs(const DirList &dl, struct Refid outer_refid)
1343{
1344 for (const auto &subdir : dl)
1345 {
1346 struct Refid inner_refid = insertRefid(subdir->getOutputFileBase());
1347
1348 bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
1349 bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
1351 }
1352}
1353
1354static void writeInnerNamespaces(const NamespaceLinkedRefMap &nl, struct Refid outer_refid)
1355{
1356 for (const auto &nd : nl)
1357 {
1358 if (!nd->isHidden() && !nd->isAnonymous())
1359 {
1360 struct Refid inner_refid = insertRefid(nd->getOutputFileBase());
1361
1362 bindIntParameter(contains_insert,":inner_rowid",inner_refid.rowid);
1363 bindIntParameter(contains_insert,":outer_rowid",outer_refid.rowid);
1365 }
1366 }
1367}
1368
1369
1371 const Definition * scope,
1372 const FileDef * fileScope)
1373{
1374 for (const Argument &a : al)
1375 {
1376 if (!a.type.empty())
1377 {
1378//#warning linkifyText(TextGeneratorXMLImpl(t),a.type,LinkifyTextOptions().setScope(scope).setFileScope(fileScope));
1379 bindTextParameter(param_select,":type",a.type);
1380 bindTextParameter(param_insert,":type",a.type);
1381 }
1382 if (!a.name.empty())
1383 {
1384 bindTextParameter(param_select,":declname",a.name);
1385 bindTextParameter(param_insert,":declname",a.name);
1386 bindTextParameter(param_select,":defname",a.name);
1387 bindTextParameter(param_insert,":defname",a.name);
1388 }
1389 if (!a.defval.empty())
1390 {
1391//#warning linkifyText(TextGeneratorXMLImpl(t),a.defval,LinkifyTextOptions().setScope(scope).setFileScope(fileScope));
1392 bindTextParameter(param_select,":defval",a.defval);
1393 bindTextParameter(param_insert,":defval",a.defval);
1394 }
1395 if (!step(param_select,true,true))
1397 }
1398}
1399
1404
1405static void writeTemplateList(const ClassDef *cd)
1406{
1408}
1409
1410static void writeTemplateList(const ConceptDef *cd)
1411{
1413}
1414
1416 const Definition *def,
1417 const DString &doc,
1418 const DString &fileName,
1419 int lineNr)
1420{
1421 if (doc.empty()) return "";
1422
1423 TextStream t;
1424 auto parser { createDocParser() };
1425 auto ast { validatingParseDoc(*parser.get(),
1426 fileName,
1427 lineNr,
1428 scope,
1429 toMemberDef(def),
1430 doc,
1431 DocOptions())
1432 };
1433 auto astImpl = dynamic_cast<const DocNodeAST*>(ast.get());
1434 if (astImpl)
1435 {
1436 OutputCodeList xmlCodeList;
1437 xmlCodeList.add<XMLCodeGenerator>(&t);
1438 // create a parse tree visitor for XML
1439 XmlDocVisitor visitor(t,xmlCodeList,
1440 scope ? scope->getDefFileExtension() : DString(""));
1441 std::visit(visitor,astImpl->root);
1442 }
1444}
1445
1446static void getSQLDesc(SqlStmt &s,const char *col,const DString &value,const Definition *def)
1447{
1449 s,
1450 col,
1452 def->getOuterScope(),
1453 def,
1454 value,
1455 def->docFile(),
1456 def->docLine()
1457 )
1458 );
1459}
1460
1461static void getSQLDescCompound(SqlStmt &s,const char *col,const DString &value,const Definition *def)
1462{
1464 s,
1465 col,
1467 def,
1468 def,
1469 value,
1470 def->docFile(),
1471 def->docLine()
1472 )
1473 );
1474}
1475////////////////////////////////////////////
1476
1477/* (updated Sep 01 2018)
1478DoxMemberKind and DoxCompoundKind (compound.xsd) gave me some
1479faulty assumptions about "kind" strings, so I compiled a reference
1480
1481The XML schema claims:
1482 DoxMemberKind: (14)
1483 dcop define enum event friend function interface property prototype
1484 service signal slot typedef variable
1485
1486 DoxCompoundKind: (17)
1487 category class dir example exception file group interface module
1488 namespace page protocol service singleton struct type union
1489
1490Member kind comes from MemberDef::memberTypeName()
1491 types.h defines 14 MemberType::*s
1492 _DCOP _Define _Enumeration _EnumValue _Event _Friend _Function _Interface
1493 _Property _Service _Signal _Slot _Typedef _Variable
1494 - xml doesn't include enumvalue here
1495 (but renders enumvalue as) a sub-node of memberdef/templateparamlist
1496 - xml includes 'prototype' that is unlisted here
1497 vestigial? commented out in docsets.cpp and perlmodgen.cpp
1498 MemberDef::memberTypeName() can return 15 strings:
1499 (sorted by MemberType to match above; quoted because whitespace...)
1500 "dcop" "macro definition" "enumeration" "enumvalue" "event" "friend"
1501 "function" "interface" "property" "service" "signal" "slot" "typedef"
1502 "variable"
1503
1504 Above describes potential values for memberdef.kind
1505
1506Compound kind is more complex. *Def::compoundTypeString()
1507 ClassDef kind comes from ::compoundTypeString()
1508 classdef.h defines 9 compound types
1509 Category Class Exception Interface Protocol Service Singleton Struct Union
1510 But ClassDef::compoundTypeString() "could" return 13 strings
1511 - default "unknown" shouldn't actually return
1512 - other 12 can vary by source language; see method for specifics
1513 category class enum exception interface module protocol service
1514 singleton struct type union
1515
1516 DirDef, FileDef, GroupDef have no method to return a string
1517 tagfile/outputs hard-code kind to 'dir' 'file' or 'group'
1518
1519 NamespaceDef kind comes from ::compoundTypeString()
1520 NamespaceDef::compoundTypeString() "could" return 6 strings
1521 - default empty ("") string
1522 - other 5 differ by source language
1523 constants library module namespace package
1524
1525 PageDef also has no method to return a string
1526 - some locations hard-code the kind to 'page'
1527 - others conditionally output 'page' or 'example'
1528
1529 All together, that's 23 potential strings (21 excl "" and unknown)
1530 "" category class constants dir enum example exception file group
1531 interface library module namespace package page protocol service singleton
1532 struct type union unknown
1533
1534 Above describes potential values for compounddef.kind
1535
1536For reference, there are 35 potential values of def.kind (33 excl "" and unknown):
1537 "" "category" "class" "constants" "dcop" "dir" "enum" "enumeration"
1538 "enumvalue" "event" "example" "exception" "file" "friend" "function" "group"
1539 "interface" "library" "macro definition" "module" "namespace" "package"
1540 "page" "property" "protocol" "service" "signal" "singleton" "slot" "struct"
1541 "type" "typedef" "union" "unknown" "variable"
1542
1543This is relevant because the 'def' view generalizes memberdef and compounddef,
1544and two member+compound kind strings (interface and service) overlap.
1545
1546I have no grasp of whether a real user docset would include one or more
1547member and compound using the interface or service kind.
1548*/
1549
1550//////////////////////////////////////////////////////////////////////////////
1551static void generateSqlite3ForMember(const MemberDef *md, struct Refid scope_refid, const Definition *def)
1552{
1553 // + declaration/definition arg lists
1554 // + reimplements
1555 // + reimplementedBy
1556 // - exceptions
1557 // + const/volatile specifiers
1558 // - examples
1559 // + source definition
1560 // + source references
1561 // + source referenced by
1562 // - body code
1563 // + template arguments
1564 // (templateArguments(), definitionTemplateParameterLists())
1565 // - call graph
1566
1567 // enum values are written as part of the enum
1568 if (md->memberType()==MemberType::EnumValue) return;
1569 if (md->isHidden()) return;
1570
1571 DString memType;
1572
1573 // memberdef
1574 DString qrefid = md->getOutputFileBase() + "_1" + md->anchor();
1575 struct Refid refid = insertRefid(qrefid);
1576
1577 associateMember(md, refid, scope_refid);
1578
1579 // compacting duplicate defs
1580 if(!refid.created && memberdefExists(refid) && memberdefIncomplete(refid, md))
1581 {
1582 /*
1583 For performance, ideal to skip a member we've already added.
1584 Unfortunately, we can have two memberdefs with the same refid documenting
1585 the declaration and definition. memberdefIncomplete() uses the 'inline'
1586 value to figure this out. Once we get to this point, we should *only* be
1587 seeing the *other* type of def/decl, so we'll set inline to a new value (2),
1588 indicating that this entry covers both inline types.
1589 */
1590 struct SqlStmt memberdef_update;
1591
1592 // definitions have bodyfile/start/end
1593 if (md->getStartBodyLine()!=-1)
1594 {
1595 memberdef_update = memberdef_update_def;
1596 int bodyfile_id = insertPath(md->getBodyDef()->absFilePath(),!md->getBodyDef()->isReference());
1597 if (bodyfile_id == -1)
1598 {
1599 sqlite3_clear_bindings(memberdef_update.stmt);
1600 }
1601 else
1602 {
1603 bindIntParameter(memberdef_update,":bodyfile_id",bodyfile_id);
1604 bindIntParameter(memberdef_update,":bodystart",md->getStartBodyLine());
1605 bindIntParameter(memberdef_update,":bodyend",md->getEndBodyLine());
1606 }
1607 }
1608 // declarations don't
1609 else
1610 {
1611 memberdef_update = memberdef_update_decl;
1612 if (md->getDefLine() != -1)
1613 {
1614 int file_id = insertPath(md->getDefFileName(),!md->isReference());
1615 if (file_id!=-1)
1616 {
1617 bindIntParameter(memberdef_update,":file_id",file_id);
1618 bindIntParameter(memberdef_update,":line",md->getDefLine());
1619 bindIntParameter(memberdef_update,":column",md->getDefColumn());
1620 }
1621 }
1622 }
1623
1624 bindIntParameter(memberdef_update, ":rowid", refid.rowid);
1625 // value 2 indicates we've seen "both" inline types.
1626 bindIntParameter(memberdef_update,":inline", 2);
1627
1628 /* in case both are used, append/prepend descriptions */
1629 getSQLDesc(memberdef_update,":briefdescription",md->briefDescription(),md);
1630 getSQLDesc(memberdef_update,":detaileddescription",md->documentation(),md);
1631 getSQLDesc(memberdef_update,":inbodydescription",md->inbodyDocumentation(),md);
1632
1633 step(memberdef_update,true);
1634
1635 // don't think we need to repeat params; should have from first encounter
1636
1637 // + source references
1638 // The cross-references in initializers only work when both the src and dst
1639 // are defined.
1640 auto refList = md->getReferencesMembers();
1641 for (const auto &rmd : refList)
1642 {
1643 insertMemberReference(md,rmd, "inline");
1644 }
1645 // + source referenced by
1646 auto refByList = md->getReferencedByMembers();
1647 for (const auto &rmd : refByList)
1648 {
1649 insertMemberReference(rmd,md, "inline");
1650 }
1651 return;
1652 }
1653
1654 bindIntParameter(memberdef_insert,":rowid", refid.rowid);
1656 bindIntParameter(memberdef_insert,":prot",static_cast<int>(md->protection()));
1657
1660
1661 bool isFunc=to_isFunction(md->memberType());
1662
1663 if (isFunc)
1664 {
1665 const ArgumentList &al = md->argumentList();
1668 bindIntParameter(memberdef_insert,":explicit",md->isExplicit());
1673 bindIntParameter(memberdef_insert,":optional",md->isOptional());
1674 bindIntParameter(memberdef_insert,":required",md->isRequired());
1675
1676 bindIntParameter(memberdef_insert,":virt",static_cast<int>(md->virtualness()));
1677 }
1678
1679 if (md->memberType() == MemberType::Variable)
1680 {
1682 bindIntParameter(memberdef_insert,":thread_local",md->isThreadLocal());
1683 bindIntParameter(memberdef_insert,":initonly",md->isInitonly());
1684 bindIntParameter(memberdef_insert,":attribute",md->isAttribute());
1685 bindIntParameter(memberdef_insert,":property",md->isProperty());
1686 bindIntParameter(memberdef_insert,":readonly",md->isReadonly());
1688 bindIntParameter(memberdef_insert,":removable",md->isRemovable());
1689 bindIntParameter(memberdef_insert,":constrained",md->isConstrained());
1690 bindIntParameter(memberdef_insert,":transient",md->isTransient());
1691 bindIntParameter(memberdef_insert,":maybevoid",md->isMaybeVoid());
1692 bindIntParameter(memberdef_insert,":maybedefault",md->isMaybeDefault());
1693 bindIntParameter(memberdef_insert,":maybeambiguous",md->isMaybeAmbiguous());
1694 if (!md->bitfieldString().empty())
1695 {
1696 DString bitfield = md->bitfieldString();
1697 if (bitfield.at(0)==':') bitfield=bitfield.mid(1);
1698 bindTextParameter(memberdef_insert,":bitfield",bitfield.stripWhiteSpace());
1699 }
1700 }
1701 else if (md->memberType() == MemberType::Property)
1702 {
1703 bindIntParameter(memberdef_insert,":readable",md->isReadable());
1704 bindIntParameter(memberdef_insert,":writable",md->isWritable());
1705 bindIntParameter(memberdef_insert,":gettable",md->isGettable());
1706 bindIntParameter(memberdef_insert,":privategettable",md->isPrivateGettable());
1707 bindIntParameter(memberdef_insert,":protectedgettable",md->isProtectedGettable());
1708 bindIntParameter(memberdef_insert,":settable",md->isSettable());
1709 bindIntParameter(memberdef_insert,":privatesettable",md->isPrivateSettable());
1710 bindIntParameter(memberdef_insert,":protectedsettable",md->isProtectedSettable());
1711
1712 if (md->isAssign() || md->isCopy() || md->isRetain()
1713 || md->isStrong() || md->isWeak())
1714 {
1715 int accessor=0;
1716 if (md->isAssign()) accessor = 1;
1717 else if (md->isCopy()) accessor = 2;
1718 else if (md->isRetain()) accessor = 3;
1719 else if (md->isStrong()) accessor = 4;
1720 else if (md->isWeak()) accessor = 5;
1721
1722 bindIntParameter(memberdef_insert,":accessor",accessor);
1723 }
1726 }
1727 else if (md->memberType() == MemberType::Event)
1728 {
1730 bindIntParameter(memberdef_insert,":removable",md->isRemovable());
1731 bindIntParameter(memberdef_insert,":raisable",md->isRaisable());
1732 }
1733
1734 const MemberDef *rmd = md->reimplements();
1735 if (rmd)
1736 {
1737 DString qreimplemented_refid = rmd->getOutputFileBase() + "_1" + rmd->anchor();
1738
1739 struct Refid reimplemented_refid = insertRefid(qreimplemented_refid);
1740
1741 bindIntParameter(reimplements_insert,":memberdef_rowid", refid.rowid);
1742 bindIntParameter(reimplements_insert,":reimplemented_rowid", reimplemented_refid.rowid);
1744 }
1745
1746 LinkifyTextOptions options;
1747 options.setScope(def).setFileScope(md->getBodyDef()).setSelf(md);
1748
1749 // + declaration/definition arg lists
1750 if (md->memberType()!=MemberType::Define &&
1751 md->memberType()!=MemberType::Enumeration
1752 )
1753 {
1754 if (md->memberType()!=MemberType::Typedef)
1755 {
1757 }
1758 DString typeStr = md->typeString();
1759 stripQualifiers(typeStr);
1760 StringVector list;
1761 linkifyText(TextGeneratorSqlite3Impl(list),typeStr,options);
1762 if (!typeStr.empty())
1763 {
1764 bindTextParameter(memberdef_insert,":type",typeStr);
1765 }
1766
1767 if (!md->definition().empty())
1768 {
1769 bindTextParameter(memberdef_insert,":definition",md->definition());
1770 }
1771
1772 if (!md->argsString().empty())
1773 {
1774 bindTextParameter(memberdef_insert,":argsstring",md->argsString());
1775 }
1776 }
1777
1779
1780 // Extract references from initializer
1782 {
1783 bindTextParameter(memberdef_insert,":initializer",md->initializer());
1784
1785 StringVector list;
1787 for (const auto &s : list)
1788 {
1789 if (md->getBodyDef())
1790 {
1791 DBG_CTX(("initializer:%s %s %s %d\n",
1792 qPrint(md->anchor()),
1793 qPrint(s),
1795 md->getStartBodyLine()));
1796 DString qsrc_refid = md->getOutputFileBase() + "_1" + md->anchor();
1797 struct Refid src_refid = insertRefid(qsrc_refid);
1798 struct Refid dst_refid = insertRefid(s);
1799 insertMemberReference(src_refid,dst_refid, "initializer");
1800 }
1801 }
1802 }
1803
1804 if ( !md->getScopeString().empty() )
1805 {
1807 }
1808
1809 // +Brief, detailed and inbody description
1810 getSQLDesc(memberdef_insert,":briefdescription",md->briefDescription(),md);
1811 getSQLDesc(memberdef_insert,":detaileddescription",md->documentation(),md);
1812 getSQLDesc(memberdef_insert,":inbodydescription",md->inbodyDocumentation(),md);
1813
1814 // File location
1815 if (md->getDefLine() != -1)
1816 {
1817 int file_id = insertPath(md->getDefFileName(),!md->isReference());
1818 if (file_id!=-1)
1819 {
1820 bindIntParameter(memberdef_insert,":file_id",file_id);
1823
1824 // definitions also have bodyfile/start/end
1825 if (md->getStartBodyLine()!=-1)
1826 {
1827 int bodyfile_id = insertPath(md->getBodyDef()->absFilePath(),!md->getBodyDef()->isReference());
1828 if (bodyfile_id == -1)
1829 {
1830 sqlite3_clear_bindings(memberdef_insert.stmt);
1831 }
1832 else
1833 {
1834 bindIntParameter(memberdef_insert,":bodyfile_id",bodyfile_id);
1837 }
1838 }
1839 }
1840 }
1841
1842 int memberdef_id=step(memberdef_insert,true);
1843
1844 if (isFunc)
1845 {
1846 insertMemberFunctionParams(memberdef_id,md,def);
1847 }
1848 else if (md->memberType()==MemberType::Define &&
1849 !md->argsString().empty())
1850 {
1851 insertMemberDefineParams(memberdef_id,md,def);
1852 }
1853
1854 // + source references
1855 // The cross-references in initializers only work when both the src and dst
1856 // are defined.
1857 for (const auto &refmd : md->getReferencesMembers())
1858 {
1859 insertMemberReference(md,refmd, "inline");
1860 }
1861 // + source referenced by
1862 for (const auto &refmd : md->getReferencedByMembers())
1863 {
1864 insertMemberReference(refmd,md, "inline");
1865 }
1866}
1867
1869 const MemberList *ml,
1870 struct Refid scope_refid,
1871 const char * /*kind*/,
1872 const DString & /*header*/=DString(),
1873 const DString & /*documentation*/=DString())
1874{
1875 if (ml==nullptr) return;
1876 for (const auto &md : *ml)
1877 {
1878 // TODO: necessary? just tracking what xmlgen does; xmlgen says:
1879 // namespace members are also inserted in the file scope, but
1880 // to prevent this duplication in the XML output, we filter those here.
1881 if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==nullptr)
1882 {
1883 generateSqlite3ForMember(md, scope_refid, d);
1884 }
1885 }
1886}
1887
1888static void associateAllClassMembers(const ClassDef *cd, struct Refid scope_refid)
1889{
1890 for (auto &mni : cd->memberNameInfoLinkedMap())
1891 {
1892 for (auto &mi : *mni)
1893 {
1894 const MemberDef *md = mi->memberDef();
1895 DString qrefid = md->getOutputFileBase() + "_1" + md->anchor();
1896 associateMember(md, insertRefid(qrefid), scope_refid);
1897 }
1898 }
1899}
1900
1901// many kinds: category class enum exception interface
1902// module protocol service singleton struct type union
1903// enum is Java only (and is distinct from enum memberdefs)
1904static void generateSqlite3ForClass(const ClassDef *cd)
1905{
1906 // NOTE: Skeptical about XML's version of these
1907 // 'x' marks missing items XML claims to include
1908
1909 // + brief description
1910 // + detailed description
1911 // + template argument list(s)
1912 // + include file
1913 // + member groups
1914 // x inheritance DOT diagram
1915 // + list of direct super classes
1916 // + list of direct sub classes
1917 // + list of inner classes
1918 // x collaboration DOT diagram
1919 // + list of all members
1920 // x user defined member sections
1921 // x standard member sections
1922 // x detailed member documentation
1923 // - examples using the class
1924
1925 if (cd->isReference()) return; // skip external references.
1926 if (cd->isHidden()) return; // skip hidden classes.
1927 if (cd->isAnonymous()) return; // skip anonymous compounds.
1928 if (cd->isImplicitTemplateInstance()) return; // skip generated template instances.
1929
1930 struct Refid refid = insertRefid(cd->getOutputFileBase());
1931
1932 // can omit a class that already has a refid
1933 if(!refid.created && compounddefExists(refid)){return;}
1934
1935 bindIntParameter(compounddef_insert,":rowid", refid.rowid);
1936
1940 bindIntParameter(compounddef_insert,":prot",static_cast<int>(cd->protection()));
1941
1942 int file_id = insertPath(cd->getDefFileName());
1943 bindIntParameter(compounddef_insert,":file_id",file_id);
1946
1947 // + include file
1948 /*
1949 TODO: I wonder if this can actually be cut (just here)
1950
1951 We were adding this "include" to the "includes" table alongside
1952 other includes (from a FileDef). However, FileDef and ClassDef are using
1953 "includes" nodes in very a different way:
1954 - With FileDef, it means the file includes another.
1955 - With ClassDef, it means you should include this file to use this class.
1956
1957 Because of this difference, I added a column to compounddef, header_id, and
1958 linked it back to the appropriate file. We could just add a nullable text
1959 column that would hold a string equivalent to what the HTML docs include,
1960 but the logic for generating it is embedded in
1961 ClassDef::writeIncludeFiles(OutputList &ol).
1962
1963 That said, at least on the handful of test sets I have, header_id == file_id,
1964 suggesting it could be cut and clients might be able to reconstruct it from
1965 other values if there's a solid heuristic for *when a class will
1966 have a header file*.
1967 */
1968 const IncludeInfo *ii=cd->includeInfo();
1969 if (ii)
1970 {
1971 DString nm = ii->includeName;
1972 if (nm.empty() && ii->fileDef) nm = ii->fileDef->docName();
1973 if (!nm.empty())
1974 {
1975 int header_id=-1;
1976 if (ii->fileDef)
1977 {
1979 }
1980 DBG_CTX(("-----> ClassDef includeInfo for %s\n", qPrint(nm)));
1981 DBG_CTX((" local : %d\n", ii->local));
1982 DBG_CTX((" imported : %d\n", ii->imported));
1983 if (ii->fileDef)
1984 {
1985 DBG_CTX(("header: %s\n", qPrint(ii->fileDef->absFilePath())));
1986 }
1987 DBG_CTX((" file_id : %d\n", file_id));
1988 DBG_CTX((" header_id: %d\n", header_id));
1989
1990 if(header_id!=-1)
1991 {
1992 bindIntParameter(compounddef_insert,":header_id",header_id);
1993 }
1994 }
1995 }
1996
1997 getSQLDescCompound(compounddef_insert,":briefdescription",cd->briefDescription(),cd);
1998 getSQLDescCompound(compounddef_insert,":detaileddescription",cd->documentation(),cd);
1999
2001
2002 // + list of direct super classes
2003 for (const auto &bcd : cd->baseClasses())
2004 {
2005 struct Refid base_refid = insertRefid(bcd.classDef->getOutputFileBase());
2006 struct Refid derived_refid = insertRefid(cd->getOutputFileBase());
2007 bindIntParameter(compoundref_insert,":base_rowid", base_refid.rowid);
2008 bindIntParameter(compoundref_insert,":derived_rowid", derived_refid.rowid);
2009 bindIntParameter(compoundref_insert,":prot",static_cast<int>(bcd.prot));
2010 bindIntParameter(compoundref_insert,":virt",static_cast<int>(bcd.virt));
2012 }
2013
2014 // + list of direct sub classes
2015 for (const auto &bcd : cd->subClasses())
2016 {
2017 struct Refid derived_refid = insertRefid(bcd.classDef->getOutputFileBase());
2018 struct Refid base_refid = insertRefid(cd->getOutputFileBase());
2019 bindIntParameter(compoundref_insert,":base_rowid", base_refid.rowid);
2020 bindIntParameter(compoundref_insert,":derived_rowid", derived_refid.rowid);
2021 bindIntParameter(compoundref_insert,":prot",static_cast<int>(bcd.prot));
2022 bindIntParameter(compoundref_insert,":virt",static_cast<int>(bcd.virt));
2024 }
2025
2026 // + list of inner classes
2028
2029 // + template argument list(s)
2031
2032 // + member groups
2033 for (const auto &mg : cd->getMemberGroups())
2034 {
2035 generateSqlite3Section(cd,&mg->members(),refid,"user-defined",mg->header(),
2036 mg->documentation());
2037 }
2038
2039 // this is just a list of *local* members
2040 for (const auto &ml : cd->getMemberLists())
2041 {
2042 if (!ml->listType().isDetailed())
2043 {
2044 generateSqlite3Section(cd,ml.get(),refid,"user-defined");
2045 }
2046 }
2047
2048 // + list of all members
2050}
2051
2053{
2054 if (cd->isReference() || cd->isHidden()) return; // skip external references
2055
2056 struct Refid refid = insertRefid(cd->getOutputFileBase());
2057 if(!refid.created && compounddefExists(refid)){return;}
2058 bindIntParameter(compounddef_insert,":rowid", refid.rowid);
2060 bindTextParameter(compounddef_insert,":kind","concept");
2061
2062 int file_id = insertPath(cd->getDefFileName());
2063 bindIntParameter(compounddef_insert,":file_id",file_id);
2066
2067 getSQLDescCompound(compounddef_insert,":briefdescription",cd->briefDescription(),cd);
2068 getSQLDescCompound(compounddef_insert,":detaileddescription",cd->documentation(),cd);
2069
2071
2072 // + template argument list(s)
2074}
2075
2077{
2078 // + contained class definitions
2079 // + contained concept definitions
2080 // + member groups
2081 // + normal members
2082 // + brief desc
2083 // + detailed desc
2084 // + location (file_id, line, column)
2085 // - exports
2086 // + used files
2087
2088 if (mod->isReference() || mod->isHidden()) return;
2089 struct Refid refid = insertRefid(mod->getOutputFileBase());
2090 if(!refid.created && compounddefExists(refid)){return;}
2091 bindIntParameter(compounddef_insert,":rowid", refid.rowid);
2093 bindTextParameter(compounddef_insert,":kind","module");
2094
2095 int file_id = insertPath(mod->getDefFileName());
2096 bindIntParameter(compounddef_insert,":file_id",file_id);
2099
2100 getSQLDescCompound(compounddef_insert,":briefdescription",mod->briefDescription(),mod);
2101 getSQLDescCompound(compounddef_insert,":detaileddescription",mod->documentation(),mod);
2102
2104
2105 // + contained class definitions
2107
2108 // + contained concept definitions
2110
2111 // + member groups
2112 for (const auto &mg : mod->getMemberGroups())
2113 {
2114 generateSqlite3Section(mod,&mg->members(),refid,"user-defined",mg->header(),
2115 mg->documentation());
2116 }
2117
2118 // + normal members
2119 for (const auto &ml : mod->getMemberLists())
2120 {
2121 if (ml->listType().isDeclaration())
2122 {
2123 generateSqlite3Section(mod,ml.get(),refid,"user-defined");
2124 }
2125 }
2126
2127 // + files
2129}
2130
2131// kinds: constants library module namespace package
2133{
2134 // + contained class definitions
2135 // + contained namespace definitions
2136 // + member groups
2137 // + normal members
2138 // + brief desc
2139 // + detailed desc
2140 // + location (file_id, line, column)
2141 // - files containing (parts of) the namespace definition
2142
2143 if (nd->isReference() || nd->isHidden()) return; // skip external references
2144 struct Refid refid = insertRefid(nd->getOutputFileBase());
2145 if(!refid.created && compounddefExists(refid)){return;}
2146 bindIntParameter(compounddef_insert,":rowid", refid.rowid);
2147
2150 bindTextParameter(compounddef_insert,":kind","namespace");
2151
2152 int file_id = insertPath(nd->getDefFileName());
2153 bindIntParameter(compounddef_insert,":file_id",file_id);
2156
2157 getSQLDescCompound(compounddef_insert,":briefdescription",nd->briefDescription(),nd);
2158 getSQLDescCompound(compounddef_insert,":detaileddescription",nd->documentation(),nd);
2159
2161
2162 // + contained class definitions
2164
2165 // + contained concept definitions
2167
2168 // + contained namespace definitions
2170
2171 // + member groups
2172 for (const auto &mg : nd->getMemberGroups())
2173 {
2174 generateSqlite3Section(nd,&mg->members(),refid,"user-defined",mg->header(),
2175 mg->documentation());
2176 }
2177
2178 // + normal members
2179 for (const auto &ml : nd->getMemberLists())
2180 {
2181 if (ml->listType().isDeclaration())
2182 {
2183 generateSqlite3Section(nd,ml.get(),refid,"user-defined");
2184 }
2185 }
2186}
2187
2188// kind: file
2189static void generateSqlite3ForFile(const FileDef *fd)
2190{
2191 // + includes files
2192 // + includedby files
2193 // x include graph
2194 // x included by graph
2195 // + contained class definitions
2196 // + contained namespace definitions
2197 // + member groups
2198 // + normal members
2199 // + brief desc
2200 // + detailed desc
2201 // x source code
2202 // + location (file_id, line, column)
2203 // - number of lines
2204
2205 if (fd->isReference()) return; // skip external references
2206
2207 struct Refid refid = insertRefid(fd->getOutputFileBase());
2208 if(!refid.created && compounddefExists(refid)){return;}
2209 bindIntParameter(compounddef_insert,":rowid", refid.rowid);
2210
2213 bindTextParameter(compounddef_insert,":kind","file");
2214
2215 int file_id = insertPath(fd->getDefFileName());
2216 bindIntParameter(compounddef_insert,":file_id",file_id);
2219
2220 getSQLDesc(compounddef_insert,":briefdescription",fd->briefDescription(),fd);
2221 getSQLDesc(compounddef_insert,":detaileddescription",fd->documentation(),fd);
2222
2224
2225 // + includes files
2226 for (const auto &ii : fd->includeFileList())
2227 {
2228 int src_id=insertPath(fd->absFilePath(),!fd->isReference());
2229 int dst_id=0;
2230 DString dst_path;
2231 bool isLocal = (ii.kind & IncludeKind_LocalMask)!=0;
2232
2233 if(ii.fileDef) // found file
2234 {
2235 if(ii.fileDef->isReference())
2236 {
2237 // strip tagfile from path
2238 DString tagfile = ii.fileDef->getReference();
2239 dst_path = ii.fileDef->absFilePath();
2240 dst_path.stripPrefix(tagfile+":");
2241 }
2242 else
2243 {
2244 dst_path = ii.fileDef->absFilePath();
2245 }
2246 dst_id = insertPath(dst_path,isLocal);
2247 }
2248 else // can't find file
2249 {
2250 dst_id = insertPath(ii.includeName,isLocal,false);
2251 }
2252
2253 DBG_CTX(("-----> FileDef includeInfo for %s\n", qPrint(ii.includeName)));
2254 DBG_CTX((" local: %d\n", isLocal));
2255 DBG_CTX((" imported: %d\n", (ii.kind & IncludeKind_ImportMask)!=0));
2256 if(ii.fileDef)
2257 {
2258 DBG_CTX(("include: %s\n", qPrint(ii.fileDef->absFilePath())));
2259 }
2260 DBG_CTX((" src_id : %d\n", src_id));
2261 DBG_CTX((" dst_id: %d\n", dst_id));
2262
2263 bindIntParameter(incl_select,":local",isLocal);
2264 bindIntParameter(incl_select,":src_id",src_id);
2265 bindIntParameter(incl_select,":dst_id",dst_id);
2266 if (step(incl_select,true,true)==0) {
2267 bindIntParameter(incl_insert,":local",isLocal);
2268 bindIntParameter(incl_insert,":src_id",src_id);
2269 bindIntParameter(incl_insert,":dst_id",dst_id);
2271 }
2272 }
2273
2274 // + includedby files
2275 for (const auto &ii : fd->includedByFileList())
2276 {
2277 int dst_id=insertPath(fd->absFilePath(),!fd->isReference());
2278 int src_id=0;
2279 DString src_path;
2280 bool isLocal = (ii.kind & IncludeKind_LocalMask)!=0;
2281
2282 if(ii.fileDef) // found file
2283 {
2284 if(ii.fileDef->isReference())
2285 {
2286 // strip tagfile from path
2287 DString tagfile = ii.fileDef->getReference();
2288 src_path = ii.fileDef->absFilePath();
2289 src_path.stripPrefix(tagfile+":");
2290 }
2291 else
2292 {
2293 src_path = ii.fileDef->absFilePath();
2294 }
2295 src_id = insertPath(src_path,isLocal);
2296 }
2297 else // can't find file
2298 {
2299 src_id = insertPath(ii.includeName,isLocal,false);
2300 }
2301
2302 bindIntParameter(incl_select,":local",isLocal);
2303 bindIntParameter(incl_select,":src_id",src_id);
2304 bindIntParameter(incl_select,":dst_id",dst_id);
2305 if (step(incl_select,true,true)==0) {
2306 bindIntParameter(incl_insert,":local",isLocal);
2307 bindIntParameter(incl_insert,":src_id",src_id);
2308 bindIntParameter(incl_insert,":dst_id",dst_id);
2310 }
2311 }
2312
2313 // + contained class definitions
2315
2316 // + contained concept definitions
2318
2319 // + contained namespace definitions
2321
2322 // + member groups
2323 for (const auto &mg : fd->getMemberGroups())
2324 {
2325 generateSqlite3Section(fd,&mg->members(),refid,"user-defined",mg->header(),
2326 mg->documentation());
2327 }
2328
2329 // + normal members
2330 for (const auto &ml : fd->getMemberLists())
2331 {
2332 if (ml->listType().isDeclaration())
2333 {
2334 generateSqlite3Section(fd,ml.get(),refid,"user-defined");
2335 }
2336 }
2337}
2338
2339// kind: group
2340static void generateSqlite3ForGroup(const GroupDef *gd)
2341{
2342 // + members
2343 // + member groups
2344 // + files
2345 // + classes
2346 // + namespaces
2347 // - packages
2348 // + pages
2349 // + child groups
2350 // - examples
2351 // + brief description
2352 // + detailed description
2353
2354 if (gd->isReference()) return; // skip external references.
2355
2356 struct Refid refid = insertRefid(gd->getOutputFileBase());
2357 if(!refid.created && compounddefExists(refid)){return;}
2358 bindIntParameter(compounddef_insert,":rowid", refid.rowid);
2359
2362 bindTextParameter(compounddef_insert,":kind","group");
2363
2364 int file_id = insertPath(gd->getDefFileName());
2365 bindIntParameter(compounddef_insert,":file_id",file_id);
2368
2369 getSQLDesc(compounddef_insert,":briefdescription",gd->briefDescription(),gd);
2370 getSQLDesc(compounddef_insert,":detaileddescription",gd->documentation(),gd);
2371
2373
2374 // + files
2376
2377 // + classes
2379
2380 // + concepts
2382
2383 // + modules
2385
2386 // + namespaces
2388
2389 // + pages
2391
2392 // + groups
2394
2395 // + member groups
2396 for (const auto &mg : gd->getMemberGroups())
2397 {
2398 generateSqlite3Section(gd,&mg->members(),refid,"user-defined",mg->header(),
2399 mg->documentation());
2400 }
2401
2402 // + members
2403 for (const auto &ml : gd->getMemberLists())
2404 {
2405 if (ml->listType().isDeclaration())
2406 {
2407 generateSqlite3Section(gd,ml.get(),refid,"user-defined");
2408 }
2409 }
2410}
2411
2412// kind: dir
2413static void generateSqlite3ForDir(const DirDef *dd)
2414{
2415 // + dirs
2416 // + files
2417 // + briefdescription
2418 // + detaileddescription
2419 // + location (below uses file_id, line, column; XML just uses file)
2420 if (dd->isReference()) return; // skip external references
2421
2422 struct Refid refid = insertRefid(dd->getOutputFileBase());
2423 if(!refid.created && compounddefExists(refid)){return;}
2424 bindIntParameter(compounddef_insert,":rowid", refid.rowid);
2425
2428
2429 int file_id = insertPath(dd->getDefFileName(),true,true,2);
2430 bindIntParameter(compounddef_insert,":file_id",file_id);
2431
2432 /*
2433 line and column are weird here, but:
2434 - dir goes into compounddef with all of the others
2435 - the semantics would be fine if we set them to NULL here
2436 - but defining line and column as NOT NULL is an important promise
2437 for other compounds, so I don't want to loosen it
2438
2439 For reference, the queries return 1.
2440 0 or -1 make more sense, but I see that as a change for DirDef.
2441 */
2444
2445 getSQLDesc(compounddef_insert,":briefdescription",dd->briefDescription(),dd);
2446 getSQLDesc(compounddef_insert,":detaileddescription",dd->documentation(),dd);
2447
2449
2450 // + files
2452
2453 // + files
2455}
2456
2457// kinds: page, example
2458static void generateSqlite3ForPage(const PageDef *pd,bool isExample)
2459{
2460 // + name
2461 // + title
2462 // + brief description
2463 // + documentation (detailed description)
2464 // + inbody documentation
2465 // + sub pages
2466 if (pd->isReference()) return; // skip external references.
2467
2468 // TODO: do we more special handling if isExample?
2469
2470 DString qrefid = pd->getOutputFileBase();
2471 if (pd->getGroupDef())
2472 {
2473 qrefid+="_"+pd->name();
2474 }
2475 if (qrefid=="index") qrefid="indexpage"; // to prevent overwriting the generated index page.
2476
2477 struct Refid refid = insertRefid(qrefid);
2478
2479 // can omit a page that already has a refid
2480 if(!refid.created && compounddefExists(refid)){return;}
2481
2483 // + name
2485
2486 DString title;
2487 if (pd==Doxygen::mainPage.get()) // main page is special
2488 {
2489 if (mainPageHasTitle())
2490 {
2491 title = filterTitle(HtmlEntityMapper::instance().convertCharEntitiesToUTF8(Doxygen::mainPage->title()));
2492 }
2493 else
2494 {
2495 title = Config_getString(PROJECT_NAME);
2496 }
2497 }
2498 else
2499 {
2501 if (si)
2502 {
2503 title = si->title();
2504 }
2505 if (title.empty())
2506 {
2507 title = pd->title();
2508 }
2509 }
2510
2511 // + title
2512 bindTextParameter(compounddef_insert,":title",title);
2513
2514 bindTextParameter(compounddef_insert,":kind", isExample ? "example" : "page");
2515
2516 int file_id = insertPath(pd->getDefFileName());
2517
2518 bindIntParameter(compounddef_insert,":file_id",file_id);
2521
2522 // + brief description
2523 getSQLDesc(compounddef_insert,":briefdescription",pd->briefDescription(),pd);
2524 // + documentation (detailed description)
2525 getSQLDesc(compounddef_insert,":detaileddescription",pd->documentation(),pd);
2526
2528 // + sub pages
2530}
2531
2532
2533static sqlite3* openDbConnection()
2534{
2535
2536 DString outputDirectory = Config_getString(SQLITE3_OUTPUT);
2537 sqlite3 *db = nullptr;
2538
2539 int rc = sqlite3_initialize();
2540 if (rc != SQLITE_OK)
2541 {
2542 err("sqlite3_initialize failed\n");
2543 return nullptr;
2544 }
2545
2546 std::string dbFileName = "doxygen_sqlite3.db";
2547 FileInfo fi(outputDirectory.str()+"/"+dbFileName);
2548
2549 if (fi.exists())
2550 {
2551 if (Config_getBool(SQLITE3_RECREATE_DB))
2552 {
2553 Dir().remove(fi.absFilePath());
2554 }
2555 else
2556 {
2557 err("doxygen_sqlite3.db already exists! Rename, remove, or archive it to regenerate\n");
2558 return nullptr;
2559 }
2560 }
2561
2562 rc = sqlite3_open_v2(
2563 fi.absFilePath().c_str(),
2564 &db,
2565 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
2566 nullptr
2567 );
2568 if (rc != SQLITE_OK)
2569 {
2570 sqlite3_close(db);
2571 err("Database open failed: doxygen_sqlite3.db\n");
2572 }
2573 return db;
2574}
2575//////////////////////////////////////////////////////////////////////////////
2576//////////////////////////////////////////////////////////////////////////////
2578{
2579 // + classes
2580 // + namespaces
2581 // + files
2582 // + groups
2583 // + related pages
2584 // + examples
2585 // + main page
2586 sqlite3 *db = openDbConnection();
2587 if (db==nullptr)
2588 {
2589 return;
2590 }
2591
2592# ifdef SQLITE3_DEBUG
2593 // debug: show all executed statements
2594 sqlite3_trace(db, &sqlLog, nullptr);
2595# endif
2596
2597 beginTransaction(db);
2598 pragmaTuning(db);
2599
2600 if (-1==initializeTables(db))
2601 return;
2602
2603 if ( -1 == prepareStatements(db) )
2604 {
2605 err("sqlite generator: prepareStatements failed!\n");
2606 return;
2607 }
2608
2610
2611 // + classes
2612 for (const auto &cd : *Doxygen::classLinkedMap)
2613 {
2614 msg("Generating Sqlite3 output for class {}\n",cd->name());
2615 generateSqlite3ForClass(cd.get());
2616 }
2617
2618 // + concepts
2619 for (const auto &cd : *Doxygen::conceptLinkedMap)
2620 {
2621 msg("Generating Sqlite3 output for concept {}\n",cd->name());
2622 generateSqlite3ForConcept(cd.get());
2623 }
2624
2625 // + modules
2626 for (const auto &mod : ModuleManager::instance().modules())
2627 {
2628 msg("Generating Sqlite3 output for module {}\n",mod->name());
2629 generateSqlite3ForModule(mod.get());
2630 }
2631
2632 // + namespaces
2633 for (const auto &nd : *Doxygen::namespaceLinkedMap)
2634 {
2635 msg("Generating Sqlite3 output for namespace {}\n",nd->name());
2637 }
2638
2639 // + files
2640 for (const auto &fn : *Doxygen::inputNameLinkedMap)
2641 {
2642 for (const auto &fd : *fn)
2643 {
2644 msg("Generating Sqlite3 output for file {}\n",fd->name());
2645 generateSqlite3ForFile(fd.get());
2646 }
2647 }
2648
2649 // + groups
2650 for (const auto &gd : *Doxygen::groupLinkedMap)
2651 {
2652 msg("Generating Sqlite3 output for group {}\n",gd->name());
2653 generateSqlite3ForGroup(gd.get());
2654 }
2655
2656 // + page
2657 for (const auto &pd : *Doxygen::pageLinkedMap)
2658 {
2659 msg("Generating Sqlite3 output for page {}\n",pd->name());
2660 generateSqlite3ForPage(pd.get(),false);
2661 }
2662
2663 // + dirs
2664 for (const auto &dd : *Doxygen::dirLinkedMap)
2665 {
2666 msg("Generating Sqlite3 output for dir {}\n",dd->name());
2667 generateSqlite3ForDir(dd.get());
2668 }
2669
2670 // + examples
2671 for (const auto &pd : *Doxygen::exampleLinkedMap)
2672 {
2673 msg("Generating Sqlite3 output for example {}\n",pd->name());
2674 generateSqlite3ForPage(pd.get(),true);
2675 }
2676
2677 // + main page
2679 {
2680 msg("Generating Sqlite3 output for the main page\n");
2682 }
2683
2684 // TODO: copied from initializeSchema; not certain if we should say/do more
2685 // if there's a failure here?
2686 if (-1==initializeViews(db))
2687 return;
2688
2689 endTransaction(db);
2690}
2691
2692// vim: noai:ts=2:sw=2:ss=2:expandtab
This class contains the information about the argument of a function or template.
Definition arguments.h:27
DString name
Definition arguments.h:45
This class represents an function or template argument list.
Definition arguments.h:66
iterator end()
Definition arguments.h:95
size_t size() const
Definition arguments.h:101
bool constSpecifier() const
Definition arguments.h:112
bool empty() const
Definition arguments.h:100
iterator begin()
Definition arguments.h:94
bool volatileSpecifier() const
Definition arguments.h:113
A abstract class representing of a compound symbol.
Definition classdef.h:100
virtual const ArgumentList & templateArguments() const =0
Returns the template arguments of this class.
virtual const MemberLists & getMemberLists() const =0
Returns the list containing the list of members sorted per type.
virtual const BaseClassList & baseClasses() const =0
Returns the list of base classes from which this class directly inherits.
virtual Protection protection() const =0
Return the protection level (Public,Protected,Private) in which this compound was found.
virtual DString compoundTypeString() const =0
Returns the type of compound as a string.
virtual const MemberNameInfoLinkedMap & memberNameInfoLinkedMap() const =0
Returns a dictionary of all members.
virtual bool isImplicitTemplateInstance() const =0
virtual const MemberGroupList & getMemberGroups() const =0
Returns the member groups defined for this class.
virtual ClassLinkedRefMap getClasses() const =0
returns the classes nested into this class
virtual FileDef * getFileDef() const =0
Returns the file in which this compound's definition can be found.
virtual const IncludeInfo * includeInfo() const =0
virtual DString title() const =0
virtual const BaseClassList & subClasses() const =0
Returns the list of sub classes that directly derive from this class.
virtual ArgumentList getTemplateParameterList() const =0
virtual const FileDef * getFileDef() const =0
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:318
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
char & at(size_t i)
Returns a reference to the character at index i.
Definition dstring.h:686
DString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition dstring.h:337
const std::string & str() const
Definition dstring.h:645
bool stripPrefix(const DString &prefix)
Definition dstring.h:290
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition dstring.h:157
The common base class of all entity definitions found in the sources.
Definition definition.h:77
virtual DString briefDescription(bool abbreviate=false) const =0
virtual int getEndBodyLine() const =0
virtual DString getDefFileExtension() const =0
virtual int docLine() const =0
virtual DString getDefFileName() const =0
virtual DString documentation() const =0
virtual DString inbodyDocumentation() const =0
virtual int getDefLine() const =0
virtual DefType definitionType() const =0
virtual const DString & name() const =0
virtual const FileDef * getBodyDef() const =0
virtual size_t getDefColumn() const =0
virtual bool isAnonymous() const =0
virtual DString displayName(bool includeScope=true) const =0
virtual bool isHidden() const =0
virtual DString anchor() const =0
virtual Definition * getOuterScope() const =0
virtual DString docFile() const =0
virtual const MemberVector & getReferencedByMembers() const =0
virtual int getStartBodyLine() const =0
virtual bool isReference() const =0
virtual const MemberVector & getReferencesMembers() const =0
virtual DString getOutputFileBase() const =0
A model of a directory symbol.
Definition dirdef.h:108
virtual const DirList & subDirs() const =0
virtual const FileList & getFiles() const =0
Class representing a directory in the file system.
Definition dir.h:73
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:320
A list of directories.
Definition dirdef.h:178
Class representing the abstract syntax tree of a documentation block.
Definition docnode.h:1471
static NamespaceLinkedMap * namespaceLinkedMap
Definition doxygen.h:108
static ConceptLinkedMap * conceptLinkedMap
Definition doxygen.h:90
static std::unique_ptr< PageDef > mainPage
Definition doxygen.h:93
static FileNameLinkedMap * inputNameLinkedMap
Definition doxygen.h:97
static ClassLinkedMap * classLinkedMap
Definition doxygen.h:88
static PageLinkedMap * exampleLinkedMap
Definition doxygen.h:91
static PageLinkedMap * pageLinkedMap
Definition doxygen.h:92
static DirLinkedMap * dirLinkedMap
Definition doxygen.h:120
static GroupLinkedMap * groupLinkedMap
Definition doxygen.h:107
A model of a file symbol.
Definition filedef.h:97
virtual const NamespaceLinkedRefMap & getNamespaces() const =0
virtual const MemberGroupList & getMemberGroups() const =0
virtual DString absFilePath() const =0
virtual const DString & docName() const =0
virtual const ClassLinkedRefMap & getClasses() const =0
virtual const IncludeInfoList & includeFileList() const =0
virtual const MemberLists & getMemberLists() const =0
virtual DString title() const =0
virtual const ConceptLinkedRefMap & getConcepts() const =0
virtual const IncludeInfoList & includedByFileList() const =0
Minimal replacement for QFileInfo.
Definition fileinfo.h:26
bool exists() const
Definition fileinfo.cpp:34
std::string absFilePath() const
Definition fileinfo.cpp:105
A model of a group of symbols.
Definition groupdef.h:48
virtual DString groupTitle() const =0
virtual const GroupList & getSubGroups() const =0
virtual const FileList & getFiles() const =0
virtual const MemberLists & getMemberLists() const =0
virtual const MemberGroupList & getMemberGroups() const =0
virtual const ConceptLinkedRefMap & getConcepts() const =0
virtual const PageLinkedRefMap & getPages() const =0
virtual const NamespaceLinkedRefMap & getNamespaces() const =0
virtual const ClassLinkedRefMap & getClasses() const =0
virtual const ModuleLinkedRefMap & getModules() const =0
static HtmlEntityMapper & instance()
Returns the one and only instance of the HTML entity mapper.
DString convertCharEntitiesToUTF8(const DString &s) const
Class representing the data associated with a #include statement.
Definition filedef.h:72
const FileDef * fileDef
Definition filedef.h:77
DString includeName
Definition filedef.h:78
const T * find(const std::string &key) const
Definition linkedmap.h:47
A model of a class/file/namespace member symbol.
Definition memberdef.h:45
virtual bool isInitonly() const =0
virtual bool isAssign() const =0
virtual bool isExplicit() const =0
virtual bool isNew() const =0
virtual bool isMaybeVoid() const =0
virtual DString argsString() const =0
virtual bool isSealed() const =0
virtual DString definition() const =0
virtual const ClassDef * getClassDef() const =0
virtual const ArgumentList & templateArguments() const =0
virtual const DString & initializer() const =0
virtual bool isSettable() const =0
virtual bool isRetain() const =0
virtual bool isAddable() const =0
virtual const FileDef * getFileDef() const =0
virtual bool isInline() const =0
virtual DString getReadAccessor() const =0
virtual const ArgumentList & argumentList() const =0
virtual bool isWritable() const =0
virtual bool isMaybeAmbiguous() const =0
virtual bool isPrivateGettable() const =0
virtual bool isRequired() const =0
virtual bool isAttribute() const =0
virtual bool isExternal() const =0
virtual bool isCopy() const =0
virtual DString bitfieldString() const =0
virtual bool isStatic() const =0
virtual const MemberDef * reimplements() const =0
virtual bool isMaybeDefault() const =0
virtual bool isPrivateSettable() const =0
virtual bool isRaisable() const =0
virtual bool isRemovable() const =0
virtual bool isConstrained() const =0
virtual DString getWriteAccessor() const =0
virtual bool isReadonly() const =0
virtual bool isBound() const =0
virtual bool isThreadLocal() const =0
virtual DString getScopeString() const =0
virtual bool isProtectedSettable() const =0
virtual bool isProtectedGettable() const =0
virtual bool hasOneLineInitializer() const =0
virtual bool isTransient() const =0
virtual bool hasMultiLineInitializer() const =0
virtual Protection protection() const =0
virtual bool isOptional() const =0
virtual bool isGettable() const =0
virtual MemberType memberType() const =0
virtual bool isReadable() const =0
virtual bool isWeak() const =0
virtual bool isStrong() const =0
virtual DString typeString() const =0
virtual Specifier virtualness(int count=0) const =0
virtual bool isFinal() const =0
virtual const ArgumentList & declArgumentList() const =0
virtual DString memberTypeName() const =0
virtual bool isMutable() const =0
virtual bool isProperty() const =0
A list of MemberDef objects as shown in documentation sections.
Definition memberlist.h:126
MemberListType listType() const
Definition memberlist.h:131
constexpr bool isDeclaration() const noexcept
Definition types.h:384
constexpr bool isDetailed() const noexcept
Definition types.h:383
virtual const MemberGroupList & getMemberGroups() const =0
virtual const MemberLists & getMemberLists() const =0
virtual FileList getUsedFiles() const =0
virtual const ConceptLinkedRefMap & getConcepts() const =0
virtual const ClassLinkedRefMap & getClasses() const =0
static ModuleManager & instance()
An abstract interface of a namespace symbol.
virtual ConceptLinkedRefMap getConcepts() const =0
virtual const MemberLists & getMemberLists() const =0
virtual NamespaceLinkedRefMap getNamespaces() const =0
virtual DString title() const =0
virtual ClassLinkedRefMap getClasses() const =0
virtual const MemberGroupList & getMemberGroups() const =0
Class representing a list of different code generators.
Definition outputlist.h:162
void add(OutputCodeIntfPtr &&p)
Definition outputlist.h:192
A model of a page symbol.
Definition pagedef.h:27
virtual const PageLinkedRefMap & getSubPages() const =0
virtual DString title() const =0
virtual const GroupDef * getGroupDef() const =0
class that provide information about a section.
Definition section.h:58
DString title() const
Definition section.h:70
static SectionManager & instance()
returns a reference to the singleton
Definition section.h:179
Abstract interface for a hyperlinked text fragment.
Definition linkifytext.h:30
void writeBreak(int) const override
void writeLink(const DString &, const DString &file, const DString &anchor, std::string_view) const override
TextGeneratorSqlite3Impl(StringVector &l)
void writeString(std::string_view, bool) const override
Text streaming class that buffers data.
Definition textstream.h:36
std::string str() const
Return the contents of the buffer as a std::string object.
Definition textstream.h:232
Concrete visitor implementation for XML output.
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
std::vector< std::string > StringVector
Definition containers.h:33
DString dateToString(DateTimeType includeTime)
Returns the current date, when includeTime is set also the time is provided.
Definition datetime.cpp:64
IDocParserPtr createDocParser()
factory function to create a parser
Definition docparser.cpp:59
IDocNodeASTPtr validatingParseDoc(IDocParser &parserIntf, const DString &fileName, int startLine, const Definition *ctx, const MemberDef *md, const DString &input, const DocOptions &options)
const char * qPrint(const char *s)
Definition dstring.h:783
constexpr uint32_t IncludeKind_ImportMask
Definition filedef.h:62
constexpr uint32_t IncludeKind_LocalMask
Definition filedef.h:60
void linkifyText(const TextGeneratorIntf &out, const DString &text, const LinkifyTextOptions &options)
MemberDef * toMemberDef(Definition *d)
#define msg(fmt,...)
Definition message.h:94
#define err(fmt,...)
Definition message.h:127
SqlStmt memberdef_insert
static bool memberdefExists(struct Refid refid)
static void recordMetadata()
static int prepareStatement(sqlite3 *db, SqlStmt &s)
SqlStmt compounddef_exists
static bool compounddefExists(struct Refid refid)
SqlStmt incl_select
static bool insertMemberReference(struct Refid src_refid, struct Refid dst_refid, const char *context)
#define DBG_CTX(x)
static int initializeTables(sqlite3 *db)
static void stripQualifiers(DString &typeStr)
struct Refid insertRefid(const DString &refid)
static bool memberdefIncomplete(struct Refid refid, const MemberDef *md)
SqlStmt memberdef_incomplete
static void generateSqlite3ForModule(const ModuleDef *mod)
SqlStmt compoundref_insert
static void beginTransaction(sqlite3 *db)
static void generateSqlite3ForConcept(const ConceptDef *cd)
static void insertMemberFunctionParams(int memberdef_id, const MemberDef *md, const Definition *def)
static void writeInnerClasses(const ClassLinkedRefMap &cl, struct Refid outer_refid)
SqlStmt refid_insert
static void generateSqlite3ForGroup(const GroupDef *gd)
static void writeInnerConcepts(const ConceptLinkedRefMap &cl, struct Refid outer_refid)
static void writeInnerGroups(const GroupList &gl, struct Refid outer_refid)
static void writeInnerPages(const PageLinkedRefMap &pl, struct Refid outer_refid)
SqlStmt param_select
static void writeInnerNamespaces(const NamespaceLinkedRefMap &nl, struct Refid outer_refid)
static int prepareStatements(sqlite3 *db)
SqlStmt xrefs_insert
static void writeInnerModules(const ModuleLinkedRefMap &ml, struct Refid outer_refid)
SqlStmt reimplements_insert
static void insertMemberDefineParams(int memberdef_id, const MemberDef *md, const Definition *def)
static void writeTemplateList(const ClassDef *cd)
static void getSQLDesc(SqlStmt &s, const char *col, const DString &value, const Definition *def)
const char * table_schema[][2]
static void endTransaction(sqlite3 *db)
SqlStmt member_insert
static void generateSqlite3Section(const Definition *d, const MemberList *ml, struct Refid scope_refid, const char *, const DString &=DString(), const DString &=DString())
static void writeTemplateArgumentList(const ArgumentList &al, const Definition *scope, const FileDef *fileScope)
static void associateAllClassMembers(const ClassDef *cd, struct Refid scope_refid)
static void generateSqlite3ForDir(const DirDef *dd)
SqlStmt memberdef_update_def
SqlStmt contains_insert
const char * view_schema[][2]
SqlStmt incl_insert
SqlStmt memberdef_update_decl
static void writeInnerFiles(const FileList &fl, struct Refid outer_refid)
DString getSQLDocBlock(const Definition *scope, const Definition *def, const DString &doc, const DString &fileName, int lineNr)
SqlStmt memberdef_param_insert
static int initializeViews(sqlite3 *db)
SqlStmt path_insert
static int insertPath(DString name, bool local=true, bool found=true, int type=1)
static void getSQLDescCompound(SqlStmt &s, const char *col, const DString &value, const Definition *def)
static bool bindTextParameter(SqlStmt &s, const char *name, const DString &value)
static sqlite3 * openDbConnection()
SqlStmt meta_insert
static void generateSqlite3ForClass(const ClassDef *cd)
static void writeInnerDirs(const DirList &dl, struct Refid outer_refid)
static void generateSqlite3ForNamespace(const NamespaceDef *nd)
SqlStmt memberdef_exists
static void writeMemberTemplateLists(const MemberDef *md)
static void generateSqlite3ForMember(const MemberDef *md, struct Refid scope_refid, const Definition *def)
void generateSqlite3()
static void generateSqlite3ForFile(const FileDef *fd)
SqlStmt path_select
static void generateSqlite3ForPage(const PageDef *pd, bool isExample)
static int step(SqlStmt &s, bool getRowId=false, bool select=false)
SqlStmt param_insert
SqlStmt refid_select
static void pragmaTuning(sqlite3 *db)
SqlStmt compounddef_insert
static bool bindIntParameter(SqlStmt &s, const char *name, int value)
static void associateMember(const MemberDef *md, struct Refid member_refid, struct Refid scope_refid)
Helper class to pass options when calling OutputList::generateDoc().
Definition docoptions.h:24
LinkifyTextOptions & setScope(const Definition *scope)
Definition linkifytext.h:58
LinkifyTextOptions & setSelf(const Definition *self)
Definition linkifytext.h:64
LinkifyTextOptions & setFileScope(const FileDef *fileScope)
Definition linkifytext.h:61
bool created
DString refid
int rowid
const char * query
sqlite3 * db
sqlite3_stmt * stmt
bool mainPageHasTitle()
Definition util.cpp:4959
DString filterTitle(const DString &title)
Definition util.cpp:4454
DString stripFromPath(const DString &path)
Definition util.cpp:219
A bunch of utility functions.