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