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 }