From aa12dcc4d17b6e39c960906acf581739394fa333 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Sun, 5 Nov 2023 21:00:52 +0800 Subject: [PATCH] - fix: Crash if #include a non-exist header file in the source. --- NEWS.md | 1 + RedPandaIDE/compiler/projectcompiler.cpp | 4 +- RedPandaIDE/compiler/sdccprojectcompiler.cpp | 4 +- RedPandaIDE/parser/cppparser.cpp | 81 ++++++++++---------- RedPandaIDE/parser/cppparser.h | 4 +- RedPandaIDE/parser/cpppreprocessor.cpp | 39 +++------- RedPandaIDE/parser/cpppreprocessor.h | 24 ++++-- RedPandaIDE/widgets/codecompletionpopup.cpp | 8 +- 8 files changed, 81 insertions(+), 84 deletions(-) diff --git a/NEWS.md b/NEWS.md index e7574cec..14b05243 100644 --- a/NEWS.md +++ b/NEWS.md @@ -25,6 +25,7 @@ Red Panda C++ Version 2.26 - enhancement: Slightly reduce memory usage. - change: In Options -> Language -> Generate Assembly, option "Don't generate SEH directives" default to True. - change: In Options —> Editor -> Code Suggestion, option "Hide symbols starting with underscore" default to True. + - fix: Crash if include a non-exist header file in the source. Red Panda C++ Version 2.25 diff --git a/RedPandaIDE/compiler/projectcompiler.cpp b/RedPandaIDE/compiler/projectcompiler.cpp index 56ab9e6c..a1e2ef36 100644 --- a/RedPandaIDE/compiler/projectcompiler.cpp +++ b/RedPandaIDE/compiler/projectcompiler.cpp @@ -358,8 +358,8 @@ void ProjectCompiler::writeMakeObjFilesRules(QFile &file) writeln(file); QString objStr=genMakePath2(shortFileName); // if we have scanned it, use scanned info - if (parser && parser->scannedFiles().contains(unit->fileName())) { - QSet fileIncludes = parser->getFileIncludes(unit->fileName()); + if (parser && parser->fileScanned(unit->fileName())) { + QSet fileIncludes = parser->getIncludedFiles(unit->fileName()); foreach(const PProjectUnit &unit2, projectUnits) { if (unit2==unit) continue; diff --git a/RedPandaIDE/compiler/sdccprojectcompiler.cpp b/RedPandaIDE/compiler/sdccprojectcompiler.cpp index e360985e..d471dadb 100644 --- a/RedPandaIDE/compiler/sdccprojectcompiler.cpp +++ b/RedPandaIDE/compiler/sdccprojectcompiler.cpp @@ -235,8 +235,8 @@ void SDCCProjectCompiler::writeMakeObjFilesRules(QFile &file) writeln(file); QString objStr=genMakePath2(shortFileName); // if we have scanned it, use scanned info - if (parser && parser->scannedFiles().contains(unit->fileName())) { - QSet fileIncludes = parser->getFileIncludes(unit->fileName()); + if (parser && parser->fileScanned(unit->fileName())) { + QSet fileIncludes = parser->getIncludedFiles(unit->fileName()); foreach(const PProjectUnit &unit2, projectUnits) { if (unit2==unit) continue; diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 9cb96d5f..62e11711 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -187,7 +187,7 @@ PStatement CppParser::findScopeStatement(const QString &filename, int line) PStatement CppParser::doFindScopeStatement(const QString &filename, int line) const { - PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(filename); if (!fileIncludes) return PStatement(); @@ -197,9 +197,9 @@ PStatement CppParser::doFindScopeStatement(const QString &filename, int line) co PFileIncludes CppParser::findFileIncludes(const QString &filename, bool deleteIt) { QMutexLocker locker(&mMutex); - PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename,PFileIncludes()); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(filename); if (deleteIt && fileIncludes) - mPreprocessor.includesList().remove(filename); + mPreprocessor.removeFileIncludes(filename); return fileIncludes; } QString CppParser::findFirstTemplateParamOf(const QString &fileName, const QString &phrase, const PStatement& currentScope) @@ -221,7 +221,7 @@ QString CppParser::findTemplateParamOf(const QString &fileName, const QString &p PStatement CppParser::findFunctionAt(const QString &fileName, int line) { QMutexLocker locker(&mMutex); - PFileIncludes fileIncludes = mPreprocessor.includesList().value(fileName); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(fileName); if (!fileIncludes) return PStatement(); for (PStatement& statement : fileIncludes->statements) { @@ -775,7 +775,7 @@ QStringList CppParser::getFileDirectIncludes(const QString &filename) return QStringList(); if (filename.isEmpty()) return QStringList(); - PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename,PFileIncludes()); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(filename); if (fileIncludes) { return fileIncludes->directIncludes; @@ -784,7 +784,7 @@ QStringList CppParser::getFileDirectIncludes(const QString &filename) } -QSet CppParser::getFileIncludes(const QString &filename) +QSet CppParser::getIncludedFiles(const QString &filename) { QMutexLocker locker(&mMutex); QSet list; @@ -793,7 +793,7 @@ QSet CppParser::getFileIncludes(const QString &filename) if (filename.isEmpty()) return list; list.insert(filename); - PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename,PFileIncludes()); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(filename); if (fileIncludes) { foreach (const QString& file, fileIncludes->includeFiles.keys()) { @@ -816,13 +816,13 @@ QSet CppParser::internalGetFileUsings(const QString &filename) const return result; // if (mParsing) // return result; - PFileIncludes fileIncludes= mPreprocessor.includesList().value(filename,PFileIncludes()); + PFileIncludes fileIncludes= mPreprocessor.findFileIncludes(filename); if (fileIncludes) { foreach (const QString& usingName, fileIncludes->usings) { result.insert(usingName); } foreach (const QString& subFile,fileIncludes->includeFiles.keys()){ - PFileIncludes subIncludes = mPreprocessor.includesList().value(subFile,PFileIncludes()); + PFileIncludes subIncludes = mPreprocessor.findFileIncludes(subFile); if (subIncludes) { foreach (const QString& usingName, subIncludes->usings) { result.insert(usingName); @@ -872,7 +872,7 @@ bool CppParser::isLineVisible(const QString &fileName, int line) if (mParsing) { return true; } - PFileIncludes fileIncludes = mPreprocessor.includesList().value(fileName); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(fileName); if (!fileIncludes) return true; return fileIncludes->isLineVisible(line); @@ -952,7 +952,7 @@ void CppParser::parseFile(const QString &fileName, bool inProject, bool onlyIfNo emit onEndParsing(mFilesScannedCount,0); }); QString fName = fileName; - if (onlyIfNotParsed && mPreprocessor.scannedFiles().contains(fName)) + if (onlyIfNotParsed && mPreprocessor.fileScanned(fName)) return; if (inProject) { @@ -966,7 +966,7 @@ void CppParser::parseFile(const QString &fileName, bool inProject, bool onlyIfNo foreach (const QString& file,files) { mFilesScannedCount++; emit onProgress(file,mFilesToScanCount,mFilesScannedCount); - if (!mPreprocessor.scannedFiles().contains(file)) { + if (!mPreprocessor.fileScanned(file)) { internalParse(file); } } @@ -1022,7 +1022,7 @@ void CppParser::parseFileList(bool updateView) foreach (const QString& file, files) { mFilesScannedCount++; emit onProgress(mCurrentFile,mFilesToScanCount,mFilesScannedCount); - if (!mPreprocessor.scannedFiles().contains(file)) { + if (!mPreprocessor.fileScanned(file)) { internalParse(file); } } @@ -1119,14 +1119,17 @@ void CppParser::unFreeze() mLockCount--; } -QSet CppParser::scannedFiles() +bool CppParser::fileScanned(const QString &fileName) { - return mPreprocessor.scannedFiles(); + QMutexLocker locker(&mMutex); + if (mParsing) + return false; + return mPreprocessor.fileScanned(fileName); } bool CppParser::isFileParsed(const QString &filename) { - return mPreprocessor.scannedFiles().contains(filename); + return mPreprocessor.fileScanned(filename); } QString CppParser::getScopePrefix(const PStatement& statement) const{ @@ -1280,7 +1283,7 @@ void CppParser::addProjectFile(const QString &fileName, bool needScan) mProjectFiles.insert(fileName); // Only parse given file - if (needScan && !mPreprocessor.scannedFiles().contains(fileName)) { + if (needScan && !mPreprocessor.fileScanned(fileName)) { mFilesToScan.insert(fileName); } } @@ -1362,7 +1365,7 @@ PStatement CppParser::addStatement(const PStatement& parent, if (oldStatement && !oldStatement->hasDefinition()) { oldStatement->setHasDefinition(true); if (oldStatement->fileName!=fileName) { - PFileIncludes fileIncludes=mPreprocessor.includesList().value(fileName); + PFileIncludes fileIncludes=mPreprocessor.findFileIncludes(fileName); if (fileIncludes) { fileIncludes->statements.insert(oldStatement->fullName, oldStatement); @@ -1424,7 +1427,7 @@ PStatement CppParser::addStatement(const PStatement& parent, } if (result->kind!= StatementKind::skBlock) { - PFileIncludes fileIncludes = mPreprocessor.includesList().value(fileName); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(fileName); if (fileIncludes) { fileIncludes->statements.insert(result->fullName,result); } @@ -1663,7 +1666,7 @@ void CppParser::addSoloScopeLevel(PStatement& statement, int line, bool shouldRe mCurrentScope.append(statement); - PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(mCurrentFile); if (fileIncludes) { fileIncludes->scopes.addScope(line,statement); @@ -1695,17 +1698,17 @@ void CppParser::removeScopeLevel(int line) // qDebug()<<"--remove scope"<kind == StatementKind::skBlock) { if (currentScope->children.isEmpty()) { // remove no children block - if (fileIncludes) { + if (fileIncludes) fileIncludes->scopes.removeLastScope(); - } mStatementList.deleteStatement(currentScope); } else { - fileIncludes->statements.insert(currentScope->fullName,currentScope); + if (fileIncludes) + fileIncludes->statements.insert(currentScope->fullName,currentScope); } } else if (currentScope->kind == StatementKind::skClass) { mIndex=indexOfNextSemicolon(mIndex); @@ -1742,13 +1745,11 @@ void CppParser::internalClear() QStringList CppParser::sortFilesByIncludeRelations(const QSet &files) { QStringList result; - QSet saveScannedFiles; - - saveScannedFiles=mPreprocessor.scannedFiles(); + QSet saveScannedFiles{mPreprocessor.scannedFiles()}; //rebuild file include relations foreach(const QString& file, files) { - if (mPreprocessor.scannedFiles().contains(file)) + if (mPreprocessor.fileScanned(file)) continue; //already removed in interalInvalidateFiles //mPreprocessor.removeScannedFile(file); @@ -1762,12 +1763,14 @@ QStringList CppParser::sortFilesByIncludeRelations(const QSet &files) while (!fileSet.isEmpty()) { bool found=false; foreach (const QString& file,fileSet) { - PFileIncludes fileIncludes = mPreprocessor.includesList().value(file); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(file); bool hasInclude=false; - foreach(const QString& inc,fileIncludes->includeFiles.keys()) { - if (fileSet.contains(inc)) { - hasInclude=true; - break; + if (fileIncludes) { + foreach(const QString& inc,fileIncludes->includeFiles.keys()) { + if (fileSet.contains(inc)) { + hasInclude=true; + break; + } } } if (!hasInclude) { @@ -1784,7 +1787,7 @@ QStringList CppParser::sortFilesByIncludeRelations(const QSet &files) } } } - QSet newScannedFiles = mPreprocessor.scannedFiles(); + QSet newScannedFiles{mPreprocessor.scannedFiles()}; foreach(const QString& file, newScannedFiles) { if (!saveScannedFiles.contains(file)) mPreprocessor.removeScannedFile(file); @@ -3454,7 +3457,7 @@ void CppParser::handlePreprocessor() if (delimPos>=0) { // qDebug()<line<baseFile; } else { @@ -4061,7 +4064,7 @@ void CppParser::handleUsing() scopeStatement->usingList.insert(fullName); } } else { - PFileIncludes fileInfo = mPreprocessor.includesList().value(mCurrentFile); + PFileIncludes fileInfo = mPreprocessor.findFileIncludes(mCurrentFile); if (!fileInfo) return; if (mNamespaces.contains(usingName)) { @@ -4538,7 +4541,7 @@ PStatement CppParser::findMacro(const QString &phrase, const QString &fileName) if (statementMap.isEmpty()) return PStatement(); StatementList statements = statementMap.values(phrase); - PFileIncludes includes = mPreprocessor.includesList().value(fileName,PFileIncludes()); + PFileIncludes includes = mPreprocessor.findFileIncludes(fileName); foreach (const PStatement& s, statements) { if (s->kind == StatementKind::skPreprocessor) { if (includes && !includes->includeFiles.contains(s->fileName) @@ -4602,7 +4605,7 @@ PStatement CppParser::findMemberOfStatement(const QString& filename, return statementMap.value(s,PStatement()); } else { QList stats = statementMap.values(s); - PFileIncludes fileIncludes = mPreprocessor.includesList().value(filename,PFileIncludes()); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(filename); foreach(const PStatement &s,stats) { if (s->line==-1) { return s; // hard defines @@ -5952,7 +5955,7 @@ QSet CppParser::calculateFilesToBeReparsed(const QString &fileName) QSet result; result.insert(fileName); foreach (const QString& file, mProjectFiles) { - PFileIncludes fileIncludes = mPreprocessor.includesList().value(file,PFileIncludes()); + PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(file); if (fileIncludes && fileIncludes->includeFiles.contains(fileName)) { result.insert(file); } diff --git a/RedPandaIDE/parser/cppparser.h b/RedPandaIDE/parser/cppparser.h index c05ae7cc..0327f419 100644 --- a/RedPandaIDE/parser/cppparser.h +++ b/RedPandaIDE/parser/cppparser.h @@ -98,7 +98,7 @@ public: bool freeze(const QString& serialId); // Freeze/Lock (stop reparse while searching) QStringList getClassesList(); QStringList getFileDirectIncludes(const QString& filename); - QSet getFileIncludes(const QString& filename); + QSet getIncludedFiles(const QString& filename); QSet getFileUsings(const QString& filename); QString getHeaderFileName(const QString& relativeTo, const QString& headerName, bool fromNext=false);// both @@ -116,7 +116,7 @@ public: bool parsing() const; void resetParser(); void unFreeze(); // UnFree/UnLock (reparse while searching) - QSet scannedFiles(); + bool fileScanned(const QString& fileName); bool isFileParsed(const QString& filename); diff --git a/RedPandaIDE/parser/cpppreprocessor.cpp b/RedPandaIDE/parser/cpppreprocessor.cpp index 2e1749e7..e489e4a7 100644 --- a/RedPandaIDE/parser/cpppreprocessor.cpp +++ b/RedPandaIDE/parser/cpppreprocessor.cpp @@ -857,9 +857,11 @@ void CppPreprocessor::openInclude(QString fileName) //add defines of already parsed including headers; addDefinesInFile(fileName); PFileIncludes fileIncludes = getFileIncludesEntry(fileName); - for (PParsedFile& file:mIncludes) { - foreach (const QString& incFile,fileIncludes->includeFiles.keys()) { - file->fileIncludes->includeFiles.insert(incFile,false); + if (fileIncludes) { + for (PParsedFile& file:mIncludes) { + foreach (const QString& incFile,fileIncludes->includeFiles.keys()) { + file->fileIncludes->includeFiles.insert(incFile,false); + } } } } @@ -942,8 +944,10 @@ void CppPreprocessor::addDefinesInFile(const QString &fileName) } PFileIncludes fileIncludes = getFileIncludesEntry(fileName); - foreach (const QString& file, fileIncludes->includeFiles.keys()) { - addDefinesInFile(file); + if (fileIncludes) { + foreach (const QString& file, fileIncludes->includeFiles.keys()) { + addDefinesInFile(file); + } } } @@ -2022,28 +2026,3 @@ const DefineMap &CppPreprocessor::hardDefines() const { return mHardDefines; } - -const QSet &CppPreprocessor::projectIncludePaths() -{ - return mProjectIncludePaths; -} - -const QSet &CppPreprocessor::includePaths() -{ - return mIncludePaths; -} - -QSet &CppPreprocessor::scannedFiles() -{ - return mScannedFiles; -} - -QHash &CppPreprocessor::includesList() -{ - return mIncludesList; -} - -const QHash &CppPreprocessor::includesList() const -{ - return mIncludesList; -} diff --git a/RedPandaIDE/parser/cpppreprocessor.h b/RedPandaIDE/parser/cpppreprocessor.h index 37a9f31d..ea219f9c 100644 --- a/RedPandaIDE/parser/cpppreprocessor.h +++ b/RedPandaIDE/parser/cpppreprocessor.h @@ -84,15 +84,29 @@ public: return mResult; }; - QHash &includesList(); + PFileIncludes findFileIncludes(const QString& fileName) const { + return mIncludesList.value(fileName); + } - const QHash &includesList() const; + void removeFileIncludes(const QString& fileName) { + mIncludesList.remove(fileName); + } - QSet &scannedFiles(); + bool fileScanned(const QString& fileName) const { + return mScannedFiles.contains(fileName); + } - const QSet &includePaths(); + const QSet& includePaths() const { + return mIncludePaths; + } - const QSet &projectIncludePaths(); + const QSet& scannedFiles() const { + return mScannedFiles; + } + + const QSet &projectIncludePaths() { + return mProjectIncludePaths; + } const DefineMap &hardDefines() const; diff --git a/RedPandaIDE/widgets/codecompletionpopup.cpp b/RedPandaIDE/widgets/codecompletionpopup.cpp index 17385755..5f94f302 100644 --- a/RedPandaIDE/widgets/codecompletionpopup.cpp +++ b/RedPandaIDE/widgets/codecompletionpopup.cpp @@ -98,15 +98,15 @@ void CodeCompletionPopup::prepareSearch( getCompletionListForComplexKeyword(preWord); break; case CodeCompletionType::Types: - mIncludedFiles = mParser->getFileIncludes(filename); + mIncludedFiles = mParser->getIncludedFiles(filename); getCompletionListForTypes(preWord,filename,line); break; case CodeCompletionType::FunctionWithoutDefinition: - mIncludedFiles = mParser->getFileIncludes(filename); + mIncludedFiles = mParser->getIncludedFiles(filename); getCompletionForFunctionWithoutDefinition(preWord, ownerExpression,memberOperator,memberExpression, filename,line); break; case CodeCompletionType::Namespaces: - mIncludedFiles = mParser->getFileIncludes(filename); + mIncludedFiles = mParser->getIncludedFiles(filename); getCompletionListForNamespaces(preWord,filename,line); break; case CodeCompletionType::KeywordsOnly: @@ -114,7 +114,7 @@ void CodeCompletionPopup::prepareSearch( getKeywordCompletionFor(customKeywords); break; default: - mIncludedFiles = mParser->getFileIncludes(filename); + mIncludedFiles = mParser->getIncludedFiles(filename); getCompletionFor(ownerExpression,memberOperator,memberExpression, filename,line, customKeywords); } setCursor(oldCursor);