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