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

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 #include <duchain/builders/declarationbuilder.h>
0024 
0025 #include <language/duchain/aliasdeclaration.h>
0026 #include <language/duchain/duchainutils.h>
0027 #include <language/duchain/types/functiontype.h>
0028 #include <language/duchain/types/unsuretype.h>
0029 
0030 // Ruby
0031 #include <duchaindebug.h>
0032 #include <duchain/declarations/methoddeclaration.h>
0033 #include <duchain/declarations/moduledeclaration.h>
0034 #include <duchain/declarations/variabledeclaration.h>
0035 #include <duchain/editorintegrator.h>
0036 #include <duchain/expressionvisitor.h>
0037 
0038 using namespace KDevelop;
0039 using namespace ruby;
0040 
0041 DeclarationBuilder::DeclarationBuilder(EditorIntegrator *editor)
0042     : DeclarationBuilderBase()
0043     , m_editor(editor)
0044 {
0045     setEditor(editor);
0046 }
0047 
0048 DeclarationBuilder::~DeclarationBuilder()
0049 {
0050 }
0051 
0052 void DeclarationBuilder::closeDeclaration()
0053 {
0054     if (currentDeclaration() && lastType()) {
0055         DUChainWriteLocker wlock;
0056         currentDeclaration()->setType(lastType());
0057     }
0058     eventuallyAssignInternalContext();
0059     DeclarationBuilderBase::closeDeclaration();
0060 }
0061 
0062 void DeclarationBuilder::closeContext()
0063 {
0064     if (currentContext()->type() == DUContext::Function) {
0065         Q_ASSERT(currentDeclaration<AbstractFunctionDeclaration>());
0066         currentDeclaration<AbstractFunctionDeclaration>()->
0067             setInternalFunctionContext(currentContext());
0068     }
0069 
0070     DeclarationBuilderBase::closeContext();
0071 }
0072 
0073 void DeclarationBuilder::startVisiting(Ast *node)
0074 {
0075     m_unresolvedImports.clear();
0076     m_injected = false;
0077     m_lastMethodCall = nullptr;
0078 
0079     DeclarationBuilderBase::startVisiting(node);
0080 }
0081 
0082 bool DeclarationBuilder::declaredInContext(const QByteArray &name) const
0083 {
0084     return declaredIn(name, DUContextPointer(currentContext()));
0085 }
0086 
0087 void DeclarationBuilder::visitClassStatement(Ast *node)
0088 {
0089     ModuleDeclaration *baseClass = nullptr;
0090     RangeInRevision range = getNameRange(node);
0091     const QByteArray comment = getComment(node);
0092     QualifiedIdentifier id = getIdentifier(node);
0093     DUContext *ctx = getContainedNameContext(node);
0094 
0095     /* First of all, open the declaration. */
0096     ModuleDeclaration *decl = reopenDeclaration<ModuleDeclaration>(id, range, ctx, DeclarationKind::Class);
0097     if (!decl) {
0098         node->foundProblems = true;
0099         return;
0100     }
0101 
0102     // Initialize the declaration.
0103     DUChainWriteLocker lock;
0104     if (!comment.isEmpty()) {
0105         decl->setComment(comment);
0106     }
0107     decl->setIsModule(false);
0108     decl->clearBaseClass();
0109     decl->clearModuleMixins();
0110     decl->setKind(KDevelop::Declaration::Type);
0111     m_accessPolicy.push(Declaration::Public);
0112     m_classDeclarations.push(DeclarationPointer(decl));
0113 
0114     /*
0115      * Now let's check for the base class. Ruby does not support multiple
0116      * inheritance, and the access is always public.
0117      */
0118     Node *aux = node->tree;
0119     node->tree = node->tree->cond;
0120     if (node->tree) {
0121         ExpressionVisitor ev(ctx, m_editor);
0122         lock.unlock();
0123         ev.visitNode(node);
0124         DeclarationPointer baseDecl = ev.lastDeclaration();
0125         lock.lock();
0126         if (baseDecl) {
0127             baseClass = dynamic_cast<ModuleDeclaration *>(baseDecl.data());
0128             if (!baseClass || baseClass->isModule()) {
0129                 appendProblem(
0130                     node->tree,
0131                     i18n("TypeError: wrong argument type (expected Class)")
0132                 );
0133             } else if (baseClass->internalContext()) {
0134                 decl->setBaseClass(baseClass->indexedType());
0135             }
0136         }
0137     }
0138     node->tree = aux;
0139 
0140     /*  Setup types and go for the class body */
0141     ClassType::Ptr type(new ClassType());
0142     type->setDeclaration(decl);
0143     decl->setType(type);
0144     openType(type);
0145 
0146     openContextForClassDefinition(decl, node);
0147     if (baseClass && baseClass->internalContext()) {
0148         currentContext()->addImportedParentContext(baseClass->internalContext());
0149     }
0150     decl->setInternalContext(currentContext());
0151     lock.unlock();
0152     DeclarationBuilderBase::visitClassStatement(node);
0153     lock.lock();
0154     closeContext();
0155 
0156     closeType();
0157     closeDeclaration();
0158     m_classDeclarations.pop();
0159     m_accessPolicy.pop();
0160 }
0161 
0162 void DeclarationBuilder::visitSingletonClass(Ast *node)
0163 {
0164     ExpressionVisitor ev(currentContext(), m_editor);
0165     Node *aux = node->tree;
0166 
0167     node->tree = node->tree->r;
0168     ev.visitNode(node);
0169     if (ev.lastType()) {
0170         DeclarationPointer d = ev.lastDeclaration();
0171         if (d) {
0172             m_instance = false;
0173             if (!d->internalContext()) {
0174                 StructureType::Ptr sType;
0175                 auto ut = ev.lastType().dynamicCast<UnsureType>();
0176                 if (ut && ut->typesSize() > 0) {
0177                     sType = ut->types()[0].type<StructureType>();
0178                 } else {
0179                     sType = ev.lastType().dynamicCast<StructureType>();
0180                 }
0181                 if (sType) {
0182                     DUChainWriteLocker lock;
0183                     d = sType->declaration(topContext());
0184                     m_instance = true;
0185                 } else {
0186                     d = DeclarationPointer();
0187                 }
0188             }
0189             if (d) {
0190                 m_classDeclarations.push(d);
0191                 m_injected = true;
0192                 injectContext(d->internalContext());
0193             }
0194         }
0195     }
0196 
0197     node->tree = aux;
0198     m_accessPolicy.push(Declaration::Public);
0199     AstVisitor::visitSingletonClass(node);
0200     m_accessPolicy.pop();
0201     if (m_injected) {
0202         closeInjectedContext();
0203         m_injected = false;
0204         m_classDeclarations.pop();
0205     }
0206 }
0207 
0208 void DeclarationBuilder::visitModuleStatement(Ast *node)
0209 {
0210     RangeInRevision range = getNameRange(node);
0211     QualifiedIdentifier id = getIdentifier(node);
0212     const QByteArray comment = getComment(node);
0213     DUContext *ctx = getContainedNameContext(node);
0214 
0215     /* First of all, open the declaration. */
0216     ModuleDeclaration *decl = reopenDeclaration<ModuleDeclaration>(id, range, ctx, DeclarationKind::Module);
0217     if (!decl) {
0218         node->foundProblems = true;
0219         return;
0220     }
0221 
0222     // Initialize the declaration.
0223     DUChainWriteLocker wlock;
0224     if (!comment.isEmpty()) {
0225         decl->setComment(comment);
0226     }
0227     decl->setIsModule(true);
0228     decl->clearModuleMixins();
0229     decl->clearMixers();
0230     decl->setKind(KDevelop::Declaration::Type);
0231     m_accessPolicy.push(Declaration::Public);
0232     m_classDeclarations.push(DeclarationPointer(decl));
0233 
0234     StructureType::Ptr type(new StructureType());
0235     type->setDeclaration(decl);
0236     decl->setType(type);
0237     openType(type);
0238 
0239     openContextForClassDefinition(decl, node);
0240     decl->setInternalContext(currentContext());
0241     wlock.unlock();
0242     DeclarationBuilderBase::visitModuleStatement(node);
0243     wlock.lock();
0244     closeContext();
0245 
0246     closeType();
0247     closeDeclaration();
0248     m_accessPolicy.pop();
0249     m_classDeclarations.pop();
0250 }
0251 
0252 void DeclarationBuilder::visitMethodStatement(Ast *node)
0253 {
0254     RangeInRevision range = getNameRange(node);
0255     QualifiedIdentifier id = getIdentifier(node);
0256     const QByteArray comment = getComment(node);
0257     bool injectedContext = false;
0258     bool instance = true;
0259     Node *aux = node->tree;
0260 
0261     /*
0262      * Check if this is a singleton method. If it is so, we have to determine
0263      * what's the context to be injected in order to get everything straight.
0264      */
0265     // TODO: this will change with the introduction of the eigen class.
0266     node->tree = aux->cond;
0267     if (valid_children(node->tree)) {
0268         node->tree = node->tree->l;
0269         ExpressionVisitor ev(currentContext(), m_editor);
0270         ev.visitNode(node);
0271         if (ev.lastType()) {
0272             DeclarationPointer d = ev.lastDeclaration();
0273             if (d) {
0274                 if (!d->internalContext()) {
0275                     DUChainWriteLocker lock;
0276                     auto sType = ev.lastType().dynamicCast<StructureType>();
0277                     d = (sType) ? sType->declaration(topContext()) : nullptr;
0278                     instance = true;
0279                 } else
0280                     instance = false;
0281                 if (d) {
0282                     injectedContext = true;
0283                     injectContext(d->internalContext());
0284                     node->tree = aux->cond->r;
0285                     id = getIdentifier(node);
0286                     range = editorFindRange(node, node);
0287                 }
0288             }
0289         }
0290     }
0291     node->tree = aux;
0292 
0293     // Re-open the declaration.
0294     bool isClassMethod = (m_injected) ? !m_instance : !instance;
0295     MethodDeclaration *decl = reopenDeclaration(id, range, isClassMethod);
0296 
0297     DUChainWriteLocker lock;
0298     if (!comment.isEmpty()) {
0299         decl->setComment(comment);
0300     }
0301     decl->clearYieldTypes();
0302     decl->setClassMethod(isClassMethod);
0303 
0304     FunctionType::Ptr type = FunctionType::Ptr(new FunctionType());
0305     if (currentContext()->type() == DUContext::Class) {
0306         decl->setAccessPolicy(currentAccessPolicy());
0307     }
0308 
0309     openType(type);
0310     decl->setInSymbolTable(false);
0311     decl->setType(type);
0312     decl->clearDefaultParameters();
0313     lock.unlock();
0314     DeclarationBuilderBase::visitMethodStatement(node);
0315     lock.lock();
0316     closeDeclaration();
0317     closeType();
0318 
0319     /*
0320      * In Ruby, a method returns the last expression if no return expression
0321      * has been fired. Thus, the type of the last expression has to be mixed
0322      * into the return type of this method.
0323      */
0324     node->tree = aux->l;
0325     if (node->tree && node->tree->l) {
0326         node->tree = get_last_expr(node->tree->l);
0327         if (node->tree->kind != token_return) {
0328             lock.unlock();
0329             ExpressionVisitor ev(node->context, m_editor);
0330             ev.visitNode(node);
0331             if (ev.lastType()) {
0332                 type->setReturnType(mergeTypes(ev.lastType(), type->returnType()));
0333             }
0334             lock.lock();
0335         }
0336     }
0337     node->tree = aux;
0338 
0339     if (!type->returnType()) {
0340         type->setReturnType(getBuiltinsType(QStringLiteral("NilClass"), currentContext()));
0341     }
0342     decl->setType(type);
0343     decl->setInSymbolTable(true);
0344 
0345     if (injectedContext) {
0346         closeInjectedContext();
0347     }
0348 }
0349 
0350 void DeclarationBuilder::visitParameter(Ast *node)
0351 {
0352     MethodDeclaration *mDecl = dynamic_cast<MethodDeclaration *>(currentDeclaration());
0353     ExpressionVisitor ev(currentContext(), m_editor);
0354     ev.visitParameter(node);
0355     AbstractType::Ptr type = ev.lastType();
0356 
0357     /* Just grab the left side if this is an optional parameter */
0358     if (node->tree->l) {
0359         DUChainWriteLocker wlock;
0360         Node *aux = node->tree->l;
0361         node->tree = node->tree->r;
0362         mDecl->addDefaultParameter(IndexedString(m_editor->tokenToString(node->tree)));
0363         node->tree = aux;
0364     }
0365 
0366     /* Finally, declare the parameter */
0367     FunctionType::Ptr mType = currentType<FunctionType>();
0368     if (mType) {
0369         DUChainWriteLocker wlock;
0370         mType->addArgument(type);
0371         declareVariable(getIdentifier(node), type, node, DUContext::DontSearchInParent);
0372     }
0373 }
0374 
0375 void DeclarationBuilder::visitBlock(Ast *node)
0376 {
0377     m_accessPolicy.push(Declaration::Public);
0378     DeclarationBuilderBase::visitBlock(node);
0379     m_accessPolicy.pop();
0380 }
0381 
0382 void DeclarationBuilder::visitBlockVariables(Ast *node)
0383 {
0384     DUChainReadLocker rlock;
0385     MethodDeclaration *last = dynamic_cast<MethodDeclaration *>(m_lastMethodCall);
0386     Node *n = node->tree;
0387     if (!n) {
0388         return;
0389     }
0390 
0391     uint max = 0, i = 0;
0392     const YieldType *yieldList = nullptr;
0393     if (last) {
0394         yieldList = last->yieldTypes();
0395         max = last->yieldTypesSize();
0396     }
0397 
0398     AbstractType::Ptr type;
0399     for (Node *aux = n; aux != nullptr; aux = aux->next, i++) {
0400         node->tree = aux;
0401         if (yieldList && i < max) {
0402             type = yieldList[i].type.abstractType();
0403         } else {
0404             type = getBuiltinsType(QStringLiteral("Object"), currentContext());
0405         }
0406         rlock.unlock();
0407         declareVariable(getIdentifier(node), type, node, DUContext::DontSearchInParent);
0408         rlock.lock();
0409     }
0410 }
0411 
0412 void DeclarationBuilder::visitReturnStatement(Ast *node)
0413 {
0414     AstVisitor::visitReturnStatement(node);
0415 
0416     if (node->tree->l != nullptr) {
0417         node->tree = node->tree->l;
0418         if (!hasCurrentType()) {
0419             appendProblem(node->tree, i18n("Return statement not within function declaration"));
0420             return;
0421         }
0422         TypePtr<FunctionType> t = currentType<FunctionType>();
0423         if (!t) { // the case of: a = -> { return 1 }
0424             return;
0425         }
0426         ExpressionVisitor ev(currentContext(), m_editor);
0427         ev.visitNode(node);
0428         AbstractType::Ptr rType = t->returnType();
0429         DUChainWriteLocker wlock;
0430         t->setReturnType(mergeTypes(ev.lastType(), rType));
0431     }
0432 }
0433 
0434 void DeclarationBuilder::visitAssignmentStatement(Ast *node)
0435 {
0436     QList<AbstractType::Ptr> values;
0437     QList<DeclarationPointer> declarations;
0438     QList<bool> alias;
0439     DUChainReadLocker lock;
0440 
0441     /* First of all, fetch the types and declaration on the right side */
0442     Ast *aux = new Ast(node->tree->r, node->context);
0443     for (Node *n = aux->tree; n != nullptr; n = n->next) {
0444         ExpressionVisitor v(currentContext(), m_editor);
0445         aux->tree = n;
0446         lock.unlock();
0447         // TODO: improve this
0448         DeclarationBuilderBase::visitNode(aux);
0449         v.visitNode(aux);
0450         lock.lock();
0451         values << v.lastType();
0452         alias << v.lastAlias();
0453         declarations << v.lastDeclaration();
0454     }
0455     lock.unlock();
0456 
0457     /*
0458      * Check if we can unpack. If it's possible, do it and get out! We can
0459      * unpack if the following conditions are satisfied:
0460      *  - More than 1 expressions on the left side.
0461      *  - Just one expression on the right side, which has Array as its type.
0462      */
0463     int rsize = values.length();
0464     if (rsize == 1) {
0465         int rest = nodeListSize(node->tree->l);
0466         auto ct = values.first().dynamicCast<ClassType>();
0467         if (rest > 1 && ct && ct->contentType()) {
0468             lock.lock();
0469             QualifiedIdentifier qi = ct.data()->declaration(topContext())->qualifiedIdentifier();
0470             lock.unlock();
0471             if (qi == QualifiedIdentifier("Array")) {
0472                 for (Node *n = node->tree->l; n != nullptr; n = n->next) {
0473                     aux->tree = n;
0474                     QualifiedIdentifier id = getIdentifier(aux);
0475                     declareVariable(id, ct->contentType().abstractType(), aux);
0476                 }
0477                 delete aux;
0478                 return;
0479             }
0480         }
0481     }
0482 
0483     /*
0484      * We cannot unpack, so iterate over the left side expressions
0485      * and assign types.
0486      */
0487     int i = 0;
0488     AbstractType::Ptr type;
0489     for (Node *n = node->tree->l; n != nullptr; n = n->next, i++) {
0490         if (n->kind == token_method_call)
0491             continue;
0492         aux->tree = n;
0493         if (has_star(n)) {
0494             int rest = nodeListSize(n) - 1;
0495             int pack = rsize - i - rest;
0496             auto newType = getBuiltinsType(QStringLiteral("Array"), currentContext()).dynamicCast<ClassType>();
0497             DUChainWriteLocker wlock;
0498             for (int j = pack; j > 0; j--, i++) {
0499                 newType->addContentType(values.at(i));
0500             }
0501             wlock.unlock();
0502             i--;
0503             if (!is_just_a_star(n)) {
0504                 QualifiedIdentifier id = getIdentifier(aux);
0505                 declareVariable(id, newType, aux);
0506             }
0507         } else if (i < rsize) {
0508             if (alias.at(i)) {
0509                 DUChainWriteLocker wlock;
0510                 RangeInRevision range = getNameRange(aux);
0511                 QualifiedIdentifier id = getIdentifier(aux);
0512                 AliasDeclaration *d = openDeclaration<AliasDeclaration>(id, range);
0513                 d->setAliasedDeclaration(declarations.at(i).data());
0514                 closeDeclaration();
0515             } else {
0516                 type = values.at(i);
0517                 if (!type) { // HACK: provisional fix, should be removed in the future
0518                     type = getBuiltinsType(QStringLiteral("Object"), currentContext());
0519                 }
0520                 QualifiedIdentifier id = getIdentifier(aux);
0521                 declareVariable(id, type, aux);
0522             }
0523         } else {
0524             lock.lock();
0525             type = getBuiltinsType(QStringLiteral("NilClass"), currentContext());
0526             lock.unlock();
0527             QualifiedIdentifier id = getIdentifier(aux);
0528             declareVariable(id, type, aux);
0529         }
0530     }
0531     delete aux;
0532 }
0533 
0534 void DeclarationBuilder::visitAliasStatement(Ast *node)
0535 {
0536     Ast *right = new Ast(node->tree->r, node->context);
0537     QualifiedIdentifier id = QualifiedIdentifier(QString(right->tree->name));
0538     const RangeInRevision &range = editorFindRange(right, right);
0539     DeclarationPointer decl = getDeclaration(id, range, DUContextPointer(currentContext()));
0540 
0541     if (is_global_var(node->tree->l) && is_global_var(right->tree)) {
0542         DUChainWriteLocker wlock;
0543         // If the global variable on the right is not declared, declare it as nil
0544         if (!decl) {
0545             AbstractType::Ptr type = topContext()->findDeclarations(QualifiedIdentifier("NilClass")).first()->abstractType();
0546             VariableDeclaration *vDecl = openDefinition<VariableDeclaration>(id, range);
0547             vDecl->setVariableKind(right->tree);
0548             vDecl->setKind(Declaration::Instance);
0549             vDecl->setType(type);
0550             eventuallyAssignInternalContext();
0551             DeclarationBuilderBase::closeDeclaration();
0552             decl = vDecl;
0553         }
0554         node->tree = node->tree->l;
0555         QualifiedIdentifier aid = getIdentifier(node);
0556         AbstractType::Ptr type = decl->abstractType();
0557         declareVariable(aid, type, node);
0558     } else if (decl && decl->isFunctionDeclaration()) {
0559         DUChainWriteLocker wlock;
0560         MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(decl.data());
0561         node->tree = node->tree->l;
0562         const RangeInRevision & arange = editorFindRange(node, node);
0563         QualifiedIdentifier aid = getIdentifier(node);
0564         aliasMethodDeclaration(aid, arange, md);
0565     } else
0566         appendProblem(node->tree, i18n("undefined method `%1'", id.toString()));
0567 }
0568 
0569 void DeclarationBuilder::visitMethodCall(Ast *node)
0570 {
0571     Node *aux = node->tree;
0572 
0573     /*
0574      * Handle chained method calls. Take a look at the implementation of
0575      * AstVisitor::visitMethodCall() for more details.
0576      */
0577     node->tree = aux->l;
0578     if (node->tree->kind == token_method_call)
0579         visitMethodCall(node);
0580     node->tree = aux;
0581 
0582     ExpressionVisitor v(currentContext(), m_editor);
0583     v.visitNode(node);
0584     DeclarationPointer lastMethod = v.lastDeclaration();
0585 
0586     /* Let's take a look at the method arguments */
0587     visitMethodCallArgs(node, lastMethod);
0588 
0589     /* And last but not least, go for the block */
0590     node->tree = aux->cond;
0591     m_lastMethodCall = lastMethod.data();
0592     visitBlock(node);
0593     m_lastMethodCall = nullptr;
0594     node->tree = aux;
0595 }
0596 
0597 void DeclarationBuilder::visitMixin(Ast *node, bool include)
0598 {
0599     Ast *module = new Ast(node->tree->r, node->context);
0600     ModuleDeclaration *decl = getModuleDeclaration(module);
0601 
0602     if (decl) {
0603         // Report an error if we're completely sure that this is not a module.
0604         if (!decl->isModule()) {
0605             appendProblem(node->tree->r, i18n("TypeError: wrong argument type (expected Module)"));
0606             return;
0607         }
0608 
0609         // Register the Module mixin
0610         if (insideClassModule()) {
0611             ModuleDeclaration *current = dynamic_cast<ModuleDeclaration *>(lastClassModule());
0612             if (current) {
0613                 DUChainWriteLocker lock;
0614                 ModuleMixin mixin;
0615                 mixin.included = include;
0616                 mixin.module = decl->indexedType();
0617                 current->addModuleMixin(mixin);
0618                 mixin.module = current->indexedType();
0619                 decl->addMixer(mixin);
0620             }
0621         }
0622 
0623         // Add all the available methods from the mixed in module
0624         QList<MethodDeclaration *> eMethods = getDeclaredMethods(decl);
0625         foreach (MethodDeclaration *md, eMethods) {
0626             if (md->isClassMethod() ^ include) {
0627                 DUChainWriteLocker wlock;
0628                 aliasMethodDeclaration(md->qualifiedIdentifier(), md->range(), md);
0629             }
0630         }
0631     }
0632     delete module;
0633 }
0634 
0635 void DeclarationBuilder::visitForStatement(Ast *node)
0636 {
0637     Node *aux = node->tree;
0638     node->tree = node->tree->cond;
0639 
0640     ExpressionVisitor ev(currentContext(), m_editor);
0641     ev.visitNode(node);
0642     AbstractType::Ptr type = ev.lastType();
0643 
0644     DUChainReadLocker rlock;
0645     if (type) {
0646         auto ctype = type.dynamicCast<ClassType>();
0647         if (ctype && ctype->contentType()) {
0648             type = ctype->contentType().abstractType();
0649         } else {
0650             type = getBuiltinsType(QStringLiteral("Object"), currentContext());
0651         }
0652     } else {
0653         type = getBuiltinsType(QStringLiteral("Object"), currentContext());
0654     }
0655 
0656     node->tree = aux->r;
0657     for (Node *n = node->tree; n != nullptr; n = n->next) {
0658         node->tree = n;
0659         QualifiedIdentifier id = getIdentifier(node);
0660         rlock.unlock();
0661         declareVariable(id, type, node);
0662         rlock.lock();
0663     }
0664     node->tree = aux;
0665 }
0666 
0667 void DeclarationBuilder::visitAccessSpecifier(const access_t policy)
0668 {
0669     switch (policy) {
0670     case public_a:
0671         setAccessPolicy(Declaration::Public);
0672         break;
0673     case protected_a:
0674         setAccessPolicy(Declaration::Protected);
0675         break;
0676     case private_a:
0677         setAccessPolicy(Declaration::Private);
0678     }
0679 }
0680 
0681 void DeclarationBuilder::visitYieldStatement(Ast *node)
0682 {
0683     MethodDeclaration *mDecl = currentDeclaration<MethodDeclaration>();
0684     Node *n = node->tree;
0685 
0686     if (mDecl && n->l) {
0687         ExpressionVisitor ev(currentContext(), m_editor);
0688         uint i = 0;
0689         for (Node *aux = n->l; aux != nullptr; aux = aux->next, i++) {
0690             node->tree = aux;
0691             ev.visitNode(node);
0692 
0693             DUChainWriteLocker wlock;
0694             YieldType yt = { ev.lastType()->indexed() };
0695             mDecl->replaceYieldTypes(yt, i);
0696             wlock.unlock();
0697         }
0698     }
0699     node->tree = n;
0700 }
0701 
0702 void DeclarationBuilder::visitRescueArg(Ast *node)
0703 {
0704     AbstractType::Ptr type(nullptr);
0705     ModuleDeclaration *mDecl = nullptr;
0706     Node *n = node->tree;
0707     node->tree = n->l;
0708 
0709     /* If there's no rescue variable, don't even care. */
0710     if (!n->r) {
0711         return;
0712     }
0713 
0714     /* Get the type of the exception list. */
0715     for (node->tree = n->l; node->tree; node->tree = node->tree->next) {
0716         ExpressionVisitor ev(currentContext(), m_editor);
0717         ev.visitNode(node);
0718         mDecl = dynamic_cast<ModuleDeclaration *>(ev.lastDeclaration().data());
0719         if (mDecl) {
0720             type = mergeTypes(type, mDecl->indexedType().abstractType());
0721         }
0722     }
0723 
0724     node->tree = n->r;
0725     const QualifiedIdentifier &id = getIdentifier(node);
0726     declareVariable(id, type, node);
0727 }
0728 
0729 const KDevelop::RangeInRevision DeclarationBuilder::getNameRange(const Ast *node) const
0730 {
0731     return m_editor->findRange(rb_name_node(node->tree));
0732 }
0733 
0734 void DeclarationBuilder::openContextForClassDefinition(ModuleDeclaration *decl, Ast *node)
0735 {
0736     RangeInRevision range = editorFindRange(node, node);
0737     KDevelop::QualifiedIdentifier className(getName(node));
0738 
0739     DUChainWriteLocker wlock;
0740 
0741     // Class/Module.
0742     openContext(node, range, DUContext::Class, className);
0743     currentContext()->setLocalScopeIdentifier(className);
0744 
0745     // Eigen class.
0746     DUContext *ctx = openContextInternal(range, DUContext::Other, className);
0747     decl->setEigenClass(ctx);
0748     closeContext();
0749 }
0750 
0751 template<typename T>
0752 T * DeclarationBuilder::reopenDeclaration(const QualifiedIdentifier &id,
0753                                           const RangeInRevision &range,
0754                                           DUContext *context,
0755                                           DeclarationKind kind)
0756 {
0757     Declaration *res = nullptr;
0758     DUChainReadLocker rlock;
0759     QList<Declaration *> decls = context->findDeclarations(id);
0760     rlock.unlock();
0761 
0762     foreach (Declaration *d, decls) {
0763         Declaration *fitting = dynamic_cast<T*>(d);
0764         if (fitting) {
0765             const bool valid = validReDeclaration(d, id, range, kind);
0766             if (!valid)
0767                 return nullptr;
0768 
0769             qCDebug(DUCHAIN) << "Reopening the following declaration: " << d->toString();
0770             openDeclarationInternal(d);
0771             d->setRange(range);
0772             setEncountered(d);
0773             // TODO: register the re-opening
0774             res = d;
0775             break;
0776         } else
0777             qCDebug(DUCHAIN) << "Do not reopen since it's not in the same top context";
0778     }
0779 
0780     if (!res) {
0781         DUChainWriteLocker lock;
0782         injectContext(context);
0783         res = openDeclaration<T>(id, range);
0784         closeInjectedContext();
0785     }
0786     return static_cast<T*>(res);
0787 }
0788 
0789 MethodDeclaration * DeclarationBuilder::reopenDeclaration(const QualifiedIdentifier &id,
0790                                                           const RangeInRevision &range,
0791                                                           bool classMethod)
0792 {
0793     DUChainReadLocker rlock;
0794     Declaration *res = nullptr;
0795     DUContext *ctx = currentContext();
0796 
0797     // Handle class methods here.
0798     if (classMethod) {
0799         Declaration *d = currentContext()->owner();
0800         ModuleDeclaration *md = dynamic_cast<ModuleDeclaration *>(d);
0801         if (!md)
0802             return nullptr;
0803         ctx = md->eigenClass();
0804     }
0805 
0806     /**
0807      * We just want declarations from the current (or eigen) context.
0808      * Moreover, we don't want declarations from imported contexts
0809      * either (base classes).
0810      */
0811     QList<Declaration *> decls = ctx->findLocalDeclarations(id.first(), range.start);
0812     rlock.unlock();
0813     foreach (Declaration *d, decls) {
0814         MethodDeclaration *method = dynamic_cast<MethodDeclaration *>(d);
0815         if (method) {
0816             qCDebug(DUCHAIN) << "Reopening the following method: " << d->toString();
0817             openDeclarationInternal(method);
0818             method->setRange(range);
0819             setEncountered(method);
0820             res = d;
0821             break;
0822         }
0823     }
0824 
0825     if (!res) {
0826         DUChainWriteLocker lock;
0827         injectContext(ctx);
0828         res = openDeclaration<MethodDeclaration>(id, range);
0829         closeInjectedContext();
0830     }
0831     return static_cast<MethodDeclaration *>(res);
0832 }
0833 
0834 void DeclarationBuilder::declareVariable(const QualifiedIdentifier &id,
0835                                          const AbstractType::Ptr &type,
0836                                          Ast *node,
0837                                          DUContext::SearchFlag flags)
0838 {
0839     RangeInRevision range;
0840     Node *aux = node->tree;
0841     QualifiedIdentifier rId(id);
0842     VariableDeclaration *dec = nullptr;
0843     bool hintContainer = false;
0844 
0845     /* Take care of the special a[...] case */
0846     if (aux->kind == token_array_value) {
0847         node->tree = aux->l;
0848         rId = getIdentifier(node);
0849         hintContainer = true;
0850     }
0851     range = editorFindRange(node, node);
0852 
0853     if ((is_ivar(node->tree) || is_cvar(node->tree)) && !m_classDeclarations.isEmpty()) {
0854         DUChainWriteLocker wlock;
0855         DUContext *internal = m_classDeclarations.last()->internalContext();
0856         DUContext *previousCtx = currentContext();
0857         injectContext(internal);
0858         VariableDeclaration *var = reopenDeclaration<VariableDeclaration>(rId, range, currentContext());
0859         var->setRange(RangeInRevision(internal->range().start, internal->range().start));
0860         var->setAutoDeclaration(true);
0861         previousCtx->createUse(var->ownIndex(), range);
0862         var->setVariableKind(node->tree);
0863         var->setKind(Declaration::Instance);
0864         AbstractType::Ptr atype = mergeTypes(var->abstractType(), type);
0865         auto utype = atype.dynamicCast<UnsureType>();
0866         if (!utype || utype->typesSize() > 0) {
0867             var->setType(atype);
0868         } else {
0869             var->setType(getBuiltinsType(QStringLiteral("Object"), currentContext()));
0870         }
0871         wlock.unlock();
0872         DeclarationBuilderBase::closeDeclaration();
0873         wlock.lock();
0874         closeInjectedContext();
0875         node->tree = aux;
0876         return;
0877     }
0878 
0879     /* Let's check if this variable is already declared */
0880     DUChainWriteLocker wlock;
0881     QList<Declaration *> decs = currentContext()->findDeclarations(rId.first(), startPos(node), nullptr, flags);
0882     if (!decs.isEmpty()) {
0883         dec = dynamic_cast<VariableDeclaration *>(decs.last());
0884         if (dec) {
0885             ClassType::Ptr ct = dec->type<ClassType>();
0886             if (ct && hintContainer) {
0887                 ct->addContentType(type);
0888                 dec->setType(ct);
0889             } else
0890                 dec->setType(mergeTypes(dec->abstractType(), type));
0891             node->tree = aux;
0892             return;
0893         }
0894     }
0895 
0896     if (is_global_var(node->tree))
0897         injectContext(topContext());
0898     dec = openDefinition<VariableDeclaration>(rId, range);
0899     dec->setVariableKind(node->tree);
0900     dec->setKind(Declaration::Instance);
0901     dec->setType(type);
0902     wlock.unlock();
0903     DeclarationBuilderBase::closeDeclaration();
0904     wlock.lock();
0905     if (is_global_var(node->tree))
0906         closeInjectedContext();
0907 
0908     node->tree = aux;
0909 }
0910 
0911 void DeclarationBuilder::aliasMethodDeclaration(const QualifiedIdentifier &id,
0912                                                 const RangeInRevision &range,
0913                                                 const MethodDeclaration *decl)
0914 {
0915     setComment(decl->comment());
0916     MethodDeclaration *alias = openDeclaration<MethodDeclaration>(id, range);
0917     alias->setType(decl->type<FunctionType>());
0918     closeDeclaration();
0919 }
0920 
0921 ModuleDeclaration * DeclarationBuilder::getModuleDeclaration(Ast *module) const
0922 {
0923     ExpressionVisitor ev(currentContext(), m_editor);
0924     Declaration *d;
0925 
0926     ev.visitNode(module);
0927     d = ev.lastDeclaration().data();
0928     ModuleDeclaration *found = dynamic_cast<ModuleDeclaration *>(d);
0929     return found;
0930 }
0931 
0932 QList<MethodDeclaration *> DeclarationBuilder::getDeclaredMethods(const Declaration *decl)
0933 {
0934     DUChainReadLocker rlock;
0935     QList<MethodDeclaration *> res;
0936     DUContext *internal = decl->internalContext();
0937     if (!internal)
0938         return res;
0939 
0940     QVector<Declaration *> decls = internal->localDeclarations();
0941     foreach (Declaration *d, decls) {
0942         MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(d);
0943         if (md)
0944             res << md;
0945     }
0946     return res;
0947 }
0948 
0949 bool DeclarationBuilder::validReDeclaration(Declaration *decl, const QualifiedIdentifier &id,
0950                                             const RangeInRevision &range, DeclarationKind kind)
0951 {
0952     // Check that we'll deal just with a class or a module.
0953     if (kind != DeclarationKind::Class && kind != DeclarationKind::Module) {
0954         return true;
0955     }
0956     ModuleDeclaration *md = dynamic_cast<ModuleDeclaration *>(decl);
0957     if (!md) {
0958         return true;
0959     }
0960 
0961     // Now let's check that we're not trying to redeclare a class as
0962     // a module and viceversa.
0963     const bool mod = md->isModule();
0964     if ((mod && kind == DeclarationKind::Class)
0965             || (!mod && kind == DeclarationKind::Module)) {
0966         QString str;
0967         if (kind == DeclarationKind::Class) {
0968             str = QStringLiteral("class");
0969         } else {
0970             str = QStringLiteral("module");
0971         }
0972         const QString msg = i18n("TypeError: %1 is not a %2", id.toString(), str);
0973 
0974         appendProblem(range, msg);
0975         return false;
0976     }
0977     return true;
0978 }
0979 
0980 DUContext * DeclarationBuilder::getContainedNameContext(Ast *node)
0981 {
0982     Node *aux = node->tree;
0983     Node *last = aux->r->last;
0984     DUContext *ctx = currentContext();
0985     ExpressionVisitor ev(currentContext(), m_editor);
0986 
0987     if (!last)
0988         return ctx;
0989     for (Node *n = aux->r; n != last; n = n->next) {
0990         node->tree = n;
0991         ev.visitNode(node);
0992         const DeclarationPointer d = ev.lastDeclaration();
0993         if (d) {
0994             ctx = d->internalContext();
0995             ev.setContext(ctx);
0996         } else
0997             break;
0998     }
0999     node->tree = aux;
1000     return ctx;
1001 }
1002 
1003 void DeclarationBuilder::visitMethodCallArgs(const Ast *mc, const DeclarationPointer &lastMethod)
1004 {
1005     DUChainReadLocker rlock;
1006     Ast *node = new Ast(mc->tree->r, mc->context);
1007     VariableDeclaration *vd;
1008     int total, left = 0, right = 0;
1009     bool mark = false, starSeen = false;
1010 
1011     DUContext *argCtx = nullptr;
1012     if (lastMethod.data())
1013         argCtx = DUChainUtils::argumentContext(lastMethod.data());
1014     if (!argCtx || !lastMethod->type<FunctionType>()) {
1015         /*
1016          * We couldn't get enough info, visit the list of parameters as a
1017          * regular list and get out.
1018          */
1019         for (Node *n = node->tree; n; n = n->next) {
1020             node->tree = n;
1021             rlock.unlock();
1022             DeclarationBuilderBase::visitNode(node);
1023             rlock.lock();
1024         }
1025         delete node;
1026         return;
1027     }
1028 
1029     QVector<Declaration *> args = argCtx->localDeclarations();
1030     rlock.unlock();
1031     if (args.isEmpty())
1032         total = 0;
1033     else {
1034         vd = dynamic_cast<VariableDeclaration *>(args.last());
1035         total = args.size() - vd->isBlock();
1036     }
1037 
1038     /*
1039      * Normal arguments can appear before and/or after a list of opt_args
1040      * and a rest_arg. Therefore, these kind of arguments will mark the left
1041      * side and the right side. This is important to know because of the
1042      * flexibility that Ruby gives to the programmer.
1043      */
1044     for (int i = 0; i < total; i++) {
1045         vd = dynamic_cast<VariableDeclaration *>(args.at(i));
1046         if (!vd->hasStar() && !vd->isOpt()) {
1047             (mark) ? right++ : left++;
1048         } else if (vd->hasStar()) {
1049             starSeen = true;
1050             mark = true;
1051         } else
1052             mark = true;
1053     }
1054 
1055     /* We have enough info to know if we have to raise an ArgumentError */
1056     int nCaller = nodeListSize(node->tree);
1057     if (nCaller < (left + right)) {
1058         appendProblem(mc->tree, i18n("wrong number of arguments (%1 for %2)"
1059                                        " (ArgumentError)", nCaller, left + right));
1060         delete node;
1061         return;
1062     } else if (!starSeen && (total < nCaller)) {
1063         appendProblem(mc->tree, i18n("wrong number of arguments (%1 for %2)"
1064                                        " (ArgumentError)", nCaller, total));
1065         delete node;
1066         return;
1067     }
1068 
1069     /*
1070      * Everything is fine, do the iteration. Note that opt_args and rest_args
1071      * will be fed depending on the left and right counters.
1072      */
1073     int i = 0;
1074     int rest = nCaller - left - right;
1075     DUChainWriteLocker wlock;
1076     for (Node *n = node->tree; n; i++) {
1077         vd = dynamic_cast<VariableDeclaration *>(args.at(i));
1078         node->tree = n;
1079         if (vd->isOpt()) {
1080             if (rest > 0)
1081                 rest--;
1082             else
1083                 continue;
1084         } else if (vd->hasStar()) {
1085             ClassType::Ptr ct = vd->type<ClassType>();
1086             if (!ct) {// TODO: shouldn't happen but it does :(
1087                 n = n->next;
1088                 continue;
1089             }
1090             for (int j = rest; j > 0; j--) {
1091                 ExpressionVisitor av(currentContext(), m_editor);
1092                 av.visitNode(node);
1093                 if (av.lastType())
1094                     ct->addContentType(av.lastType());
1095                 node->tree = node->tree->next;
1096             }
1097             vd->setType(ct);
1098             n = node->tree;
1099             continue;
1100         }
1101         ExpressionVisitor av(currentContext(), m_editor);
1102         wlock.unlock();
1103         DeclarationBuilderBase::visitNode(node);
1104         wlock.lock();
1105         av.visitNode(node);
1106         AbstractType::Ptr last = av.lastType();
1107         AbstractType::Ptr original = args.at(i)->abstractType();
1108         args.at(i)->setType(mergeTypes(original, last));
1109         n = n->next;
1110     }
1111     delete node;
1112 }
1113