- enhancement: Deduce type info for "auto" in some simple cases.

This commit is contained in:
Roy Qu 2022-11-27 13:32:14 +08:00
parent 8788e950dd
commit adb3d79b60
8 changed files with 203 additions and 34 deletions

View File

@ -10,6 +10,7 @@ Red Panda C++ Version 2.5
- change: Default value of option "Auto clear symbols in hidden editors" is ON if number of CPU cores > 8 and "Editors share one code analyzer" is on - change: Default value of option "Auto clear symbols in hidden editors" is ON if number of CPU cores > 8 and "Editors share one code analyzer" is on
- enhancement: show completion suggest for "namespace" after "using" - enhancement: show completion suggest for "namespace" after "using"
- fix: MinGW-w64 gcc displayed as "MinGW GCC" - fix: MinGW-w64 gcc displayed as "MinGW GCC"
- enhancement: Deduce type info for "auto" in some simple cases.
Red Panda C++ Version 2.4 Red Panda C++ Version 2.4

View File

@ -735,6 +735,11 @@ void Editor::keyPressEvent(QKeyEvent *event)
showCompletion(lastWord,false, CodeCompletionType::ComplexKeyword); showCompletion(lastWord,false, CodeCompletionType::ComplexKeyword);
handled=true; handled=true;
return; return;
} else if (lastWord == "namespace") {
commandProcessor(QSynedit::EditCommand::ecChar,ch,nullptr);
showCompletion(lastWord,false, CodeCompletionType::Namespaces);
handled=true;
return;
} else if (CppTypeKeywords.contains(lastWord)) { } else if (CppTypeKeywords.contains(lastWord)) {
PStatement currentScope = mParser->findScopeStatement(mFilename,caretY()); PStatement currentScope = mParser->findScopeStatement(mFilename,caretY());
while(currentScope && currentScope->kind==StatementKind::skBlock) { while(currentScope && currentScope->kind==StatementKind::skBlock) {

View File

@ -190,25 +190,7 @@ QString CppParser::findFirstTemplateParamOf(const QString &fileName, const QStri
QMutexLocker locker(&mMutex); QMutexLocker locker(&mMutex);
if (mParsing) if (mParsing)
return ""; return "";
// Remove pointer stuff from type return doFindFirstTemplateParamOf(fileName,phrase,currentScope);
QString s = phrase; // 'Type' is a keyword
int i = s.indexOf('<');
if (i>=0) {
int t=getFirstTemplateParamEnd(s,i);
return s.mid(i+1,t-i-1);
}
int position = s.length()-1;
while ((position >= 0) && (s[position] == '*'
|| s[position] == ' '
|| s[position] == '&'))
position--;
if (position != s.length()-1)
s.truncate(position+1);
PStatement scopeStatement = currentScope;
PStatement statement = findStatementOf(fileName,s,currentScope);
return getFirstTemplateParam(statement,fileName, phrase, currentScope);
} }
PStatement CppParser::findFunctionAt(const QString &fileName, int line) PStatement CppParser::findFunctionAt(const QString &fileName, int line)
@ -2023,6 +2005,29 @@ void CppParser::checkAndHandleMethodOrVar(KeywordType keywordType)
} }
} }
QString CppParser::doFindFirstTemplateParamOf(const QString &fileName, const QString &phrase, const PStatement &currentScope)
{
// Remove pointer stuff from type
QString s = phrase; // 'Type' is a keyword
int i = s.indexOf('<');
if (i>=0) {
int t=getFirstTemplateParamEnd(s,i);
return s.mid(i+1,t-i-1);
}
int position = s.length()-1;
while ((position >= 0) && (s[position] == '*'
|| s[position] == ' '
|| s[position] == '&'))
position--;
if (position != s.length()-1)
s.truncate(position+1);
PStatement scopeStatement = currentScope;
PStatement statement = findStatementOf(fileName,s,currentScope);
return getFirstTemplateParam(statement,fileName, phrase, currentScope);
}
int CppParser::getCurrentBlockEndSkip() int CppParser::getCurrentBlockEndSkip()
{ {
if (mBlockEndSkips.isEmpty()) if (mBlockEndSkips.isEmpty())
@ -3524,6 +3529,7 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
lastType=typePrefix; lastType=typePrefix;
} }
PStatement addedVar;
//we only check the first token to reduce calculations //we only check the first token to reduce calculations
// if (mIndex>=mTokenizer.tokenCount() // if (mIndex>=mTokenizer.tokenCount()
@ -3582,6 +3588,30 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
// as // as
// unsigned short bAppReturnCode,reserved,fBusy,fAck // unsigned short bAppReturnCode,reserved,fBusy,fAck
if (mTokenizer[mIndex]->text.front() == ':') { if (mTokenizer[mIndex]->text.front() == ':') {
if (mIndex+1<mTokenizer.tokenCount()
&& isIdentifier(mTokenizer[mIndex+1]->text)
&& isIdentChar(mTokenizer[mIndex+1]->text.back())
&& addedVar
&& !(addedVar->properties & StatementProperty::spFunctionPointer)
&& addedVar->type == "auto") {
QStringList phraseExpression;
phraseExpression.append(mTokenizer[mIndex+1]->text);
int pos = 0;
PEvalStatement aliasStatement = doEvalExpression(mCurrentFile,
phraseExpression,
pos,
getCurrentScope(),
PEvalStatement(),
true);
if(aliasStatement && aliasStatement->effectiveTypeStatement
&& STLContainers.contains(aliasStatement->effectiveTypeStatement->fullName)) {
QString type=doFindFirstTemplateParamOf(mCurrentFile,aliasStatement->baseType,
getCurrentScope());
if (!type.isEmpty())
addedVar->type = type;
}
}
addedVar.reset();
while ( (mIndex < mTokenizer.tokenCount()) while ( (mIndex < mTokenizer.tokenCount())
&& !( && !(
mTokenizer[mIndex]->text==',' mTokenizer[mIndex]->text==','
@ -3602,9 +3632,10 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
int argEnd=mTokenizer[argStart]->matchIndex; int argEnd=mTokenizer[argStart]->matchIndex;
if (cmd.startsWith("*")) if (cmd.startsWith("*"))
cmd = cmd.mid(1); cmd = cmd.mid(1);
if (!cmd.isEmpty()) { if (!cmd.isEmpty()) {
QString type=lastType; QString type=lastType;
addChildStatement( addedVar = addChildStatement(
getCurrentScope(), getCurrentScope(),
mCurrentFile, mCurrentFile,
(lastType+" "+tempType+" "+mTokenizer[mIndex]->text).trimmed(), (lastType+" "+tempType+" "+mTokenizer[mIndex]->text).trimmed(),
@ -3618,7 +3649,10 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
mClassScope, mClassScope,
//True, //True,
(isExtern?StatementProperty::spNone:StatementProperty::spHasDefinition) (isExtern?StatementProperty::spNone:StatementProperty::spHasDefinition)
| (isStatic?StatementProperty::spStatic:StatementProperty::spNone)); | (isStatic?StatementProperty::spStatic:StatementProperty::spNone)
| StatementProperty::spFunctionPointer);
} else {
addedVar.reset();
} }
tempType=""; tempType="";
mIndex=indexOfNextSemicolonOrLeftBrace(argEnd+1); mIndex=indexOfNextSemicolonOrLeftBrace(argEnd+1);
@ -3635,7 +3669,7 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
cmd=mTokenizer[mIndex]->text; cmd=mTokenizer[mIndex]->text;
parseCommandTypeAndArgs(cmd,suffix,args); parseCommandTypeAndArgs(cmd,suffix,args);
if (!cmd.isEmpty()) { if (!cmd.isEmpty()) {
addChildStatement( addedVar = addChildStatement(
getCurrentScope(), getCurrentScope(),
mCurrentFile, mCurrentFile,
(lastType+' '+tempType+suffix).trimmed(), (lastType+' '+tempType+suffix).trimmed(),
@ -3655,13 +3689,90 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
} }
mIndex++; mIndex++;
} }
} else if (mTokenizer[mIndex]->text=='(') {
mIndex=mTokenizer[mIndex]->matchIndex+1;
} else if (mTokenizer[mIndex]->text=='=') { } else if (mTokenizer[mIndex]->text=='=') {
mIndex = skipAssignment(mIndex, mTokenizer.tokenCount()); if (mIndex+1<mTokenizer.tokenCount()
} else if (mTokenizer[mIndex]->text=='{') { && isIdentifier(mTokenizer[mIndex+1]->text)
&& addedVar
&& !(addedVar->properties & StatementProperty::spFunctionPointer)
&& addedVar->type == "auto") {
int pos = 0;
int endIndex = skipAssignment(mIndex, mTokenizer.tokenCount());
QStringList phraseExpression;
for (int i=mIndex+1;i<endIndex;i++) {
QString cmd = mTokenizer[i]->text;
if (cmd.length()>1 && cmd.endsWith(".")) {
phraseExpression.append(cmd.left(cmd.length()-1));
phraseExpression.append(".");
} else if (cmd.length()>2 && cmd.endsWith("->")) {
phraseExpression.append(cmd.left(cmd.length()-2));
phraseExpression.append("->");
} else if (cmd.length()>2 && cmd.endsWith("::")) {
phraseExpression.append(cmd.left(cmd.length()-2));
phraseExpression.append("::");
} else
phraseExpression.append(cmd);
}
PEvalStatement aliasStatement = doEvalExpression(mCurrentFile,
phraseExpression,
pos,
getCurrentScope(),
PEvalStatement(),
true);
if(aliasStatement) {
if (aliasStatement->effectiveTypeStatement)
addedVar->type = aliasStatement->effectiveTypeStatement->fullName;
else
addedVar->type = aliasStatement->baseType;
if (aliasStatement->pointerLevel>0)
addedVar->type += QString(aliasStatement->pointerLevel,'*');
}
mIndex = endIndex;
} else
mIndex = skipAssignment(mIndex, mTokenizer.tokenCount());
addedVar.reset();
} else if (mTokenizer[mIndex]->text=='{'
|| mTokenizer[mIndex]->text=='(') {
tempType=""; tempType="";
if (mIndex+1<mTokenizer.tokenCount()
&& isIdentifier(mTokenizer[mIndex+1]->text)
&& addedVar
&& !(addedVar->properties & StatementProperty::spFunctionPointer)
&& addedVar->type == "auto") {
int pos = 0;
int endIndex = mTokenizer[mIndex]->matchIndex;
QStringList phraseExpression;
for (int i=mIndex+1;i<endIndex;i++) {
QString cmd = mTokenizer[i]->text;
if (cmd.length()>1 && cmd.endsWith(".")) {
phraseExpression.append(cmd.left(cmd.length()-1));
phraseExpression.append(".");
} else if (cmd.length()>2 && cmd.endsWith("->")) {
phraseExpression.append(cmd.left(cmd.length()-2));
phraseExpression.append("->");
} else if (cmd.length()>2 && cmd.endsWith("::")) {
phraseExpression.append(cmd.left(cmd.length()-2));
phraseExpression.append("::");
} else
phraseExpression.append(cmd);
}
PEvalStatement aliasStatement = doEvalExpression(mCurrentFile,
phraseExpression,
pos,
getCurrentScope(),
PEvalStatement(),
true);
if(aliasStatement && aliasStatement->effectiveTypeStatement) {
if (aliasStatement->effectiveTypeStatement)
addedVar->type = aliasStatement->effectiveTypeStatement->fullName;
else
addedVar->type = aliasStatement->baseType;
if (aliasStatement->pointerLevel>0)
addedVar->type += QString(aliasStatement->pointerLevel,'*');
}
}
mIndex=mTokenizer[mIndex]->matchIndex+1; mIndex=mTokenizer[mIndex]->matchIndex+1;
addedVar.reset();
} else { } else {
tempType=""; tempType="";
mIndex++; mIndex++;
@ -4601,6 +4712,7 @@ PStatement CppParser::doParseEvalTypeInfo(
bracketLevel++; bracketLevel++;
} else if (token == "<") { } else if (token == "<") {
templateLevel++; templateLevel++;
baseType += token;
} else if (token == "::") { } else if (token == "::") {
baseType += token; baseType += token;
} }
@ -4616,6 +4728,7 @@ PStatement CppParser::doParseEvalTypeInfo(
} else if (token == ">") { } else if (token == ">") {
templateLevel--; templateLevel--;
} }
baseType += token;
} }
highlighter.next(); highlighter.next();
} }
@ -4627,7 +4740,7 @@ PStatement CppParser::doParseEvalTypeInfo(
} }
position--; position--;
} }
PStatement statement = findStatementOf(fileName,baseType,scope); PStatement statement = findStatementOf(fileName,baseType,scope,true);
return getTypeDef(statement,fileName,baseType); return getTypeDef(statement,fileName,baseType);
} }
@ -5338,6 +5451,12 @@ const QSet<QString> &CppParser::projectFiles() const
return mProjectFiles; return mProjectFiles;
} }
QList<QString> CppParser::namespaces()
{
QMutexLocker locker(&mMutex);
return mNamespaces.keys();
}
ParserLanguage CppParser::language() const ParserLanguage CppParser::language() const
{ {
return mLanguage; return mLanguage;

View File

@ -145,6 +145,8 @@ public:
const QSet<QString> &projectFiles() const; const QSet<QString> &projectFiles() const;
QList<QString> namespaces();
signals: signals:
void onProgress(const QString& fileName, int total, int current); void onProgress(const QString& fileName, int total, int current);
void onBusy(); void onBusy();
@ -223,6 +225,10 @@ private:
void checkAndHandleMethodOrVar(KeywordType keywordType); void checkAndHandleMethodOrVar(KeywordType keywordType);
QString doFindFirstTemplateParamOf(const QString& fileName,
const QString& phrase,
const PStatement& currentScope);
void fillListOfFunctions(const QString& fileName, int line, void fillListOfFunctions(const QString& fileName, int line,
const PStatement& statement, const PStatement& statement,
const PStatement& scopeStatement, QStringList& list); const PStatement& scopeStatement, QStringList& list);

View File

@ -187,7 +187,7 @@ QString CppTokenizer::getForInit()
simplify(s); simplify(s);
if (!s.isEmpty()) if (!s.isEmpty())
addToken(s,mCurrentLine,tokenType); addToken(s,mCurrentLine,tokenType);
if ( (s == "") || (s == ";") || (s==":")) if ( (s == "") || (s == ";") || (s==")") || (s=="("))
break; break;
// : is used in for-each loop // : is used in for-each loop
} }

