File indexing completed on 2024-05-05 04:36:51

0001 /* This file is part of KDevelop
0002  *
0003  * Copyright (C) 2011-2015 Miquel Sabaté Solà <mikisabate@gmail.com>
0004  *
0005  * This program is free software: you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation, either version 3 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017  */
0018 
0019 #include <duchain/builders/usebuilder.h>
0020 
0021 #include <language/duchain/types/functiontype.h>
0022 
0023 #include <parser/parser.h>
0024 #include <duchain/editorintegrator.h>
0025 #include <duchain/expressionvisitor.h>
0026 #include <duchain/declarations/moduledeclaration.h>
0027 
0028 using namespace KDevelop;
0029 using namespace ruby;
0030 
0031 UseBuilder::UseBuilder(EditorIntegrator *editor) : UseBuilderBase()
0032 {
0033     m_editor = editor;
0034     m_lastCtx = nullptr;
0035     m_depth = 0;
0036     m_classMethod = false;
0037 }
0038 
0039 bool UseBuilder::declaredInContext(const QByteArray &name) const
0040 {
0041     return declaredIn(name, DUContextPointer(currentContext()));
0042 }
0043 
0044 void UseBuilder::visitName(Ast *node)
0045 {
0046     const QualifiedIdentifier &id = getIdentifier(node);
0047     const RangeInRevision &range = editorFindRange(node, node);
0048     auto decl = getDeclaration(id, range, DUContextPointer(currentContext()));
0049 
0050     if (!decl || decl->range() == range) {
0051         return;
0052     }
0053     UseBuilderBase::newUse(range, decl);
0054 }
0055 
0056 void UseBuilder::visitClassName(Ast *node)
0057 {
0058     Node *aux = node->tree;
0059     Node *last = node->tree->last;
0060     ExpressionVisitor ev(currentContext(), m_editor);
0061 
0062     for (Node *n = aux; n && last; n = n->next) {
0063         node->tree = n;
0064         ev.visitNode(node);
0065         const DeclarationPointer d = ev.lastDeclaration();
0066         if (d.data()) {
0067             UseBuilderBase::newUse(editorFindRange(node, node), d);
0068             ev.setContext(d->internalContext());
0069         } else {
0070             break;
0071         }
0072     }
0073     node->tree = aux;
0074 }
0075 
0076 void UseBuilder::visitMixin(Ast *node, bool include)
0077 {
0078     Q_UNUSED(include);
0079 
0080     ExpressionVisitor ev(currentContext(), m_editor);
0081     Node *aux = node->tree;
0082     Node *n = (aux->r->l) ? aux->r->l : aux->r;
0083 
0084     for (; n; n = n->next) {
0085         node->tree = n;
0086         ev.visitNode(node);
0087         const DeclarationPointer d = ev.lastDeclaration();
0088         if (d) {
0089             UseBuilderBase::newUse(m_editor->findRange(n), d);
0090             ev.setContext(d->internalContext());
0091         } else {
0092             break;
0093         }
0094     }
0095     node->tree = aux;
0096 }
0097 
0098 void UseBuilder::visitMethodCall(Ast *node)
0099 {
0100     Node *n = node->tree;
0101 
0102     /* Visit the method call members */
0103     node->tree = n->l;
0104     if (node->tree->kind == token_method_call) {
0105         m_depth++;
0106         visitMethodCall(node);
0107         m_depth--;
0108     }
0109     m_classMethod = true;
0110     visitMethodCallMembers(node);
0111     if (!m_depth) {
0112         m_lastCtx = nullptr;
0113     }
0114 
0115     /* Visit the method arguments */
0116     node->tree = n->r;
0117     for (Node *aux = n->r; aux; aux = aux->next) {
0118         visitNode(node);
0119         node->tree = aux->next;
0120     }
0121 
0122     /* Vist method call block */
0123     node->tree = n->cond;
0124     visitBlock(node);
0125     node->tree = n;
0126 }
0127 
0128 void UseBuilder::visitMethodCallMembers(Ast *node)
0129 {
0130     RangeInRevision range;
0131     DUContext *ctx = (m_lastCtx) ? m_lastCtx : currentContext();
0132     Declaration *last;
0133     ExpressionVisitor ev(ctx, editor());
0134 
0135     // Go to the next element since we're coming from a recursion and we've
0136     // already checked its children nodes.
0137     if (node->tree->kind == token_method_call) {
0138         node->tree = node->tree->next;
0139     }
0140 
0141     // And this is the loop that does the dirty job.
0142     for (Node *aux = node->tree; aux && ctx; aux = aux->next) {
0143         node->tree = aux;
0144         if (node->tree->kind != token_object) {
0145             // i.e. visit "a" and "b" from (a - b).bytesize
0146             UseBuilderBase::visitNode(node);
0147         }
0148         range = editorFindRange(node, node);
0149         ev.setContext(ctx);
0150         ev.setIsClassMethod(m_classMethod);
0151         ev.visitNode(node);
0152         if (!ev.lastType()) {
0153             DUChainReadLocker lock;
0154             ModuleDeclaration *cdeclaration = dynamic_cast<ModuleDeclaration *>(ctx->owner());
0155             lock.unlock();
0156             if (cdeclaration && !cdeclaration->isModule()) {
0157                 ev.setContext(getClassContext(currentContext()));
0158                 ev.visitNode(node);
0159             }
0160         }
0161         last = ev.lastDeclaration().data();
0162         auto sType = ev.lastType().dynamicCast<StructureType>();
0163 
0164         // Handle the difference between instance & class methods.
0165         if (dynamic_cast<ModuleDeclaration *>(ev.lastDeclaration().data())) {
0166             m_classMethod = true;
0167         } else {
0168             m_classMethod = false;
0169         }
0170 
0171         // Mark a new use if possible
0172         if (last && node->tree->kind != token_self) {
0173             UseBuilderBase::newUse(range, DeclarationPointer(last));
0174         }
0175 
0176         // If this is a StructureType, it means that we're in a case like;
0177         // "A::B::" and therefore the next context should be A::B.
0178         if (!sType) {
0179             // It's not a StructureType, therefore it's a variable or a method.
0180             auto fType = ev.lastType().dynamicCast<FunctionType>();
0181             if (!fType) {
0182                 ctx = (last) ? last->internalContext() : nullptr;
0183             } else {
0184                 DUChainReadLocker lock;
0185                 auto rType = fType->returnType().dynamicCast<StructureType>();
0186                 ctx = (rType) ? rType->internalContext(topContext()) : nullptr;
0187             }
0188         } else {
0189             DUChainReadLocker lock;
0190             ctx = sType->internalContext(topContext());
0191         }
0192     }
0193     m_lastCtx = ctx;
0194 }
0195 
0196 void UseBuilder::visitRequire(Ast *node, bool relative)
0197 {
0198     Q_UNUSED(node);
0199     Q_UNUSED(relative);
0200 }
0201