work save

This commit is contained in:
royqh1979@gmail.com 2021-08-19 23:49:23 +08:00
parent 95129e8859
commit 24a22ec264
6 changed files with 345 additions and 44 deletions

View File

@ -10,6 +10,42 @@ CppParser::CppParser(QObject *parent) : QObject(parent)
}
void CppParser::addHardDefineByLine(const QString &line)
{
QMutexLocker locker(&mMutex);
if (line.startsWith('#')) {
mPreprocessor.addDefineByLine(line.mid(1).trimmed(), true);
} else {
mPreprocessor.addDefineByLine(line, true);
}
}
void CppParser::addIncludePath(const QString &value)
{
mIncludePaths.insert(value);
}
void CppParser::addProjectIncludePath(const QString &value)
{
mProjectIncludePaths.insert(value);
}
void CppParser::addFileToScan(QString value, bool inProject)
{
QMutexLocker locker(&mMutex);
//value.replace('/','\\'); // only accept full file names
// Update project listing
if (inProject)
mProjectFiles.insert(value);
// Only parse given file
if (!mScannedFiles->contains(value)) {
mFilesToScan.insert(value);
}
}
PStatement CppParser::addInheritedStatement(PStatement derived, PStatement inherit, StatementClassScope access)
{
@ -73,7 +109,7 @@ PStatement CppParser::addStatement(PStatement parent, const QString &fileName, c
if (oldStatement->fileName!=fileName) {
PFileIncludes fileIncludes1=findFileIncludes(fileName);
if (fileIncludes1) {
fileIncludes1->statements.insert(oldStatement->command,
fileIncludes1->statements.insert(oldStatement->fullName,
oldStatement);
fileIncludes1->dependingFiles.insert(oldStatement->fileName);
PFileIncludes fileIncludes2=findFileIncludes(oldStatement->fileName);
@ -132,9 +168,69 @@ PStatement CppParser::addStatement(PStatement parent, const QString &fileName, c
}
namespaceList->append(result);
}
if (result->kind!= StatementKind::skBlock) {
PFileIncludes fileIncludes = findFileIncludes(fileName);
if (fileIncludes) {
fileIncludes->statements.insert(result->fullName,result);
fileIncludes->declaredStatements.insert(result->fullName,result);
}
}
return result;
}
void CppParser::setInheritance(int index, PStatement classStatement, bool isStruct)
{
// Clear it. Assume it is assigned
classStatement->inheritanceList.clear();
StatementClassScope lastInheritScopeType = StatementClassScope::scsNone;
// Assemble a list of statements in text form we inherit from
while (true) {
StatementClassScope inheritScopeType = getClassScope(index);
if (inheritScopeType == StatementClassScope::scsNone) {
if (mTokenizer[index]->text.front()!=','
&& mTokenizer[index]->text.front()!=':'
&& mTokenizer[index]->text.front()!='(') {
QString basename = mTokenizer[index]->text;
//remove template staff
if (basename.endsWith('>')) {
int pBegin = basename.indexOf('<');
if (pBegin>=0)
basename.truncate(pBegin);
}
// Find the corresponding PStatement
PStatement statement = findStatementOf(mCurrentFile,basename,
classStatement->parentScope.lock(),true);
if (statement && statement->kind == StatementKind::skClass) {
classStatement->inheritanceList.append(statement);
inheritClassStatement(classStatement,isStruct,statement,lastInheritScopeType);
}
}
}
index++;
lastInheritScopeType = inheritScopeType;
if (index >= mTokenizer.tokenCount())
break;
if (mTokenizer[index]->text.front() == '{'
|| mTokenizer[index]->text.front() == ';')
break;
}
}
bool CppParser::isCurrentScope(const QString &command)
{
PStatement statement = getCurrentScope();
if (!statement)
return false;
QString s = command;
// remove template staff
int i= command.indexOf('<');
if (i>=0) {
s.truncate(i);
}
return (statement->command == s);
}
void CppParser::addSoloScopeLevel(PStatement statement, int line)
{
// Add class list
@ -173,6 +269,79 @@ void CppParser::addSoloScopeLevel(PStatement statement, int line)
mCurrentClassScope.append(mClassScope);
}
void CppParser::removeScopeLevel(int line)
{
// Remove class list
if (mCurrentScope.isEmpty())
return; // TODO: should be an exception
PStatement currentScope = mCurrentScope.back();;
PFileIncludes fileIncludes = findFileIncludes(mCurrentFile);
if (currentScope && (currentScope->kind == StatementKind::skBlock)) {
if (currentScope->children.isEmpty()) {
// remove no children block
if (fileIncludes && !fileIncludes->scopes.isEmpty()) {
fileIncludes->scopes.remove(currentScope->line);
}
mStatementList.deleteStatement(currentScope);
} else {
fileIncludes->statements.insert(currentScope->fullName,currentScope);
fileIncludes->declaredStatements.insert(currentScope->fullName,currentScope);
}
}
mCurrentScope.pop_back();
mCurrentClassScope.pop_back();
// Set new scope
currentScope = getCurrentScope();
// fileIncludes:=FindFileIncludes(fCurrentFile);
if (fileIncludes && !fileIncludes->scopes.isEmpty()
&& fileIncludes->scopes.value(fileIncludes->scopes.keys().back())!=currentScope) {
fileIncludes->scopes.insert(line,currentScope);
}
if (!currentScope) {
mClassScope = StatementClassScope::scsNone;
} else {
mClassScope = mCurrentClassScope.back();
}
}
int CppParser::skipBraces(int startAt)
{
int i = startAt;
int level = 0; // assume we start on top of {
while (i < mTokenizer.tokenCount()) {
switch(mTokenizer[i]->text.front().unicode()) {
case '{': level++;
break;
case '}':
level--;
if (level==0)
return i;
}
i++;
}
return startAt;
}
int CppParser::skipBracket(int startAt)
{
int i = startAt;
int level = 0; // assume we start on top of {
while (i < mTokenizer.tokenCount()) {
switch(mTokenizer[i]->text.front().unicode()) {
case '[': level++;
break;
case ']':
level--;
if (level==0)
return i;
}
i++;
}
return startAt;
}
bool CppParser::checkForCatchBlock()
{
// return mIndex < mTokenizer.tokenCount() &&
@ -270,7 +439,7 @@ bool CppParser::checkForMethod(QString &sType, QString &sName, QString &sArgs, b
sType = mTokenizer[mIndex]->text;
if (sType[0] == '~')
sType.remove(0,1);
bTypeOK = isInCurrentScopeLevel(sType); // constructor/destructor
bTypeOK = isCurrentScope(sType); // constructor/destructor
}
break;
} else {
@ -1258,16 +1427,20 @@ void CppParser::handlePreprocessor()
mIndex++;
}
StatementClassScope CppParser::getClassScope(int index) {
if (mTokenizer[index]->text=="public")
return StatementClassScope::scsPublic;
else if (mTokenizer[index]->text=="private")
return StatementClassScope::scsPrivate;
else if (mTokenizer[index]->text=="protected")
return StatementClassScope::scsProtected;
else
return StatementClassScope::scsNone;
}
void CppParser::handleScope()
{
if (mTokenizer[mIndex]->text=="public")
mClassScope = StatementClassScope::scsPublic;
else if (mTokenizer[mIndex]->text=="private")
mClassScope = StatementClassScope::scsPrivate;
else if (mTokenizer[mIndex]->text=="protected")
mClassScope = StatementClassScope::scsProtected;
else
mClassScope = StatementClassScope::scsNone;
mClassScope = getClassScope(mIndex);
mIndex+=2; // the scope is followed by a ':'
}
@ -1850,7 +2023,7 @@ void CppParser::handleVar()
mIndex++;
}
void CppParser::internalParse(const QString &fileName, bool manualUpdate)
void CppParser::internalParse(const QString &fileName)
{
// Perform some validation before we start
if (!mEnabled)
@ -2099,6 +2272,129 @@ int CppParser::calcKeyLenForStruct(const QString &word)
return -1;
}
void CppParser::scanMethodArgs(PStatement functionStatement, const QString &argStr)
{
// Split up argument string by ,
int i = 1; // assume it starts with ( and ends with )
int paramStart = i;
QString args;
while (i < argStr.length()) {
if ((argStr[i] == ',') ||
((i == argStr.length()-1) && (argStr[i] == ')'))) {
// We've found "int* a" for example
QString s = argStr.mid(paramStart,i-paramStart);
//remove default value
int assignPos = s.indexOf('=');
if (assignPos >= 0) {
s.truncate(assignPos);
s = s.trimmed();
}
// we don't support function pointer parameters now, till we can tokenize function parameters
// {
// // Can be a function pointer. If so, scan after last )
// BracePos := LastPos(')', S);
// if (BracePos > 0) then // it's a function pointer... begin
// SpacePos := LastPos(' ', Copy(S, BracePos, MaxInt)) // start search at brace
// end else begin
// }
int spacePos = s.lastIndexOf(' '); // Cut up at last space
if (spacePos >= 0) {
args = "";
int bracketPos = s.indexOf('[');
if (bracketPos >= 0) {
args = s.mid(bracketPos);
s.truncate(bracketPos);
}
addStatement(
functionStatement,
mCurrentFile,
"", // do not override hint
s.mid(0,spacePos), // 'int*'
s.mid(spacePos+1), // a
args,
"",
functionStatement->definitionLine,
StatementKind::skParameter,
StatementScope::ssLocal,
StatementClassScope::scsNone,
true,
false);
}
paramStart = i + 1; // step over ,
}
i++;
}
}
QString CppParser::splitPhrase(const QString &phrase, QString &sClazz, QString &sMember, QString &sOperator)
{
sClazz="";
sMember="";
sOperator="";
QString result="";
int bracketLevel = 0;
// Obtain stuff before first operator
int firstOpStart = phrase.length() + 1;
int firstOpEnd = phrase.length() + 1;
for (int i = 0; i<phrase.length();i++) {
if ((i+1<phrase.length()) && (phrase[i] == '-') && (phrase[i + 1] == '>') && (bracketLevel=0)) {
firstOpStart = i;
firstOpEnd = i+2;
sOperator = "->";
break;
} else if ((i+1<phrase.length()) && (phrase[i] == ':') && (phrase[i + 1] == ':') && (bracketLevel=0)) {
firstOpStart = i;
firstOpEnd = i+2;
sOperator = "::";
break;
} else if ((phrase[i] == '.') && (bracketLevel=0)) {
firstOpStart = i;
firstOpEnd = i+1;
sOperator = ".";
break;
} else if (phrase[i] == '[') {
bracketLevel++;
} else if (phrase[i] == ']') {
bracketLevel--;
}
}
sClazz = phrase.mid(0, firstOpStart);
if (firstOpStart == 0) {
sMember = "";
return "";
}
result = phrase.mid(firstOpEnd);
// ... and before second op, if there is one
int secondOp = 0;
bracketLevel = 0;
for (int i = firstOpEnd; i<phrase.length();i++) {
if ((i+1<phrase.length()) && (phrase[i] == '-') && (phrase[i + 1] == '>') && (bracketLevel=0)) {
secondOp = i;
break;
} else if ((i+1<phrase.length()) && (phrase[i] == ':') && (phrase[i + 1] == ':') && (bracketLevel=0)) {
secondOp = i;
break;
} else if ((phrase[i] == '.') && (bracketLevel=0)) {
secondOp = i;
break;
} else if (phrase[i] == '[') {
bracketLevel++;
} else if (phrase[i] == ']') {
bracketLevel--;
}
}
if (secondOp == 0) {
sMember = phrase.mid(firstOpEnd);
} else {
sMember = phrase.mid(firstOpEnd,secondOp-firstOpEnd);
}
return result;
}
QString CppParser::removeArgNames(const QString &args)
{
QString result = "";
@ -2328,3 +2624,8 @@ bool CppParser::isTypeStatement(StatementKind kind)
return false;
}
}
void CppParser::updateSerialId()
{
mSerialId = QString("%1 %2").arg(mParserId).arg(mSerialCount);
}

View File

@ -48,7 +48,7 @@ public:
void clearProjectFiles();
void addIncludePath(const QString& value);
void addProjectIncludePath(const QString& value);
void addFileToScan(const QString& value, bool inProject = false);
void addFileToScan(QString value, bool inProject = false);
QString prettyPrintStatement(PStatement statement, int line = -1);
void fillListOfFunctions(const QString& fileName,
const QString& phrase,
@ -97,6 +97,10 @@ public:
QStringList& params,
bool &isVoid);
signals:
void onProgress(const QString& fileName, int total, int current);
void onBusy();
void onStartParsing();
void onEndParsing(int total, int updateView);
private:
PStatement addInheritedStatement(
PStatement derived,
@ -133,7 +137,7 @@ private:
bool isDefinition,
bool isStatic);
void setInheritance(int index, PStatement classStatement, bool isStruct);
bool isInCurrentScopeLevel(const QString& command);
bool isCurrentScope(const QString& command);
void addSoloScopeLevel(PStatement statement, int line); // adds new solo level
void removeScopeLevel(int line); // removes level
int skipBraces(int startAt);
@ -164,6 +168,7 @@ private:
const QString& noNameArgs,
StatementKind kind,
PStatement scope);
StatementClassScope getClassScope(int index);
int getCurrentBlockBeginSkip();
int getCurrentBlockEndSkip();
int getCurrentInlineNamespaceEndSkip();
@ -200,9 +205,7 @@ private:
void handleStructs(bool isTypedef = false);
void handleUsing();
void handleVar();
void internalParse(
const QString& fileName,
bool manualUpdate = false);
void internalParse(const QString& fileName);
// function FindMacroDefine(const Command: AnsiString): PStatement;
void inheritClassStatement(
PStatement derived,
@ -270,17 +273,13 @@ private:
*/
bool isTypeStatement(StatementKind kind);
void onProgress(const QString& fileName, int total, int current);
void onBusy();
void onStartParsing();
void onEndParsing(int total, int updateView);
void updateSerialId();
private:
int mParserId;
int mSerialCount;
int mSerialId;
QString mSerialId;
int mUniqId;
bool mEnabled;
int mIndex;
@ -303,15 +302,15 @@ private:
CppTokenizer mTokenizer;
CppPreprocessor mPreprocessor;
//{ List of current compiler set's include path}
QStringList mIncludePaths;
QSet<QString> mIncludePaths;
//{ List of current project's include path }
QStringList mProjectIncludePaths;
QSet<QString> mProjectIncludePaths;
//{ List of current project's include path }
QSet<QString> mProjectFiles;
QVector<int> mBlockBeginSkips; //list of for/catch block begin token index;
QVector<int> mBlockEndSkips; //list of for/catch block end token index;
QVector<int> mInlineNamespaceEndSkips; // list for inline namespace end token index;
QStringList mFilesToScan; // list of base files to scan
QSet<QString> mFilesToScan; // list of base files to scan
int mFilesScannedCount; // count of files that have been scanned
int mFilesToScanCount; // count of files and files included in files that have to be scanned
bool mParseLocalHeaders;
@ -323,7 +322,7 @@ private:
QHash<QString,PStatementList> mNamespaces; //TStringList<String,List<Statement>> namespace and the statements in its scope
//fRemovedStatements: THashedStringList; //THashedStringList<String,PRemovedStatements>
QMutex mMutex;
QRecursiveMutex mMutex;
GetFileStreamCallBack mOnGetFileStream;
};

