- enhancement: Parse files that contains C++ 20 'concept' keyword. (No code suggesion for concepts now)

- enhancement: Parse files that contains C++ 20 'requires' keyword.
  - fix: Code suggestions in namespace.
  - enhancement: Code suggestions for namespace alias.
  - fix: Correctly handle statements like 'using xxx::operator()'.
This commit is contained in:
Roy Qu 2023-10-22 13:19:03 +08:00
parent 9467645bef
commit 30cabe2faa
8 changed files with 128 additions and 7 deletions

View File

@ -4,6 +4,11 @@ Red Panda C++ Version 2.26
- enhancement: Auto adjust position of the suggestion popup window. - enhancement: Auto adjust position of the suggestion popup window.
- enhancement: Windows XP support ( by cyano.CN ) - enhancement: Windows XP support ( by cyano.CN )
- fix: __attribute__ is not correctly handled if it is after 'static'. - fix: __attribute__ is not correctly handled if it is after 'static'.
- enhancement: Parse files that contains C++ 20 'concept' keyword. (No code suggesion for concepts now)
- enhancement: Parse files that contains C++ 20 'requires' keyword.
- fix: Code suggestions in namespace.
- enhancement: Code suggestions for namespace alias.
- fix: Correctly handle statements like 'using xxx::operator()'.
Red Panda C++ Version 2.25 Red Panda C++ Version 2.25

View File

@ -216,7 +216,7 @@ QByteArray Compiler::pipedText()
return QByteArray(); return QByteArray();
} }
bool Compiler::beforeRunExtraCommand(int idx) bool Compiler::beforeRunExtraCommand(int /* idx */)
{ {
return true; return true;
} }

View File

