/* * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PARSER_UTILS_H #define PARSER_UTILS_H #include #include #include #include #include #include using GetFileStreamCallBack = std::function; enum class ParserLanguage { C, CPlusPlus, #ifdef ENABLE_SDCC SDCC, #endif }; inline uint qHash(const ParserLanguage& value, uint seed) { return qHash((int)value, seed); } struct CodeSnippet { QString caption; //Name QString prefix; //Prefix used in code suggestion QString code; //Code body QString desc; //Description int section; //Section in the menu }; using PCodeSnippet = std::shared_ptr; // preprocess/ macro define struct Define { QString name; QString args; QString value; QString filename; bool hardCoded;// if true, don't free memory (points to hard defines) QList argUsed; int varArgIndex; QString formatValue; // format template to format values }; using PDefine = std::shared_ptr; using DefineMap = QHash; using PDefineMap = std::shared_ptr; enum class KeywordType { SkipItself, // skip itself 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 Private, Protected, Friend, Struct, // struct/class/enum Enum, //enum Inline, // inline Namespace, //namespace Typedef, //typedef Using, //using DeclType, // decltype Operator, //operator Concept, //concept Requires, //requires None, // It's a keyword but don't process here Extern, NotKeyword }; enum class StatementKind { Unknown, Namespace, NamespaceAlias, Class, Preprocessor, EnumType, EnumClassType, Typedef, Constructor, Destructor, Function, Variable, GlobalVariable, LocalVariable, Enum, Operator, Parameter, Block, Lambda, UserCodeSnippet, // user code template Keyword, // keywords KeywordType, //keywords for type (for color management) Alias, // using alias }; inline uint qHash(const StatementKind& value, uint seed) { return qHash((int)value, seed); } enum class StatementScope { Global, Local, ClassLocal }; enum class StatementAccessibility { None, Private, Protected, Public }; enum class MemberOperatorType { Arrow, Dot, DColon, Other }; enum class EvalStatementKind { Namespace, Type, Variable, Literal, Function }; struct StatementMatchPosition{ uint16_t start; uint16_t end; }; enum class StatementProperty { None = 0x0, Static = 0x0001, HasDefinition = 0x0002, InProject = 0x0004, InSystemHeader = 0x0008, Inherited = 0x0010, Virtual = 0x0020, Override = 0x0040, Constexpr = 0x0080, FunctionPointer = 0x0100, OperatorOverloading = 0x0200, DummyStatement = 0x0400 }; Q_DECLARE_FLAGS(StatementProperties, StatementProperty) Q_DECLARE_OPERATORS_FOR_FLAGS(StatementProperties) using PStatementMathPosition = std::shared_ptr; struct Statement; using PStatement = std::shared_ptr; using StatementList = QList; using PStatementList = std::shared_ptr; using StatementMap = QMultiMap; struct Statement { std::weak_ptr parentScope; // parent class/struct/namespace scope, use weak pointer to prevent circular reference QString type; // type "int" QString command; // identifier/name of statement "foo" QString args; // args "(int a,float b)" QString value; // Used for macro defines/typedef, "100" in "#defin COUNT 100" QString templateSpecializationParams; StatementKind kind; // kind of statement class/variable/function/etc StatementScope scope; // global/local/classlocal StatementAccessibility accessibility; // protected/private/public int line; // declaration int definitionLine; // definition QString fileName; // declaration QString definitionFileName; // definition StatementMap children; // functions can be overloaded,so we use list to save children with the same name QSet friends; // friend class / functions QString fullName; // fullname(including class and namespace), ClassA::foo QSet usingList; // using namespaces QString noNameArgs;// Args without name QSet lambdaCaptures; StatementProperties properties; // fields for code completion int usageCount; //Usage Count uint16_t matchPosTotal; // total of matched positions uint16_t matchPosSpan; // distance between the first match pos and the last match pos; uint16_t firstMatchLength; // length of first match; uint16_t caseMatched; // if match with case QList matchPositions; // definiton line/filename is valid bool hasDefinition() { return properties.testFlag(StatementProperty::HasDefinition); } void setHasDefinition(bool on) { properties.setFlag(StatementProperty::HasDefinition,on); } // statement in project bool inProject() { return properties.testFlag(StatementProperty::InProject); } void setInProject(bool on) { properties.setFlag(StatementProperty::InProject, on); } // statement in system header (#include <>) bool inSystemHeader() { return properties.testFlag(StatementProperty::InSystemHeader); } void setInSystemHeader(bool on) { properties.setFlag(StatementProperty::InSystemHeader, on); } bool isStatic() { return properties.testFlag(StatementProperty::Static); } // static function / variable void setIsStatic(bool on) { properties.setFlag(StatementProperty::Static, on); } bool isInherited() { return properties.testFlag(StatementProperty::Inherited); } // inherted member; }; struct EvalStatement; using PEvalStatement = std::shared_ptr; /** * @brief Statement for evaluation result * Ex. (Test*)(y+1) * it's baseStatement is the statement for y * it's effetiveTypeStatement is Test */ struct EvalStatement { QString baseType; // type "int" QString templateParams; EvalStatementKind kind; // namespace / type / variable / function / literal int pointerLevel; // 0 for "int", 1 for "int *", 2 for "int **"... QString definitionString; // std::vector etc... PStatement baseStatement; // if not literal or primitive type, the base statement PStatement typeStatement; PStatement effectiveTypeStatement; public: EvalStatement (const QString& baseType, EvalStatementKind kind, const PStatement& baseStatement, const PStatement& typeStatement, const PStatement& effectiveTypeStatement, int pointerLevel=0, const QString& templateParams=QString()); void assignType(const PEvalStatement& typeStatement); }; struct UsingNamespace { QStringList namespaces; // List['std','foo'] for using namespace std::foo; QString filename; int line; bool fromHeader; }; using PUsingNamespace = std::shared_ptr; struct CppScope { int startLine; PStatement statement; }; using PCppScope = std::shared_ptr; class CppScopes { public: PStatement findScopeAtLine(int line) const; void addScope(int line, PStatement scopeStatement); PStatement lastScope() const { if (mScopes.isEmpty()) return PStatement(); return mScopes.back()->statement; } void removeLastScope() { if (!mScopes.isEmpty()) mScopes.pop_back(); } void clear() { mScopes.clear(); } private: QVector mScopes; }; struct ClassInheritanceInfo { std::weak_ptr derivedClass; QString file; QString parentClassName; bool isGlobal; bool isStruct; StatementAccessibility visibility; // QString parentClassFilename; bool handled; }; using PClassInheritanceInfo = std::shared_ptr; class ParsedFileInfo { public: ParsedFileInfo(const QString& fileName): mFileName {fileName} { } ParsedFileInfo(const ParsedFileInfo&)=delete; ParsedFileInfo& operator=(const ParsedFileInfo&)=delete; void insertBranch(int level, bool branchTrue) { mBranches.insert(level, branchTrue); } bool isLineVisible(int line) const; void addInclude(const QString &fileName) { mIncludes.insert(fileName); } void addDirectInclude(const QString &fileName) { mDirectIncludes.append(fileName); } bool including(const QString &fileName) const { return mIncludes.contains(fileName); } PStatement findScopeAtLine(int line) const { return mScopes.findScopeAtLine(line); } void addStatement(const PStatement &statement) { mStatements.insert(statement->fullName,statement); } void clearStatements() { mStatements.clear(); } void addScope(int line, const PStatement &scope) { mScopes.addScope(line,scope); } void removeLastScope() { mScopes.removeLastScope(); } PStatement lastScope() const { return mScopes.lastScope(); } void addUsing(const QString &usingSymbol) { mUsings.insert(usingSymbol); } void addHandledInheritances(std::weak_ptr classInheritanceInfo) { mHandledInheritances.append(classInheritanceInfo); } void clearHandledInheritances() { mHandledInheritances.clear(); } QString fileName() const { return mFileName; } const StatementMap& statements() const { return mStatements; } const QSet& usings() const { return mUsings; } const QStringList& directIncludes() const { return mDirectIncludes; } const QSet& includes() const { return mIncludes; } const QList >& handledInheritances() const { return mHandledInheritances; } private: QString mFileName; QSet mIncludes; QStringList mDirectIncludes; //We need order here. QSet mUsings; // namespaces it usings StatementMap mStatements; // but we don't save temporary statements (full name as key) CppScopes mScopes; // int is start line of the statement scope QMap mBranches; QList> mHandledInheritances; }; using PParsedFileInfo = std::shared_ptr; extern QStringList CppDirectives; extern QStringList JavadocTags; extern QMap CppKeywords; #ifdef ENABLE_SDCC extern QMap SDCCKeywords; extern QSet SDCCTypeKeywords; #endif extern QSet CppControlKeyWords; extern QSet CKeywords; extern QSet CppTypeKeywords; extern QSet STLPointers; extern QSet STLContainers; extern QSet STLMaps; extern QSet STLElementMethods; extern QSet STLIterators; extern QSet MemberOperators; extern QSet IOManipulators; extern QSet AutoTypes; void initParser(); QString getHeaderFilename(const QString& relativeTo, const QString& line, const QStringList& includePaths, const QStringList& projectIncludePaths); QString getLocalHeaderFilename(const QString& relativeTo, const QString& fileName); QString getSystemHeaderFilename(const QString& fileName, const QStringList& includePaths); bool isSystemHeaderFile(const QString& fileName, const QSet& includePaths); bool isHFile(const QString& filename); bool isCFile(const QString& filename); bool isCppFile(const QString& filename); bool isCppKeyword(const QString& word); bool isCppControlKeyword(const QString& word); bool isScopeTypeKind(StatementKind kind); bool isTypeKind(StatementKind kind); MemberOperatorType getOperatorType(const QString& phrase, int index); QStringList getOwnerExpressionAndMember( const QStringList expression, QString& memberOperator, QStringList& memberExpression); bool isMemberOperator(QString token); StatementKind getKindOfStatement(const PStatement& statement); #endif // PARSER_UTILS_H