- improve template parameters checker

- streamline cppparser
This commit is contained in:
Roy Qu 2022-11-05 08:42:54 +08:00
parent ef79640eb0
commit 8d9740dd57
4 changed files with 64 additions and 58 deletions

View File

@ -1,8 +1,8 @@
Red Panda C++ Version 2.2 Red Panda C++ Version 2.2
- enhancement: basic code completion support for C++ lambda - enhancement: basic code completion support for C++ lambdas
- enhancement: slightly reduce parsing time - enhancement: slightly reduce parsing time
- fix: Wrong charset name returned when saveing file - fix: Wrong charset name returned when saving file
- fix: 'using =' / 'namespace =' not correctly handled - fix: 'using =' / 'namespace =' not correctly handled
- fix: Pressing '*' at begin of line will crash app - fix: Pressing '*' at begin of line will crash app

View File

@ -957,7 +957,6 @@ void CppParser::resetParser()
mCurrentScope.clear(); mCurrentScope.clear();
mCurrentClassScope.clear(); mCurrentClassScope.clear();
mSkipList.clear();
mStatementList.clear(); mStatementList.clear();
mProjectFiles.clear(); mProjectFiles.clear();
@ -1460,7 +1459,8 @@ void CppParser::removeScopeLevel(int line)
// qDebug()<<"--remove scope"<<mCurrentFile<<line<<mCurrentClassScope.count(); // qDebug()<<"--remove scope"<<mCurrentFile<<line<<mCurrentClassScope.count();
PStatement currentScope = getCurrentScope(); PStatement currentScope = getCurrentScope();
PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile); PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile);
if (currentScope && (currentScope->kind == StatementKind::skBlock)) { if (currentScope) {
if (currentScope->kind == StatementKind::skBlock) {
if (currentScope->children.isEmpty()) { if (currentScope->children.isEmpty()) {
// remove no children block // remove no children block
if (fileIncludes) { if (fileIncludes) {
@ -1470,6 +1470,9 @@ void CppParser::removeScopeLevel(int line)
} else { } else {
fileIncludes->statements.insert(currentScope->fullName,currentScope); fileIncludes->statements.insert(currentScope->fullName,currentScope);
} }
} else if (currentScope->kind == StatementKind::skClass) {
mIndex=indexOfNextSemicolon(mIndex);
}
} }
mCurrentScope.pop_back(); mCurrentScope.pop_back();
mCurrentClassScope.pop_back(); mCurrentClassScope.pop_back();
@ -1494,7 +1497,6 @@ void CppParser::internalClear()
mCurrentClassScope.clear(); mCurrentClassScope.clear();
mIndex = 0; mIndex = 0;
mClassScope = StatementClassScope::None; mClassScope = StatementClassScope::None;
mSkipList.clear();
mBlockBeginSkips.clear(); mBlockBeginSkips.clear();
mBlockEndSkips.clear(); mBlockEndSkips.clear();
mInlineNamespaceEndSkips.clear(); mInlineNamespaceEndSkips.clear();
@ -1729,14 +1731,6 @@ bool CppParser::checkForScope(KeywordType keywordType)
); );
} }
void CppParser::checkForSkipStatement()
{
if ((mSkipList.count()>0) && (mIndex == mSkipList.back())) { // skip to next ';'
skipNextSemicolon(mIndex);
mSkipList.pop_back();
}
}
bool CppParser::checkForStructs(KeywordType keywordType) bool CppParser::checkForStructs(KeywordType keywordType)
{ {
int dis = 0; int dis = 0;
@ -2181,7 +2175,7 @@ void CppParser::handleCatchBlock()
true, true,
false); false);
addSoloScopeLevel(block,startLine); addSoloScopeLevel(block,startLine);
scanMethodArgs(block,mIndex, mTokenizer[mIndex]->matchIndex); scanMethodArgs(block,mIndex);
mIndex=mTokenizer[mIndex]->matchIndex+1; mIndex=mTokenizer[mIndex]->matchIndex+1;
} }
@ -2450,8 +2444,9 @@ void CppParser::handleKeyword(KeywordType skipType)
void CppParser::handleLambda(int index) void CppParser::handleLambda(int index)
{ {
Q_ASSERT(mTokenizer[index]->text.startsWith('[')); Q_ASSERT(mTokenizer[index]->text.startsWith('['));
Q_ASSERT(mTokenizer[index+1]->text.startsWith('('));
int startLine=mTokenizer[index]->line; int startLine=mTokenizer[index]->line;
int argStart=index; int argStart=index+1;
int argEnd= mTokenizer[argStart]->matchIndex; int argEnd= mTokenizer[argStart]->matchIndex;
int blockLine=mTokenizer[argStart]->line; int blockLine=mTokenizer[argStart]->line;
//TODO: parse captures //TODO: parse captures
@ -2473,7 +2468,7 @@ void CppParser::handleLambda(int index)
StatementClassScope::None, StatementClassScope::None,
true, true,
false); false);
scanMethodArgs(lambdaBlock,argStart,argEnd); scanMethodArgs(lambdaBlock,argStart);
addSoloScopeLevel(lambdaBlock,blockLine); addSoloScopeLevel(lambdaBlock,blockLine);
} }
@ -2536,7 +2531,6 @@ void CppParser::handleMethod(StatementKind functionKind,const QString &sType, co
scopeStatement->friends.insert(scopelessName); scopeStatement->friends.insert(scopelessName);
} else if (isValid) { } else if (isValid) {
// Use the class the function belongs to as the parent ID if the function is declared outside of the class body // Use the class the function belongs to as the parent ID if the function is declared outside of the class body
int delimPos = sName.lastIndexOf("::");
QString scopelessName; QString scopelessName;
QString parentClassName; QString parentClassName;
if (splitLastMember(sName,scopelessName,parentClassName)) { if (splitLastMember(sName,scopelessName,parentClassName)) {
@ -2563,7 +2557,7 @@ void CppParser::handleMethod(StatementKind functionKind,const QString &sType, co
mClassScope, mClassScope,
true, true,
isStatic); isStatic);
scanMethodArgs(functionStatement, argStart,argEnd); scanMethodArgs(functionStatement, argStart);
// add variable this to the class function // add variable this to the class function
if (scopeStatement && scopeStatement->kind == StatementKind::skClass && if (scopeStatement && scopeStatement->kind == StatementKind::skClass &&
!isStatic) { !isStatic) {
@ -3031,10 +3025,10 @@ bool CppParser::handleStatement()
} }
Q_ASSERT(mIndex<999999); Q_ASSERT(mIndex<999999);
while (mTokenizer.lambdasCount()>0 && mTokenizer.indexOfFirstLambda()<mIndex) { // while (mTokenizer.lambdasCount()>0 && mTokenizer.indexOfFirstLambda()<mIndex) {
handleLambda(mTokenizer.indexOfFirstLambda()); // handleLambda(mTokenizer.indexOfFirstLambda());
mTokenizer.removeFirstLambda(); // mTokenizer.removeFirstLambda();
} // }
// else if (checkForMethod(funcType, funcName, argStart,argEnd, isStatic, isFriend)) { // else if (checkForMethod(funcType, funcName, argStart,argEnd, isStatic, isFriend)) {
// handleMethod(funcType, funcName, argStart, argEnd, isStatic, isFriend); // don't recalculate parts // handleMethod(funcType, funcName, argStart, argEnd, isStatic, isFriend); // don't recalculate parts
// } else if (tryHandleVar()) { // } else if (tryHandleVar()) {
@ -3043,7 +3037,7 @@ bool CppParser::handleStatement()
// mIndex++; // mIndex++;
//todo: remove mSkipList (we can check '}''s statement type instead) //todo: remove mSkipList (we can check '}''s statement type instead)
checkForSkipStatement(); // checkForSkipStatement();
return mIndex < mTokenizer.tokenCount(); return mIndex < mTokenizer.tokenCount();
@ -3210,7 +3204,6 @@ void CppParser::handleStructs(bool isTypedef)
mTokenizer[i + 1]->text.front() == ';' mTokenizer[i + 1]->text.front() == ';'
|| mTokenizer[i + 1]->text.front() == '}')) { || mTokenizer[i + 1]->text.front() == '}')) {
// When encountering names again after struct body scanning, skip it // When encountering names again after struct body scanning, skip it
mSkipList.append(i+1); // add first name to skip statement so that we can skip it until the next ;
QString command = ""; QString command = "";
QString args = ""; QString args = "";
@ -3599,7 +3592,7 @@ void CppParser::internalParse(const QString &fileName)
QStringList preprocessResult = mPreprocessor.result(); QStringList preprocessResult = mPreprocessor.result();
#ifdef QT_DEBUG #ifdef QT_DEBUG
stringsToFile(mPreprocessor.result(),QString("r:\\preprocess-%1.txt").arg(extractFileName(fileName))); // stringsToFile(mPreprocessor.result(),QString("r:\\preprocess-%1.txt").arg(extractFileName(fileName)));
// mPreprocessor.dumpDefinesTo("r:\\defines.txt"); // mPreprocessor.dumpDefinesTo("r:\\defines.txt");
// mPreprocessor.dumpIncludesListTo("r:\\includes.txt"); // mPreprocessor.dumpIncludesListTo("r:\\includes.txt");
#endif #endif
@ -3613,7 +3606,7 @@ void CppParser::internalParse(const QString &fileName)
if (mTokenizer.tokenCount() == 0) if (mTokenizer.tokenCount() == 0)
return; return;
#ifdef QT_DEBUG #ifdef QT_DEBUG
mTokenizer.dumpTokens(QString("r:\\tokens-%1.txt").arg(extractFileName(fileName))); // mTokenizer.dumpTokens(QString("r:\\tokens-%1.txt").arg(extractFileName(fileName)));
#endif #endif
// Process the token list // Process the token list
while(true) { while(true) {
@ -3621,8 +3614,8 @@ void CppParser::internalParse(const QString &fileName)
break; break;
} }
#ifdef QT_DEBUG #ifdef QT_DEBUG
mStatementList.dumpAll(QString("r:\\all-stats-%1.txt").arg(extractFileName(fileName))); // mStatementList.dumpAll(QString("r:\\all-stats-%1.txt").arg(extractFileName(fileName)));
mStatementList.dump(QString("r:\\stats-%1.txt").arg(extractFileName(fileName))); // mStatementList.dump(QString("r:\\stats-%1.txt").arg(extractFileName(fileName)));
#endif #endif
//reduce memory usage //reduce memory usage
internalClear(); internalClear();
@ -4637,8 +4630,10 @@ int CppParser::calcKeyLenForStruct(const QString &word)
return -1; return -1;
} }
void CppParser::scanMethodArgs(const PStatement& functionStatement, int argStart, int argEnd) void CppParser::scanMethodArgs(const PStatement& functionStatement, int argStart)
{ {
Q_ASSERT(mTokenizer[argStart]->text=='(');
int argEnd=mTokenizer[argStart]->matchIndex;
int paramStart = argStart+1; int paramStart = argStart+1;
int i = paramStart ; // assume it starts with ( and ends with ) int i = paramStart ; // assume it starts with ( and ends with )
// Keep going and stop on top of the variable name // Keep going and stop on top of the variable name

View File

@ -216,7 +216,6 @@ private:
bool checkForPreprocessor(); bool checkForPreprocessor();
// bool checkForLambda(); // bool checkForLambda();
bool checkForScope(KeywordType keywordType); bool checkForScope(KeywordType keywordType);
void checkForSkipStatement();
bool checkForStructs(KeywordType keywordType); bool checkForStructs(KeywordType keywordType);
bool checkForTypedefEnum(); bool checkForTypedefEnum();
bool checkForTypedefStruct(); bool checkForTypedefStruct();
@ -451,8 +450,7 @@ private:
// } // }
void scanMethodArgs( void scanMethodArgs(
const PStatement& functionStatement, const PStatement& functionStatement,
int argStart, int argStart);
int argEnd);
QString splitPhrase(const QString& phrase, QString& sClazz, QString splitPhrase(const QString& phrase, QString& sClazz,
QString& sOperator, QString &sMember); QString& sOperator, QString &sMember);
QString removeTemplateParams(const QString& phrase); QString removeTemplateParams(const QString& phrase);
@ -608,9 +606,6 @@ private:
QVector<PStatement> mCurrentScope; QVector<PStatement> mCurrentScope;
QVector<StatementClassScope> mCurrentClassScope; QVector<StatementClassScope> mCurrentClassScope;
// the start index in tokens to skip to ; when parsing typedef struct we need to skip
// the names after the closing bracket because we have processed it
QVector<int> mSkipList; // TList<Integer>
StatementClassScope mClassScope; StatementClassScope mClassScope;
StatementModel mStatementList; StatementModel mStatementList;
//It's used in preprocessor, so we can't use fIncludeList instead //It's used in preprocessor, so we can't use fIncludeList instead

View File

@ -113,7 +113,9 @@ void CppTokenizer::addToken(const QString &sText, int iLine, TokenType tokenType
PToken token = std::make_shared<Token>(); PToken token = std::make_shared<Token>();
token->text = sText; token->text = sText;
token->line = iLine; token->line = iLine;
#ifdef Q_DEBUG
token->matchIndex = 1000000000; token->matchIndex = 1000000000;
#endif
switch(tokenType) { switch(tokenType) {
case TokenType::LeftBrace: case TokenType::LeftBrace:
token->matchIndex=-1; token->matchIndex=-1;
@ -573,16 +575,16 @@ void CppTokenizer::skipDoubleQuotes()
} }
} }
void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, bool keepLambda) void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd)
{ {
mCurrent++; mCurrent++;
while (*mCurrent != 0) { while (*mCurrent != 0) {
if (*mCurrent == '(') { if (*mCurrent == '(') {
skipPair('(', ')',keepLambda); skipPair('(', ')');
} else if (*mCurrent == '[') { } else if (*mCurrent == '[') {
skipPair('[', ']',keepLambda); skipPair('[', ']');
} else if (*mCurrent == '{') { } else if (*mCurrent == '{') {
skipPair('{', '}',keepLambda); skipPair('{', '}');
} else if (*mCurrent == cStart) { } else if (*mCurrent == cStart) {
skipPair(cStart, cEnd); skipPair(cStart, cEnd);
} else if (*mCurrent == cEnd) { } else if (*mCurrent == cEnd) {
@ -603,8 +605,6 @@ void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, bool keepLamb
skipSingleQuote(); // don't do it inside AnsiString! skipSingleQuote(); // don't do it inside AnsiString!
else else
mCurrent++; mCurrent++;
} else if (failChars.contains(*mCurrent)) {
break;
} else { } else {
mCurrent++; mCurrent++;
} }
@ -614,26 +614,40 @@ void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, bool keepLamb
bool CppTokenizer::skipAngleBracketPair() bool CppTokenizer::skipAngleBracketPair()
{ {
QChar* backup=mCurrent; QChar* backup=mCurrent;
int level=0; QVector<QChar> stack;
while (*mCurrent != '\0') { while (*mCurrent != '\0') {
switch((*mCurrent).unicode()) { switch((*mCurrent).unicode()) {
case '<': case '<':
case '(': case '(':
case '[': case '[':
level++; stack.push_back(*mCurrent);
break; break;
case ')': case ')':
case ']': while (!stack.isEmpty() && stack.back()!='(') {
level--; stack.pop_back();
if (level==0) { }
//pop up '('
if (stack.isEmpty()) {
mCurrent=backup; mCurrent=backup;
return false; return false;
} }
stack.pop_back();
break;
case ']':
while (!stack.isEmpty() && stack.back()!='[')
stack.pop_back();
//pop up '['
if (stack.isEmpty()) {
mCurrent=backup;
return false;
}
stack.pop_back();
break; break;
case '>': case '>':
level--; if (stack.back()=='<')
if (level==0) { stack.pop_back();
mCurrent++; //skip over > if (stack.isEmpty()) {
mCurrent++;
return true; return true;
} }
break; break;
@ -766,9 +780,11 @@ void CppTokenizer::removeFirstLambda()
void CppTokenizer::advance() void CppTokenizer::advance()
{ {
switch(mCurrent->unicode()) { switch(mCurrent->unicode()) {
case '\"': skipDoubleQuotes(); case '\"':
skipDoubleQuotes();
break; break;
case '\'': skipSingleQuote(); case '\'':
skipSingleQuote();
break; break;
case '/': case '/':
if (*(mCurrent + 1) == '=') if (*(mCurrent + 1) == '=')