File indexing completed on 2024-05-19 04:42:00

0001 /*
0002     SPDX-FileCopyrightText: 2012 Aleix Pol <aleixpol@kde.org>
0003     SPDX-FileCopyrightText: 2012 Milian Wolff <mail@milianw.de>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #ifndef DECLARATIONBUILDER_H
0009 #define DECLARATIONBUILDER_H
0010 
0011 #include <language/duchain/builders/abstractdeclarationbuilder.h>
0012 #include <language/duchain/builders/abstracttypebuilder.h>
0013 
0014 #include "contextbuilder.h"
0015 
0016 #include <util/stack.h>
0017 
0018 namespace KDevelop
0019 {
0020     class ClassDeclaration;
0021 }
0022 
0023 namespace QmlJS
0024 {
0025     class NodeJS;
0026 }
0027 
0028 using TypeBuilder = KDevelop::AbstractTypeBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName, ContextBuilder>;
0029 using DeclarationBuilderBase = KDevelop::AbstractDeclarationBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName, TypeBuilder>;
0030 
0031 class KDEVQMLJSDUCHAIN_EXPORT DeclarationBuilder : public DeclarationBuilderBase
0032 {
0033     friend class QmlJS::NodeJS;
0034 
0035 public:
0036     explicit DeclarationBuilder(ParseSession* session);
0037 
0038     KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url,
0039                                            QmlJS::AST::Node* node,
0040                                            const KDevelop::ReferencedTopDUContext& updateContext = KDevelop::ReferencedTopDUContext()) override;
0041     void startVisiting(QmlJS::AST::Node* node) override;
0042 
0043 protected:
0044     using Visitor::visit;
0045     using Visitor::endVisit;
0046 
0047     using ExportLiteralsAndNames = QList<QPair<QmlJS::AST::StringLiteral*, QString>>;
0048 
0049     // Functions
0050     template<typename Decl>
0051     void declareFunction(QmlJS::AST::Node* node,
0052                          bool newPrototypeContext,
0053                          const KDevelop::Identifier& name,
0054                          const KDevelop::RangeInRevision& nameRange,
0055                          QmlJS::AST::Node* parameters,
0056                          const KDevelop::RangeInRevision& parametersRange,
0057                          QmlJS::AST::Node* body,
0058                          const KDevelop::RangeInRevision& bodyRange);
0059     template<typename Node>
0060     void declareParameters(Node* node, QmlJS::AST::UiQualifiedId* Node::*typeFunc);
0061     void endVisitFunction();    // Set the return type of the function to void if no return statement has been encountered
0062 
0063     bool visit(QmlJS::AST::FunctionDeclaration* node) override;
0064     bool visit(QmlJS::AST::FunctionExpression* node) override;
0065     bool visit(QmlJS::AST::FormalParameterList* node) override;
0066     bool visit(QmlJS::AST::UiParameterList* node) override;
0067     bool visit(QmlJS::AST::ReturnStatement* node) override;
0068     void endVisit(QmlJS::AST::FunctionDeclaration* node) override;
0069     void endVisit(QmlJS::AST::FunctionExpression* node) override;
0070 
0071     // Variables
0072     /// NOTE: this visits the @p base node and its children
0073     void inferArgumentsFromCall(QmlJS::AST::Node* base,
0074                                 QmlJS::AST::ArgumentList* arguments);
0075     bool visit(QmlJS::AST::VariableDeclaration* node) override;
0076     void endVisit(QmlJS::AST::VariableDeclaration* node) override;
0077     bool visit(QmlJS::AST::BinaryExpression* node) override;
0078     bool visit(QmlJS::AST::CallExpression* node) override;
0079     bool visit(QmlJS::AST::NewMemberExpression* node) override;
0080 
0081     // Arrays
0082     void declareFieldMember(const KDevelop::DeclarationPointer& declaration,
0083                             const QString& member,
0084                             QmlJS::AST::Node* node,
0085                             const QmlJS::AST::SourceLocation& location);
0086     bool visit(QmlJS::AST::FieldMemberExpression* node) override;
0087     bool visit(QmlJS::AST::ArrayMemberExpression* node) override;
0088 
0089     bool visit(QmlJS::AST::ObjectLiteral* node) override;
0090     bool visit(QmlJS::AST::PropertyNameAndValue* node) override;
0091     void endVisit(QmlJS::AST::PropertyNameAndValue* node) override;
0092     void endVisit(QmlJS::AST::ObjectLiteral* node) override;
0093 
0094     // plugin.qmltypes
0095     void declareComponent(QmlJS::AST::UiObjectInitializer* node,
0096                           const KDevelop::RangeInRevision &range,
0097                           const KDevelop::Identifier &name);
0098     void declareMethod(QmlJS::AST::UiObjectInitializer* node,
0099                        const KDevelop::RangeInRevision &range,
0100                        const KDevelop::Identifier &name,
0101                        bool isSlot,
0102                        bool isSignal);
0103     void declareProperty(QmlJS::AST::UiObjectInitializer* node,
0104                          const KDevelop::RangeInRevision &range,
0105                          const KDevelop::Identifier &name);
0106     void declareParameter(QmlJS::AST::UiObjectInitializer* node,
0107                           const KDevelop::RangeInRevision &range,
0108                           const KDevelop::Identifier &name);
0109     void declareEnum(const KDevelop::RangeInRevision &range,
0110                      const KDevelop::Identifier &name);
0111     void declareComponentSubclass(QmlJS::AST::UiObjectInitializer* node,
0112                                   const KDevelop::RangeInRevision& range,
0113                                   const QString& baseclass,
0114                                   QmlJS::AST::UiQualifiedId* qualifiedId);
0115     void declareComponentInstance(QmlJS::AST::ExpressionStatement *expression);
0116     ExportLiteralsAndNames exportedNames(QmlJS::AST::ExpressionStatement *exports);
0117     void declareExports(const ExportLiteralsAndNames& exports,
0118                         KDevelop::ClassDeclaration* classdecl);
0119 
0120     // UI
0121     void importDirectory(const QString& directory, QmlJS::AST::UiImport* node);
0122     void importModule(QmlJS::AST::UiImport* node);
0123     bool visit(QmlJS::AST::UiImport* node) override;
0124 
0125     bool visit(QmlJS::AST::UiObjectDefinition* node) override;
0126     void endVisit(QmlJS::AST::UiObjectDefinition* node) override;
0127 
0128     bool visit(QmlJS::AST::UiScriptBinding* node) override;
0129     void endVisit(QmlJS::AST::UiScriptBinding* node) override;
0130     bool visit(QmlJS::AST::UiObjectBinding* node) override;
0131     void endVisit(QmlJS::AST::UiObjectBinding* node) override;
0132 
0133     bool visit(QmlJS::AST::UiPublicMember* node) override;
0134     void endVisit(QmlJS::AST::UiPublicMember* node) override;
0135 
0136 protected:
0137     template<class DeclarationT>
0138     DeclarationT* openDeclaration(const KDevelop::Identifier& id,
0139                                   const KDevelop::RangeInRevision& newRange,
0140                                   DeclarationFlags flags = NoFlags)
0141     {
0142         auto* res = DeclarationBuilderBase::openDeclaration<DeclarationT>(id, newRange, flags);
0143         res->setAlwaysForceDirect(true);
0144         return res;
0145     }
0146 
0147 private:
0148     void closeAndAssignType();
0149     void registerBaseClasses();              /*!< @brief Enumerates the base classes of the current class and import their inner contexts */
0150     void addBaseClass(KDevelop::ClassDeclaration* classDecl, const QString &name);    /*!< @brief Add a base class to a class declaration */
0151     void addBaseClass(KDevelop::ClassDeclaration* classDecl, const KDevelop::IndexedType& type);
0152     KDevelop::AbstractType::Ptr typeFromName(const QString& name);          /*!< @brief Type from a general name (int, string, or a class name) */
0153     KDevelop::AbstractType::Ptr typeFromClassName(const QString& name);     /*!< @brief Type from a class name, built-in types are not supported here */
0154     bool areTypesEqual(const KDevelop::AbstractType::Ptr& a,
0155                        const KDevelop::AbstractType::Ptr& b);
0156 
0157     using DeclarationBuilderBase::setComment;
0158     void setComment(QmlJS::AST::Node* node);
0159 
0160 private:
0161     bool m_prebuilding;
0162     KDevelop::Stack<bool> m_skipEndVisit;
0163 };
0164 
0165 #endif // DECLARATIONBUILDER_H