File indexing completed on 2024-04-28 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 0020 // Qt + KDevelop 0021 #include <QtTest/QtTest> 0022 #include <language/duchain/duchain.h> 0023 #include <language/duchain/declaration.h> 0024 #include <language/duchain/types/integraltype.h> 0025 #include <language/duchain/types/structuretype.h> 0026 #include <language/duchain/types/unsuretype.h> 0027 #include <language/duchain/types/functiontype.h> 0028 #include <language/duchain/duchainutils.h> 0029 #include <language/duchain/problem.h> 0030 0031 // Ruby 0032 #include <duchain/tests/duchain.h> 0033 #include <duchain/helpers.h> 0034 #include <duchain/types/classtype.h> 0035 #include <duchain/declarations/methoddeclaration.h> 0036 #include <duchain/declarations/moduledeclaration.h> 0037 #include <duchain/declarations/variabledeclaration.h> 0038 0039 QTEST_MAIN(ruby::TestDUChain) 0040 0041 using namespace KDevelop; 0042 namespace ruby 0043 { 0044 0045 TestDUChain::TestDUChain() 0046 { 0047 /* There's nothing to do here */ 0048 } 0049 0050 TopDUContext * TestDUChain::parse(const QByteArray &code, const QString &id) 0051 { 0052 const QString &name = "duchain_" + id; 0053 return DUChainTestBase::parse(code, name); 0054 } 0055 0056 void TestDUChain::testUnsureTypes(TypePtr<UnsureType> type, const QStringList &list) 0057 { 0058 for (uint i = 0; i < type->typesSize(); i++) { 0059 QualifiedIdentifier qi = type->types()[i].type<StructureType>()->qualifiedIdentifier(); 0060 qDebug() << qi.toString() << " " << list[i]; 0061 QCOMPARE(qi, QualifiedIdentifier(list[i])); 0062 } 0063 } 0064 0065 void TestDUChain::testProblems(TopDUContext *ctx, const QStringList &list) 0066 { 0067 int i = 0; 0068 QList<ProblemPointer> problems = ctx->problems(); 0069 QVERIFY(problems.size() == list.size()); 0070 foreach (ProblemPointer pp, problems) { 0071 Problem *p = pp.data(); 0072 QCOMPARE(p->description(), list[i]); 0073 i++; 0074 } 0075 } 0076 0077 //BEGIN: Builtin classes 0078 0079 void TestDUChain::numeric() 0080 { 0081 QByteArray code("a = 1; b = 1.2; c = 12i; d = 34r"); 0082 TopDUContext *top = parse(code, "numeric"); 0083 DUChainReleaser releaser(top); 0084 DUChainWriteLocker lock; 0085 0086 Declaration *dec1 = top->localDeclarations().at(0); 0087 QVERIFY(dec1->type<StructureType>()); 0088 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0089 0090 Declaration *dec2 = top->localDeclarations().at(1); 0091 QVERIFY(dec2->type<StructureType>()); 0092 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Float")); 0093 0094 Declaration *dec3 = top->localDeclarations().at(2); 0095 QVERIFY(dec3->type<StructureType>()); 0096 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Complex")); 0097 0098 Declaration *dec4 = top->localDeclarations().at(3); 0099 QVERIFY(dec4->type<StructureType>()); 0100 QCOMPARE(dec4->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Rational")); 0101 } 0102 0103 void TestDUChain::range() 0104 { 0105 QByteArray code("a = 1..42"); 0106 TopDUContext *top = parse(code, "range"); 0107 DUChainReleaser releaser(top); 0108 DUChainWriteLocker lock; 0109 0110 Declaration *dec1 = top->localDeclarations().at(0); 0111 QVERIFY(dec1->type<StructureType>()); 0112 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Range")); 0113 } 0114 0115 void TestDUChain::stringAndRegexp() 0116 { 0117 QByteArray code("a = 'string'; b = //"); 0118 TopDUContext *top = parse(code, "stringAndRegexp"); 0119 DUChainReleaser releaser(top); 0120 DUChainWriteLocker lock; 0121 0122 QVERIFY(top->localDeclarations().size() == 2); 0123 0124 /* a = 'string' */ 0125 Declaration *dec1 = top->localDeclarations().at(0); 0126 QVERIFY(dec1->type<StructureType>()); 0127 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 0128 0129 /* b = // */ 0130 Declaration *dec2 = top->localDeclarations().at(1); 0131 QVERIFY(dec2->type<StructureType>()); 0132 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Regexp")); 0133 } 0134 0135 void TestDUChain::booleanAndNil() 0136 { 0137 QByteArray code("a = true; b = false; c = nil"); 0138 TopDUContext *top = parse(code, "booleanAndNil"); 0139 DUChainReleaser releaser(top); 0140 DUChainWriteLocker lock; 0141 0142 QVERIFY(top->localDeclarations().size() == 3); 0143 0144 /* a = true */ 0145 Declaration *dec1 = top->localDeclarations().at(0); 0146 QVERIFY(dec1->type<StructureType>()); 0147 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("TrueClass")); 0148 0149 /* b = false */ 0150 Declaration *dec2 = top->localDeclarations().at(1); 0151 QVERIFY(dec2->type<StructureType>()); 0152 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("FalseClass")); 0153 0154 /* c = nil */ 0155 Declaration *dec3 = top->localDeclarations().at(2); 0156 QVERIFY(dec3->type<StructureType>()); 0157 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("NilClass")); 0158 } 0159 0160 void TestDUChain::lineFileEncoding() 0161 { 0162 QByteArray code("a = __LINE__; b = __FILE__; c = __ENCODING__"); 0163 TopDUContext *top = parse(code, "lineFileEncoding"); 0164 DUChainReleaser releaser(top); 0165 DUChainWriteLocker lock; 0166 0167 QVERIFY(top->localDeclarations().size() == 3); 0168 0169 /* a = __LINE__ */ 0170 Declaration *dec1 = top->localDeclarations().at(0); 0171 QVERIFY(dec1->type<StructureType>()); 0172 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0173 0174 /* b = __FILE__ */ 0175 Declaration *dec2 = top->localDeclarations().at(1); 0176 QVERIFY(dec2->type<StructureType>()); 0177 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 0178 0179 /* c = __ENCODING__ */ 0180 Declaration *dec3 = top->localDeclarations().at(2); 0181 QVERIFY(dec3->type<StructureType>()); 0182 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Encoding")); 0183 } 0184 0185 void TestDUChain::symbol() 0186 { 0187 QByteArray code("a = :a"); 0188 TopDUContext *top = parse(code, "symbol"); 0189 DUChainReleaser releaser(top); 0190 DUChainWriteLocker lock; 0191 0192 Declaration *dec = top->localDeclarations().at(0); 0193 QVERIFY(dec->type<StructureType>()); 0194 QCOMPARE(dec->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Symbol")); 0195 } 0196 0197 void TestDUChain::lambda() 0198 { 0199 QByteArray code("a = ->(a) { puts a }; b = lambda { |x| return x + 1 }"); 0200 TopDUContext *top = parse(code, "lambda"); 0201 DUChainReleaser releaser(top); 0202 DUChainWriteLocker lock; 0203 0204 Declaration *dec = top->localDeclarations().at(0); 0205 QVERIFY(dec->type<StructureType>()); 0206 QCOMPARE(dec->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Proc")); 0207 0208 dec = top->localDeclarations().at(1); 0209 QVERIFY(dec->type<StructureType>()); 0210 QCOMPARE(dec->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Proc")); 0211 } 0212 0213 void TestDUChain::self() 0214 { 0215 QByteArray code("module Modul; a = self; class Klass; b = self; end; end; c = self; def foo; self; end"); 0216 TopDUContext *top = parse(code, "self"); 0217 DUChainReleaser releaser(top); 0218 DUChainWriteLocker lock; 0219 0220 // a 0221 Declaration *d = top->localDeclarations().first(); 0222 Declaration *obj = d->internalContext()->localDeclarations().first(); 0223 QCOMPARE(obj->qualifiedIdentifier(), QualifiedIdentifier("Modul::a")); 0224 QCOMPARE(obj->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Modul")); 0225 0226 // b 0227 obj = d->internalContext()->localDeclarations().last()->internalContext()->localDeclarations().first(); 0228 QCOMPARE(obj->qualifiedIdentifier(), QualifiedIdentifier("Modul::Klass::b")); 0229 QCOMPARE(obj->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Modul::Klass")); 0230 0231 // c 0232 d = top->localDeclarations().at(1); 0233 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("c")); 0234 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Object")); 0235 0236 // Return type for foo 0237 d = top->localDeclarations().last(); 0238 AbstractType::Ptr rType = d->type<FunctionType>()->returnType(); 0239 auto structT = rType.staticCast<StructureType>(); 0240 QCOMPARE(structT->qualifiedIdentifier(), QualifiedIdentifier("Object")); 0241 } 0242 0243 //END: Builtin classes 0244 0245 //BEGIN: Statements 0246 0247 void TestDUChain::alias() 0248 { 0249 QByteArray code("def foo; 'a' end; alias asd foo"); 0250 TopDUContext *top = parse(code, "alias"); 0251 DUChainReleaser releaser(top); 0252 DUChainWriteLocker lock; 0253 0254 /* def foo; end */ 0255 Declaration *dec1 = top->localDeclarations().at(0); 0256 QVERIFY(dec1->isFunctionDeclaration()); 0257 QCOMPARE(dec1->qualifiedIdentifier(), QualifiedIdentifier("foo")); 0258 0259 /* alias asd foo */ 0260 Declaration *dec2 = top->localDeclarations().at(1); 0261 QVERIFY(dec2->isFunctionDeclaration()); 0262 QCOMPARE(dec2->qualifiedIdentifier(), QualifiedIdentifier("asd")); 0263 0264 /* The return type of asd is also a String */ 0265 AbstractType::Ptr rt = dec2->type<FunctionType>()->returnType(); 0266 auto structT = rt.staticCast<StructureType>(); 0267 QCOMPARE(structT->qualifiedIdentifier(), QualifiedIdentifier("String")); 0268 } 0269 0270 void TestDUChain::aliasGlobal1() 0271 { 0272 QByteArray code("$a = 0; alias $b $a"); 0273 TopDUContext *top = parse(code, "aliasGlobal1"); 0274 DUChainReleaser releaser(top); 0275 DUChainWriteLocker lock; 0276 0277 QVERIFY(top->localDeclarations().size() == 2); 0278 0279 Declaration *dec1 = top->localDeclarations().at(0); 0280 Declaration *dec2 = top->localDeclarations().at(1); 0281 0282 QCOMPARE(dec1->qualifiedIdentifier(), QualifiedIdentifier("$a")); 0283 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0284 QCOMPARE(dec2->qualifiedIdentifier(), QualifiedIdentifier("$b")); 0285 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0286 } 0287 0288 void TestDUChain::aliasGlobal2() 0289 { 0290 QByteArray code("alias $b $a"); 0291 TopDUContext *top = parse(code, "aliasGlobal2"); 0292 DUChainReleaser releaser(top); 0293 DUChainWriteLocker lock; 0294 0295 QVERIFY(top->localDeclarations().size() == 2); 0296 0297 Declaration *dec1 = top->localDeclarations().at(0); 0298 Declaration *dec2 = top->localDeclarations().at(1); 0299 0300 QCOMPARE(dec1->qualifiedIdentifier(), QualifiedIdentifier("$b")); 0301 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("NilClass")); 0302 QCOMPARE(dec2->qualifiedIdentifier(), QualifiedIdentifier("$a")); 0303 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("NilClass")); 0304 } 0305 0306 void TestDUChain::yield1() 0307 { 0308 QByteArray code("def foo; yield; end; foo { |a, b| puts a + b }"); 0309 TopDUContext *top = parse(code, "yield1"); 0310 DUChainReleaser releaser(top); 0311 DUChainWriteLocker lock; 0312 0313 QVector<Declaration *> decls = top->childContexts().last()->localDeclarations(); 0314 0315 QCOMPARE(decls.size(), 2); 0316 Declaration *dec1 = decls.at(0); 0317 Declaration *dec2 = decls.at(1); 0318 0319 QCOMPARE(dec1->qualifiedIdentifier(), QualifiedIdentifier("a")); 0320 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Object")); 0321 QCOMPARE(dec2->qualifiedIdentifier(), QualifiedIdentifier("b")); 0322 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Object")); 0323 } 0324 0325 void TestDUChain::yield2() 0326 { 0327 QByteArray code("def foo; yield 1, 2; yield 'a', 'b'; end; foo { |a, b| puts a + b }"); 0328 TopDUContext *top = parse(code, "yield2"); 0329 DUChainReleaser releaser(top); 0330 DUChainWriteLocker lock; 0331 0332 QVector<Declaration *> decls = top->childContexts().last()->localDeclarations(); 0333 QVERIFY(decls.size() == 2); 0334 0335 Declaration *dec = decls.at(0); 0336 QCOMPARE(dec->qualifiedIdentifier(), QualifiedIdentifier("a")); 0337 auto ut = dec->abstractType().dynamicCast<UnsureType>(); 0338 QStringList list; 0339 list << "Fixnum" << "String"; 0340 testUnsureTypes(ut, list); 0341 0342 dec = decls.at(1); 0343 QCOMPARE(dec->qualifiedIdentifier(), QualifiedIdentifier("b")); 0344 ut = dec->abstractType().dynamicCast<UnsureType>(); 0345 testUnsureTypes(ut, list); 0346 } 0347 0348 void TestDUChain::yield3() 0349 { 0350 QByteArray code("foo { |a, b| puts a + b }"); 0351 TopDUContext *top = parse(code, "yield3"); 0352 DUChainReleaser releaser(top); 0353 DUChainWriteLocker lock; 0354 0355 QVector<Declaration *> decls = top->childContexts().last()->localDeclarations(); 0356 0357 QCOMPARE(decls.size(), 2); 0358 Declaration *dec1 = decls.at(0); 0359 Declaration *dec2 = decls.at(1); 0360 0361 QCOMPARE(dec1->qualifiedIdentifier(), QualifiedIdentifier("a")); 0362 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Object")); 0363 QCOMPARE(dec2->qualifiedIdentifier(), QualifiedIdentifier("b")); 0364 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Object")); 0365 } 0366 0367 void TestDUChain::ifStatement() 0368 { 0369 QByteArray code("a = if d; 1; elsif b; nil; else; 'asd'; end"); 0370 TopDUContext *top = parse(code, "ifStatement"); 0371 DUChainReleaser releaser(top); 0372 DUChainWriteLocker lock; 0373 0374 Declaration *dec = top->localDeclarations().at(0); 0375 auto ut = dec->abstractType().dynamicCast<UnsureType>(); 0376 QStringList list; 0377 list << "NilClass" << "String" << "Fixnum"; 0378 testUnsureTypes(ut, list); 0379 } 0380 0381 void TestDUChain::caseStatement() 0382 { 0383 QByteArray code("f = case a; when 1; 2; nil; when 2; 1; else; 'asd'; end"); 0384 TopDUContext *top = parse(code, "caseStatement"); 0385 DUChainReleaser releaser(top); 0386 DUChainWriteLocker lock; 0387 0388 Declaration *dec = top->localDeclarations().at(0); 0389 auto ut = dec->abstractType().dynamicCast<UnsureType>(); 0390 QStringList list; 0391 list << "NilClass" << "Fixnum" << "String"; 0392 testUnsureTypes(ut, list); 0393 } 0394 0395 void TestDUChain::forStatement() 0396 { 0397 QByteArray code("for i in [1, 'str'] do; end"); 0398 TopDUContext *top = parse(code, "forStatement"); 0399 DUChainReleaser releaser(top); 0400 DUChainWriteLocker lock; 0401 0402 QCOMPARE(top->localDeclarations().size(), 1); 0403 Declaration *d = top->localDeclarations().first(); 0404 auto ut = d->abstractType().dynamicCast<UnsureType>(); 0405 QStringList list; 0406 list << "Fixnum" << "String"; 0407 testUnsureTypes(ut, list); 0408 } 0409 0410 void TestDUChain::hereDoc() 0411 { 0412 // heredoc should be a string and should not be parsed as ruby code 0413 QByteArray code("execute <<EOS\n\ 0414 foo (\n\ 0415 EOS\n\ 0416 "); 0417 parse(code, "hereDoc"); 0418 0419 DOES_NOT_CRASH; 0420 } 0421 0422 void TestDUChain::exceptions() 0423 { 0424 QByteArray code("begin; 1 / 0; rescue ZeroDivisionError, LoadError => e; end"); 0425 0426 { 0427 TopDUContext *top = parse(code, "exceptions"); 0428 DUChainReleaser releaser(top); 0429 DUChainWriteLocker lock; 0430 Declaration *d = top->localDeclarations().first(); 0431 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("e")); 0432 auto unsure = d->abstractType().dynamicCast<UnsureType>(); 0433 QStringList list; 0434 list << "ZeroDivisionError" << "LoadError"; 0435 testUnsureTypes(unsure, list); 0436 } 0437 0438 { 0439 code = "begin; 1 / 0; rescue ZeroDivisionError, LoadError; end"; 0440 TopDUContext *top = parse(code, "exceptions"); 0441 DUChainReleaser releaser(top); 0442 DUChainWriteLocker lock; 0443 DOES_NOT_CRASH; 0444 } 0445 } 0446 0447 void TestDUChain::method() 0448 { 0449 QByteArray code("a = def foo; 0; end"); 0450 TopDUContext *top = parse(code, "method"); 0451 DUChainReleaser releaser(top); 0452 DUChainWriteLocker lock; 0453 0454 Declaration *d = top->localDeclarations().first(); 0455 QVERIFY(d); 0456 QCOMPARE(d->abstractType()->toString(), QString("Symbol")); 0457 } 0458 0459 void TestDUChain::classStatement() 0460 { 0461 QByteArray code("a = class Klass; 0; ''; end"); 0462 TopDUContext *top = parse(code, "classStatement"); 0463 DUChainReleaser releaser(top); 0464 DUChainWriteLocker lock; 0465 0466 Declaration *d = top->localDeclarations().first(); 0467 QVERIFY(d); 0468 QCOMPARE(d->abstractType()->toString(), QString("String")); 0469 } 0470 0471 //END: Statements 0472 0473 //BEGIN: Assignments 0474 0475 void TestDUChain::simpleUnsure() 0476 { 0477 QByteArray code("a = 1; a = 'string'"); 0478 TopDUContext *top = parse(code, "simpleUnsure"); 0479 DUChainReleaser releaser(top); 0480 DUChainWriteLocker lock; 0481 0482 QVERIFY(top->localDeclarations().size() == 1); 0483 Declaration *d = top->localDeclarations().first(); 0484 auto unsure = d->abstractType().dynamicCast<UnsureType>(); 0485 QStringList list; 0486 list << "Fixnum" << "String"; 0487 testUnsureTypes(unsure, list); 0488 } 0489 0490 void TestDUChain::unsureHash() 0491 { 0492 // this test (when run separately from other tests) crashes 0493 // when storing Hash of unsure (Bar::Foo, String) in the item repository 0494 QByteArray code("class Bar; class Foo; end; x = [ Foo.new, 'test' ]; end"); 0495 parse(code, "unsureTypeStorage"); 0496 0497 DOES_NOT_CRASH; 0498 } 0499 0500 void TestDUChain::multipleAssignment1() 0501 { 0502 QByteArray code("a, b = 1, 'a'"); 0503 TopDUContext *top = parse(code, "multipleAssignment1"); 0504 DUChainReleaser releaser(top); 0505 DUChainWriteLocker lock; 0506 0507 QVERIFY(top->localDeclarations().size() == 2); 0508 0509 /* a */ 0510 Declaration *dec1 = top->localDeclarations().at(0); 0511 QVERIFY(dec1->type<StructureType>()); 0512 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0513 0514 /* b */ 0515 Declaration *dec2 = top->localDeclarations().at(1); 0516 QVERIFY(dec2->type<StructureType>()); 0517 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 0518 } 0519 0520 void TestDUChain::multipleAssignment2() 0521 { 0522 QByteArray code("a, b = 1, [1, 2, 3]"); 0523 TopDUContext *top = parse(code, "multipleAssignment2"); 0524 DUChainReleaser releaser(top); 0525 DUChainWriteLocker lock; 0526 0527 QVERIFY(top->localDeclarations().size() == 2); 0528 0529 // a 0530 Declaration *dec = top->localDeclarations().at(0); 0531 QVERIFY(dec->type<StructureType>()); 0532 QCOMPARE(dec->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0533 0534 /* b */ 0535 dec = top->localDeclarations().at(1); 0536 QCOMPARE(dec->type<ClassType>()->toString(), QString("Array of Fixnum")); 0537 } 0538 0539 void TestDUChain::multipleAssignmentLeft() 0540 { 0541 QByteArray code("a, b, c = 1, 2"); 0542 TopDUContext *top = parse(code, "multipleAssignmentLeft"); 0543 DUChainReleaser releaser(top); 0544 DUChainWriteLocker lock; 0545 0546 QVERIFY(top->localDeclarations().size() == 3); 0547 0548 /* a */ 0549 Declaration *dec1 = top->localDeclarations().at(0); 0550 QVERIFY(dec1->type<StructureType>()); 0551 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0552 0553 /* b */ 0554 Declaration *dec2 = top->localDeclarations().at(1); 0555 QVERIFY(dec2->type<StructureType>()); 0556 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0557 0558 /* c */ 0559 Declaration *dec3 = top->localDeclarations().at(2); 0560 QVERIFY(dec3->type<StructureType>()); 0561 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("NilClass")); 0562 } 0563 0564 void TestDUChain::multipleAssignmentRight1() 0565 { 0566 QByteArray code("a = 1, 2, 3"); 0567 TopDUContext *top = parse(code, "multipleAssignmentRight1"); 0568 DUChainReleaser releaser(top); 0569 DUChainWriteLocker lock; 0570 0571 QVERIFY(top->localDeclarations().size() == 1); 0572 0573 Declaration *dec = top->localDeclarations().at(0); 0574 QVERIFY(dec->type<StructureType>()); 0575 QCOMPARE(dec->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0576 } 0577 0578 void TestDUChain::multipleAssignmentRight2() 0579 { 0580 QByteArray code("a, = 1, 2, 3"); 0581 TopDUContext *top = parse(code, "multipleAssignmentRight2"); 0582 DUChainReleaser releaser(top); 0583 DUChainWriteLocker lock; 0584 0585 QVERIFY(top->localDeclarations().size() == 1); 0586 0587 Declaration *dec = top->localDeclarations().at(0); 0588 QVERIFY(dec->type<StructureType>()); 0589 QCOMPARE(dec->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0590 } 0591 0592 void TestDUChain::multipleAssignmentStar() 0593 { 0594 QByteArray code("b = 0; a, *, c = b, nil, 3, 4, 5, 'asd'"); 0595 TopDUContext *top = parse(code, "multipleAssignmentStar"); 0596 DUChainReleaser releaser(top); 0597 DUChainWriteLocker lock; 0598 0599 QVERIFY(top->localDeclarations().size() == 3); 0600 0601 Declaration *dec1 = top->localDeclarations().at(1); 0602 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0603 0604 Declaration *dec2 = top->localDeclarations().at(2); 0605 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 0606 } 0607 0608 void TestDUChain::multipleAssignmentNamedStar() 0609 { 0610 QByteArray code("a, *b, c = nil, nil, 3, 4, 5, 'asd'"); 0611 TopDUContext *top = parse(code, "multipleAssignmentNamedStar"); 0612 DUChainReleaser releaser(top); 0613 DUChainWriteLocker lock; 0614 0615 QVERIFY(top->localDeclarations().size() == 3); 0616 0617 Declaration *dec1 = top->localDeclarations().at(0); 0618 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("NilClass")); 0619 0620 Declaration *dec2 = top->localDeclarations().at(1); 0621 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Array")); 0622 QVERIFY(dec2->type<ClassType>()->contentType()); 0623 auto unsure = dec2->type<ClassType>()->contentType().abstractType().dynamicCast<UnsureType>(); 0624 QStringList list; 0625 list << "NilClass" << "Fixnum"; 0626 testUnsureTypes(unsure, list); 0627 0628 Declaration *dec3 = top->localDeclarations().at(2); 0629 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 0630 } 0631 0632 void TestDUChain::starAtTheBeginning() 0633 { 0634 QByteArray code("*, i = 1, 2, nil"); 0635 TopDUContext *top = parse(code, "starAtTheBeginning"); 0636 DUChainReleaser releaser(top); 0637 DUChainWriteLocker lock; 0638 0639 Declaration *dec1 = top->localDeclarations().at(0); 0640 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("NilClass")); 0641 } 0642 0643 void TestDUChain::starAtTheEnd() 0644 { 0645 QByteArray code("q, * = //, 1, 2"); 0646 TopDUContext *top = parse(code, "starAtTheEnd"); 0647 DUChainReleaser releaser(top); 0648 DUChainWriteLocker lock; 0649 0650 Declaration *dec1 = top->localDeclarations().at(0); 0651 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Regexp")); 0652 } 0653 0654 void TestDUChain::emptyStar() 0655 { 0656 QByteArray code("r, *t, w = 1, 'as'"); 0657 TopDUContext *top = parse(code, "emptyStar"); 0658 DUChainReleaser releaser(top); 0659 DUChainWriteLocker lock; 0660 0661 QVERIFY(top->localDeclarations().size() == 3); 0662 0663 Declaration *dec1 = top->localDeclarations().at(0); 0664 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0665 0666 Declaration *dec2 = top->localDeclarations().at(1); 0667 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Array")); 0668 0669 Declaration *dec3 = top->localDeclarations().at(2); 0670 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 0671 } 0672 0673 void TestDUChain::unpackArray1() 0674 { 0675 QByteArray code("a, b = [1, 2]"); 0676 TopDUContext *top = parse(code, "unpackArray1"); 0677 DUChainReleaser releaser(top); 0678 DUChainWriteLocker lock; 0679 0680 QVERIFY(top->localDeclarations().size() == 2); 0681 0682 Declaration *dec1 = top->localDeclarations().at(0); 0683 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0684 0685 Declaration *dec2 = top->localDeclarations().at(1); 0686 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0687 } 0688 0689 void TestDUChain::unpackArray2() 0690 { 0691 QByteArray code("a = [1, 2, 3]; b, c, d = a"); 0692 TopDUContext *top = parse(code, "unpackArray2"); 0693 DUChainReleaser releaser(top); 0694 DUChainWriteLocker lock; 0695 0696 QVERIFY(top->localDeclarations().size() == 4); 0697 0698 Declaration *dec1 = top->localDeclarations().at(1); 0699 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0700 0701 Declaration *dec2 = top->localDeclarations().at(2); 0702 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0703 0704 Declaration *dec3 = top->localDeclarations().at(3); 0705 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0706 } 0707 0708 void TestDUChain::unpackArray3() 0709 { 0710 QByteArray code("a, b = [1, 2], 1"); 0711 TopDUContext *top = parse(code, "unpackArray3"); 0712 DUChainReleaser releaser(top); 0713 DUChainWriteLocker lock; 0714 0715 QVERIFY(top->localDeclarations().size() == 2); 0716 0717 Declaration *dec1 = top->localDeclarations().at(0); 0718 QCOMPARE(dec1->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Array")); 0719 0720 Declaration *dec2 = top->localDeclarations().at(1); 0721 QCOMPARE(dec2->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0722 } 0723 0724 void TestDUChain::aliasedAssignment() 0725 { 0726 QByteArray code("a = 1..2; b = 1; c, d = a, b"); 0727 TopDUContext *top = parse(code, "aliasedAssignment"); 0728 DUChainReleaser releaser(top); 0729 DUChainWriteLocker lock; 0730 0731 QVERIFY(top->localDeclarations().size() == 4); 0732 0733 Declaration *dec3 = top->localDeclarations().at(2); 0734 QVERIFY(dec3->type<StructureType>()); 0735 QCOMPARE(dec3->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Range")); 0736 0737 Declaration *dec4 = top->localDeclarations().at(3); 0738 QVERIFY(dec4->type<StructureType>()); 0739 QCOMPARE(dec4->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0740 } 0741 0742 void TestDUChain::withMethodCallAndBlock() 0743 { 0744 QByteArray code("a = Class.new do; def foo; b = 0; end; end.foo(1, 2)"); 0745 TopDUContext *top = parse(code, "withMethodCallAndBlock"); 0746 DUChainReleaser releaser(top); 0747 DUChainWriteLocker lock; 0748 0749 DOES_NOT_CRASH; 0750 } 0751 0752 //END: Assignments 0753 0754 //BEGIN: ClassType 0755 0756 void TestDUChain::assignFromArrayItem1() 0757 { 0758 QByteArray code("a = [1, 2, 3]; b = a[0]"); 0759 TopDUContext *top = parse(code, "assignFromArrayItem1"); 0760 DUChainReleaser releaser(top); 0761 DUChainWriteLocker lock; 0762 0763 QVERIFY(top->localDeclarations().size() == 2); 0764 0765 // a 0766 Declaration *d = top->localDeclarations().at(0); 0767 QCOMPARE(d->type<ClassType>()->toString(), QString("Array of Fixnum")); 0768 0769 // b 0770 d = top->localDeclarations().at(1); 0771 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 0772 } 0773 0774 void TestDUChain::assignFromArrayItem2() 0775 { 0776 QByteArray code("a = [1, '2']; b = a[0]"); 0777 TopDUContext *top = parse(code, "assignFromArrayItem2"); 0778 DUChainReleaser releaser(top); 0779 DUChainWriteLocker lock; 0780 0781 QVERIFY(top->localDeclarations().size() == 2); 0782 0783 // a 0784 Declaration *d = top->localDeclarations().at(0); 0785 QCOMPARE(d->type<ClassType>()->toString(), QString("Array of unsure (Fixnum, String)")); 0786 0787 // b 0788 d = top->localDeclarations().at(1); 0789 QStringList list; 0790 list << "Fixnum" << "String"; 0791 testUnsureTypes(d->type<UnsureType>(), list); 0792 } 0793 0794 void TestDUChain::assignFromHashItem() 0795 { 0796 QByteArray code("a = { :a => 'a', b: 1 }; b = a[:a]"); 0797 TopDUContext *top = parse(code, "assignFromHashItem"); 0798 DUChainReleaser releaser(top); 0799 DUChainWriteLocker lock; 0800 0801 QVERIFY(top->localDeclarations().size() == 2); 0802 0803 // a 0804 Declaration *d = top->localDeclarations().at(0); 0805 QCOMPARE(d->type<ClassType>()->toString(), QString("Hash of unsure (String, Fixnum)")); 0806 0807 // b 0808 d = top->localDeclarations().at(1); 0809 QStringList list; 0810 list << "String" << "Fixnum"; 0811 testUnsureTypes(d->type<UnsureType>(), list); 0812 } 0813 0814 void TestDUChain::assignToArrayItem() 0815 { 0816 QByteArray code("a = [1, nil]; a[1] = 'asd'"); 0817 TopDUContext *top = parse(code, "assignToArrayItem"); 0818 DUChainReleaser releaser(top); 0819 DUChainWriteLocker lock; 0820 0821 Declaration *d = top->localDeclarations().at(0); 0822 UnsureType::Ptr cont = d->type<ClassType>()->contentType().type<UnsureType>(); 0823 QStringList list; 0824 list << "Fixnum" << "NilClass" << "String"; 0825 testUnsureTypes(cont, list); 0826 } 0827 0828 void TestDUChain::arrayInstanceVariable() 0829 { 0830 QByteArray code("class Klass; def foo; @var = [1, 'str']; @var[0]; end; end"); 0831 TopDUContext *top = parse(code, "arrayInstanceVariable"); 0832 DUChainReleaser releaser(top); 0833 DUChainWriteLocker lock; 0834 0835 Declaration *d = top->localDeclarations().first(); 0836 d = d->internalContext()->localDeclarations().first(); 0837 QVERIFY(d); 0838 FunctionType::Ptr fType = d->type<FunctionType>(); 0839 QVERIFY(fType); 0840 auto ut = fType->returnType().dynamicCast<UnsureType>(); 0841 QVERIFY(ut); 0842 QCOMPARE(ut->typesSize(), (uint) 2); 0843 QStringList list; 0844 list << "Fixnum" << "String"; 0845 testUnsureTypes(ut, list); 0846 } 0847 0848 //END: ClassType 0849 0850 //BEGIN: Declarations 0851 0852 void TestDUChain::checkVariableKind() 0853 { 0854 QByteArray code("$a = 0; @a = 0; @@a = 0; a = 0; A = 0"); 0855 TopDUContext *top = parse(code, "checkVariableKind"); 0856 DUChainReleaser releaser(top); 0857 DUChainWriteLocker lock; 0858 0859 VariableDeclaration *obj = dynamic_cast<VariableDeclaration *>(top->localDeclarations().at(0)); 0860 QVERIFY(obj->isGlobal()); 0861 0862 obj = dynamic_cast<VariableDeclaration *>(top->localDeclarations().at(1)); 0863 QVERIFY(obj->isIvar()); 0864 0865 obj = dynamic_cast<VariableDeclaration *>(top->localDeclarations().at(2)); 0866 QVERIFY(obj->isCvar()); 0867 0868 obj = dynamic_cast<VariableDeclaration *>(top->localDeclarations().at(3)); 0869 QVERIFY(obj->isNormal()); 0870 0871 obj = dynamic_cast<VariableDeclaration *>(top->localDeclarations().at(4)); 0872 QVERIFY(obj->isConstant()); 0873 } 0874 0875 void TestDUChain::instanceClassMethodDeclaration() 0876 { 0877 QByteArray code("class Klass; def foo(a, b); end; def asd; end; "); 0878 code += "def self.selfish; end; def Klass.selfis; end; end"; 0879 TopDUContext *top = parse(code, "instanceClassMethodDeclaration"); 0880 DUChainReleaser releaser(top); 0881 DUChainWriteLocker lock; 0882 0883 ModuleDeclaration *mod = dynamic_cast<ModuleDeclaration *>(top->localDeclarations().first()); 0884 QVERIFY(mod); 0885 0886 // Instance methods 0887 QVector<Declaration *> decs = mod->internalContext()->localDeclarations(); 0888 QCOMPARE(decs.size(), 2); 0889 0890 MethodDeclaration *d = dynamic_cast<MethodDeclaration *>(decs.first()); 0891 QCOMPARE(d->qualifiedIdentifier().toString(), QString("Klass::foo")); 0892 d = dynamic_cast<MethodDeclaration *>(decs.last()); 0893 QCOMPARE(d->qualifiedIdentifier().toString(), QString("Klass::asd")); 0894 0895 // Class methods 0896 decs = mod->eigenClass()->localDeclarations(); 0897 QCOMPARE(decs.size(), 2); 0898 0899 d = dynamic_cast<MethodDeclaration *>(decs.first()); 0900 QCOMPARE(d->qualifiedIdentifier().toString(), QString("Klass::Klass::selfish")); 0901 d = dynamic_cast<MethodDeclaration *>(decs.last()); 0902 QCOMPARE(d->qualifiedIdentifier().toString(), QString("Klass::Klass::selfis")); 0903 } 0904 0905 void TestDUChain::reopenMethodDeclaration() 0906 { 0907 QByteArray code("class Klass; def foo; ''; end; end; def foo; 'str'; end; def foo; 0; end"); 0908 TopDUContext *top = parse(code, "reopenMethodDeclaration"); 0909 DUChainReleaser releaser(top); 0910 DUChainWriteLocker lock; 0911 0912 QVector<Declaration *> decls = top->localDeclarations(); 0913 QCOMPARE(decls.size(), 2); 0914 0915 Declaration *d = decls.first()->internalContext()->localDeclarations().first(); 0916 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("Klass::foo")); 0917 MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(d); 0918 AbstractType::Ptr type = md->type<FunctionType>()->returnType(); 0919 QCOMPARE(type->toString(), QString("String")); 0920 0921 d = decls.last(); 0922 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("foo")); 0923 md = dynamic_cast<MethodDeclaration *>(d); 0924 type = md->type<FunctionType>()->returnType(); 0925 QCOMPARE(type->toString(), QString("Fixnum")); 0926 } 0927 0928 void TestDUChain::singletonMethods() 0929 { 0930 QByteArray code("def Hash.foo; end; a = 0; def a.lala; end"); 0931 TopDUContext *top = parse(code, "singletonMethods"); 0932 DUChainReleaser releaser(top); 0933 DUChainWriteLocker lock; 0934 0935 // Hash.foo 0936 Declaration *d = getBuiltinDeclaration("Hash#foo", top, top); 0937 MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(d); 0938 QVERIFY(md); 0939 QVERIFY(md->isClassMethod()); 0940 0941 // a.lala 0942 d = getBuiltinDeclaration("Fixnum#lala", top, top); 0943 md = dynamic_cast<MethodDeclaration *>(d); 0944 QVERIFY(md); 0945 QVERIFY(!md->isClassMethod()); 0946 } 0947 0948 void TestDUChain::singletonClass1() 0949 { 0950 QByteArray code("a = 0; class << a; def foo; 'string'; end; end"); 0951 TopDUContext *top = parse(code, "singletonClass1"); 0952 DUChainReleaser releaser(top); 0953 DUChainWriteLocker lock; 0954 0955 Declaration *d = getBuiltinDeclaration("Fixnum#foo", top, top); 0956 MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(d); 0957 QVERIFY(md); 0958 QVERIFY(!md->isClassMethod()); 0959 0960 AbstractType::Ptr type = md->type<FunctionType>()->returnType(); 0961 QCOMPARE(type.staticCast<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 0962 } 0963 0964 void TestDUChain::singletonClass2() 0965 { 0966 QSKIP("It crashes right now since I'm not done with the eigenclass thing"); 0967 0968 QByteArray code("class Klass; class << self; def foo; 'string'; end; end; end"); 0969 TopDUContext *top = parse(code, "singletonClass2"); 0970 DUChainReleaser releaser(top); 0971 DUChainWriteLocker lock; 0972 0973 DUContext *ctx = top->localDeclarations().first()->internalContext(); 0974 Declaration *d = ctx->findDeclarations(QualifiedIdentifier("foo")).first(); 0975 MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(d); 0976 QVERIFY(md); 0977 QVERIFY(md->isClassMethod()); 0978 0979 auto type = md->type<FunctionType>()->returnType().staticCast<StructureType>(); 0980 QCOMPARE(type->qualifiedIdentifier(), QualifiedIdentifier("String")); 0981 } 0982 0983 void TestDUChain::singletonClass3() 0984 { 0985 QByteArray code("a = 0; a = 'str'; class << a; end"); 0986 TopDUContext *top = parse(code, "singletonClass3"); 0987 DUChainReleaser releaser(top); 0988 DUChainWriteLocker lock; 0989 0990 DOES_NOT_CRASH; 0991 } 0992 0993 void TestDUChain::singletonMethodVisibility() 0994 { 0995 QByteArray code("class << Foo; private; def foo; end; end"); 0996 parse(code, "singletonMethodVisibility"); 0997 0998 DOES_NOT_CRASH; 0999 } 1000 1001 void TestDUChain::accessPolicyMethodInClass() 1002 { 1003 QByteArray code("class Klass; def foo; end; protected; def asd; end; "); 1004 code += "private; def zxc; end; public; def iop; end; end"; 1005 TopDUContext *top = parse(code, "accessPolicyMethodInClass"); 1006 DUChainReleaser releaser(top); 1007 DUChainWriteLocker lock; 1008 QVector<Declaration *> decs = top->childContexts().first()->localDeclarations(); 1009 1010 MethodDeclaration *d1 = dynamic_cast<MethodDeclaration *>(decs.first()); 1011 QVERIFY(d1->accessPolicy() == Declaration::Public); 1012 1013 MethodDeclaration *d2 = dynamic_cast<MethodDeclaration *>(decs.at(1)); 1014 QVERIFY(d2->accessPolicy() == Declaration::Protected); 1015 1016 MethodDeclaration *d3 = dynamic_cast<MethodDeclaration *>(decs.at(2)); 1017 QVERIFY(d3->accessPolicy() == Declaration::Private); 1018 1019 MethodDeclaration *d4 = dynamic_cast<MethodDeclaration *>(decs.at(3)); 1020 QVERIFY(d4->accessPolicy() == Declaration::Public); 1021 } 1022 1023 void TestDUChain::accessPolicyMethodInModule() 1024 { 1025 QByteArray code("module Klass; def foo; end; protected; def asd; end; "); 1026 code += "private; def zxc; end; public; def iop; end; end"; 1027 TopDUContext *top = parse(code, "accessPolicyMethodInClass"); 1028 DUChainReleaser releaser(top); 1029 DUChainWriteLocker lock; 1030 QVector<Declaration *> decs = top->childContexts().first()->localDeclarations(); 1031 1032 MethodDeclaration *d1 = dynamic_cast<MethodDeclaration *>(decs.first()); 1033 QVERIFY(d1->accessPolicy() == Declaration::Public); 1034 1035 MethodDeclaration *d2 = dynamic_cast<MethodDeclaration *>(decs.at(1)); 1036 QVERIFY(d2->accessPolicy() == Declaration::Protected); 1037 1038 MethodDeclaration *d3 = dynamic_cast<MethodDeclaration *>(decs.at(2)); 1039 QVERIFY(d3->accessPolicy() == Declaration::Private); 1040 1041 MethodDeclaration *d4 = dynamic_cast<MethodDeclaration *>(decs.at(3)); 1042 QVERIFY(d4->accessPolicy() == Declaration::Public); 1043 } 1044 1045 void TestDUChain::accessPolicyOnBlock() 1046 { 1047 QByteArray code("class Klass; end; Klass.class_eval { private; def foo; end }"); 1048 TopDUContext *top = parse(code, "accessPolicyOnBlock"); 1049 DUChainReleaser releaser(top); 1050 DUChainWriteLocker lock; 1051 1052 DOES_NOT_CRASH; 1053 } 1054 1055 void TestDUChain::nestedAccessPolicy() 1056 { 1057 QByteArray code("class Outer; class Inner; private; def innerFoo; end; "); 1058 code += "end; def outerFoo; end; end"; 1059 TopDUContext *top = parse(code, "nestedAccessPolicy"); 1060 DUChainReleaser releaser(top); 1061 DUChainWriteLocker lock; 1062 QVector<Declaration *> decs = top->childContexts().first()->localDeclarations(); 1063 1064 // innerFoo 1065 Declaration *d = decs.first()->internalContext()->localDeclarations().first(); 1066 QVERIFY(dynamic_cast<MethodDeclaration *>(d)->accessPolicy() == Declaration::Private); 1067 1068 // outerFoo 1069 d = decs.last(); 1070 QVERIFY(dynamic_cast<MethodDeclaration *>(d)->accessPolicy() == Declaration::Public); 1071 } 1072 1073 void TestDUChain::checkSubClassing1() 1074 { 1075 QByteArray code("class Base; end; class Final < Base; end"); 1076 TopDUContext *top = parse(code, "checkSubClassing1"); 1077 DUChainReleaser releaser(top); 1078 DUChainWriteLocker lock; 1079 1080 // Base 1081 ModuleDeclaration *base = dynamic_cast<ModuleDeclaration *>(top->localDeclarations().first()); 1082 QVERIFY(base); 1083 QCOMPARE(base->internalContext()->childContexts().count(), 0); 1084 QCOMPARE(base->internalContext()->importedParentContexts().count(), 0); 1085 QCOMPARE(base->internalContext()->localScopeIdentifier(), QualifiedIdentifier("Base")); 1086 1087 // Final 1088 ModuleDeclaration *final = dynamic_cast<ModuleDeclaration *>(top->localDeclarations().last()); 1089 QVERIFY(final); 1090 QCOMPARE(final->internalContext()->childContexts().count(), 0); 1091 QCOMPARE(final->internalContext()->importedParentContexts().count(), 1); 1092 QCOMPARE(final->internalContext()->localScopeIdentifier(), QualifiedIdentifier("Final")); 1093 QVERIFY(final->baseClass()); 1094 QCOMPARE(final->baseClass(), base->indexedType()); 1095 } 1096 1097 void TestDUChain::checkSubClassing2() 1098 { 1099 QByteArray code("module A; class B; end; end; class C < A::B; end"); 1100 TopDUContext *top = parse(code, "checkSubClassing2"); 1101 DUChainReleaser releaser(top); 1102 DUChainWriteLocker lock; 1103 1104 // B 1105 Declaration *decl = top->localDeclarations().first(); // A 1106 decl = decl->internalContext()->localDeclarations().first(); // B 1107 QVERIFY(decl); 1108 QCOMPARE(decl->internalContext()->childContexts().count(), 0); 1109 QCOMPARE(decl->internalContext()->importedParentContexts().count(), 0); 1110 QCOMPARE(decl->qualifiedIdentifier(), QualifiedIdentifier("A::B")); 1111 1112 // C 1113 ModuleDeclaration *cDecl = dynamic_cast<ModuleDeclaration *>(top->localDeclarations().last()); 1114 QVERIFY(cDecl); 1115 QCOMPARE(cDecl->internalContext()->childContexts().count(), 0); 1116 QCOMPARE(cDecl->internalContext()->importedParentContexts().count(), 1); 1117 QCOMPARE(cDecl->qualifiedIdentifier(), QualifiedIdentifier("C")); 1118 QVERIFY(cDecl->baseClass()); 1119 QCOMPARE(cDecl->baseClass(), decl->indexedType()); 1120 } 1121 1122 void TestDUChain::checkSubClassingErrors() 1123 { 1124 QStringList errors; 1125 errors << "TypeError: wrong argument type (expected Class)"; 1126 1127 { 1128 QByteArray code("module A; end; class B < A; end;"); 1129 TopDUContext *top = parse(code, "checkSubClassingErrors"); 1130 DUChainReleaser releaser(top); 1131 DUChainWriteLocker lock; 1132 testProblems(top, errors); 1133 } 1134 1135 { 1136 QByteArray code("A = 0; class B < A; end;"); 1137 TopDUContext *top = parse(code, "checkSubClassingErrors"); 1138 DUChainReleaser releaser(top); 1139 DUChainWriteLocker lock; 1140 testProblems(top, errors); 1141 } 1142 } 1143 1144 void TestDUChain::errorOnInvalidRedeclaration1() 1145 { 1146 QByteArray code("class Klass; end; module Module; end; class Kernel; end"); 1147 TopDUContext *top = parse(code, "errorOnInvalidRedeclaration1"); 1148 DUChainReleaser releaser(top); 1149 DUChainWriteLocker lock; 1150 1151 QStringList errors; 1152 errors << "TypeError: Module is not a module" 1153 << "TypeError: Kernel is not a class"; 1154 testProblems(top, errors); 1155 } 1156 1157 void TestDUChain::errorOnInvalidRedeclaration2() 1158 { 1159 QByteArray code("module Klass; end; module Mod; class Klass; end; end"); 1160 TopDUContext *top = parse(code, "errorOnInvalidRedeclaration2"); 1161 DUChainReleaser releaser(top); 1162 DUChainWriteLocker lock; 1163 1164 /* 1165 * This test just checks that no problems are being raised, since the 1166 * second class Klass is inside the module Mod, so it's not the same 1167 * as the first Klass, which is a module. 1168 */ 1169 1170 QStringList errors; 1171 testProblems(top, errors); 1172 } 1173 1174 void TestDUChain::instanceVariable() 1175 { 1176 // class Klass 1177 // @asd = 1 1178 // 1179 // def foo 1180 // @asd = 'asd' 1181 // @asd 1182 // end 1183 // 1184 // class Mod 1185 // def lala 1186 // @asd = 12i 1187 // @asd 1188 // end 1189 // end 1190 // end 1191 // 1192 // a = Klass.new 1193 // b = a.foo 1194 // c = Klass::Mod.new 1195 // d = c.lala 1196 1197 QByteArray code("class Klass; @asd = 1; def foo; @asd = 'asd'; @asd; end;"); 1198 code += " class Mod; def lala; @asd = 12i; @asd; end; end; end;"; 1199 code += " a = Klass.new; b = a.foo; c = Klass::Mod.new; d = c.lala"; 1200 TopDUContext *top = parse(code, "instanceVariable1"); 1201 DUChainReleaser releaser(top); 1202 DUChainWriteLocker lock; 1203 1204 QList<Declaration *> ds; 1205 foreach (Declaration *d, top->childContexts().first()->localDeclarations()) 1206 if (dynamic_cast<VariableDeclaration *>(d)) 1207 ds << d; 1208 QCOMPARE(ds.size(), 1); 1209 QCOMPARE(ds.first()->qualifiedIdentifier(), QualifiedIdentifier("Klass::@asd")); 1210 QVERIFY(ds.first()->isAutoDeclaration()); 1211 1212 // It's an unsure(Fixnum, String, Complex) 1213 auto ut = ds.first()->abstractType().dynamicCast<UnsureType>(); 1214 QStringList list; 1215 list << "Fixnum" << "String" << "Complex"; 1216 testUnsureTypes(ut, list); 1217 1218 // b is an unsure(Fixnum, String, Complex) 1219 QVector<Declaration *> decls = top->localDeclarations(); 1220 Declaration *d = decls.at(2); 1221 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("b")); 1222 ut = d->abstractType().dynamicCast<UnsureType>(); 1223 QVERIFY(ut); 1224 testUnsureTypes(ut, list); 1225 1226 // d is also an unsure(Fixnum, String, Complex) 1227 QCOMPARE(decls.at(4)->qualifiedIdentifier(), QualifiedIdentifier("d")); 1228 ut = decls.at(4)->abstractType().dynamicCast<UnsureType>(); 1229 QVERIFY(ut); 1230 testUnsureTypes(ut, list); 1231 } 1232 1233 void TestDUChain::classVariable() 1234 { 1235 QByteArray code("class Base; @@lala = 1; end; class Klass < Base; @@lala; end"); 1236 TopDUContext *top = parse(code, "classVariable"); 1237 DUChainReleaser releaser(top); 1238 DUChainWriteLocker lock; 1239 1240 QList<Declaration *> ds; 1241 foreach (Declaration *d, top->childContexts().first()->localDeclarations()) 1242 if (dynamic_cast<VariableDeclaration *>(d)) 1243 ds << d; 1244 QCOMPARE(ds.size(), 1); 1245 1246 // @@lala = 1 1247 Declaration *decl = ds.first(); 1248 QVERIFY(decl->isAutoDeclaration()); 1249 QCOMPARE(decl->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1250 1251 // Check that the @@lala inside Klass is the same as the Base one 1252 QCOMPARE(top->childContexts().last()->localDeclarations().size(), 0); 1253 QVector<DUContext::Import> aux = top->childContexts().last()->importedParentContexts(); 1254 ds.clear(); 1255 foreach (Declaration *d, aux.first().context(top)->localDeclarations()) 1256 if (dynamic_cast<VariableDeclaration *>(d)) 1257 ds << d; 1258 QCOMPARE(ds.size(), 1); 1259 decl = ds.first(); 1260 QCOMPARE(decl->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1261 } 1262 1263 void TestDUChain::classModulesScopes() 1264 { 1265 QByteArray code("module Klass; end; module Modul; end; class Modul::Klass;"); 1266 code += " ::Klass; module Thing; Klass; ::Klass; end; end;"; 1267 TopDUContext *top = parse(code, "classModulesScopes"); 1268 DUChainReleaser releaser(top); 1269 DUChainWriteLocker lock; 1270 1271 QVector<Declaration *> decls = top->localDeclarations(); 1272 QCOMPARE(decls.size(), 2); 1273 1274 QCOMPARE(decls.first()->qualifiedIdentifier(), QualifiedIdentifier("Klass")); 1275 QCOMPARE(decls.at(1)->qualifiedIdentifier(), QualifiedIdentifier("Modul")); 1276 1277 decls = decls.at(1)->internalContext()->localDeclarations(); 1278 QCOMPARE(decls.size(), 1); 1279 1280 QCOMPARE(decls.first()->qualifiedIdentifier(), QualifiedIdentifier("Modul::Klass")); 1281 1282 decls = decls.first()->internalContext()->localDeclarations(); 1283 QCOMPARE(decls.size(), 1); 1284 1285 QCOMPARE(decls.first()->qualifiedIdentifier(), QualifiedIdentifier("Klass::Thing")); 1286 } 1287 1288 void TestDUChain::globals1() 1289 { 1290 QByteArray code("$asd = 1234; class Klass; a = $asd; $asd = 1; class Sub;"); 1291 code += " $asd = 'asd'; end; end"; 1292 TopDUContext *top = parse(code, "globals1"); 1293 DUChainReleaser releaser(top); 1294 DUChainWriteLocker lock; 1295 1296 // The goal of this test is to check that there's only 3 declarations: 1297 // $asd, Klass and Sub. All assignments of $asd correspond to the same 1298 // global variable. 1299 1300 // Only 2 declarations: $asd and Klass. 1301 QVector<Declaration *> decls = top->localDeclarations(); 1302 Declaration *asd; 1303 QCOMPARE(decls.size(), 2); 1304 asd = decls.first(); 1305 QCOMPARE(asd->qualifiedIdentifier(), QualifiedIdentifier("$asd")); 1306 QCOMPARE(decls.last()->qualifiedIdentifier(), QualifiedIdentifier("Klass")); 1307 1308 // Only 2 declarations: a and Sub. 1309 decls = decls.last()->internalContext()->localDeclarations(); 1310 QCOMPARE(decls.first()->qualifiedIdentifier(), QualifiedIdentifier("Klass::a")); 1311 QCOMPARE(decls.last()->qualifiedIdentifier(), QualifiedIdentifier("Klass::Sub")); 1312 1313 // No declarations. 1314 decls = decls.last()->internalContext()->localDeclarations(); 1315 QVERIFY(decls.empty()); 1316 1317 // Check that $asd is an unsure(Fixnum, String) 1318 auto ut = asd->abstractType().dynamicCast<UnsureType>(); 1319 QStringList list; 1320 list << "Fixnum" << "String"; 1321 testUnsureTypes(ut, list); 1322 } 1323 1324 void TestDUChain::globals2() 1325 { 1326 QByteArray code("class Klass; $asd = 1; end; module Mod; $asd = 'asd'; end"); 1327 TopDUContext *top = parse(code, "globals2"); 1328 DUChainReleaser releaser(top); 1329 DUChainWriteLocker lock; 1330 1331 // The point of this test is to check that the $asd global variable is set 1332 // in the top DUContext, so there's just one single $asd declaration. 1333 // This $asd variable is expected to be in the top. 1334 1335 QVector<Declaration *> decls = top->localDeclarations(); 1336 QCOMPARE(decls.size(), 3); 1337 Declaration *d = decls.at(1); 1338 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("$asd")); 1339 1340 // Check that there's no new declaration inside the Mod module. 1341 decls = decls.last()->internalContext()->localDeclarations(); 1342 QVERIFY(decls.empty()); 1343 1344 // Check that $asd is an unsure(Fixnum, String) 1345 auto ut = d->abstractType().dynamicCast<UnsureType>(); 1346 QStringList list; 1347 list << "Fixnum" << "String"; 1348 testUnsureTypes(ut, list); 1349 } 1350 1351 //END: Declarations 1352 1353 //BEGIN: Returning Values 1354 1355 void TestDUChain::multipleReturns() 1356 { 1357 QByteArray code("def foo(a, b); return nil if a.nil?; return 'a'; end"); 1358 TopDUContext *top = parse(code, "multipleReturns"); 1359 DUChainReleaser releaser(top); 1360 DUChainWriteLocker lock; 1361 1362 Declaration *decl = top->localDeclarations().first(); 1363 FunctionType::Ptr ft = decl->type<FunctionType>(); 1364 auto ut = ft->returnType().dynamicCast<UnsureType>(); 1365 QStringList list; 1366 list << "String" << "NilClass"; 1367 testUnsureTypes(ut, list); 1368 } 1369 1370 void TestDUChain::implicitReturn() 1371 { 1372 QByteArray code("class Klass; def item; @list = [1, 'str']; @list[0]; end; end;"); 1373 code += "a = Klass.new; b = a.item"; 1374 TopDUContext *top = parse(code, "returnFromInstanceMethod"); 1375 DUChainReleaser releaser(top); 1376 DUChainWriteLocker lock; 1377 1378 Declaration *d = top->localDeclarations().last(); 1379 UnsureType::Ptr ut = d->type<UnsureType>(); 1380 QVERIFY(ut); 1381 QStringList list; 1382 list << "Fixnum" << "String"; 1383 testUnsureTypes(ut, list); 1384 } 1385 1386 void TestDUChain::mixedExplicitAndImplicitReturn() 1387 { 1388 QByteArray code("def foo(a); return nil if a.nil?; 'a'; end"); 1389 TopDUContext *top = parse(code, "mixedExplicitAndImplicitReturn"); 1390 DUChainReleaser releaser(top); 1391 DUChainWriteLocker lock; 1392 1393 Declaration *decl = top->localDeclarations().first(); 1394 FunctionType::Ptr ft = decl->type<FunctionType>(); 1395 auto ut = ft->returnType().dynamicCast<UnsureType>(); 1396 QStringList list; 1397 list << "String" << "NilClass"; 1398 testUnsureTypes(ut, list); 1399 } 1400 1401 void TestDUChain::nilReturn() 1402 { 1403 QByteArray code("def foo; end"); 1404 TopDUContext *top = parse(code, "nilReturn"); 1405 DUChainReleaser releaser(top); 1406 DUChainWriteLocker lock; 1407 1408 Declaration *decl = top->localDeclarations().first(); 1409 FunctionType::Ptr ft = decl->type<FunctionType>(); 1410 auto rt = ft->returnType().staticCast<StructureType>(); 1411 QCOMPARE(rt->qualifiedIdentifier(), QualifiedIdentifier("NilClass")); 1412 } 1413 1414 void TestDUChain::instanceClassMethodsReturn() 1415 { 1416 QByteArray code("class Klass; def self.foo; 0; end; def foo; ''; end; end; a = Klass.new; b = a.foo; c = Klass.foo"); 1417 TopDUContext *top = parse(code, "instanceClassMethodsReturn"); 1418 DUChainReleaser releaser(top); 1419 DUChainWriteLocker lock; 1420 1421 qDebug() << top->localDeclarations().size(); 1422 1423 Declaration *d = top->localDeclarations().at(2); 1424 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("b")); 1425 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 1426 1427 d = top->localDeclarations().last(); 1428 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("c")); 1429 qDebug() << d->type<StructureType>()->qualifiedIdentifier().toString(); 1430 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1431 } 1432 1433 //END: Returning Values 1434 1435 //BEGIN: Methods 1436 1437 void TestDUChain::callingToInstanceMethod() 1438 { 1439 QByteArray code("class Klass; def foo; 1; end; end; obj = Klass.new; a = obj.foo"); 1440 TopDUContext *top = parse(code, "callingToInstanceMethod"); 1441 DUChainReleaser releaser(top); 1442 DUChainWriteLocker lock; 1443 1444 Declaration *obj = top->localDeclarations().at(1); 1445 QCOMPARE(obj->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Klass")); 1446 1447 obj = top->localDeclarations().at(2); 1448 QCOMPARE(obj->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1449 } 1450 1451 void TestDUChain::chainedCalls1() 1452 { 1453 QByteArray code("module Modul; class Klass; def self.selfish(a, b); "); 1454 code += "'str'; end; end; end; a = Modul::Klass.selfish(1, 2)"; 1455 TopDUContext *top = parse(code, "chainedCalls1"); 1456 DUChainReleaser releaser(top); 1457 DUChainWriteLocker lock; 1458 1459 Declaration *d = top->localDeclarations().last(); 1460 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("a")); 1461 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 1462 } 1463 1464 void TestDUChain::chainedCalls2() 1465 { 1466 QByteArray code("class Base; def foo; 'asd'; end; end; class Klass; "); 1467 code += "def foo1; a = Base.new; a.foo; end; end; b = Klass.new; c = b.foo1"; 1468 TopDUContext *top = parse(code, "chainedCalls2"); 1469 DUChainReleaser releaser(top); 1470 DUChainWriteLocker lock; 1471 1472 // b 1473 Declaration *d = top->localDeclarations().at(2); 1474 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("b")); 1475 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Klass")); 1476 1477 // c 1478 d = top->localDeclarations().last(); 1479 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("c")); 1480 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 1481 } 1482 1483 void TestDUChain::chainedCalls3() 1484 { 1485 // TODO 1486 QSKIP("There's still some work to do before getting this test to pass"); 1487 1488 QByteArray code("module A; class B; def foo; //; end; end; a = B.new.foo;"); 1489 code += "end; b = A::B.new.foo"; 1490 TopDUContext *top = parse(code, "chainedCalls3"); 1491 DUChainReleaser releaser(top); 1492 DUChainWriteLocker lock; 1493 1494 // a 1495 Declaration *d = top->localDeclarations().first(); 1496 d = d->internalContext()->localDeclarations().last(); 1497 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("A::a")); 1498 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Regexp")); 1499 1500 // b 1501 d = top->localDeclarations().last(); 1502 QCOMPARE(d->qualifiedIdentifier(), QualifiedIdentifier("b")); 1503 QCOMPARE(d->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Regexp")); 1504 } 1505 1506 void TestDUChain::super() 1507 { 1508 QByteArray code("class Base; def foo; 'string'; end; end; class Klass < "); 1509 code += "Base; def foo; super; end; end"; 1510 TopDUContext *top = parse(code, "super"); 1511 DUChainReleaser releaser(top); 1512 DUChainWriteLocker lock; 1513 1514 DUContext *ctx = top->localDeclarations().last()->internalContext(); 1515 Declaration *d = ctx->findDeclarations(QualifiedIdentifier("foo")).first(); 1516 QVERIFY(d); 1517 auto sType = d->type<FunctionType>()->returnType().dynamicCast<StructureType>(); 1518 QVERIFY(sType); 1519 QCOMPARE(sType->qualifiedIdentifier(), QualifiedIdentifier("String")); 1520 } 1521 1522 // Defines a method with an amazing list of arguments 1523 const QByteArray foo("def foo(a, b = 0, c = 0, *d, e, f, &blk); end; "); 1524 1525 void TestDUChain::guessArgumentsType1() 1526 { 1527 QByteArray code(foo + "foo 1, 'str', //"); 1528 TopDUContext *top = parse(code, "guessArgumentsType1"); 1529 DUChainReleaser releaser(top); 1530 DUChainWriteLocker lock; 1531 1532 Declaration *d = top->localDeclarations().first(); 1533 QVector<Declaration *> args = DUChainUtils::argumentContext(d)->localDeclarations(); 1534 QCOMPARE(args.size(), 7); 1535 1536 // a, b and c are just Fixnum 1537 QCOMPARE(args.first()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1538 QCOMPARE(args.at(1)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1539 QCOMPARE(args.at(2)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1540 1541 // d is an empty array 1542 QCOMPARE(args.at(3)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Array")); 1543 QVERIFY(! args.at(3)->type<ClassType>()->contentType()); 1544 1545 // e is a String and f is a Regexp 1546 QCOMPARE(args.at(4)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("String")); 1547 QCOMPARE(args.at(5)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Regexp")); 1548 1549 // blk is just a Proc 1550 QCOMPARE(args.last()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Proc")); 1551 } 1552 1553 void TestDUChain::guessArgumentsType2() 1554 { 1555 QByteArray code(foo + "foo 1, 'str', 1.2, //"); 1556 TopDUContext *top = parse(code, "guessArgumentsType2"); 1557 DUChainReleaser releaser(top); 1558 DUChainWriteLocker lock; 1559 1560 Declaration *d = top->localDeclarations().first(); 1561 QVector<Declaration *> args = DUChainUtils::argumentContext(d)->localDeclarations(); 1562 QCOMPARE(args.size(), 7); 1563 1564 // a is just a Fixnum 1565 QCOMPARE(args.first()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1566 1567 // b is an Unsure of Fixnum and String 1568 auto unsure = args.at(1)->abstractType().dynamicCast<UnsureType>(); 1569 QStringList list; 1570 list << "Fixnum" << "String"; 1571 testUnsureTypes(unsure, list); 1572 1573 // c is just a Fixnum 1574 QCOMPARE(args.at(2)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1575 1576 // d is an empty array 1577 QCOMPARE(args.at(3)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Array")); 1578 QVERIFY(! args.at(3)->type<ClassType>()->contentType()); 1579 1580 // e is a Float and f is a Regexp 1581 QCOMPARE(args.at(4)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Float")); 1582 QCOMPARE(args.at(5)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Regexp")); 1583 1584 // blk is just a Proc 1585 QCOMPARE(args.last()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Proc")); 1586 } 1587 1588 void TestDUChain::guessArgumentsType3() 1589 { 1590 QByteArray code(foo + "foo 1, 'str', 1, 2, 'str', 1.2, //"); 1591 TopDUContext *top = parse(code, "guessArgumentsType3"); 1592 DUChainReleaser releaser(top); 1593 DUChainWriteLocker lock; 1594 1595 Declaration *d = top->localDeclarations().first(); 1596 QVector<Declaration *> args = DUChainUtils::argumentContext(d)->localDeclarations(); 1597 QCOMPARE(args.size(), 7); 1598 1599 // a is just a Fixnum 1600 QCOMPARE(args.first()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1601 1602 // b is an Unsure of Fixnum and String 1603 auto unsure = args.at(1)->abstractType().dynamicCast<UnsureType>(); 1604 QStringList list; 1605 list << "Fixnum" << "String"; 1606 testUnsureTypes(unsure, list); 1607 1608 // c is just a Fixnum 1609 QCOMPARE(args.at(2)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1610 1611 // d is an empty array 1612 QCOMPARE(args.at(3)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Array")); 1613 unsure = args.at(3)->type<ClassType>()->contentType().abstractType().dynamicCast<UnsureType>(); 1614 list.clear(); 1615 list << "Fixnum" << "String"; 1616 testUnsureTypes(unsure, list); 1617 1618 // e is a Float and f is a Regexp 1619 QCOMPARE(args.at(4)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Float")); 1620 QCOMPARE(args.at(5)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Regexp")); 1621 1622 // blk is just a Proc 1623 QCOMPARE(args.last()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Proc")); 1624 } 1625 1626 void TestDUChain::showErrorOnTooFewArguments() 1627 { 1628 QByteArray code("def foo(a, b = 0, c = 0, *d, e, f, &blk); end; foo 1, 2"); 1629 TopDUContext *top = parse(code, "showErrorOnTooFewArguments"); 1630 DUChainReleaser releaser(top); 1631 DUChainWriteLocker lock; 1632 1633 QStringList errors; 1634 errors << "wrong number of arguments (2 for 3) (ArgumentError)"; 1635 testProblems(top, errors); 1636 } 1637 1638 void TestDUChain::showErrorOnTooManyArguments() 1639 { 1640 QByteArray code("def foo(a, b); end; foo 1, 2, 3"); 1641 TopDUContext *top = parse(code, "showErrorOnTooManyArguments"); 1642 DUChainReleaser releaser(top); 1643 DUChainWriteLocker lock; 1644 1645 QStringList errors; 1646 errors << "wrong number of arguments (3 for 2) (ArgumentError)"; 1647 testProblems(top, errors); 1648 } 1649 1650 void TestDUChain::hashArgument() 1651 { 1652 QByteArray code("def foo(a, *b, c); end; foo 1, 2, 'string', :a => 'a', :b => 1"); 1653 TopDUContext *top = parse(code, "hashArgument"); 1654 DUChainReleaser releaser(top); 1655 DUChainWriteLocker lock; 1656 1657 Declaration *d = top->localDeclarations().first(); 1658 QVector<Declaration *> args = DUChainUtils::argumentContext(d)->localDeclarations(); 1659 QCOMPARE(args.size(), 3); 1660 1661 // a 1662 QCOMPARE(args.first()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1663 1664 // b 1665 QCOMPARE(args.at(1)->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Array")); 1666 auto unsure = args.at(1)->type<ClassType>()->contentType().abstractType().dynamicCast<UnsureType>(); 1667 QStringList list; 1668 list << "Fixnum" << "String"; 1669 testUnsureTypes(unsure, list); 1670 1671 // c 1672 QCOMPARE(args.last()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Hash")); 1673 unsure = args.last()->type<ClassType>()->contentType().abstractType().dynamicCast<UnsureType>(); 1674 list.clear(); 1675 list << "String" << "Fixnum"; 1676 testUnsureTypes(unsure, list); 1677 } 1678 1679 void TestDUChain::setUnsureArgument() 1680 { 1681 QByteArray code("def foo(a, b); end; foo 1, 2; foo 'asd', 2"); 1682 TopDUContext *top = parse(code, "setUnsureArgument"); 1683 DUChainReleaser releaser(top); 1684 DUChainWriteLocker lock; 1685 1686 MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(top->localDeclarations().first()); 1687 QVERIFY(md); 1688 QVector<Declaration *> args = DUChainUtils::argumentContext(md)->localDeclarations(); 1689 QVERIFY(args.size() == 2); 1690 auto unsure = args.first()->indexedType().abstractType().dynamicCast<UnsureType>(); 1691 QStringList list; 1692 list << "Fixnum" << "String"; 1693 testUnsureTypes(unsure, list); 1694 QCOMPARE(args.last()->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Fixnum")); 1695 } 1696 1697 void TestDUChain::conflictOnSpecialMethods() 1698 { 1699 QByteArray code("module Modul; end; class Klass; extend Modul; "); 1700 code += "def include; end; private = 1; end"; 1701 TopDUContext *top = parse(code, "conflictOnSpecialMethods"); 1702 DUChainReleaser releaser(top); 1703 DUChainWriteLocker lock; 1704 1705 QVector<Declaration *> decls = top->localDeclarations(); 1706 ModuleDeclaration *modul = dynamic_cast<ModuleDeclaration *>(decls.first()); 1707 ModuleDeclaration *klass = dynamic_cast<ModuleDeclaration *>(decls.last()); 1708 QVERIFY(modul); 1709 QVERIFY(klass); 1710 1711 /* 1712 * First check that special methods that have been re-declared are being 1713 * properly handled. 1714 */ 1715 1716 decls = klass->internalContext()->localDeclarations(); 1717 QCOMPARE(decls.size(), 2); 1718 1719 MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(decls.first()); 1720 VariableDeclaration *vd = dynamic_cast<VariableDeclaration *>(decls.last()); 1721 QVERIFY(md); 1722 QVERIFY(vd); 1723 QCOMPARE(md->qualifiedIdentifier(), QualifiedIdentifier("Klass::include")); 1724 QCOMPARE(vd->qualifiedIdentifier(), QualifiedIdentifier("Klass::private")); 1725 1726 /* 1727 * Finally, check that since the "extend" method hasn't been touched, it 1728 * should've extended the Klass class as expected. 1729 */ 1730 1731 QCOMPARE(klass->moduleMixinsSize(), 1u); 1732 QVERIFY(!klass->moduleMixins()[0].included); 1733 QCOMPARE(klass->moduleMixins()[0].module.type<StructureType>()->qualifiedIdentifier(), modul->qualifiedIdentifier()); 1734 } 1735 1736 //END: Methods 1737 1738 //BEGIN: Include & Extend 1739 1740 void TestDUChain::include1() 1741 { 1742 /* 1743 * The class Klass includes the module AA::BB that has the instance 1744 * method foo. 1745 */ 1746 QByteArray code("module AA; module BB; def foo; end; def self.selfish; end;"); 1747 code += "end; end; class Klass; include AA::BB; end"; 1748 TopDUContext *top = parse(code, "include1"); 1749 DUChainReleaser releaser(top); 1750 DUChainWriteLocker lock; 1751 1752 Declaration *obj = top->findLocalDeclarations(Identifier("Klass")).first(); 1753 ModuleDeclaration *md = dynamic_cast<ModuleDeclaration *>(obj); 1754 QVERIFY(md); 1755 1756 // Check for the moduleMixins list of the class Klass 1757 QCOMPARE(md->internalContext()->localDeclarations(md->topContext()).size(), 1); 1758 QCOMPARE(md->moduleMixinsSize(), 1u); 1759 QVERIFY(md->moduleMixins()[0].included); 1760 QCOMPARE(md->moduleMixins()[0].module.type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("AA::BB")); 1761 QCOMPARE(md->mixersSize(), 0u); 1762 1763 // Check for the mixers list of the module AA::BB 1764 obj = top->localDeclarations().at(0)->internalContext()->localDeclarations().first(); 1765 md = dynamic_cast<ModuleDeclaration *>(obj); 1766 QVERIFY(md); 1767 QCOMPARE(md->moduleMixinsSize(), 0u); 1768 QCOMPARE(md->mixersSize(), 1u); 1769 QCOMPARE(md->mixers()[0].module.type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Klass")); 1770 } 1771 1772 void TestDUChain::include2() 1773 { 1774 /* 1775 * The module AA::CC includes the module AA::BB, that has the instance 1776 * method foo. Finally, the class Klass includes the module AA::CC. 1777 */ 1778 QByteArray code("module AA; module BB; def foo; end; end; module CC; "); 1779 code += "include ::AA::BB; end; end; class Klass; include AA::CC; end"; 1780 TopDUContext *top = parse(code, "include2"); 1781 DUChainReleaser releaser(top); 1782 DUChainWriteLocker lock; 1783 1784 Declaration *obj = top->findLocalDeclarations(Identifier("Klass")).first(); 1785 ModuleDeclaration *md = dynamic_cast<ModuleDeclaration *>(obj); 1786 QVERIFY(md); 1787 QCOMPARE(md->internalContext()->localDeclarations(md->topContext()).size(), 1); 1788 QCOMPARE(md->moduleMixinsSize(), 1u); 1789 QVERIFY(md->moduleMixins()[0].included); 1790 QCOMPARE(md->moduleMixins()[0].module.type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("AA::CC")); 1791 } 1792 1793 void TestDUChain::extend() 1794 { 1795 /* Same as include1 but with extend and a class method */ 1796 QByteArray code("module AA; module BB; def foo; end; def self.selfish; end;"); 1797 code += "end; end; class Klass; extend AA::BB; end"; 1798 TopDUContext *top = parse(code, "extend"); 1799 DUChainReleaser releaser(top); 1800 DUChainWriteLocker lock; 1801 1802 // Check for the moduleMixins list of the class Klass 1803 Declaration *obj = top->findLocalDeclarations(Identifier("Klass")).first(); 1804 ModuleDeclaration *md = dynamic_cast<ModuleDeclaration *>(obj); 1805 QVERIFY(md); 1806 QCOMPARE(md->internalContext()->localDeclarations(md->topContext()).size(), 1); 1807 QCOMPARE(md->moduleMixinsSize(), 1u); 1808 QVERIFY(!md->moduleMixins()[0].included); 1809 QCOMPARE(md->moduleMixins()[0].module.type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("AA::BB")); 1810 1811 // Check for the mixers list of the module AA::BB 1812 obj = top->localDeclarations().at(0)->internalContext()->localDeclarations().first(); 1813 md = dynamic_cast<ModuleDeclaration *>(obj); 1814 QVERIFY(md); 1815 QCOMPARE(md->moduleMixinsSize(), 0u); 1816 QCOMPARE(md->mixersSize(), 1u); 1817 QCOMPARE(md->mixers()[0].module.type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("Klass")); 1818 } 1819 1820 void TestDUChain::problemOnInvalidMixin() 1821 { 1822 QByteArray code("class Lala; end; class Klass; include Lala; end"); 1823 TopDUContext *top = parse(code, "problemOnInvalidMixin"); 1824 DUChainReleaser releaser(top); 1825 DUChainWriteLocker lock; 1826 1827 QStringList list; 1828 list << "TypeError: wrong argument type (expected Module)"; 1829 testProblems(top, list); 1830 } 1831 1832 //END: Include & Extend 1833 1834 } 1835