@ -1958,6 +1958,8 @@ bool CppParser::checkForKeyword(KeywordType& keywordType)
case KeywordType::NotKeyword: case KeywordType::NotKeyword:
case KeywordType::DeclType: case KeywordType::DeclType:
case KeywordType::Operator: case KeywordType::Operator:
case KeywordType::Requires:
case KeywordType::Concept:
return false; return false;
default: default:
return true; return true;
@ -2577,6 +2579,19 @@ void CppParser::handleCatchBlock()
mIndex=mTokenizer[mIndex]->matchIndex+1; mIndex=mTokenizer[mIndex]->matchIndex+1;
} }
void CppParser::handleConcept()
{
mIndex++; // skip 'concept';
// just skip it;
mIndex = indexOfNextSemicolonOrLeftBrace(mIndex);
if (mIndex<mTokenizer.tokenCount()) {
if (mTokenizer[mIndex]->text=='{')
mIndex = mTokenizer[mIndex]->matchIndex+1; // skip '}'
else
mIndex++; // skip ;
}
}
void CppParser::handleEnum(bool isTypedef) void CppParser::handleEnum(bool isTypedef)
{ {
int tokenCount = mTokenizer.tokenCount(); int tokenCount = mTokenizer.tokenCount();
@ -3244,6 +3259,17 @@ void CppParser::handleNamespace(KeywordType skipType)
QString aliasName; QString aliasName;
if ((mIndex+2<tokenCount) && (mTokenizer[mIndex]->text == '=')) { if ((mIndex+2<tokenCount) && (mTokenizer[mIndex]->text == '=')) {
aliasName=mTokenizer[mIndex+1]->text; aliasName=mTokenizer[mIndex+1]->text;
mIndex+=2;
if (aliasName == "::" && mIndex<tokenCount) {
aliasName += mTokenizer[mIndex]->text;
mIndex++;
}
while(mIndex+1<tokenCount && mTokenizer[mIndex]->text == "::") {
aliasName+="::";
aliasName+=mTokenizer[mIndex+1]->text;
mIndex+=2;
}
//qDebug()<<command<<aliasName;
//namespace alias //namespace alias
addStatement( addStatement(
getCurrentScope(), getCurrentScope(),
@ -3259,7 +3285,7 @@ void CppParser::handleNamespace(KeywordType skipType)
getScope(), getScope(),
mCurrentMemberAccessibility, mCurrentMemberAccessibility,
StatementProperty::spHasDefinition); StatementProperty::spHasDefinition);
mIndex+=2; //skip ; mIndex++; // skip ;
return; return;
} else if (isInline) { } else if (isInline) {
//inline namespace , just skip it //inline namespace , just skip it
@ -3589,6 +3615,10 @@ bool CppParser::handleStatement()
mIndex=moveToEndOfStatement(mIndex,true); mIndex=moveToEndOfStatement(mIndex,true);
} else if (checkForKeyword(keywordType)) { // includes template now } else if (checkForKeyword(keywordType)) { // includes template now
handleKeyword(keywordType); handleKeyword(keywordType);
} else if (keywordType==KeywordType::Concept) {
handleConcept();
} else if (keywordType==KeywordType::Requires) {
skipRequires();
} else if (keywordType==KeywordType::For) { // (for/catch) } else if (keywordType==KeywordType::For) { // (for/catch)
handleForBlock(); handleForBlock();
} else if (keywordType==KeywordType::Catch) { // (for/catch) } else if (keywordType==KeywordType::Catch) { // (for/catch)
@ -3980,10 +4010,18 @@ void CppParser::handleUsing()
|| (mTokenizer[mIndex]->text != "namespace")) { || (mTokenizer[mIndex]->text != "namespace")) {
QString fullName; QString fullName;
QString usingName; QString usingName;
bool appendUsingName = false;
while (mIndex<tokenCount && while (mIndex<tokenCount &&
mTokenizer[mIndex]->text!=';') { mTokenizer[mIndex]->text!=';') {
fullName += mTokenizer[mIndex]->text; fullName += mTokenizer[mIndex]->text;
usingName = mTokenizer[mIndex]->text; if (!appendUsingName) {
usingName = mTokenizer[mIndex]->text;
if (usingName == "operator") {
appendUsingName=true;
}
} else {
usingName += mTokenizer[mIndex]->text;
}
mIndex++; mIndex++;
} }
if (fullName!=usingName) { if (fullName!=usingName) {
@ -4327,6 +4365,43 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
mIndex++; mIndex++;
} }
void CppParser::skipRequires()
{
mIndex++; //skip 'requires';
int tokenCount = mTokenizer.tokenCount();
while (mIndex < tokenCount) { // ||
while (mIndex < tokenCount) { // &&
if (mTokenizer[mIndex]->text=='(') {
//skip parenthesized expression
mIndex = mTokenizer[mIndex]->matchIndex+1;
} else if (isIdentifier(mTokenizer[mIndex]->text)) {
// skip foo<T> or foo::boo::ttt<T>
while (mIndex < tokenCount) {
if (!isIdentifier(mTokenizer[mIndex]->text))
return;
mIndex++;
if (mIndex>=tokenCount)
return;
if (mTokenizer[mIndex]->text!="::")
break;
mIndex++; // skip '::';
}
}
if (mIndex>=tokenCount)
return;
if (mTokenizer[mIndex]->text!="&&")
break;
mIndex++; // skip '&&';
}
if (mIndex>=tokenCount)
return;
if (mTokenizer[mIndex]->text!="||")
break;
mIndex++; // skip '||';
}
}
void CppParser::internalParse(const QString &fileName) void CppParser::internalParse(const QString &fileName)
{ {
// Perform some validation before we start // Perform some validation before we start
@ -5209,6 +5284,9 @@ PEvalStatement CppParser::doEvalTerm(const QString &fileName,
case StatementKind::skNamespace: case StatementKind::skNamespace:
result = doCreateEvalNamespace(statement); result = doCreateEvalNamespace(statement);
break; break;
case StatementKind::skNamespaceAlias:
result = doFindAliasedNamespace(statement);
break;
case StatementKind::skAlias: { case StatementKind::skAlias: {
statement = doFindAliasedStatement(statement); statement = doFindAliasedStatement(statement);
if (statement) if (statement)
@ -5421,6 +5499,29 @@ PEvalStatement CppParser::doCreateEvalNamespace(const PStatement &namespaceState
namespaceStatement); namespaceStatement);
} }
PEvalStatement CppParser::doFindAliasedNamespace(const PStatement &namespaceAlias) const
{
QStringList expList;
QString s = namespaceAlias->type;
int pos = s.indexOf("::");
while (pos>=0) {
expList.append(s.left(pos));
expList.append("::");
s = s.mid(pos+2);
pos = s.indexOf("::");
}
expList.append(s);
pos=0;
return doEvalExpression(
namespaceAlias->fileName,
expList,
pos,
namespaceAlias->parentScope.lock(),
PEvalStatement(),
true
);
}
PEvalStatement CppParser::doCreateEvalType(const QString &fileName, const QString &typeName, const PStatement& parentScope) const PEvalStatement CppParser::doCreateEvalType(const QString &fileName, const QString &typeName, const PStatement& parentScope) const
{ {
QString baseType; QString baseType;

View File

@ -223,11 +223,13 @@ private:
int evaluateConstExprTerm(int endIndex, bool &ok); int evaluateConstExprTerm(int endIndex, bool &ok);
int evaluateLiteralNumber(int endIndex, bool &ok); int evaluateLiteralNumber(int endIndex, bool &ok);
bool checkForConcept(KeywordType &keywordType) { return keywordType == KeywordType::Concept; }
bool checkForKeyword(KeywordType &keywordType); bool checkForKeyword(KeywordType &keywordType);
bool checkForNamespace(KeywordType keywordType); bool checkForNamespace(KeywordType keywordType);
bool checkForPreprocessor(); bool checkForPreprocessor();
// bool checkForLambda(); // bool checkForLambda();
bool checkForAccessibilitySpecifiers(KeywordType keywordType); bool checkForAccessibilitySpecifiers(KeywordType keywordType);
bool checkForRequires(KeywordType keywordType) { return keywordType == KeywordType::Requires; }
bool checkForStructs(KeywordType keywordType); bool checkForStructs(KeywordType keywordType);
bool checkForTypedefEnum(); bool checkForTypedefEnum();
bool checkForTypedefStruct(); bool checkForTypedefStruct();
@ -371,6 +373,8 @@ private:
PEvalStatement doCreateEvalNamespace(const PStatement& namespaceStatement) const; PEvalStatement doCreateEvalNamespace(const PStatement& namespaceStatement) const;
PEvalStatement doFindAliasedNamespace(const PStatement& namespaceAlias) const;
PEvalStatement doCreateEvalType(const QString& fileName,const QString& typeName, const PStatement& parentScope) const; PEvalStatement doCreateEvalType(const QString& fileName,const QString& typeName, const PStatement& parentScope) const;
PEvalStatement doCreateEvalType(const QString& fileName,const PStatement& typeStatement) const; PEvalStatement doCreateEvalType(const QString& fileName,const PStatement& typeStatement) const;
PEvalStatement doCreateEvalType(const QString& primitiveType) const; PEvalStatement doCreateEvalType(const QString& primitiveType) const;
@ -485,6 +489,7 @@ private:
PStatement getTypeDef(const PStatement& statement, PStatement getTypeDef(const PStatement& statement,
const QString& fileName, const QString& aType) const; const QString& fileName, const QString& aType) const;
void handleCatchBlock(); void handleCatchBlock();
void handleConcept();
void handleEnum(bool isTypedef); void handleEnum(bool isTypedef);
void handleForBlock(); void handleForBlock();
void handleKeyword(KeywordType skipType); void handleKeyword(KeywordType skipType);
@ -510,6 +515,7 @@ private:
void handleStructs(bool isTypedef = false); void handleStructs(bool isTypedef = false);
void handleUsing(); void handleUsing();
void handleVar(const QString& typePrefix,bool isExtern,bool isStatic); void handleVar(const QString& typePrefix,bool isExtern,bool isStatic);
void skipRequires();
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(

View File

@ -135,20 +135,21 @@ void initParser()
CppKeywords.insert("__asm",KeywordType::SkipNextParenthesis); CppKeywords.insert("__asm",KeywordType::SkipNextParenthesis);
// Skip to { // Skip to {
CppKeywords.insert("requires",KeywordType::Requires);
CppKeywords.insert("concept",KeywordType::Concept);
// wont handle // wont handle
//Not supported yet //Not supported yet
CppKeywords.insert("atomic_cancel",KeywordType::None); CppKeywords.insert("atomic_cancel",KeywordType::None);
CppKeywords.insert("atomic_commit",KeywordType::None); CppKeywords.insert("atomic_commit",KeywordType::None);
CppKeywords.insert("atomic_noexcept",KeywordType::None); CppKeywords.insert("atomic_noexcept",KeywordType::None);
CppKeywords.insert("concept",KeywordType::None);
CppKeywords.insert("consteval",KeywordType::None); CppKeywords.insert("consteval",KeywordType::None);
CppKeywords.insert("constinit",KeywordType::None); CppKeywords.insert("constinit",KeywordType::None);
CppKeywords.insert("co_wait",KeywordType::None); CppKeywords.insert("co_wait",KeywordType::None);
CppKeywords.insert("co_return",KeywordType::None); CppKeywords.insert("co_return",KeywordType::None);
CppKeywords.insert("co_yield",KeywordType::None); CppKeywords.insert("co_yield",KeywordType::None);
CppKeywords.insert("reflexpr",KeywordType::None); CppKeywords.insert("reflexpr",KeywordType::None);
CppKeywords.insert("requires",KeywordType::None);
// its a type // its a type
CppKeywords.insert("auto",KeywordType::None); CppKeywords.insert("auto",KeywordType::None);

View File

@ -81,6 +81,8 @@ enum class KeywordType {
Using, //using Using, //using
DeclType, // decltype DeclType, // decltype
Operator, //operator Operator, //operator
Concept, //concept
Requires, //requires
None, // It's a keyword but don't process here None, // It's a keyword but don't process here
NotKeyword NotKeyword
}; };

View File

@ -664,7 +664,13 @@ void CodeCompletionPopup::getCompletionFor(
// repeat until reach global // repeat until reach global
while (scopeStatement) { while (scopeStatement) {
//add members of current scope that not added before //add members of current scope that not added before
if (scopeStatement->kind == StatementKind::skClass) { if (scopeStatement->kind == StatementKind::skNamespace) {
PStatementList namespaceStatementsList =
mParser->findNamespace(scopeStatement->fullName);
foreach (const PStatement& namespaceStatement,*namespaceStatementsList) {
addChildren(namespaceStatement, fileName, line, isLambdaReturnType);
}
} else if (scopeStatement->kind == StatementKind::skClass) {
addChildren(scopeStatement, fileName, -1, isLambdaReturnType); addChildren(scopeStatement, fileName, -1, isLambdaReturnType);
} else { } else {
addChildren(scopeStatement, fileName, line, isLambdaReturnType); addChildren(scopeStatement, fileName, line, isLambdaReturnType);

View File

@ -148,7 +148,7 @@ public:
virtual bool getTokenFinished() const = 0; virtual bool getTokenFinished() const = 0;
virtual bool isLastLineCommentNotFinished(int state) const = 0; virtual bool isLastLineCommentNotFinished(int state) const = 0;
virtual bool isLastLineStringNotFinished(int state) const = 0; virtual bool isLastLineStringNotFinished(int state) const = 0;
virtual bool isDocstringNotFinished(int state) const { return false; } virtual bool isDocstringNotFinished(int /* state */) const { return false; }
virtual bool eol() const = 0; virtual bool eol() const = 0;
virtual SyntaxState getState() const = 0; virtual SyntaxState getState() const = 0;
virtual QString getToken() const=0; virtual QString getToken() const=0;