work save

This commit is contained in:
royqh1979@gmail.com 2021-08-15 16:49:37 +08:00
parent 5174823cb8
commit 2376a09d73
5 changed files with 407 additions and 72 deletions

View File

@ -1,6 +1,301 @@
#include "cppparser.h" #include "cppparser.h"
#include "parserutils.h"
#include <QHash>
#include <QQueue>
CppParser::CppParser(QObject *parent) : QObject(parent) CppParser::CppParser(QObject *parent) : QObject(parent)
{ {
} }
PStatement CppParser::addInheritedStatement(PStatement derived, PStatement inherit, StatementClassScope access)
{
PStatement statement = addStatement(
derived,
inherit->fileName,
inherit->hintText,
inherit->type, // "Type" is already in use
inherit->command,
inherit->args,
inherit->value,
inherit->line,
inherit->kind,
inherit->scope,
access,
true,
inherit->inheritanceList,
inherit->isStatic);
statement->isInherited = true;
return statement;
}
PStatement CppParser::addChildStatement(PStatement parent, const QString &fileName, const QString &hintText, const QString &aType, const QString &command, const QString &args, const QString &value, int line, StatementKind kind, StatementScope scope, StatementClassScope classScope, bool isDefinition, bool isStatic)
{
return addStatement(
parent,
fileName,
hintText,
aType,
command,
args,
value,
line,
kind,
scope,
classScope,
isDefinition,
QList<std::weak_ptr<Statement>>(),
isStatic);
}
PStatement CppParser::addStatement(PStatement parent, const QString &fileName, const QString &hintText, const QString &aType, const QString &command, const QString &args, const QString &value, int line, StatementKind kind, StatementScope scope, StatementClassScope classScope, bool isDefinition, const QList<std::weak_ptr<Statement> > &inheritanceList, bool isStatic)
{
// Move '*', '&' to type rather than cmd (it's in the way for code-completion)
QString newType = aType;
QString newCommand = command;
while (!newCommand.isEmpty() && (newCommand.front() == '*' || newCommand.front() == '&')) {
newType += newCommand.front();
newCommand.remove(0,1); // remove first
}
QString noNameArgs = "";
if (kind == StatementKind::skConstructor
|| kind == StatementKind::skFunction
|| kind == StatementKind::skDestructor
|| kind == StatementKind::skVariable) {
noNameArgs = removeArgNames(args);
//find
PStatement oldStatement = findStatementInScope(command,noNameArgs,kind,parent);
if (oldStatement && isDefinition && !oldStatement->hasDefinition) {
oldStatement->hasDefinition = true;
if (oldStatement->fileName!=fileName) {
PFileIncludes fileIncludes1=findFileIncludes(fileName);
if (fileIncludes1) {
fileIncludes1->statements.insert(oldStatement->command,
oldStatement);
fileIncludes1->dependingFiles.insert(oldStatement->fileName);
PFileIncludes fileIncludes2=findFileIncludes(oldStatement->fileName);
if (fileIncludes2) {
fileIncludes2->dependedFiles.insert(fileName);
}
}
}
oldStatement->definitionLine = line;
oldStatement->definitionFileName = fileName;
return oldStatement;
}
}
PStatement result = std::make_shared<Statement>();
result->parentScope = parent;
result->hintText = hintText;
result->type = newType;
if (!newCommand.isEmpty())
result->command = newCommand;
else {
mUniqId++;
result->command = QString("__STATEMENT__%1").arg(mUniqId);
}
result->args = args;
result->noNameArgs = noNameArgs;
result->value = value;
result->kind = kind;
result->inheritanceList = inheritanceList;
result->scope = scope;
result->classScope = classScope;
result->hasDefinition = isDefinition;
result->line = line;
result->definitionLine = line;
result->fileName = fileName;
result->definitionFileName = fileName;
if (!fileName.isEmpty())
result->inProject = mIsProjectFile;
else
result->inProject = false;
result->inSystemHeader = mIsSystemHeader;
//result->children;
//result->friends;
result->isStatic = isStatic;
result->isInherited = false;
if (scope == StatementScope::ssLocal)
result->fullName = newCommand;
else
result->fullName = getFullStatementName(newCommand, parent);
result->usageCount = 0;
result->freqTop = 0;
if (result->kind == StatementKind::skNamespace) {
PStatementList namespaceList = mNamespaces.value(result->fullName,PStatementList());
if (!namespaceList) {
namespaceList=std::make_shared<StatementList>();
mNamespaces.insert(result->fullName,namespaceList);
}
namespaceList->append(result);
}
return result;
}
void CppParser::addSoloScopeLevel(PStatement statement, int line)
{
// Add class list
PStatement parentScope;
if (statement && (statement->kind == StatementKind::skBlock)) {
parentScope = statement->parentScope.lock();
while (parentScope && (parentScope->kind == StatementKind::skBlock)) {
parentScope = parentScope->parentScope.lock();
}
if (!parentScope)
statement.reset();
}
if (mCurrentClassScope.count()>0) {
mCurrentClassScope.back() = mClassScope;
}
mCurrentScope.append(statement);
PFileIncludes fileIncludes = findFileIncludes(mCurrentFile);
if (fileIncludes) {
fileIncludes->scopes.insert(line,statement);
}
// Set new scope
if (!statement)
mClassScope = StatementClassScope::scsNone; // {}, namespace or class that doesn't exist
else if (statement->kind == StatementKind::skNamespace)
mClassScope = StatementClassScope::scsNone;
else if (statement->type == "class")
mClassScope = StatementClassScope::scsPrivate; // classes are private by default
else
mClassScope = StatementClassScope::scsPublic; // structs are public by default
mCurrentClassScope.append(mClassScope);
}
bool CppParser::checkForCatchBlock()
{
return mIndex < mTokenizer.tokenCount() &&
mTokenizer[mIndex]->text == "catch";
}
bool CppParser::checkForEnum()
{
return mIndex < mTokenizer.tokenCount() &&
mTokenizer[mIndex]->text == "enum";
}
bool CppParser::checkForForBlock()
{
return mIndex < mTokenizer.tokenCount() &&
mTokenizer[mIndex]->text == "for";
}
bool CppParser::checkForKeyword()
{
SkipType st = CppKeywords.value(mTokenizer[mIndex]->text,SkipType::skNone);
return st!=SkipType::skNone;
}
bool CppParser::checkForMethod(QString &sType, QString &sName, QString &sArgs, bool &isStatic, bool &isFriend)
{
}
void CppParser::calculateFilesToBeReparsed(const QString &fileName, QStringList &files)
{
if (fileName.isEmpty())
return;
files.clear();
QQueue<QString> queue;
QSet<QString> processed;
queue.enqueue(fileName);
while (!queue.isEmpty()) {
QString name = queue.dequeue();
files.append(name);
processed.insert(name);
PFileIncludes p=findFileIncludes(name);
if (!p)
continue;
for (QString s:p->dependedFiles) {
if (!processed.contains(s)) {
queue.enqueue(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) {
currentArg += ' ' + word;
} else {
if (isKeyword(word)) {
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.trimmed().isEmpty()) {
if (!typeGetted) {
currentArg += ' ' + word;
if (CppTypeKeywords.contains(word) || !isKeyword(word))
typeGetted = true;
} else {
if (isKeyword(word))
currentArg += ' ' + word;
}
word = "";
}
break;
default:
if (isLetterChar(args[i]))
word+=args[i];
}
i++;
}
if (!typeGetted) {
currentArg += ' ' + word;
} else {
if (isKeyword(word)) {
currentArg += ' ' + word;
}
}
result += currentArg.trimmed();
return result;
}

View File

@ -16,64 +16,86 @@ public:
explicit CppParser(QObject *parent = nullptr); explicit CppParser(QObject *parent = nullptr);
void parseHardDefines(); void parseHardDefines();
function FindFileIncludes(const Filename: AnsiString; DeleteIt: boolean = False): PFileIncludes; PFileIncludes findFileIncludes(const QString &filename, bool deleteIt = false);
procedure AddHardDefineByLine(const Line: AnsiString); void addHardDefineByLine(const QString& line);
procedure InvalidateFile(const FileName: AnsiString); void invalidateFile(const QString& fileName);
procedure GetFileDirectIncludes(const Filename: AnsiString; var List: TStringList); QStringList getFileDirectIncludes(const QString& filename) const;
procedure GetFileIncludes(const Filename: AnsiString; var List: TStringList); const QList<QString>& getFileIncludes(const QString& filename) const;
procedure GetFileUsings(const Filename: AnsiString; var List: TDevStringList); const QSet<QString>& getFileUsings(const QString& filename) &;
function IsSystemHeaderFile(const FileName: AnsiString): boolean; bool isSystemHeaderFile(const QString& fileName);
function IsProjectHeaderFile(const FileName: AnsiString): boolean; bool isProjectHeaderFile(const QString& fileName);
procedure GetSourcePair(const FName: AnsiString; var CFile, HFile: AnsiString); void getSourcePair(const QString& fName, QString& CFile, QString& HFile);
procedure GetClassesList(var List: TStringList); void getClassesList(QStringList& list);
function SuggestMemberInsertionLine(ParentStatement: PStatement; Scope: TStatementClassScope; var AddScopeStr: int suggestMemberInsertionLine(PStatement parentStatement,
boolean): StatementClassScope Scope,
integer; bool addScopeStr);
{ // {
function GetSystemHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h> // function GetSystemHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h>
function GetProjectHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h> // function GetProjectHeaderFileName(const FileName: AnsiString): AnsiString; // <file.h>
function GetLocalHeaderFileName(const RelativeTo, FileName: AnsiString): AnsiString; // "file.h" // function GetLocalHeaderFileName(const RelativeTo, FileName: AnsiString): AnsiString; // "file.h"
} // }
function GetHeaderFileName(const RelativeTo, Line: AnsiString): AnsiString; // both QString getHeaderFileName(const QString& relativeTo, const QString& line) const;// both
function IsIncludeLine(const Line: AnsiString): boolean; bool isIncludeLine(const QString &line);
constructor Create(wnd:HWND); void parseFileList(bool updateView = true);
destructor Destroy; override; void parseFile(const QString& fileName, bool inProject,
procedure ParseFileList(UpdateView:boolean = True); bool onlyIfNotParsed = false, bool updateView = true);
procedure ParseFile(const FileName: AnsiString; InProject: boolean; OnlyIfNotParsed: boolean = False; UpdateView: QString statementKindStr(StatementKind value);
boolean = True); QString statementClassScopeStr(StatementClassScope value);
function StatementKindStr(Value: TStatementKind): AnsiString; void reset();
function StatementClassScopeStr(Value: TStatementClassScope): AnsiString; void clearIncludePaths();
procedure Reset; void clearProjectIncludePaths();
procedure ClearIncludePaths; void clearProjectFiles();
procedure ClearProjectIncludePaths; void addIncludePath(const QString& value);
procedure ClearProjectFiles; void addProjectIncludePath(const QString& value);
procedure AddIncludePath(const Value: AnsiString); void addFileToScan(const QString& value, bool inProject = false);
procedure AddProjectIncludePath(const Value: AnsiString); QString prettyPrintStatement(PStatement statement, int line = -1);
procedure AddFileToScan(Value: AnsiString; InProject: boolean = False); void fillListOfFunctions(const QString& fileName,
function PrettyPrintStatement(Statement: PStatement; line:integer = -1): AnsiString; const QString& phrase,
procedure FillListOfFunctions(const FileName, Phrase: AnsiString; const Line: integer; List: TStringList); int line,
function FindAndScanBlockAt(const Filename: AnsiString; Line: integer): PStatement; QStringList& list);
function FindStatementOf(FileName, Phrase: AnsiString; Line: integer): PStatement; overload; PStatement findAndScanBlockAt(const QString& filename, int line);
function FindStatementOf(FileName, Phrase: AnsiString; CurrentClass: PStatement; PStatement findStatementOf(const QString& fileName,
var CurrentClassType: PStatement ; force:boolean = False): PStatement; overload; const QString& phrase,
function FindStatementOf(FileName, Phrase: AnsiString; CurrentClass: PStatement; force:boolean = False): PStatement; overload; int line);
PStatement findStatementOf(const QString& fileName,
const QString& phrase,
PStatement currentClass,
PStatement& currentClassType,
bool force = false);
PStatement findStatementOf(const QString& fileName,
const QString& phrase,
PStatement currentClass,
bool force = false);
function FindKindOfStatementOf(FileName, Phrase: AnsiString; Line: integer): TStatementKind; StatementKind findKindOfStatementOf(const QString& fileName,
function GetHintFromStatement(FileName, Phrase: AnsiString; Line: integer):AnsiString; const QString& phrase,
{Find statement starting from startScope} int line);
function FindStatementStartingFrom(const FileName, Phrase: AnsiString; startScope: PStatement; force:boolean = False): PStatement; QString getHintFromStatement(const QString& fileName,
function FindTypeDefinitionOf(const FileName: AnsiString;const aType: AnsiString; CurrentClass: PStatement): PStatement; const QString& phrase,
function FindFirstTemplateParamOf(const FileName: AnsiString;const aPhrase: AnsiString; currentClass: PStatement): String; int line);
function FindLastOperator(const Phrase: AnsiString): integer; //{Find statement starting from startScope}
function FindNamespace(const name:AnsiString):TList; // return a list of PSTATEMENTS (of the namespace) PStatement findStatementStartingFrom(const QString& fileName,
function Freeze:boolean; overload; // Freeze/Lock (stop reparse while searching) const QString& phrase,
function Freeze(serialId:String):boolean; overload; // Freeze/Lock (stop reparse while searching) PStatement startScope,
procedure UnFreeze; // UnFree/UnLock (reparse while searching) bool force = false);
function GetParsing: boolean; PStatement findTypeDefinitionOf(const QString& fileName,
const QString& phrase,
PStatement currentClass);
QString FindFirstTemplateParamOf(const QString& fileName,
const QString& phrase,
PStatement currentClass);
int findLastOperator(const QString& phrase) const;
QList<PStatement> findNamespace(const QString& name); // return a list of PSTATEMENTS (of the namespace)
bool freeze(); // Freeze/Lock (stop reparse while searching)
bool freeze(const QString& serialId); // Freeze/Lock (stop reparse while searching)
void unFreeze(); // UnFree/UnLock (reparse while searching)
bool getParsing();
function FindFunctionDoc(const FileName:AnsiString; const Line: integer; QString findFunctionDoc(const QString& fileName,
params:TStringList; var isVoid:boolean): AnsiString; int line,
QStringList& params,
bool &isVoid);
signals: signals:
private: private:
PStatement addInheritedStatement( PStatement addInheritedStatement(
@ -83,7 +105,7 @@ private:
PStatement addChildStatement( PStatement addChildStatement(
// support for multiple parents (only typedef struct/union use multiple parents) // support for multiple parents (only typedef struct/union use multiple parents)
PStatement Parent, PStatement parent,
const QString& fileName, const QString& fileName,
const QString& hintText, const QString& hintText,
const QString& aType, // "Type" is already in use const QString& aType, // "Type" is already in use
@ -109,7 +131,7 @@ private:
StatementScope scope, StatementScope scope,
StatementClassScope classScope, StatementClassScope classScope,
bool isDefinition, bool isDefinition,
const QStringList& InheritanceList, const QList<std::weak_ptr<Statement>>& inheritanceList,
bool isStatic); bool isStatic);
void setInheritance(int index, PStatement classStatement, bool isStruct); void setInheritance(int index, PStatement classStatement, bool isStruct);
PStatement getCurrentScope(); // gets last item from last level PStatement getCurrentScope(); // gets last item from last level
@ -119,22 +141,21 @@ private:
void checkForSkipStatement(); void checkForSkipStatement();
int skipBraces(int startAt); int skipBraces(int startAt);
int skipBracket(int startAt); int skipBracket(int startAt);
bool checkForPreprocessor(); bool checkForCatchBlock();
bool checkForEnum();
bool checkForForBlock();
bool checkForKeyword(); bool checkForKeyword();
bool checkForMethod(QString &sType, QString &sName, QString &sArgs,
bool &isStatic, bool &isFriend); // caching of results
bool checkForNamespace(); bool checkForNamespace();
bool checkForPreprocessor();
bool checkForUsing(); bool checkForUsing();
bool checkForScope();
bool CheckForStructs();
bool checkForTypedef(); bool checkForTypedef();
bool checkForTypedefEnum(); bool checkForTypedefEnum();
bool checkForTypedefStruct(); bool checkForTypedefStruct();
bool CheckForStructs();
bool checkForMethod(QString &sType, QString &sName, QString &sArgs,
bool &isStatic, bool &isFriend); // caching of results
bool checkForScope();
bool checkForVar(); bool checkForVar();
bool checkForEnum();
bool checkForForBlock();
bool checkForCatchBlock();
StatementScope getScope(); StatementScope getScope();
int getCurrentBlockEndSkip(); int getCurrentBlockEndSkip();
int getCurrentBlockBeginSkip(); int getCurrentBlockBeginSkip();
@ -204,6 +225,8 @@ private:
QString getStatementKey(const QString& sName, QString getStatementKey(const QString& sName,
const QString& sType, const QString& sType,
const QString& sNoNameArgs); const QString& sNoNameArgs);
QString removeArgNames(const QString& args);
void onProgress(const QString& fileName, int total, int current); void onProgress(const QString& fileName, int total, int current);
void onBusy(); void onBusy();
void onStartParsing(); void onStartParsing();

View File

@ -57,6 +57,21 @@ void CppTokenizer::dumpTokens(const QString &fileName)
} }
} }
const CppTokenizer::TokenList &CppTokenizer::tokens()
{
return mTokenList;
}
CppTokenizer::PToken CppTokenizer::operator[](int i)
{
return mTokenList[i];
}
int CppTokenizer::tokenCount()
{
return mTokenList.count();
}
void CppTokenizer::addToken(const QString &sText, int iLine) void CppTokenizer::addToken(const QString &sText, int iLine)
{ {
PToken token = std::make_shared<Token>(); PToken token = std::make_shared<Token>();

View File

@ -18,6 +18,9 @@ public:
void reset(); void reset();
void tokenize(const QStringList& buffer); void tokenize(const QStringList& buffer);
void dumpTokens(const QString& fileName); void dumpTokens(const QString& fileName);
const TokenList& tokens();
PToken operator[](int i);
int tokenCount();
signals: signals:
private: private:
void addToken(const QString& sText, int iLine); void addToken(const QString& sText, int iLine);

View File

@ -90,7 +90,7 @@ struct Statement;
using PStatement = std::shared_ptr<Statement>; using PStatement = std::shared_ptr<Statement>;
using StatementList = QList<PStatement>; using StatementList = QList<PStatement>;
using PStatementList = std::shared_ptr<StatementList>; using PStatementList = std::shared_ptr<StatementList>;
using StatementMap = QMultiHash<QString, PStatement>; using StatementMap = QMultiMap<QString, PStatement>;
struct Statement { struct Statement {
std::weak_ptr<Statement> parentScope; // parent class/struct/namespace scope, don't use auto pointer to prevent circular reference std::weak_ptr<Statement> parentScope; // parent class/struct/namespace scope, don't use auto pointer to prevent circular reference
QString hintText; // text to force display when using PrettyPrintStatement QString hintText; // text to force display when using PrettyPrintStatement
@ -133,7 +133,7 @@ struct UsingNamespace {
using PUsingNamespace = std::shared_ptr<UsingNamespace>; using PUsingNamespace = std::shared_ptr<UsingNamespace>;
struct IncompleteClass { struct IncompleteClass {
std::weak_ptr<Statement> statement; PStatement statement;
int count; int count;
}; };
using PIncompleteClass = std::shared_ptr<IncompleteClass>; using PIncompleteClass = std::shared_ptr<IncompleteClass>;
@ -142,10 +142,9 @@ struct FileIncludes {
QString baseFile; QString baseFile;
QMap<QString,bool> includeFiles; // true means the file is directly included, false means included indirectly QMap<QString,bool> includeFiles; // true means the file is directly included, false means included indirectly
QSet<QString> usings; // namespaces it usings QSet<QString> usings; // namespaces it usings
QVector<std::weak_ptr<Statement>> statements; // but we don't save temporary statements StatementMap statements; // but we don't save temporary statements
//StatementsIndex: TDevStringHash; StatementMap declaredStatements; // statements declared in this file
QVector<std::weak_ptr<Statement>> declaredStatements; // statements declared in this file QMap<int, PStatement> scopes; // int is start line of the statement scope
QMap<int, std::weak_ptr<Statement>> scopes; // int is start line of the statement scope
QSet<QString> dependingFiles; // The files I depeneds on QSet<QString> dependingFiles; // The files I depeneds on
QSet<QString> dependedFiles; // the files depends on me QSet<QString> dependedFiles; // the files depends on me
}; };