summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDimitri van Heesch <doxygen@gmail.com>2020-07-15 19:23:12 (GMT)
committerDimitri van Heesch <doxygen@gmail.com>2020-07-16 06:27:29 (GMT)
commit50fdb591d4abfdf88bfdda96ffd832cc4c024963 (patch)
tree85ad9b591eb36ad73cc07f4fb91ddcfb6d5762cf /src
parent93dc8f81eaaf5523715a4d5867cbb55f46c3f647 (diff)
downloadDoxygen-50fdb591d4abfdf88bfdda96ffd832cc4c024963.zip
Doxygen-50fdb591d4abfdf88bfdda96ffd832cc4c024963.tar.gz
Doxygen-50fdb591d4abfdf88bfdda96ffd832cc4c024963.tar.bz2
Refactor: Modernize clang parser and make it run with multiple threads
Diffstat (limited to 'src')
-rw-r--r--src/clangparser.cpp535
-rw-r--r--src/clangparser.h80
-rw-r--r--src/doxygen.cpp276
-rw-r--r--src/filedef.cpp65
-rw-r--r--src/filedef.h10
-rw-r--r--src/fortranscanner.h11
-rw-r--r--src/fortranscanner.l3
-rw-r--r--src/markdown.cpp3
-rw-r--r--src/markdown.h5
-rw-r--r--src/parserintf.h26
-rw-r--r--src/pyscanner.h15
-rw-r--r--src/pyscanner.l5
-rw-r--r--src/scanner.h13
-rw-r--r--src/scanner.l61
-rw-r--r--src/vhdldocgen.cpp6
-rw-r--r--src/vhdljjparser.cpp2
-rwxr-xr-xsrc/vhdljjparser.h7
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 <mutex>
+#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<std::mutex> 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<uint> 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<void> *fileDict = (QDict<void> *)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<QCString> sources;
+ std::vector<CXUnsavedFile> ufs;
+ std::vector<CXCursor> cursors;
+ std::unordered_map<std::string,uint> 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<Private>(parser,fd))
{
- // put the files in this translation unit in a dictionary
- QDict<void> 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<clang::tooling::CompilationDatabase> db =
- clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.data(), error);
- int clang_option_len = 0;
+ size_t clang_option_len = 0;
std::vector<clang::tooling::CompileCommand> 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<std::string> 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<std::string> 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;i<clangOptions.size();i++)
+ {
+ argv[argc++]=qstrdup(clangOptions[i].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.
}
else
{
@@ -218,7 +212,7 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit)
for (const std::string &path : Doxygen::inputPaths)
{
QCString inc = QCString("-I")+path.data();
- argv[argc]=qstrdup(inc.data());
+ argv[argc++]=qstrdup(inc.data());
//printf("argv[%d]=%s\n",argc,argv[argc]);
}
// add external include paths
@@ -241,67 +235,63 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit)
// we use the source file to detected the language. Detection will fail if you
// pass a bunch of .h files containing ObjC code, and no sources :-(
SrcLangExt lang = getLanguageFromFileName(fileName);
- if (lang==SrcLangExt_ObjC || p->detectedLang!=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<int>(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() && i<numUnsavedFiles;++it,i++)
+ for (auto it = p->filesInSameTU.begin();
+ it != p->filesInSameTU.end() && i<numUnsavedFiles;
+ ++it, i++)
{
- p->fileMapping.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<uint>(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;i<argc;++i)
{
@@ -311,9 +301,6 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit)
if (p->tu)
{
- // 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 && *pIndex<p->numFiles)
- {
- 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;i<p->numFiles;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->curToken<p->numTokens)
{
- 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<void> flowKeywords(47);
- static QDict<void> 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_currentLine<line)) // avoid self-reference
+ if (p->insideBody &&
+ p->currentMemberDef && d->definitionType()==Definition::TypeMember &&
+ (p->currentMemberDef!=d || p->currentLine<line)) // avoid self-reference
{
- addDocCrossReference(g_currentMemberDef,dynamic_cast<MemberDef *>(d));
+ addDocCrossReference(p->currentMemberDef,dynamic_cast<MemberDef *>(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<clang::tooling::CompilationDatabase> db;
+};
+
+const clang::tooling::CompilationDatabase *ClangParser::database() const
+{
+ return p->db.get();
+}
+
+ClangParser::ClangParser() : p(std::make_unique<Private>())
{
- p = new Private;
}
ClangParser::~ClangParser()
{
- delete p;
}
+std::unique_ptr<ClangTUParser> ClangParser::createTUParser(const FileDef *fd) const
+{
+ return std::make_unique<ClangTUParser>(*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 <qcstring.h>
#include <qstrlist.h>
+#include "containers.h"
+#include <memory>
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<Private> 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<ClangTUParser> 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<Private> 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<OutlineParserInterface> getParserForFile(const char *fn)
static std::shared_ptr<Entry> 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<Entry> parseFile(OutlineParserInterface &parser,
convBuf.addChar('\0');
- if (Doxygen::clangAssistedParsing && !sameTu)
- {
- fd->getAllIncludeFilesRecursively(filesInSameTu);
- }
-
std::shared_ptr<Entry> fileRoot = std::make_shared<Entry>();
// 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<Entry> &root)
{
@@ -9137,7 +9137,12 @@ static void parseFiles(const std::shared_ptr<Entry> &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<Entry> > > > results;
for (const auto &s : g_inputFiles)
{
bool ambig;
@@ -9145,70 +9150,89 @@ static void parseFiles(const std::shared_ptr<Entry> &root)
ASSERT(fd!=0);
if (fd->isSource() && !fd->isReference()) // this is a source file
{
- QStrList filesInSameTu;
- std::unique_ptr<OutlineParserInterface> parser { getParserForFile(s.c_str()) };
- parser->startTranslationUnit(s.c_str());
- std::shared_ptr<Entry> 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<Entry> > 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<std::mutex> 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<OutlineParserInterface> parser { getParserForFile(s.c_str()) };
- parser->startTranslationUnit(s.c_str());
- std::shared_ptr<Entry> 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<Entry> > 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<OutlineParserInterface> parser { getParserForFile(s.c_str()) };
- parser->startTranslationUnit(s.c_str());
- std::shared_ptr<Entry> 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<Entry> &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<OutlineParserInterface> parser { getParserForFile(s.c_str()) };
- parser->startTranslationUnit(s.c_str());
- std::shared_ptr<Entry> 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<Entry> &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<Entry> &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<OutlineParserInterface> parser { getParserForFile(s.c_str()) };
+ std::shared_ptr<Entry> 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<Entry> &, bool, QStrList &) {}
+ void parseInput(const char *, const char *,const std::shared_ptr<Entry> &, 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<Definition> *getUsedClasses() const { return m_usingDeclList; }
virtual QList<IncludeInfo> *includeFileList() const { return m_includeList; }
virtual QList<IncludeInfo> *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<MemberList> &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<MemberList> mli(m_memberLists);
@@ -2159,7 +2130,7 @@ bool FileDefImpl::isLinkableInProject() const
}
static void getAllIncludeFilesRecursively(
- QDict<void> *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<void> 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<Definition> *getUsedClasses() const = 0;
virtual QList<IncludeInfo> *includeFileList() const = 0;
virtual QList<IncludeInfo> *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<MemberList> &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<Entry> &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<Entry> &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<Entry> &root,
- bool /*sameTranslationUnit*/,
- QStrList & /*filesInSameTranslationUnit*/)
+ ClangTUParser* /*clangParser*/)
{
std::shared_ptr<Entry> current = std::make_shared<Entry>();
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<Entry> &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 <string>
#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<Entry> &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<Entry> &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<Entry> &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<Entry> &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<Entry*,std::shared_ptr<Entry> > > 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);
}
}
<ObjCMethod>":"{B}* { // start of parameter list
@@ -2045,9 +2047,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
BEGIN(FindMembers);
}
<FindMembers,FindMemberName>{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})
*/
<Define>{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})
}
<Sharp>. { yyextra->current->type += *yytext ; }
<FindFields>{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})
}
<CompoundName>{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})
}
}
<ClassVar>{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<Entry> &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<Entry> &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<Entry> root = std::make_shared<Entry>();
- 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<Entry> &root, bool ,QStrList&)
+ const std::shared_ptr<Entry> &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<Entry> &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();