- fix: Dummy struct/enum symbols shouldn't be shown in the completion suggestion.

- enhancement: Support optional enum name.
  - enhancement: Support optional enum type.
  - enhancement: Support simple const expression evaluation for enum values.
  - fix: Accessibilty for inherited members are not correct calculated in multiple inheritance.
  - fix: Can't handle full class name when handle inheritance.
This commit is contained in:
Roy Qu 2023-08-07 14:23:57 +08:00
parent dd724e64c2
commit 6a06b5b3d6
7 changed files with 359 additions and 127 deletions

View File

@ -10,6 +10,12 @@ Red Panda C++ Version 2.24
- enhancement: Press left/right arrow will move caret to the begin/end of the selection. - enhancement: Press left/right arrow will move caret to the begin/end of the selection.
- enhancement: Press up/down arrow will move caret up/down from the begin/end of the selection. - enhancement: Press up/down arrow will move caret up/down from the begin/end of the selection.
- enhancement: Show progress dialog if the time for searching compilers is too long. - enhancement: Show progress dialog if the time for searching compilers is too long.
- fix: Dummy struct/enum symbols shouldn't be shown in the completion suggestion.
- enhancement: Support optional enum name.
- enhancement: Support optional enum type.
- enhancement: Support simple const expression evaluation for enum values.
- fix: Accessibilty for inherited members are not correct calculated in multiple inheritance.
- fix: Can't handle full class name when handle inheritance.
Red Panda C++ Version 2.23 Red Panda C++ Version 2.23
@ -1054,7 +1060,7 @@ Red Panda C++ Version 0.14.0
- enhancement: show custom icon set folder in options -> enviroment -> folders - enhancement: show custom icon set folder in options -> enviroment -> folders
- enhancement: new class ( to project) wizard - enhancement: new class ( to project) wizard
- enhancement: greatly speed up code completion - enhancement: greatly speed up code completion
- fix: code folding calcuation not correct when some codes are folded and editing after them - fix: code folding calculation not correct when some codes are folded and editing after them
- enhancement: code completion ui redesigned - enhancement: code completion ui redesigned
- fix: mainwindow action's short cut doesn't work, if the action is not in menu or toolbar - fix: mainwindow action's short cut doesn't work, if the action is not in menu or toolbar
- fix: when run all cases for a problem, processing of output is slow - fix: when run all cases for a problem, processing of output is slow

View File