View File

@ -149,7 +149,8 @@ enum StatementProperty {
spInherited = 0x0010, spInherited = 0x0010,
spVirtual = 0x0020, spVirtual = 0x0020,
spOverride = 0x0040, spOverride = 0x0040,
spConstexpr = 0x0080 spConstexpr = 0x0080,
spFunctionPointer = 0x0100
}; };
Q_DECLARE_FLAGS(StatementProperties, StatementProperty) Q_DECLARE_FLAGS(StatementProperties, StatementProperty)

View File

@ -92,16 +92,22 @@ void CodeCompletionPopup::prepareSearch(
mMemberPhrase = memberExpression.join(""); mMemberPhrase = memberExpression.join("");
mMemberOperator = memberOperator; mMemberOperator = memberOperator;
if (type == CodeCompletionType::ComplexKeyword) { switch(type) {
case CodeCompletionType::ComplexKeyword:
getCompletionListForTypeKeywordComplex(preWord); getCompletionListForTypeKeywordComplex(preWord);
} else if (type == CodeCompletionType::FunctionWithoutDefinition) { break;
case CodeCompletionType::FunctionWithoutDefinition:
mIncludedFiles = mParser->getFileIncludes(filename); mIncludedFiles = mParser->getFileIncludes(filename);
getCompletionForFunctionWithoutDefinition(preWord, ownerExpression,memberOperator,memberExpression, filename,line); getCompletionForFunctionWithoutDefinition(preWord, ownerExpression,memberOperator,memberExpression, filename,line);
} else if (preWord.isEmpty()) { break;
case CodeCompletionType::Namespaces:
mIncludedFiles = mParser->getFileIncludes(filename);
getCompletionListForNamespaces(preWord,filename,line);
break;
default:
mIncludedFiles = mParser->getFileIncludes(filename); mIncludedFiles = mParser->getFileIncludes(filename);
getCompletionFor(ownerExpression,memberOperator,memberExpression, filename,line, customKeywords); getCompletionFor(ownerExpression,memberOperator,memberExpression, filename,line, customKeywords);
} }
setCursor(oldCursor); setCursor(oldCursor);
} }
@ -900,7 +906,34 @@ void CodeCompletionPopup::getCompletionListForTypeKeywordComplex(const QString &
addKeyword("char"); addKeyword("char");
} else if (preWord == "using") { } else if (preWord == "using") {
addKeyword("namespace"); addKeyword("namespace");
}
}
void CodeCompletionPopup::getCompletionListForNamespaces(const QString &preWord,
const QString& fileName,
int line)
{
if (!mParser->enabled())
return;
if (!mParser->freeze())
return;
{
auto action = finally([this]{
mParser->unFreeze();
});
QList<QString> namespaceNames = mParser->namespaces();
foreach (const QString& name, namespaceNames) {
PStatementList namespaces = mParser->findNamespace(name);
foreach(const PStatement& statement, *namespaces) {
if (isIncluded(statement->fileName)
|| isIncluded(statement->definitionFileName)) {
addStatement(statement,fileName,line);
continue;
}
}
}
} }
} }

View File

@ -40,7 +40,8 @@ private:
enum class CodeCompletionType { enum class CodeCompletionType {
Normal, Normal,
ComplexKeyword, ComplexKeyword,
FunctionWithoutDefinition FunctionWithoutDefinition,
Namespaces
}; };
class CodeCompletionListItemDelegate: public QStyledItemDelegate { class CodeCompletionListItemDelegate: public QStyledItemDelegate {
@ -149,6 +150,9 @@ private:
int line); int line);
void getCompletionListForTypeKeywordComplex(const QString& preWord); void getCompletionListForTypeKeywordComplex(const QString& preWord);
void getCompletionListForNamespaces(const QString &preWord,
const QString& fileName,
int line);
void addKeyword(const QString& keyword); void addKeyword(const QString& keyword);
bool isIncluded(const QString& fileName); bool isIncluded(const QString& fileName);
private: private: