- fix: Crash if #include a non-exist header file in the source.

This commit is contained in:
Roy Qu 2023-11-05 21:00:52 +08:00
parent ce9398c2a4
commit aa12dcc4d1
8 changed files with 81 additions and 84 deletions

View File

@ -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

View File

@ -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<QString> fileIncludes = parser->getFileIncludes(unit->fileName());
if (parser && parser->fileScanned(unit->fileName())) {
QSet<QString> fileIncludes = parser->getIncludedFiles(unit->fileName());
foreach(const PProjectUnit &unit2, projectUnits) {
if (unit2==unit)
continue;

View File

@ -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<QString> fileIncludes = parser->getFileIncludes(unit->fileName());
if (parser && parser->fileScanned(unit->fileName())) {
QSet<QString> fileIncludes = parser->getIncludedFiles(unit->fileName());
foreach(const PProjectUnit &unit2, projectUnits) {
if (unit2==unit)
continue;

View File

@ -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<QString> CppParser::getFileIncludes(const QString &filename)
QSet<QString> CppParser::getIncludedFiles(const QString &filename)
{
QMutexLocker locker(&mMutex);
QSet<QString> list;
@ -793,7 +793,7 @@ QSet<QString> 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<QString> 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<QString> 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,16 +1698,16 @@ void CppParser::removeScopeLevel(int line)
// qDebug()<<"--remove scope"<<mCurrentFile<<line<<mCurrentClassScope.count();
#endif
PStatement currentScope = getCurrentScope();
PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile);
PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(mCurrentFile);
if (currentScope) {
if (currentScope->kind == StatementKind::skBlock) {
if (currentScope->children.isEmpty()) {
// remove no children block
if (fileIncludes) {
if (fileIncludes)
fileIncludes->scopes.removeLastScope();
}
mStatementList.deleteStatement(currentScope);
} else {
if (fileIncludes)
fileIncludes->statements.insert(currentScope->fullName,currentScope);
}
} else if (currentScope->kind == StatementKind::skClass) {
@ -1742,13 +1745,11 @@ void CppParser::internalClear()
QStringList CppParser::sortFilesByIncludeRelations(const QSet<QString> &files)
{
QStringList result;
QSet<QString> saveScannedFiles;
saveScannedFiles=mPreprocessor.scannedFiles();
QSet<QString> 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,14 +1763,16 @@ QStringList CppParser::sortFilesByIncludeRelations(const QSet<QString> &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;
if (fileIncludes) {
foreach(const QString& inc,fileIncludes->includeFiles.keys()) {
if (fileSet.contains(inc)) {
hasInclude=true;
break;
}
}
}
if (!hasInclude) {
result.push_front(file);
fileSet.remove(file);
@ -1784,7 +1787,7 @@ QStringList CppParser::sortFilesByIncludeRelations(const QSet<QString> &files)
}
}
}
QSet<QString> newScannedFiles = mPreprocessor.scannedFiles();
QSet<QString> 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()<<mCurrentScope.size()<<mCurrentFile<<mTokenizer[mIndex]->line<<s.mid(0,delimPos).trimmed();
mCurrentFile = s.mid(0,delimPos).trimmed();
PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile);
PFileIncludes fileIncludes = mPreprocessor.findFileIncludes(mCurrentFile);
if (fileIncludes) {
mCurrentFile = fileIncludes->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<PStatement> 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<QString> CppParser::calculateFilesToBeReparsed(const QString &fileName)
QSet<QString> 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);
}

View File

@ -98,7 +98,7 @@ public:
bool freeze(const QString& serialId); // Freeze/Lock (stop reparse while searching)
QStringList getClassesList();
QStringList getFileDirectIncludes(const QString& filename);
QSet<QString> getFileIncludes(const QString& filename);
QSet<QString> getIncludedFiles(const QString& filename);
QSet<QString> 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<QString> scannedFiles();
bool fileScanned(const QString& fileName);
bool isFileParsed(const QString& filename);

View File

@ -857,12 +857,14 @@ void CppPreprocessor::openInclude(QString fileName)
//add defines of already parsed including headers;
addDefinesInFile(fileName);
PFileIncludes fileIncludes = getFileIncludesEntry(fileName);
if (fileIncludes) {
for (PParsedFile& file:mIncludes) {
foreach (const QString& incFile,fileIncludes->includeFiles.keys()) {
file->fileIncludes->includeFiles.insert(incFile,false);
}
}
}
}
mIncludes.append(parsedFile);
// Process it
@ -942,10 +944,12 @@ void CppPreprocessor::addDefinesInFile(const QString &fileName)
}
PFileIncludes fileIncludes = getFileIncludesEntry(fileName);
if (fileIncludes) {
foreach (const QString& file, fileIncludes->includeFiles.keys()) {
addDefinesInFile(file);
}
}
}
void CppPreprocessor::parseArgs(PDefine define)
{
@ -2022,28 +2026,3 @@ const DefineMap &CppPreprocessor::hardDefines() const
{
return mHardDefines;
}
const QSet<QString> &CppPreprocessor::projectIncludePaths()
{
return mProjectIncludePaths;
}
const QSet<QString> &CppPreprocessor::includePaths()
{
return mIncludePaths;
}
QSet<QString> &CppPreprocessor::scannedFiles()
{
return mScannedFiles;
}
QHash<QString, PFileIncludes> &CppPreprocessor::includesList()
{
return mIncludesList;
}
const QHash<QString, PFileIncludes> &CppPreprocessor::includesList() const
{
return mIncludesList;
}

View File

@ -84,15 +84,29 @@ public:
return mResult;
};
QHash<QString, PFileIncludes> &includesList();
PFileIncludes findFileIncludes(const QString& fileName) const {
return mIncludesList.value(fileName);
}
const QHash<QString, PFileIncludes> &includesList() const;
void removeFileIncludes(const QString& fileName) {
mIncludesList.remove(fileName);
}
QSet<QString> &scannedFiles();
bool fileScanned(const QString& fileName) const {
return mScannedFiles.contains(fileName);
}
const QSet<QString> &includePaths();
const QSet<QString>& includePaths() const {
return mIncludePaths;
}
const QSet<QString> &projectIncludePaths();
const QSet<QString>& scannedFiles() const {
return mScannedFiles;
}
const QSet<QString> &projectIncludePaths() {
return mProjectIncludePaths;
}
const DefineMap &hardDefines() const;

View File

@ -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);