- 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: Windows XP support ( by cyano.CN )
- 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

View File

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

View File

@ -1958,6 +1958,8 @@ bool CppParser::checkForKeyword(KeywordType& keywordType)
case KeywordType::NotKeyword:
case KeywordType::DeclType:
case KeywordType::Operator:
case KeywordType::Requires:
case KeywordType::Concept:
return false;
default:
return true;
@ -2577,6 +2579,19 @@ void CppParser::handleCatchBlock()
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)
{
int tokenCount = mTokenizer.tokenCount();
@ -3244,6 +3259,17 @@ void CppParser::handleNamespace(KeywordType skipType)
QString aliasName;
if ((mIndex+2<tokenCount) && (mTokenizer[mIndex]->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
addStatement(
getCurrentScope(),
@ -3259,7 +3285,7 @@ void CppParser::handleNamespace(KeywordType skipType)
getScope(),
mCurrentMemberAccessibility,
StatementProperty::spHasDefinition);
mIndex+=2; //skip ;
mIndex++; // skip ;
return;
} else if (isInline) {
//inline namespace , just skip it
@ -3589,6 +3615,10 @@ bool CppParser::handleStatement()
mIndex=moveToEndOfStatement(mIndex,true);
} else if (checkForKeyword(keywordType)) { // includes template now
handleKeyword(keywordType);
} else if (keywordType==KeywordType::Concept) {
handleConcept();
} else if (keywordType==KeywordType::Requires) {
skipRequires();
} else if (keywordType==KeywordType::For) { // (for/catch)
handleForBlock();
} else if (keywordType==KeywordType::Catch) { // (for/catch)
@ -3980,10 +4010,18 @@ void CppParser::handleUsing()
|| (mTokenizer[mIndex]->text != "namespace")) {
QString fullName;
QString usingName;
bool appendUsingName = false;
while (mIndex<tokenCount &&
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++;
}
if (fullName!=usingName) {
@ -4327,6 +4365,43 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
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)
{
// Perform some validation before we start
@ -5209,6 +5284,9 @@ PEvalStatement CppParser::doEvalTerm(const QString &fileName,
case StatementKind::skNamespace:
result = doCreateEvalNamespace(statement);
break;
case StatementKind::skNamespaceAlias:
result = doFindAliasedNamespace(statement);
break;
case StatementKind::skAlias: {
statement = doFindAliasedStatement(statement);
if (statement)
@ -5421,6 +5499,29 @@ PEvalStatement CppParser::doCreateEvalNamespace(const PStatement &namespaceState
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
{
QString baseType;

View File

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

View File

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

View File

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

View File

@ -664,7 +664,13 @@ void CodeCompletionPopup::getCompletionFor(
// repeat until reach global
while (scopeStatement) {
//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);
} else {
addChildren(scopeStatement, fileName, line, isLambdaReturnType);

View File

@ -148,7 +148,7 @@ public:
virtual bool getTokenFinished() const = 0;
virtual bool isLastLineCommentNotFinished(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 SyntaxState getState() const = 0;
virtual QString getToken() const=0;