Warning, file /kdevelop/kdev-php/duchain/tests/uses.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "uses.h" 0008 0009 #include <QtTest> 0010 0011 #include <language/duchain/duchain.h> 0012 #include <language/duchain/duchainlock.h> 0013 #include <language/duchain/problem.h> 0014 0015 #include "../declarations/classdeclaration.h" 0016 #include "../declarations/variabledeclaration.h" 0017 #include "../declarations/traitmethodaliasdeclaration.h" 0018 #include "../declarations/traitmemberaliasdeclaration.h" 0019 0020 #include "../types/structuretype.h" 0021 0022 using namespace KDevelop; 0023 0024 QTEST_MAIN(Php::TestUses) 0025 0026 namespace Php 0027 { 0028 0029 void compareUses(Declaration* dec, QList<RangeInRevision> ranges) 0030 { 0031 qDebug() << "comparing uses for" << dec->toString(); 0032 QCOMPARE(dec->uses().keys().count(), 1); 0033 QCOMPARE(dec->uses().values().count(), 1); 0034 QCOMPARE(dec->uses().values().first().count(), ranges.count()); 0035 for (int i = 0; i < ranges.count(); ++i) { 0036 qDebug() << dec->uses().values().first().at(i) << ranges.at(i); 0037 QCOMPARE(dec->uses().values().first().at(i), ranges.at(i)); 0038 } 0039 } 0040 0041 void compareUses(Declaration* dec, RangeInRevision range) 0042 { 0043 QList<RangeInRevision> r; 0044 r << range; 0045 compareUses(dec, r); 0046 } 0047 0048 TestUses::TestUses() 0049 { 0050 } 0051 0052 void TestUses::newObject() 0053 { 0054 0055 // 0 1 2 3 4 5 6 7 0056 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0057 QByteArray method("<? class Foo {} $a = new Foo(); "); 0058 TopDUContext* top = parse(method, DumpNone, QUrl(QStringLiteral("file:///internal/usestest/newObject.php"))); 0059 DUChainReleaser releaseTop(top); 0060 DUChainWriteLocker lock(DUChain::lock()); 0061 compareUses(top->localDeclarations().first(), RangeInRevision(0, 25, 0, 28)); 0062 QCOMPARE(top->localDeclarations().first()->uses().keys().first(), IndexedString(QUrl("file:///internal/usestest/newObject.php"))); 0063 } 0064 0065 void TestUses::functionCall() 0066 { 0067 0068 // 0 1 2 3 4 5 6 7 0069 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0070 QByteArray method("<? function foo() {} foo(); "); 0071 TopDUContext* top = parse(method, DumpNone, QUrl(QStringLiteral("file:///internal/usestest/functionCall.php"))); 0072 DUChainReleaser releaseTop(top); 0073 DUChainWriteLocker lock(DUChain::lock()); 0074 Declaration* fun = top->localDeclarations().first(); 0075 compareUses(fun, RangeInRevision(0, 21, 0, 24)); 0076 QCOMPARE(fun->uses().keys().first(), IndexedString(QUrl("file:///internal/usestest/functionCall.php"))); 0077 } 0078 0079 void TestUses::functionCallWithClosureArgs() 0080 { 0081 0082 // 0 1 2 3 4 5 6 7 8 9 0083 // 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0084 QByteArray method("<? function foo($a, $b) {} $c = []; $d = []; foo(function ($x) use ($c) { return $c[$x]; }, $d); "); 0085 TopDUContext* top = parse(method, DumpNone); 0086 DUChainReleaser releaseTop(top); 0087 DUChainWriteLocker lock(DUChain::lock()); 0088 0089 // foo 0090 Declaration* fun = top->localDeclarations().first(); 0091 compareUses(fun, RangeInRevision(0, 45, 0, 48)); 0092 0093 // $c 0094 Declaration* c = top->localDeclarations().at(1); 0095 compareUses(c, QList<RangeInRevision>() << RangeInRevision(0, 68, 0, 70) << RangeInRevision(0, 81, 0, 83)); 0096 0097 // $d 0098 Declaration* d = top->localDeclarations().at(2); 0099 compareUses(d, RangeInRevision(0, 92, 0, 94)); 0100 } 0101 0102 void TestUses::memberFunctionCall() 0103 { 0104 0105 // 0 1 2 3 4 5 6 7 0106 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0107 QByteArray method("<? class A { function foo() {} } $a = new A(); $a->foo(); "); 0108 TopDUContext* top = parse(method, DumpNone, QUrl(QStringLiteral("file:///internal/usestest/memberFunctionCall.php"))); 0109 DUChainReleaser releaseTop(top); 0110 DUChainWriteLocker lock(DUChain::lock()); 0111 Declaration* fun = top->childContexts().first()->localDeclarations().first(); 0112 compareUses(fun, RangeInRevision(0, 51, 0, 54)); 0113 QCOMPARE(fun->uses().keys().first(), IndexedString(QUrl("file:///internal/usestest/memberFunctionCall.php"))); 0114 } 0115 0116 void TestUses::unsureMemberFunctionCall() { 0117 //First try with a single unsure structure type 0118 0119 { 0120 // 0 1 2 3 4 5 6 7 8 0121 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0122 QByteArray method("<? class A { function foo() {} } if (true) { $a = new A(); } else { $a = null; } $a->foo();"); 0123 TopDUContext* top = parse(method, DumpNone); 0124 DUChainReleaser releaseTop(top); 0125 DUChainWriteLocker lock(DUChain::lock()); 0126 Declaration* fun = top->childContexts().first()->localDeclarations().first(); 0127 compareUses(fun, RangeInRevision(0, 85, 0, 88)); 0128 } 0129 0130 //Now try with two unsure structure types 0131 0132 { 0133 // 0 1 2 3 4 5 6 7 8 0134 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0135 QByteArray method("<? class A { function foo() {} } class B {} if (true) { $a = new A(); } else { $a = new B(); } $a->foo();"); 0136 TopDUContext* top = parse(method, DumpNone); 0137 DUChainReleaser releaseTop(top); 0138 DUChainWriteLocker lock(DUChain::lock()); 0139 Declaration* fun = top->childContexts().first()->localDeclarations().first(); 0140 QCOMPARE(fun->uses().keys().count(), 0); 0141 } 0142 } 0143 0144 void TestUses::memberVariable() 0145 { 0146 0147 // 0 1 2 3 4 5 6 7 0148 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0149 QByteArray method("<? class A { public $foo; } $a = new A(); $a->foo; "); 0150 TopDUContext* top = parse(method, DumpNone, QUrl(QStringLiteral("file:///internal/usestest/memberVariable.php"))); 0151 DUChainReleaser releaseTop(top); 0152 DUChainWriteLocker lock(DUChain::lock()); 0153 Declaration* var = top->childContexts().first()->localDeclarations().first(); 0154 compareUses(var, RangeInRevision(0, 46, 0, 49)); 0155 QCOMPARE(var->uses().keys().first(), IndexedString(QUrl("file:///internal/usestest/memberVariable.php"))); 0156 } 0157 0158 void TestUses::implicitMemberVariable() 0159 { 0160 0161 // 0 1 2 3 4 5 6 7 0162 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0163 QByteArray method("<? $x = new A(); $x->y = 1; $x->y = 2; class A {}"); 0164 TopDUContext* top = parse(method, DumpNone); 0165 DUChainReleaser releaseTop(top); 0166 DUChainWriteLocker lock(DUChain::lock()); 0167 Declaration* var = top->childContexts().first()->localDeclarations().first(); 0168 QList<RangeInRevision> ranges; 0169 ranges << RangeInRevision(0, 21, 0, 22) << RangeInRevision(0, 32, 0, 33); 0170 compareUses(var, ranges); 0171 QVERIFY(var->range() == RangeInRevision(0, 21, 0, 22)); 0172 } 0173 0174 void TestUses::variable() 0175 { 0176 // 0 1 2 3 4 5 6 7 0177 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0178 QByteArray method("<?php\nclass A { public $foo; } $a = new A(); $a; $a->foo; foo($a); "); 0179 TopDUContext* top = parse(method, DumpAll); 0180 DUChainReleaser releaseTop(top); 0181 DUChainWriteLocker lock(DUChain::lock()); 0182 QList<RangeInRevision> ranges; 0183 ranges << RangeInRevision(1, 42 - 3, 1, 44 - 3) << RangeInRevision(1, 46 - 3, 1, 48 - 3) << RangeInRevision(1, 59 - 3, 1, 61 - 3); 0184 compareUses(top->localDeclarations().at(1), ranges); 0185 } 0186 0187 void TestUses::varInString() 0188 { 0189 0190 // 0 1 2 3 4 5 6 7 0191 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0192 QByteArray method("<?php $a=0; \"$a {$a}\"; "); 0193 TopDUContext* top = parse(method, DumpAll); 0194 DUChainReleaser releaseTop(top); 0195 DUChainWriteLocker lock(DUChain::lock()); 0196 QList<RangeInRevision> ranges; 0197 ranges << RangeInRevision(0, 13, 0, 15) << RangeInRevision(0, 17, 0, 19); 0198 compareUses(top->localDeclarations().at(0), ranges); 0199 } 0200 0201 void TestUses::variableInNamespace() 0202 { 0203 0204 // 0 1 2 3 4 5 6 7 0205 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0206 QByteArray method("<?php\nclass A { public $foo; } namespace Foo { $a = new A(); $a; $a->foo; foo($a); };"); 0207 TopDUContext* top = parse(method, DumpAll); 0208 DUChainReleaser releaseTop(top); 0209 DUChainWriteLocker lock(DUChain::lock()); 0210 QList<RangeInRevision> ranges; 0211 ranges << RangeInRevision(1, 55, 1, 57) << RangeInRevision(1, 59, 1, 61) << RangeInRevision(1, 72, 1, 74); 0212 compareUses(top->localDeclarations().at(2), ranges); 0213 } 0214 0215 void TestUses::globalVariableInNamespace() 0216 { 0217 0218 // 0 1 2 3 4 5 6 7 0219 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0220 QByteArray method("<?php\nclass A { public $foo; } $a = new A(); namespace Foo { $a; $a->foo; foo($a); };"); 0221 TopDUContext* top = parse(method, DumpAll); 0222 DUChainReleaser releaseTop(top); 0223 DUChainWriteLocker lock(DUChain::lock()); 0224 QList<RangeInRevision> ranges; 0225 ranges << RangeInRevision(1, 55, 1, 57) << RangeInRevision(1, 59, 1, 61) << RangeInRevision(1, 72, 1, 74); 0226 compareUses(top->localDeclarations().at(1), ranges); 0227 } 0228 0229 void TestUses::variableInOtherNamespace() 0230 { 0231 // 0 1 2 3 4 5 6 7 0232 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0233 QByteArray method("<?php\nclass A { public $foo; } namespace Foo { $a = new A(); } namespace Bar { $a; $a->foo; foo($a); };"); 0234 TopDUContext* top = parse(method, DumpAll); 0235 DUChainReleaser releaseTop(top); 0236 DUChainWriteLocker lock(DUChain::lock()); 0237 QList<RangeInRevision> ranges; 0238 ranges << RangeInRevision(1, 73, 1, 75) << RangeInRevision(1, 77, 1, 79) << RangeInRevision(1, 90, 1, 92); 0239 compareUses(top->localDeclarations().at(2), ranges); 0240 } 0241 0242 void TestUses::memberVarInString() 0243 { 0244 0245 // 0 1 2 3 4 5 6 7 0246 // 01234567890123456789012345678901234567890123456789 01234567890123 4567890123456789 0247 QByteArray method("<?php class A { public $v=0; } $a=new A(); $a->v; \"$a->v {$a->v}\"; "); 0248 TopDUContext* top = parse(method, DumpAll); 0249 DUChainReleaser releaseTop(top); 0250 DUChainWriteLocker lock(DUChain::lock()); 0251 0252 QList<RangeInRevision> ranges; 0253 ranges << RangeInRevision(0, 43, 0, 45) << RangeInRevision(0, 51, 0, 53) << RangeInRevision(0, 58, 0, 60); 0254 compareUses(top->localDeclarations().at(1), ranges); 0255 0256 ranges.clear(); 0257 ranges << RangeInRevision(0, 47, 0, 48) << RangeInRevision(0, 55, 0, 56) << RangeInRevision(0, 62, 0, 63); 0258 compareUses(top->childContexts().first()->localDeclarations().first(), ranges); 0259 } 0260 0261 void TestUses::memberFunctionInString() 0262 { 0263 0264 // 0 1 2 3 4 5 6 7 0265 // 012345678901234567890123456789012345678901234567 890123456789 01234567890123456789 0266 QByteArray method("<?php class A { function foo() {} } $a=new A(); \"{$a->foo()}\"; "); 0267 TopDUContext* top = parse(method, DumpAll); 0268 DUChainReleaser releaseTop(top); 0269 DUChainWriteLocker lock(DUChain::lock()); 0270 0271 //$a 0272 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 50, 0, 52)); 0273 0274 //foo 0275 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 54, 0, 57)); 0276 } 0277 0278 void TestUses::variableTypeChange() 0279 { 0280 // 0 1 2 3 4 5 6 7 0281 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0282 QByteArray method("<? class A { } $a = 'a'; $a; $a = 0; $a; $a = 'x'; $a; "); 0283 // 15 25 29 37 41 51 0284 TopDUContext* top = parse(method, DumpAll); 0285 DUChainReleaser releaseTop(top); 0286 DUChainWriteLocker lock(DUChain::lock()); 0287 0288 QList<RangeInRevision> ranges; 0289 ranges << RangeInRevision(0, 25, 0, 27); 0290 ranges << RangeInRevision(0, 29, 0, 31); 0291 ranges << RangeInRevision(0, 37, 0, 39); 0292 ranges << RangeInRevision(0, 41, 0, 43); 0293 ranges << RangeInRevision(0, 51, 0, 53); 0294 compareUses(top->localDeclarations().at(1), ranges); 0295 } 0296 0297 void TestUses::variableTypeChangeInFunction() 0298 { 0299 // 0 1 2 3 4 5 6 7 0300 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0301 QByteArray method("<? function foo() { $a='a'; $a; $a=0; $a; $a=false; }"); 0302 // 20 28 32 38 42 0303 0304 TopDUContext* top = parse(method, DumpAll); 0305 DUChainReleaser releaseTop(top); 0306 DUChainWriteLocker lock(DUChain::lock()); 0307 0308 QList<RangeInRevision> ranges; 0309 ranges << RangeInRevision(0, 28, 0, 30); 0310 ranges << RangeInRevision(0, 32, 0, 34); 0311 ranges << RangeInRevision(0, 38, 0, 40); 0312 ranges << RangeInRevision(0, 42, 0, 44); 0313 compareUses(top->childContexts().at(1)->localDeclarations().at(0), ranges); 0314 } 0315 0316 void TestUses::classExtends() 0317 { 0318 // 0 1 2 3 4 5 6 7 0319 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0320 QByteArray method("<? class A { } class B extends A { } "); 0321 TopDUContext* top = parse(method, DumpAll); 0322 DUChainWriteLocker lock(DUChain::lock()); 0323 0324 compareUses(top->localDeclarations().at(0), RangeInRevision(0, 31, 0, 32)); 0325 } 0326 0327 void TestUses::classImplements() 0328 { 0329 // 0 1 2 3 4 5 6 7 0330 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0331 QByteArray method("<? interface A { } class B implements A { } "); 0332 TopDUContext* top = parse(method, DumpAll); 0333 DUChainReleaser releaseTop(top); 0334 DUChainWriteLocker lock(DUChain::lock()); 0335 0336 compareUses(top->localDeclarations().at(0), RangeInRevision(0, 38, 0, 39)); 0337 } 0338 0339 void TestUses::classImplementsMultiple() 0340 { 0341 // 0 1 2 3 4 5 6 7 0342 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0343 QByteArray method("<? interface A { } interface B { } class C implements A, B { } "); 0344 TopDUContext* top = parse(method, DumpAll); 0345 DUChainReleaser releaseTop(top); 0346 DUChainWriteLocker lock(DUChain::lock()); 0347 0348 compareUses(top->localDeclarations().at(0), RangeInRevision(0, 54, 0, 55)); 0349 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 57, 0, 58)); 0350 } 0351 0352 void TestUses::interfaceExtends() 0353 { 0354 // 0 1 2 3 4 5 6 7 0355 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0356 QByteArray method("<? interface A { } interface B extends A { }"); 0357 TopDUContext* top = parse(method, DumpAll); 0358 DUChainReleaser releaseTop(top); 0359 DUChainWriteLocker lock(DUChain::lock()); 0360 0361 compareUses(top->localDeclarations().at(0), RangeInRevision(0, 39, 0, 40)); 0362 } 0363 0364 void TestUses::interfaceExtendsMultiple() 0365 { 0366 // 0 1 2 3 4 5 6 7 0367 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0368 QByteArray method("<? interface A { } interface B { } interface C extends A, B { }"); 0369 TopDUContext* top = parse(method, DumpAll); 0370 DUChainReleaser releaseTop(top); 0371 DUChainWriteLocker lock(DUChain::lock()); 0372 0373 compareUses(top->localDeclarations().at(0), RangeInRevision(0, 55, 0, 56)); 0374 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 58, 0, 59)); 0375 } 0376 0377 void TestUses::staticMemberFunctionCall() 0378 { 0379 // 0 1 2 3 4 5 6 7 0380 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0381 QByteArray method("<? class A { public static function foo() {} } A::foo(); "); 0382 TopDUContext* top = parse(method, DumpAll); 0383 DUChainReleaser releaseTop(top); 0384 DUChainWriteLocker lock(DUChain::lock()); 0385 0386 compareUses(top->localDeclarations().first(), RangeInRevision(0, 47, 0, 48)); 0387 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 50, 0, 53)); 0388 } 0389 0390 void TestUses::staticMemberVariable() 0391 { 0392 // 0 1 2 3 4 5 6 7 0393 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0394 QByteArray method("<? class A { public static $foo; } $foo=0; A::$foo; $foo;"); 0395 TopDUContext* top = parse(method, DumpAll); 0396 DUChainReleaser releaseTop(top); 0397 DUChainWriteLocker lock(DUChain::lock()); 0398 0399 compareUses(top->localDeclarations().first(), RangeInRevision(0, 43, 0, 44)); 0400 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 46, 0, 50)); 0401 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 52, 0, 56)); 0402 } 0403 0404 void TestUses::dynamicStaticMemberVariable() 0405 { 0406 // 0 1 2 3 4 5 6 7 0407 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0408 QByteArray method("<? class A { public static $foo; } $var='foo'; A::${$var};"); 0409 TopDUContext* top = parse(method, DumpAll); 0410 DUChainReleaser releaseTop(top); 0411 DUChainWriteLocker lock(DUChain::lock()); 0412 0413 Declaration* dec = top->localDeclarations().at(0); 0414 QCOMPARE(dec->identifier(), Identifier(u"a")); 0415 compareUses(dec, QList<RangeInRevision>() 0416 << RangeInRevision(0, 47, 0, 48)); 0417 0418 dec = top->localDeclarations().at(1); 0419 QCOMPARE(dec->identifier(), Identifier(u"var")); 0420 compareUses(dec, QList<RangeInRevision>() 0421 << RangeInRevision(0, 52, 0, 56)); 0422 } 0423 0424 void TestUses::constant() 0425 { 0426 // 0 1 2 3 4 5 6 7 0427 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0428 QByteArray method("<? define('A', 'foo'); echo A;"); 0429 TopDUContext* top = parse(method, DumpAll); 0430 DUChainReleaser releaseTop(top); 0431 DUChainWriteLocker lock(DUChain::lock()); 0432 0433 compareUses(top->localDeclarations().first(), RangeInRevision(0, 28, 0, 29)); 0434 } 0435 0436 void TestUses::classConstant() 0437 { 0438 { 0439 // 0 1 2 3 4 5 6 7 0440 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0441 QByteArray method("<? class A { const FOO = 'abc'; } echo A::FOO;"); 0442 TopDUContext* top = parse(method, DumpAll); 0443 DUChainReleaser releaseTop(top); 0444 DUChainWriteLocker lock(DUChain::lock()); 0445 0446 compareUses(top->localDeclarations().first(), RangeInRevision(0, 39, 0, 40)); 0447 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 42, 0, 45)); 0448 } 0449 { 0450 // bug: https://bugs.kde.org/show_bug.cgi?id=241597 0451 0452 // 0 1 2 3 4 5 6 7 0453 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0454 QByteArray method("<? class A { const FOO = 'abc'; }\n" 0455 "class B extends A { function foo() { self::FOO; } }\n" 0456 "A::FOO;\n" 0457 "B::FOO;\n"); 0458 TopDUContext* top = parse(method, DumpAll); 0459 DUChainReleaser releaseTop(top); 0460 DUChainWriteLocker lock; 0461 0462 Declaration* dec = top->childContexts().first()->localDeclarations().first(); 0463 QVERIFY(dec->abstractType()->modifiers() & AbstractType::ConstModifier); 0464 QCOMPARE(dec->qualifiedIdentifier().toString(), QString("a::FOO")); 0465 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(1, 43, 1, 46) 0466 << RangeInRevision(2, 3, 2, 6) 0467 << RangeInRevision(3, 3, 3, 6)); 0468 } 0469 } 0470 0471 void TestUses::classParent() 0472 { 0473 // 0 1 2 3 4 5 6 7 0474 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0475 QByteArray method("<? class A { function x() {} } class B extends A { function x() { parent::x(); }} "); 0476 TopDUContext* top = parse(method, DumpAll); 0477 DUChainReleaser releaseTop(top); 0478 DUChainWriteLocker lock(DUChain::lock()); 0479 0480 QList<RangeInRevision> range; 0481 range << RangeInRevision(0, 47, 0, 48); 0482 range << RangeInRevision(0, 66, 0, 72); 0483 compareUses(top->localDeclarations().first(), range); 0484 0485 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 74, 0, 75)); 0486 } 0487 0488 void TestUses::classSelf() 0489 { 0490 // 0 1 2 3 4 5 6 7 0491 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0492 QByteArray method("<? class A { function x() { self::x(); } } "); 0493 TopDUContext* top = parse(method, DumpAll); 0494 DUChainReleaser releaseTop(top); 0495 DUChainWriteLocker lock(DUChain::lock()); 0496 0497 compareUses(top->localDeclarations().first(), RangeInRevision(0, 28, 0, 32)); 0498 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 34, 0, 35)); 0499 } 0500 void TestUses::classThis() 0501 { 0502 // 0 1 2 3 4 5 6 7 0503 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0504 QByteArray method("<? class A { function x() { $this->x(); } } "); 0505 TopDUContext* top = parse(method, DumpAll); 0506 DUChainReleaser releaseTop(top); 0507 DUChainWriteLocker lock(DUChain::lock()); 0508 0509 compareUses(top->localDeclarations().first(), RangeInRevision(0, 28, 0, 33)); 0510 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 35, 0, 36)); 0511 } 0512 0513 void TestUses::objectWithClassName() 0514 { 0515 // 0 1 2 3 4 5 6 7 8 0516 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0517 QByteArray method("<? class Aa { public static $i; const j=0; public $k; } $Aa = new Aa; $Aa->k; Aa::j; Aa::$i;"); 0518 TopDUContext* top = parse(method, DumpAll); 0519 DUChainReleaser releaseTop(top); 0520 DUChainWriteLocker lock(DUChain::lock()); 0521 0522 QList<RangeInRevision> ranges; 0523 ranges << RangeInRevision(0, 66, 0, 66 + 2); 0524 ranges << RangeInRevision(0, 78, 0, 78 + 2); 0525 ranges << RangeInRevision(0, 85, 0, 85 + 2); 0526 compareUses(top->localDeclarations().first(), ranges); 0527 0528 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 70, 0, 70 + 3)); 0529 } 0530 0531 void TestUses::classAndConstWithSameName() 0532 { 0533 // 0 1 2 3 4 5 6 7 8 0534 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0535 QByteArray method("<? class A { } define('A', 0); A; new A; define('B', 0); class B { } new B; B; "); 0536 TopDUContext* top = parse(method, DumpAll); 0537 DUChainReleaser releaseTop(top); 0538 DUChainWriteLocker lock(DUChain::lock()); 0539 0540 compareUses(top->localDeclarations().first(), RangeInRevision(0, 38, 0, 39)); 0541 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 31, 0, 32)); 0542 compareUses(top->localDeclarations().at(2), RangeInRevision(0, 76, 0, 77)); 0543 compareUses(top->localDeclarations().at(3), RangeInRevision(0, 73, 0, 74)); 0544 } 0545 0546 0547 void TestUses::classAndFunctionWithSameName() 0548 { 0549 // 0 1 2 3 4 5 6 7 8 0550 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0551 QByteArray method("<? class A { } function A() {} new A; A(); "); 0552 TopDUContext* top = parse(method, DumpAll); 0553 DUChainReleaser releaseTop(top); 0554 DUChainWriteLocker lock(DUChain::lock()); 0555 0556 compareUses(top->localDeclarations().first(), RangeInRevision(0, 35, 0, 36)); 0557 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 38, 0, 39)); 0558 } 0559 0560 void TestUses::constAndVariableWithSameName() 0561 { 0562 // 0 1 2 3 4 5 6 7 8 0563 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0564 QByteArray method("<? $A = 0; define('A', 0); A; $A; "); 0565 TopDUContext* top = parse(method, DumpAll); 0566 DUChainReleaser releaseTop(top); 0567 DUChainWriteLocker lock(DUChain::lock()); 0568 0569 compareUses(top->localDeclarations().first(), RangeInRevision(0, 30, 0, 32)); 0570 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 27, 0, 28)); 0571 } 0572 0573 void TestUses::functionAndClassWithSameName() 0574 { 0575 // 0 1 2 3 4 5 6 7 8 0576 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 0577 QByteArray method("<? interface foo { function asdf(); } class asdf {} class bar extends asdf implements foo {} "); 0578 TopDUContext* top = parse(method, DumpAll); 0579 DUChainReleaser releaseTop(top); 0580 DUChainWriteLocker lock(DUChain::lock()); 0581 0582 Declaration* fnAsdf = top->childContexts().first()->localDeclarations().first(); 0583 QCOMPARE(fnAsdf->uses().keys().count(), 0); 0584 0585 compareUses(top->localDeclarations().at(1), RangeInRevision(0, 70, 0, 74)); 0586 } 0587 0588 void TestUses::constantInClassMember() 0589 { 0590 // 0 1 2 3 4 5 6 7 0591 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0592 QByteArray method("<? define('TEST', 1); class A { var $a = TEST; var $b = array( TEST ); } TEST;"); 0593 0594 TopDUContext* top = parse(method, DumpAll); 0595 DUChainReleaser releaseTop(top); 0596 DUChainWriteLocker lock(DUChain::lock()); 0597 0598 Declaration* constant = top->findDeclarations(Identifier(QStringLiteral("TEST"))).first(); 0599 0600 QList<RangeInRevision> uses; 0601 uses << RangeInRevision(0, 41, 0, 45); 0602 uses << RangeInRevision(0, 63, 0, 67); 0603 uses << RangeInRevision(0, 73, 0, 77); 0604 compareUses(constant, uses); 0605 } 0606 0607 void TestUses::useInAsignment() 0608 { 0609 // 0 1 2 3 4 5 6 7 0610 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0611 QByteArray method("<? $a = 0; $b = $a; "); 0612 0613 TopDUContext* top = parse(method, DumpAll); 0614 DUChainReleaser releaseTop(top); 0615 DUChainWriteLocker lock(DUChain::lock()); 0616 0617 Declaration *d = top->localDeclarations().first(); 0618 compareUses(d, RangeInRevision(0, 16, 0, 18)); 0619 } 0620 0621 void TestUses::foreachArray() 0622 { 0623 // 0 1 2 3 4 5 6 7 0624 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0625 QByteArray method("<? $a = array(1); foreach($a as $k=>$i) { var_dump($k, $i); } "); 0626 0627 TopDUContext* top = parse(method, DumpAll); 0628 DUChainReleaser releaseTop(top); 0629 DUChainWriteLocker lock(DUChain::lock()); 0630 0631 // $a, $k, $i 0632 QCOMPARE(top->localDeclarations().size(), 3); 0633 0634 // $a 0635 Declaration *d = top->localDeclarations().at(0); 0636 compareUses(d, RangeInRevision(0, 26, 0, 28)); 0637 0638 // $k 0639 d = top->localDeclarations().at(1); 0640 compareUses(d, RangeInRevision(0, 51, 0, 53)); 0641 0642 // $i 0643 d = top->localDeclarations().at(2); 0644 compareUses(d, RangeInRevision(0, 55, 0, 57)); 0645 } 0646 0647 void TestUses::assignmentToMemberArray() 0648 { 0649 // 0 1 2 3 4 5 6 7 0650 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0651 QByteArray method("<?php class x { var $y; function z($a) { $b = $a; $this->y[$a] = true; } }"); 0652 0653 TopDUContext* top = parse(method, DumpAll); 0654 DUChainReleaser releaseTop(top); 0655 DUChainWriteLocker lock(DUChain::lock()); 0656 0657 // class x 0658 Declaration *x = top->localDeclarations().first(); 0659 QVERIFY(x); 0660 0661 // $this 0662 compareUses(x, RangeInRevision(0, 50, 0, 55)); 0663 0664 // var $y 0665 Declaration *y = x->logicalInternalContext(top)->findDeclarations(Identifier(QStringLiteral("y"))).first(); 0666 QVERIFY(y); 0667 0668 // $this->y 0669 compareUses(y, RangeInRevision(0, 57, 0, 58)); 0670 0671 // function z 0672 Declaration *z = x->logicalInternalContext(top)->findDeclarations(Identifier(QStringLiteral("z"))).first(); 0673 QVERIFY(z); 0674 0675 // $a 0676 Declaration *a = z->logicalInternalContext(top)->findDeclarations(Identifier(QStringLiteral("a"))).first(); 0677 QVERIFY(a); 0678 compareUses(a, QList<RangeInRevision>() 0679 // $b = $a 0680 << RangeInRevision(0, 46, 0, 48) 0681 // $this->y[$a] 0682 << RangeInRevision(0, 59, 0, 61) 0683 ); 0684 } 0685 0686 void TestUses::staticArrayIndex() 0687 { 0688 // bug: https://bugs.kde.org/show_bug.cgi?id=241160 0689 0690 // 0 1 2 3 4 5 6 7 0691 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0692 QByteArray method("<?php class x { static private $a = array(); function z($i) { self::$a[$i]; } }"); 0693 0694 TopDUContext* top = parse(method, DumpNone); 0695 DUChainReleaser releaseTop(top); 0696 DUChainWriteLocker lock(DUChain::lock()); 0697 0698 Declaration* a = top->childContexts().first()->localDeclarations().first(); 0699 QCOMPARE(a->identifier().toString(), QString("a")); 0700 compareUses(a, RangeInRevision(0, 68, 0, 70)); 0701 0702 Declaration* i = top->childContexts().first()->childContexts().first()->localDeclarations().first(); 0703 QCOMPARE(i->identifier().toString(), QString("i")); 0704 compareUses(i, RangeInRevision(0, 71, 0, 73)); 0705 } 0706 0707 void TestUses::functionParamNewDeclaration() 0708 { 0709 // 0 1 2 3 4 5 6 7 0710 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0711 QByteArray method("<? function foo($a) { $a; $a = 0; }"); 0712 0713 TopDUContext* top = parse(method, DumpAll); 0714 DUChainReleaser releaseTop(top); 0715 DUChainWriteLocker lock(DUChain::lock()); 0716 0717 Declaration *d = top->childContexts().first()->localDeclarations().first(); 0718 QList<RangeInRevision> ranges; 0719 ranges << RangeInRevision(0, 22, 0, 24); 0720 ranges << RangeInRevision(0, 26, 0, 28); 0721 compareUses(d, ranges); 0722 } 0723 0724 void TestUses::catchClass() 0725 { 0726 // 0 1 2 3 4 5 6 7 0727 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0728 QByteArray method("<? try { } catch (Exception $e) {}"); 0729 0730 TopDUContext* top = parse(method, DumpAll); 0731 DUChainReleaser releaseTop(top); 0732 DUChainWriteLocker lock(DUChain::lock()); 0733 0734 Declaration *d = top->findDeclarations(QualifiedIdentifier(QStringLiteral("exception"))).first(); 0735 compareUses(d, RangeInRevision(0, 18, 0, 27)); 0736 } 0737 0738 void TestUses::variableRedeclaration() 0739 { 0740 // 0 1 2 3 4 5 6 7 0741 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0742 QByteArray method("<? $s = 'a'; $s = $s . $s;"); 0743 0744 TopDUContext* top = parse(method, DumpAll); 0745 DUChainReleaser releaseTop(top); 0746 DUChainWriteLocker lock(DUChain::lock()); 0747 0748 QList< Declaration* > decs = top->findDeclarations(QualifiedIdentifier(QStringLiteral("s"))); 0749 QCOMPARE(decs.size(), 1); 0750 Declaration *d = decs.first(); 0751 compareUses(d, QList<RangeInRevision>() 0752 << RangeInRevision(0, 13, 0, 15) 0753 << RangeInRevision(0, 18, 0, 20) 0754 << RangeInRevision(0, 23, 0, 25) 0755 ); 0756 } 0757 0758 void TestUses::caseInsensitiveFunction() 0759 { 0760 // 0 1 2 3 4 5 6 7 0761 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0762 QByteArray method("<? function fooBar(){}\n" 0763 "fOoBar();\nFOOBAR();\nfoobar();"); 0764 0765 TopDUContext* top = parse(method, DumpNone); 0766 DUChainReleaser releaseTop(top); 0767 DUChainWriteLocker lock(DUChain::lock()); 0768 0769 QList<Declaration*> decs = top->findLocalDeclarations(Identifier(QStringLiteral("foobar"))); 0770 QCOMPARE(decs.size(), 1); 0771 Declaration *d = decs.first(); 0772 compareUses(d, QList<RangeInRevision>() 0773 << RangeInRevision(1, 0, 1, 6) 0774 << RangeInRevision(2, 0, 2, 6) 0775 << RangeInRevision(3, 0, 3, 6) 0776 ); 0777 } 0778 0779 void TestUses::caseInsensitiveMethod() 0780 { 0781 // 0 1 2 3 4 5 6 7 0782 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0783 QByteArray method("<? class asdf{ static function barFoo(){} function fooBar() {} } $a = new asdf;\n" 0784 "$a->fOoBar();\n$a->FOOBAR();\n$a->foobar();\n" 0785 "asdf::barfoo();\nasdf::bArFoo();\nasdf::BARFOO();\n"); 0786 0787 TopDUContext* top = parse(method, DumpNone); 0788 DUChainReleaser releaseTop(top); 0789 DUChainWriteLocker lock(DUChain::lock()); 0790 0791 { 0792 QList<Declaration*> decs = top->childContexts().first()->findDeclarations(QualifiedIdentifier(QStringLiteral("foobar"))); 0793 QCOMPARE(decs.size(), 1); 0794 Declaration *d = decs.first(); 0795 compareUses(d, QList<RangeInRevision>() 0796 << RangeInRevision(1, 4, 1, 10) 0797 << RangeInRevision(2, 4, 2, 10) 0798 << RangeInRevision(3, 4, 3, 10) 0799 ); 0800 } 0801 0802 { 0803 QList<Declaration*> decs = top->childContexts().first()->findDeclarations(QualifiedIdentifier(QStringLiteral("barfoo"))); 0804 QCOMPARE(decs.size(), 1); 0805 Declaration *d = decs.first(); 0806 compareUses(d, QList<RangeInRevision>() 0807 << RangeInRevision(4, 6, 4, 12) 0808 << RangeInRevision(5, 6, 5, 12) 0809 << RangeInRevision(6, 6, 6, 12) 0810 ); 0811 } 0812 } 0813 0814 void TestUses::caseInsensitiveClass() 0815 { 0816 // 0 1 2 3 4 5 6 7 0817 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0818 QByteArray method("<? class asDf{}\n" 0819 "new asdf();\nnew ASDF();\nnew asDF();"); 0820 0821 TopDUContext* top = parse(method, DumpNone); 0822 DUChainReleaser releaseTop(top); 0823 DUChainWriteLocker lock(DUChain::lock()); 0824 0825 QList<Declaration*> decs = top->findLocalDeclarations(Identifier(QStringLiteral("asdf"))); 0826 QCOMPARE(decs.size(), 1); 0827 Declaration *d = decs.first(); 0828 compareUses(d, QList<RangeInRevision>() 0829 << RangeInRevision(1, 4, 1, 8) 0830 << RangeInRevision(2, 4, 2, 8) 0831 << RangeInRevision(3, 4, 3, 8) 0832 ); 0833 } 0834 0835 void TestUses::functionUseBeforeDeclaration() 0836 { 0837 // 0 1 2 3 4 5 6 7 0838 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0839 QByteArray method("<? test(); function test() {}"); 0840 0841 TopDUContext* top = parse(method, DumpNone); 0842 DUChainReleaser releaseTop(top); 0843 DUChainWriteLocker lock(DUChain::lock()); 0844 0845 QVector<Declaration*> decs = top->localDeclarations(); 0846 QCOMPARE(decs.size(), 1); 0847 QCOMPARE(decs.first()->range(), RangeInRevision(0, 20, 0, 24)); 0848 compareUses(decs.first(), RangeInRevision(0, 3, 0, 7)); 0849 } 0850 0851 void TestUses::propertyAndMethodWithSameName() 0852 { 0853 0854 // 0 1 2 3 4 5 6 7 0855 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0856 QByteArray method("<? class a{ function name1(){} public $name1; public $name2; function name2() {} }\n" 0857 "$a = new a;\n" 0858 "$a->name1(); $a->name1;\n" 0859 "$a->name2; $a->name2();"); 0860 0861 TopDUContext* top = parse(method, DumpNone); 0862 DUChainReleaser releaseTop(top); 0863 DUChainWriteLocker lock(DUChain::lock()); 0864 0865 QVector<Declaration*> decs = top->childContexts().first()->localDeclarations(); 0866 QCOMPARE(decs.size(), 4); 0867 0868 // method name1 0869 QVERIFY(decs[0]->identifier().nameEquals(Identifier(u"name1"))); 0870 QVERIFY(decs[0]->isFunctionDeclaration()); 0871 compareUses(decs[0], RangeInRevision(2, 4, 2, 9)); 0872 // property name1 0873 QVERIFY(decs[1]->identifier().nameEquals(Identifier(u"name1"))); 0874 QVERIFY(!decs[1]->isFunctionDeclaration()); 0875 compareUses(decs[1], RangeInRevision(2, 17, 2, 22)); 0876 0877 // property name2 0878 QVERIFY(decs[2]->identifier().nameEquals(Identifier(u"name2"))); 0879 QVERIFY(!decs[2]->isFunctionDeclaration()); 0880 compareUses(decs[2], RangeInRevision(3, 4, 3, 9)); 0881 // method name2 0882 QVERIFY(decs[3]->identifier().nameEquals(Identifier(u"name2"))); 0883 QVERIFY(decs[3]->isFunctionDeclaration()); 0884 compareUses(decs[3], RangeInRevision(3, 15, 3, 20)); 0885 } 0886 0887 void TestUses::nestedMethodCalls() 0888 { 0889 // 0 1 2 3 4 5 6 7 0890 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0891 QByteArray method("<?\n" 0892 "class a{ /** @return a **/ function a(){} }\n" 0893 "class b{ function b(){} }\n" 0894 "$a = new a;\n" 0895 "$b = new b;\n" 0896 "$a->a($b->b());"); 0897 0898 TopDUContext* top = parse(method, DumpNone); 0899 DUChainReleaser releaseTop(top); 0900 DUChainWriteLocker lock(DUChain::lock()); 0901 0902 QVector<Declaration*> topDecs = top->localDeclarations(); 0903 QCOMPARE(topDecs.size(), 4); 0904 0905 // class a 0906 QVERIFY(topDecs[0]->identifier().nameEquals(Identifier(u"a"))); 0907 QVERIFY(dynamic_cast<ClassDeclaration*>(topDecs[0])); 0908 compareUses(topDecs[0], RangeInRevision(3, 9, 3, 10)); 0909 // class b 0910 QVERIFY(topDecs[1]->identifier().nameEquals(Identifier(u"b"))); 0911 QVERIFY(dynamic_cast<ClassDeclaration*>(topDecs[1])); 0912 compareUses(topDecs[1], RangeInRevision(4, 9, 4, 10)); 0913 0914 // $a 0915 QVERIFY(topDecs[2]->identifier().nameEquals(Identifier(u"a"))); 0916 QVERIFY(dynamic_cast<VariableDeclaration*>(topDecs[2])); 0917 compareUses(topDecs[2], RangeInRevision(5, 0, 5, 2)); 0918 // $b 0919 QVERIFY(topDecs[3]->identifier().nameEquals(Identifier(u"b"))); 0920 QVERIFY(dynamic_cast<VariableDeclaration*>(topDecs[3])); 0921 compareUses(topDecs[3], RangeInRevision(5, 6, 5, 8)); 0922 0923 // function a 0924 Declaration* methodADec = topDecs[0]->internalContext()->localDeclarations().first(); 0925 QVERIFY(methodADec->isFunctionDeclaration()); 0926 compareUses(methodADec, RangeInRevision(5, 4, 5, 5)); 0927 0928 // function b 0929 Declaration* methodBDec = topDecs[1]->internalContext()->localDeclarations().first(); 0930 QVERIFY(methodBDec->isFunctionDeclaration()); 0931 compareUses(methodBDec, RangeInRevision(5, 10, 5, 11)); 0932 } 0933 0934 void TestUses::unset() 0935 { 0936 // 0 1 2 3 4 5 6 7 0937 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0938 QByteArray method("<? $a = 1; unset($a);"); 0939 0940 TopDUContext* top = parse(method, DumpAll); 0941 DUChainReleaser releaseTop(top); 0942 DUChainWriteLocker lock(DUChain::lock()); 0943 0944 QVector<Declaration*> decs = top->localDeclarations(); 0945 QCOMPARE(decs.size(), 1); 0946 QCOMPARE(decs.first()->range(), RangeInRevision(0, 3, 0, 5)); 0947 compareUses(decs.first(), RangeInRevision(0, 17, 0, 19)); 0948 } 0949 0950 void TestUses::functionArguments() 0951 { 0952 // 0 1 2 3 4 5 6 7 0953 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0954 QByteArray method("<? function foo($a, &$b) { $a = 0; $b = 2; }"); 0955 0956 TopDUContext* top = parse(method, DumpAll); 0957 DUChainReleaser releaseTop(top); 0958 DUChainWriteLocker lock(DUChain::lock()); 0959 0960 QCOMPARE(top->childContexts().size(), 2); 0961 QCOMPARE(top->childContexts().first()->type(), DUContext::Function); 0962 0963 // $a 0964 Declaration *d = top->childContexts().at(0)->localDeclarations().at(0); 0965 compareUses(d, RangeInRevision(0, 27, 0, 29)); 0966 0967 // $b 0968 d = top->childContexts().at(0)->localDeclarations().at(1); 0969 compareUses(d, RangeInRevision(0, 35, 0, 37)); 0970 } 0971 0972 void TestUses::namespaces() 0973 { 0974 // 0 1 2 3 4 5 6 7 0975 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 0976 TopDUContext* top = parse("<?php\n" 0977 "namespace Foo\\Bar {\n" 0978 "const MyConst = 1;\n" 0979 "$z = MyConst;\n" 0980 "function MyFunc(){}\n" 0981 "class MyClass{ const ClassConst = 2; }\n" 0982 "interface MyInterface{}\n" 0983 "}\n" 0984 "namespace {\n" 0985 "\\Foo\\Bar\\MyConst;\n" 0986 "\\Foo\\Bar\\MyClass::ClassConst;\n" 0987 "\\Foo\\Bar\\MyFunc();\n" 0988 "new \\Foo\\Bar\\MyClass;\n" 0989 "function Func(\\Foo\\Bar\\MyClass $a){}\n" 0990 "class a extends \\Foo\\Bar\\MyClass implements \\Foo\\Bar\\MyInterface {}\n" 0991 "}\n" 0992 "namespace Foo {\n" 0993 "}\n", DumpAll); 0994 QVERIFY(top); 0995 DUChainReleaser releaseTop(top); 0996 DUChainWriteLocker lock; 0997 0998 Declaration* dec; 0999 1000 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo"))).last(); 1001 QCOMPARE(dec->kind(), Declaration::Namespace); 1002 compareUses(dec, QList<RangeInRevision>() 1003 << RangeInRevision(9, 1, 9, 4) 1004 << RangeInRevision(10, 1, 10, 4) 1005 << RangeInRevision(11, 1, 11, 4) 1006 << RangeInRevision(12, 5, 12, 8) 1007 << RangeInRevision(13, 15, 13, 18) 1008 << RangeInRevision(14, 17, 14, 20) 1009 << RangeInRevision(14, 45, 14, 48)); 1010 1011 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar"))).first(); 1012 QCOMPARE(dec->kind(), Declaration::Namespace); 1013 QVERIFY(dec->internalContext()); 1014 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(9, 5, 9, 8) 1015 << RangeInRevision(10, 5, 10, 8) 1016 << RangeInRevision(11, 5, 11, 8) 1017 << RangeInRevision(12, 9, 12, 12) 1018 << RangeInRevision(13, 19, 13, 22) 1019 << RangeInRevision(14, 21, 14, 24) 1020 << RangeInRevision(14, 49, 14, 52)); 1021 QCOMPARE(dec->internalContext()->localDeclarations().size(), 4); 1022 foreach(Declaration* d, dec->internalContext()->localDeclarations()) { 1023 qDebug() << d->toString() << d->qualifiedIdentifier(); 1024 } 1025 1026 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::MyConst"))).first(); 1027 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(3, 5, 3, 12) 1028 << RangeInRevision(9, 9, 9, 16)); 1029 1030 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::myclass"))).first(); 1031 QVERIFY(dynamic_cast<ClassDeclaration*>(dec)); 1032 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(10, 9, 10, 16) 1033 << RangeInRevision(12, 13, 12, 20) 1034 << RangeInRevision(13, 23, 13, 30) 1035 << RangeInRevision(14, 25, 14, 32) 1036 ); 1037 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::myinterface"))).first(); 1038 QVERIFY(dynamic_cast<ClassDeclaration*>(dec)); 1039 compareUses(dec, RangeInRevision(14, 53, 14, 64) ); 1040 1041 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::myclass::ClassConst"))).first(); 1042 compareUses(dec, RangeInRevision(10, 18, 10, 28)); 1043 1044 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::myfunc"))).first(); 1045 compareUses(dec, RangeInRevision(11, 9, 11, 15)); 1046 } 1047 1048 void TestUses::useNamespace() 1049 { 1050 // 0 1 2 3 4 5 6 7 1051 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1052 TopDUContext* top = parse("<?php\n" 1053 "namespace Foo\\Bar {class A{} function B(){} const C = 1;}\n" 1054 "namespace VeryLong {class A{} function B(){} const C = 1;}\n" 1055 "namespace Baz {class A{} const C = 1;}\n" 1056 "namespace {\n" 1057 "use Foo\\Bar, VeryLong as Short;\n" 1058 "use Baz\\A as Bazaar;\n" 1059 "new Bar\\A; Bar\\B(); Bar\\C;\n" 1060 "new Short\\A; Short\\B(); Short\\C;\n" 1061 "new Bazaar;\n" 1062 "}\n", DumpNone); 1063 QVERIFY(top); 1064 DUChainReleaser releaseTop(top); 1065 DUChainWriteLocker lock; 1066 1067 Declaration* dec; 1068 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo"))).first(); 1069 QCOMPARE(dec->kind(), Declaration::Namespace); 1070 compareUses(dec, RangeInRevision(5, 4, 5, 7)); 1071 1072 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar"))).first(); 1073 QCOMPARE(dec->kind(), Declaration::Namespace); 1074 compareUses(dec, RangeInRevision(5, 8, 5, 11)); 1075 1076 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("verylong"))).first(); 1077 QCOMPARE(dec->kind(), Declaration::Namespace); 1078 compareUses(dec, RangeInRevision(5, 13, 5, 21)); 1079 1080 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("bar"))).first(); 1081 QCOMPARE(dec->kind(), Declaration::NamespaceAlias); 1082 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(7, 4, 7, 7) 1083 << RangeInRevision(7, 11, 7, 14) 1084 << RangeInRevision(7, 20, 7, 23) ); 1085 1086 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("short"))).first(); 1087 QCOMPARE(dec->kind(), Declaration::NamespaceAlias); 1088 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(8, 4, 8, 9) 1089 << RangeInRevision(8, 13, 8, 18) 1090 << RangeInRevision(8, 24, 8, 29) ); 1091 1092 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("baz::a"))).first(); 1093 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(6, 8, 6, 9) 1094 << RangeInRevision(9, 4, 9, 10)); 1095 1096 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::a"))).first(); 1097 compareUses(dec, RangeInRevision(7, 8, 7, 9)); 1098 1099 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::b"))).first(); 1100 compareUses(dec, RangeInRevision(7, 15, 7, 16)); 1101 1102 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::C"))).first(); 1103 compareUses(dec, RangeInRevision(7, 24, 7, 25)); 1104 1105 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("verylong::a"))).first(); 1106 compareUses(dec, RangeInRevision(8, 10, 8, 11)); 1107 1108 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("verylong::b"))).first(); 1109 compareUses(dec, RangeInRevision(8, 19, 8, 20)); 1110 1111 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("verylong::C"))).first(); 1112 compareUses(dec, RangeInRevision(8, 30, 8, 31)); 1113 } 1114 1115 1116 void TestUses::useGroupedNamespace() 1117 { 1118 // 0 1 2 3 4 5 6 7 1119 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1120 TopDUContext* top = parse("<?php\n" 1121 "namespace Foo\\Bar { class A{} }\n" 1122 "namespace Foo\\Bar { class D{} }\n" 1123 "namespace {\n" 1124 "use Foo\\Bar\\{A,D};\n" 1125 "}\n", DumpNone); 1126 QVERIFY(top); 1127 DUChainReleaser releaseTop(top); 1128 DUChainWriteLocker lock; 1129 1130 Declaration* dec; 1131 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo"))).first(); 1132 QCOMPARE(dec->kind(), Declaration::Namespace); 1133 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(2, 10, 2, 13) 1134 << RangeInRevision(4, 4, 4, 7) ); 1135 1136 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar"))).first(); 1137 QCOMPARE(dec->kind(), Declaration::Namespace); 1138 compareUses(dec, RangeInRevision(4, 8, 4, 11)); 1139 1140 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::a"))).first(); 1141 compareUses(dec, RangeInRevision(4, 13, 4, 14)); 1142 1143 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::d"))).first(); 1144 compareUses(dec, RangeInRevision(4, 15, 4, 16)); 1145 } 1146 1147 1148 void TestUses::useGroupedPartialNamespace() 1149 { 1150 // 0 1 2 3 4 5 6 7 1151 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1152 TopDUContext* top = parse("<?php\n" 1153 "namespace Foo\\Bar { class A{} }\n" 1154 "namespace Foo\\Baz { class D{} }\n" 1155 "namespace {\n" 1156 "use Foo\\{Bar\\A,Baz\\D};\n" 1157 "}\n", DumpNone); 1158 QVERIFY(top); 1159 DUChainReleaser releaseTop(top); 1160 DUChainWriteLocker lock; 1161 1162 Declaration* dec; 1163 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo"))).first(); 1164 QCOMPARE(dec->kind(), Declaration::Namespace); 1165 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(2, 10, 2, 13) 1166 << RangeInRevision(4, 4, 4, 7) ); 1167 1168 // TODO: Remaining implementation for https://bugs.kde.org/show_bug.cgi?id=411588 1169 // dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar"))).first(); 1170 // QCOMPARE(dec->kind(), Declaration::Namespace); 1171 // compareUses(dec, RangeInRevision(4, 9, 4, 12)); 1172 1173 // dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::baz"))).first(); 1174 // QCOMPARE(dec->kind(), Declaration::Namespace); 1175 // compareUses(dec, RangeInRevision(4, 15, 4, 18)); 1176 1177 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::bar::a"))).first(); 1178 compareUses(dec, RangeInRevision(4, 13, 4, 14)); 1179 1180 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("foo::baz::d"))).first(); 1181 compareUses(dec, RangeInRevision(4, 19, 4, 20)); 1182 } 1183 1184 1185 void TestUses::useNamespaceFunctionConst() 1186 { 1187 // 0 1 2 3 4 5 6 7 1188 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1189 TopDUContext* top = parse("<?php\n" 1190 /* 1*/ "namespace Foo\\Bar {function A(){} const B = 1;}\n" 1191 /* 2*/ "namespace Qux {function F(){} const C = 2;}\n" 1192 /* 3*/ "namespace Baz {function F(){} const C = 3;}\n" 1193 /* 4*/ "namespace {\n" 1194 /* 5*/ "use function Foo\\Bar\\A;\n" 1195 /* 6*/ "use const Foo\\Bar\\B;\n" 1196 /* 7*/ "use function Qux\\F as QuxF, Baz\\F as BazF;\n" 1197 /* 8*/ "use const Qux\\C as QuxC, Baz\\C as BazC;\n" 1198 /* 9*/ "echo A();\n" 1199 /*10*/ "echo B;\n" 1200 /*11*/ "echo QuxF();\n" 1201 /*12*/ "echo QuxC;\n" 1202 /*13*/ "echo BazF();\n" 1203 /*14*/ "echo BazC;\n" 1204 "}\n", DumpNone); 1205 QVERIFY(top); 1206 DUChainReleaser releaseTop(top); 1207 DUChainWriteLocker lock; 1208 1209 Declaration* dec; 1210 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("a"))).first(); 1211 QVERIFY(dec); 1212 QCOMPARE(dec->kind(), Declaration::Type); 1213 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(5, 21, 5, 22) << RangeInRevision(9, 5, 9, 6)); 1214 1215 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("B"))).first(); 1216 QVERIFY(dec); 1217 QCOMPARE(dec->kind(), Declaration::Instance); 1218 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(6, 18, 6, 19) << RangeInRevision(10, 5, 10, 6)); 1219 1220 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("quxf"))).first(); 1221 QVERIFY(dec); 1222 QCOMPARE(dec->kind(), Declaration::Type); 1223 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(7, 17, 7, 18) << RangeInRevision(11, 5, 11, 9)); 1224 1225 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("bazf"))).first(); 1226 QVERIFY(dec); 1227 QCOMPARE(dec->kind(), Declaration::Type); 1228 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(7, 32, 7, 33) << RangeInRevision(13, 5, 13, 9)); 1229 1230 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("QuxC"))).first(); 1231 QVERIFY(dec); 1232 QCOMPARE(dec->kind(), Declaration::Instance); 1233 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(8, 14, 8, 15) << RangeInRevision(12, 5, 12, 9)); 1234 1235 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("BazC"))).first(); 1236 QVERIFY(dec); 1237 QCOMPARE(dec->kind(), Declaration::Instance); 1238 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(8, 29, 8, 30) << RangeInRevision(14, 5, 14, 9)); 1239 } 1240 1241 void TestUses::lateStatic() 1242 { 1243 // 0 1 2 3 4 5 6 7 1244 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1245 TopDUContext* top = parse("<?php class a { function b() { static::b(); } }", DumpAll); 1246 QVERIFY(top); 1247 DUChainReleaser releaseTop(top); 1248 DUChainWriteLocker lock; 1249 1250 compareUses(top->childContexts().first()->localDeclarations().first(), RangeInRevision(0, 39, 0, 40)); 1251 } 1252 1253 void TestUses::closures() 1254 { 1255 // 0 1 2 3 4 5 6 7 1256 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1257 TopDUContext* top = parse("<?php $a = 1; $b = 2;\n" 1258 "$l = function($b) use ($a) { return $a - $b; };\n", DumpNone); 1259 QVERIFY(top); 1260 DUChainReleaser releaseTop(top); 1261 DUChainWriteLocker lock; 1262 1263 QCOMPARE(top->localDeclarations().count(), 4); 1264 1265 Declaration* a = top->localDeclarations().at(0); 1266 QCOMPARE(a->identifier().toString(), QString("a")); 1267 compareUses(a, QList<RangeInRevision>() << RangeInRevision(1, 23, 1, 25) << RangeInRevision(1, 36, 1, 38)); 1268 1269 Declaration* b = top->localDeclarations().at(1); 1270 QCOMPARE(b->identifier().toString(), QString("b")); 1271 QVERIFY(b->uses().isEmpty()); 1272 } 1273 1274 void TestUses::closureTypehints() { 1275 TopDUContext* top = parse("<?php class A {} $b = function (A $a): A {};", DumpNone); 1276 QVERIFY(top); 1277 DUChainReleaser releaseTop(top); 1278 DUChainWriteLocker lock; 1279 1280 QCOMPARE(top->localDeclarations().count(), 3); 1281 Declaration* a = top->localDeclarations().at(0); 1282 QCOMPARE(a->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1283 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 32, 0, 33) << RangeInRevision(0, 39, 0, 40)); 1284 } 1285 1286 void TestUses::instanceof() 1287 { 1288 // 0 1 2 3 4 5 1289 // 012345678901234567890123456789012345678901234567890123456789 1290 TopDUContext* top = parse("<?php class a {}\n" 1291 "$a = new a;\n" 1292 "$b = $a instanceof a;\n", DumpNone); 1293 QVERIFY(top); 1294 DUChainReleaser releaseTop(top); 1295 DUChainWriteLocker lock; 1296 1297 QCOMPARE(top->localDeclarations().count(), 3); 1298 1299 Declaration* a = top->localDeclarations().at(0); 1300 QCOMPARE(a->identifier().toString(), QString("a")); 1301 compareUses(a, QList<RangeInRevision>() 1302 << RangeInRevision(1, 9, 1, 10) 1303 << RangeInRevision(2, 19, 2, 20)); 1304 } 1305 1306 void TestUses::instanceofClassProperty() 1307 { 1308 // 0 1 2 3 4 5 1309 // 012345678901234567890123456789012345678901234567890123456789 1310 TopDUContext* top = parse("<? class A { /** @var B **/ public $foo; }\n" 1311 "class B { /** @var A **/ public $bar; }\n" 1312 "$a = new A(); $a instanceof $a->foo->bar->foo;\n", DumpNone); 1313 1314 QVERIFY(top); 1315 DUChainReleaser releaseTop(top); 1316 DUChainWriteLocker lock; 1317 1318 QVERIFY(top->problems().isEmpty()); 1319 1320 QVERIFY(!top->parentContext()); 1321 QCOMPARE(top->childContexts().count(), 2); 1322 QCOMPARE(top->localDeclarations().count(), 3); 1323 1324 Declaration* dec = top->localDeclarations().at(0); 1325 QCOMPARE(dec->identifier(), Identifier(u"a")); 1326 compareUses(dec, QList<RangeInRevision>() 1327 << RangeInRevision(2, 9, 2, 10)); 1328 1329 dec = top->localDeclarations().at(2); 1330 QCOMPARE(dec->identifier(), Identifier(u"a")); 1331 StructureType::Ptr classType = dec->type<StructureType>(); 1332 QVERIFY(classType); 1333 QCOMPARE(classType->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1334 QVERIFY(classType->equals(dec->abstractType().data())); 1335 compareUses(dec, QList<RangeInRevision>() 1336 << RangeInRevision(2, 14, 2, 16) 1337 << RangeInRevision(2, 28, 2, 30)); 1338 1339 dec = top->childContexts().at(0)->localDeclarations().at(0); 1340 QVERIFY(dec); 1341 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1342 compareUses(dec, QList<RangeInRevision>() 1343 << RangeInRevision(2, 32, 2, 35) 1344 << RangeInRevision(2, 42, 2, 45)); 1345 1346 dec = top->childContexts().at(1)->localDeclarations().at(0); 1347 QVERIFY(dec); 1348 QCOMPARE(dec->identifier(), Identifier(u"bar")); 1349 compareUses(dec, QList<RangeInRevision>() 1350 << RangeInRevision(2, 37, 2, 40)); 1351 } 1352 1353 void TestUses::instanceofStaticProperty() 1354 { 1355 // 0 1 2 3 4 5 1356 // 012345678901234567890123456789012345678901234567890123456789 1357 TopDUContext* top = parse("<? class A { /** @var B **/ public static $foo; }\n" 1358 "class B { /** @var A **/ public static $bar; }\n" 1359 "$a = new A(); $a instanceof A::$foo::$bar::$foo;\n", DumpNone); 1360 1361 QVERIFY(top); 1362 DUChainReleaser releaseTop(top); 1363 DUChainWriteLocker lock; 1364 1365 QVERIFY(top->problems().isEmpty()); 1366 1367 QVERIFY(!top->parentContext()); 1368 QCOMPARE(top->childContexts().count(), 2); 1369 QCOMPARE(top->localDeclarations().count(), 3); 1370 1371 Declaration* dec = top->localDeclarations().at(0); 1372 QCOMPARE(dec->identifier(), Identifier(u"a")); 1373 compareUses(dec, QList<RangeInRevision>() 1374 << RangeInRevision(2, 9, 2, 10) 1375 << RangeInRevision(2, 28, 2, 29)); 1376 1377 dec = top->localDeclarations().at(2); 1378 QCOMPARE(dec->identifier(), Identifier(u"a")); 1379 StructureType::Ptr classType = dec->type<StructureType>(); 1380 QVERIFY(classType); 1381 QCOMPARE(classType->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1382 QVERIFY(classType->equals(dec->abstractType().data())); 1383 compareUses(dec, QList<RangeInRevision>() 1384 << RangeInRevision(2, 14, 2, 16)); 1385 1386 dec = top->childContexts().at(0)->localDeclarations().at(0); 1387 QVERIFY(dec); 1388 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1389 compareUses(dec, QList<RangeInRevision>() 1390 << RangeInRevision(2, 31, 2, 35) 1391 << RangeInRevision(2, 43, 2, 47)); 1392 1393 dec = top->childContexts().at(1)->localDeclarations().at(0); 1394 QVERIFY(dec); 1395 QCOMPARE(dec->identifier(), Identifier(u"bar")); 1396 compareUses(dec, QList<RangeInRevision>() 1397 << RangeInRevision(2, 37, 2, 41)); 1398 } 1399 1400 void TestUses::instanceofMixedProperty() 1401 { 1402 // 0 1 2 3 4 5 1403 // 012345678901234567890123456789012345678901234567890123456789 1404 TopDUContext* top = parse("<? class A { /** @var B **/ public static $foo; }\n" 1405 "class B { /** @var A **/ public $bar; }\n" 1406 "$a = new A(); $a instanceof A::$foo->bar::$foo;\n", DumpNone); 1407 1408 QVERIFY(top); 1409 DUChainReleaser releaseTop(top); 1410 DUChainWriteLocker lock; 1411 1412 QVERIFY(top->problems().isEmpty()); 1413 1414 QVERIFY(!top->parentContext()); 1415 QCOMPARE(top->childContexts().count(), 2); 1416 QCOMPARE(top->localDeclarations().count(), 3); 1417 1418 Declaration* dec = top->localDeclarations().at(0); 1419 QCOMPARE(dec->identifier(), Identifier(u"a")); 1420 compareUses(dec, QList<RangeInRevision>() 1421 << RangeInRevision(2, 9, 2, 10) 1422 << RangeInRevision(2, 28, 2, 29)); 1423 1424 dec = top->localDeclarations().at(2); 1425 QCOMPARE(dec->identifier(), Identifier(u"a")); 1426 StructureType::Ptr classType = dec->type<StructureType>(); 1427 QVERIFY(classType); 1428 QCOMPARE(classType->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1429 QVERIFY(classType->equals(dec->abstractType().data())); 1430 compareUses(dec, QList<RangeInRevision>() 1431 << RangeInRevision(2, 14, 2, 16)); 1432 1433 dec = top->childContexts().at(0)->localDeclarations().at(0); 1434 QVERIFY(dec); 1435 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1436 compareUses(dec, QList<RangeInRevision>() 1437 << RangeInRevision(2, 31, 2, 35) 1438 << RangeInRevision(2, 42, 2, 46)); 1439 1440 dec = top->childContexts().at(1)->localDeclarations().at(0); 1441 QVERIFY(dec); 1442 QCOMPARE(dec->identifier(), Identifier(u"bar")); 1443 compareUses(dec, QList<RangeInRevision>() 1444 << RangeInRevision(2, 37, 2, 40)); 1445 } 1446 1447 void TestUses::instanceofVariableProperty() 1448 { 1449 // 0 1 2 3 4 5 1450 // 012345678901234567890123456789012345678901234567890123456789 1451 TopDUContext* top = parse("<? class A { /** @var B **/ public $foo; }\n" 1452 "class B { /** @var A **/ public $bar; }\n" 1453 "$foo = 'foo'; $bar = 'bar';\n" 1454 "$a = new A(); $a instanceof $a->$foo->$bar->$foo;\n", DumpNone); 1455 1456 QVERIFY(top); 1457 DUChainReleaser releaseTop(top); 1458 DUChainWriteLocker lock; 1459 1460 QVERIFY(top->problems().isEmpty()); 1461 1462 QVERIFY(!top->parentContext()); 1463 QCOMPARE(top->childContexts().count(), 2); 1464 QCOMPARE(top->localDeclarations().count(), 5); 1465 1466 Declaration* dec = top->localDeclarations().at(0); 1467 QCOMPARE(dec->identifier(), Identifier(u"a")); 1468 compareUses(dec, QList<RangeInRevision>() 1469 << RangeInRevision(3, 9, 3, 10)); 1470 1471 dec = top->localDeclarations().at(4); 1472 QCOMPARE(dec->identifier(), Identifier(u"a")); 1473 StructureType::Ptr classType = dec->type<StructureType>(); 1474 QVERIFY(classType); 1475 QCOMPARE(classType->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1476 QVERIFY(classType->equals(dec->abstractType().data())); 1477 compareUses(dec, QList<RangeInRevision>() 1478 << RangeInRevision(3, 14, 3, 16) 1479 << RangeInRevision(3, 28, 3, 30)); 1480 1481 dec = top->localDeclarations().at(2); 1482 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1483 compareUses(dec, QList<RangeInRevision>() 1484 << RangeInRevision(3, 32, 3, 36) 1485 << RangeInRevision(3, 44, 3, 48)); 1486 1487 dec = top->localDeclarations().at(3); 1488 QCOMPARE(dec->identifier(), Identifier(u"bar")); 1489 compareUses(dec, QList<RangeInRevision>() 1490 << RangeInRevision(3, 38, 3, 42)); 1491 } 1492 1493 void TestUses::instanceofDynamicStaticProperty() 1494 { 1495 // 0 1 2 3 4 5 1496 // 012345678901234567890123456789012345678901234567890123456789 1497 TopDUContext* top = parse("<? class A { /** @var B **/ public $foo; }\n" 1498 "class B { /** @var A **/ public $bar; }\n" 1499 "$foo = 'foo'; $bar = 'bar';\n" 1500 "$a = new A(); $a instanceof $a::${$foo}::${$bar}::${$foo};\n", DumpNone); 1501 1502 QVERIFY(top); 1503 DUChainReleaser releaseTop(top); 1504 DUChainWriteLocker lock; 1505 1506 QVERIFY(top->problems().isEmpty()); 1507 1508 QVERIFY(!top->parentContext()); 1509 QCOMPARE(top->childContexts().count(), 2); 1510 QCOMPARE(top->localDeclarations().count(), 5); 1511 1512 Declaration* dec = top->localDeclarations().at(0); 1513 QCOMPARE(dec->identifier(), Identifier(u"a")); 1514 compareUses(dec, QList<RangeInRevision>() 1515 << RangeInRevision(3, 9, 3, 10)); 1516 1517 dec = top->localDeclarations().at(4); 1518 QCOMPARE(dec->identifier(), Identifier(u"a")); 1519 StructureType::Ptr classType = dec->type<StructureType>(); 1520 QVERIFY(classType); 1521 QCOMPARE(classType->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1522 QVERIFY(classType->equals(dec->abstractType().data())); 1523 compareUses(dec, QList<RangeInRevision>() 1524 << RangeInRevision(3, 14, 3, 16) 1525 << RangeInRevision(3, 28, 3, 30)); 1526 1527 dec = top->localDeclarations().at(2); 1528 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1529 compareUses(dec, QList<RangeInRevision>() 1530 << RangeInRevision(3, 34, 3, 38) 1531 << RangeInRevision(3, 52, 3, 56)); 1532 1533 dec = top->localDeclarations().at(3); 1534 QCOMPARE(dec->identifier(), Identifier(u"bar")); 1535 compareUses(dec, QList<RangeInRevision>() 1536 << RangeInRevision(3, 43, 3, 47)); 1537 } 1538 1539 void TestUses::instanceofDynamicVariableProperty() 1540 { 1541 // 0 1 2 3 4 5 1542 // 012345678901234567890123456789012345678901234567890123456789 1543 TopDUContext* top = parse("<? class A { /** @var B **/ public $foo; }\n" 1544 "class B { /** @var A **/ public $bar; }\n" 1545 "$foo = 'foo'; $bar = 'bar';\n" 1546 "$a = new A(); $a instanceof $a->${$foo}->${$bar}->${$foo};\n", DumpNone); 1547 1548 QVERIFY(top); 1549 DUChainReleaser releaseTop(top); 1550 DUChainWriteLocker lock; 1551 1552 QVERIFY(top->problems().isEmpty()); 1553 1554 QVERIFY(!top->parentContext()); 1555 QCOMPARE(top->childContexts().count(), 2); 1556 QCOMPARE(top->localDeclarations().count(), 5); 1557 1558 Declaration* dec = top->localDeclarations().at(0); 1559 QCOMPARE(dec->identifier(), Identifier(u"a")); 1560 compareUses(dec, QList<RangeInRevision>() 1561 << RangeInRevision(3, 9, 3, 10)); 1562 1563 dec = top->localDeclarations().at(4); 1564 QCOMPARE(dec->identifier(), Identifier(u"a")); 1565 StructureType::Ptr classType = dec->type<StructureType>(); 1566 QVERIFY(classType); 1567 QCOMPARE(classType->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1568 QVERIFY(classType->equals(dec->abstractType().data())); 1569 compareUses(dec, QList<RangeInRevision>() 1570 << RangeInRevision(3, 14, 3, 16) 1571 << RangeInRevision(3, 28, 3, 30)); 1572 1573 dec = top->localDeclarations().at(2); 1574 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1575 compareUses(dec, QList<RangeInRevision>() 1576 << RangeInRevision(3, 34, 3, 38) 1577 << RangeInRevision(3, 52, 3, 56)); 1578 1579 dec = top->localDeclarations().at(3); 1580 QCOMPARE(dec->identifier(), Identifier(u"bar")); 1581 compareUses(dec, QList<RangeInRevision>() 1582 << RangeInRevision(3, 43, 3, 47)); 1583 } 1584 1585 void TestUses::instanceofPropertyArrayAccess() 1586 { 1587 // 0 1 2 3 4 5 1588 // 012345678901234567890123456789012345678901234567890123456789 1589 TopDUContext* top = parse("<? class A { /** @var array **/ public $foo; }\n" 1590 "class B { /** @var array **/ public static $bar; }\n" 1591 "$a = new A(); $a instanceof $a->foo[0]::$bar[0]->foo;\n", DumpNone); 1592 1593 QVERIFY(top); 1594 DUChainReleaser releaseTop(top); 1595 DUChainWriteLocker lock; 1596 1597 QVERIFY(top->problems().isEmpty()); 1598 1599 QVERIFY(!top->parentContext()); 1600 QCOMPARE(top->childContexts().count(), 2); 1601 QCOMPARE(top->localDeclarations().count(), 3); 1602 1603 Declaration* dec = top->localDeclarations().at(0); 1604 QCOMPARE(dec->identifier(), Identifier(u"a")); 1605 compareUses(dec, QList<RangeInRevision>() 1606 << RangeInRevision(2, 9, 2, 10)); 1607 1608 dec = top->localDeclarations().at(2); 1609 QCOMPARE(dec->identifier(), Identifier(u"a")); 1610 StructureType::Ptr classType = dec->type<StructureType>(); 1611 QVERIFY(classType); 1612 QCOMPARE(classType->qualifiedIdentifier(), QualifiedIdentifier(u"a")); 1613 QVERIFY(classType->equals(dec->abstractType().data())); 1614 compareUses(dec, QList<RangeInRevision>() 1615 << RangeInRevision(2, 14, 2, 16) 1616 << RangeInRevision(2, 28, 2, 30)); 1617 1618 dec = top->childContexts().at(0)->localDeclarations().at(0); 1619 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1620 compareUses(dec, QList<RangeInRevision>() 1621 << RangeInRevision(2, 32, 2, 35)); 1622 1623 dec = top->childContexts().at(1)->localDeclarations().at(0); 1624 QCOMPARE(dec->identifier(), Identifier(u"bar")); 1625 QVERIFY(dec->uses().isEmpty()); 1626 } 1627 1628 void TestUses::dimListAfterClassNameReference() 1629 { 1630 // 0 1 2 3 4 5 1631 // 012345678901234567890123456789012345678901234567890123456789 1632 TopDUContext* top = parse("<? class A { /** @var array **/ public $foo;\n" 1633 "public function bar() { $object = new $this->foo[$index]; }\n" 1634 "}\n", DumpNone); 1635 1636 QVERIFY(top); 1637 DUChainReleaser releaseTop(top); 1638 DUChainWriteLocker lock; 1639 1640 QVERIFY(top->problems().isEmpty()); 1641 1642 QVERIFY(!top->parentContext()); 1643 QCOMPARE(top->childContexts().count(), 1); 1644 QCOMPARE(top->localDeclarations().count(), 1); 1645 1646 Declaration* dec = top->localDeclarations().at(0); 1647 QCOMPARE(dec->identifier(), Identifier(u"a")); 1648 compareUses(dec, QList<RangeInRevision>() 1649 << RangeInRevision(1, 38, 1, 43)); 1650 1651 QCOMPARE(top->childContexts().at(0)->localDeclarations().count(), 2); 1652 QCOMPARE(top->childContexts().at(0)->childContexts().count(), 2); 1653 QCOMPARE(top->childContexts().at(0)->childContexts().at(1)->localDeclarations().count(), 1); 1654 1655 dec = top->childContexts().at(0)->localDeclarations().at(0); 1656 QCOMPARE(dec->identifier(), Identifier(u"foo")); 1657 compareUses(dec, QList<RangeInRevision>() 1658 << RangeInRevision(1, 45, 1, 48)); 1659 } 1660 1661 void TestUses::classNameString() 1662 { 1663 // 0 1 2 3 4 5 6 7 1664 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1665 QByteArray method("<? class Foo { } echo 'Foo';"); 1666 TopDUContext* top = parse(method, DumpNone); 1667 DUChainReleaser releaseTop(top); 1668 DUChainWriteLocker lock(DUChain::lock()); 1669 1670 1671 Declaration* foo = top->localDeclarations().at(0); 1672 QCOMPARE(foo->identifier().toString(), QString("foo")); 1673 compareUses(foo, RangeInRevision(0, 22, 0, 27)); 1674 } 1675 1676 void TestUses::useTrait() 1677 { 1678 // 0 1 2 3 4 5 6 7 8 1679 // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 1680 TopDUContext* top = parse("<?php\n" 1681 "trait A { public function one(){} public function two(){} }\n" 1682 "trait B { public function one(){} private function three(){} }\n" 1683 "trait C { public $baz; public function one(){} public static function five(){} }\n" 1684 "class Foo { use A;}\n" 1685 "class Bar { use A,B { A::one insteadof B; B::three as public four; } }\n" 1686 "class Baz { use A,B,C { C::one insteadof A,B; C::five as six; } }\n" 1687 "class Boo { use A,B,C { A::one insteadof B,C; A::two as switch; B::three as public; C::five as public static; } }\n" 1688 "$a = new Foo(); $a->one(); $a->two();\n" 1689 "$b = new Bar(); $b->one(); $b->two(); $b->four();\n" 1690 "$c = new Baz(); $c->one(); $c->two(); $c->baz; $c::six();\n" 1691 "$d = new Boo(); $d->one(); $d->switch(); $d->three(); $d->static();\n", DumpAll); 1692 QVERIFY(top); 1693 DUChainReleaser releaseTop(top); 1694 DUChainWriteLocker lock; 1695 1696 Declaration* dec; 1697 QVector<Declaration*> topDecs = top->localDeclarations(); 1698 TraitMethodAliasDeclaration* method; 1699 TraitMemberAliasDeclaration* member; 1700 1701 QCOMPARE(topDecs.size(), 11); 1702 1703 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("a"))).first(); 1704 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(4, 16, 4, 17) 1705 << RangeInRevision(5, 16, 5, 17) 1706 << RangeInRevision(5, 22, 5, 23) 1707 << RangeInRevision(6, 16, 6, 17) 1708 << RangeInRevision(6, 41, 6, 42) 1709 << RangeInRevision(7, 16, 7, 17) 1710 << RangeInRevision(7, 24, 7, 25) 1711 << RangeInRevision(7, 46, 7, 47) ); 1712 1713 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("b"))).first(); 1714 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(5, 18, 5, 19) 1715 << RangeInRevision(5, 39, 5, 40) 1716 << RangeInRevision(5, 42, 5, 43) 1717 << RangeInRevision(6, 18, 6, 19) 1718 << RangeInRevision(6, 43, 6, 44) 1719 << RangeInRevision(7, 18, 7, 19) 1720 << RangeInRevision(7, 41, 7, 42) 1721 << RangeInRevision(7, 64, 7, 65) ); 1722 1723 dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("c"))).first(); 1724 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(6, 20, 6, 21) 1725 << RangeInRevision(6, 24, 6, 25) 1726 << RangeInRevision(6, 46, 6, 47) 1727 << RangeInRevision(7, 20, 7, 21) 1728 << RangeInRevision(7, 43, 7, 44) 1729 << RangeInRevision(7, 84, 7, 85) ); 1730 1731 dec = topDecs[3]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("one"))).first(); 1732 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1733 QVERIFY(method); 1734 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"a")); 1735 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(8, 20, 8, 23) ); 1736 1737 dec = topDecs[3]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("two"))).first(); 1738 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1739 QVERIFY(method); 1740 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"a")); 1741 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(8, 31, 8, 34) ); 1742 1743 dec = topDecs[4]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("one"))).first(); 1744 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1745 QVERIFY(method); 1746 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"a")); 1747 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(9, 20, 9, 23) ); 1748 1749 dec = topDecs[4]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("two"))).first(); 1750 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1751 QVERIFY(method); 1752 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"a")); 1753 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(9, 31, 9, 34) ); 1754 1755 dec = topDecs[4]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("four"))).first(); 1756 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1757 QVERIFY(method); 1758 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"b")); 1759 QCOMPARE(method->aliasedDeclaration().data()->identifier(), Identifier(u"three")); 1760 QCOMPARE(method->accessPolicy(), Declaration::AccessPolicy::Public); 1761 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(9, 42, 9, 46) ); 1762 1763 dec = topDecs[5]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("one"))).first(); 1764 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1765 QVERIFY(method); 1766 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"c")); 1767 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(10, 20, 10, 23) ); 1768 1769 dec = topDecs[5]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("two"))).first(); 1770 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1771 QVERIFY(method); 1772 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"a")); 1773 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(10, 31, 10, 34) ); 1774 1775 dec = topDecs[5]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("baz"))).first(); 1776 member = dynamic_cast<TraitMemberAliasDeclaration*>(dec); 1777 QVERIFY(member); 1778 QCOMPARE(member->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"c")); 1779 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(10, 42, 10, 45) ); 1780 1781 dec = topDecs[5]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("six"))).first(); 1782 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1783 QVERIFY(method); 1784 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"c")); 1785 QCOMPARE(method->aliasedDeclaration().data()->identifier(), Identifier(u"five")); 1786 QVERIFY(method->isStatic()); 1787 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(10, 51, 10, 54) ); 1788 1789 dec = topDecs[6]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("one"))).first(); 1790 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1791 QVERIFY(method); 1792 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"a")); 1793 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(11, 20, 11, 23) ); 1794 1795 dec = topDecs[6]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("switch"))).first(); 1796 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1797 QVERIFY(method); 1798 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"a")); 1799 QCOMPARE(method->aliasedDeclaration().data()->identifier(), Identifier(u"two")); 1800 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(11, 31, 11, 37) ); 1801 1802 dec = topDecs[6]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("three"))).first(); 1803 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1804 QVERIFY(method); 1805 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"b")); 1806 QCOMPARE(method->aliasedDeclaration().data()->identifier(), Identifier(u"three")); 1807 QCOMPARE(method->accessPolicy(), Declaration::AccessPolicy::Public); 1808 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(11, 45, 11, 50) ); 1809 1810 dec = topDecs[6]->internalContext()->findLocalDeclarations(Identifier(QStringLiteral("static"))).first(); 1811 method = dynamic_cast<TraitMethodAliasDeclaration*>(dec); 1812 QVERIFY(method); 1813 QCOMPARE(method->aliasedDeclaration().data()->context()->owner()->identifier(), Identifier(u"c")); 1814 QCOMPARE(method->aliasedDeclaration().data()->identifier(), Identifier(u"five")); 1815 compareUses(dec, QList<RangeInRevision>() << RangeInRevision(11, 58, 11, 64) ); 1816 } 1817 1818 void TestUses::exceptionFinally() 1819 { 1820 // 0 1 2 3 4 1821 // 01234567890123456789012345678901234567890123456 1822 QByteArray method("<? $a = 0; try { $a = 2; } finally { $a = 3; }"); 1823 TopDUContext *top = parse(method, DumpNone); 1824 DUChainReleaser releaseTop(top); 1825 DUChainWriteLocker lock(DUChain::lock()); 1826 1827 Declaration *a = top->localDeclarations().at(0); 1828 QCOMPARE(a->identifier().toString(), QString("a")); 1829 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 17, 0, 19) 1830 << RangeInRevision(0, 37, 0, 39)); 1831 } 1832 1833 void TestUses::returnTypeClassFunction() { 1834 QByteArray method("<? class A { function foo(): A {} function bar(): self {} }"); 1835 TopDUContext *top = parse(method, DumpNone); 1836 DUChainReleaser releaseTop(top); 1837 DUChainWriteLocker lock(DUChain::lock()); 1838 1839 Declaration *a = top->localDeclarations().at(0); 1840 QCOMPARE(a->identifier().toString(), QString("a")); 1841 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 29, 0, 30) << RangeInRevision(0, 50, 0, 54)); 1842 } 1843 1844 void TestUses::returnTypeFunction() { 1845 QByteArray method("<? class A {} function foo(): A {}"); 1846 TopDUContext *top = parse(method, DumpNone); 1847 DUChainReleaser releaseTop(top); 1848 DUChainWriteLocker lock(DUChain::lock()); 1849 1850 Declaration *a = top->localDeclarations().at(0); 1851 QCOMPARE(a->identifier().toString(), QString("a")); 1852 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 30, 0, 31)); 1853 } 1854 1855 void TestUses::defaultValue() { 1856 QByteArray method("<? class A {const C = 1;} function foo($a = A::C) {}"); 1857 TopDUContext *top = parse(method, DumpNone); 1858 DUChainReleaser releaseTop(top); 1859 DUChainWriteLocker lock(DUChain::lock()); 1860 1861 Declaration *a = top->localDeclarations().at(0); 1862 QCOMPARE(a->identifier().toString(), QString("a")); 1863 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 44, 0, 45)); 1864 1865 Declaration *c = top->childContexts().at(0)->localDeclarations().at(0); 1866 QCOMPARE(c->identifier().toString(), QString("C")); 1867 compareUses(c, QList<RangeInRevision>() << RangeInRevision(0, 47, 0, 48)); 1868 } 1869 1870 void TestUses::propertyType() { 1871 // 0 1 2 3 4 1872 // 01234567890123456789012345678901234567890123456 1873 QByteArray method("<? class A { public A $foo; }"); 1874 TopDUContext *top = parse(method, DumpNone); 1875 DUChainReleaser releaseTop(top); 1876 DUChainWriteLocker lock(DUChain::lock()); 1877 1878 Declaration *a = top->localDeclarations().at(0); 1879 QCOMPARE(a->identifier().toString(), QString("a")); 1880 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 20, 0, 21)); 1881 } 1882 1883 void TestUses::functionParameterUnionType() { 1884 // 0 1 2 3 4 5 6 1885 // 0123456789012345678901234567890123456789012345678901234567890 1886 QByteArray method("<? class A {} class B {} class C {} function foo(A|B|C $a) {}"); 1887 TopDUContext *top = parse(method, DumpNone); 1888 DUChainReleaser releaseTop(top); 1889 DUChainWriteLocker lock(DUChain::lock()); 1890 1891 Declaration *a = top->localDeclarations().at(0); 1892 QCOMPARE(a->identifier().toString(), QString("a")); 1893 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 49, 0, 50)); 1894 1895 Declaration *b = top->localDeclarations().at(1); 1896 QCOMPARE(b->identifier().toString(), QString("b")); 1897 compareUses(b, QList<RangeInRevision>() << RangeInRevision(0, 51, 0, 52)); 1898 1899 Declaration *c = top->localDeclarations().at(2); 1900 QCOMPARE(c->identifier().toString(), QString("c")); 1901 compareUses(c, QList<RangeInRevision>() << RangeInRevision(0, 53, 0, 54)); 1902 } 1903 1904 void TestUses::functionReturnUnionType() { 1905 // 0 1 2 3 4 5 6 1906 // 0123456789012345678901234567890123456789012345678901234567890 1907 QByteArray method("<? class A {} class B {} class C {} function foo(): A|B|C {}"); 1908 TopDUContext *top = parse(method, DumpNone); 1909 DUChainReleaser releaseTop(top); 1910 DUChainWriteLocker lock(DUChain::lock()); 1911 1912 Declaration *a = top->localDeclarations().at(0); 1913 QCOMPARE(a->identifier().toString(), QString("a")); 1914 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 52, 0, 53)); 1915 1916 Declaration *b = top->localDeclarations().at(1); 1917 QCOMPARE(b->identifier().toString(), QString("b")); 1918 compareUses(b, QList<RangeInRevision>() << RangeInRevision(0, 54, 0, 55)); 1919 1920 Declaration *c = top->localDeclarations().at(2); 1921 QCOMPARE(c->identifier().toString(), QString("c")); 1922 compareUses(c, QList<RangeInRevision>() << RangeInRevision(0, 56, 0, 57)); 1923 } 1924 1925 void TestUses::closureParameterUnionType() { 1926 // 0 1 2 3 4 5 6 1927 // 0123456789012345678901234567890123456789012345678901234567890 1928 QByteArray method("<? class A {} class B {} class C {} $a = function (A|B|C $a) {};"); 1929 TopDUContext *top = parse(method, DumpNone); 1930 DUChainReleaser releaseTop(top); 1931 DUChainWriteLocker lock(DUChain::lock()); 1932 1933 Declaration *a = top->localDeclarations().at(0); 1934 QCOMPARE(a->identifier().toString(), QString("a")); 1935 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 51, 0, 52)); 1936 1937 Declaration *b = top->localDeclarations().at(1); 1938 QCOMPARE(b->identifier().toString(), QString("b")); 1939 compareUses(b, QList<RangeInRevision>() << RangeInRevision(0, 53, 0, 54)); 1940 1941 Declaration *c = top->localDeclarations().at(2); 1942 QCOMPARE(c->identifier().toString(), QString("c")); 1943 compareUses(c, QList<RangeInRevision>() << RangeInRevision(0, 55, 0, 56)); 1944 } 1945 1946 void TestUses::closureReturnUnionType() { 1947 // 0 1 2 3 4 5 6 1948 // 0123456789012345678901234567890123456789012345678901234567890 1949 QByteArray method("<? class A {} class B {} class C {} $a = function (): A|B|C {};"); 1950 TopDUContext *top = parse(method, DumpNone); 1951 DUChainReleaser releaseTop(top); 1952 DUChainWriteLocker lock(DUChain::lock()); 1953 1954 Declaration *a = top->localDeclarations().at(0); 1955 QCOMPARE(a->identifier().toString(), QString("a")); 1956 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 54, 0, 55)); 1957 1958 Declaration *b = top->localDeclarations().at(1); 1959 QCOMPARE(b->identifier().toString(), QString("b")); 1960 compareUses(b, QList<RangeInRevision>() << RangeInRevision(0, 56, 0, 57)); 1961 1962 Declaration *c = top->localDeclarations().at(2); 1963 QCOMPARE(c->identifier().toString(), QString("c")); 1964 compareUses(c, QList<RangeInRevision>() << RangeInRevision(0, 58, 0, 59)); 1965 } 1966 1967 void TestUses::propertyUnionType() { 1968 // 0 1 2 3 4 5 6 1969 // 01234567890123456789012345678901234567890123456789012345678901234567 1970 QByteArray method("<? class A {} class B {} class C {} class D { public A|B|C $foo; }"); 1971 TopDUContext *top = parse(method, DumpNone); 1972 DUChainReleaser releaseTop(top); 1973 DUChainWriteLocker lock(DUChain::lock()); 1974 1975 Declaration *a = top->localDeclarations().at(0); 1976 QCOMPARE(a->identifier().toString(), QString("a")); 1977 compareUses(a, QList<RangeInRevision>() << RangeInRevision(0, 53, 0, 54)); 1978 1979 Declaration *b = top->localDeclarations().at(1); 1980 QCOMPARE(b->identifier().toString(), QString("b")); 1981 compareUses(b, QList<RangeInRevision>() << RangeInRevision(0, 55, 0, 56)); 1982 1983 Declaration *c = top->localDeclarations().at(2); 1984 QCOMPARE(c->identifier().toString(), QString("c")); 1985 compareUses(c, QList<RangeInRevision>() << RangeInRevision(0, 57, 0, 58)); 1986 } 1987 1988 1989 } 1990 1991 #include "moc_uses.cpp"