diff --git a/NEWS.md b/NEWS.md index 957dae73..76db2545 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 diff --git a/RedPandaIDE/compiler/compiler.cpp b/RedPandaIDE/compiler/compiler.cpp index b65b3939..fd6d87c4 100644 --- a/RedPandaIDE/compiler/compiler.cpp +++ b/RedPandaIDE/compiler/compiler.cpp @@ -216,7 +216,7 @@ QByteArray Compiler::pipedText() return QByteArray(); } -bool Compiler::beforeRunExtraCommand(int idx) +bool Compiler::beforeRunExtraCommand(int /* idx */) { return true; } diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 9093a217..c572e2fa 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -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 (mIndextext=='{') + 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+2text == '=')) { aliasName=mTokenizer[mIndex+1]->text; + mIndex+=2; + if (aliasName == "::" && mIndextext; + mIndex++; + } + while(mIndex+1text == "::") { + aliasName+="::"; + aliasName+=mTokenizer[mIndex+1]->text; + mIndex+=2; + } + //qDebug()<text != "namespace")) { QString fullName; QString usingName; + bool appendUsingName = false; while (mIndextext!=';') { 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 or foo::boo::ttt + 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; diff --git a/RedPandaIDE/parser/cppparser.h b/RedPandaIDE/parser/cppparser.h index 5f93fa46..cfd2c756 100644 --- a/RedPandaIDE/parser/cppparser.h +++ b/RedPandaIDE/parser/cppparser.h @@ -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( diff --git a/RedPandaIDE/parser/parserutils.cpp b/RedPandaIDE/parser/parserutils.cpp index 2dbd7e61..392944ee 100644 --- a/RedPandaIDE/parser/parserutils.cpp +++ b/RedPandaIDE/parser/parserutils.cpp @@ -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); diff --git a/RedPandaIDE/parser/parserutils.h b/RedPandaIDE/parser/parserutils.h index 3247996b..ccc4431d 100644 --- a/RedPandaIDE/parser/parserutils.h +++ b/RedPandaIDE/parser/parserutils.h @@ -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 }; diff --git a/RedPandaIDE/widgets/codecompletionpopup.cpp b/RedPandaIDE/widgets/codecompletionpopup.cpp index 454cbad1..0c2775f3 100644 --- a/RedPandaIDE/widgets/codecompletionpopup.cpp +++ b/RedPandaIDE/widgets/codecompletionpopup.cpp @@ -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); diff --git a/libs/qsynedit/qsynedit/syntaxer/syntaxer.h b/libs/qsynedit/qsynedit/syntaxer/syntaxer.h index 32c86c9b..5d39ee6b 100644 --- a/libs/qsynedit/qsynedit/syntaxer/syntaxer.h +++ b/libs/qsynedit/qsynedit/syntaxer/syntaxer.h @@ -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;