adapt to kdevplatform changes, use DeclarationPointer when the duchain might get...
[kdevelop:php.git] / duchain / builders / declarationbuilder.cpp
1 /***************************************************************************
2  *   This file is part of KDevelop                                         *
3  *   Copyright 2008 Niko Sams <niko.sams@gmail.com>                        *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Library General Public License as       *
7  *   published by the Free Software Foundation; either version 2 of the    *
8  *   License, or (at your option) any later version.                       *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU Library General Public     *
16  *   License along with this program; if not, write to the                 *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "declarationbuilder.h"
22 #include "predeclarationbuilder.h"
23
24 #include <QByteArray>
25
26 #include <language/duchain/stringhelpers.h>
27 #include <language/duchain/aliasdeclaration.h>
28 #include <language/duchain/types/integraltype.h>
29 #include <language/duchain/types/unsuretype.h>
30
31 #include <interfaces/icore.h>
32 #include <interfaces/ilanguagecontroller.h>
33 #include <interfaces/icompletionsettings.h>
34
35 #include <klocalizedstring.h>
36
37 #include "phpast.h"
38 #include "parsesession.h"
39 #include "helper.h"
40 #include "../declarations/variabledeclaration.h"
41 #include "../declarations/classmethoddeclaration.h"
42 #include "../declarations/classdeclaration.h"
43 #include "../declarations/functiondeclaration.h"
44 #include "../declarations/namespacedeclaration.h"
45 #include "../declarations/namespacealiasdeclaration.h"
46 #include "expressionvisitor.h"
47
48 using namespace KDevelop;
49
50 namespace Php
51 {
52
53 void DeclarationBuilder::getVariableIdentifier(VariableAst* node,
54                                                 QualifiedIdentifier &identifier,
55                                                 QualifiedIdentifier &parent,
56                                                 AstNode* &targetNode,
57                                                 bool &arrayAccess)
58 {
59     parent = QualifiedIdentifier();
60     if ( node->variablePropertiesSequence ) {
61         // at least one "->" in the assigment target
62         // => find he parent of the target
63         // => find the target (last object property)
64         if ( node->variablePropertiesSequence->count() == 1 ) {
65             // $parent->target
66             ///TODO: $parent[0]->target = ... (we don't know the type of [0] yet, need proper array handling first)
67             if ( node->var && node->var->baseVariable && node->var->baseVariable->var
68                 && !node->var->baseVariable->offsetItemsSequence ) {
69                 parent = identifierForNode(
70                     node->var->baseVariable->var->variable
71                 );
72             }
73         } else {
74             // $var->...->parent->target
75             ///TODO: $var->...->parent[0]->target = ... (we don't know the type of [0] yet, need proper array handling first)
76             const KDevPG::ListNode< VariablePropertyAst* >* parentNode = node->variablePropertiesSequence->at(
77                 node->variablePropertiesSequence->count() - 2
78             );
79             if ( parentNode->element && parentNode->element->objectProperty
80                 && parentNode->element->objectProperty->objectDimList
81                 && parentNode->element->objectProperty->objectDimList->variableName
82                 && !parentNode->element->objectProperty->objectDimList->offsetItemsSequence ) {
83                 parent = identifierForNode(
84                     parentNode->element->objectProperty->objectDimList->variableName->name
85                 );
86             }
87         }
88
89         if ( !parent.isEmpty() ) {
90             const KDevPG::ListNode< VariablePropertyAst* >* tNode = node->variablePropertiesSequence->at(
91                 node->variablePropertiesSequence->count() - 1
92             );
93             if ( tNode->element && tNode->element->objectProperty
94                 && tNode->element->objectProperty->objectDimList
95                 && tNode->element->objectProperty->objectDimList->variableName ) {
96                 arrayAccess = (bool) tNode->element->objectProperty->objectDimList->offsetItemsSequence;
97                 identifier = identifierForNode(
98                     tNode->element->objectProperty->objectDimList->variableName->name
99                 );
100                 targetNode = tNode->element->objectProperty->objectDimList->variableName->name;
101             }
102         }
103     } else {
104         // simple assignment to $var
105         if ( node->var && node->var->baseVariable && node->var->baseVariable->var ) {
106             arrayAccess = (bool) node->var->baseVariable->offsetItemsSequence;
107             identifier = identifierForNode(
108                 node->var->baseVariable->var->variable
109             );
110             targetNode = node->var->baseVariable->var->variable;
111         }
112     }
113 }
114
115 ReferencedTopDUContext DeclarationBuilder::build(const IndexedString& url, AstNode* node,
116         ReferencedTopDUContext updateContext)
117 {
118     //Run DeclarationBuilder twice, to find uses of declarations that are
119     //declared after the use. ($a = new Foo; class Foo {})
120     {
121         PreDeclarationBuilder prebuilder(&m_types, &m_functions, &m_namespaces,
122                                          &m_upcomingClassVariables, m_editor);
123         updateContext = prebuilder.build(url, node, updateContext);
124         m_actuallyRecompiling = prebuilder.didRecompile();
125     }
126
127     // now skip through some things the DeclarationBuilderBase (ContextBuilder) would do,
128     // most significantly don't clear imported parent contexts
129     m_isInternalFunctions = url == internalFunctionFile();
130     if ( m_isInternalFunctions ) {
131         m_reportErrors = false;
132     } else if ( ICore::self() ) {
133         m_reportErrors = ICore::self()->languageController()->completionSettings()->highlightSemanticProblems();
134     }
135
136     return ContextBuilderBase::build(url, node, updateContext);
137 }
138
139 void DeclarationBuilder::startVisiting(AstNode* node)
140 {
141     setRecompiling(m_actuallyRecompiling);
142     setCompilingContexts(false);
143     DeclarationBuilderBase::startVisiting(node);
144 }
145
146 void DeclarationBuilder::closeDeclaration()
147 {
148     if (currentDeclaration() && lastType()) {
149         DUChainWriteLocker lock(DUChain::lock());
150         currentDeclaration()->setType(lastType());
151     }
152
153     eventuallyAssignInternalContext();
154
155     DeclarationBuilderBase::closeDeclaration();
156 }
157
158 void DeclarationBuilder::classContextOpened(DUContext* context)
159 {
160     DUChainWriteLocker lock(DUChain::lock());
161     currentDeclaration()->setInternalContext(context);
162 }
163
164 void DeclarationBuilder::visitClassDeclarationStatement(ClassDeclarationStatementAst * node)
165 {
166     ClassDeclaration* classDec = openTypeDeclaration(node->className, ClassDeclarationData::Class);
167     openType(classDec->abstractType());
168     DeclarationBuilderBase::visitClassDeclarationStatement(node);
169     closeType();
170     closeDeclaration();
171     m_upcomingClassVariables.clear();
172 }
173
174 void DeclarationBuilder::visitInterfaceDeclarationStatement(InterfaceDeclarationStatementAst *node)
175 {
176     ClassDeclaration* interfaceDec = openTypeDeclaration(node->interfaceName, ClassDeclarationData::Interface);
177     openType(interfaceDec->abstractType());
178     DeclarationBuilderBase::visitInterfaceDeclarationStatement(node);
179     closeType();
180     closeDeclaration();
181 }
182
183 ClassDeclaration* DeclarationBuilder::openTypeDeclaration(IdentifierAst* name, ClassDeclarationData::ClassType type)
184 {
185     ClassDeclaration* classDec = m_types.value(name->string, 0);
186     Q_ASSERT(classDec);
187     isGlobalRedeclaration(identifierForNode(name), name, ClassDeclarationType);
188     Q_ASSERT(classDec->classType() == type);
189
190     // seems like we have to do that manually, else the usebuilder crashes...
191     setEncountered(classDec);
192     openDeclarationInternal(classDec);
193
194     return classDec;
195 }
196
197 bool DeclarationBuilder::isBaseMethodRedeclaration(const IdentifierPair &ids, ClassDeclaration *curClass,
198         ClassStatementAst *node)
199 {
200     DUChainWriteLocker lock(DUChain::lock());
201     while (curClass->baseClassesSize() > 0) {
202         StructureType::Ptr type;
203         FOREACH_FUNCTION(const BaseClassInstance& base, curClass->baseClasses) {
204             DUChainReadLocker lock(DUChain::lock());
205             type = base.baseClass.type<StructureType>();
206             if (!type) {
207                 continue;
208             }
209             ClassDeclaration *nextClass = dynamic_cast<ClassDeclaration*>(type->declaration(currentContext()->topContext()));
210             if (!nextClass || nextClass->classType() != ClassDeclarationData::Class) {
211                 type.clear();
212                 continue;
213             }
214             curClass = nextClass;
215             break;
216         }
217         if (!type) {
218             break;
219         }
220         {
221             if (!type->internalContext(currentContext()->topContext())) {
222                 continue;
223             }
224             foreach(Declaration * dec, type->internalContext(currentContext()->topContext())->findLocalDeclarations(ids.second.first(), startPos(node)))
225             {
226                 if (dec->isFunctionDeclaration()) {
227                     ClassMethodDeclaration* func = dynamic_cast<ClassMethodDeclaration*>(dec);
228                     if (!func) {
229                         continue;
230                     }
231                     // we cannot redeclare final classes ever
232                     if (func->isFinal()) {
233                         reportRedeclarationError(dec, node->methodName);
234                         return true;
235                     }
236                     // also we may not redeclare an already abstract method, we would have to implement it
237                     // TODO: original error message?
238                     // -> Can't inherit abstract function class::func() (previously declared in otherclass)
239                     else if (func->isAbstract() && node->modifiers->modifiers & ModifierAbstract) {
240                         reportRedeclarationError(dec, node->methodName);
241                         return true;
242                     }
243                 }
244             }
245         }
246     }
247     return false;
248 }
249
250 void DeclarationBuilder::visitClassStatement(ClassStatementAst *node)
251 {
252     setComment(formatComment(node, m_editor));
253     if (node->methodName) {
254         //method declaration
255
256         ClassDeclaration *parent =  dynamic_cast<ClassDeclaration*>(currentDeclaration());
257         Q_ASSERT(parent);
258
259         IdentifierPair ids = identifierPairForNode(node->methodName);
260         if (m_reportErrors) {   // check for redeclarations
261             Q_ASSERT(currentContext()->type() == DUContext::Class);
262             bool localError = false;
263             {
264                 DUChainWriteLocker lock(DUChain::lock());
265                 foreach(Declaration * dec, currentContext()->findLocalDeclarations(ids.second.first(), startPos(node->methodName)))
266                 {
267                     if (dec->isFunctionDeclaration()) {
268                         reportRedeclarationError(dec, node->methodName);
269                         localError = true;
270                         break;
271                     }
272                 }
273             }
274
275             if (!localError) {
276                 // if we have no local error, check that we don't try to overwrite a final method of a baseclass
277                 isBaseMethodRedeclaration(ids, parent, node);
278             }
279         }
280
281         {
282             DUChainWriteLocker lock(DUChain::lock());
283             ClassMethodDeclaration* dec = openDefinition<ClassMethodDeclaration>(ids.second, editorFindRange(node->methodName, node->methodName));
284             dec->setPrettyName(ids.first);
285             dec->clearDefaultParameters();
286             dec->setKind(Declaration::Type);
287             if (node->modifiers->modifiers & ModifierPublic) {
288                 dec->setAccessPolicy(Declaration::Public);
289             } else if (node->modifiers->modifiers & ModifierProtected) {
290                 dec->setAccessPolicy(Declaration::Protected);
291             } else if (node->modifiers->modifiers & ModifierPrivate) {
292                 dec->setAccessPolicy(Declaration::Private);
293             }
294             if (node->modifiers->modifiers & ModifierStatic) {
295                 dec->setStatic(true);
296             }
297             if (parent->classType() == ClassDeclarationData::Interface) {
298                 if (m_reportErrors) {
299                     if (node->modifiers->modifiers & ModifierFinal || node->modifiers->modifiers & ModifierAbstract) {
300                         reportError(i18n("Access type for interface method %1 must be omitted.",
301                                          dec->toString()), node->modifiers);
302                     }
303                     if (!isEmptyMethodBody(node->methodBody)) {
304                         reportError(i18n("Interface function %1 cannot contain body.",
305                                          dec->toString()), node->methodBody);
306                     }
307                 }
308                 // handle interface methods like abstract methods
309                 dec->setIsAbstract(true);
310             } else {
311                 if (node->modifiers->modifiers & ModifierAbstract) {
312                     if (!m_reportErrors) {
313                         dec->setIsAbstract(true);
314                     } else {
315                         if (parent->classModifier() != ClassDeclarationData::Abstract) {
316                             reportError(i18n("Class %1 contains abstract method %2 and must therefore be declared abstract "
317                                              "or implement the method.",
318                                              parent->identifier().toString(),
319                                              dec->identifier().toString()),
320                                         node->modifiers);
321                         } else if (!isEmptyMethodBody(node->methodBody)) {
322                             reportError(i18n("Abstract function %1 cannot contain body.",
323                                              dec->toString()), node->methodBody);
324                         } else if (node->modifiers->modifiers & ModifierFinal) {
325                             reportError(i18n("Cannot use the final modifier on an abstract class member."),
326                                         node->modifiers);
327                         } else {
328                             dec->setIsAbstract(true);
329                         }
330                     }
331                 } else if (node->modifiers->modifiers & ModifierFinal) {
332                     dec->setIsFinal(true);
333                 }
334                 if (m_reportErrors && !dec->isAbstract() && isEmptyMethodBody(node->methodBody)) {
335                     reportError(i18n("Non-abstract method %1 must contain body.", dec->toString()), node->methodBody);
336                 }
337             }
338         }
339
340         DeclarationBuilderBase::visitClassStatement(node);
341
342         closeDeclaration();
343     } else {
344         if (node->modifiers) {
345             m_currentModifers = node->modifiers->modifiers;
346             if (m_reportErrors) {
347                 // have to report the errors here to get a good problem range
348                 if (m_currentModifers & ModifierFinal) {
349                     reportError(i18n("Properties cannot be declared final."), node->modifiers);
350                 }
351                 if (m_currentModifers & ModifierAbstract) {
352                     reportError(i18n("Properties cannot be declared abstract."), node->modifiers);
353                 }
354             }
355         } else {
356             m_currentModifers = 0;
357         }
358         DeclarationBuilderBase::visitClassStatement(node);
359         m_currentModifers = 0;
360     }
361 }
362
363 void DeclarationBuilder::visitClassExtends(ClassExtendsAst *node)
364 {
365     addBaseType(node->identifier);
366 }
367
368 void DeclarationBuilder::visitClassImplements(ClassImplementsAst *node)
369 {
370     const KDevPG::ListNode<NamespacedIdentifierAst*> *__it = node->implementsSequence->front(), *__end = __it;
371     do {
372         addBaseType(__it->element);
373         __it = __it->next;
374     } while (__it != __end);
375     DeclarationBuilderBase::visitClassImplements(node);
376 }
377
378 void DeclarationBuilder::visitClassVariable(ClassVariableAst *node)
379 {
380     QualifiedIdentifier name = identifierForNode(node->variable);
381     if (m_reportErrors) {   // check for redeclarations
382         DUChainWriteLocker lock(DUChain::lock());
383         Q_ASSERT(currentContext()->type() == DUContext::Class);
384         foreach(Declaration * dec, currentContext()->findLocalDeclarations(name.first(), startPos(node)))
385         {
386             if (!dec->isFunctionDeclaration() && ! dec->abstractType()->modifiers() & AbstractType::ConstModifier) {
387                 reportRedeclarationError(dec, node);
388                 break;
389             }
390         }
391     }
392     openClassMemberDeclaration(node->variable, name);
393     DeclarationBuilderBase::visitClassVariable(node);
394     closeDeclaration();
395 }
396
397 void DeclarationBuilder::openClassMemberDeclaration(AstNode* node, const QualifiedIdentifier &name)
398 {
399     DUChainWriteLocker lock(DUChain::lock());
400
401     // dirty hack: declarations of class members outside the class context would
402     //             make the class context encompass the newRange. This is not what we want.
403     RangeInRevision oldRange = currentContext()->range();
404
405     RangeInRevision newRange = editorFindRange(node, node);
406     openDefinition<ClassMemberDeclaration>(name, newRange);
407
408     ClassMemberDeclaration* dec = dynamic_cast<ClassMemberDeclaration*>(currentDeclaration());
409     Q_ASSERT(dec);
410     if (m_currentModifers & ModifierPublic) {
411         dec->setAccessPolicy(Declaration::Public);
412     } else if (m_currentModifers & ModifierProtected) {
413         dec->setAccessPolicy(Declaration::Protected);
414     } else if (m_currentModifers & ModifierPrivate) {
415         dec->setAccessPolicy(Declaration::Private);
416     }
417     if (m_currentModifers & ModifierStatic) {
418         dec->setStatic(true);
419     }
420     dec->setKind(Declaration::Instance);
421
422     currentContext()->setRange(oldRange);
423 }
424
425 void DeclarationBuilder::declareClassMember(DUContext *parentCtx, AbstractType::Ptr type,
426                                                 const QualifiedIdentifier& identifier,
427                                                 AstNode* node )
428 {
429     if ( m_upcomingClassVariables.contains(identifier) ) {
430         if (m_actuallyRecompiling) {
431             DUChainWriteLocker lock;
432             Declaration* dec = currentContext()->parentContext()->findDeclarationAt(startPos(node));
433             if ( dynamic_cast<ClassMemberDeclaration*>(dec) ) {
434                 // invalidate declaration, it got added
435                 // see also bug https://bugs.kde.org/show_bug.cgi?id=241750
436                 delete dec;
437             }
438         }
439         return;
440     }
441
442     DUChainWriteLocker lock(DUChain::lock());
443
444     // check for redeclaration of private or protected stuff
445     {
446         // only interesting context might be the class context when we are inside a method
447         DUContext *ctx = currentContext()->parentContext();
448         foreach ( Declaration* dec, parentCtx->findDeclarations(identifier) ) {
449             if ( ClassMemberDeclaration* cdec = dynamic_cast<ClassMemberDeclaration*>(dec) ) {
450                 if ( cdec->accessPolicy() == Declaration::Private && cdec->context() != ctx ) {
451                     reportError(i18n("Cannot redeclare private property %1 from this context.",
452                                         cdec->toString()), node);
453                     return;
454                 } else if ( cdec->accessPolicy() == Declaration::Protected
455                             && cdec->context() != ctx
456                             && ( !ctx || !ctx->imports(cdec->context()) ) ) {
457                     reportError(i18n("Cannot redeclare protected property %1 from this context.",
458                                         cdec->toString()), node);
459                     return;
460                 }
461                 if ( cdec->abstractType()->indexed() == type->indexed() ) {
462                     encounter(dec);
463                     return;
464                 }
465             }
466         }
467     }
468
469     // this member should be public and non-static
470     m_currentModifers = ModifierPublic;
471     injectContext(parentCtx);
472     openClassMemberDeclaration(node, identifier);
473     m_currentModifers = 0;
474     //own closeDeclaration() that doesn't use lastType()
475     currentDeclaration()->setType(type);
476     eventuallyAssignInternalContext();
477     DeclarationBuilderBase::closeDeclaration();
478     closeInjectedContext();
479 }
480
481 void DeclarationBuilder::visitConstantDeclaration(ConstantDeclarationAst *node)
482 {
483     if (m_reportErrors) {   // check for redeclarations
484         DUChainWriteLocker lock(DUChain::lock());
485         foreach(Declaration * dec, currentContext()->findLocalDeclarations(identifierForNode(node->identifier).first(), startPos(node->identifier)))
486         {
487             if (!dec->isFunctionDeclaration() && dec->abstractType()->modifiers() & AbstractType::ConstModifier) {
488                 reportRedeclarationError(dec, node->identifier);
489                 break;
490             }
491         }
492     }
493     ClassMemberDeclaration* dec = openDefinition<ClassMemberDeclaration>(node->identifier, node->identifier);
494     {
495         DUChainWriteLocker lock(DUChain::lock());
496         dec->setAccessPolicy(Declaration::Public);
497         dec->setStatic(true);
498         dec->setKind(Declaration::Instance);
499     }
500     DeclarationBuilderBase::visitConstantDeclaration(node);
501     closeDeclaration();
502     if ( m_reportErrors ) {
503         // const class members may only be ints, floats, bools or strings
504         bool badType = true;
505         if ( IntegralType* type = fastCast<IntegralType*>(lastType().unsafeData()) ) {
506             switch( type->dataType() ) {
507                 case IntegralType::TypeBoolean:
508                 case IntegralType::TypeFloat:
509                 case IntegralType::TypeInt:
510                 case IntegralType::TypeString:
511                     badType = false;
512                     break;
513                 default:
514                     // every other type is a badType (see above)
515                     break;
516             }
517         }
518         if ( badType ) {
519             reportError(i18n("Only booleans, ints, floats and strings are allowed for class constants."), node->scalar);
520         }
521     }
522 }
523
524 void DeclarationBuilder::visitParameter(ParameterAst *node)
525 {
526     AbstractFunctionDeclaration* funDec = dynamic_cast<AbstractFunctionDeclaration*>(currentDeclaration());
527     Q_ASSERT(funDec);
528     if (node->defaultValue) {
529         QString symbol = m_editor->parseSession()->symbol(node->defaultValue);
530         funDec->addDefaultParameter(IndexedString(symbol));
531         if ( node->parameterType && symbol.compare(QLatin1String("null"), Qt::CaseInsensitive) != 0 ) {
532             reportError(i18n("Default value for parameters with a class type hint can only be NULL."), node->defaultValue);
533         }
534     } else if ( !node->defaultValue && funDec->defaultParametersSize() ) {
535         reportError(i18n("Following parameters must have a default value assigned."), node);
536     }
537     {
538         // create variable declaration for argument
539         DUChainWriteLocker lock(DUChain::lock());
540         RangeInRevision newRange = editorFindRange(node->variable, node->variable);
541         openDefinition<VariableDeclaration>(identifierForNode(node->variable), newRange);
542         currentDeclaration()->setKind(Declaration::Instance);
543     }
544
545     DeclarationBuilderBase::visitParameter(node);
546     closeDeclaration();
547 }
548
549 void DeclarationBuilder::visitFunctionDeclarationStatement(FunctionDeclarationStatementAst* node)
550 {
551     isGlobalRedeclaration(identifierForNode(node->functionName), node->functionName, FunctionDeclarationType);
552
553     FunctionDeclaration* dec = m_functions.value(node->functionName->string, 0);
554     Q_ASSERT(dec);
555     // seems like we have to set that, else the usebuilder crashes
556     DeclarationBuilderBase::setEncountered(dec);
557
558     openDeclarationInternal(dec);
559     openType(dec->abstractType());
560
561     DeclarationBuilderBase::visitFunctionDeclarationStatement(node);
562
563     closeType();
564     closeDeclaration();
565 }
566 void DeclarationBuilder::visitClosure(ClosureAst* node)
567 {
568     setComment(formatComment(node, editor()));
569     {
570         DUChainWriteLocker lock;
571         FunctionDeclaration *dec = openDefinition<FunctionDeclaration>(QualifiedIdentifier(),
572                                                                        editor()->findRange(node->startToken));
573         dec->setKind(Declaration::Type);
574         dec->clearDefaultParameters();
575     }
576
577     DeclarationBuilderBase::visitClosure(node);
578
579     closeDeclaration();
580 }
581 void DeclarationBuilder::visitLexicalVar(LexicalVarAst* node)
582 {
583     DeclarationBuilderBase::visitLexicalVar(node);
584
585     QualifiedIdentifier id = identifierForNode(node->variable);
586     DUChainWriteLocker lock;
587     if ( recompiling() ) {
588         // sadly we can't use findLocalDeclarations() here, since it un-aliases declarations
589         foreach ( Declaration* dec, currentContext()->localDeclarations() ) {
590             if ( dynamic_cast<AliasDeclaration*>(dec) && dec->identifier() == id.first() ) {
591                 // don't redeclare but reuse the existing declaration
592                 encounter(dec);
593                 return;
594             }
595         }
596     }
597
598     // no existing declaration found, create one
599     foreach(Declaration* aliasedDeclaration, currentContext()->findDeclarations(id)) {
600         if (aliasedDeclaration->kind() == Declaration::Instance) {
601             AliasDeclaration* dec = openDefinition<AliasDeclaration>(id, editor()->findRange(node->variable));
602             dec->setAliasedDeclaration(aliasedDeclaration);
603             closeDeclaration();
604             break;
605         }
606     }
607 }
608
609 bool DeclarationBuilder::isGlobalRedeclaration(const QualifiedIdentifier &identifier, AstNode* node,
610         DeclarationType type)
611 {
612     if (!m_reportErrors) {
613         return false;
614     }
615     ///TODO: method redeclaration etc.
616     if (type != ClassDeclarationType
617             && type != FunctionDeclarationType
618             && type != ConstantDeclarationType) {
619         // the other types can be redeclared
620         return false;
621     }
622
623     DUChainWriteLocker lock(DUChain::lock());
624     QList<Declaration*> declarations = currentContext()->topContext()->findDeclarations( identifier, startPos(node) );
625     foreach(Declaration* dec, declarations) {
626         if (isMatch(dec, type)) {
627             reportRedeclarationError(dec, node);
628             return true;
629         }
630     }
631     return false;
632 }
633
634 void DeclarationBuilder::reportRedeclarationError(Declaration* declaration, AstNode* node)
635 {
636     if (declaration->range().contains(startPos(node))) {
637         // make sure this is not a wrongly reported redeclaration error
638         return;
639     }
640     if (declaration->context()->topContext()->url() == internalFunctionFile()) {
641         reportError(i18n("Cannot redeclare PHP internal %1.", declaration->toString()), node);
642     } else {
643         ///TODO: try to shorten the filename by removing the leading path to the current project
644         reportError(
645             i18n("Cannot redeclare %1, already declared in %2 on line %3.",
646                  declaration->toString(), declaration->context()->topContext()->url().str(), declaration->range().start.line + 1
647                 ), node
648         );
649     }
650 }
651 void DeclarationBuilder::visitOuterTopStatement(OuterTopStatementAst* node)
652 {
653     //docblock of an AssignmentExpression
654     setComment(formatComment(node, m_editor));
655     m_lastTopStatementComment = m_editor->parseSession()->docComment(node->startToken);
656
657     DeclarationBuilderBase::visitOuterTopStatement(node);
658 }
659
660 void DeclarationBuilder::visitAssignmentExpression(AssignmentExpressionAst* node)
661 {
662     if ( node->assignmentExpressionEqual ) {
663         bool lastFindVariable = m_findVariable;
664         QualifiedIdentifier lastVariable = m_variable;
665         QualifiedIdentifier lastVariableParent = m_variableParent;
666         bool lastIsArray = m_variableIsArray;
667         AstNode* lastNode = m_variableNode;
668
669         m_findVariable = true;
670         m_variable = QualifiedIdentifier();
671         m_variableParent = QualifiedIdentifier();
672         m_variableIsArray = false;
673         m_variableNode = 0;
674
675         DeclarationBuilderBase::visitAssignmentExpression(node);
676
677         m_findVariable = lastFindVariable;
678         m_variable = lastVariable;
679         m_variableParent = lastVariableParent;
680         m_variableIsArray = lastIsArray;
681         m_variableNode = lastNode;
682     } else {
683         DeclarationBuilderBase::visitAssignmentExpression(node);
684     }
685 }
686
687 void DeclarationBuilder::visitVariable(VariableAst* node)
688 {
689     if ( m_findVariable ) {
690         getVariableIdentifier(node, m_variable, m_variableParent,
691                                     m_variableNode, m_variableIsArray);
692         m_findVariable = false;
693     }
694     DeclarationBuilderBase::visitVariable(node);
695 }
696
697 void DeclarationBuilder::declareVariable(DUContext* parentCtx, AbstractType::Ptr type,
698                                             const QualifiedIdentifier& identifier,
699                                             AstNode* node)
700 {
701     // we must not re-assign $this in a class context
702     /// Qualified identifier for 'this'
703     static const QualifiedIdentifier thisQId("this");
704     if ( identifier == thisQId
705             && currentContext()->parentContext()
706             && currentContext()->parentContext()->type() == DUContext::Class ) {
707         reportError(i18n("Cannot re-assign $this."), QList<AstNode*>() << node);
708         return;
709     }
710
711     DUChainWriteLocker lock(DUChain::lock());
712     // check if this variable is already declared
713     {
714         QList< Declaration* > decs = parentCtx->findDeclarations(identifier.first(), startPos(node), 0, DUContext::DontSearchInParent);
715         if ( !decs.isEmpty() ) {
716             QList< Declaration* >::const_iterator it = decs.constEnd() - 1;
717             while ( true ) {
718                 // we expect that the list of declarations has the newest declaration at back
719                 if ( dynamic_cast<VariableDeclaration*>( *it ) ) {
720                     encounter(*it);
721                     if ( (*it)->abstractType() && !(*it)->abstractType()->equals(type.unsafeData()) ) {
722                         // if it's currently mixed and we now get something more definite, use that instead
723                         if ( ReferenceType::Ptr rType = ReferenceType::Ptr::dynamicCast((*it)->abstractType()) ) {
724                             if ( IntegralType::Ptr integral = IntegralType::Ptr::dynamicCast(rType->baseType()) ) {
725                                 if ( integral->dataType() == IntegralType::TypeMixed ) {
726                                     // referenced mixed to referenced @p type
727                                     ReferenceType::Ptr newType(new ReferenceType());
728                                     newType->setBaseType(type);
729                                     (*it)->setType(newType);
730                                     return;
731                                 }
732                             }
733                         }
734                         if ( IntegralType::Ptr integral = IntegralType::Ptr::dynamicCast((*it)->abstractType()) ) {
735                             if ( integral->dataType() == IntegralType::TypeMixed ) {
736                                 // mixed to @p type
737                                 (*it)->setType(type);
738                                 return;
739                             }
740                         }
741                         // else make it unsure
742                         UnsureType::Ptr unsure = UnsureType::Ptr::dynamicCast((*it)->abstractType());
743                         // maybe it's referenced?
744                         ReferenceType::Ptr rType = ReferenceType::Ptr::dynamicCast((*it)->abstractType());
745                         if ( !unsure && rType ) {
746                             unsure = UnsureType::Ptr::dynamicCast(rType->baseType());
747                         }
748                         if ( !unsure ) {
749                             unsure = UnsureType::Ptr(new UnsureType());
750                             if ( rType ) {
751                                 unsure->addType(rType->baseType()->indexed());
752                             } else {
753                                 unsure->addType((*it)->indexedType());
754                             }
755                         }
756                         unsure->addType(type->indexed());
757                         if ( rType ) {
758                             rType->setBaseType(AbstractType::Ptr(unsure.unsafeData()));
759                             (*it)->setType(rType);
760                         } else {
761                             (*it)->setType(unsure);
762                         }
763                     }
764                     return;
765                 }
766                 if ( it == decs.constBegin() ) {
767                     break;
768                 }
769                 --it;
770             }
771         }
772     }
773
774     RangeInRevision newRange = editorFindRange(node, node);
775
776     VariableDeclaration *dec = openDefinition<VariableDeclaration>(identifier, newRange);
777     dec->setKind(Declaration::Instance);
778     if (!m_lastTopStatementComment.isEmpty()) {
779         QRegExp rx("(\\*|///)\\s*@superglobal");
780         if (rx.indexIn(m_lastTopStatementComment) != -1) {
781             dec->setSuperglobal(true);
782         }
783     }
784     //own closeDeclaration() that doesn't use lastType()
785     currentDeclaration()->setType(type);
786     eventuallyAssignInternalContext();
787     DeclarationBuilderBase::closeDeclaration();
788 }
789
790 DUContext* getClassContext(const QualifiedIdentifier &identifier, DUContext* currentCtx) {
791     /// Qualified identifier for 'this'
792     static const QualifiedIdentifier thisQId("this");
793     if ( identifier == thisQId ) {
794         if ( currentCtx->parentContext() && currentCtx->parentContext()->type() == DUContext::Class ) {
795             return currentCtx->parentContext();
796         }
797     } else {
798         DUChainReadLocker lock(DUChain::lock());
799         foreach( Declaration* parent, currentCtx->topContext()->findDeclarations(identifier) ) {
800             if ( StructureType::Ptr ctype = parent->type<StructureType>() ) {
801                 return ctype->internalContext(currentCtx->topContext());
802             }
803         }
804         ///TODO: if we can't find anything here we might have to use the findDeclarationImport helper
805     }
806     return 0;
807 }
808
809 ///TODO: we need to handle assignment to array-members properly
810 ///      currently we just make sure the the array is declared, but don't know
811 ///      anything about its contents
812 void DeclarationBuilder::visitAssignmentExpressionEqual(AssignmentExpressionEqualAst *node)
813 {
814     DeclarationBuilderBase::visitAssignmentExpressionEqual(node);
815
816     if ( !m_variable.isEmpty() && currentAbstractType()) {
817         //create new declaration assignments to not-yet declared variables and class members
818
819         AbstractType::Ptr type;
820         if ( m_variableIsArray ) {
821             // implicit array declaration
822             type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray));
823         } else {
824             type = currentAbstractType();
825         }
826
827         if ( !m_variableParent.isEmpty() ) {
828             // assignment to class members
829
830             if ( DUContext* ctx = getClassContext(m_variableParent, currentContext()) ) {
831                 declareClassMember(ctx, type, m_variable, m_variableNode);
832             }
833         } else {
834             // assigment to other variables
835             declareVariable(currentContext(), type, m_variable, m_variableNode );
836         }
837     }
838 }
839
840 void DeclarationBuilder::visitFunctionCall(FunctionCallAst* node)
841 {
842     QualifiedIdentifier id;
843     {
844         FunctionType::Ptr oldFunction = m_currentFunctionType;
845
846         DeclarationPointer dec;
847         if ( node->stringFunctionName ) {
848             dec = findDeclarationImport(FunctionDeclarationType, node->stringFunctionName);
849         } else if ( node->stringFunctionNameOrClass ) {
850             id = identifierForNamespace(node->stringFunctionNameOrClass, m_editor);
851             dec = findDeclarationImport(FunctionDeclarationType, id, node->stringFunctionNameOrClass);
852         } else {
853             ///TODO: node->varFunctionName
854         }
855
856         if ( dec ) {
857             m_currentFunctionType = dec->type<FunctionType>();
858         } else {
859             m_currentFunctionType = 0;
860         }
861
862         DeclarationBuilderBase::visitFunctionCall(node);
863
864         m_currentFunctionType = oldFunction;
865     }
866
867     if (node->stringFunctionNameOrClass && !node->stringFunctionName && !node->varFunctionName) {
868         if (id.toString(true) == "define"
869                 && node->stringParameterList && node->stringParameterList->parametersSequence
870                 && node->stringParameterList->parametersSequence->count() > 0) {
871             //constant, defined through define-function
872
873             //find name of the constant (first argument of the function call)
874             CommonScalarAst* scalar = findCommonScalar(node->stringParameterList->parametersSequence->at(0)->element);
875             if (scalar && scalar->string != -1) {
876                 QString constant = m_editor->parseSession()->symbol(scalar->string);
877                 constant = constant.mid(1, constant.length() - 2);
878                 RangeInRevision newRange = editorFindRange(scalar, scalar);
879                 DUChainWriteLocker lock(DUChain::lock());
880                 // find fitting context to put define in,
881                 // pick first namespace or global context otherwise
882                 DUContext* ctx = currentContext();
883                 while (ctx->type() != DUContext::Namespace && ctx->parentContext()) {
884                     ctx = ctx->parentContext();
885                 }
886                 injectContext(ctx); //constants are always global
887                 QualifiedIdentifier identifier(constant);
888                 isGlobalRedeclaration(identifier, scalar, ConstantDeclarationType);
889                 openDefinition<Declaration>(identifier, newRange);
890                 currentDeclaration()->setKind(Declaration::Instance);
891                 Q_ASSERT(lastType());
892                 lastType()->setModifiers(lastType()->modifiers() | AbstractType::ConstModifier);
893                 closeDeclaration();
894                 closeInjectedContext();
895             }
896         }
897     }
898 }
899
900 void DeclarationBuilder::visitFunctionCallParameterList(FunctionCallParameterListAst* node)
901 {
902     int oldPos = m_functionCallParameterPos;
903     m_functionCallParameterPos = 0;
904
905     DeclarationBuilderBase::visitFunctionCallParameterList(node);
906
907     m_functionCallParameterPos = oldPos;
908 }
909
910 void DeclarationBuilder::visitFunctionCallParameterListElement(FunctionCallParameterListElementAst* node)
911 {
912     bool lastFindVariable = m_findVariable;
913     QualifiedIdentifier lastVariable = m_variable;
914     QualifiedIdentifier lastVariableParent = m_variableParent;
915     bool lastIsArray = m_variableIsArray;
916     AstNode* lastNode = m_variableNode;
917
918     m_findVariable = true;
919     m_variable = QualifiedIdentifier();
920     m_variableParent = QualifiedIdentifier();
921     m_variableIsArray = false;
922     m_variableNode = 0;
923
924     DeclarationBuilderBase::visitFunctionCallParameterListElement(node);
925
926     if ( m_variableNode && !m_currentFunctionType.isNull() &&
927             m_currentFunctionType->arguments().count() > m_functionCallParameterPos) {
928         ReferenceType::Ptr refType = m_currentFunctionType->arguments()
929                                         .at(m_functionCallParameterPos).cast<ReferenceType>();
930         if ( refType ) {
931             // this argument is referenced, so if the node contains undeclared variables we have
932             // to declare them with a NULL type, see also:
933             // http://de.php.net/manual/en/language.references.whatdo.php
934
935             // declare with NULL type, just like PHP does
936             declareFoundVariable(new IntegralType(IntegralType::TypeNull));
937         }
938     }
939
940     m_findVariable = lastFindVariable;
941     m_variable = lastVariable;
942     m_variableParent = lastVariableParent;
943     m_variableIsArray = lastIsArray;
944     m_variableNode = lastNode;
945
946     ++m_functionCallParameterPos;
947 }
948
949 void DeclarationBuilder::visitAssignmentListElement(AssignmentListElementAst* node)
950 {
951     bool lastFindVariable = m_findVariable;
952     QualifiedIdentifier lastVariable = m_variable;
953     QualifiedIdentifier lastVariableParent = m_variableParent;
954     bool lastIsArray = m_variableIsArray;
955     AstNode* lastNode = m_variableNode;
956
957     m_findVariable = true;
958     m_variable = QualifiedIdentifier();
959     m_variableParent = QualifiedIdentifier();
960     m_variableIsArray = false;
961     m_variableNode = 0;
962
963     DeclarationBuilderBase::DefaultVisitor::visitAssignmentListElement(node);
964
965     if ( m_variableNode ) {
966         ///TODO: get a proper type here, if possible
967         declareFoundVariable(new IntegralType(IntegralType::TypeMixed));
968     }
969
970     m_findVariable = lastFindVariable;
971     m_variable = lastVariable;
972     m_variableParent = lastVariableParent;
973     m_variableIsArray = lastIsArray;
974     m_variableNode = lastNode;
975
976 }
977
978 void DeclarationBuilder::declareFoundVariable(AbstractType* type)
979 {
980     Q_ASSERT(m_variableNode);
981
982     ///TODO: support something like: foo($var[0])
983     if ( !m_variableIsArray ) {
984         DUContext *ctx = 0;
985         if ( m_variableParent.isEmpty() ) {
986             ctx = currentContext();
987         } else {
988             ctx = getClassContext(m_variableParent, currentContext());
989         }
990         if ( ctx ) {
991             bool isDeclared = false;
992             {
993                 DUChainWriteLocker lock(DUChain::lock());
994                 foreach ( Declaration* dec, ctx->findDeclarations(m_variable) ) {
995                     if ( dec->kind() == Declaration::Instance ) {
996                         isDeclared = true;
997                         // update comment but nothing else
998                         encounter(dec);
999                         break;
1000                     }
1001                 }
1002             }
1003             if ( !isDeclared && m_variableParent.isEmpty() ) {
1004                 // check also for global vars
1005                 isDeclared = findDeclarationImport(GlobalVariableDeclarationType, m_variable, m_variableNode);
1006             }
1007             if ( !isDeclared ) {
1008                 // couldn't find the dec, declare it
1009                 AbstractType::Ptr newType(type);
1010                 if ( !m_variableParent.isEmpty() ) {
1011                     declareClassMember(ctx, newType, m_variable, m_variableNode);
1012                 } else {
1013                     declareVariable(ctx, newType, m_variable, m_variableNode);
1014                 }
1015             }
1016         }
1017     }
1018 }
1019
1020 void DeclarationBuilder::visitStatement(StatementAst* node)
1021 {
1022     DeclarationBuilderBase::visitStatement(node);
1023
1024     if (node->foreachVariable) {
1025         DUChainWriteLocker lock(DUChain::lock());
1026         RangeInRevision newRange = editorFindRange(node->foreachVariable->variable, node->foreachVariable->variable);
1027         openDefinition<VariableDeclaration>(identifierForNode(node->foreachVariable->variable), newRange);
1028         currentDeclaration()->setKind(Declaration::Instance);
1029         closeDeclaration();
1030     }
1031
1032     if (node->foreachVarAsVar) {
1033         DUChainWriteLocker lock(DUChain::lock());
1034         RangeInRevision newRange = editorFindRange(node->foreachVarAsVar->variable, node->foreachVarAsVar->variable);
1035         openDefinition<VariableDeclaration>(identifierForNode(node->foreachVarAsVar->variable), newRange);
1036         currentDeclaration()->setKind(Declaration::Instance);
1037         closeDeclaration();
1038     }
1039
1040     if (node->foreachExprAsVar) {
1041         DUChainWriteLocker lock(DUChain::lock());
1042         RangeInRevision newRange = editorFindRange(node->foreachExprAsVar, node->foreachExprAsVar);
1043         openDefinition<VariableDeclaration>(identifierForNode(node->foreachExprAsVar), newRange);
1044         currentDeclaration()->setKind(Declaration::Instance);
1045         closeDeclaration();
1046     }
1047
1048 }
1049
1050 void DeclarationBuilder::visitStaticVar(StaticVarAst* node)
1051 {
1052     DeclarationBuilderBase::visitStaticVar(node);
1053
1054     DUChainWriteLocker lock(DUChain::lock());
1055     openDefinition<VariableDeclaration>(identifierForNode(node->var),
1056                                         editorFindRange(node->var, node->var));
1057     currentDeclaration()->setKind(Declaration::Instance);
1058
1059     closeDeclaration();
1060 }
1061
1062 void DeclarationBuilder::visitGlobalVar(GlobalVarAst* node)
1063 {
1064     DeclarationBuilderBase::visitGlobalVar(node);
1065     if (node->var) {
1066         QualifiedIdentifier id = identifierForNode(node->var);
1067         if ( recompiling() ) {
1068             DUChainWriteLocker lock(DUChain::lock());
1069             // sadly we can't use findLocalDeclarations() here, since it un-aliases declarations
1070             foreach ( Declaration* dec, currentContext()->localDeclarations() ) {
1071                 if ( dynamic_cast<AliasDeclaration*>(dec) && dec->identifier() == id.first() ) {
1072                     // don't redeclare but reuse the existing declaration
1073                     encounter(dec);
1074                     return;
1075                 }
1076             }
1077         }
1078         // no existing declaration found, create one
1079         DeclarationPointer aliasedDeclaration = findDeclarationImport(GlobalVariableDeclarationType, node->var);
1080         if (aliasedDeclaration) {
1081             DUChainWriteLocker lock(DUChain::lock());
1082             AliasDeclaration* dec = openDefinition<AliasDeclaration>(id, m_editor->findRange(node->var));
1083             dec->setAliasedDeclaration(aliasedDeclaration.data());
1084             closeDeclaration();
1085         }
1086     }
1087 }
1088
1089 void DeclarationBuilder::visitCatchItem(CatchItemAst *node)
1090 {
1091     DeclarationBuilderBase::visitCatchItem(node);
1092
1093     DUChainWriteLocker lock(DUChain::lock());
1094     openDefinition<VariableDeclaration>(identifierForNode(node->var),
1095                                         editorFindRange(node->var, node->var));
1096     currentDeclaration()->setKind(Declaration::Instance);
1097     closeDeclaration();
1098 }
1099
1100 void DeclarationBuilder::visitUnaryExpression(UnaryExpressionAst* node)
1101 {
1102     DeclarationBuilderBase::visitUnaryExpression(node);
1103     IndexedString includeFile = getIncludeFileForNode(node, m_editor);
1104     if ( !includeFile.isEmpty() ) {
1105         DUChainWriteLocker lock;
1106         TopDUContext* includedCtx = DUChain::self()->chainForDocument(includeFile);
1107         if ( !includedCtx ) {
1108             // invalid include
1109             return;
1110         }
1111
1112         QualifiedIdentifier identifier(includeFile.str());
1113
1114         foreach ( Declaration* dec, includedCtx->findDeclarations(identifier, CursorInRevision(0, 1)) ) {
1115             if ( dec->kind() == Declaration::Import ) {
1116                 encounter(dec);
1117                 return;
1118             }
1119         }
1120         injectContext(includedCtx);
1121         openDefinition<Declaration>(identifier, RangeInRevision(0, 0, 0, 0));
1122         currentDeclaration()->setKind(Declaration::Import);
1123         eventuallyAssignInternalContext();
1124         DeclarationBuilderBase::closeDeclaration();
1125         closeInjectedContext();
1126     }
1127 }
1128
1129 void DeclarationBuilder::openNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier, const RangeInRevision& range)
1130 {
1131     NamespaceDeclaration* dec = m_namespaces.value(node->string, 0);
1132     Q_ASSERT(dec);
1133     DeclarationBuilderBase::setEncountered(dec);
1134     openDeclarationInternal(dec);
1135
1136     DeclarationBuilderBase::openNamespace(parent, node, identifier, range);
1137 }
1138
1139 void DeclarationBuilder::closeNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier)
1140 {
1141     DeclarationBuilderBase::closeNamespace(parent, node, identifier);
1142     closeDeclaration();
1143 }
1144
1145 void DeclarationBuilder::visitUseNamespace(UseNamespaceAst* node)
1146 {
1147     if ( !node->aliasIdentifier && node->identifier->namespaceNameSequence->count() == 1 ) {
1148         reportError(i18n("The use statement with non-compound name '%1' has no effect.",
1149                          identifierForNode(node->identifier->namespaceNameSequence->front()->element).toString()),
1150                     node->identifier, ProblemData::Warning);
1151         return;
1152     }
1153     IdentifierAst* idNode = node->aliasIdentifier ? node->aliasIdentifier : node->identifier->namespaceNameSequence->back()->element;
1154     IdentifierPair id = identifierPairForNode(idNode);
1155     DUChainWriteLocker lock;
1156     NamespaceAliasDeclaration* decl = openDefinition<NamespaceAliasDeclaration>(id.second,
1157                                                                                 m_editor->findRange(idNode));
1158     {
1159         ///TODO: case insensitive!
1160         decl->setImportIdentifier( identifierForNamespace(node->identifier, m_editor) );
1161         decl->setPrettyName( id.first );
1162         decl->setKind(Declaration::NamespaceAlias);
1163     }
1164     closeDeclaration();
1165 }
1166
1167 void DeclarationBuilder::updateCurrentType()
1168 {
1169     DUChainWriteLocker lock(DUChain::lock());
1170     currentDeclaration()->setAbstractType(currentAbstractType());
1171 }
1172
1173 void DeclarationBuilder::supportBuild(AstNode* node, DUContext* context)
1174 {
1175     // generally we are the second pass through the doc (see PreDeclarationBuilder)
1176     // so notify our base about it
1177     setCompilingContexts(false);
1178     DeclarationBuilderBase::supportBuild(node, context);
1179 }
1180
1181 void DeclarationBuilder::closeContext()
1182 {
1183     // We don't want the first pass to clean up stuff, since
1184     // there is lots of stuff we visit/encounter here first.
1185     // So we clean things up here.
1186     setCompilingContexts(true);
1187     DeclarationBuilderBase::closeContext();
1188     setCompilingContexts(false);
1189 }
1190 void DeclarationBuilder::encounter(Declaration* dec)
1191 {
1192     // when we are recompiling, it's important to mark decs as encountered
1193     // and update their comments
1194     if ( recompiling() && !wasEncountered(dec) ) {
1195         dec->setComment(comment());
1196         setEncountered(dec);
1197     }
1198 }
1199
1200 }