@ -4018,28 +4018,6 @@ QString Editor::getParserHint(const QStringList& expression,const QString &/*s*/
if (statement->kind == StatementKind::skFunction if (statement->kind == StatementKind::skFunction
|| statement->kind == StatementKind::skConstructor || statement->kind == StatementKind::skConstructor
|| statement->kind == StatementKind::skDestructor) { || statement->kind == StatementKind::skDestructor) {
//PStatement parentScope = statement->parentScope.lock();
// if (parentScope && parentScope->kind == StatementKind::skNamespace) {
// PStatementList namespaceStatementsList =
// mParser->findNamespace(parentScope->command);
// if (namespaceStatementsList) {
// int counts=0;
// foreach (const PStatement& namespaceStatement, *namespaceStatementsList) {
// QString hint = getHintForFunction(statement,namespaceStatement,
// mFilename,line);
// if (!hint.isEmpty()) {
// counts++;
// if (!result.isEmpty())
// result += "\n";
// if (counts>4) {
// result += "...";
// break;
// }
// result += hint;
// }
// }
// }
// } else
result = getHintForFunction(statement,mFilename,line); result = getHintForFunction(statement,mFilename,line);
} else if (statement->line>0) { } else if (statement->line>0) {
QFileInfo fileInfo(statement->fileName); QFileInfo fileInfo(statement->fileName);

View File

@ -266,7 +266,9 @@ PStatement CppParser::doFindStatement(const QString &fullname) const
return PStatement(); return PStatement();
PStatement parentStatement; PStatement parentStatement;
PStatement statement; PStatement statement;
foreach (const QString& phrase, phrases) {
for (int i=(phrases[0].isEmpty()?1:0);i<phrases.count();i++) {
const QString& phrase=phrases[i];
if (parentStatement && parentStatement->kind == StatementKind::skNamespace) { if (parentStatement && parentStatement->kind == StatementKind::skNamespace) {
PStatementList lst = doFindNamespace(parentStatement->fullName); PStatementList lst = doFindNamespace(parentStatement->fullName);
foreach (const PStatement& namespaceStatement, *lst) { foreach (const PStatement& namespaceStatement, *lst) {
@ -1143,7 +1145,13 @@ QString CppParser::prettyPrintStatement(const PStatement& statement, const QStri
result = "enum "+statement->command; result = "enum "+statement->command;
break; break;
case StatementKind::skEnum: case StatementKind::skEnum:
result = statement->type + "::" + statement->command; if (!statement->type.isEmpty())
result = statement->type + "::";
else
result = "";
result += statement->command;
if (!statement->value.isEmpty())
result += "(" + statement->value + ")";
break; break;
case StatementKind::skTypedef: case StatementKind::skTypedef:
result = "typedef "+statement->type+" "+statement->command; result = "typedef "+statement->type+" "+statement->command;
@ -1518,25 +1526,53 @@ void CppParser::setInheritance(int index, const PStatement& classStatement, bool
//skip to matching ')' //skip to matching ')'
index=mTokenizer[index]->matchIndex; index=mTokenizer[index]->matchIndex;
} else if (inheritScopeType == StatementAccessibility::None) { } else if (inheritScopeType == StatementAccessibility::None) {
if (currentText !=',' if (currentText=="::"
&& currentText!=':') { || isIdentChar(currentText[0])) {
QString basename = currentText; QString basename = currentText;
bool isGlobal = false;
index++;
if (basename=="::") {
if (index>=tokenCount || !isIdentChar(mTokenizer[index]->text[0])) {
return;
}
isGlobal=true;
basename=mTokenizer[index]->text;
index++;
}
//remove template staff //remove template staff
if (basename.endsWith('>')) { if (basename.endsWith('>')) {
int pBegin = basename.indexOf('<'); int pBegin = basename.indexOf('<');
if (pBegin>=0) if (pBegin>=0)
basename.truncate(pBegin); basename.truncate(pBegin);
} }
while (index+1<tokenCount
&& mTokenizer[index]->text=="::"
&& isIdentChar(mTokenizer[index+1]->text[0])){
basename += "::" + mTokenizer[index+1]->text;
index+=2;
//remove template staff
if (basename.endsWith('>')) {
int pBegin = basename.indexOf('<');
if (pBegin>=0)
basename.truncate(pBegin);
}
}
// Find the corresponding PStatement // Find the corresponding PStatement
PStatement statement = doFindStatementOf(mCurrentFile,basename, PStatement statement = doFindStatementOf(mCurrentFile,basename,
classStatement->parentScope.lock()); isGlobal?PStatement():classStatement->parentScope.lock());
if (statement && statement->kind == StatementKind::skClass) { if (statement && statement->kind == StatementKind::skClass) {
inheritClassStatement(classStatement,isStruct,statement,lastInheritScopeType); inheritClassStatement(classStatement,isStruct,statement,lastInheritScopeType);
} }
} }
} else {
lastInheritScopeType = inheritScopeType;
} }
index++; index++;
lastInheritScopeType = inheritScopeType;
if (index >= tokenCount) if (index >= tokenCount)
break; break;
if (mTokenizer[index]->text.front() == '{' if (mTokenizer[index]->text.front() == '{'
@ -1717,6 +1753,174 @@ QStringList CppParser::sortFilesByIncludeRelations(const QSet<QString> &files)
return result; return result;
} }
int CppParser::evaluateConstExpr(int endIndex, bool &ok)
{
int result = 0;
if (mIndex>=endIndex) {
ok=false;
return 0;
}
result = evaluateAdditionConstExpr(endIndex,ok);
if (mIndex!=endIndex)
ok = false;
return result;
}
int CppParser::evaluateAdditionConstExpr(int endIndex, bool &ok)
{
int result = 0;
if (mIndex>=endIndex) {
ok=false;
return 0;
}
result = evaluateMultiplyConstExpr(endIndex,ok);
if (!ok)
return result;
while (mIndex<endIndex) {
if (mTokenizer[mIndex]->text=='+') {
mIndex++;
int temp = evaluateMultiplyConstExpr(endIndex,ok);
if (!ok)
return result;
result+=temp;
} else if (mTokenizer[mIndex]->text=='-') {
mIndex++;
int temp = evaluateMultiplyConstExpr(endIndex,ok);
if (!ok)
return result;
result-=temp;
} else
break;
}
return result;
}
int CppParser::evaluateMultiplyConstExpr(int endIndex, bool &ok)
{
int result = 0;
if (mIndex>=endIndex) {
ok=false;
return 0;
}
result = evaluateConstExprTerm(endIndex,ok);
if (!ok)
return result;
while (mIndex<endIndex) {
if (mTokenizer[mIndex]->text=='*') {
mIndex++;
int temp = evaluateConstExprTerm(endIndex,ok);
if (!ok)
return result;
result*=temp;
} else if (mTokenizer[mIndex]->text=='/') {
mIndex++;
int temp = evaluateConstExprTerm(endIndex,ok);
if (!ok)
return result;
result/=temp;
} else if (mTokenizer[mIndex]->text=='%') {
mIndex++;
int temp = evaluateConstExprTerm(endIndex,ok);
if (!ok)
return result;
result%=temp;
} else
break;
}
return result;
}
int CppParser::evaluateConstExprTerm(int endIndex, bool &ok)
{
int result = 0;
if (mIndex>=endIndex) {
ok=false;
return 0;
}
if (mTokenizer[mIndex]->text=="(") {
mIndex++;
result = evaluateConstExpr(endIndex, ok);
if (mIndex>=endIndex || mTokenizer[mIndex]->text!=')')
ok=false;
mIndex++;
} else if (isIdentChar(mTokenizer[mIndex]->text[0])
|| mTokenizer[mIndex]->text=="::") {
QString s = mTokenizer[mIndex]->text;
QSet<QString> searched;
mIndex++;
if (s=="::") {
if (mIndex>=endIndex || !isIdentChar(mTokenizer[mIndex]->text[0])) {
ok=false;
return result;
}
s+=mTokenizer[mIndex]->text;
mIndex++;
}
while (mIndex+1<endIndex
&& mTokenizer[mIndex]->text=="::"
&& isIdentChar(mTokenizer[mIndex+1]->text[0])){
s += "::" + mTokenizer[mIndex+1]->text;
mIndex+=2;
}
while (true){
//prevent infinite loop
if (searched.contains(s)) {
ok=false;
return result;
}
searched.insert(s);
PStatement statement = doFindStatement(s);
if (!statement) {
ok=false;
return result;
}
if (statement->kind == StatementKind::skEnum) {
result = statement->value.toInt(&ok);
break;
} else if (statement->kind == StatementKind::skPreprocessor) {
if (!statement->args.isEmpty()) {
ok=false;
return result;
}
QString macroText = statement->value;
if (macroText.isEmpty()) {
ok=false;
return result;
}
if (isDigitChar(macroText[0])) {
result = evaluateLiteralNumber(endIndex,ok);
} else {
s = macroText;
}
}
}
} else {
result = evaluateLiteralNumber(endIndex,ok);
mIndex++;
}
return result;
}
int CppParser::evaluateLiteralNumber(int endIndex, bool &ok)
{
int result = 0;
if (mIndex>=endIndex) {
ok=false;
return 0;
}
if (mTokenizer[mIndex]->text.startsWith("0x")
|| mTokenizer[mIndex]->text.startsWith("0X"))
result = mTokenizer[mIndex]->text.mid(2).toInt(&ok,16);
else if (mTokenizer[mIndex]->text.startsWith("0b")
|| mTokenizer[mIndex]->text.startsWith("0B"))
result = mTokenizer[mIndex]->text.mid(2).toInt(&ok,2);
else if (mTokenizer[mIndex]->text.startsWith("0"))
result = mTokenizer[mIndex]->text.toInt(&ok,8);
else
result = mTokenizer[mIndex]->text.toInt(&ok);
return result;
}
bool CppParser::checkForKeyword(KeywordType& keywordType) bool CppParser::checkForKeyword(KeywordType& keywordType)
{ {
keywordType = mCppKeywords.value(mTokenizer[mIndex]->text,KeywordType::NotKeyword); keywordType = mCppKeywords.value(mTokenizer[mIndex]->text,KeywordType::NotKeyword);
@ -2349,9 +2553,9 @@ void CppParser::handleEnum(bool isTypedef)
//enum class //enum class
isEnumClass = true; isEnumClass = true;
mIndex++; //skip class mIndex++; //skip class
} }
bool isAdhocVar=false; bool isAdhocVar=false;
bool isNonameEnum=false;
int endIndex=-1; int endIndex=-1;
if ((mIndex< tokenCount) && mTokenizer[mIndex]->text.startsWith('{')) { // enum {...} NAME if ((mIndex< tokenCount) && mTokenizer[mIndex]->text.startsWith('{')) { // enum {...} NAME
// Skip to the closing brace // Skip to the closing brace
@ -2360,9 +2564,12 @@ void CppParser::handleEnum(bool isTypedef)
if (i + 1 < tokenCount) { if (i + 1 < tokenCount) {
enumName = mTokenizer[i + 1]->text.trimmed(); enumName = mTokenizer[i + 1]->text.trimmed();
if (!isIdentifierOrPointer(enumName)) { if (!isIdentifierOrPointer(enumName)) {
if (isTypedef || isEnumClass) {
//not a valid enum, skip to j //not a valid enum, skip to j
mIndex=indexOfNextSemicolon(i+1)+1; mIndex=indexOfNextSemicolon(i+1)+1;
return; return;
} else
isNonameEnum = true;
} }
if (!isTypedef) { if (!isTypedef) {
//it's an ad-hoc enum var define; //it's an ad-hoc enum var define;
@ -2371,13 +2578,20 @@ void CppParser::handleEnum(bool isTypedef)
mIndex=indexOfNextSemicolon(i+1)+1; mIndex=indexOfNextSemicolon(i+1)+1;
return; return;
} }
enumName = "__enum__"+enumName+"__"; enumName = "__@enum@__"+enumName+"__";
isAdhocVar=true; isAdhocVar=true;
} }
} }
endIndex=i+1; endIndex=i+1;
} else if (mIndex+1< tokenCount && mTokenizer[mIndex+1]->text.startsWith('{')){ // enum NAME {...}; } else if (mIndex+1< tokenCount && mTokenizer[mIndex+1]->text.startsWith('{')){ // enum NAME {...};
enumName = mTokenizer[mIndex]->text; enumName = mTokenizer[mIndex]->text;
mIndex++;
} else if (mIndex+1< tokenCount && mTokenizer[mIndex+1]->text.startsWith(':')){ // enum NAME:int {...};
enumName = mTokenizer[mIndex]->text;
//skip :
mIndex = indexOfNextLeftBrace(mIndex);
if (mIndex>tokenCount)
return;
} else { } else {
// enum NAME blahblah // enum NAME blahblah
// it's an old c-style enum variable definition // it's an old c-style enum variable definition
@ -2386,6 +2600,7 @@ void CppParser::handleEnum(bool isTypedef)
// Add statement for enum name too // Add statement for enum name too
PStatement enumStatement; PStatement enumStatement;
if (!isNonameEnum) {
if (isEnumClass) { if (isEnumClass) {
enumStatement=addStatement( enumStatement=addStatement(
getCurrentScope(), getCurrentScope(),
@ -2413,7 +2628,9 @@ void CppParser::handleEnum(bool isTypedef)
StatementKind::skEnumType, StatementKind::skEnumType,
getScope(), getScope(),
mCurrentMemberAccessibility, mCurrentMemberAccessibility,
StatementProperty::spHasDefinition); isAdhocVar?(StatementProperty::spHasDefinition|StatementProperty::spDummyStatement)
:StatementProperty::spHasDefinition );
}
} }
if (isAdhocVar) { if (isAdhocVar) {
//Ad-hoc var definition //Ad-hoc var definition
@ -2454,20 +2671,31 @@ void CppParser::handleEnum(bool isTypedef)
mIndex++; mIndex++;
// Call every member "enum NAME ITEMNAME" // Call every member "enum NAME ITEMNAME"
QString lastType("enum"); QString lastType;
if (!enumName.isEmpty()) if (enumStatement && !isAdhocVar)
lastType += ' ' + enumName; lastType = "enum " + enumName;
QString cmd; QString cmd;
QString args; QString args;
if (mTokenizer[mIndex]->text!='}') { int value=0;
bool canCalcValue=true;
while ((mIndex < tokenCount) && while ((mIndex < tokenCount) &&
mTokenizer[mIndex]->text!='}') { mTokenizer[mIndex]->text!='}') {
if (mTokenizer[mIndex]->text=="=") { if (tokenIsIdentifier(mTokenizer[mIndex]->text)) {
mIndex=indexOfNextPeriodOrSemicolon(mIndex);
continue;
} else if (tokenIsIdentifier(mTokenizer[mIndex]->text)) {
cmd = mTokenizer[mIndex]->text; cmd = mTokenizer[mIndex]->text;
args = ""; args = "";
if (mIndex+1<tokenCount &&
mTokenizer[mIndex+1]->text=="=") {
mIndex+=2;
if (mIndex<tokenCount) {
bool ok;
int endIndex = indexOfNextPeriodOrSemicolon(mIndex);
value = evaluateConstExpr(endIndex,ok);
if (!ok) {
canCalcValue=false;
}
mIndex = endIndex - 1;
}
}
if (isEnumClass) { if (isEnumClass) {
if (enumStatement) { if (enumStatement) {
addStatement( addStatement(
@ -2477,7 +2705,7 @@ void CppParser::handleEnum(bool isTypedef)
cmd, cmd,
args, args,
"", "",
"", canCalcValue?QString("%1").arg(value):"",
mTokenizer[mIndex]->line, mTokenizer[mIndex]->line,
StatementKind::skEnum, StatementKind::skEnum,
getScope(), getScope(),
@ -2485,6 +2713,7 @@ void CppParser::handleEnum(bool isTypedef)
StatementProperty::spHasDefinition); StatementProperty::spHasDefinition);
} }
} else { } else {
QString strValue=canCalcValue?QString("%1").arg(value):"";
if (enumStatement) { if (enumStatement) {
addStatement( addStatement(
enumStatement, enumStatement,
@ -2493,7 +2722,7 @@ void CppParser::handleEnum(bool isTypedef)
cmd, cmd,
args, args,
"", "",
"", strValue,
mTokenizer[mIndex]->line, mTokenizer[mIndex]->line,
StatementKind::skEnum, StatementKind::skEnum,
getScope(), getScope(),
@ -2507,17 +2736,17 @@ void CppParser::handleEnum(bool isTypedef)
cmd, cmd,
"", "",
"", "",
"", strValue,
mTokenizer[mIndex]->line, mTokenizer[mIndex]->line,
StatementKind::skEnum, StatementKind::skEnum,
getScope(), getScope(),
mCurrentMemberAccessibility, mCurrentMemberAccessibility,
StatementProperty::spHasDefinition); StatementProperty::spHasDefinition);
} }
value++;
} }
mIndex ++ ; mIndex ++ ;
} }
}
if (mIndex<endIndex) if (mIndex<endIndex)
mIndex=endIndex; mIndex=endIndex;
mIndex = indexOfNextSemicolon(mIndex)+1; mIndex = indexOfNextSemicolon(mIndex)+1;
@ -3474,6 +3703,7 @@ void CppParser::handleStructs(bool isTypedef)
PStatement scopeStatement=getCurrentScope(); PStatement scopeStatement=getCurrentScope();
QString scopelessName; QString scopelessName;
QString parentName; QString parentName;
if (splitLastMember(command,scopelessName,parentName)) { if (splitLastMember(command,scopelessName,parentName)) {
scopeStatement = getIncompleteClass(parentName,getCurrentScope()); scopeStatement = getIncompleteClass(parentName,getCurrentScope());
} else { } else {
@ -3580,7 +3810,7 @@ void CppParser::handleStructs(bool isTypedef)
getCurrentScope(), getCurrentScope(),
mCurrentFile, mCurrentFile,
prefix, prefix,
"__"+command, "_@dummy@_"+command,
"", "",
"", "",
"", "",
@ -3589,7 +3819,7 @@ void CppParser::handleStructs(bool isTypedef)
StatementKind::skClass, StatementKind::skClass,
getScope(), getScope(),
mCurrentMemberAccessibility, mCurrentMemberAccessibility,
StatementProperty::spHasDefinition); StatementProperty::spHasDefinition | StatementProperty::spDummyStatement);
} }
if (isTypedef) { if (isTypedef) {
//typedef //typedef

View File

@ -216,6 +216,12 @@ private:
QStringList sortFilesByIncludeRelations(const QSet<QString> &files); QStringList sortFilesByIncludeRelations(const QSet<QString> &files);
int evaluateConstExpr(int endIndex, bool &ok);
int evaluateAdditionConstExpr(int endIndex, bool &ok);
int evaluateMultiplyConstExpr(int endIndex, bool &ok);
int evaluateConstExprTerm(int endIndex, bool &ok);
int evaluateLiteralNumber(int endIndex, bool &ok);
bool checkForKeyword(KeywordType &keywordType); bool checkForKeyword(KeywordType &keywordType);
bool checkForNamespace(KeywordType keywordType); bool checkForNamespace(KeywordType keywordType);
bool checkForPreprocessor(); bool checkForPreprocessor();

View File

@ -153,7 +153,8 @@ enum StatementProperty {
spOverride = 0x0040, spOverride = 0x0040,
spConstexpr = 0x0080, spConstexpr = 0x0080,
spFunctionPointer = 0x0100, spFunctionPointer = 0x0100,
spOperatorOverloading = 0x0200 spOperatorOverloading = 0x0200,
spDummyStatement = 0x0400
}; };
Q_DECLARE_FLAGS(StatementProperties, StatementProperty) Q_DECLARE_FLAGS(StatementProperties, StatementProperty)

View File

@ -148,12 +148,18 @@ QVariant ClassBrowserModel::data(const QModelIndex &index, int role) const
return QVariant(); return QVariant();
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
if (node->statement) { if (node->statement) {
if (!(node->statement->type.isEmpty()) && if (!(node->statement->type.isEmpty())) {
((node->statement->kind == StatementKind::skFunction) if ((node->statement->kind == StatementKind::skFunction)
|| (node->statement->kind == StatementKind::skVariable) || (node->statement->kind == StatementKind::skVariable)
|| (node->statement->kind == StatementKind::skTypedef) || (node->statement->kind == StatementKind::skTypedef)
)) { ) {
return node->statement->command + node->statement->args + " : " + node->statement->type; return node->statement->command + node->statement->args + " : " + node->statement->type;
} else if (node->statement->kind == StatementKind::skEnum) {
if (!node->statement->value.isEmpty())
return node->statement->command + node->statement->args + QString("(%1)").arg(node->statement->value);
else
return node->statement->command;
}
} }
return node->statement->command + node->statement->args; return node->statement->command + node->statement->args;
} }
@ -351,9 +357,12 @@ void ClassBrowserModel::filterChildren(ClassBrowserNode *node, const StatementMa
if (mProcessedStatements.contains(statement.get())) if (mProcessedStatements.contains(statement.get()))
continue; continue;
// if (statement->properties.testFlag(StatementProperty::spDummyStatement))
// continue;
if (statement->kind == StatementKind::skBlock) if (statement->kind == StatementKind::skBlock)
continue; continue;
if (statement->isInherited() && !pSettings->ui().classBrowserShowInherited()) if (statement->isInherited() && !pSettings->ui().classBrowserShowInherited())
continue; continue;

View File

@ -286,7 +286,9 @@ void CodeCompletionPopup::addStatement(const PStatement& statement, const QStrin
if (statement->kind == StatementKind::skConstructor if (statement->kind == StatementKind::skConstructor
|| statement->kind == StatementKind::skDestructor || statement->kind == StatementKind::skDestructor
|| statement->kind == StatementKind::skBlock || statement->kind == StatementKind::skBlock
|| statement->properties.testFlag(StatementProperty::spOperatorOverloading)) || statement->properties.testFlag(StatementProperty::spOperatorOverloading)
|| statement->properties.testFlag(StatementProperty::spDummyStatement)
)
return; return;
if ((line!=-1) if ((line!=-1)
&& (line < statement->line) && (line < statement->line)