work save: cpp parser done

This commit is contained in:
royqh1979@gmail.com 2021-08-22 23:48:00 +08:00
parent 9da351dfda
commit 41b9c53146
6 changed files with 205 additions and 92 deletions

View File

@ -16,9 +16,7 @@ CppParser::CppParser(QObject *parent) : QObject(parent)
mUniqId = 0; mUniqId = 0;
mParsing = false; mParsing = false;
//mStatementList ; // owns the objects //mStatementList ; // owns the objects
mIncludesList = std::make_shared<QHash<QString,PFileIncludes>>();
//mFilesToScan; //mFilesToScan;
mScannedFiles = std::make_shared<QSet<QString>>();
//mIncludePaths; //mIncludePaths;
//mProjectIncludePaths; //mProjectIncludePaths;
//mProjectFiles; //mProjectFiles;
@ -115,7 +113,7 @@ PStatement CppParser::findAndScanBlockAt(const QString &filename, int line)
QMutexLocker locker(&mMutex); QMutexLocker locker(&mMutex);
if (mParsing) if (mParsing)
return PStatement(); return PStatement();
PFileIncludes fileIncludes = mIncludesList->value(filename); PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename);
if (!fileIncludes) if (!fileIncludes)
return PStatement(); return PStatement();
@ -127,9 +125,9 @@ PStatement CppParser::findAndScanBlockAt(const QString &filename, int line)
PFileIncludes CppParser::findFileIncludes(const QString &filename, bool deleteIt) PFileIncludes CppParser::findFileIncludes(const QString &filename, bool deleteIt)
{ {
QMutexLocker locker(&mMutex); QMutexLocker locker(&mMutex);
PFileIncludes fileIncludes = mIncludesList->value(filename,PFileIncludes()); PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename,PFileIncludes());
if (deleteIt && fileIncludes) if (deleteIt && fileIncludes)
mIncludesList->remove(filename); mPreprocessor.includesList().remove(filename);
return fileIncludes; return fileIncludes;
} }
@ -163,7 +161,7 @@ QString CppParser::findFirstTemplateParamOf(const QString &fileName, const QStri
PStatement CppParser::findFunctionAt(const QString &fileName, int line) PStatement CppParser::findFunctionAt(const QString &fileName, int line)
{ {
QMutexLocker locker(&mMutex); QMutexLocker locker(&mMutex);
PFileIncludes fileIncludes = mIncludesList->value(fileName); PFileIncludes fileIncludes = mPreprocessor.includesList().value(fileName);
if (!fileIncludes) if (!fileIncludes)
return PStatement(); return PStatement();
for (PStatement statement : fileIncludes->statements) { for (PStatement statement : fileIncludes->statements) {
@ -489,7 +487,7 @@ QSet<QString> CppParser::getFileDirectIncludes(const QString &filename)
return list; return list;
if (filename.isEmpty()) if (filename.isEmpty())
return list; return list;
PFileIncludes fileIncludes = mIncludesList->value(filename,PFileIncludes()); PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename,PFileIncludes());
if (fileIncludes) { if (fileIncludes) {
QMap<QString, bool>::const_iterator iter = fileIncludes->includeFiles.cbegin(); QMap<QString, bool>::const_iterator iter = fileIncludes->includeFiles.cbegin();
@ -511,7 +509,7 @@ QSet<QString> CppParser::getFileIncludes(const QString &filename)
if (filename.isEmpty()) if (filename.isEmpty())
return list; return list;
list.insert(filename); list.insert(filename);
PFileIncludes fileIncludes = mIncludesList->value(filename,PFileIncludes()); PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename,PFileIncludes());
if (fileIncludes) { if (fileIncludes) {
for (QString file: fileIncludes->includeFiles.keys()) { for (QString file: fileIncludes->includeFiles.keys()) {
@ -528,7 +526,7 @@ QSet<QString> CppParser::getFileUsings(const QString &filename)
return QSet<QString>(); return QSet<QString>();
if (mParsing) if (mParsing)
return QSet<QString>(); return QSet<QString>();
PFileIncludes fileIncludes= mIncludesList->value(filename,PFileIncludes()); PFileIncludes fileIncludes= mPreprocessor.includesList().value(filename,PFileIncludes());
if (fileIncludes) { if (fileIncludes) {
return fileIncludes->usings; return fileIncludes->usings;
} }
@ -572,6 +570,17 @@ void CppParser::invalidateFile(const QString &fileName)
mParsing = false; mParsing = false;
} }
bool CppParser::isIncludeLine(const QString &line)
{
QString trimmedLine = line.trimmed();
if ((trimmedLine.length() > 0)
&& trimmedLine.startsWith('#')) { // it's a preprocessor line
if (trimmedLine.mid(1).trimmed().startsWith("include"))
return true;
}
return false;
}
bool CppParser::isProjectHeaderFile(const QString &fileName) bool CppParser::isProjectHeaderFile(const QString &fileName)
{ {
QMutexLocker locker(&mMutex); QMutexLocker locker(&mMutex);
@ -651,58 +660,154 @@ void CppParser::parseFileList(bool updateView)
{ {
if (!mEnabled) if (!mEnabled)
return; return;
if not fEnabled then {
Exit; QMutexLocker locker(&mMutex);
fCriticalSection.Acquire; if (mParsing || mLockCount>0)
try return;
if fParsing or (fLockCount>0) then updateSerialId();
Exit; mParsing = true;
UpdateSerialId; if (updateView)
fParsing:=True; emit onBusy();
OnBusy; emit onStartParsing();
OnStartParsing; }
finally {
fCriticalSection.Release; auto action = finally([&,this]{
end; mParsing = false;
try if (updateView)
// Support stopping of parsing when files closes unexpectedly emit onEndParsing(mFilesScannedCount,1);
fFilesScannedCount := 0; else
fFilesToScanCount := fFilesToScan.Count; emit onEndParsing(mFilesScannedCount,0);
// parse header files in the first parse });
for i:=0 to fFilesToScan.Count-1 do begin // Support stopping of parsing when files closes unexpectedly
if IsCFile(fFilesToScan[i]) then mFilesScannedCount = 0;
continue; mFilesToScanCount = mFilesToScan.count();
Inc(fFilesScannedCount); // progress is mentioned before scanning begins // parse header files in the first parse
OnProgress(fCurrentFile,fFilesToScanCount,fFilesScannedCount); for (QString file:mFilesToScan) {
if FastIndexOf(fScannedFiles,fFilesToScan[i]) = -1 then begin if (isHfile(file)) {
InternalParse(fFilesToScan[i]); mFilesScannedCount++;
end; emit onProgress(mCurrentFile,mFilesToScanCount,mFilesScannedCount);
end; if (!mPreprocessor.scannedFiles().contains(file)) {
//we only parse CFile in the second parse internalParse(file);
for i:=0 to fFilesToScan.Count-1 do begin }
if not IsCFile(fFilesToScan[i]) then }
continue; }
Inc(fFilesScannedCount); // progress is mentioned before scanning begins //we only parse CFile in the second parse
OnProgress(fCurrentFile,fFilesToScanCount,fFilesScannedCount); for (QString file:mFilesToScan) {
if FastIndexOf(fScannedFiles,fFilesToScan[i]) = -1 then begin if (isCfile(file)) {
InternalParse(fFilesToScan[i]); mFilesScannedCount++;
end; emit onProgress(mCurrentFile,mFilesToScanCount,mFilesScannedCount);
end; if (!mPreprocessor.scannedFiles().contains(file)) {
fFilesToScan.Clear; internalParse(file);
finally }
fParsing:=False; }
if UpdateView then }
OnEndParsing(fFilesScannedCount,1) mFilesToScan.clear();
else }
OnEndParsing(fFilesScannedCount,0);
end;
} }
bool CppParser::parsing() void CppParser::parseHardDefines()
{
QMutexLocker locker(&mMutex);
if (mParsing)
return;
mParsing=true;
{
auto action = finally([this]{
mParsing = false;
});
for (PDefine define:mPreprocessor.hardDefines()) {
QString hintText = "#define";
if (define->name != "")
hintText += ' ' + define->name;
if (define->args != "")
hintText += ' ' + define->args;
if (define->value != "")
hintText += ' ' + define->value;
addStatement(
PStatement(), // defines don't belong to any scope
"",
hintText, // override hint
"", // define has no type
define->name,
define->value,
define->args,
-1,
StatementKind::skPreprocessor,
StatementScope::ssGlobal,
StatementClassScope::scsNone,
true,
false);
}
}
}
bool CppParser::parsing() const
{ {
return mParsing; return mParsing;
} }
void CppParser::reset()
{
while (true) {
{
QMutexLocker locker(&mMutex);
if (!mParsing && mLockCount ==0) {
mParsing = true;
break;
}
}
QThread::msleep(50);
QCoreApplication* app = QApplication::instance();
app->processEvents();
}
{
auto action = finally([this]{
mParsing = false;
});
emit onBusy();
mPreprocessor.clear();
mUniqId = 0;
mSkipList.clear();
mBlockBeginSkips.clear();
mBlockEndSkips.clear();
mInlineNamespaceEndSkips.clear();
mParseLocalHeaders = true;
mParseGlobalHeaders = true;
mCurrentScope.clear();
mCurrentClassScope.clear();
mProjectFiles.clear();
mFilesToScan.clear();
mTokenizer.reset();
// Remove all statements
mStatementList.clear();
// We haven't scanned anything anymore
mPreprocessor.scannedFiles().clear();
// We don't include anything anymore
mPreprocessor.includesList().clear();
mNamespaces.clear();
mPreprocessor.projectIncludePaths().clear();
mPreprocessor.includePaths().clear();
mProjectFiles.clear();
}
}
void CppParser::unFreeze()
{
QMutexLocker locker(&mMutex);
mLockCount--;
}
QString CppParser::prettyPrintStatement(PStatement statement, int line)
{
//TODO: implement it
return "not implemented yet";
}
QString CppParser::getFirstTemplateParam(PStatement statement, const QString& filename, const QString& phrase, PStatement currentScope) QString CppParser::getFirstTemplateParam(PStatement statement, const QString& filename, const QString& phrase, PStatement currentScope)
{ {
if (!statement) if (!statement)
@ -813,12 +918,12 @@ PStatement CppParser::addStatement(PStatement parent, const QString &fileName, c
if (oldStatement && isDefinition && !oldStatement->hasDefinition) { if (oldStatement && isDefinition && !oldStatement->hasDefinition) {
oldStatement->hasDefinition = true; oldStatement->hasDefinition = true;
if (oldStatement->fileName!=fileName) { if (oldStatement->fileName!=fileName) {
PFileIncludes fileIncludes1=mIncludesList->value(fileName); PFileIncludes fileIncludes1=mPreprocessor.includesList().value(fileName);
if (fileIncludes1) { if (fileIncludes1) {
fileIncludes1->statements.insert(oldStatement->fullName, fileIncludes1->statements.insert(oldStatement->fullName,
oldStatement); oldStatement);
fileIncludes1->dependingFiles.insert(oldStatement->fileName); fileIncludes1->dependingFiles.insert(oldStatement->fileName);
PFileIncludes fileIncludes2=mIncludesList->value(oldStatement->fileName); PFileIncludes fileIncludes2=mPreprocessor.includesList().value(oldStatement->fileName);
if (fileIncludes2) { if (fileIncludes2) {
fileIncludes2->dependedFiles.insert(fileName); fileIncludes2->dependedFiles.insert(fileName);
} }
@ -876,7 +981,7 @@ PStatement CppParser::addStatement(PStatement parent, const QString &fileName, c
} }
if (result->kind!= StatementKind::skBlock) { if (result->kind!= StatementKind::skBlock) {
PFileIncludes fileIncludes = mIncludesList->value(fileName); PFileIncludes fileIncludes = mPreprocessor.includesList().value(fileName);
if (fileIncludes) { if (fileIncludes) {
fileIncludes->statements.insert(result->fullName,result); fileIncludes->statements.insert(result->fullName,result);
fileIncludes->declaredStatements.insert(result->fullName,result); fileIncludes->declaredStatements.insert(result->fullName,result);
@ -957,7 +1062,7 @@ void CppParser::addSoloScopeLevel(PStatement statement, int line)
mCurrentScope.append(statement); mCurrentScope.append(statement);
PFileIncludes fileIncludes = mIncludesList->value(mCurrentFile); PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile);
if (fileIncludes) { if (fileIncludes) {
fileIncludes->scopes.addScope(line,statement); fileIncludes->scopes.addScope(line,statement);
@ -981,7 +1086,7 @@ void CppParser::removeScopeLevel(int line)
if (mCurrentScope.isEmpty()) if (mCurrentScope.isEmpty())
return; // TODO: should be an exception return; // TODO: should be an exception
PStatement currentScope = mCurrentScope.back();; PStatement currentScope = mCurrentScope.back();;
PFileIncludes fileIncludes = mIncludesList->value(mCurrentFile); PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile);
if (currentScope && (currentScope->kind == StatementKind::skBlock)) { if (currentScope && (currentScope->kind == StatementKind::skBlock)) {
if (currentScope->children.isEmpty()) { if (currentScope->children.isEmpty()) {
// remove no children block // remove no children block
@ -1482,6 +1587,7 @@ PStatement CppParser::getTypeDef(PStatement statement, const QString& fileName,
PStatement result = findTypeDefinitionOf(fileName,statement->type, statement->parentScope.lock()); PStatement result = findTypeDefinitionOf(fileName,statement->type, statement->parentScope.lock());
if (!result) // found end of typedef trail, return result if (!result) // found end of typedef trail, return result
return statement; return statement;
return result;
} else } else
return PStatement(); return PStatement();
} }
@ -1764,7 +1870,7 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, const Q
int startLine = mTokenizer[mIndex]->line; int startLine = mTokenizer[mIndex]->line;
// Skip over argument list // Skip over argument list
while ((mIndex < mTokenizer.tokenCount()) and ! ( while ((mIndex < mTokenizer.tokenCount()) && ! (
isblockChar(mTokenizer[mIndex]->text.front()) isblockChar(mTokenizer[mIndex]->text.front())
|| mTokenizer[mIndex]->text.startsWith(':'))) || mTokenizer[mIndex]->text.startsWith(':')))
mIndex++; mIndex++;
@ -2574,7 +2680,7 @@ void CppParser::handleUsing()
scopeStatement->usingList.insert(fullName); scopeStatement->usingList.insert(fullName);
} }
} else { } else {
PFileIncludes fileInfo = mIncludesList->value(mCurrentFile); PFileIncludes fileInfo = mPreprocessor.includesList().value(mCurrentFile);
if (!fileInfo) if (!fileInfo)
return; return;
if (mNamespaces.contains(usingName)) { if (mNamespaces.contains(usingName)) {
@ -2715,7 +2821,7 @@ void CppParser::handleVar()
getScope(), getScope(),
mClassScope, mClassScope,
//True, //True,
not isExtern, !isExtern,
isStatic); // TODO: not supported to pass list isStatic); // TODO: not supported to pass list
varAdded = true; varAdded = true;
} }
@ -2807,8 +2913,8 @@ void CppParser::internalParse(const QString &fileName)
void CppParser::inheritClassStatement(PStatement derived, bool isStruct, PStatement base, StatementClassScope access) void CppParser::inheritClassStatement(PStatement derived, bool isStruct, PStatement base, StatementClassScope access)
{ {
PFileIncludes fileIncludes1=mIncludesList->value(derived->fileName); PFileIncludes fileIncludes1=mPreprocessor.includesList().value(derived->fileName);
PFileIncludes fileIncludes2=mIncludesList->value(base->fileName); PFileIncludes fileIncludes2=mPreprocessor.includesList().value(base->fileName);
if (fileIncludes1 && fileIncludes2) { if (fileIncludes1 && fileIncludes2) {
//derived class depeneds on base class //derived class depeneds on base class
fileIncludes1->dependingFiles.insert(base->fileName); fileIncludes1->dependingFiles.insert(base->fileName);
@ -2985,7 +3091,7 @@ void CppParser::internalInvalidateFile(const QString &fileName)
} }
} }
// delete it from scannedfiles // delete it from scannedfiles
mScannedFiles->remove(fileName); mPreprocessor.scannedFiles().remove(fileName);
// remove its include files list // remove its include files list
PFileIncludes p = findFileIncludes(fileName, true); PFileIncludes p = findFileIncludes(fileName, true);
@ -3031,7 +3137,7 @@ QSet<QString> CppParser::calculateFilesToBeReparsed(const QString &fileName)
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
QString name = queue.dequeue(); QString name = queue.dequeue();
processed.insert(name); processed.insert(name);
PFileIncludes p=mIncludesList->value(name); PFileIncludes p=mPreprocessor.includesList().value(name);
if (!p) if (!p)
continue; continue;
for (QString s:p->dependedFiles) { for (QString s:p->dependedFiles) {
@ -3411,6 +3517,11 @@ void CppParser::updateSerialId()
mSerialId = QString("%1 %2").arg(mParserId).arg(mSerialCount); mSerialId = QString("%1 %2").arg(mParserId).arg(mSerialCount);
} }
int CppParser::parserId() const
{
return mParserId;
}
void CppParser::setOnGetFileStream(const GetFileStreamCallBack &newOnGetFileStream) void CppParser::setOnGetFileStream(const GetFileStreamCallBack &newOnGetFileStream)
{ {
mOnGetFileStream = newOnGetFileStream; mOnGetFileStream = newOnGetFileStream;

View File

@ -66,29 +66,29 @@ public:
QString getHeaderFileName(const QString& relativeTo, const QString& line);// both QString getHeaderFileName(const QString& relativeTo, const QString& line);// both
StatementKind getKindOfStatement(PStatement statement); StatementKind getKindOfStatement(PStatement statement);
void invalidateFile(const QString& fileName); void invalidateFile(const QString& fileName);
bool isIncludeLine(const QString &line);
bool isProjectHeaderFile(const QString& fileName); bool isProjectHeaderFile(const QString& fileName);
bool isSystemHeaderFile(const QString& fileName); bool isSystemHeaderFile(const QString& fileName);
void parseFile(const QString& fileName, bool inProject, void parseFile(const QString& fileName, bool inProject,
bool onlyIfNotParsed = false, bool updateView = true); bool onlyIfNotParsed = false, bool updateView = true);
void parseFileList(bool updateView = true); void parseFileList(bool updateView = true);
bool parsing();
void parseHardDefines(); void parseHardDefines();
void getSourcePair(const QString& fName, QString& CFile, QString& HFile); bool parsing() const;
void reset();
void unFreeze(); // UnFree/UnLock (reparse while searching)
int suggestMemberInsertionLine(PStatement parentStatement, //void getSourcePair(const QString& fName, QString& CFile, QString& HFile);
StatementClassScope Scope,
bool addScopeStr); // int suggestMemberInsertionLine(PStatement parentStatement,
// StatementClassScope Scope,
// bool addScopeStr);
// { // {
// function GetSystemHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h> // function GetSystemHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h>
// function GetProjectHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h> // function GetProjectHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h>
// function GetLocalHeaderFileName(const RelativeTo, FileName: AnsiString): AnsiString; // "file.h" // function GetLocalHeaderFileName(const RelativeTo, FileName: AnsiString): AnsiString; // "file.h"
// } // }
bool isIncludeLine(const QString &line); //QString statementKindStr(StatementKind value);
void parseFileList(bool updateView = true); //QString statementClassScopeStr(StatementClassScope value);
QString statementKindStr(StatementKind value);
QString statementClassScopeStr(StatementClassScope value);
void reset();
QString prettyPrintStatement(PStatement statement, int line = -1); QString prettyPrintStatement(PStatement statement, int line = -1);
@ -97,15 +97,9 @@ public:
// StatementKind findKindOfStatementOf(const QString& fileName, // StatementKind findKindOfStatementOf(const QString& fileName,
// const QString& phrase, // const QString& phrase,
// int line); // int line);
QString getHintFromStatement(const QString& fileName, // QString getHintFromStatement(const QString& fileName,
const QString& phrase, // const QString& phrase,
int line); // int line);
void unFreeze(); // UnFree/UnLock (reparse while searching)
bool getParsing();
bool enabled() const; bool enabled() const;
void setEnabled(bool newEnabled); void setEnabled(bool newEnabled);
@ -114,6 +108,8 @@ public:
void setOnGetFileStream(const GetFileStreamCallBack &newOnGetFileStream); void setOnGetFileStream(const GetFileStreamCallBack &newOnGetFileStream);
int parserId() const;
signals: signals:
void onProgress(const QString& fileName, int total, int current); void onProgress(const QString& fileName, int total, int current);
void onBusy(); void onBusy();
@ -326,7 +322,6 @@ private:
QVector<int> mSkipList; // TList<Integer> QVector<int> mSkipList; // TList<Integer>
StatementClassScope mClassScope; StatementClassScope mClassScope;
StatementModel mStatementList; StatementModel mStatementList;
std::shared_ptr<QHash<QString,PFileIncludes>> mIncludesList; //List of scaned files and it's infos
//It's used in preprocessor, so we can't use fIncludeList instead //It's used in preprocessor, so we can't use fIncludeList instead
CppTokenizer mTokenizer; CppTokenizer mTokenizer;

View File

@ -1580,6 +1580,11 @@ int CppPreprocessor::evaluateExpression(QString line)
return result; return result;
} }
const DefineMap &CppPreprocessor::hardDefines() const
{
return mHardDefines;
}
QSet<QString> &CppPreprocessor::projectIncludePaths() QSet<QString> &CppPreprocessor::projectIncludePaths()
{ {
return mProjectIncludePaths; return mProjectIncludePaths;

View File

@ -57,6 +57,8 @@ public:
QSet<QString> &projectIncludePaths(); QSet<QString> &projectIncludePaths();
const DefineMap &hardDefines() const;
signals: signals:
private: private:

View File

@ -103,8 +103,8 @@ void SynEditTextPainter::paintGutter(const QRect& clip)
if (edit->mGutter.useFontStyle()) { if (edit->mGutter.useFontStyle()) {
painter->setFont(edit->mGutter.font()); painter->setFont(edit->mGutter.font());
} }
if (edit->mGutter->textColor().isValid()) { if (edit->mGutter.textColor().isValid()) {
painter->setPen(edit->mGutter->textColor()); painter->setPen(edit->mGutter.textColor());
} else { } else {
painter->setPen(edit->palette().color(QPalette::Text)); painter->setPen(edit->palette().color(QPalette::Text));
} }

View File

@ -256,7 +256,7 @@ void SearchResultTreeViewDelegate::paint(QPainter *painter, const QStyleOptionVi
// Painting item without text (this takes care of painting e.g. the highlighted for selected // Painting item without text (this takes care of painting e.g. the highlighted for selected
// or hovered over items in an ItemView) // or hovered over items in an ItemView)
option->text = QString(); option.text = QString();
style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget);
SearchResultTreeItem* item = static_cast<SearchResultTreeItem *>(index.internalPointer()); SearchResultTreeItem* item = static_cast<SearchResultTreeItem *>(index.internalPointer());
@ -268,7 +268,7 @@ void SearchResultTreeViewDelegate::paint(QPainter *painter, const QStyleOptionVi
.arg(item->text); .arg(item->text);
} }
// Figure out where to render the text in order to follow the requested alignment // Figure out where to render the text in order to follow the requested alignment
option->text = fullText; option.text = fullText;
QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &option); QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &option);
QFontMetrics metrics = option.fontMetrics; QFontMetrics metrics = option.fontMetrics;