1 /******************************************************************************
3 * Copyright (C) 2009-2015 by Joenio Costa.
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.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
17 * @brief Code parse based on doxyapp by Dimitri van Heesch
24 #include "outputgen.h"
25 #include "parserintf.h"
26 #include "classlist.h"
31 #include "arguments.h"
32 #include "memberlist.h"
39 class Doxyparse : public CodeOutputInterface
42 Doxyparse(FileDef *fd) : m_fd(fd) {}
45 // these are just null functions, they can be used to produce a syntax highlighted
46 // and cross-linked version of the source code, but who needs that anyway ;-)
47 void codify(const char *) {}
48 void writeCodeLink(const char *,const char *,const char *,const char *,const char *) {}
49 void startCodeLine() {}
51 void startCodeAnchor(const char *) {}
52 void endCodeAnchor() {}
53 void startFontClass(const char *) {}
54 void endFontClass() {}
55 void writeCodeAnchor(const char *) {}
56 void writeLineNumber(const char *,const char *,const char *,int) {}
57 virtual void writeTooltip(const char *,const DocLinkInfo &,
58 const char *,const char *,const SourceLinkInfo &,
59 const SourceLinkInfo &) {}
60 void startCodeLine(bool) {}
61 void setCurrentDoc(Definition *,const char *,bool) {}
62 void addWord(const char *,bool) {}
64 void linkableSymbol(int l, const char *sym, Definition *symDef, Definition *context)
67 // in this case we have a local or external symbol
69 // TODO record use of external symbols
70 // TODO must have a way to differentiate external symbols from local variables
78 static bool is_c_code = true;
79 static std::map<std::string, bool> modules;
80 static std::string current_module;
82 static void findXRefSymbols(FileDef *fd)
84 // get the interface to a parser that matches the file extension
85 ParserInterface *pIntf=Doxygen::parserManager->getParser(fd->getDefFileExtension());
87 // get the programming language from the file name
88 SrcLangExt lang = getLanguageFromFileName(fd->name());
90 // reset the parsers state
91 pIntf->resetCodeParserState();
93 // create a new backend object
94 Doxyparse *parse = new Doxyparse(fd);
96 // parse the source code
97 pIntf->parseCode(*parse, 0, fileToString(fd->absFilePath()), lang, FALSE, 0, fd);
99 // dismiss the object.
103 static bool ignoreStaticExternalCall(MemberDef *context, MemberDef *md) {
104 if (md->isStatic()) {
105 if(md->getFileDef()) {
106 if(md->getFileDef()->getOutputFileBase() == context->getFileDef()->getOutputFileBase())
107 // TODO ignore prefix of file
121 static void printFile(std::string file) {
122 printf("%s:\n", file.c_str());
124 static void printModule(std::string module) {
125 current_module = module;
126 printf(" %s:\n", module.c_str());
128 static void printClassInformation(std::string information) {
129 printf(" information: %s\n", information.c_str());
131 static void printInheritance(std::string base_class) {
132 printf(" inherits: %s\n", base_class.c_str());
134 static void printDefines() {
135 if (! modules[current_module]) {
136 printf(" defines:\n");
138 modules[current_module] = true;
140 static void printDefinition(std::string type, std::string signature, int line) {
141 printf(" - \"%s\":\n", signature.c_str());
142 printf(" type: %s\n", type.c_str());
143 printf(" line: %d\n", line);
145 static void printProtection(std::string protection) {
146 printf(" protection: %s\n", protection.c_str());
148 static void printNumberOfLines(int lines) {
149 printf(" lines_of_code: %d\n", lines);
151 static void printNumberOfArguments(int arguments) {
152 printf(" parameters: %d\n", arguments);
154 static void printUses() {
157 static void printReferenceTo(std::string type, std::string signature, std::string defined_in) {
158 printf(" - \"%s\":\n", signature.c_str());
159 printf(" type: %s\n", type.c_str());
160 printf(" defined_in: %s\n", defined_in.c_str());
162 static void printNumberOfConditionalPaths(MemberDef* md) {
163 printf(" conditional_paths: %d\n", md->numberOfFlowKeyWords());
166 static int isPartOfCStruct(MemberDef * md) {
167 return is_c_code && md->getClassDef() != NULL;
170 std::string removeDoubleQuotes(std::string data) {
171 // remove surrounding double quotes
172 if (data.front() == '"' && data.back() == '"') {
173 data.erase(0, 1); // first double quote
174 data.erase(data.size() - 1); // last double quote
179 std::string argumentData(Argument *argument) {
180 std::string data = "";
181 if (argument->type != NULL)
182 data = removeDoubleQuotes(argument->type.data());
183 else if (argument->name != NULL)
184 data = removeDoubleQuotes(argument->name.data());
188 std::string functionSignature(MemberDef* md) {
189 std::string signature = md->name().data();
190 if(md->isFunction()){
191 ArgumentList *argList = md->argumentList();
192 ArgumentListIterator iterator(*argList);
194 Argument * argument = iterator.toFirst();
195 if(argument != NULL) {
196 signature += argumentData(argument);
197 for(++iterator; (argument = iterator.current()); ++iterator){
198 signature += std::string(",") + argumentData(argument);
206 static void referenceTo(MemberDef* md) {
207 std::string type = md->memberTypeName().data();
208 std::string defined_in = "";
209 std::string signature = "";
210 if (isPartOfCStruct(md)) {
211 signature = md->getClassDef()->name().data() + std::string("::") + functionSignature(md);
212 defined_in = md->getClassDef()->getFileDef()->getOutputFileBase().data();
215 signature = functionSignature(md);
216 if (md->getClassDef()) {
217 defined_in = md->getClassDef()->name().data();
219 else if (md->getFileDef()) {
220 defined_in = md->getFileDef()->getOutputFileBase().data();
223 printReferenceTo(type, signature, defined_in);
226 void cModule(ClassDef* cd) {
227 MemberList* ml = cd->getMemberList(MemberListType_variableMembers);
229 MemberListIterator mli(*ml);
231 for (mli.toFirst(); (md=mli.current()); ++mli) {
232 printDefinition("variable", cd->name().data() + std::string("::") + md->name().data(), md->getDefLine());
233 if (md->protection() == Public) {
234 printProtection("public");
240 void functionInformation(MemberDef* md) {
241 int size = md->getEndBodyLine() - md->getStartBodyLine() + 1;
242 printNumberOfLines(size);
243 ArgumentList *argList = md->argumentList();
244 printNumberOfArguments(argList->count());
245 printNumberOfConditionalPaths(md);
246 MemberSDict *defDict = md->getReferencesMembers();
248 MemberSDict::Iterator msdi(*defDict);
251 for (msdi.toFirst(); (rmd=msdi.current()); ++msdi) {
252 if (rmd->definitionType() == Definition::TypeMember && !ignoreStaticExternalCall(md, rmd)) {
259 static void lookupSymbol(Definition *d) {
260 if (d->definitionType() == Definition::TypeMember) {
261 MemberDef *md = (MemberDef *)d;
262 std::string type = md->memberTypeName().data();
263 std::string signature = functionSignature(md);
264 printDefinition(type, signature, md->getDefLine());
265 if (md->protection() == Public) {
266 printProtection("public");
268 if (md->isFunction()) {
269 functionInformation(md);
274 void listMembers(MemberList *ml) {
276 MemberListIterator mli(*ml);
279 for (mli.toFirst(); (md=mli.current()); ++mli) {
280 lookupSymbol((Definition*) md);
285 void listAllMembers(ClassDef* cd) {
287 listMembers(cd->getMemberList(MemberListType_functionMembers));
289 listMembers(cd->getMemberList(MemberListType_constructors));
291 listMembers(cd->getMemberList(MemberListType_variableMembers));
294 static void classInformation(ClassDef* cd) {
298 printModule(cd->name().data());
299 BaseClassList* baseClasses = cd->baseClasses();
301 BaseClassListIterator bci(*baseClasses);
303 for (bci.toFirst(); (bcd = bci.current()); ++bci) {
304 printInheritance(bcd->classDef->name().data());
307 if(cd->isAbstract()) {
308 printClassInformation("abstract class");
314 static bool checkLanguage(std::string& filename, std::string extension) {
315 if (filename.find(extension, filename.size() - extension.size()) != std::string::npos) {
322 /* Detects the programming language of the project. Actually, we only care
323 * about whether it is a C project or not. */
324 static void detectProgrammingLanguage(FileNameListIterator& fnli) {
326 for (fnli.toFirst(); (fn=fnli.current()); ++fnli) {
327 std::string filename = fn->fileName();
329 checkLanguage(filename, ".cc") ||
330 checkLanguage(filename, ".cxx") ||
331 checkLanguage(filename, ".cpp") ||
332 checkLanguage(filename, ".java") ||
333 checkLanguage(filename, ".py") ||
334 checkLanguage(filename, ".pyw") ||
335 checkLanguage(filename, ".cs")
342 static void listSymbols() {
343 // iterate over the input files
344 FileNameListIterator fnli(*Doxygen::inputNameList);
347 detectProgrammingLanguage(fnli);
350 for (fnli.toFirst(); (fn=fnli.current()); ++fnli) {
351 FileNameIterator fni(*fn);
353 for (; (fd=fni.current()); ++fni) {
354 printFile(fd->absFilePath().data());
355 MemberList *ml = fd->getMemberList(MemberListType_allMembersList);
356 if (ml && ml->count() > 0) {
357 printModule(fd->getOutputFileBase().data());
361 ClassSDict *classes = fd->getClassSDict();
363 ClassSDict::Iterator cli(*classes);
365 for (cli.toFirst(); (cd = cli.current()); ++cli) {
366 classInformation(cd);
371 // TODO print external symbols referenced
374 int main(int argc,char **argv) {
376 printf("Usage: %s [source_file | source_dir]\n",argv[0]);
380 // initialize data structures
383 // check and finalize the configuration
384 checkConfiguration();
385 adjustConfiguration();
387 // setup the non-default configuration options
389 // we need a place to put intermediate files
390 std::ostringstream tmpdir;
391 tmpdir << "/tmp/doxyparse-" << getpid();
392 Config_getString(OUTPUT_DIRECTORY)= tmpdir.str().c_str();
393 // enable HTML (fake) output to omit warning about missing output format
394 Config_getBool(GENERATE_HTML)=TRUE;
395 // disable latex output
396 Config_getBool(GENERATE_LATEX)=FALSE;
398 Config_getBool(QUIET)=TRUE;
400 Config_getBool(WARNINGS)=FALSE;
401 Config_getBool(WARN_IF_UNDOCUMENTED)=FALSE;
402 Config_getBool(WARN_IF_DOC_ERROR)=FALSE;
403 // Extract as much as possible
404 Config_getBool(EXTRACT_ALL)=TRUE;
405 Config_getBool(EXTRACT_STATIC)=TRUE;
406 Config_getBool(EXTRACT_PRIVATE)=TRUE;
407 Config_getBool(EXTRACT_LOCAL_METHODS)=TRUE;
408 // Extract source browse information, needed
409 // to make doxygen gather the cross reference info
410 Config_getBool(SOURCE_BROWSER)=TRUE;
411 // find functions call between modules
412 Config_getBool(CALL_GRAPH)=TRUE;
413 // loop recursive over input files
414 Config_getBool(RECURSIVE)=TRUE;
416 Config_getList(INPUT).clear();
417 for (int i = 1; i < argc; i++) {
418 if (strcmp(argv[i], "-") == 0) {
421 scanf("%s[^\n]", filename);
425 Config_getList(INPUT).append(filename);
428 Config_getList(INPUT).append(argv[i]);
431 if (Config_getList(INPUT).isEmpty()) {
438 // iterate over the input files
439 FileNameListIterator fnli(*Doxygen::inputNameList);
441 // for each file with a certain name
442 for (fnli.toFirst();(fn=fnli.current());++fnli) {
443 FileNameIterator fni(*fn);
445 // for each file definition
446 for (;(fd=fni.current());++fni) {
447 // get the references (linked and unlinked) found in this file
452 // remove temporary files
453 if (!Doxygen::objDBFileName.isEmpty()) unlink(Doxygen::objDBFileName);
454 if (!Doxygen::entryDBFileName.isEmpty()) unlink(Doxygen::entryDBFileName);
456 rmdir(Config_getString(OUTPUT_DIRECTORY));
460 std::string cleanup_command = "rm -rf ";
461 cleanup_command += tmpdir.str();
462 system(cleanup_command.c_str());