work save
This commit is contained in:
parent
20917e3a8b
commit
585d7678d4
1
NEWS.md
1
NEWS.md
|
@ -4,6 +4,7 @@ Red Panda C++ Version 2.2
|
|||
- enhancement: slightly reduce parsing time
|
||||
- fix: Wrong charset name returned when saveing file
|
||||
- fix: 'using =' / 'namespace =' not correctly handled
|
||||
- fix: Pressing '*' at begin of line will crash app
|
||||
|
||||
Red Panda C++ Version 2.1
|
||||
|
||||
|
|
|
@ -2338,7 +2338,7 @@ bool Editor::handleBracketSkip()
|
|||
|
||||
bool Editor::handleMultilineCommentCompletion()
|
||||
{
|
||||
if ((caretX()-2 < lineText().length()) && (lineText()[caretX() - 2] == '/')) {
|
||||
if ((caretX()-2>=0) && (caretX()-2 < lineText().length()) && (lineText()[caretX() - 2] == '/')) {
|
||||
QString text=selText();
|
||||
beginUpdate();
|
||||
beginUndoBlock();
|
||||
|
|
|
@ -1275,6 +1275,7 @@ PStatement CppParser::addStatement(const PStatement& parent,
|
|||
|
||||
PStatement CppParser::addStatement(const PStatement &parent, const QString &fileName, const QString &aType, const QString &command, int argStart, int argEnd, const QString &value, int line, StatementKind kind, const StatementScope &scope, const StatementClassScope &classScope, bool isDefinition, bool isStatic)
|
||||
{
|
||||
Q_ASSERT(mTokenizer[argStart]->text=='(');
|
||||
QString args("(");
|
||||
QString noNameArgs("(");
|
||||
|
||||
|
@ -1284,7 +1285,7 @@ PStatement CppParser::addStatement(const PStatement &parent, const QString &file
|
|||
QString word;
|
||||
for (int i=start;i<argEnd;i++) {
|
||||
QChar ch=mTokenizer[i]->text[0];
|
||||
if (this->isLetterChar(ch)) {
|
||||
if (this->isIdentChar(ch)) {
|
||||
QString spaces=(i>argStart)?" ":"";
|
||||
args+=spaces;
|
||||
word += mTokenizer[i]->text[0];
|
||||
|
@ -1556,11 +1557,10 @@ QStringList CppParser::sortFilesByIncludeRelations(const QSet<QString> &files)
|
|||
|
||||
bool CppParser::checkForKeyword(KeywordType& keywordType)
|
||||
{
|
||||
keywordType = mCppKeywords.value(mTokenizer[mIndex]->text,KeywordType::None);
|
||||
keywordType = mCppKeywords.value(mTokenizer[mIndex]->text,KeywordType::NotKeyword);
|
||||
switch(keywordType) {
|
||||
case KeywordType::Catch:
|
||||
case KeywordType::For:
|
||||
case KeywordType::None:
|
||||
case KeywordType::Public:
|
||||
case KeywordType::Private:
|
||||
case KeywordType::Enum:
|
||||
|
@ -1570,6 +1570,8 @@ bool CppParser::checkForKeyword(KeywordType& keywordType)
|
|||
case KeywordType::Using:
|
||||
case KeywordType::Friend:
|
||||
case KeywordType::Protected:
|
||||
case KeywordType::None:
|
||||
case KeywordType::NotKeyword:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
|
@ -1625,13 +1627,13 @@ bool CppParser::checkForMethod(QString &sType, QString &sName, int &argStartInde
|
|||
if (currentScope) {
|
||||
//in namespace, it might be function or object initilization
|
||||
if (currentScope->kind == StatementKind::skNamespace
|
||||
&& isNotFuncArgs(mIndex + 1,mTokenizer[mIndex + 1]->matchIndex)) {
|
||||
&& isNotFuncArgs(mIndex + 1)) {
|
||||
break;
|
||||
//not in class, it can't be a valid function definition
|
||||
} else if (currentScope->kind != StatementKind::skClass)
|
||||
break;
|
||||
//variable can't be initialized in class definition, it must be a function
|
||||
} else if (isNotFuncArgs(mIndex + 1,mTokenizer[mIndex + 1]->matchIndex))
|
||||
} else if (isNotFuncArgs(mIndex + 1))
|
||||
break;
|
||||
}
|
||||
sName = mTokenizer[mIndex]->text;
|
||||
|
@ -1708,12 +1710,12 @@ bool CppParser::checkForPreprocessor()
|
|||
return (mTokenizer[mIndex]->text.startsWith('#'));
|
||||
}
|
||||
|
||||
bool CppParser::checkForLambda()
|
||||
{
|
||||
return (mIndex+1<mTokenizer.tokenCount()
|
||||
&& mTokenizer[mIndex]->text.startsWith('[')
|
||||
&& mTokenizer[mIndex+1]->text=='(');
|
||||
}
|
||||
//bool CppParser::checkForLambda()
|
||||
//{
|
||||
// return (mIndex+1<mTokenizer.tokenCount()
|
||||
// && mTokenizer[mIndex]->text.startsWith('[')
|
||||
// && mTokenizer[mIndex+1]->text=='(');
|
||||
//}
|
||||
|
||||
bool CppParser::checkForScope(KeywordType keywordType)
|
||||
{
|
||||
|
@ -1727,13 +1729,7 @@ bool CppParser::checkForScope(KeywordType keywordType)
|
|||
void CppParser::checkForSkipStatement()
|
||||
{
|
||||
if ((mSkipList.count()>0) && (mIndex == mSkipList.back())) { // skip to next ';'
|
||||
do {
|
||||
if (isLeftParenthesis(mTokenizer[mIndex]->text))
|
||||
mIndex=mTokenizer[mIndex]->matchIndex+1;
|
||||
else
|
||||
mIndex++;
|
||||
} while ((mIndex < mTokenizer.tokenCount()) && (mTokenizer[mIndex]->text[0] != ';'));
|
||||
mIndex++; //skip ';'
|
||||
skipNextSemicolon(mIndex);
|
||||
mSkipList.pop_back();
|
||||
}
|
||||
}
|
||||
|
@ -1819,6 +1815,189 @@ bool CppParser::checkForUsing(KeywordType keywordType)
|
|||
|
||||
}
|
||||
|
||||
void CppParser::checkAndHandleMethodOrVar()
|
||||
{
|
||||
if (mIndex+2>=mTokenizer.tokenCount()) {
|
||||
mIndex+=2; // left's finish;
|
||||
return;
|
||||
}
|
||||
QString currentText=mTokenizer[mIndex]->text;
|
||||
|
||||
mIndex++;
|
||||
//next token must be */&/word/(/{
|
||||
if (mTokenizer[mIndex]->text=='(') {
|
||||
int indexAfterParentheis=mTokenizer[mIndex]->matchIndex+1;
|
||||
if (indexAfterParentheis>=mTokenizer.tokenCount()) {
|
||||
//error
|
||||
mIndex=indexAfterParentheis;
|
||||
} else if (mTokenizer[indexAfterParentheis]->text=='(') {
|
||||
// operator overloading like (operator int)
|
||||
if (mTokenizer[mIndex+1]->text=="operator") {
|
||||
mIndex=indexAfterParentheis;
|
||||
handleMethod(StatementKind::skFunction,"",
|
||||
mergeArgs(mIndex+1,mTokenizer[mIndex]->matchIndex-1),
|
||||
indexAfterParentheis,false,false);
|
||||
} else if (currentText.endsWith("::operator")) {
|
||||
mIndex=indexAfterParentheis;
|
||||
handleMethod(StatementKind::skFunction,"",
|
||||
mergeArgs(mIndex+1,mTokenizer[mIndex]->matchIndex-1),
|
||||
indexAfterParentheis,false,false);
|
||||
} else {
|
||||
//function pointer var
|
||||
handleVar(currentText,false,false);
|
||||
}
|
||||
} else {
|
||||
if (currentText.startsWith("operator")
|
||||
&& currentText.length()>8
|
||||
&& !isIdentChar(currentText[8])) {
|
||||
// operator overloading
|
||||
handleMethod(StatementKind::skFunction,"",
|
||||
mergeArgs(mIndex+1,mTokenizer[mIndex]->matchIndex-1),
|
||||
indexAfterParentheis,false,false);
|
||||
return;
|
||||
}
|
||||
//check for constructor like Foo::Foo()
|
||||
QString name;
|
||||
QString temp,temp2;
|
||||
QString parentName;
|
||||
if (splitLastMember(currentText,name,temp)) {
|
||||
//has '::'
|
||||
bool isDestructor=false;
|
||||
if (!splitLastMember(temp,parentName,temp2))
|
||||
parentName=temp;
|
||||
if (name.startsWith('~'))
|
||||
name=name.mid(1);
|
||||
if (removeTemplateParams(name)==removeTemplateParams(parentName))
|
||||
handleMethod( (isDestructor?StatementKind::skDestructor:StatementKind::skConstructor),
|
||||
"",
|
||||
currentText,
|
||||
mIndex,false,false);
|
||||
return;
|
||||
}
|
||||
// check for constructor like:
|
||||
// class Foo {
|
||||
// Foo();
|
||||
// };
|
||||
PStatement scope=getCurrentScope();
|
||||
if (scope && scope->kind==StatementKind::skClass
|
||||
&& removeTemplateParams(scope->command) == removeTemplateParams(currentText)) {
|
||||
handleMethod(StatementKind::skConstructor,"",
|
||||
currentText,
|
||||
mIndex,false,false);
|
||||
return;
|
||||
}
|
||||
|
||||
// function call, skip it
|
||||
skipNextSemicolon(mIndex);
|
||||
}
|
||||
} else if (mTokenizer[mIndex]->text.startsWith('*')
|
||||
|| mTokenizer[mIndex]->text.startsWith('&')
|
||||
|| tokenIsIdentifier(mTokenizer[mIndex]->text)
|
||||
) {
|
||||
// it should be function/var
|
||||
|
||||
bool isStatic = false;
|
||||
bool isFriend = false;
|
||||
bool isExtern = false;
|
||||
|
||||
QString sType = currentText; // should contain type "int"
|
||||
QString sName = ""; // should contain function name "foo::function"
|
||||
|
||||
|
||||
|
||||
// Gather data for the string parts
|
||||
while (mIndex+1 < mTokenizer.tokenCount()) {
|
||||
if (mTokenizer[mIndex + 1]->text == '(') {
|
||||
if (mTokenizer[mIndex+2]->text == '*') {
|
||||
//foo(*blabla), it's a function pointer var
|
||||
handleVar(sType,isExtern,isStatic);
|
||||
return;
|
||||
}
|
||||
|
||||
int indexAfter=mTokenizer[mIndex + 1]->matchIndex+1;
|
||||
if (indexAfter>=mTokenizer.tokenCount()) {
|
||||
//error
|
||||
mIndex=indexAfter;
|
||||
return;
|
||||
}
|
||||
//if it's like: foo(...)(...)
|
||||
if (mTokenizer[indexAfter]->text=='(') {
|
||||
if (mTokenizer[mIndex]->text=="operator") {
|
||||
//operator()() , it's an operator overload for ()
|
||||
handleMethod(StatementKind::skFunction,sType,
|
||||
"operator()",indexAfter,isStatic,false);
|
||||
return;
|
||||
}
|
||||
if (mTokenizer[mIndex]->text.endsWith("::operator")) {
|
||||
// operator overloading
|
||||
handleMethod(StatementKind::skFunction,"",
|
||||
mTokenizer[mIndex]->text+"()",indexAfter,isStatic,false);
|
||||
return;
|
||||
}
|
||||
//foo(...)(...), it's a function pointer var
|
||||
handleVar(sType,isExtern,isStatic);
|
||||
//Won't implement: ignore function decl like int (text)(int x) { };
|
||||
return;
|
||||
}
|
||||
//it's not a function define
|
||||
if (mTokenizer[indexAfter]->text[0] == ',') {
|
||||
// var decl with init
|
||||
handleVar(sType,isExtern,isStatic);
|
||||
return;
|
||||
}
|
||||
if (mTokenizer[indexAfter]->text[0] == ';') {
|
||||
//function can only be defined in global/namespaces/classes
|
||||
PStatement currentScope=getCurrentScope();
|
||||
if (currentScope) {
|
||||
//in namespace, it might be function or object initilization
|
||||
if (currentScope->kind == StatementKind::skNamespace
|
||||
&& isNotFuncArgs(mIndex + 1)) {
|
||||
// var decl with init
|
||||
handleVar(sType,isExtern,isStatic);
|
||||
return;
|
||||
//not in class, it can't be a valid function definition
|
||||
} else if (currentScope->kind != StatementKind::skClass) {
|
||||
// var decl with init
|
||||
handleVar(sType,isExtern,isStatic);
|
||||
return;
|
||||
}
|
||||
//variable can't be initialized in class definition, it must be a function
|
||||
} else if (isNotFuncArgs(mIndex + 1)){
|
||||
// var decl with init
|
||||
handleVar(sType,isExtern,isStatic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
sName = mTokenizer[mIndex]->text;
|
||||
mIndex++;
|
||||
|
||||
handleMethod(StatementKind::skFunction,sType,
|
||||
sName,mIndex,isStatic,isFriend);
|
||||
|
||||
return;
|
||||
} else if (
|
||||
mTokenizer[mIndex + 1]->text == ','
|
||||
||mTokenizer[mIndex + 1]->text == ';'
|
||||
||mTokenizer[mIndex + 1]->text == ':'
|
||||
||mTokenizer[mIndex + 1]->text == '{') {
|
||||
handleVar(sType,isExtern,isStatic);
|
||||
return;
|
||||
} else {
|
||||
QString s = mTokenizer[mIndex]->text;
|
||||
if (s == "static")
|
||||
isStatic = true;
|
||||
else if (s == "friend")
|
||||
isFriend = true;
|
||||
else if (s == "extern")
|
||||
isExtern = true;
|
||||
if (!s.isEmpty() && !(s=="extern"))
|
||||
sType = sType + ' '+ s;
|
||||
mIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CppParser::getCurrentBlockEndSkip()
|
||||
{
|
||||
if (mBlockEndSkips.isEmpty())
|
||||
|
@ -2232,23 +2411,23 @@ void CppParser::handleKeyword(KeywordType skipType)
|
|||
// skip it;
|
||||
mIndex++;
|
||||
break;
|
||||
case KeywordType::SkipAfterSemicolon:
|
||||
case KeywordType::SkipNextSemicolon:
|
||||
// Skip to ; and over it
|
||||
mIndex = indexOfNextSemicolon(mIndex)+1;
|
||||
skipNextSemicolon(mIndex);
|
||||
break;
|
||||
case KeywordType::SkipAfterColon:
|
||||
case KeywordType::SkipNextColon:
|
||||
// Skip to : and over it
|
||||
mIndex = indexOfNextColon(mIndex)+1;
|
||||
break;
|
||||
case KeywordType::SkipAfterParenthesis:
|
||||
case KeywordType::SkipNextParenthesis:
|
||||
// skip pass ()
|
||||
mIndex = indexPassParenthesis(mIndex);
|
||||
skipParenthesis(mIndex);
|
||||
break;
|
||||
case KeywordType::SkipToLeftBrace:
|
||||
case KeywordType::MoveToLeftBrace:
|
||||
// Skip to {
|
||||
mIndex = indexOfNextLeftBrace(mIndex);
|
||||
break;
|
||||
case KeywordType::SkipAfterBrace:
|
||||
case KeywordType::MoveToRightBrace:
|
||||
// Skip pass {}
|
||||
mIndex = indexPassBraces(mIndex);
|
||||
break;
|
||||
|
@ -2288,19 +2467,21 @@ void CppParser::handleLambda()
|
|||
mIndex=bodyStart+1; // skip '{'
|
||||
}
|
||||
|
||||
void CppParser::handleMethod(const QString &sType, const QString &sName, int argStart, int argEnd, bool isStatic, bool isFriend)
|
||||
void CppParser::handleMethod(StatementKind functionKind,const QString &sType, const QString &sName, int argStart, bool isStatic, bool isFriend)
|
||||
{
|
||||
bool isValid = true;
|
||||
bool isDeclaration = false; // assume it's not a prototype
|
||||
int startLine = mTokenizer[mIndex]->line;
|
||||
int argEnd = mTokenizer[argStart]->matchIndex;
|
||||
|
||||
if (mIndex >= mTokenizer.tokenCount()) // not finished define, just skip it;
|
||||
return;
|
||||
|
||||
PStatement functionClass = getCurrentScope();
|
||||
PStatement scopeStatement = getCurrentScope();
|
||||
|
||||
//find start of the function body;
|
||||
bool foundColon=false;
|
||||
mIndex=argEnd+1;
|
||||
while ((mIndex < mTokenizer.tokenCount()) && !isblockChar(mTokenizer[mIndex]->text.front())) {
|
||||
if (mTokenizer[mIndex]->text=='(') {
|
||||
mIndex=mTokenizer[mIndex]->matchIndex+1;
|
||||
|
@ -2335,17 +2516,17 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
|
|||
|
||||
QString scopelessName;
|
||||
PStatement functionStatement;
|
||||
if (isFriend && isDeclaration && functionClass) {
|
||||
if (isFriend && isDeclaration && scopeStatement) {
|
||||
int delimPos = sName.indexOf("::");
|
||||
if (delimPos >= 0) {
|
||||
scopelessName = sName.mid(delimPos+2);
|
||||
} else
|
||||
scopelessName = sName;
|
||||
//TODO : we should check namespace
|
||||
functionClass->friends.insert(scopelessName);
|
||||
scopeStatement->friends.insert(scopelessName);
|
||||
} else if (isValid) {
|
||||
// Use the class the function belongs to as the parent ID if the function is declared outside of the class body
|
||||
int delimPos = sName.indexOf("::");
|
||||
int delimPos = sName.lastIndexOf("::");
|
||||
QString scopelessName;
|
||||
QString parentClassName;
|
||||
if (delimPos >= 0) {
|
||||
|
@ -2354,24 +2535,15 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
|
|||
|
||||
// Check what class this function belongs to
|
||||
parentClassName = sName.mid(0, delimPos);
|
||||
functionClass = getIncompleteClass(parentClassName,getCurrentScope());
|
||||
scopeStatement = getIncompleteClass(parentClassName,getCurrentScope());
|
||||
} else
|
||||
scopelessName = sName;
|
||||
|
||||
StatementKind functionKind;
|
||||
// Determine function type
|
||||
if (scopelessName == sType) {
|
||||
functionKind = StatementKind::skConstructor;
|
||||
} else if (scopelessName == '~' + sType) {
|
||||
functionKind = StatementKind::skDestructor;
|
||||
} else {
|
||||
functionKind = StatementKind::skFunction;
|
||||
}
|
||||
|
||||
// For function definitions, the parent class is given. Only use that as a parent
|
||||
if (!isDeclaration) {
|
||||
functionStatement=addStatement(
|
||||
functionClass,
|
||||
scopeStatement,
|
||||
mCurrentFile,
|
||||
sType,
|
||||
scopelessName,
|
||||
|
@ -2387,13 +2559,13 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
|
|||
isStatic);
|
||||
scanMethodArgs(functionStatement, argStart,argEnd);
|
||||
// add variable this to the class function
|
||||
if (functionClass && functionClass->kind == StatementKind::skClass &&
|
||||
if (scopeStatement && scopeStatement->kind == StatementKind::skClass &&
|
||||
!isStatic) {
|
||||
//add this to non-static class member function
|
||||
addStatement(
|
||||
functionStatement,
|
||||
mCurrentFile,
|
||||
functionClass->command,
|
||||
scopeStatement->command+"*",
|
||||
"this",
|
||||
"",
|
||||
"",
|
||||
|
@ -2405,6 +2577,7 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
|
|||
true,
|
||||
false);
|
||||
}
|
||||
|
||||
// add "__func__ variable"
|
||||
addStatement(
|
||||
functionStatement,
|
||||
|
@ -2420,9 +2593,10 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
|
|||
StatementClassScope::None,
|
||||
true,
|
||||
false);
|
||||
|
||||
} else {
|
||||
functionStatement = addStatement(
|
||||
functionClass,
|
||||
scopeStatement,
|
||||
mCurrentFile,
|
||||
sType,
|
||||
scopelessName,
|
||||
|
@ -2440,7 +2614,6 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
|
|||
|
||||
}
|
||||
|
||||
|
||||
if ((mIndex < mTokenizer.tokenCount()) && mTokenizer[mIndex]->text.startsWith('{')) {
|
||||
addSoloScopeLevel(functionStatement,startLine);
|
||||
mIndex++; //skip '{'
|
||||
|
@ -2452,7 +2625,6 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
|
|||
removeScopeLevel(startLine+1);
|
||||
mIndex++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CppParser::handleNamespace(KeywordType skipType)
|
||||
|
@ -2467,9 +2639,9 @@ void CppParser::handleNamespace(KeywordType skipType)
|
|||
|
||||
mIndex++; //skip 'namespace'
|
||||
|
||||
if (!isLetterChar(mTokenizer[mIndex]->text.front()))
|
||||
//wrong namespace define, stop handling
|
||||
return;
|
||||
// if (!tokenIsIdentifier(mTokenizer[mIndex]->text))
|
||||
// //wrong namespace define, stop handling
|
||||
// return;
|
||||
QString command = mTokenizer[mIndex]->text;
|
||||
|
||||
QString fullName = getFullStatementName(command,getCurrentScope());
|
||||
|
@ -2747,8 +2919,6 @@ void CppParser::handleScope(KeywordType keywordType)
|
|||
bool CppParser::handleStatement()
|
||||
{
|
||||
QString funcType,funcName;
|
||||
int argStart,argEnd;
|
||||
bool isStatic, isFriend;
|
||||
int idx=getCurrentBlockEndSkip();
|
||||
int idx2=getCurrentBlockBeginSkip();
|
||||
int idx3=getCurrentInlineNamespaceEndSkip();
|
||||
|
@ -2796,10 +2966,30 @@ bool CppParser::handleStatement()
|
|||
mIndex++;
|
||||
} else if (checkForPreprocessor()) {
|
||||
handlePreprocessor();
|
||||
} else if (checkForLambda()) { // is lambda
|
||||
handleLambda();
|
||||
} else if (!isLetterChar(mTokenizer[mIndex]->text[0])) {
|
||||
// } else if (checkForLambda()) { // is lambda
|
||||
// handleLambda();
|
||||
} else if (mTokenizer[mIndex]->text=='(') {
|
||||
if (mTokenizer[mIndex]->text=="operator") {
|
||||
// things like (operator int)
|
||||
mIndex++; //just skip '('
|
||||
} else
|
||||
skipParenthesis(mIndex);
|
||||
} else if (mTokenizer[mIndex]->text==')') {
|
||||
mIndex++;
|
||||
} else if (mTokenizer[mIndex]->text.startsWith('~')) {
|
||||
//it should be a destructor
|
||||
if (mIndex+1<mTokenizer.tokenCount()
|
||||
&& mTokenizer[mIndex+1]->text=='(') {
|
||||
//dont further check to speed up
|
||||
handleMethod(StatementKind::skDestructor, "", '~'+mTokenizer[mIndex]->text, mIndex+1, false, false);
|
||||
} else {
|
||||
skipNextSemicolon(mIndex);
|
||||
}
|
||||
} else if (!isIdentChar(mTokenizer[mIndex]->text[0])) {
|
||||
skipNextSemicolon(mIndex);
|
||||
} else if (mTokenizer[mIndex]->text.endsWith('.')
|
||||
|| mTokenizer[mIndex]->text.endsWith("->")) {
|
||||
skipNextSemicolon(mIndex);
|
||||
} else if (checkForKeyword(keywordType)) { // includes template now
|
||||
handleKeyword(keywordType);
|
||||
} else if (keywordType==KeywordType::For) { // (for/catch)
|
||||
|
@ -2828,13 +3018,19 @@ bool CppParser::handleStatement()
|
|||
handleUsing();
|
||||
} else if (checkForStructs(keywordType)) {
|
||||
handleStructs(false);
|
||||
} else if (checkForMethod(funcType, funcName, argStart,argEnd, isStatic, isFriend)) {
|
||||
handleMethod(funcType, funcName, argStart, argEnd, isStatic, isFriend); // don't recalculate parts
|
||||
} else if (tryHandleVar()) {
|
||||
//do nothing
|
||||
} else
|
||||
mIndex++;
|
||||
} else {
|
||||
// it should be method/constructor/var
|
||||
checkAndHandleMethodOrVar();
|
||||
}
|
||||
Q_ASSERT(mIndex<999999);
|
||||
// else if (checkForMethod(funcType, funcName, argStart,argEnd, isStatic, isFriend)) {
|
||||
// handleMethod(funcType, funcName, argStart, argEnd, isStatic, isFriend); // don't recalculate parts
|
||||
// } else if (tryHandleVar()) {
|
||||
// //do nothing
|
||||
// } else
|
||||
// mIndex++;
|
||||
|
||||
//todo: remove mSkipList (we can check '}''s statement type instead)
|
||||
checkForSkipStatement();
|
||||
|
||||
return mIndex < mTokenizer.tokenCount();
|
||||
|
@ -2947,6 +3143,7 @@ void CppParser::handleStructs(bool isTypedef)
|
|||
command = "";
|
||||
}
|
||||
mIndex++;
|
||||
break;
|
||||
} else if ((mIndex + 2 < mTokenizer.tokenCount())
|
||||
&& (mTokenizer[mIndex + 1]->text == "final")
|
||||
&& (mTokenizer[mIndex + 2]->text.front()==','
|
||||
|
@ -2971,6 +3168,7 @@ void CppParser::handleStructs(bool isTypedef)
|
|||
command="";
|
||||
}
|
||||
mIndex+=2;
|
||||
break;
|
||||
} else
|
||||
mIndex++;
|
||||
}
|
||||
|
@ -2980,8 +3178,7 @@ void CppParser::handleStructs(bool isTypedef)
|
|||
if ((mIndex < mTokenizer.tokenCount()) && (mTokenizer[mIndex]->text.front() == ':')) {
|
||||
if (firstSynonym)
|
||||
setInheritance(mIndex, firstSynonym, isStruct); // set the _InheritanceList value
|
||||
while ((mIndex < mTokenizer.tokenCount()) && (mTokenizer[mIndex]->text.front() != '{'))
|
||||
mIndex++; // skip decl after ':'
|
||||
mIndex=indexOfNextLeftBrace(mIndex);
|
||||
}
|
||||
|
||||
// Check for struct synonyms after close brace
|
||||
|
@ -3087,7 +3284,7 @@ void CppParser::handleStructs(bool isTypedef)
|
|||
}
|
||||
}
|
||||
if (!firstSynonym) {
|
||||
//anonymous union/struct/class, add ast a block
|
||||
//anonymous union/struct/class, add as a block
|
||||
firstSynonym=addStatement(
|
||||
getCurrentScope(),
|
||||
mCurrentFile,
|
||||
|
@ -3201,77 +3398,65 @@ void CppParser::handleUsing()
|
|||
}
|
||||
}
|
||||
|
||||
bool CppParser::tryHandleVar()
|
||||
void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
|
||||
{
|
||||
int indexBackup=mIndex;
|
||||
KeywordType keywordType;
|
||||
QString varType=mTokenizer[mIndex]->text;
|
||||
bool isExtern = false;
|
||||
bool isStatic = false;
|
||||
QString lastType;
|
||||
if (isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front())
|
||||
|| mTokenizer[mIndex]->text.endsWith('.')
|
||||
|| mTokenizer[mIndex]->text.endsWith("->"))
|
||||
//failed to handle
|
||||
return false;
|
||||
if (varType=="extern") {
|
||||
if (typePrefix=="extern") {
|
||||
isExtern=true;
|
||||
} else if (varType=="static") {
|
||||
} else if (typePrefix=="static") {
|
||||
isStatic=true;
|
||||
} else {
|
||||
lastType=varType;
|
||||
lastType=typePrefix;
|
||||
}
|
||||
mIndex++;
|
||||
|
||||
|
||||
//we only check the first token to reduce calculations
|
||||
if (mIndex>=mTokenizer.tokenCount()
|
||||
|| checkForKeyword(keywordType)
|
||||
|| isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front())
|
||||
|| mTokenizer[mIndex]->text.endsWith('.')
|
||||
|| mTokenizer[mIndex]->text.endsWith("->")) {
|
||||
//failed to handle
|
||||
mIndex=indexBackup;
|
||||
return false;
|
||||
}
|
||||
// if (mIndex>=mTokenizer.tokenCount()
|
||||
// || mTokenizer[mIndex]->text.endsWith('.')
|
||||
// || mTokenizer[mIndex]->text.endsWith("->")) {
|
||||
// //failed to handle
|
||||
// skipNextSemicolon(mIndex);
|
||||
// return ;
|
||||
// }
|
||||
|
||||
while (mIndex+1<mTokenizer.tokenCount()) {
|
||||
if (mTokenizer[mIndex]->text=='(') {
|
||||
if ( mTokenizer[mIndex]->matchIndex<=mTokenizer.tokenCount()
|
||||
&& mTokenizer[mTokenizer[mIndex]->matchIndex]->text=='(') {
|
||||
//function pointer
|
||||
break;
|
||||
}
|
||||
//error break;
|
||||
mIndex=indexBackup;
|
||||
return false;
|
||||
} else if (mTokenizer[mIndex + 1]->text=='('
|
||||
|| mTokenizer[mIndex + 1]->text==','
|
||||
|| mTokenizer[mIndex + 1]->text==';'
|
||||
|| mTokenizer[mIndex + 1]->text.front()==':'
|
||||
|| mTokenizer[mIndex + 1]->text=='}'
|
||||
|| mTokenizer[mIndex + 1]->text.front()=='#'
|
||||
|| mTokenizer[mIndex + 1]->text=='{') {
|
||||
//end of type info
|
||||
break;
|
||||
} else if (mTokenizer[mIndex]->text!="struct"
|
||||
&& mTokenizer[mIndex]->text!="class"
|
||||
&& mTokenizer[mIndex]->text!="union") {
|
||||
QString s=mTokenizer[mIndex]->text;
|
||||
if (s == "extern") {
|
||||
isExtern = true;
|
||||
} else if (s == "static") {
|
||||
isStatic = true;
|
||||
} else
|
||||
lastType += ' '+s;
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
// while (mIndex+1<mTokenizer.tokenCount()) {
|
||||
// if (mTokenizer[mIndex]->text=='(') {
|
||||
// if ( mTokenizer[mIndex]->matchIndex<=mTokenizer.tokenCount()
|
||||
// && mTokenizer[mTokenizer[mIndex]->matchIndex]->text=='(') {
|
||||
// //function pointer
|
||||
// break;
|
||||
// }
|
||||
// //error break;
|
||||
// mIndex=indexBackup;
|
||||
// return false;
|
||||
// } else if (mTokenizer[mIndex + 1]->text=='('
|
||||
// || mTokenizer[mIndex + 1]->text==','
|
||||
// || mTokenizer[mIndex + 1]->text==';'
|
||||
// || mTokenizer[mIndex + 1]->text.front()==':'
|
||||
// || mTokenizer[mIndex + 1]->text=='}'
|
||||
// || mTokenizer[mIndex + 1]->text.front()=='#'
|
||||
// || mTokenizer[mIndex + 1]->text=='{') {
|
||||
// //end of type info
|
||||
// break;
|
||||
// } else if (mTokenizer[mIndex]->text!="struct"
|
||||
// && mTokenizer[mIndex]->text!="class"
|
||||
// && mTokenizer[mIndex]->text!="union") {
|
||||
// QString s=mTokenizer[mIndex]->text;
|
||||
// if (s == "extern") {
|
||||
// isExtern = true;
|
||||
// } else if (s == "static") {
|
||||
// isStatic = true;
|
||||
// } else
|
||||
// lastType += ' '+s;
|
||||
// }
|
||||
// mIndex++;
|
||||
// }
|
||||
|
||||
if (mIndex+1 >= mTokenizer.tokenCount() || lastType.isEmpty()
|
||||
|| lastType.endsWith(':')) {
|
||||
mIndex=indexBackup;
|
||||
return false;
|
||||
}
|
||||
// if (mIndex+1 >= mTokenizer.tokenCount() || lastType.isEmpty()
|
||||
// || lastType.endsWith(':')) {
|
||||
// mIndex=indexBackup;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
bool varAdded = false;
|
||||
QString tempType;
|
||||
|
@ -3365,8 +3550,6 @@ bool CppParser::tryHandleVar()
|
|||
}
|
||||
// Skip ;
|
||||
mIndex++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CppParser::internalParse(const QString &fileName)
|
||||
|
@ -4505,6 +4688,8 @@ void CppParser::scanMethodArgs(const PStatement& functionStatement, int argStart
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (!varType.isEmpty())
|
||||
varType+=' ';
|
||||
varType+=cmd;
|
||||
}
|
||||
i++;
|
||||
|
@ -4585,118 +4770,49 @@ QString CppParser::splitPhrase(const QString &phrase, QString &sClazz,
|
|||
return result;
|
||||
}
|
||||
|
||||
QString CppParser::removeTemplateParams(const QString &phrase)
|
||||
{
|
||||
int pos = phrase.indexOf('<');
|
||||
if (pos>=0) {
|
||||
return phrase.left(pos);
|
||||
}
|
||||
return phrase;
|
||||
}
|
||||
|
||||
bool CppParser::splitLastMember(const QString &token, QString &lastMember, QString &remaining)
|
||||
{
|
||||
int pos = token.lastIndexOf("::");
|
||||
if (pos<0)
|
||||
return false;
|
||||
lastMember=token.mid(pos+2);
|
||||
remaining=token.left(pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isIdentChar(const QChar& ch) {
|
||||
return ch.isLetter()
|
||||
|| ch == '_'
|
||||
|| ch.isDigit();
|
||||
}
|
||||
|
||||
static void appendArgWord(QString& args, const QString& word) {
|
||||
QString s=word.trimmed();
|
||||
if (s.isEmpty())
|
||||
return;
|
||||
if (args.isEmpty())
|
||||
args.append(s);
|
||||
else if (isIdentChar(args.back()) && isIdentChar(word.front()) ) {
|
||||
args+=" ";
|
||||
args+=s;
|
||||
} else {
|
||||
args+=s;
|
||||
}
|
||||
}
|
||||
QString CppParser::removeArgNames(const QString &args)
|
||||
{
|
||||
QString result = "";
|
||||
int argsLen = args.length();
|
||||
if (argsLen < 2)
|
||||
return "";
|
||||
int i=1; // skip start '('
|
||||
QString currentArg;
|
||||
QString word;
|
||||
int brackLevel = 0;
|
||||
bool typeGetted = false;
|
||||
while (i<argsLen-1) { //skip end ')'
|
||||
switch(args[i].unicode()) {
|
||||
case ',':
|
||||
if (brackLevel >0) {
|
||||
word+=args[i];
|
||||
} else {
|
||||
if (!typeGetted) {
|
||||
appendArgWord(currentArg,word);
|
||||
} else {
|
||||
if (isCppKeyword(word)) {
|
||||
appendArgWord(currentArg,word);
|
||||
}
|
||||
}
|
||||
word = "";
|
||||
result += currentArg.trimmed() + ',';
|
||||
currentArg = "";
|
||||
typeGetted = false;
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
case '[':
|
||||
case '(':
|
||||
brackLevel++;
|
||||
word+=args[i];
|
||||
break;
|
||||
case '>':
|
||||
case ']':
|
||||
case ')':
|
||||
brackLevel--;
|
||||
word+=args[i];
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
if ((brackLevel >0) && !isSpaceChar(args[i-1])) {
|
||||
word+=args[i];
|
||||
} else if (!word.isEmpty()) {
|
||||
if (!typeGetted) {
|
||||
appendArgWord(currentArg,word);
|
||||
if (mCppTypeKeywords.contains(word) || !isCppKeyword(word))
|
||||
typeGetted = true;
|
||||
} else {
|
||||
if (isCppKeyword(word))
|
||||
appendArgWord(currentArg,word);
|
||||
}
|
||||
word = "";
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
case '*':
|
||||
if (!word.isEmpty()) {
|
||||
if (!typeGetted) {
|
||||
appendArgWord(currentArg,word);
|
||||
if (mCppTypeKeywords.contains(word) || !isCppKeyword(word))
|
||||
typeGetted = true;
|
||||
} else {
|
||||
if (isCppKeyword(word))
|
||||
appendArgWord(currentArg,word);
|
||||
}
|
||||
word = "";
|
||||
}
|
||||
currentArg+=args[i];
|
||||
break;
|
||||
default:
|
||||
if (isIdentChar(args[i])) {
|
||||
word+=args[i];
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!typeGetted) {
|
||||
appendArgWord(currentArg,word);
|
||||
} else {
|
||||
if (isCppKeyword(word)) {
|
||||
appendArgWord(currentArg,word);
|
||||
}
|
||||
}
|
||||
result += currentArg.trimmed();
|
||||
return result;
|
||||
}
|
||||
//static void appendArgWord(QString& args, const QString& word) {
|
||||
// QString s=word.trimmed();
|
||||
// if (s.isEmpty())
|
||||
// return;
|
||||
// if (args.isEmpty())
|
||||
// args.append(s);
|
||||
// else if (isIdentChar(args.back()) && isIdentChar(word.front()) ) {
|
||||
// args+=" ";
|
||||
// args+=s;
|
||||
// } else {
|
||||
// args+=s;
|
||||
// }
|
||||
//}
|
||||
|
||||
bool CppParser::isNotFuncArgs(int startIndex, int endIndex)
|
||||
bool CppParser::isNotFuncArgs(int startIndex)
|
||||
{
|
||||
Q_ASSERT(mTokenizer[startIndex]->text=='(');
|
||||
int endIndex=mTokenizer[startIndex]->matchIndex;
|
||||
//no args, it must be a function
|
||||
if (endIndex-startIndex==1)
|
||||
return false;
|
||||
|
@ -4709,25 +4825,37 @@ bool CppParser::isNotFuncArgs(int startIndex, int endIndex)
|
|||
// args contains a string/char, can't be a func define
|
||||
case '"':
|
||||
case '\'':
|
||||
return true;
|
||||
case '(':
|
||||
case '[':
|
||||
case '+':
|
||||
case '-':
|
||||
case '/':
|
||||
case '|':
|
||||
case '!':
|
||||
case '{':
|
||||
return true;
|
||||
case '[': // function args like int f[10]
|
||||
i=mTokenizer[i]->matchIndex+1;
|
||||
if (i<endPos &&
|
||||
(mTokenizer[i]->text=='('
|
||||
|| mTokenizer[i]->text=='{')) //lambda
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
if (isDigitChar(ch))
|
||||
return true;
|
||||
if (isLetterChar(ch)) {
|
||||
if (isIdentChar(ch)) {
|
||||
QString currentText=mTokenizer[i]->text;
|
||||
while (currentText.startsWith('*')
|
||||
|| currentText.startsWith('&'))
|
||||
currentText.remove(0,1);
|
||||
if (mTokenizer[i]->text.endsWith('.'))
|
||||
return true;
|
||||
if (mTokenizer[i]->text.endsWith("->"))
|
||||
return true;
|
||||
if (!mCppTypeKeywords.contains(currentText)) {
|
||||
if (currentText=="true" || currentText=="false" || currentText=="nullptr" ||
|
||||
currentText=='this')
|
||||
return true;
|
||||
if (currentText=="const" )
|
||||
if (currentText=="const")
|
||||
return false;
|
||||
|
||||
if (isCppKeyword(currentText))
|
||||
return false;
|
||||
|
||||
PStatement statement =findStatementOf(mCurrentFile,word,getCurrentScope(),true);
|
||||
|
@ -4867,6 +4995,38 @@ int CppParser::indexPassBraces(int index)
|
|||
return index;
|
||||
}
|
||||
|
||||
void CppParser::skipNextSemicolon(int index)
|
||||
{
|
||||
mIndex=index;
|
||||
while (mIndex<mTokenizer.tokenCount()) {
|
||||
switch(mTokenizer[mIndex]->text[0].unicode()) {
|
||||
case ';':
|
||||
mIndex++;
|
||||
return;
|
||||
case '{':
|
||||
mIndex = mTokenizer[mIndex]->matchIndex+1;
|
||||
break;
|
||||
case '(':
|
||||
mIndex = mTokenizer[mIndex]->matchIndex+1;
|
||||
break;
|
||||
default:
|
||||
mIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppParser::skipParenthesis(int index)
|
||||
{
|
||||
mIndex=index;
|
||||
while (mIndex<mTokenizer.tokenCount()) {
|
||||
if (mTokenizer[mIndex]->text=='(') {
|
||||
mIndex=mTokenizer[mIndex]->matchIndex+1;
|
||||
return;
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
QString CppParser::mergeArgs(int startIndex, int endIndex)
|
||||
{
|
||||
QString result;
|
||||
|
|
|
@ -214,7 +214,7 @@ private:
|
|||
int &argEndIndex, bool &isStatic, bool &isFriend); // caching of results
|
||||
bool checkForNamespace(KeywordType keywordType);
|
||||
bool checkForPreprocessor();
|
||||
bool checkForLambda();
|
||||
// bool checkForLambda();
|
||||
bool checkForScope(KeywordType keywordType);
|
||||
void checkForSkipStatement();
|
||||
bool checkForStructs(KeywordType keywordType);
|
||||
|
@ -222,6 +222,8 @@ private:
|
|||
bool checkForTypedefStruct();
|
||||
bool checkForUsing(KeywordType keywordType);
|
||||
|
||||
void checkAndHandleMethodOrVar();
|
||||
|
||||
void fillListOfFunctions(const QString& fileName, int line,
|
||||
const PStatement& statement,
|
||||
const PStatement& scopeStatement, QStringList& list);
|
||||
|
@ -321,7 +323,7 @@ private:
|
|||
void doSkipInExpression(const QStringList& expression, int&pos, const QString& startSymbol, const QString& endSymbol);
|
||||
|
||||
bool isIdentifier(const QString& token) const {
|
||||
return (!token.isEmpty() && isLetterChar(token.front())
|
||||
return (!token.isEmpty() && isIdentChar(token.front())
|
||||
&& !token.contains('\"'));
|
||||
}
|
||||
|
||||
|
@ -333,7 +335,7 @@ private:
|
|||
case '\'':
|
||||
return false;
|
||||
default:
|
||||
return isLetterChar(term[0]);
|
||||
return isIdentChar(term[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,6 +363,16 @@ private:
|
|||
return false;
|
||||
return (token.startsWith('\''));
|
||||
}
|
||||
|
||||
bool isKeyword(const QString& token) const {
|
||||
return mCppKeywords.contains(token);
|
||||
}
|
||||
|
||||
bool tokenIsIdentifier(const QString& token) const {
|
||||
//token won't be empty
|
||||
return isIdentChar(token[0]);
|
||||
}
|
||||
|
||||
PStatement doParseEvalTypeInfo(
|
||||
const QString& fileName,
|
||||
const PStatement& scope,
|
||||
|
@ -402,10 +414,10 @@ private:
|
|||
void handleKeyword(KeywordType skipType);
|
||||
void handleLambda();
|
||||
void handleMethod(
|
||||
StatementKind functionKind,
|
||||
const QString& sType,
|
||||
const QString& sName,
|
||||
int argStart,
|
||||
int argEnd,
|
||||
bool isStatic,
|
||||
bool isFriend);
|
||||
void handleNamespace(KeywordType skipType);
|
||||
|
@ -415,7 +427,7 @@ private:
|
|||
bool handleStatement();
|
||||
void handleStructs(bool isTypedef = false);
|
||||
void handleUsing();
|
||||
bool tryHandleVar();
|
||||
void handleVar(const QString& typePrefix,bool isExtern,bool isStatic);
|
||||
void internalParse(const QString& fileName);
|
||||
// function FindMacroDefine(const Command: AnsiString): PStatement;
|
||||
void inheritClassStatement(
|
||||
|
@ -443,8 +455,9 @@ private:
|
|||
int argEnd);
|
||||
QString splitPhrase(const QString& phrase, QString& sClazz,
|
||||
QString& sOperator, QString &sMember);
|
||||
QString removeTemplateParams(const QString& phrase);
|
||||
|
||||
QString removeArgNames(const QString& args);
|
||||
bool splitLastMember(const QString& token, QString& lastMember, QString& remaining);
|
||||
|
||||
bool isSpaceChar(const QChar& ch) const {
|
||||
return ch==' ' || ch =='\t';
|
||||
|
@ -457,7 +470,14 @@ private:
|
|||
|| ch == '&';
|
||||
}
|
||||
|
||||
bool isLetterChar(const QChar& ch) const {
|
||||
bool isIdentifier(const QChar& ch) const {
|
||||
return ch.isLetter()
|
||||
|| ch == '_'
|
||||
|| ch == '~'
|
||||
;
|
||||
}
|
||||
|
||||
bool isIdentChar(const QChar& ch) const {
|
||||
return ch.isLetter()
|
||||
|| ch == '_';
|
||||
}
|
||||
|
@ -499,10 +519,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
bool isLeftParenthesis(const QString& text) const {
|
||||
return text=="(";
|
||||
}
|
||||
|
||||
/*';', '{', '}'*/
|
||||
bool isblockChar(const QChar& ch) const {
|
||||
switch(ch.unicode()){
|
||||
|
@ -545,7 +561,7 @@ private:
|
|||
return ch=='\n' || ch=='\r';
|
||||
}
|
||||
|
||||
bool isNotFuncArgs(int startIndex, int endIndex);
|
||||
bool isNotFuncArgs(int startIndex);
|
||||
|
||||
/**
|
||||
* @brief Test if a statement is a class/struct/union/namespace/function
|
||||
|
@ -569,6 +585,8 @@ private:
|
|||
int indexOfNextLeftBrace(int index);
|
||||
int indexPassParenthesis(int index);
|
||||
int indexPassBraces(int index);
|
||||
void skipNextSemicolon(int index);
|
||||
void skipParenthesis(int index);
|
||||
QString mergeArgs(int startIndex, int endIndex);
|
||||
void parseCommandTypeAndArgs(QString& command,
|
||||
QString& typeSuffix,
|
||||
|
|
|
@ -112,6 +112,7 @@ void CppTokenizer::addToken(const QString &sText, int iLine, TokenType tokenType
|
|||
PToken token = std::make_shared<Token>();
|
||||
token->text = sText;
|
||||
token->line = iLine;
|
||||
token->matchIndex = 1000000000;
|
||||
switch(tokenType) {
|
||||
case TokenType::LeftBrace:
|
||||
token->matchIndex=-1;
|
||||
|
@ -167,15 +168,6 @@ void CppTokenizer::countLines()
|
|||
}
|
||||
}
|
||||
|
||||
QString CppTokenizer::getLambdaCaptures()
|
||||
{
|
||||
QChar* offset = mCurrent;
|
||||
skipPair('[', ']');
|
||||
QString result(offset,mCurrent-offset);
|
||||
skipToNextToken();
|
||||
return result;
|
||||
}
|
||||
|
||||
QString CppTokenizer::getForInit()
|
||||
{
|
||||
QChar* startOffset = mCurrent;
|
||||
|
@ -290,33 +282,18 @@ QString CppTokenizer::getNextToken(TokenType *pTokenType, bool bSkipArray, bool
|
|||
done = true;
|
||||
break;
|
||||
case '[':
|
||||
{
|
||||
// QChar* backup=mCurrent;
|
||||
// skipPair('[',']');
|
||||
// skipToNextToken();
|
||||
// qDebug()<<*mCurrent;
|
||||
// if (*mCurrent!='(') {
|
||||
// mCurrent=backup;
|
||||
// advance();
|
||||
// } else {
|
||||
// mCurrent=backup;
|
||||
// skipPair('[',']');
|
||||
// *pTokenType=TokenType::LambdaCaptures;
|
||||
// countLines();
|
||||
// result = QString(backup,mCurrent-backup);
|
||||
// done = true;
|
||||
// qDebug()<<"yes"<<result;
|
||||
// }
|
||||
|
||||
*pTokenType=TokenType::LambdaCaptures;
|
||||
countLines();
|
||||
QChar* backup=mCurrent;
|
||||
skipPair('[',']');
|
||||
result = QString(backup,mCurrent-backup);
|
||||
done = true;
|
||||
// qDebug()<<"yes"<<result;
|
||||
if (*(mCurrent+1)!='[') {
|
||||
*pTokenType=TokenType::LambdaCaptures;
|
||||
countLines();
|
||||
QChar* backup=mCurrent;
|
||||
skipPair('[',']');
|
||||
result = QString(backup,mCurrent-backup);
|
||||
done = true;
|
||||
} else {
|
||||
skipPair('[',']'); // attribute, skipit
|
||||
advance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ')':
|
||||
*pTokenType=TokenType::RightParenthesis;
|
||||
countLines();
|
||||
|
@ -430,10 +407,11 @@ QString CppTokenizer::getWord(bool bSkipParenthesis, bool bSkipArray, bool bSkip
|
|||
|
||||
// Skip template contents, but keep template variable types
|
||||
if (*mCurrent == '<') {
|
||||
offset = mCurrent; //we don't skip
|
||||
skipTemplateArgs();
|
||||
offset = mCurrent;
|
||||
|
||||
if (!bFoundTemplate) {
|
||||
if (bFoundTemplate) {
|
||||
skipTemplateArgs();
|
||||
} else if (skipAngleBracketPair()){
|
||||
result += QString(offset, mCurrent-offset);
|
||||
skipToNextToken();
|
||||
}
|
||||
|
@ -630,6 +608,61 @@ void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, const QSet<QC
|
|||
}
|
||||
}
|
||||
|
||||
bool CppTokenizer::skipAngleBracketPair()
|
||||
{
|
||||
QChar* backup=mCurrent;
|
||||
int level=0;
|
||||
while (*mCurrent != '\0') {
|
||||
switch((*mCurrent).unicode()) {
|
||||
case '<':
|
||||
case '(':
|
||||
case '[':
|
||||
level++;
|
||||
break;
|
||||
case ')':
|
||||
case ']':
|
||||
level--;
|
||||
if (level==0) {
|
||||
mCurrent=backup;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
level--;
|
||||
if (level==0) {
|
||||
mCurrent++; //skip over >
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
case '}':
|
||||
case ';':
|
||||
case '"':
|
||||
case '\'':
|
||||
mCurrent=backup;
|
||||
return false;
|
||||
case '-':
|
||||
if (*(mCurrent+1)=='>') {
|
||||
mCurrent=backup;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (*(mCurrent+1)!='.') {
|
||||
mCurrent=backup;
|
||||
return false;
|
||||
}
|
||||
// skip
|
||||
while (*(mCurrent+1)=='.')
|
||||
mCurrent++;
|
||||
break;
|
||||
}
|
||||
mCurrent++;
|
||||
}
|
||||
mCurrent=backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
void CppTokenizer::skipRawString()
|
||||
{
|
||||
mCurrent++; //skip R
|
||||
|
@ -678,17 +711,8 @@ void CppTokenizer::skipTemplateArgs()
|
|||
{
|
||||
if (*mCurrent != '<')
|
||||
return;
|
||||
QChar* start = mCurrent;
|
||||
|
||||
QSet<QChar> failSet;
|
||||
failSet.insert('{');
|
||||
failSet.insert('}');
|
||||
failSet.insert(';');
|
||||
skipPair('<', '>', failSet);
|
||||
|
||||
// if we failed, return to where we came from
|
||||
if (start!=mCurrent && *(mCurrent - 1) != '>')
|
||||
mCurrent = start;
|
||||
skipPair('<', '>');
|
||||
}
|
||||
|
||||
void CppTokenizer::skipToEOL()
|
||||
|
|
|
@ -56,7 +56,6 @@ private:
|
|||
void advance();
|
||||
void countLines();
|
||||
PToken getToken(int index);
|
||||
QString getLambdaCaptures();
|
||||
|
||||
QString getForInit();
|
||||
QString getNextToken(
|
||||
|
@ -79,6 +78,7 @@ private:
|
|||
void skipAssignment();
|
||||
void skipDoubleQuotes();
|
||||
void skipPair(const QChar& cStart, const QChar cEnd, const QSet<QChar>& failChars = QSet<QChar>());
|
||||
bool skipAngleBracketPair();
|
||||
void skipRawString();
|
||||
void skipSingleQuote();
|
||||
void skipSplitLine();
|
||||
|
|
|
@ -79,7 +79,6 @@ void initParser()
|
|||
CppKeywords.insert("or_eq",KeywordType::SkipItself);
|
||||
CppKeywords.insert("register",KeywordType::SkipItself);
|
||||
CppKeywords.insert("reinterpret_cast",KeywordType::SkipItself);
|
||||
CppKeywords.insert("static_assert",KeywordType::SkipItself);
|
||||
CppKeywords.insert("static_cast",KeywordType::SkipItself);
|
||||
CppKeywords.insert("template",KeywordType::SkipItself);
|
||||
//CppKeywords.insert("this",SkipType::skItself);
|
||||
|
@ -97,32 +96,34 @@ void initParser()
|
|||
CppKeywords.insert("try",KeywordType::SkipItself);
|
||||
|
||||
// Skip to ;
|
||||
CppKeywords.insert("delete",KeywordType::SkipAfterSemicolon);
|
||||
CppKeywords.insert("delete[]",KeywordType::SkipAfterSemicolon);
|
||||
CppKeywords.insert("goto",KeywordType::SkipAfterSemicolon);
|
||||
CppKeywords.insert("new",KeywordType::SkipAfterSemicolon);
|
||||
CppKeywords.insert("return",KeywordType::SkipAfterSemicolon);
|
||||
CppKeywords.insert("throw",KeywordType::SkipAfterSemicolon);
|
||||
CppKeywords.insert("delete",KeywordType::SkipNextSemicolon);
|
||||
CppKeywords.insert("delete[]",KeywordType::SkipNextSemicolon);
|
||||
CppKeywords.insert("goto",KeywordType::SkipNextSemicolon);
|
||||
CppKeywords.insert("new",KeywordType::SkipNextSemicolon);
|
||||
CppKeywords.insert("return",KeywordType::SkipNextSemicolon);
|
||||
CppKeywords.insert("throw",KeywordType::SkipNextSemicolon);
|
||||
// CppKeywords.insert("using",SkipType::skToSemicolon); //won't use it
|
||||
|
||||
// Skip to :
|
||||
CppKeywords.insert("case",KeywordType::SkipAfterColon);
|
||||
CppKeywords.insert("default",KeywordType::SkipAfterColon);
|
||||
CppKeywords.insert("case",KeywordType::SkipNextColon);
|
||||
CppKeywords.insert("default",KeywordType::SkipNextColon);
|
||||
|
||||
// Skip to )
|
||||
CppKeywords.insert("__attribute__",KeywordType::SkipAfterParenthesis);
|
||||
CppKeywords.insert("alignas",KeywordType::SkipAfterParenthesis); // not right
|
||||
CppKeywords.insert("alignof",KeywordType::SkipAfterParenthesis); // not right
|
||||
CppKeywords.insert("decltype",KeywordType::SkipAfterParenthesis); // not right
|
||||
CppKeywords.insert("if",KeywordType::SkipAfterParenthesis);
|
||||
CppKeywords.insert("sizeof",KeywordType::SkipAfterParenthesis);
|
||||
CppKeywords.insert("switch",KeywordType::SkipAfterParenthesis);
|
||||
CppKeywords.insert("typeid",KeywordType::SkipAfterParenthesis);
|
||||
CppKeywords.insert("while",KeywordType::SkipAfterParenthesis);
|
||||
CppKeywords.insert("__attribute__",KeywordType::SkipNextParenthesis);
|
||||
CppKeywords.insert("__attribute",KeywordType::SkipNextParenthesis);
|
||||
CppKeywords.insert("alignas",KeywordType::SkipNextParenthesis); // not right
|
||||
CppKeywords.insert("alignof",KeywordType::SkipNextParenthesis); // not right
|
||||
CppKeywords.insert("decltype",KeywordType::SkipNextParenthesis); // not right
|
||||
CppKeywords.insert("if",KeywordType::SkipNextParenthesis);
|
||||
CppKeywords.insert("sizeof",KeywordType::SkipNextParenthesis);
|
||||
CppKeywords.insert("switch",KeywordType::SkipNextParenthesis);
|
||||
CppKeywords.insert("typeid",KeywordType::SkipNextParenthesis);
|
||||
CppKeywords.insert("while",KeywordType::SkipNextParenthesis);
|
||||
CppKeywords.insert("static_assert",KeywordType::SkipNextParenthesis);
|
||||
|
||||
// Skip to }
|
||||
CppKeywords.insert("asm",KeywordType::SkipAfterBrace);
|
||||
//CppKeywords.insert("namespace",SkipType::skToLeftBrace); // won't process it
|
||||
CppKeywords.insert("asm",KeywordType::MoveToRightBrace);
|
||||
CppKeywords.insert("__asm",KeywordType::MoveToRightBrace);
|
||||
// Skip to {
|
||||
|
||||
// wont handle
|
||||
|
|
|
@ -58,11 +58,11 @@ using PDefineMap = std::shared_ptr<DefineMap>;
|
|||
|
||||
enum class KeywordType {
|
||||
SkipItself, // skip itself
|
||||
SkipAfterSemicolon, // skip to ;
|
||||
SkipAfterColon, // skip to :
|
||||
SkipAfterParenthesis, // skip to )
|
||||
SkipToLeftBrace,// Skip to {
|
||||
SkipAfterBrace, // skip to }
|
||||
SkipNextSemicolon, // move to ; and skip it
|
||||
SkipNextColon, // move to : and skip it
|
||||
SkipNextParenthesis, // move to ) and skip it
|
||||
MoveToLeftBrace,// move to {
|
||||
MoveToRightBrace, // move to }
|
||||
For, //for
|
||||
Catch, //catch
|
||||
Public, // public
|
||||
|
@ -74,7 +74,8 @@ enum class KeywordType {
|
|||
Namespace, //namespace
|
||||
Typedef, //typedef
|
||||
Using, //using
|
||||
None // It's a keyword but don't process here
|
||||
None, // It's a keyword but don't process here
|
||||
NotKeyword
|
||||
};
|
||||
|
||||
//It will be used as hash key. DONT make it enum class!!!!!
|
||||
|
|
Loading…
Reference in New Issue