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"