summaryrefslogtreecommitdiffstats
path: root/addon/doxyparse/doxyparse.cpp
diff options
context:
space:
mode:
authorJoenio Costa <joenio@colivre.coop.br>2015-12-13 16:10:21 (GMT)
committerJoenio Costa <joenio@colivre.coop.br>2015-12-13 16:25:58 (GMT)
commite6dcc3b6c6dd449800eeebc172c1d15367d61d74 (patch)
tree1cb9a76ae8a3545b273a3dd40103f15ec9b68dc8 /addon/doxyparse/doxyparse.cpp
parenta7284cbd77518200d9cd4f5adb04cfc40f357d24 (diff)
downloadDoxygen-e6dcc3b6c6dd449800eeebc172c1d15367d61d74.zip
Doxygen-e6dcc3b6c6dd449800eeebc172c1d15367d61d74.tar.gz
Doxygen-e6dcc3b6c6dd449800eeebc172c1d15367d61d74.tar.bz2
new addon doxyparse, a source parsing engine
doxyparse parses source code and dumps the dependencies between the code elements. Today doxyparse is in use by Analizo* toolkit, a suite of source code analysis tools, aimed at being language-independent and extensible. * http://analizo.org Signed-off-by: Antonio Terceiro <terceiro@softwarelivre.org> Signed-off-by: João M. Miranda <joaomm88@gmail.com> Signed-off-by: Paulo Meirelles <paulo@softwarelivre.org> Signed-off-by: Vinicius Daros <vkdaros@mercurio.eclipse.ime.usp.br>
Diffstat (limited to 'addon/doxyparse/doxyparse.cpp')
-rw-r--r--addon/doxyparse/doxyparse.cpp449
1 files changed, 449 insertions, 0 deletions
diff --git a/addon/doxyparse/doxyparse.cpp b/addon/doxyparse/doxyparse.cpp
new file mode 100644
index 0000000..063a5f7
--- /dev/null
+++ b/addon/doxyparse/doxyparse.cpp
@@ -0,0 +1,449 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2015 by Joenio Costa.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+/** @file
+ * @brief Code parse based on doxyapp by Dimitri van Heesch
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "doxygen.h"
+#include "outputgen.h"
+#include "parserintf.h"
+#include "classlist.h"
+#include "config.h"
+#include "filedef.h"
+#include "util.h"
+#include "filename.h"
+#include "arguments.h"
+#include "memberlist.h"
+#include "types.h"
+#include <string>
+#include <cstdlib>
+#include <sstream>
+
+class Doxyparse : public CodeOutputInterface
+{
+ public:
+ Doxyparse(FileDef *fd) : m_fd(fd) {}
+ ~Doxyparse() {}
+
+ // these are just null functions, they can be used to produce a syntax highlighted
+ // and cross-linked version of the source code, but who needs that anyway ;-)
+ void codify(const char *) {}
+ void writeCodeLink(const char *,const char *,const char *,const char *,const char *) {}
+ void startCodeLine() {}
+ void endCodeLine() {}
+ void startCodeAnchor(const char *) {}
+ void endCodeAnchor() {}
+ void startFontClass(const char *) {}
+ void endFontClass() {}
+ void writeCodeAnchor(const char *) {}
+ void writeLineNumber(const char *,const char *,const char *,int) {}
+ virtual void writeTooltip(const char *,const DocLinkInfo &,
+ const char *,const char *,const SourceLinkInfo &,
+ const SourceLinkInfo &) {}
+ void startCodeLine(bool) {}
+ void setCurrentDoc(Definition *,const char *,bool) {}
+ void addWord(const char *,bool) {}
+
+ void linkableSymbol(int l, const char *sym, Definition *symDef, Definition *context)
+ {
+ if (!symDef) {
+ // in this case we have a local or external symbol
+
+ // TODO record use of external symbols
+ // TODO must have a way to differentiate external symbols from local variables
+ }
+ }
+
+ private:
+ FileDef *m_fd;
+};
+
+static bool is_c_code = true;
+
+static void findXRefSymbols(FileDef *fd)
+{
+ // get the interface to a parser that matches the file extension
+ ParserInterface *pIntf=Doxygen::parserManager->getParser(fd->getDefFileExtension());
+
+ // get the programming language from the file name
+ SrcLangExt lang = getLanguageFromFileName(fd->name());
+
+ // reset the parsers state
+ pIntf->resetCodeParserState();
+
+ // create a new backend object
+ Doxyparse *parse = new Doxyparse(fd);
+
+ // parse the source code
+ pIntf->parseCode(*parse, 0, fileToString(fd->absFilePath()), lang, FALSE, 0, fd);
+
+ // dismiss the object.
+ delete parse;
+}
+
+static bool ignoreStaticExternalCall(MemberDef *context, MemberDef *md) {
+ if (md->isStatic()) {
+ if(md->getFileDef()) {
+ if(md->getFileDef()->getFileBase() == context->getFileDef()->getFileBase())
+ // TODO ignore prefix of file
+ return false;
+ else
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+}
+
+void printArgumentList(MemberDef* md) {
+ ArgumentList *argList = md->argumentList();
+ ArgumentListIterator iterator(*argList);
+
+ printf("(");
+ Argument * argument = iterator.toFirst();
+ if(argument != NULL) {
+ printf("%s", argument->type.data());
+ for(++iterator; (argument = iterator.current()) ;++iterator){
+ printf(",%s", argument->type.data());
+ }
+ }
+ printf(")");
+}
+
+void printType(MemberDef* md) {
+ printf("%s ", md->memberTypeName().data());
+}
+
+void printSignature(MemberDef* md) {
+ printf("%s", md->name().data());
+ if(md->isFunction()){
+ printArgumentList(md);
+ }
+ printf(" ");
+}
+
+static void printWhereItWasDefined(MemberDef * md) {
+ if (md->getClassDef()) {
+ printf("defined in %s\n", md->getClassDef()->name().data());
+ }
+ else if (md->getFileDef()) {
+ printf("defined in %s\n", md->getFileDef()->getFileBase().data());
+ }
+ else {
+ printf("\n");
+ }
+}
+
+static void printCStructMember(MemberDef * md) {
+ printType(md);
+ printf("%s::", md->getClassDef()->name().data());
+ printSignature(md);
+ printf("defined in %s\n", md->getClassDef()->getFileDef()->getFileBase().data());
+}
+
+static int isPartOfCStruct(MemberDef * md) {
+ return is_c_code && md->getClassDef() != NULL;
+}
+
+static void printReferenceTo(MemberDef* md) {
+ printf(" uses ");
+ if (isPartOfCStruct(md)) {
+ printCStructMember(md);
+ }
+ else {
+ printType(md);
+ printSignature(md);
+ printWhereItWasDefined(md);
+ }
+}
+
+static void printReferencesMembers(MemberDef *md) {
+ MemberSDict *defDict = md->getReferencesMembers();
+ if (defDict) {
+ MemberSDict::Iterator msdi(*defDict);
+ MemberDef *rmd;
+ for (msdi.toFirst(); (rmd=msdi.current()); ++msdi) {
+ if (rmd->definitionType() == Definition::TypeMember && !ignoreStaticExternalCall(md, rmd)) {
+ printReferenceTo(rmd);
+ }
+ }
+ }
+}
+
+void printDefinitionLine(MemberDef* md) {
+ printf("in line %d\n", md->getDefLine());
+}
+
+void printDefinition(MemberDef* md) {
+ printf(" ");
+ printType(md);
+ printSignature(md);
+ printDefinitionLine(md);
+}
+
+static void printProtection(MemberDef* md) {
+ if (md->protection() == Public) {
+ printf(" protection public\n");
+ }
+}
+
+void printNumberOfLines(MemberDef* md) {
+ int size = md->getEndBodyLine() - md->getStartBodyLine() + 1;
+ printf(" %d lines of code\n", size);
+}
+
+void printNumberOfArguments(MemberDef* md) {
+ ArgumentList *argList = md->argumentList();
+ printf(" %d parameters\n", argList->count());
+}
+
+void printFunctionInformation(MemberDef* md) {
+ printNumberOfLines(md);
+ printNumberOfArguments(md);
+ printReferencesMembers(md);
+}
+
+static void lookupSymbol(Definition *d) {
+ if (d->definitionType() == Definition::TypeMember) {
+ MemberDef *md = (MemberDef *)d;
+ printDefinition(md);
+ printProtection(md);
+ if (md->isFunction()) {
+ printFunctionInformation(md);
+ }
+ }
+}
+
+void listMembers(MemberList *ml) {
+ if (ml) {
+ MemberListIterator mli(*ml);
+ MemberDef *md;
+ for (mli.toFirst(); (md=mli.current()); ++mli) {
+ lookupSymbol((Definition*) md);
+ }
+ }
+}
+
+static void printInheritance(ClassDef* cd) {
+ BaseClassList* baseClasses = cd->baseClasses();
+ if (baseClasses) {
+ BaseClassListIterator bci(*baseClasses);
+ BaseClassDef* bcd;
+ for (bci.toFirst(); (bcd = bci.current()); ++bci) {
+ printf(" inherits from %s\n", bcd->classDef->name().data());
+ }
+ }
+}
+
+void printCModule(ClassDef* cd) {
+ MemberList* ml = cd->getMemberList(MemberListType_variableMembers);
+ if (ml) {
+ MemberListIterator mli(*ml);
+ MemberDef* md;
+ for (mli.toFirst(); (md=mli.current()); ++mli) {
+ printf(" variable %s::%s in line %d\n", cd->name().data(), md->name().data(), md->getDefLine());
+ printProtection(md);
+ }
+ }
+}
+
+void listAllMembers(ClassDef* cd) {
+ // methods
+ listMembers(cd->getMemberList(MemberListType_functionMembers));
+ // constructors
+ listMembers(cd->getMemberList(MemberListType_constructors));
+ // attributes
+ listMembers(cd->getMemberList(MemberListType_variableMembers));
+}
+
+void printClassInformation(ClassDef* cd) {
+ printf("module %s\n", cd->name().data());
+ printInheritance(cd);
+ if(cd->isAbstract()) {
+ printf(" abstract class\n");
+ }
+ listAllMembers(cd);
+}
+
+static void printClass(ClassDef* cd) {
+ if (is_c_code) {
+ printCModule(cd);
+ } else {
+ printClassInformation(cd);
+ }
+}
+
+static void printFile(FileDef* fd) {
+ printf("file %s\n", fd->absFilePath().data());
+ MemberList *ml = fd->getMemberList(MemberListType_allMembersList);
+ if (ml && ml->count() > 0) {
+ printf("module %s\n", fd->getFileBase().data());
+ listMembers(ml);
+ }
+}
+
+static bool checkLanguage(std::string& filename, std::string extension) {
+ if (filename.find(extension, filename.size() - extension.size()) != std::string::npos) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* Detects the programming language of the project. Actually, we only care
+ * about whether it is a C project or not. */
+static void detectProgrammingLanguage(FileNameListIterator& fnli) {
+ FileName* fn;
+ for (fnli.toFirst(); (fn=fnli.current()); ++fnli) {
+ std::string filename = fn->fileName();
+ if (
+ checkLanguage(filename, ".cc") ||
+ checkLanguage(filename, ".cxx") ||
+ checkLanguage(filename, ".cpp") ||
+ checkLanguage(filename, ".java")
+ ) {
+ is_c_code = false;
+ }
+ }
+}
+
+static void listSymbols() {
+ // iterate over the input files
+ FileNameListIterator fnli(*Doxygen::inputNameList);
+ FileName *fn;
+
+ detectProgrammingLanguage(fnli);
+
+ // for each file
+ for (fnli.toFirst(); (fn=fnli.current()); ++fnli) {
+ FileNameIterator fni(*fn);
+ FileDef *fd;
+ for (; (fd=fni.current()); ++fni) {
+ printFile(fd);
+
+ ClassSDict *classes = fd->getClassSDict();
+ if (classes) {
+ ClassSDict::Iterator cli(*classes);
+ ClassDef *cd;
+ for (cli.toFirst(); (cd = cli.current()); ++cli) {
+ printClass(cd);
+ }
+ }
+ }
+ }
+ // TODO print external symbols referenced
+}
+
+int main(int argc,char **argv) {
+ if (argc < 2) {
+ printf("Usage: %s [source_file | source_dir]\n",argv[0]);
+ exit(1);
+ }
+
+ // initialize data structures
+ initDoxygen();
+
+ // setup the non-default configuration options
+
+ // we need a place to put intermediate files
+ std::ostringstream tmpdir;
+ tmpdir << "/tmp/doxyparse-" << getpid();
+ Config_getString("OUTPUT_DIRECTORY")= tmpdir.str().c_str();
+
+ // enable HTML (fake) output to omit warning about missing output format
+ Config_getBool("GENERATE_HTML")=TRUE;
+ // disable latex output
+ Config_getBool("GENERATE_LATEX")=FALSE;
+ // be quiet
+ Config_getBool("QUIET")=TRUE;
+ // turn off warnings
+ Config_getBool("WARNINGS")=FALSE;
+ Config_getBool("WARN_IF_UNDOCUMENTED")=FALSE;
+ Config_getBool("WARN_IF_DOC_ERROR")=FALSE;
+ // Extract as much as possible
+ Config_getBool("EXTRACT_ALL")=TRUE;
+ Config_getBool("EXTRACT_STATIC")=TRUE;
+ Config_getBool("EXTRACT_PRIVATE")=TRUE;
+ Config_getBool("EXTRACT_LOCAL_METHODS")=TRUE;
+ // Extract source browse information, needed
+ // to make doxygen gather the cross reference info
+ Config_getBool("SOURCE_BROWSER")=TRUE;
+ // find functions call between modules
+ Config_getBool("CALL_GRAPH")=TRUE;
+ // loop recursive over input files
+ Config_getBool("RECURSIVE")=TRUE;
+ // set the input
+ Config_getList("INPUT").clear();
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-") == 0) {
+ char filename[1024];
+ while (1) {
+ scanf("%s[^\n]", filename);
+ if (feof(stdin)) {
+ break;
+ }
+ Config_getList("INPUT").append(filename);
+ }
+ } else {
+ Config_getList("INPUT").append(argv[i]);
+ }
+ }
+ if (Config_getList("INPUT").isEmpty()) {
+ exit(0);
+ }
+
+ // check and finalize the configuration
+ checkConfiguration();
+ adjustConfiguration();
+
+ // parse the files
+ parseInput();
+
+ // iterate over the input files
+ FileNameListIterator fnli(*Doxygen::inputNameList);
+ FileName *fn;
+ // for each file with a certain name
+ for (fnli.toFirst();(fn=fnli.current());++fnli) {
+ FileNameIterator fni(*fn);
+ FileDef *fd;
+ // for each file definition
+ for (;(fd=fni.current());++fni) {
+ // get the references (linked and unlinked) found in this file
+ findXRefSymbols(fd);
+ }
+ }
+
+ // remove temporary files
+ if (!Doxygen::objDBFileName.isEmpty()) unlink(Doxygen::objDBFileName);
+ if (!Doxygen::entryDBFileName.isEmpty()) unlink(Doxygen::entryDBFileName);
+ // clean up after us
+ rmdir(Config_getString("OUTPUT_DIRECTORY"));
+
+ listSymbols();
+
+ std::string cleanup_command = "rm -rf ";
+ cleanup_command += tmpdir.str();
+ system(cleanup_command.c_str());
+
+ exit(0);
+}