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 functionSignature(MemberDef* md) {
171 std::string signature = md->name().data();
172 if(md->isFunction()){
173 ArgumentList *argList = md->argumentList();
174 ArgumentListIterator iterator(*argList);
176 Argument * argument = iterator.toFirst();
177 if(argument != NULL) {
178 signature += argument->type.data();
179 for(++iterator; (argument = iterator.current()) ;++iterator){
180 signature += std::string(",") + argument->type.data();
188 static void referenceTo(MemberDef* md) {
189 std::string type = md->memberTypeName().data();
190 std::string defined_in = "";
191 std::string signature = "";
192 if (isPartOfCStruct(md)) {
193 signature = md->getClassDef()->name().data() + std::string("::") + functionSignature(md);
194 defined_in = md->getClassDef()->getFileDef()->getOutputFileBase().data();
197 signature = functionSignature(md);
198 if (md->getClassDef()) {
199 defined_in = md->getClassDef()->name().data();
201 else if (md->getFileDef()) {
202 defined_in = md->getFileDef()->getOutputFileBase().data();
205 printReferenceTo(type, signature, defined_in);
208 void cModule(ClassDef* cd) {
209 MemberList* ml = cd->getMemberList(MemberListType_variableMembers);
211 MemberListIterator mli(*ml);
213 for (mli.toFirst(); (md=mli.current()); ++mli) {
214 printDefinition("variable", cd->name().data() + std::string("::") + md->name().data(), md->getDefLine());
215 if (md->protection() == Public) {
216 printProtection("public");
222 void functionInformation(MemberDef* md) {
223 int size = md->getEndBodyLine() - md->getStartBodyLine() + 1;
224 printNumberOfLines(size);
225 ArgumentList *argList = md->argumentList();
226 printNumberOfArguments(argList->count());
227 printNumberOfConditionalPaths(md);
228 MemberSDict *defDict = md->getReferencesMembers();
230 MemberSDict::Iterator msdi(*defDict);
233 for (msdi.toFirst(); (rmd=msdi.current()); ++msdi) {
234 if (rmd->definitionType() == Definition::TypeMember && !ignoreStaticExternalCall(md, rmd)) {
241 static void lookupSymbol(Definition *d) {
242 if (d->definitionType() == Definition::TypeMember) {
243 MemberDef *md = (MemberDef *)d;
244 std::string type = md->memberTypeName().data();
245 std::string signature = functionSignature(md);
246 printDefinition(type, signature, md->getDefLine());
247 if (md->protection() == Public) {
248 printProtection("protection public");
250 if (md->isFunction()) {
251 functionInformation(md);
256 void listMembers(MemberList *ml) {
258 MemberListIterator mli(*ml);
261 for (mli.toFirst(); (md=mli.current()); ++mli) {
262 lookupSymbol((Definition*) md);
267 void listAllMembers(ClassDef* cd) {
269 listMembers(cd->getMemberList(MemberListType_functionMembers));
271 listMembers(cd->getMemberList(MemberListType_constructors));
273 listMembers(cd->getMemberList(MemberListType_variableMembers));
276 static void classInformation(ClassDef* cd) {
280 printModule(cd->name().data());
281 BaseClassList* baseClasses = cd->baseClasses();
283 BaseClassListIterator bci(*baseClasses);
285 for (bci.toFirst(); (bcd = bci.current()); ++bci) {
286 printInheritance(bcd->classDef->name().data());
289 if(cd->isAbstract()) {
290 printClassInformation("abstract class");
296 static bool checkLanguage(std::string& filename, std::string extension) {
297 if (filename.find(extension, filename.size() - extension.size()) != std::string::npos) {
304 /* Detects the programming language of the project. Actually, we only care
305 * about whether it is a C project or not. */
306 static void detectProgrammingLanguage(FileNameListIterator& fnli) {
308 for (fnli.toFirst(); (fn=fnli.current()); ++fnli) {
309 std::string filename = fn->fileName();
311 checkLanguage(filename, ".cc") ||
312 checkLanguage(filename, ".cxx") ||
313 checkLanguage(filename, ".cpp") ||
314 checkLanguage(filename, ".java")
321 static void listSymbols() {
322 // iterate over the input files
323 FileNameListIterator fnli(*Doxygen::inputNameList);
326 detectProgrammingLanguage(fnli);
329 for (fnli.toFirst(); (fn=fnli.current()); ++fnli) {
330 FileNameIterator fni(*fn);
332 for (; (fd=fni.current()); ++fni) {
333 printFile(fd->absFilePath().data());
334 MemberList *ml = fd->getMemberList(MemberListType_allMembersList);
335 if (ml && ml->count() > 0) {
336 printModule(fd->getOutputFileBase().data());
340 ClassSDict *classes = fd->getClassSDict();
342 ClassSDict::Iterator cli(*classes);
344 for (cli.toFirst(); (cd = cli.current()); ++cli) {
345 classInformation(cd);
350 // TODO print external symbols referenced
353 int main(int argc,char **argv) {
355 printf("Usage: %s [source_file | source_dir]\n",argv[0]);
359 // initialize data structures
362 // check and finalize the configuration
363 checkConfiguration();
364 adjustConfiguration();
366 // setup the non-default configuration options
368 // we need a place to put intermediate files
369 std::ostringstream tmpdir;
370 tmpdir << "/tmp/doxyparse-" << getpid();
371 Config_getString(OUTPUT_DIRECTORY)= tmpdir.str().c_str();
372 // enable HTML (fake) output to omit warning about missing output format
373 Config_getBool(GENERATE_HTML)=TRUE;
374 // disable latex output
375 Config_getBool(GENERATE_LATEX)=FALSE;
377 Config_getBool(QUIET)=TRUE;
379 Config_getBool(WARNINGS)=FALSE;
380 Config_getBool(WARN_IF_UNDOCUMENTED)=FALSE;
381 Config_getBool(WARN_IF_DOC_ERROR)=FALSE;
382 // Extract as much as possible
383 Config_getBool(EXTRACT_ALL)=TRUE;
384 Config_getBool(EXTRACT_STATIC)=TRUE;
385 Config_getBool(EXTRACT_PRIVATE)=TRUE;
386 Config_getBool(EXTRACT_LOCAL_METHODS)=TRUE;
387 // Extract source browse information, needed
388 // to make doxygen gather the cross reference info
389 Config_getBool(SOURCE_BROWSER)=TRUE;
390 // find functions call between modules
391 Config_getBool(CALL_GRAPH)=TRUE;
392 // loop recursive over input files
393 Config_getBool(RECURSIVE)=TRUE;
395 Config_getList(INPUT).clear();
396 for (int i = 1; i < argc; i++) {
397 if (strcmp(argv[i], "-") == 0) {
400 scanf("%s[^\n]", filename);
404 Config_getList(INPUT).append(filename);
407 Config_getList(INPUT).append(argv[i]);
410 if (Config_getList(INPUT).isEmpty()) {
417 // iterate over the input files
418 FileNameListIterator fnli(*Doxygen::inputNameList);
420 // for each file with a certain name
421 for (fnli.toFirst();(fn=fnli.current());++fnli) {
422 FileNameIterator fni(*fn);
424 // for each file definition
425 for (;(fd=fni.current());++fni) {
426 // get the references (linked and unlinked) found in this file
431 // remove temporary files
432 if (!Doxygen::objDBFileName.isEmpty()) unlink(Doxygen::objDBFileName);
433 if (!Doxygen::entryDBFileName.isEmpty()) unlink(Doxygen::entryDBFileName);
435 rmdir(Config_getString(OUTPUT_DIRECTORY));
439 std::string cleanup_command = "rm -rf ";
440 cleanup_command += tmpdir.str();
441 system(cleanup_command.c_str());