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

View File

@ -66,29 +66,29 @@ public:
QString getHeaderFileName(const QString& relativeTo, const QString& line);// both
StatementKind getKindOfStatement(PStatement statement);
void invalidateFile(const QString& fileName);
bool isIncludeLine(const QString &line);
bool isProjectHeaderFile(const QString& fileName);
bool isSystemHeaderFile(const QString& fileName);
void parseFile(const QString& fileName, bool inProject,
bool onlyIfNotParsed = false, bool updateView = true);
void parseFileList(bool updateView = true);
bool parsing();
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,
StatementClassScope Scope,
bool addScopeStr);
//void getSourcePair(const QString& fName, QString& CFile, QString& HFile);
// int suggestMemberInsertionLine(PStatement parentStatement,
// StatementClassScope Scope,
// bool addScopeStr);
// {
// function GetSystemHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h>
// function GetProjectHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h>
// function GetLocalHeaderFileName(const RelativeTo, FileName: AnsiString): AnsiString; // "file.h"
// }
bool isIncludeLine(const QString &line);
void parseFileList(bool updateView = true);
QString statementKindStr(StatementKind value);
QString statementClassScopeStr(StatementClassScope value);
void reset();
//QString statementKindStr(StatementKind value);
//QString statementClassScopeStr(StatementClassScope value);
QString prettyPrintStatement(PStatement statement, int line = -1);
@ -97,15 +97,9 @@ public:
// StatementKind findKindOfStatementOf(const QString& fileName,
// const QString& phrase,
// int line);
QString getHintFromStatement(const QString& fileName,
const QString& phrase,
int line);
void unFreeze(); // UnFree/UnLock (reparse while searching)
bool getParsing();
// QString getHintFromStatement(const QString& fileName,
// const QString& phrase,
// int line);
bool enabled() const;
void setEnabled(bool newEnabled);
@ -114,6 +108,8 @@ public:
void setOnGetFileStream(const GetFileStreamCallBack &newOnGetFileStream);
int parserId() const;
signals:
void onProgress(const QString& fileName, int total, int current);
void onBusy();
@ -326,7 +322,6 @@ private:
QVector<int> mSkipList; // TList<Integer>
StatementClassScope mClassScope;
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
CppTokenizer mTokenizer;

View File

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

View File

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

View File

@ -103,8 +103,8 @@ void SynEditTextPainter::paintGutter(const QRect& clip)
if (edit->mGutter.useFontStyle()) {
painter->setFont(edit->mGutter.font());
}
if (edit->mGutter->textColor().isValid()) {
painter->setPen(edit->mGutter->textColor());
if (edit->mGutter.textColor().isValid()) {
painter->setPen(edit->mGutter.textColor());
} else {
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
// or hovered over items in an ItemView)
option->text = QString();
option.text = QString();
style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget);
SearchResultTreeItem* item = static_cast<SearchResultTreeItem *>(index.internalPointer());
@ -268,7 +268,7 @@ void SearchResultTreeViewDelegate::paint(QPainter *painter, const QStyleOptionVi
.arg(item->text);
}
// 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);
QFontMetrics metrics = option.fontMetrics;