work save

This commit is contained in:
Roy Qu 2022-11-01 23:23:21 +08:00
parent ebfb631452
commit ca59fd7d70
2 changed files with 146 additions and 420 deletions

View File

@ -1797,78 +1797,6 @@ bool CppParser::checkForUsing(KeywordType keywordType)
} }
bool CppParser::checkForVar()
{
int indexBackup=mIndex;
// Be pessimistic
bool result = false;
// Store old index
KeywordType keywordType;
// Use mIndex so we can reuse checking functions
if (mIndex + 1 < mTokenizer.tokenCount()) {
// Check the current and the next token
for (int i = 0; i<=1; i++) {
if (checkForKeyword(keywordType)
|| isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front())
|| (mTokenizer[mIndex]->text.back() == '.')
|| (
(mTokenizer[mIndex]->text.length() > 1) &&
(mTokenizer[mIndex]->text[mTokenizer[mIndex]->text.length() - 2] == '-') &&
(mTokenizer[mIndex]->text[mTokenizer[mIndex]->text.length() - 1] == '>'))
) {
// Reset index and fail
mIndex = indexBackup;
return false;
} // Could be a function pointer?
else if (mTokenizer[mIndex]->text == '(') {
int nextIndex = mTokenizer[mIndex]->matchIndex+1;
if ( (nextIndex >= mTokenizer.tokenCount())
|| (mTokenizer[nextIndex]->text != '(')
|| !mTokenizer[mIndex+1]->text.startsWith('*')) {
// Reset index and fail
mIndex = indexBackup;
return false;
} else {
nextIndex = mTokenizer[nextIndex]->matchIndex+1;
if (mTokenizer[mIndex]->text!=';') {
mIndex = indexBackup;
return false;
}
isFunctionPointer=true;
mIndex = indexBackup;
return true;
}
}
mIndex++;
}
}
// Fail if we do not find a comma or a semicolon or a ( (inline constructor)
while (mIndex < mTokenizer.tokenCount()) {
if (mTokenizer[mIndex]->text.front() == '#'
|| mTokenizer[mIndex]->text == '}'
|| checkForKeyword(keywordType)) {
break; // fail
} else if (mTokenizer[mIndex]->text.front() == ','
|| mTokenizer[mIndex]->text.front() == ';'
|| mTokenizer[mIndex]->text.front() == '{') {
result = true;
break;
}
//skip '(' ')'
if (mTokenizer[mIndex]->text=='(' || mTokenizer[mIndex]->text=='[')
mIndex=mTokenizer[mIndex]->matchIndex;
else
mIndex++;
}
// Revert to the point we started at
mIndex = indexBackup;
return result;
}
int CppParser::getCurrentBlockEndSkip() int CppParser::getCurrentBlockEndSkip()
{ {
if (mBlockEndSkips.isEmpty()) if (mBlockEndSkips.isEmpty())
@ -2826,8 +2754,8 @@ bool CppParser::handleStatement()
handleStructs(false); handleStructs(false);
} 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 (checkForVar()) { } else if (tryHandleVar()) {
handleVar(); //do nothing
} else } else
mIndex++; mIndex++;
@ -3199,81 +3127,78 @@ void CppParser::handleUsing()
} }
} }
void CppParser::handleVar() bool CppParser::tryHandleVar()
{ {
int indexBackup=mIndex; int indexBackup=mIndex;
// Keep going and stop on top of the variable name KeywordType keywordType;
QString lastType = ""; QString varType=mTokenizer[mIndex]->text;
bool isExtern = false; bool isExtern = false;
bool isStatic = false; bool isStatic = false;
bool varAdded = false; QString lastType;
if (isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front())
|| (mTokenizer[mIndex]->text.back() == '.')
|| (mTokenizer[mIndex]->text.back() == '>'))
//failed to handle
return false;
if (varType=="extern") {
lastType=varType;
isExtern=true;
} else if (varType=="static") {
lastType=varType;
isStatic=true;
}
mIndex++;
if (checkForKeyword(keywordType) //we only check the first token to reduce calculations
if (mIndex>=mTokenizer.tokenCount()
|| checkForKeyword(keywordType)
|| isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front()) || isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front())
|| (mTokenizer[mIndex]->text.back() == '.') || (mTokenizer[mIndex]->text.back() == '.')
|| ( || (mTokenizer[mIndex]->text.back() == '>')) {
(mTokenizer[mIndex]->text.length() > 1) && //failed to handle
(mTokenizer[mIndex]->text[mTokenizer[mIndex]->text.length() - 2] == '-') && mIndex=indexBackup;
(mTokenizer[mIndex]->text[mTokenizer[mIndex]->text.length() - 1] == '>')) return false;
) {
// Reset index and fail
mIndex = indexBackup;
return false;
if (!isFunctionPointer) {
while (true) {
if ((mIndex + 1 < mTokenizer.tokenCount())
&& (mTokenizer[mIndex + 1]->text=='('
|| mTokenizer[mIndex + 1]->text==','
|| mTokenizer[mIndex + 1]->text==';'
|| mTokenizer[mIndex + 1]->text.front()==':'
|| mTokenizer[mIndex + 1]->text=='}'
|| mTokenizer[mIndex + 1]->text.front()=='#'
|| mTokenizer[mIndex + 1]->text=='{')) {
break;
}
// struct/class/union is part of the type signature
// but we dont store it in the type cache, so must trim it to find the type info
if (mTokenizer[mIndex]->text!="struct"
&& mTokenizer[mIndex]->text!="class"
&& mTokenizer[mIndex]->text!="union") {
if (mTokenizer[mIndex]->text == ':') {
lastType += ':';
} else {
QString s=mTokenizer[mIndex]->text;
if (s == "extern") {
isExtern = true;
} else {
if (!s.isEmpty())
lastType += ' '+s;
if (s == "static")
isStatic = true;
}
}
}
mIndex++;
if(mIndex >= mTokenizer.tokenCount())
break;
}
lastType = lastType.trimmed();
} else {
QString s=mTokenizer[mIndex]->text;
if (s == "extern") {
isExtern = true;
} else if (s=="static") {
isStatic = true;
} else
lastType=s;
} }
// Don't bother entering the scanning loop when we have failed while (mIndex+1<mTokenizer.tokenCount()) {
if (mIndex >= mTokenizer.tokenCount()) if (mTokenizer[mIndex]->text=='('
return; && mTokenizer[mIndex]->matchIndex<=mTokenizer.tokenCount()
&& mTokenizer[mTokenizer[mIndex]->matchIndex]->text=='(') {
//function pointer
break;
} else if (mTokenizer[mIndex + 1]->text=='('
|| mTokenizer[mIndex + 1]->text==','
|| mTokenizer[mIndex + 1]->text==';'
|| mTokenizer[mIndex + 1]->text.front()==':'
|| mTokenizer[mIndex + 1]->text=='}'
|| mTokenizer[mIndex + 1]->text.front()=='#'
|| mTokenizer[mIndex + 1]->text=='{') {
//end of type info
break;
}
if (mTokenizer[mIndex]->text!="struct"
&& mTokenizer[mIndex]->text!="class"
&& mTokenizer[mIndex]->text!="union") {
QString s=mTokenizer[mIndex]->text;
if (s == "extern") {
isExtern = true;
} else if (s == "static") {
isStatic = true;
} else
lastType += ' '+s;
}
mIndex++;
}
// Find the variable name if (mIndex+1 >= mTokenizer.tokenCount() || lastType.isEmpty()
while (true) { || lastType.endsWith(':')) {
mIndex=indexBackup;
return false;
}
bool varAdded = false;
QString tempType;
while(true) {
// Skip bit identifiers, // Skip bit identifiers,
// e.g.: // e.g.:
// handle // handle
@ -3288,46 +3213,52 @@ void CppParser::handleVar()
)) ))
mIndex++; mIndex++;
} }
// Skip inline constructors, if (mTokenizer[mIndex]->text=='('
// e.g.: && mTokenizer[mIndex]->matchIndex+1<mTokenizer.tokenCount()
// handle && mTokenizer[mTokenizer[mIndex]->matchIndex+1]->text=='(') {
// int a(3) //function pointer
// as QString cmd=mTokenizer[mIndex]->text;
// int a int argStart=mTokenizer[mIndex]->matchIndex+1;
if (!isFunctionPointer && int argEnd=mTokenizer[argStart]->matchIndex;
mIndex < mTokenizer.tokenCount() && if (cmd.startsWith('*'))
mTokenizer[mIndex]->text == '(') { cmd=cmd.mid(1);
mIndex=mTokenizer[mIndex]->matchIndex+1; if (!cmd.isEmpty()) {
} addChildStatement(
getCurrentScope(),
// Did we stop on top of the variable name? mCurrentFile,
if (mIndex < mTokenizer.tokenCount()) { lastType,
if (mTokenizer[mIndex]->text.front()!=',' cmd,
&& mTokenizer[mIndex]->text.front()!=';') { mergeArgs(argStart,argEnd),
QString cmd; "",
"",
mTokenizer[mIndex]->line,
StatementKind::skVariable,
getScope(),
mClassScope,
//True,
!isExtern,
isStatic); // TODO: not supported to pass list
varAdded = true;
tempType="";
}
mIndex=argEnd+1;
} else if (isWordChar(mTokenizer[mIndex]->text[0])) {
QString cmd=mTokenizer[mIndex]->text;
while (cmd.startsWith('*')) {
cmd=cmd.mid(1);
}
if (cmd=="const") {
tempType=mTokenizer[mIndex]->text;
} else {
QString suffix;
QString args; QString args;
if (isFunctionPointer) { cmd=mTokenizer[mIndex]->text;
QString s = mTokenizer[mIndex+1]->text; parseCommandTypeAndArgs(cmd,suffix,args);
cmd = s.mid(1); // (*foo) -> foo if (!cmd.isEmpty()) {
//TODO: parse args
args = mTokenizer[mIndex + 1]->text; // (int a,int b)
lastType += "(*)" + args; // void(int a,int b)
mIndex++;
} else if (mTokenizer[mIndex]->text.back() == ']') { //array; break args
int pos = mTokenizer[mIndex]->text.indexOf('[');
cmd = mTokenizer[mIndex]->text.mid(0,pos);
args = mTokenizer[mIndex]->text.mid(pos);
} else {
cmd = mTokenizer[mIndex]->text;
args = "";
}
// Add a statement for every struct we are in
if (!lastType.isEmpty()) {
addChildStatement( addChildStatement(
getCurrentScope(), getCurrentScope(),
mCurrentFile, mCurrentFile,
lastType, (lastType+' '+tempType+suffix).trimmed(),
cmd, cmd,
args, args,
"", "",
@ -3340,32 +3271,25 @@ void CppParser::handleVar()
!isExtern, !isExtern,
isStatic); // TODO: not supported to pass list isStatic); // TODO: not supported to pass list
varAdded = true; varAdded = true;
tempType="";
} }
} }
mIndex++;
// Step over the variable name } else if (mTokenizer[mIndex]->text==';') {
if (isblockChar(mTokenizer[mIndex]->text.front())) { break;
break; } else if (mTokenizer[mIndex]->text=='(') {
} mIndex=mTokenizer[mIndex]->matchIndex+1;
} else if (mTokenizer[mIndex]->text=='{') {
mIndex=mTokenizer[mIndex]->matchIndex+1;
} else {
tempType="";
mIndex++; mIndex++;
} }
if (mIndex >= mTokenizer.tokenCount())
break;
if (isblockChar(mTokenizer[mIndex]->text.front()))
break;
} }
if (varAdded && (mIndex < mTokenizer.tokenCount()) // Skip ;
&& (mTokenizer[mIndex]->text == '{')) { mIndex++;
// skip { } like A x {new A};
int i=indexOfMatchingBrace(mIndex); return true;
if (i!=mIndex)
mIndex = i+1;
}
// Skip ; and ,
if ( (mIndex < mTokenizer.tokenCount()) &&
(mTokenizer[mIndex]->text.front() == ';'
|| mTokenizer[mIndex]->text.front() == ','))
mIndex++;
} }
void CppParser::internalParse(const QString &fileName) void CppParser::internalParse(const QString &fileName)
@ -4436,236 +4360,39 @@ int CppParser::calcKeyLenForStruct(const QString &word)
void CppParser::scanMethodArgs(const PStatement& functionStatement, int argStart, int argEnd) void CppParser::scanMethodArgs(const PStatement& functionStatement, int argStart, int argEnd)
{ {
// Split up argument string by , int paramStart = argStart+1;
int i = argStart+1; // assume it starts with ( and ends with ) int i = paramStart ; // assume it starts with ( and ends with )
int paramStart = i;
// Keep going and stop on top of the variable name // Keep going and stop on top of the variable name
QString lastType = ""; QString varType = "";
bool isFunctionPointer = false;
bool varAdded = false;
while (i < argEnd) { while (i < argEnd) {
if ((argStr[i] == ',') || if (mTokenizer[i]->text=='('
((i == argStr.length()-1) && (argStr[i] == ')'))) { && mTokenizer[i]->matchIndex+1<argEnd
// We've found "int* a" for example && mTokenizer[mTokenizer[i]->matchIndex+1]->text=='(') {
QString s = argStr.mid(paramStart,i-paramStart); //function pointer
int argStart=mTokenizer[i]->matchIndex+1;
int argEnd=mTokenizer[argStart]->matchIndex;
i=
} else if (mTokenizer[i]->text=='{') {
i=mTokenizer[i]->matchIndex+1;
} else if (mTokenizer[i]->text=='(') {
i=mTokenizer[i]->matchIndex+1;
} else if (isWordChar(mTokenizer[i]->text[0])) {
if (varType.isEmpty()) {
//remove default value } else if
int assignPos = s.indexOf('='); QString cmd=mTokenizer[i]->text;
if (assignPos >= 0) { if () {
s.truncate(assignPos); QString args,suffix;
s = s.trimmed(); parseCommandTypeAndArgs(cmd,suffix,args);
} if (!cmd.isEmpty()) {
//todo: we don't support function pointer parameters now, till we can tokenize function parameters PStatement statement=findStatementOf(mCurrentFile,cmd,functionStatement,true);
if (!statement || !isTypeStatement(statement->kind)) {
//skip [] }
int varEndPos = s.length()-1;
int bracketLevel = 0;
while (varEndPos>=0) {
switch(s[varEndPos].unicode()) {
case ']':
bracketLevel++;
break;
case '[':
bracketLevel--;
varEndPos--;
break;
}
if (bracketLevel==0)
break;
varEndPos--;
}
int varStartPos = varEndPos;
if (varEndPos>=0) {
while (varStartPos-1>=0) {
if (!mTokenizer.isIdentChar(s[varStartPos-1]))
break;
varStartPos--;
} }
} }
if (varStartPos>=0) {
if (varEndPos+1<s.length())
args=s.mid(varEndPos+1);
addStatement(
functionStatement,
mCurrentFile,
s.mid(0,varStartPos), // 'int*'
s.mid(varStartPos,varEndPos-varStartPos+1), // a
args,
"",
functionStatement->definitionLine,
StatementKind::skParameter,
StatementScope::Local,
StatementClassScope::None,
true,
false);
}
if (varStartPos<s.length()) {
args = "";
int bracketPos = s.indexOf('[');
if (bracketPos >= 0) {
args = s.mid(bracketPos);
s.truncate(bracketPos);
}
}
paramStart = i + 1; // step over ,
} }
i++;
} }
while (true) {
if ((mIndex + 2 < mTokenizer.tokenCount())
&& (mTokenizer[mIndex + 1]->text.front() == '(')
&& (mTokenizer[mIndex + 2]->text.front() == '(')) {
isFunctionPointer = mTokenizer[mIndex + 1]->text.indexOf('*') >= 0;
if (!isFunctionPointer)
break; // inline constructor
} else if ((mIndex + 1 < mTokenizer.tokenCount())
&& (mTokenizer[mIndex + 1]->text.front()=='('
|| mTokenizer[mIndex + 1]->text.front()==','
|| mTokenizer[mIndex + 1]->text.front()==';'
|| mTokenizer[mIndex + 1]->text.front()==':'
|| mTokenizer[mIndex + 1]->text.front()=='}'
|| mTokenizer[mIndex + 1]->text.front()=='#'
|| mTokenizer[mIndex + 1]->text.front()=='{')) {
break;
}
// we've made a mistake, this is a typedef , not a variable definition.
if (mTokenizer[mIndex]->text == "typedef")
return;
// struct/class/union is part of the type signature
// but we dont store it in the type cache, so must trim it to find the type info
if (mTokenizer[mIndex]->text!="struct"
&& mTokenizer[mIndex]->text!="class"
&& mTokenizer[mIndex]->text!="union") {
if (mTokenizer[mIndex]->text == ':') {
lastType += ':';
} else {
QString s=mTokenizer[mIndex]->text;
if (s == "extern") {
isExtern = true;
} else {
if (!s.isEmpty())
lastType += ' '+s;
if (s == "static")
isStatic = true;
}
}
}
mIndex++;
if(mIndex >= mTokenizer.tokenCount())
break;
if (isFunctionPointer)
break;
}
lastType = lastType.trimmed();
// Don't bother entering the scanning loop when we have failed
if (mIndex >= mTokenizer.tokenCount())
return;
// Find the variable name
while (true) {
// Skip bit identifiers,
// e.g.:
// handle
// unsigned short bAppReturnCode:8,reserved:6,fBusy:1,fAck:1
// as
// unsigned short bAppReturnCode,reserved,fBusy,fAck
if ( (mIndex < mTokenizer.tokenCount()) && (mTokenizer[mIndex]->text.front() == ':')) {
while ( (mIndex < mTokenizer.tokenCount())
&& !(
mTokenizer[mIndex]->text.front() == ','
|| isblockChar(';')
))
mIndex++;
}
// Skip inline constructors,
// e.g.:
// handle
// int a(3)
// as
// int a
if (!isFunctionPointer &&
mIndex < mTokenizer.tokenCount() &&
mTokenizer[mIndex]->text.front() == '(') {
while ((mIndex < mTokenizer.tokenCount())
&& !(
mTokenizer[mIndex]->text.front() == ','
|| isblockChar(mTokenizer[mIndex]->text.front())
))
mIndex++;
}
// Did we stop on top of the variable name?
if (mIndex < mTokenizer.tokenCount()) {
if (mTokenizer[mIndex]->text.front()!=','
&& mTokenizer[mIndex]->text.front()!=';') {
QString cmd;
QString args;
if (isFunctionPointer && (mIndex + 1 < mTokenizer.tokenCount())) {
QString s = mTokenizer[mIndex]->text;
cmd = s.mid(2,s.length()-3).trimmed(); // (*foo) -> foo
args = mTokenizer[mIndex + 1]->text; // (int a,int b)
lastType += "(*)" + args; // void(int a,int b)
mIndex++;
} else if (mTokenizer[mIndex]->text.back() == ']') { //array; break args
int pos = mTokenizer[mIndex]->text.indexOf('[');
cmd = mTokenizer[mIndex]->text.mid(0,pos);
args = mTokenizer[mIndex]->text.mid(pos);
} else {
cmd = mTokenizer[mIndex]->text;
args = "";
}
// Add a statement for every struct we are in
if (!lastType.isEmpty()) {
addChildStatement(
getCurrentScope(),
mCurrentFile,
lastType,
cmd,
args,
"",
"",
mTokenizer[mIndex]->line,
StatementKind::skVariable,
getScope(),
mClassScope,
//True,
!isExtern,
isStatic); // TODO: not supported to pass list
varAdded = true;
}
}
// Step over the variable name
if (isblockChar(mTokenizer[mIndex]->text.front())) {
break;
}
mIndex++;
}
if (mIndex >= mTokenizer.tokenCount())
break;
if (isblockChar(mTokenizer[mIndex]->text.front()))
break;
}
if (varAdded && (mIndex < mTokenizer.tokenCount())
&& (mTokenizer[mIndex]->text == '{')) {
// skip { } like A x {new A};
int i=indexOfMatchingBrace(mIndex);
if (i!=mIndex)
mIndex = i+1;
}
// Skip ; and ,
if ( (mIndex < mTokenizer.tokenCount()) &&
(mTokenizer[mIndex]->text.front() == ';'
|| mTokenizer[mIndex]->text.front() == ','))
mIndex++;
} }

View File

@ -220,7 +220,6 @@ private:
bool checkForTypedefEnum(); bool checkForTypedefEnum();
bool checkForTypedefStruct(); bool checkForTypedefStruct();
bool checkForUsing(KeywordType keywordType); bool checkForUsing(KeywordType keywordType);
bool checkForVar();
void fillListOfFunctions(const QString& fileName, int line, void fillListOfFunctions(const QString& fileName, int line,
const PStatement& statement, const PStatement& statement,
@ -414,7 +413,7 @@ private:
bool handleStatement(); bool handleStatement();
void handleStructs(bool isTypedef = false); void handleStructs(bool isTypedef = false);
void handleUsing(); void handleUsing();
void handleVar(); bool tryHandleVar();
void internalParse(const QString& fileName); void internalParse(const QString& fileName);
// function FindMacroDefine(const Command: AnsiString): PStatement; // function FindMacroDefine(const Command: AnsiString): PStatement;
void inheritClassStatement( void inheritClassStatement(