File indexing completed on 2024-04-28 08:26:55

0001 /* This file is part of KDevelop
0002  *
0003  * Copyright 2010 Niko Sams <niko.sams@gmail.com>
0004  * Copyright 2010 Alexander Dymo <adymo@kdevelop.org>
0005  * Copyright (C) 2011-2015 Miquel Sabaté Solà <mikisabate@gmail.com>
0006  *
0007  * This program is free software; you can redistribute it and/or modify
0008  * it under the terms of the GNU Library General Public License as
0009  * published by the Free Software Foundation; either version 2 of the
0010  * License, or (at your option) any later version.
0011  *
0012  * This program is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  * GNU General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU General Public
0018  * License along with this program; if not, write to the
0019  * Free Software Foundation, Inc.,
0020  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0021  */
0022 
0023 #ifndef RUBY_DECLARATION_BUILDER_H
0024 #define RUBY_DECLARATION_BUILDER_H
0025 
0026 #include <language/duchain/builders/abstractdeclarationbuilder.h>
0027 
0028 #include <duchain/builders/typebuilder.h>
0029 #include <duchain/helpers.h>
0030 #include <util/stack.h>
0031 
0032 namespace ruby {
0033 
0034 class ModuleDeclaration;
0035 class MethodDeclaration;
0036 
0037 using DeclarationBuilderBase =
0038     KDevelop::AbstractDeclarationBuilder<Ast, NameAst, TypeBuilder>;
0039 
0040 /**
0041  * @class DeclarationBuilder
0042  *
0043  * The DeclarationBuilder iterates a Ast to build declarations.
0044  */
0045 class KDEVRUBYDUCHAIN_EXPORT DeclarationBuilder : public DeclarationBuilderBase
0046 {
0047 public:
0048     explicit DeclarationBuilder(EditorIntegrator *editor);
0049     ~DeclarationBuilder() override;
0050 
0051 protected:
0052     /// Re-implemented from KDevelop::AbstractDeclarationBuilder.
0053     void closeDeclaration() override;
0054     void closeContext() override;
0055 
0056     /// Re-implemented from the ContextBuilder.
0057     void startVisiting(Ast *node) override;
0058 
0059     /// Methods re-implemented from AstVisitor.
0060 
0061     bool declaredInContext(const QByteArray &name) const override;
0062 
0063     void visitClassStatement(Ast *node) override;
0064     void visitSingletonClass(Ast *node) override;
0065     void visitModuleStatement(Ast *node) override;
0066     void visitMethodStatement(Ast *node) override;
0067     void visitParameter(Ast *node) override;
0068     void visitBlock(Ast *node) override;
0069     void visitBlockVariables(Ast *node) override;
0070     void visitReturnStatement(Ast *node) override;
0071     void visitAssignmentStatement(Ast *node) override;
0072     void visitAliasStatement(Ast *node) override;
0073     void visitMethodCall(Ast *node) override;
0074     void visitMixin(Ast *node, bool include) override;
0075     void visitForStatement(Ast *node) override;
0076     void visitAccessSpecifier(const access_t policy) override;
0077     void visitYieldStatement(Ast *node) override;
0078     void visitRescueArg(Ast *node) override;
0079 
0080 private:
0081     /// @returns the range of the name of the given @p node.
0082     const KDevelop::RangeInRevision getNameRange(const Ast *node) const;
0083 
0084     /**
0085      * Open a context for a class/module declaration. It will also open the
0086      * context for the eigen class.
0087      *
0088      * @param decl The declaration itself.
0089      * @param node The node where the declaration resides.
0090      */
0091     void openContextForClassDefinition(ModuleDeclaration *decl, Ast *node);
0092 
0093     /**
0094      * Open or re-open if already exists a declaration in the current context.
0095      *
0096      * @param id The qualified identifier for the declaration.
0097      * @param range The range in which the declaration is contained.
0098      * @param context The context in which the declaration is being performed.
0099      * @returns an opened declaration. It returns nullptr if something
0100      * went wrong.
0101      */
0102     template<typename T> T * reopenDeclaration(const KDevelop::QualifiedIdentifier &id,
0103                                                const KDevelop::RangeInRevision &range,
0104                                                KDevelop::DUContext *context,
0105                                                DeclarationKind kind = DeclarationKind::Unknown);
0106 
0107     /**
0108      * Open or re-open a method declaration in the current context. This is,
0109      * indeed, an specialization of the reopenDeclaration method.
0110      *
0111      * @param id The qualified identifier for the declaration.
0112      * @param range The range in which the declaration is contained.
0113      * @param classMethod Set to true of this is a class method, otherwise set
0114      * false if this is an instance method.
0115      * @returns an opened method declaration. It returns nullptr if something
0116      * went wrong.
0117      */
0118     MethodDeclaration * reopenDeclaration(const KDevelop::QualifiedIdentifier &id,
0119                                           const KDevelop::RangeInRevision &range,
0120                                           bool classMethod);
0121 
0122     /**
0123      * Declare a variable in the current context.
0124      *
0125      * @param id The qualified identifier of the new variable declaration.
0126      * @param type The type of the new variable declaration.
0127      * @param node The node that contains this variable declaration.
0128      */
0129     void declareVariable(const KDevelop::QualifiedIdentifier &id,
0130                          const KDevelop::AbstractType::Ptr &type,
0131                          Ast *node,
0132                          KDevelop::DUContext::SearchFlag flags = KDevelop::DUContext::NoSearchFlags);
0133 
0134     /**
0135      * Alias a method declaration.
0136      *
0137      * @param id The id of the new method.
0138      * @param range The range of the new method.
0139      * @param decl The MethodDeclaration that it's being aliased.
0140      * @note the DUChain *must* be locked before calling this method.
0141      */
0142     void aliasMethodDeclaration(const KDevelop::QualifiedIdentifier &id,
0143                                 const KDevelop::RangeInRevision &range,
0144                                 const MethodDeclaration *decl);
0145 
0146     /// @returns the current access policy.
0147     inline KDevelop::Declaration::AccessPolicy currentAccessPolicy() const
0148     {
0149         if (m_accessPolicy.isEmpty()) {
0150             return KDevelop::Declaration::Public;
0151         }
0152         return m_accessPolicy.top();
0153     }
0154 
0155     /// Sets the current access policy to the given @p policy.
0156     inline void setAccessPolicy(KDevelop::Declaration::AccessPolicy policy)
0157     {
0158         m_accessPolicy.top() = policy;
0159     }
0160 
0161     /// Module mixins helper methods.
0162 
0163     /**
0164      * Get the module declaration that is being mixed-in.
0165      *
0166      * @param module The include/extend AST.
0167      * @returns the ModuleDeclaration that is being mixed-in, or nullptr if this
0168      * module doesn't actually exist.
0169      */
0170     ModuleDeclaration * getModuleDeclaration(Ast *module) const;
0171 
0172     /**
0173      * @returns the declared methods inside the given declaration @p decl,
0174      * which is a class or a module.
0175      */
0176     QList<MethodDeclaration *> getDeclaredMethods(const KDevelop::Declaration *decl);
0177 
0178     /// other stuff.
0179 
0180     /**
0181      * Check whether the given declaration can be redeclared or not.
0182      *
0183      * @param decl The declaration to be redeclared.
0184      * @param id The id of the declaration.
0185      * @param range The range of the declaration.
0186      * @param kind The kind that the declaration has to have.
0187      * @returns true if it's a valid re-declaration, and false otherwise.
0188      */
0189     bool validReDeclaration(KDevelop::Declaration *decl,
0190                             const KDevelop::QualifiedIdentifier &id,
0191                             const KDevelop::RangeInRevision &range,
0192                             DeclarationKind kind);
0193 
0194     /**
0195      * Get the context that contains the name of the class/module being
0196      * declared. If the container of the name does not exist, then the
0197      * current context is returned. For example, for the following declaration:
0198      *
0199      *   class; A::B; end
0200      *
0201      * The returned context will be the internal context of A. In this same
0202      * example, if A does not exist, then the current context would've been
0203      * returned.
0204      * @param node The node of the class/module declaration.
0205      */
0206     KDevelop::DUContext * getContainedNameContext(Ast *node);
0207 
0208     /**
0209      * This is a helper method that iterates over the call args of a method
0210      * call in order to update the type of each parameter accordingly.
0211      * @param mc A list of call args.
0212      * @param lastMethod The last encountered method call.
0213      */
0214     void visitMethodCallArgs(const Ast *mc,
0215                              const KDevelop::DeclarationPointer &lastMethod);
0216 
0217     /// @returns true if we're inside a class/module, false otherwise.
0218     inline bool insideClassModule() const
0219     {
0220         return m_classDeclarations.size() > 0;
0221     }
0222 
0223     /// @returns the last class/module.
0224     inline KDevelop::Declaration * lastClassModule() const
0225     {
0226         return m_classDeclarations.top().data();
0227     }
0228 
0229 private:
0230     EditorIntegrator *m_editor;
0231     KDevelop::Stack<KDevelop::Declaration::AccessPolicy> m_accessPolicy;
0232     KDevelop::Stack<KDevelop::DeclarationPointer> m_classDeclarations;
0233     bool m_injected;
0234     bool m_instance;
0235     KDevelop::Declaration *m_lastMethodCall;
0236 };
0237 
0238 }
0239 
0240 #endif // RUBY_DECLARATION_BUILDER_H