View File

@ -139,12 +139,12 @@ void CppPreprocessor::setScanOptions(bool parseSystem, bool parseLocal)
mParseLocal=parseLocal;
}
void CppPreprocessor::setIncludePaths(QStringList list)
void CppPreprocessor::setIncludePaths(QSet<QString> list)
{
mIncludePaths = list;
}
void CppPreprocessor::setProjectIncludePaths(QStringList list)
void CppPreprocessor::setProjectIncludePaths(QSet<QString> list)
{
mProjectIncludePaths = list;
}
@ -748,7 +748,7 @@ void CppPreprocessor::parseArgs(PDefine define)
if(args=="")
return ;
define->argList = args.split(',');
for (int i;i<define->argList.size();i++) {
for (int i=0;i<define->argList.size();i++) {
define->argList[i]=define->argList[i].trimmed();
}
QStringList tokens = tokenizeValue(define->value);
@ -1068,7 +1068,6 @@ QString CppPreprocessor::expandDefines(QString line)
while ((tail < line.length()) && isSpaceChar(line[tail]))
tail++; // skip spaces
int defineStart;
int defineEnd;
// Skip over its arguments
if ((tail < line.length()) && (line[tail]=='(')) {
@ -1088,7 +1087,7 @@ QString CppPreprocessor::expandDefines(QString line)
while ((tail < line.length()) && (isMacroIdentChar(line[tail]) || isDigit(line[tail])))
tail++;
}
name = line.mid(defineStart, defineEnd - defineStart);
name = line.mid(defineStart, tail - defineStart);
PDefine define = getDefine(name);
QString insertValue;
if (!define) {
@ -1211,6 +1210,7 @@ bool CppPreprocessor::evalTerm(const QString &expr, int &result, int &pos)
if (expr[pos]!=')')
return false;
pos++;
return true;
} else {
return evalNumber(expr,result,pos);
}
@ -1249,6 +1249,7 @@ bool CppPreprocessor::evalUnaryExpr(const QString &expr, int &result, int &pos)
} else {
return evalTerm(expr,result,pos);
}
return true;
}
/*
@ -1294,7 +1295,7 @@ bool CppPreprocessor::evalMulExpr(const QString &expr, int &result, int &pos)
*/
bool CppPreprocessor::evalAddExpr(const QString &expr, int &result, int &pos)
{
if (!evalAddExpr(expr,result,pos))
if (!evalMulExpr(expr,result,pos))
return false;
while (true) {
if (!skipSpaces(expr,pos))

View File

@ -42,8 +42,8 @@ public:
void reset(); //reset but don't clear generated defines
void resetDefines();
void setScanOptions(bool parseSystem, bool parseLocal);
void setIncludePaths(QStringList list);
void setProjectIncludePaths(QStringList list);
void setIncludePaths(QSet<QString> list);
void setProjectIncludePaths(QSet<QString> list);
void setScannedFileList(std::shared_ptr<QSet<QString>> list);
void setIncludesList(std::shared_ptr<QHash<QString,PFileIncludes>> list);
void preprocess(const QString& fileName, QStringList buffer = QStringList());
@ -159,8 +159,8 @@ private:
QHash<QString, PDefineMap> mFileDefines; //dictionary to save defines for each headerfile;
QList<PParsedFile> mIncludes; // stack of files we've stepped into. last one is current file, first one is source file
QList<bool> mBranchResults;// stack of branch results (boolean). last one is current branch, first one is outermost branch
QStringList mIncludePaths; // path to include folders
QStringList mProjectIncludePaths;
QSet<QString> mIncludePaths; // path to include folders
QSet<QString> mProjectIncludePaths;
bool mParseSystem;
bool mParseLocal;
std::shared_ptr<QSet<QString>> mScannedFiles;

View File

@ -256,7 +256,7 @@ void initParser()
}
QString getHeaderFileName(const QString &relativeTo, const QString &line,
const QStringList& includePaths, const QStringList& projectIncludePaths) {
const QSet<QString>& includePaths, const QSet<QString>& projectIncludePaths) {
QString result = "";
// Handle <>
@ -303,7 +303,7 @@ QString getLocalHeaderFileName(const QString &relativeTo, const QString &fileNam
return "";
}
QString getSystemHeaderFileName(const QString &fileName, const QStringList& includePaths)
QString getSystemHeaderFileName(const QString &fileName, const QSet<QString>& includePaths)
{
// Search compiler include directories
@ -316,7 +316,7 @@ QString getSystemHeaderFileName(const QString &fileName, const QStringList& incl
return "";
}
bool isSystemHeaderFile(const QString &fileName, const QStringList &includePaths)
bool isSystemHeaderFile(const QString &fileName, const QSet<QString> &includePaths)
{
if (includePaths.isEmpty())
return false;
@ -332,7 +332,7 @@ bool isSystemHeaderFile(const QString &fileName, const QStringList &includePaths
if (info.exists()) { // full file name
QDir dir = info.dir();
QString absPath = dir.absolutePath();
if (includePaths.indexOf(absPath)>=0)
if (includePaths.contains(absPath))
return true;
}
} else {

View File

@ -143,8 +143,8 @@ struct FileIncludes {
QString baseFile;
QMap<QString,bool> includeFiles; // true means the file is directly included, false means included indirectly
QSet<QString> usings; // namespaces it usings
StatementMap statements; // but we don't save temporary statements
StatementMap declaredStatements; // statements declared in this file
StatementMap statements; // but we don't save temporary statements (full name as key)
StatementMap declaredStatements; // statements declared in this file (full name as key)
QMap<int, PStatement> scopes; // int is start line of the statement scope
QSet<QString> dependingFiles; // The files I depeneds on
QSet<QString> dependedFiles; // the files depends on me
@ -163,12 +163,12 @@ extern QSet<QString> STLElementMethods;
void initParser();
QString getHeaderFileName(const QString& relativeTo, const QString& line,
const QStringList& includePaths, const QStringList& projectIncludePaths);
const QSet<QString>& includePaths, const QSet<QString>& projectIncludePaths);
QString getLocalHeaderFileName(const QString& relativeTo, const QString& fileName);
QString getSystemHeaderFileName(const QString& fileName, const QStringList& includePaths);
bool isSystemHeaderFile(const QString& fileName, const QStringList& includePaths);
QString getSystemHeaderFileName(const QString& fileName, const QSet<QString>& includePaths);
bool isSystemHeaderFile(const QString& fileName, const QSet<QString>& includePaths);
bool isHfile(const QString filename);
bool isCfile(const QString filename);
bool isKeyword(const QString& word);