From 50fdb591d4abfdf88bfdda96ffd832cc4c024963 Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Wed, 15 Jul 2020 21:23:12 +0200 Subject: Refactor: Modernize clang parser and make it run with multiple threads --- src/clangparser.cpp | 535 +++++++++++++++++++++++---------------------------- src/clangparser.h | 80 +++++++- src/doxygen.cpp | 276 +++++++++++++++++--------- src/filedef.cpp | 65 ++----- src/filedef.h | 10 +- src/fortranscanner.h | 11 +- src/fortranscanner.l | 3 +- src/markdown.cpp | 3 +- src/markdown.h | 5 +- src/parserintf.h | 26 +-- src/pyscanner.h | 15 +- src/pyscanner.l | 5 +- src/scanner.h | 13 +- src/scanner.l | 61 ++---- src/vhdldocgen.cpp | 6 +- src/vhdljjparser.cpp | 2 +- src/vhdljjparser.h | 7 +- 17 files changed, 573 insertions(+), 550 deletions(-) diff --git a/src/clangparser.cpp b/src/clangparser.cpp index e0a1640..2ca5998 100644 --- a/src/clangparser.cpp +++ b/src/clangparser.cpp @@ -20,17 +20,22 @@ #include "membername.h" #include "filename.h" #include "tooltip.h" +#if MULTITHREADED_INPUT +#include +#endif +#endif -static Definition *g_currentDefinition=0; -static MemberDef *g_currentMemberDef=0; -static uint g_currentLine=0; -static bool g_searchForBody=FALSE; -static bool g_insideBody=FALSE; -static uint g_bracketCount=0; +//-------------------------------------------------------------------------- + +#if MULTITHREADED_INPUT +std::mutex g_clangMutex; #endif ClangParser *ClangParser::instance() { +#if MULTITHREADED_INPUT + std::lock_guard lock(g_clangMutex); +#endif if (!s_instance) s_instance = new ClangParser; return s_instance; } @@ -40,29 +45,7 @@ ClangParser *ClangParser::s_instance = 0; //-------------------------------------------------------------------------- #if USE_LIBCLANG -class ClangParser::Private -{ - public: - enum DetectedLang { Detected_Cpp, Detected_ObjC, Detected_ObjCpp }; - Private() : tu(0), tokens(0), numTokens(0), cursors(0), - ufs(0), sources(0), numFiles(0), fileMapping(257), - detectedLang(Detected_Cpp) - { fileMapping.setAutoDelete(TRUE); } - int getCurrentTokenLine(); - CXIndex index; - CXTranslationUnit tu; - QCString fileName; - CXToken *tokens; - uint numTokens; - CXCursor *cursors; - uint curLine; - uint curToken; - CXUnsavedFile *ufs; - QCString *sources; - uint numFiles; - QDict fileMapping; - DetectedLang detectedLang; -}; +enum class DetectedLang { Cpp, ObjC, ObjCpp }; static QCString detab(const QCString &s) { @@ -118,83 +101,89 @@ static QCString detab(const QCString &s) return out.get(); } -/** Callback function called for each include in a translation unit */ -static void inclusionVisitor(CXFile includedFile, - CXSourceLocation* /*inclusionStack*/, - unsigned /*includeLen*/, - CXClientData clientData) +static QCString keywordToType(const char *keyword) { - QDict *fileDict = (QDict *)clientData; - CXString incFileName = clang_getFileName(includedFile); - //printf("--- file %s includes %s\n",fileName,clang_getCString(incFileName)); - fileDict->insert(clang_getCString(incFileName),(void*)0x8); - clang_disposeString(incFileName); + static const StringUnorderedSet flowKeywords({ + "break", "case", "catch", "continue", "default", "do", + "else", "finally", "for", "foreach", "for each", "goto", + "if", "return", "switch", "throw", "throws", "try", + "while", "@try", "@catch", "@finally" }); + static const StringUnorderedSet typeKeywords({ + "bool", "char", "double", "float", "int", "long", "object", + "short", "signed", "unsigned", "void", "wchar_t", "size_t", + "boolean", "id", "SEL", "string", "nullptr" }); + if (flowKeywords.find(keyword)!=flowKeywords.end()) return "keywordflow"; + if (typeKeywords.find(keyword)!=typeKeywords.end()) return "keywordtype"; + return "keyword"; } -/** filter the \a files and only keep those that are found as include files - * within the current translation unit. - * @param[in,out] files The list of files to filter. - */ -void ClangParser::determineInputFilesInSameTu(QStrList &files) + +//-------------------------------------------------------------------------- + +class ClangTUParser::Private +{ + public: + Private(const ClangParser &p,const FileDef *fd) + : parser(p), fileDef(fd) {} + const ClangParser &parser; + const FileDef *fileDef; + CXIndex index; + uint curToken = 0; + DetectedLang detectedLang = DetectedLang::Cpp; + uint numFiles = 0; + std::vector sources; + std::vector ufs; + std::vector cursors; + std::unordered_map fileMapping; + CXTranslationUnit tu; + CXToken *tokens = 0; + uint numTokens = 0; + StringVector filesInSameTU; + + // state while parsing sources + MemberDef *currentMemberDef=0; + uint currentLine=0; + bool searchForBody=FALSE; + bool insideBody=FALSE; + uint bracketCount=0; +}; + +ClangTUParser::ClangTUParser(const ClangParser &parser,const FileDef *fd) + : p(std::make_unique(parser,fd)) { - // put the files in this translation unit in a dictionary - QDict incFound(257); - clang_getInclusions(p->tu, - inclusionVisitor, - (CXClientData)&incFound - ); - // create a new filtered file list - QStrList resultIncludes; - QStrListIterator it2(files); - for (it2.toFirst();it2.current();++it2) - { - if (incFound.find(it2.current())) - { - resultIncludes.append(it2.current()); - } - } - // replace the original list - files=resultIncludes; } -void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) +StringVector ClangTUParser::filesInSameTU() const { + return p->filesInSameTU; +} + +void ClangTUParser::parse() +{ + QCString fileName = p->fileDef->absFilePath(); + p->fileDef->getAllIncludeFilesRecursively(p->filesInSameTU); + //printf("ClangTUParser::ClangTUParser(fileName=%s,#filesInSameTU=%d)\n", + // qPrint(fileName),(int)p->filesInSameTU.size()); bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); + bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); const StringVector &includePath = Config_getList(INCLUDE_PATH); const StringVector &clangOptions = Config_getList(CLANG_OPTIONS); - QCString clangCompileDatabase = Config_getString(CLANG_DATABASE_PATH); if (!clangAssistedParsing) return; //printf("ClangParser::start(%s)\n",fileName); - p->fileName = fileName; p->index = clang_createIndex(0, 0); - p->curLine = 1; p->curToken = 0; int argc=0; - std::string error; - // load a clang compilation database (https://clang.llvm.org/docs/JSONCompilationDatabase.html) - // this only needs to be loaded once, and could be refactored to a higher level function - static std::unique_ptr db = - clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.data(), error); - int clang_option_len = 0; + size_t clang_option_len = 0; std::vector command; - if (qstrcmp(clangCompileDatabase, "0") != 0) + if (p->parser.database()!=nullptr) { - if (db == nullptr) - { - // user specified a path, but DB file was not found - err("%s using clang compilation database path of: \"%s\"\n", error.c_str(), - clangCompileDatabase.data()); - } - else - { - // check if the file we are parsing is in the DB - command = db->getCompileCommands(fileName); - if (!command.empty() ) - { - // it's possible to have multiple entries for the same file, so use the last entry - clang_option_len = command[command.size()-1].CommandLine.size(); - } - } + // check if the file we are parsing is in the DB + command = p->parser.database()->getCompileCommands(fileName.data()); + if (!command.empty() ) + { + // it's possible to have multiple entries for the same file, so use the last entry + clang_option_len = command[command.size()-1].CommandLine.size(); + } } char **argv = (char**)malloc(sizeof(char*)* (4+Doxygen::inputPaths.size()+ @@ -203,14 +192,19 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) clang_option_len)); if (!command.empty() ) { - std::vector options = command[command.size()-1].CommandLine; - // copy each compiler option used from the database. Skip the first which is compiler exe. - for (auto option = options.begin()+1; option != options.end(); option++) - { - argv[argc++] = qstrdup(option->c_str()); - } - // this extra addition to argv is accounted for as we are skipping the first entry in - argv[argc++]=qstrdup("-w"); // finally, turn off warnings. + std::vector options = command[command.size()-1].CommandLine; + // copy each compiler option used from the database. Skip the first which is compiler exe. + for (auto option = options.begin()+1; option != options.end(); option++) + { + argv[argc++] = qstrdup(option->c_str()); + } + // user specified options + for (size_t i=0;idetectedLang!=ClangParser::Private::Detected_Cpp) + if (lang==SrcLangExt_ObjC || p->detectedLang!=DetectedLang::Cpp) { QCString fn = fileName; - if (p->detectedLang==ClangParser::Private::Detected_Cpp && + if (p->detectedLang!=DetectedLang::Cpp && (fn.right(4).lower()==".cpp" || fn.right(4).lower()==".cxx" || fn.right(3).lower()==".cc" || fn.right(2).lower()==".c")) { // fall back to C/C++ once we see an extension that indicates this - p->detectedLang = ClangParser::Private::Detected_Cpp; + p->detectedLang = DetectedLang::Cpp; } else if (fn.right(3).lower()==".mm") // switch to Objective C++ { - p->detectedLang = ClangParser::Private::Detected_ObjCpp; + p->detectedLang = DetectedLang::ObjCpp; } else if (fn.right(2).lower()==".m") // switch to Objective C { - p->detectedLang = ClangParser::Private::Detected_ObjC; + p->detectedLang = DetectedLang::ObjC; } } - switch(p->detectedLang) + switch (p->detectedLang) { - case ClangParser::Private::Detected_Cpp: - argv[argc++]=qstrdup("c++"); - break; - case ClangParser::Private::Detected_ObjC: - argv[argc++]=qstrdup("objective-c"); - break; - case ClangParser::Private::Detected_ObjCpp: - argv[argc++]=qstrdup("objective-c++"); - break; + case DetectedLang::Cpp: argv[argc++]=qstrdup("c++"); break; + case DetectedLang::ObjC: argv[argc++]=qstrdup("objective-c"); break; + case DetectedLang::ObjCpp: argv[argc++]=qstrdup("objective-c++"); break; } // provide the input and and its dependencies as unsaved files so we can // pass the filtered versions argv[argc++]=qstrdup(fileName); } - static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); //printf("source %s ----------\n%s\n-------------\n\n", // fileName,p->source.data()); - int numUnsavedFiles = filesInTranslationUnit.count()+1; + int numUnsavedFiles = static_cast(p->filesInSameTU.size()+1); p->numFiles = numUnsavedFiles; - p->sources = new QCString[numUnsavedFiles]; - p->ufs = new CXUnsavedFile[numUnsavedFiles]; + p->sources.resize(numUnsavedFiles); + p->ufs.resize(numUnsavedFiles); p->sources[0] = detab(fileToString(fileName,filterSourceFiles,TRUE)); p->ufs[0].Filename = qstrdup(fileName); p->ufs[0].Contents = p->sources[0].data(); p->ufs[0].Length = p->sources[0].length(); - QStrListIterator it(filesInTranslationUnit); + p->fileMapping.insert({fileName.data(),0}); int i=1; - for (it.toFirst();it.current() && ifilesInSameTU.begin(); + it != p->filesInSameTU.end() && ifileMapping.insert(it.current(),new uint(i)); - p->sources[i] = detab(fileToString(it.current(),filterSourceFiles,TRUE)); - p->ufs[i].Filename = qstrdup(it.current()); + p->fileMapping.insert({it->c_str(),static_cast(i)}); + p->sources[i] = detab(fileToString(it->c_str(),filterSourceFiles,TRUE)); + p->ufs[i].Filename = qstrdup(it->c_str()); p->ufs[i].Contents = p->sources[i].data(); p->ufs[i].Length = p->sources[i].length(); } // let libclang do the actual parsing p->tu = clang_parseTranslationUnit(p->index, 0, - argv, argc, p->ufs, numUnsavedFiles, + argv, argc, p->ufs.data(), numUnsavedFiles, CXTranslationUnit_DetailedPreprocessingRecord); + //printf(" tu=%p\n",p->tu); // free arguments for (i=0;itu) { - // filter out any includes not found by the clang parser - determineInputFilesInSameTu(filesInTranslationUnit); - // show any warnings that the compiler produced int n=clang_getNumDiagnostics(p->tu); for (i=0; i!=n; ++i) @@ -325,105 +312,74 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) clang_disposeString(string); clang_disposeDiagnostic(diag); } - - // create a source range for the given file - QFileInfo fi(fileName); - CXFile f = clang_getFile(p->tu, fileName); - CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); - CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[0].Length); - CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); - - // produce a token stream for the file - clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); - - // produce cursors for each token in the stream - p->cursors=new CXCursor[p->numTokens]; - clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors); } else { p->tokens = 0; p->numTokens = 0; - p->cursors = 0; - err("clang: Failed to parse translation unit %s\n",fileName); - } -} - -void ClangParser::switchToFile(const char *fileName) -{ - if (p->tu) - { - delete[] p->cursors; - clang_disposeTokens(p->tu,p->tokens,p->numTokens); - p->tokens = 0; - p->numTokens = 0; - p->cursors = 0; - - QFileInfo fi(fileName); - CXFile f = clang_getFile(p->tu, fileName); - uint *pIndex=p->fileMapping.find(fileName); - if (pIndex && *pIndexnumFiles) - { - uint i=*pIndex; - //printf("switchToFile %s: len=%ld\n",fileName,p->ufs[i].Length); - CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); - CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[i].Length); - CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); - - clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); - p->cursors=new CXCursor[p->numTokens]; - clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors); - - p->curLine = 1; - p->curToken = 0; - } - else - { - err("clang: Failed to find input file %s in mapping\n",fileName); - } + p->cursors.clear(); + err("clang: Failed to parse translation unit %s\n",qPrint(fileName)); } } -void ClangParser::finish() +ClangTUParser::~ClangTUParser() { + //printf("ClangTUParser::~ClangTUParser() tu=%p\n",p->tu); static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); if (!clangAssistedParsing) return; if (p->tu) { - //printf("ClangParser::finish()\n"); - delete[] p->cursors; + p->cursors.clear(); clang_disposeTokens(p->tu,p->tokens,p->numTokens); clang_disposeTranslationUnit(p->tu); clang_disposeIndex(p->index); p->fileMapping.clear(); p->tokens = 0; p->numTokens = 0; - p->cursors = 0; } for (uint i=0;inumFiles;i++) { free((void *)p->ufs[i].Filename); } - delete[] p->ufs; - delete[] p->sources; - p->ufs = 0; - p->sources = 0; + p->ufs.clear(); + p->sources.clear(); p->numFiles = 0; p->tu = 0; } -int ClangParser::Private::getCurrentTokenLine() +void ClangTUParser::switchToFile(FileDef *fd) { - uint l, c; - if (numTokens==0) return 1; - // guard against filters that reduce the number of lines - if (curToken>=numTokens) curToken=numTokens-1; - CXSourceLocation start = clang_getTokenLocation(tu,tokens[curToken]); - clang_getSpellingLocation(start, 0, &l, &c, 0); - return l; + //printf("ClangTUParser::switchToFile(%s)\n",qPrint(fd->absFilePath())); + if (p->tu) + { + p->cursors.clear(); + clang_disposeTokens(p->tu,p->tokens,p->numTokens); + p->tokens = 0; + p->numTokens = 0; + + CXFile f = clang_getFile(p->tu, fd->absFilePath()); + auto it = p->fileMapping.find(fd->absFilePath().data()); + if (it!=p->fileMapping.end() && it->second < p->numFiles) + { + uint i = it->second; + //printf("switchToFile %s: len=%ld\n",fileName,p->ufs[i].Length); + CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); + CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[i].Length); + CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); + + clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); + p->cursors.resize(p->numTokens); + clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors.data()); + p->curToken = 0; + } + else + { + err("clang: Failed to find input file %s in mapping\n",qPrint(fd->absFilePath())); + } + } } -QCString ClangParser::lookup(uint line,const char *symbol) +QCString ClangTUParser::lookup(uint line,const char *symbol) { //printf("ClangParser::lookup(%d,%s)\n",line,symbol); QCString result; @@ -431,19 +387,30 @@ QCString ClangParser::lookup(uint line,const char *symbol) static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); if (!clangAssistedParsing) return result; + auto getCurrentTokenLine = [=]() -> uint + { + uint l, c; + if (p->numTokens==0) return 1; + // guard against filters that reduce the number of lines + if (p->curToken>=p->numTokens) p->curToken=p->numTokens-1; + CXSourceLocation start = clang_getTokenLocation(p->tu,p->tokens[p->curToken]); + clang_getSpellingLocation(start, 0, &l, &c, 0); + return l; + }; + int sl = strlen(symbol); - uint l = p->getCurrentTokenLine(); + uint l = getCurrentTokenLine(); while (l>=line && p->curToken>0) { if (l==line) // already at the right line { p->curToken--; // linear search to start of the line - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); } else { p->curToken/=2; // binary search backward - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); } } bool found=FALSE; @@ -468,7 +435,7 @@ QCString ClangParser::lookup(uint line,const char *symbol) { break; // end of token stream } - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); clang_disposeString(tokenString); tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]); ts = clang_getCString(tokenString); @@ -505,7 +472,7 @@ QCString ClangParser::lookup(uint line,const char *symbol) p->curToken++; if (p->curTokennumTokens) { - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); } } //if (!found) @@ -519,78 +486,23 @@ QCString ClangParser::lookup(uint line,const char *symbol) return result; } -static QCString keywordToType(const char *keyword) -{ - static bool init=TRUE; - static QDict flowKeywords(47); - static QDict typeKeywords(47); - if (init) - { - flowKeywords.insert("break",(void*)0x8); - flowKeywords.insert("case",(void*)0x8); - flowKeywords.insert("catch",(void*)0x8); - flowKeywords.insert("continue",(void*)0x8); - flowKeywords.insert("default",(void*)0x8); - flowKeywords.insert("do",(void*)0x8); - flowKeywords.insert("else",(void*)0x8); - flowKeywords.insert("finally",(void*)0x8); - flowKeywords.insert("for",(void*)0x8); - flowKeywords.insert("foreach",(void*)0x8); - flowKeywords.insert("for each",(void*)0x8); - flowKeywords.insert("goto",(void*)0x8); - flowKeywords.insert("if",(void*)0x8); - flowKeywords.insert("return",(void*)0x8); - flowKeywords.insert("switch",(void*)0x8); - flowKeywords.insert("throw",(void*)0x8); - flowKeywords.insert("throws",(void*)0x8); - flowKeywords.insert("try",(void*)0x8); - flowKeywords.insert("while",(void*)0x8); - flowKeywords.insert("@try",(void*)0x8); - flowKeywords.insert("@catch",(void*)0x8); - flowKeywords.insert("@finally",(void*)0x8); - - typeKeywords.insert("bool",(void*)0x8); - typeKeywords.insert("char",(void*)0x8); - typeKeywords.insert("double",(void*)0x8); - typeKeywords.insert("float",(void*)0x8); - typeKeywords.insert("int",(void*)0x8); - typeKeywords.insert("long",(void*)0x8); - typeKeywords.insert("object",(void*)0x8); - typeKeywords.insert("short",(void*)0x8); - typeKeywords.insert("signed",(void*)0x8); - typeKeywords.insert("unsigned",(void*)0x8); - typeKeywords.insert("void",(void*)0x8); - typeKeywords.insert("wchar_t",(void*)0x8); - typeKeywords.insert("size_t",(void*)0x8); - typeKeywords.insert("boolean",(void*)0x8); - typeKeywords.insert("id",(void*)0x8); - typeKeywords.insert("SEL",(void*)0x8); - typeKeywords.insert("string",(void*)0x8); - typeKeywords.insert("nullptr",(void*)0x8); - init=FALSE; - } - if (flowKeywords[keyword]) return "keywordflow"; - if (typeKeywords[keyword]) return "keywordtype"; - return "keyword"; -} -static void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) +void ClangTUParser::writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) { Definition *d = fd ? fd->getSourceDefinition(line) : 0; if (d && d->isLinkable()) { - g_currentDefinition=d; - g_currentLine=line; + p->currentLine=line; MemberDef *md = fd->getSourceMember(line); if (md && md->isLinkable()) // link to member { - if (g_currentMemberDef!=md) // new member, start search for body + if (p->currentMemberDef!=md) // new member, start search for body { - g_searchForBody=TRUE; - g_insideBody=FALSE; - g_bracketCount=0; + p->searchForBody=TRUE; + p->insideBody=FALSE; + p->bracketCount=0; } - g_currentMemberDef=md; + p->currentMemberDef=md; ol.writeLineNumber(md->getReference(), md->getOutputFileBase(), md->anchor(), @@ -598,7 +510,7 @@ static void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) } else // link to compound { - g_currentMemberDef=0; + p->currentMemberDef=0; ol.writeLineNumber(d->getReference(), d->getOutputFileBase(), d->anchor(), @@ -621,8 +533,8 @@ static void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) //printf("writeLineNumber(%d) g_searchForBody=%d\n",line,g_searchForBody); } -static void codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, - uint &line,uint &column,const char *fontClass=0) +void ClangTUParser::codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, + uint &line,uint &column,const char *fontClass) { if (fontClass) ol.startFontClass(fontClass); const char *p=text,*sp=p; @@ -657,7 +569,7 @@ static void codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, if (fontClass) ol.endFontClass(); } -static void writeMultiLineCodeLink(CodeOutputInterface &ol, +void ClangTUParser::writeMultiLineCodeLink(CodeOutputInterface &ol, FileDef *fd,uint &line,uint &column, Definition *d, const char *text) @@ -698,7 +610,7 @@ static void writeMultiLineCodeLink(CodeOutputInterface &ol, } } -void ClangParser::linkInclude(CodeOutputInterface &ol,FileDef *fd, +void ClangTUParser::linkInclude(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text) { QCString incName = text; @@ -732,7 +644,7 @@ void ClangParser::linkInclude(CodeOutputInterface &ol,FileDef *fd, } } -void ClangParser::linkMacro(CodeOutputInterface &ol,FileDef *fd, +void ClangTUParser::linkMacro(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text) { MemberName *mn=Doxygen::functionNameLinkedMap->find(text); @@ -751,7 +663,7 @@ void ClangParser::linkMacro(CodeOutputInterface &ol,FileDef *fd, } -void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, +void ClangTUParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text,int tokenIndex) { CXCursor c = p->cursors[tokenIndex]; @@ -782,11 +694,11 @@ void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, //} if (d && d->isLinkable()) { - if (g_insideBody && - g_currentMemberDef && d->definitionType()==Definition::TypeMember && - (g_currentMemberDef!=d || g_currentLineinsideBody && + p->currentMemberDef && d->definitionType()==Definition::TypeMember && + (p->currentMemberDef!=d || p->currentLine(d)); + addDocCrossReference(p->currentMemberDef,dynamic_cast(d)); } writeMultiLineCodeLink(ol,fd,line,column,d,text); } @@ -797,45 +709,44 @@ void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, clang_disposeString(usr); } -static void detectFunctionBody(const char *s) +void ClangTUParser::detectFunctionBody(const char *s) { //printf("punct=%s g_searchForBody=%d g_insideBody=%d g_bracketCount=%d\n", // s,g_searchForBody,g_insideBody,g_bracketCount); - if (g_searchForBody && (qstrcmp(s,":")==0 || qstrcmp(s,"{")==0)) // start of 'body' (: is for constructor) + if (p->searchForBody && (qstrcmp(s,":")==0 || qstrcmp(s,"{")==0)) // start of 'body' (: is for constructor) { - g_searchForBody=FALSE; - g_insideBody=TRUE; + p->searchForBody=FALSE; + p->insideBody=TRUE; } - else if (g_searchForBody && qstrcmp(s,";")==0) // declaration only + else if (p->searchForBody && qstrcmp(s,";")==0) // declaration only { - g_searchForBody=FALSE; - g_insideBody=FALSE; + p->searchForBody=FALSE; + p->insideBody=FALSE; } - if (g_insideBody && qstrcmp(s,"{")==0) // increase scoping level + if (p->insideBody && qstrcmp(s,"{")==0) // increase scoping level { - g_bracketCount++; + p->bracketCount++; } - if (g_insideBody && qstrcmp(s,"}")==0) // decrease scoping level + if (p->insideBody && qstrcmp(s,"}")==0) // decrease scoping level { - g_bracketCount--; - if (g_bracketCount<=0) // got outside of function body + p->bracketCount--; + if (p->bracketCount<=0) // got outside of function body { - g_insideBody=FALSE; - g_bracketCount=0; + p->insideBody=FALSE; + p->bracketCount=0; } } } -void ClangParser::writeSources(CodeOutputInterface &ol,FileDef *fd) +void ClangTUParser::writeSources(CodeOutputInterface &ol,FileDef *fd) { // (re)set global parser state - g_currentDefinition=0; - g_currentMemberDef=0; - g_currentLine=0; - g_searchForBody=FALSE; - g_insideBody=FALSE; - g_bracketCount=0; + p->currentMemberDef=0; + p->currentLine=0; + p->searchForBody=FALSE; + p->insideBody=FALSE; + p->bracketCount=0; unsigned int line=1,column=1; QCString lineNumber,lineAnchor; @@ -939,16 +850,47 @@ void ClangParser::writeSources(CodeOutputInterface &ol,FileDef *fd) ol.endCodeLine(); } -ClangParser::ClangParser() +//-------------------------------------------------------------------------- + +class ClangParser::Private +{ + public: + Private() + { + std::string error; + QCString clangCompileDatabase = Config_getString(CLANG_DATABASE_PATH); + // load a clang compilation database (https://clang.llvm.org/docs/JSONCompilationDatabase.html) + db = clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.data(), error); + if (clangCompileDatabase!="0" && db==nullptr) + { + // user specified a path, but DB file was not found + err("%s using clang compilation database path of: \"%s\"\n", error.c_str(), + clangCompileDatabase.data()); + } + } + + std::unique_ptr db; +}; + +const clang::tooling::CompilationDatabase *ClangParser::database() const +{ + return p->db.get(); +} + +ClangParser::ClangParser() : p(std::make_unique()) { - p = new Private; } ClangParser::~ClangParser() { - delete p; } +std::unique_ptr ClangParser::createTUParser(const FileDef *fd) const +{ + return std::make_unique(*this,fd); +} + + //-------------------------------------------------------------------------- #else // use stubbed functionality in case libclang support is disabled. @@ -982,7 +924,6 @@ ClangParser::~ClangParser() { } - #endif //-------------------------------------------------------------------------- diff --git a/src/clangparser.h b/src/clangparser.h index 8bb9aba..07907a6 100644 --- a/src/clangparser.h +++ b/src/clangparser.h @@ -3,9 +3,73 @@ #include #include +#include "containers.h" +#include class CodeOutputInterface; class FileDef; +class ClangParser; +class Definition; + +namespace clang { namespace tooling { + class CompilationDatabase; +} } + +/** @brief Clang parser object for a single translation unit, which consists of a source file + * and the directly or indirectly included headers + */ +class ClangTUParser +{ + public: + ClangTUParser(const ClangParser &parser,const FileDef *fd); + virtual ~ClangTUParser(); + + /** Parse the file given at construction time as a translation unit + * This file should already be preprocessed by doxygen preprocessor at the time of calling. + */ + void parse(); + + /** Switches to another file within the translation unit started with start(). + * @param[in] fileName The name of the file to switch to. + */ + void switchToFile(FileDef *fd); + + /** Returns the list of files for this translation unit */ + StringVector filesInSameTU() const; + + /** Looks for \a symbol which should be found at \a line. + * returns a clang unique reference to the symbol. + */ + QCString lookup(uint line,const char *symbol); + + /** writes the syntax highlighted source code for a file + * @param[out] ol The output generator list to write to. + * @param[in] fd The file to write sources for. + */ + void writeSources(CodeOutputInterface &ol,FileDef *fd); + + private: + void detectFunctionBody(const char *s); + void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line); + void codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, + uint &line,uint &column,const char *fontClass=0); + void writeMultiLineCodeLink(CodeOutputInterface &ol, + FileDef *fd,uint &line,uint &column, + Definition *d, const char *text); + void linkIdentifier(CodeOutputInterface &ol,FileDef *fd, + uint &line,uint &column, + const char *text,int tokenIndex); + void linkMacro(CodeOutputInterface &ol,FileDef *fd, + uint &line,uint &column, + const char *text); + void linkInclude(CodeOutputInterface &ol,FileDef *fd, + uint &line,uint &column, + const char *text); + ClangTUParser(const ClangTUParser &) = delete; + ClangTUParser &operator=(const ClangTUParser &) = delete; + class Private; + std::unique_ptr p; +}; /** @brief Wrapper for to let libclang assisted parsing. */ class ClangParser @@ -13,16 +77,20 @@ class ClangParser public: /** Returns the one and only instance of the class */ static ClangParser *instance(); - + + std::unique_ptr createTUParser(const FileDef *fd) const; + const clang::tooling::CompilationDatabase *database() const; + +#if 0 /** Start parsing a file. * @param[in] fileName The name of the file to parse. * @param[in,out] filesInTranslationUnit Other files that are * part of the input and included by the file. * The function will return a subset of the files, - * only including the ones that were actually found + * only including the ones that were actually found * during parsing. */ - void start(const char *fileName,QStrList &filesInTranslationUnit); + void start(const char *fileName,StringVector &filesInTranslationUnit); /** Switches to another file within the translation unit started * with start(). @@ -45,8 +113,10 @@ class ClangParser * @param[in] fd The file to write sources for. */ void writeSources(CodeOutputInterface &ol,FileDef *fd); +#endif private: +#if 0 void linkIdentifier(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column, const char *text,int tokenIndex); @@ -56,9 +126,9 @@ class ClangParser void linkInclude(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column, const char *text); - void determineInputFilesInSameTu(QStrList &filesInTranslationUnit); +#endif class Private; - Private *p; + std::unique_ptr p; ClangParser(); virtual ~ClangParser(); static ClangParser *s_instance; diff --git a/src/doxygen.cpp b/src/doxygen.cpp index 5ac1980..8c739ad 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -104,6 +104,7 @@ #include "plantuml.h" #include "stlsupport.h" #include "threadpool.h" +#include "clangparser.h" // provided by the generated file resources.cpp extern void initResources(); @@ -7499,50 +7500,48 @@ static void generateFileSources() { if (fd->isSource() && !fd->isReference()) { - QStrList filesInSameTu; - fd->getAllIncludeFilesRecursively(filesInSameTu); - fd->startParsing(); + auto clangParser = ClangParser::instance()->createTUParser(fd.get()); if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output { msg("Generating code for file %s...\n",fd->docName().data()); - fd->writeSource(*g_outputList,FALSE,filesInSameTu); + clangParser->parse(); + fd->writeSource(*g_outputList,clangParser.get()); } else if (!fd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg("Parsing code for file %s...\n",fd->docName().data()); - fd->parseSource(FALSE,filesInSameTu); + clangParser->parse(); + fd->parseSource(clangParser.get()); } - char *incFile = filesInSameTu.first(); - while (incFile && filesToProcess.find(incFile)!=filesToProcess.end()) + for (auto incFile : clangParser->filesInSameTU()) { - if (fd->absFilePath()!=incFile && processedFiles.find(incFile)==processedFiles.end()) + if (filesToProcess.find(incFile)!=filesToProcess.end() && // part of input + fd->absFilePath()!=incFile && // not same file + processedFiles.find(incFile)==processedFiles.end()) // not yet marked as processed { - QStrList moreFiles; + StringVector moreFiles; bool ambig; - FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile,ambig); + FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig); if (ifd && !ifd->isReference()) { if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output { msg(" Generating code for file %s...\n",ifd->docName().data()); - ifd->writeSource(*g_outputList,TRUE,moreFiles); - + ifd->writeSource(*g_outputList,clangParser.get()); } else if (!ifd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg(" Parsing code for file %s...\n",ifd->docName().data()); - ifd->parseSource(TRUE,moreFiles); + ifd->parseSource(clangParser.get()); } processedFiles.insert(incFile); } } - incFile = filesInSameTu.next(); } - fd->finishParsing(); processedFiles.insert(fd->absFilePath().str()); } } @@ -7554,21 +7553,21 @@ static void generateFileSources() { if (processedFiles.find(fd->absFilePath().str())==processedFiles.end()) // not yet processed { - QStrList filesInSameTu; - fd->startParsing(); + auto clangParser = ClangParser::instance()->createTUParser(fd.get()); if (fd->generateSourceFile() && !Htags::useHtags && !g_useOutputTemplate) // sources need to be shown in the output { msg("Generating code for file %s...\n",fd->docName().data()); - fd->writeSource(*g_outputList,FALSE,filesInSameTu); + clangParser->parse(); + fd->writeSource(*g_outputList,clangParser.get()); } else if (!fd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg("Parsing code for file %s...\n",fd->docName().data()); - fd->parseSource(FALSE,filesInSameTu); + clangParser->parse(); + fd->parseSource(clangParser.get()); } - fd->finishParsing(); } } } @@ -7580,21 +7579,20 @@ static void generateFileSources() { for (const auto &fd : *fn) { - QStrList filesInSameTu; - fd->startParsing(); + StringVector filesInSameTu; + fd->getAllIncludeFilesRecursively(filesInSameTu); if (fd->generateSourceFile() && !Htags::useHtags && !g_useOutputTemplate) // sources need to be shown in the output { msg("Generating code for file %s...\n",fd->docName().data()); - fd->writeSource(*g_outputList,FALSE,filesInSameTu); + fd->writeSource(*g_outputList,nullptr); } else if (!fd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg("Parsing code for file %s...\n",fd->docName().data()); - fd->parseSource(FALSE,filesInSameTu); + fd->parseSource(nullptr); } - fd->finishParsing(); } } } @@ -9062,7 +9060,7 @@ static std::unique_ptr getParserForFile(const char *fn) static std::shared_ptr parseFile(OutlineParserInterface &parser, FileDef *fd,const char *fn, - bool sameTu,QStrList &filesInSameTu) + ClangTUParser *clangParser,bool newTU) { QCString fileName=fn; QCString extension; @@ -9110,18 +9108,20 @@ static std::shared_ptr parseFile(OutlineParserInterface &parser, convBuf.addChar('\0'); - if (Doxygen::clangAssistedParsing && !sameTu) - { - fd->getAllIncludeFilesRecursively(filesInSameTu); - } - std::shared_ptr fileRoot = std::make_shared(); // use language parse to parse the file - parser.parseInput(fileName,convBuf.data(),fileRoot,sameTu,filesInSameTu); + if (clangParser) + { + if (newTU) clangParser->parse(); + clangParser->switchToFile(fd); + } + parser.parseInput(fileName,convBuf.data(),fileRoot,clangParser); fileRoot->setFileDef(fd); return fileRoot; } +#if MULTITHREADED_INPUT + //! parse the list of input files static void parseFiles(const std::shared_ptr &root) { @@ -9137,7 +9137,12 @@ static void parseFiles(const std::shared_ptr &root) filesToProcess.insert(s); } + std::mutex processedFilesLock; // process source files (and their include dependencies) + std::size_t numThreads = std::thread::hardware_concurrency(); + msg("Processing input using %lu threads.\n",numThreads); + ThreadPool threadPool(numThreads); + std::vector< std::future< std::vector< std::shared_ptr > > > results; for (const auto &s : g_inputFiles) { bool ambig; @@ -9145,70 +9150,89 @@ static void parseFiles(const std::shared_ptr &root) ASSERT(fd!=0); if (fd->isSource() && !fd->isReference()) // this is a source file { - QStrList filesInSameTu; - std::unique_ptr parser { getParserForFile(s.c_str()) }; - parser->startTranslationUnit(s.c_str()); - std::shared_ptr fileRoot = parseFile(*parser.get(),fd,s.c_str(),FALSE,filesInSameTu); - root->moveToSubEntryAndKeep(fileRoot); - //printf(" got %d extra files in tu\n",filesInSameTu.count()); - - // Now process any include files in the same translation unit - // first. When libclang is used this is much more efficient. - char *incFile = filesInSameTu.first(); - while (incFile && filesToProcess.find(incFile)!=filesToProcess.end()) - { - if (qstrcmp(incFile,s.c_str()) && processedFiles.find(incFile)==processedFiles.end()) + // lambda representing the work to executed by a thread + auto processFile = [s,&filesToProcess,&processedFilesLock,&processedFiles]() { + bool ambig; + std::vector< std::shared_ptr > roots; + FileDef *fd = findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser = getParserForFile(s.c_str()); + auto fileRoot { parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true) }; + roots.push_back(fileRoot); + + // Now process any include files in the same translation unit + // first. When libclang is used this is much more efficient. + for (auto incFile : clangParser->filesInSameTU()) { - FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile,ambig); - if (ifd && !ifd->isReference()) + if (filesToProcess.find(incFile)!=filesToProcess.end()) { - QStrList moreFiles; - //printf(" Processing %s in same translation unit as %s\n",incFile,s->c_str()); - fileRoot = parseFile(*parser.get(),ifd,incFile,TRUE,moreFiles); - root->moveToSubEntryAndKeep(fileRoot); - processedFiles.insert(incFile); + bool needsToBeProcessed; + { + std::lock_guard lock(processedFilesLock); + needsToBeProcessed = processedFiles.find(incFile)==processedFiles.end(); + if (needsToBeProcessed) processedFiles.insert(incFile); + } + if (incFile!=s && needsToBeProcessed) + { + FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig); + if (ifd && !ifd->isReference()) + { + //printf(" Processing %s in same translation unit as %s\n",incFile,s->c_str()); + fileRoot = parseFile(*parser.get(),ifd,incFile.c_str(),clangParser.get(),false); + roots.push_back(fileRoot); + } + } } } - incFile = filesInSameTu.next(); - } - parser->finishTranslationUnit(); - processedFiles.insert(s); + return roots; + }; + // dispatch the work and collect the future results + results.emplace_back(threadPool.queue(processFile)); + } + } + // synchronise with the Entry result lists produced and add them to the root + for (auto &f : results) + { + auto l = f.get(); + for (auto &e : l) + { + root->moveToSubEntryAndKeep(e); } } // process remaining files + results.clear(); for (const auto &s : g_inputFiles) { if (processedFiles.find(s)==processedFiles.end()) // not yet processed { - bool ambig; - QStrList filesInSameTu; - FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); - ASSERT(fd!=0); - std::unique_ptr parser { getParserForFile(s.c_str()) }; - parser->startTranslationUnit(s.c_str()); - std::shared_ptr fileRoot = parseFile(*parser.get(),fd,s.c_str(),FALSE,filesInSameTu); - root->moveToSubEntryAndKeep(fileRoot); - parser->finishTranslationUnit(); - processedFiles.insert(s); + // lambda representing the work to executed by a thread + auto processFile = [s]() { + bool ambig; + std::vector< std::shared_ptr > roots; + FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser { getParserForFile(s.c_str()) }; + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); + roots.push_back(fileRoot); + return roots; + }; + // dispatch the work and collect the future results + results.emplace_back(threadPool.queue(processFile)); + } + } + // synchronise with the Entry result lists produced and add them to the root + for (auto &f : results) + { + auto l = f.get(); + for (auto &e : l) + { + root->moveToSubEntryAndKeep(e); } } } else // normal processing #endif { -#if !MULTITHREADED_INPUT - for (const auto &s : g_inputFiles) - { - bool ambig; - QStrList filesInSameTu; - FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); - ASSERT(fd!=0); - std::unique_ptr parser { getParserForFile(s.c_str()) }; - parser->startTranslationUnit(s.c_str()); - std::shared_ptr fileRoot = parseFile(*parser.get(),fd,s.c_str(),FALSE,filesInSameTu); - root->moveToSubEntryAndKeep(fileRoot); - } -#else std::size_t numThreads = std::thread::hardware_concurrency(); msg("Processing input using %lu threads.\n",numThreads); ThreadPool threadPool(numThreads); @@ -9218,12 +9242,10 @@ static void parseFiles(const std::shared_ptr &root) // lambda representing the work to executed by a thread auto processFile = [s]() { bool ambig; - QStrList filesInSameTu; FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); - ASSERT(fd!=0); - std::unique_ptr parser { getParserForFile(s.c_str()) }; - parser->startTranslationUnit(s.c_str()); - std::shared_ptr fileRoot = parseFile(*parser.get(),fd,s.c_str(),FALSE,filesInSameTu); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser = getParserForFile(s.c_str()); + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); return fileRoot; }; // dispatch the work and collect the future results @@ -9235,10 +9257,92 @@ static void parseFiles(const std::shared_ptr &root) root->moveToSubEntryAndKeep(f.get()); } #warning "Multi-threaded input enabled. This is a highly experimental feature. Only use for doxygen development." + } +} + +#else // !MULTITHREADED_INPUT + +//! parse the list of input files +static void parseFiles(const std::shared_ptr &root) +{ +#if USE_LIBCLANG + if (Doxygen::clangAssistedParsing) + { + StringUnorderedSet processedFiles; + + // create a dictionary with files to process + StringUnorderedSet filesToProcess; + for (const auto &s : g_inputFiles) + { + filesToProcess.insert(s); + } + + // process source files (and their include dependencies) + for (const auto &s : g_inputFiles) + { + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + ASSERT(fd!=0); + if (fd->isSource() && !fd->isReference()) // this is a source file + { + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser { getParserForFile(s.c_str()) }; + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); + root->moveToSubEntryAndKeep(fileRoot); + processedFiles.insert(s); + + // Now process any include files in the same translation unit + // first. When libclang is used this is much more efficient. + for (auto incFile : clangParser->filesInSameTU()) + { + //printf(" file %s\n",incFile.c_str()); + if (filesToProcess.find(incFile)!=filesToProcess.end() && // file need to be processed + processedFiles.find(incFile)==processedFiles.end()) // and is not processed already + { + FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig); + if (ifd && !ifd->isReference()) + { + //printf(" Processing %s in same translation unit as %s\n",incFile.c_str(),s.c_str()); + fileRoot = parseFile(*parser.get(),ifd,incFile.c_str(),clangParser.get(),false); + root->moveToSubEntryAndKeep(fileRoot); + processedFiles.insert(incFile); + } + } + } + } + } + // process remaining files + for (const auto &s : g_inputFiles) + { + if (processedFiles.find(s)==processedFiles.end()) // not yet processed + { + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser { getParserForFile(s.c_str()) }; + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); + root->moveToSubEntryAndKeep(fileRoot); + processedFiles.insert(s); + } + } + } + else // normal processing #endif + { + for (const auto &s : g_inputFiles) + { + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + ASSERT(fd!=0); + std::unique_ptr parser { getParserForFile(s.c_str()) }; + std::shared_ptr fileRoot = parseFile(*parser.get(),fd,s.c_str(),nullptr,true); + root->moveToSubEntryAndKeep(fileRoot); + } } } +#endif + // resolves a path that may include symlinks, if a recursive symlink is // found an empty string is returned. static QCString resolveSymlink(QCString path) @@ -9707,9 +9811,7 @@ static const char *getArg(int argc,char **argv,int &optind) class NullOutlineParser : public OutlineParserInterface { public: - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} - void parseInput(const char *, const char *,const std::shared_ptr &, bool, QStrList &) {} + void parseInput(const char *, const char *,const std::shared_ptr &, ClangTUParser*) {} bool needsPreprocessing(const QCString &) const { return FALSE; } void parsePrototype(const char *) {} }; diff --git a/src/filedef.cpp b/src/filedef.cpp index 08f022b..658023b 100644 --- a/src/filedef.cpp +++ b/src/filedef.cpp @@ -82,7 +82,7 @@ class FileDefImpl : public DefinitionImpl, public FileDef virtual SDict *getUsedClasses() const { return m_usingDeclList; } virtual QList *includeFileList() const { return m_includeList; } virtual QList *includedByFileList() const { return m_includedByList; } - virtual void getAllIncludeFilesRecursively(QStrList &incFiles) const; + virtual void getAllIncludeFilesRecursively(StringVector &incFiles) const; virtual MemberList *getMemberList(MemberListType lt) const; virtual const QList &getMemberLists() const { return m_memberLists; } virtual MemberGroupSDict *getMemberGroupSDict() const { return m_memberGroupSDict; } @@ -101,10 +101,8 @@ class FileDefImpl : public DefinitionImpl, public FileDef virtual void writeQuickMemberLinks(OutputList &ol,const MemberDef *currentMd) const; virtual void writeSummaryLinks(OutputList &ol) const; virtual void writeTagFile(FTextStream &t); - virtual void startParsing(); - virtual void writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu); - virtual void parseSource(bool sameTu,QStrList &filesInSameTu); - virtual void finishParsing(); + virtual void writeSource(OutputList &ol,ClangTUParser *clangParser); + virtual void parseSource(ClangTUParser *clangParser); virtual void setDiskName(const QCString &name); virtual void insertMember(MemberDef *md); virtual void insertClass(ClassDef *cd); @@ -1151,7 +1149,7 @@ void FileDefImpl::writeQuickMemberLinks(OutputList &ol,const MemberDef *currentM } /*! Write a source listing of this file to the output */ -void FileDefImpl::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu) +void FileDefImpl::writeSource(OutputList &ol,ClangTUParser *clangParser) { static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); @@ -1209,22 +1207,13 @@ void FileDefImpl::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu ol.popGeneratorState(); } - (void)sameTu; - (void)filesInSameTu; #if USE_LIBCLANG - if (Doxygen::clangAssistedParsing && + if (Doxygen::clangAssistedParsing && clangParser && (getLanguage()==SrcLangExt_Cpp || getLanguage()==SrcLangExt_ObjC)) { ol.startCodeFragment(); - if (!sameTu) - { - ClangParser::instance()->start(absFilePath(),filesInSameTu); - } - else - { - ClangParser::instance()->switchToFile(absFilePath()); - } - ClangParser::instance()->writeSources(ol,this); + clangParser->switchToFile(this); + clangParser->writeSources(ol,this); ol.endCodeFragment(); } else @@ -1268,25 +1257,16 @@ void FileDefImpl::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu ol.enableAll(); } -void FileDefImpl::parseSource(bool sameTu,QStrList &filesInSameTu) +void FileDefImpl::parseSource(ClangTUParser *clangParser) { static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); DevNullCodeDocInterface devNullIntf; - (void)sameTu; - (void)filesInSameTu; #if USE_LIBCLANG - if (Doxygen::clangAssistedParsing && + if (Doxygen::clangAssistedParsing && clangParser && (getLanguage()==SrcLangExt_Cpp || getLanguage()==SrcLangExt_ObjC)) { - if (!sameTu) - { - ClangParser::instance()->start(absFilePath(),filesInSameTu); - } - else - { - ClangParser::instance()->switchToFile(absFilePath()); - } - ClangParser::instance()->writeSources(devNullIntf,this); + clangParser->switchToFile(this); + clangParser->writeSources(devNullIntf,this); } else #endif @@ -1302,15 +1282,6 @@ void FileDefImpl::parseSource(bool sameTu,QStrList &filesInSameTu) } } -void FileDefImpl::startParsing() -{ -} - -void FileDefImpl::finishParsing() -{ - ClangParser::instance()->finish(); -} - void FileDefImpl::addMembersToMemberGroup() { QListIterator mli(m_memberLists); @@ -2159,7 +2130,7 @@ bool FileDefImpl::isLinkableInProject() const } static void getAllIncludeFilesRecursively( - QDict *filesVisited,const FileDef *fd,QStrList &incFiles) + StringUnorderedSet &filesVisited,const FileDef *fd,StringVector &incFiles) { if (fd->includeFileList()) { @@ -2168,21 +2139,21 @@ static void getAllIncludeFilesRecursively( for (iii.toFirst();(ii=iii.current());++iii) { if (ii->fileDef && !ii->fileDef->isReference() && - !filesVisited->find(ii->fileDef->absFilePath())) + filesVisited.find(ii->fileDef->absFilePath().str())==filesVisited.end()) { //printf("FileDefImpl::addIncludeDependency(%s)\n",ii->fileDef->absFilePath().data()); - incFiles.append(ii->fileDef->absFilePath()); - filesVisited->insert(ii->fileDef->absFilePath(),(void*)0x8); + incFiles.push_back(ii->fileDef->absFilePath().str()); + filesVisited.insert(ii->fileDef->absFilePath().str()); getAllIncludeFilesRecursively(filesVisited,ii->fileDef,incFiles); } } } } -void FileDefImpl::getAllIncludeFilesRecursively(QStrList &incFiles) const +void FileDefImpl::getAllIncludeFilesRecursively(StringVector &incFiles) const { - QDict includes(257); - ::getAllIncludeFilesRecursively(&includes,this,incFiles); + StringUnorderedSet includes; + ::getAllIncludeFilesRecursively(includes,this,incFiles); } QCString FileDefImpl::title() const diff --git a/src/filedef.h b/src/filedef.h index c03e7ef..e4bb549 100644 --- a/src/filedef.h +++ b/src/filedef.h @@ -25,6 +25,7 @@ #include "definition.h" #include "sortdict.h" #include "memberlist.h" +#include "containers.h" class MemberList; class FileDef; @@ -40,6 +41,7 @@ class MemberGroupSDict; class PackageDef; class DirDef; class FTextStream; +class ClangTUParser; /** Class representing the data associated with a \#include statement. */ struct IncludeInfo @@ -118,7 +120,7 @@ class FileDef : virtual public Definition virtual SDict *getUsedClasses() const = 0; virtual QList *includeFileList() const = 0; virtual QList *includedByFileList() const = 0; - virtual void getAllIncludeFilesRecursively(QStrList &incFiles) const = 0; + virtual void getAllIncludeFilesRecursively(StringVector &incFiles) const = 0; virtual MemberList *getMemberList(MemberListType lt) const = 0; virtual const QList &getMemberLists() const = 0; @@ -148,10 +150,8 @@ class FileDef : virtual public Definition virtual void writeSummaryLinks(OutputList &ol) const = 0; virtual void writeTagFile(FTextStream &t) = 0; - virtual void startParsing() = 0; - virtual void writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu) = 0; - virtual void parseSource(bool sameTu,QStrList &filesInSameTu) = 0; - virtual void finishParsing() = 0; + virtual void writeSource(OutputList &ol,ClangTUParser *clangParser) = 0; + virtual void parseSource(ClangTUParser *clangParser) = 0; virtual void setDiskName(const QCString &name) = 0; virtual void insertMember(MemberDef *md) = 0; diff --git a/src/fortranscanner.h b/src/fortranscanner.h index 6ffcb1f..0e67bb2 100644 --- a/src/fortranscanner.h +++ b/src/fortranscanner.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * 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 + * 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. * @@ -29,13 +29,10 @@ class FortranOutlineParser : public OutlineParserInterface public: FortranOutlineParser(FortranFormat format=FortranFormat_Unknown); ~FortranOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} void parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &extension) const; void parsePrototype(const char *text); diff --git a/src/fortranscanner.l b/src/fortranscanner.l index 195293f..9714602 100644 --- a/src/fortranscanner.l +++ b/src/fortranscanner.l @@ -2803,8 +2803,7 @@ FortranOutlineParser::~FortranOutlineParser() void FortranOutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool /*sameTranslationUnit*/, - QStrList & /*filesInSameTranslationUnit*/) + ClangTUParser * /*clangParser*/) { struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; yyextra->thisParser = this; diff --git a/src/markdown.cpp b/src/markdown.cpp index 583ad17..1a96d45 100644 --- a/src/markdown.cpp +++ b/src/markdown.cpp @@ -2528,8 +2528,7 @@ MarkdownOutlineParser::~MarkdownOutlineParser() void MarkdownOutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool /*sameTranslationUnit*/, - QStrList & /*filesInSameTranslationUnit*/) + ClangTUParser* /*clangParser*/) { std::shared_ptr current = std::make_shared(); current->lang = SrcLangExt_Markdown; diff --git a/src/markdown.h b/src/markdown.h index 6ac59cb..43a17cc 100644 --- a/src/markdown.h +++ b/src/markdown.h @@ -93,13 +93,10 @@ class MarkdownOutlineParser : public OutlineParserInterface public: MarkdownOutlineParser(); virtual ~MarkdownOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} void parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &) const { return FALSE; } void parsePrototype(const char *text); private: diff --git a/src/parserintf.h b/src/parserintf.h index f11352e..911b707 100644 --- a/src/parserintf.h +++ b/src/parserintf.h @@ -26,12 +26,14 @@ #include #include "types.h" +#include "containers.h" class Entry; class FileDef; class CodeOutputInterface; class MemberDef; class Definition; +class ClangTUParser; /** \brief Abstract interface for outline parsers. * @@ -44,36 +46,18 @@ class OutlineParserInterface public: virtual ~OutlineParserInterface() {} - /** Starts processing a translation unit (source files + headers). - * After this call parseInput() is called with sameTranslationUnit - * set to FALSE. If parseInput() returns additional include files, - * these are also processed using parseInput() with - * sameTranslationUnit set to TRUE. After that - * finishTranslationUnit() is called. - */ - virtual void startTranslationUnit(const char *fileName) = 0; - - /** Called after all files in a translation unit have been - * processed. - */ - virtual void finishTranslationUnit() = 0; - /** Parses a single input file with the goal to build an Entry tree. * @param[in] fileName The full name of the file. * @param[in] fileBuf The contents of the file (zero terminated). * @param[in,out] root The root of the tree of Entry *nodes * representing the information extracted from the file. - * @param[in] sameTranslationUnit TRUE if this file was found in the same - * translation unit (in the filesInSameTranslationUnit list - * returned for another file). - * @param[in,out] filesInSameTranslationUnit other files expected to be - * found in the same translation unit (used for libclang) + * @param[in] clangParser The clang translation unit parser object + * or nullptr if disabled. */ virtual void parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit) = 0; + ClangTUParser *clangParser) = 0; /** Returns TRUE if the language identified by \a extension needs * the C preprocessor to be run before feed the result to the input diff --git a/src/pyscanner.h b/src/pyscanner.h index d6e8672..4f0ae38 100644 --- a/src/pyscanner.h +++ b/src/pyscanner.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * 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 + * 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. * @@ -36,13 +36,10 @@ class PythonOutlineParser : public OutlineParserInterface public: PythonOutlineParser(); virtual ~PythonOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} - void parseInput(const char * fileName, - const char *fileBuf, + void parseInput(const char * fileName, + const char *fileBuf, const std::shared_ptr &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &extension) const; void parsePrototype(const char *text); private: diff --git a/src/pyscanner.l b/src/pyscanner.l index a3dbaba..07b39d6 100644 --- a/src/pyscanner.l +++ b/src/pyscanner.l @@ -1517,7 +1517,7 @@ static void newFunction(yyscan_t yyscanner) static inline int computeIndent(const char *s) { int col=0; - static int tabSize=Config_getInt(TAB_SIZE); + int tabSize=Config_getInt(TAB_SIZE); const char *p=s; char c; while ((c=*p++)) @@ -1936,8 +1936,7 @@ PythonOutlineParser::~PythonOutlineParser() void PythonOutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool /*sameTranslationUnit*/, - QStrList & /*filesInSameTranslationUnit*/) + ClangTUParser * /*clangParser*/) { struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; yyextra->thisParser = this; diff --git a/src/scanner.h b/src/scanner.h index 70df660..cefc934 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * 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 + * 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. * @@ -23,7 +23,7 @@ /** \brief C-like language parser using state-based lexical scanning. * * This is the language parser for doxygen. It is somewhat fuzzy and - * supports C++ and various languages that are closely related to C++, + * supports C++ and various languages that are closely related to C++, * such as C, C#, Objective-C, Java, PHP, and IDL. */ class COutlineParser : public OutlineParserInterface @@ -31,13 +31,10 @@ class COutlineParser : public OutlineParserInterface public: COutlineParser(); virtual ~COutlineParser(); - void startTranslationUnit(const char *fileName); - void finishTranslationUnit(); void parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &extension) const; void parsePrototype(const char *text); private: diff --git a/src/scanner.l b/src/scanner.l index d26a9b2..d9ad41c 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -193,6 +193,8 @@ struct scannerYY_state uint fencedSize = 0; bool nestedComment = false; std::vector< std::pair > > outerScopeEntries; + + ClangTUParser * clangParser = 0; }; #if USE_STATE2STRING @@ -766,9 +768,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) yyextra->current->type = "id"; } yyextra->current->name = yytext; - if (yyextra->insideCpp || yyextra->insideObjC) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } } ":"{B}* { // start of parameter list @@ -2045,9 +2047,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) BEGIN(FindMembers); } {SCOPENAME} { - if (Doxygen::clangAssistedParsing && (yyextra->insideCpp || yyextra->insideObjC)) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } yyextra->yyBegColNr=yyextra->yyColNr; yyextra->yyBegLineNr=yyextra->yyLineNr; @@ -2348,9 +2350,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) */ {ID} { //printf("Define '%s' without args\n",yytext); - if (Doxygen::clangAssistedParsing && (yyextra->insideCpp || yyextra->insideObjC)) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } yyextra->current->bodyLine = yyextra->yyLineNr; yyextra->current->bodyColumn = yyextra->yyColNr; @@ -3463,9 +3465,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) } . { yyextra->current->type += *yytext ; } {ID} { - if (Doxygen::clangAssistedParsing && (yyextra->insideCpp || yyextra->insideObjC)) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } yyextra->current->bodyLine = yyextra->yyLineNr; yyextra->current->bodyColumn = yyextra->yyColNr; @@ -5334,9 +5336,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) } {SCOPENAME} { yyextra->current->name = yytext ; - if (Doxygen::clangAssistedParsing && (yyextra->insideCpp || yyextra->insideObjC)) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } lineCount(yyscanner); if (yyextra->current->spec & Entry::Protocol) @@ -5399,9 +5401,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) } } {ID} { - if (Doxygen::clangAssistedParsing && (yyextra->insideCpp || yyextra->insideObjC)) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } if (yyextra->insideIDL && qstrcmp(yytext,"switch")==0) { @@ -7232,8 +7234,7 @@ static void parseMain(yyscan_t yyscanner, const char *fileName, const char *fileBuf, const std::shared_ptr &rt, - bool sameTranslationUnit, - QStrList & filesInSameTranslationUnit) + ClangTUParser *clangParser) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; initParser(yyscanner); @@ -7254,18 +7255,8 @@ static void parseMain(yyscan_t yyscanner, yyextra->yyBegLineNr = 1; yyextra->yyBegColNr = 0; yyextra->yyFileName = fileName; + yyextra->clangParser = clangParser; setContext(yyscanner); - if (Doxygen::clangAssistedParsing && (yyextra->insideCpp || yyextra->insideObjC)) - { - if (!sameTranslationUnit) // new file - { - ClangParser::instance()->start(fileName,filesInSameTranslationUnit); - } - else - { - ClangParser::instance()->switchToFile(fileName); - } - } rt->lang = yyextra->language; msg("Parsing file %s...\n",yyextra->yyFileName.data()); @@ -7402,33 +7393,17 @@ COutlineParser::~COutlineParser() scannerYYlex_destroy(p->yyscanner); } -void COutlineParser::startTranslationUnit(const char *) -{ -} - -void COutlineParser::finishTranslationUnit() -{ - struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; - bool processWithClang = yyextra->insideCpp || yyextra->insideObjC; - if (processWithClang) - { - ClangParser::instance()->finish(); - } -} - void COutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr &root, - bool sameTranslationUnit, - QStrList & filesInSameTranslationUnit) + ClangTUParser *clangParser) { struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; yyextra->thisParser = this; printlex(yy_flex_debug, TRUE, __FILE__, fileName); - ::parseMain(p->yyscanner, fileName,fileBuf,root, - sameTranslationUnit,filesInSameTranslationUnit); + ::parseMain(p->yyscanner,fileName,fileBuf,root,clangParser); printlex(yy_flex_debug, FALSE, __FILE__, fileName); } diff --git a/src/vhdldocgen.cpp b/src/vhdldocgen.cpp index 28a2028..5cc57ec 100644 --- a/src/vhdldocgen.cpp +++ b/src/vhdldocgen.cpp @@ -2942,10 +2942,8 @@ void VhdlDocGen::createFlowChart(const MemberDef *mdef) auto parser { Doxygen::parserManager->getOutlineParser(".vhd") }; VhdlDocGen::setFlowMember(mdef); std::shared_ptr root = std::make_shared(); - QStrList filesInSameTu; - parser->startTranslationUnit(""); - parser->parseInput("",codeFragment.data(),root,FALSE,filesInSameTu); - parser->finishTranslationUnit(); + StringVector filesInSameTu; + parser->parseInput("",codeFragment.data(),root,nullptr); } void VhdlDocGen::resetCodeVhdlParserState() diff --git a/src/vhdljjparser.cpp b/src/vhdljjparser.cpp index aa566ae..9ad9e23 100644 --- a/src/vhdljjparser.cpp +++ b/src/vhdljjparser.cpp @@ -126,7 +126,7 @@ VHDLOutlineParser::~VHDLOutlineParser() } void VHDLOutlineParser::parseInput(const char *fileName,const char *fileBuf, - const std::shared_ptr &root, bool ,QStrList&) + const std::shared_ptr &root, ClangTUParser *) { VhdlParser::SharedState *s = &p->shared; p->thisParser=this; diff --git a/src/vhdljjparser.h b/src/vhdljjparser.h index 940631d..651221c 100755 --- a/src/vhdljjparser.h +++ b/src/vhdljjparser.h @@ -32,20 +32,17 @@ class VHDLOutlineParser : public OutlineParserInterface public: VHDLOutlineParser(); virtual ~VHDLOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} void parseInput(const char * fileName, const char *fileBuf, const std::shared_ptr &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &) const { return TRUE; } void parsePrototype(const char *text); // interface for generated parser code - + void setLineParsed(int tok); int getLine(int tok); int getLine(); -- cgit v0.12