File indexing completed on 2024-04-21 04:35:54

0001 /*
0002  * This file is part of KDevelop
0003  * Copyright (C) 2012-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/editorintegrator.h>
0020 
0021 #include <language/duchain/aliasdeclaration.h>
0022 #include <language/duchain/declaration.h>
0023 #include <language/duchain/topducontext.h>
0024 #include <language/duchain/types/functiontype.h>
0025 #include <language/duchain/types/integraltype.h>
0026 #include <language/duchain/types/unsuretype.h>
0027 
0028 #include <duchain/declarations/methoddeclaration.h>
0029 #include <duchain/declarations/moduledeclaration.h>
0030 #include <duchain/expressionvisitor.h>
0031 #include <duchain/helpers.h>
0032 
0033 using namespace KDevelop;
0034 namespace ruby {
0035 
0036 ExpressionVisitor::ExpressionVisitor(DUContext *ctx, EditorIntegrator *editor)
0037     : m_ctx(ctx)
0038     , m_editor(editor)
0039     , m_lastDeclaration(nullptr)
0040     , m_alias(false)
0041 {
0042     m_lastType = nullptr;
0043     m_lastCtx = nullptr;
0044     m_declarationKind = DeclarationKind::Unknown;
0045 }
0046 
0047 ExpressionVisitor::ExpressionVisitor(ExpressionVisitor *parent)
0048     : m_ctx(parent->m_ctx)
0049     , m_editor(parent->m_editor)
0050     , m_lastDeclaration(nullptr)
0051     , m_alias(false)
0052 {
0053     m_lastType = nullptr;
0054     m_lastCtx = nullptr;
0055     m_declarationKind = DeclarationKind::Unknown;
0056 }
0057 
0058 void ExpressionVisitor::setContext(DUContext *ctx)
0059 {
0060     m_ctx = ctx;
0061     m_lastType = nullptr;
0062     m_lastDeclaration = nullptr;
0063     m_alias = false;
0064     m_lastCtx = nullptr;
0065     m_declarationKind = DeclarationKind::Unknown;
0066 }
0067 
0068 void ExpressionVisitor::setIsClassMethod(bool isClassMethod)
0069 {
0070     if (isClassMethod) {
0071         m_declarationKind = DeclarationKind::ClassMethod;
0072     } else {
0073         m_declarationKind = DeclarationKind::InstanceMethod;
0074     }
0075 }
0076 
0077 void ExpressionVisitor::setDeclarationKind(const DeclarationKind kind)
0078 {
0079     m_declarationKind = kind;
0080 }
0081 
0082 void ExpressionVisitor::visitParameter(Ast *node)
0083 {
0084     AbstractType::Ptr obj;
0085 
0086     if (is_block_arg(node->tree)) {
0087         obj = getBuiltinsType(QStringLiteral("Proc"), m_ctx);
0088     } else if (is_rest_arg(node->tree)) {
0089         obj = getBuiltinsType(QStringLiteral("Array"), m_ctx);
0090     } else if (node->tree->r != nullptr) {
0091         ExpressionVisitor da(this);
0092         Node *n = node->tree;
0093         node->tree = node->tree->r;
0094         da.visitNode(node);
0095         node->tree = n;
0096         obj = da.lastType();
0097     } else {
0098         obj = getBuiltinsType(QStringLiteral("Object"), m_ctx);
0099     }
0100     encounter(obj);
0101 }
0102 
0103 bool ExpressionVisitor::declaredInContext(const QByteArray &name) const
0104 {
0105     return declaredIn(name, DUContextPointer(m_ctx));
0106 }
0107 
0108 void ExpressionVisitor::visitName(Ast *node)
0109 {
0110     if (!node->tree) {
0111         return;
0112     }
0113 
0114     QualifiedIdentifier id = getIdentifier(node);
0115     RangeInRevision range = m_editor->findRange(node->tree);
0116     DeclarationPointer decl = getDeclaration(id, range,
0117                                              DUContextPointer(m_ctx),
0118                                              m_declarationKind);
0119     DUChainReadLocker lock;
0120 
0121     if (decl) {
0122         m_alias = dynamic_cast<AliasDeclaration *>(decl.data());
0123         m_lastDeclaration = decl;
0124         encounter(decl->abstractType());
0125     }
0126 }
0127 
0128 void ExpressionVisitor::visitTrue(Ast *)
0129 {
0130     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("TrueClass"), m_ctx);
0131     encounter(obj);
0132 }
0133 
0134 void ExpressionVisitor::visitFalse(Ast *)
0135 {
0136     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("FalseClass"), m_ctx);
0137     encounter(obj);
0138 }
0139 
0140 void ExpressionVisitor::visitNil(Ast *)
0141 {
0142     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("NilClass"), m_ctx);
0143     encounter(obj);
0144 }
0145 
0146 void ExpressionVisitor::visitFile(Ast *)
0147 {
0148     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("String"), m_ctx);
0149     encounter(obj);
0150 }
0151 
0152 void ExpressionVisitor::visitLine(Ast *)
0153 {
0154     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Fixnum"), m_ctx);
0155     encounter(obj);
0156 }
0157 
0158 void ExpressionVisitor::visitEncoding(Ast *)
0159 {
0160     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Encoding"), m_ctx);
0161     encounter(obj);
0162 }
0163 
0164 void ExpressionVisitor::visitSelf(Ast *)
0165 {
0166     DUChainReadLocker lock;
0167     AbstractType::Ptr obj;
0168     DUContext *ctx = m_ctx;
0169 
0170     Declaration *decl = ctx->owner();
0171     while (decl) {
0172         if (dynamic_cast<ModuleDeclaration *>(decl)) {
0173             obj = ctx->owner()->abstractType();
0174             m_lastDeclaration = DeclarationPointer(ctx->owner());
0175             break;
0176         }
0177 
0178         ctx = ctx->parentContext();
0179         if (!ctx) {
0180             break;
0181         }
0182         decl = ctx->owner();
0183     }
0184 
0185     if (!ctx || !decl) {
0186         obj = getBuiltinsType(QStringLiteral("Object"), m_ctx);
0187     }
0188     encounter(obj);
0189 }
0190 
0191 void ExpressionVisitor::visitRange(Ast *)
0192 {
0193     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Range"), m_ctx);
0194     encounter(obj);
0195 }
0196 
0197 void ExpressionVisitor::visitString(Ast *)
0198 {
0199     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("String"), m_ctx);
0200     encounter(obj);
0201 }
0202 
0203 void ExpressionVisitor::visitNumeric(Ast *node)
0204 {
0205     QString type;
0206 
0207     switch (node->tree->flags) {
0208     case float_l:
0209         type = QStringLiteral("Float");
0210         break;
0211     case rational_l:
0212         type = QStringLiteral("Rational");
0213         break;
0214     case imaginary_l:
0215         type = QStringLiteral("Complex");
0216         break;
0217     default:
0218         type = QStringLiteral("Fixnum");
0219     }
0220     AbstractType::Ptr obj = getBuiltinsType(type, m_ctx);
0221     encounter(obj);
0222 }
0223 
0224 void ExpressionVisitor::visitRegexp(Ast *)
0225 {
0226     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Regexp"), m_ctx);
0227     encounter(obj);
0228 }
0229 
0230 void ExpressionVisitor::visitSymbol(Ast *)
0231 {
0232     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Symbol"), m_ctx);
0233     encounter(obj);
0234 }
0235 
0236 void ExpressionVisitor::visitArray(Ast *node)
0237 {
0238     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Array"), m_ctx);
0239     ClassType::Ptr ptr = getContainer(obj, node);
0240     encounter(ptr);
0241 }
0242 
0243 void ExpressionVisitor::visitHash(Ast *node)
0244 {
0245     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Hash"), m_ctx);
0246     ClassType::Ptr ptr = getContainer(obj, node, true);
0247     encounter(ptr);
0248 }
0249 
0250 void ExpressionVisitor::visitArrayValue(Ast *node)
0251 {
0252     Ast *child = new Ast(node->tree->l, node->context);
0253     QualifiedIdentifier id = getIdentifier(child);
0254     RangeInRevision range = m_editor->findRange(child->tree);
0255     DeclarationPointer decl = getDeclaration(id, range, DUContextPointer(m_ctx));
0256 
0257     if (decl) {
0258         auto vc = decl->abstractType().dynamicCast<ClassType>();
0259         if (vc) {
0260             encounter(vc->contentType().abstractType());
0261         }
0262     }
0263     delete child;
0264 }
0265 
0266 void ExpressionVisitor::visitMethodCall(Ast *node)
0267 {
0268     Node *n = node->tree;
0269 
0270     // Handle recursive method calls here.
0271     node->tree = n->l;
0272     if (node->tree->kind == token_method_call) {
0273         visitMethodCall(node);
0274     }
0275 
0276     // Let's evaluate now the members of the current method call.
0277     DeclarationKind oldKind = m_declarationKind;
0278     m_declarationKind = DeclarationKind::InstanceMethod;
0279     visitMethodCallMembers(node);
0280     m_declarationKind = oldKind;
0281     node->tree = n;
0282 }
0283 
0284 void ExpressionVisitor::visitSuper(Ast *)
0285 {
0286     DUChainReadLocker lock;
0287     ModuleDeclaration *mDecl = nullptr;
0288     DUContext *ctx = m_ctx->parentContext();
0289     Declaration *md = m_ctx->owner();
0290 
0291     if (!dynamic_cast<MethodDeclaration *>(md)) {
0292         return;
0293     }
0294 
0295     while (ctx) {
0296         Declaration *d = ctx->owner();
0297         mDecl = dynamic_cast<ModuleDeclaration *>(d);
0298         if (mDecl && !mDecl->isModule()) {
0299             break;
0300         }
0301         ctx = ctx->parentContext();
0302     }
0303     if (!mDecl || mDecl->isModule()) {
0304         return;
0305     }
0306 
0307     auto type = mDecl->baseClass().abstractType().dynamicCast<StructureType>();
0308     if (!type) {
0309         return;
0310     }
0311     ctx = type->internalContext(m_ctx->topContext());
0312     if (!ctx) {
0313         return;
0314     }
0315 
0316     for (const Declaration *d : ctx->findLocalDeclarations(md->identifier())) {
0317         if (d->type<FunctionType>()) {
0318             encounter(d->type<FunctionType>()->returnType());
0319             break;
0320         }
0321     }
0322 }
0323 
0324 void ExpressionVisitor::visitLambda(Ast *)
0325 {
0326     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Proc"), m_ctx);
0327     encounter(obj);
0328 }
0329 
0330 void ExpressionVisitor::visitWhileStatement(Ast *)
0331 {
0332     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("NilClass"), m_ctx);
0333     encounter(obj);
0334 }
0335 
0336 void ExpressionVisitor::visitForStatement(Ast *node)
0337 {
0338     ExpressionVisitor ev(this);
0339     Node *n = node->tree;
0340     node->tree = n->l;
0341     AstVisitor::visitNode(node);
0342     node->tree = n->cond;
0343     ev.visitNode(node);
0344     node->tree = n;
0345     encounter(ev.lastType());
0346 }
0347 
0348 void ExpressionVisitor::visitBinary(Ast *node)
0349 {
0350     Node *n = node->tree;
0351     node->tree = node->tree->l;
0352     ExpressionVisitor ev(this);
0353     ev.visitNode(node);
0354     AbstractType::Ptr left = ev.lastType();
0355     node->tree = n->r;
0356     ev.visitNode(node);
0357     node->tree = n;
0358     encounter(mergeTypes(left, ev.lastType()));
0359 }
0360 
0361 void ExpressionVisitor::visitBoolean(Ast *)
0362 {
0363     AbstractType::Ptr t = getBuiltinsType(QStringLiteral("TrueClass"), m_ctx);
0364     AbstractType::Ptr f = getBuiltinsType(QStringLiteral("FalseClass"), m_ctx);
0365     encounter(mergeTypes(t, f));
0366 }
0367 
0368 void ExpressionVisitor::visitIfStatement(Ast *node)
0369 {
0370     Node *aux = node->tree;
0371     node->tree = aux->l;
0372     ExpressionVisitor::visitLastStatement(node);
0373     AbstractType::Ptr res = lastType();
0374     node->tree = aux->r;
0375     ExpressionVisitor::visitLastStatement(node);
0376     res = mergeTypes(res, lastType());
0377 
0378     encounter(res);
0379     node->tree = aux;
0380 }
0381 
0382 void ExpressionVisitor::visitCaseStatement(Ast *node)
0383 {
0384     Node *aux = node->tree;
0385     AbstractType::Ptr res;
0386 
0387     for (Node *n = aux->l; n != nullptr; n = n->r) {
0388         node->tree = n->l;
0389         ExpressionVisitor::visitLastStatement(node);
0390         res = mergeTypes(res, lastType());
0391     }
0392     encounter(res);
0393     node->tree = aux;
0394 }
0395 
0396 void ExpressionVisitor::visitMethodStatement(Ast *)
0397 {
0398     AbstractType::Ptr obj = getBuiltinsType(QStringLiteral("Symbol"), m_ctx);
0399     encounter(obj);
0400 }
0401 
0402 ClassType::Ptr ExpressionVisitor::getContainer(AbstractType::Ptr ptr, const Ast *node, bool hasKey)
0403 {
0404     auto ct = ptr.dynamicCast<ClassType>();
0405 
0406     if (ct) {
0407         ExpressionVisitor ev(this);
0408         // TODO: I bet we can avoid this heap allocation.
0409         Ast *ast = new Ast(node->tree->l, node->context);
0410         for (Node *n = ast->tree; n != nullptr; n = n->next) {
0411             if (hasKey) {
0412                 Node *aux = ast->tree;
0413                 ast->tree = ast->tree->r;
0414                 ev.visitNode(ast);
0415                 ast->tree = aux;
0416             } else {
0417                 ev.visitNode(ast);
0418             }
0419             ct->addContentType(ev.lastType());
0420             ast->tree = n->next;
0421         }
0422         delete ast;
0423     }
0424     return ct;
0425 }
0426 
0427 void ExpressionVisitor::visitLastStatement(Ast *node)
0428 {
0429     if (!node->tree) {
0430         return;
0431     }
0432 
0433     Node *n = node->tree;
0434     if (n->last) {
0435         node->tree = n->last;
0436     }
0437     ExpressionVisitor::visitNode(node);
0438     node->tree = n;
0439 }
0440 
0441 void ExpressionVisitor::visitMethodCallMembers(Ast *node)
0442 {
0443     DUChainReadLocker rlock;
0444     RangeInRevision range;
0445     DUContext *ctx = (m_lastCtx) ? m_lastCtx : m_ctx;
0446     ExpressionVisitor ev(this);
0447 
0448     /*
0449      * Go to the next element since we're coming from a recursion and we've
0450      * already checked its children nodes.
0451      */
0452     if (node->tree->kind == token_method_call) {
0453         node->tree = node->tree->next;
0454     }
0455 
0456     // And this is the loop that does the dirty job.
0457     for (Node *aux = node->tree; aux; aux = aux->next) {
0458         node->tree = aux;
0459         range = m_editor->findRange(node->tree);
0460         ev.setContext(ctx);
0461         ev.setDeclarationKind(m_declarationKind);
0462         rlock.unlock();
0463         ev.visitNode(node);
0464         m_lastDeclaration = ev.lastDeclaration().data();
0465         auto sType = ev.lastType().dynamicCast<StructureType>();
0466         rlock.lock();
0467 
0468         /*
0469          * If this is a StructureType, it means that we're in a case like;
0470          * "A::B::" and therefore the next context should be A::B.
0471          */
0472         if (!sType) {
0473             // It's not a StructureType, therefore it's a variable or a method.
0474             auto fType = ev.lastType().dynamicCast<FunctionType>();
0475             if (!fType) {
0476                 ctx = (m_lastDeclaration) ? m_lastDeclaration->internalContext() : nullptr;
0477             } else {
0478                 auto rType = fType->returnType().dynamicCast<StructureType>();
0479                 if (rType) {
0480                     encounter(fType->returnType());
0481                     ctx = rType->internalContext(ctx->topContext());
0482                 } else {
0483                     auto ut = fType->returnType().dynamicCast<UnsureType>();
0484                     if (ut) {
0485                         encounter(ut);
0486                     }
0487                     ctx = nullptr;
0488                 }
0489             }
0490             // TODO
0491             // m_declarationKind = InstanceMethod;
0492         } else {
0493             encounter(ev.lastType());
0494             m_declarationKind = DeclarationKind::ClassMethod;
0495             ctx = sType->internalContext(ctx->topContext());
0496         }
0497 
0498         // No context found, we can't go any further.
0499         if (!ctx) {
0500             return;
0501         }
0502     }
0503     m_lastCtx = ctx;
0504 }
0505 
0506 }