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