File indexing completed on 2024-05-05 16:41:06

0001 /*
0002     SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "declarationbuilder.h"
0008 
0009 #include <KLocalizedString>
0010 
0011 #include <language/duchain/stringhelpers.h>
0012 #include <language/duchain/aliasdeclaration.h>
0013 #include <language/duchain/types/integraltype.h>
0014 #include <language/duchain/types/unsuretype.h>
0015 
0016 #include <interfaces/icore.h>
0017 #include <interfaces/ilanguagecontroller.h>
0018 #include <interfaces/icompletionsettings.h>
0019 #include <util/pushvalue.h>
0020 
0021 
0022 #include "../declarations/variabledeclaration.h"
0023 #include "../declarations/classmethoddeclaration.h"
0024 #include "../declarations/classdeclaration.h"
0025 #include "../declarations/functiondeclaration.h"
0026 #include "../declarations/namespacedeclaration.h"
0027 #include "../declarations/namespacealiasdeclaration.h"
0028 #include "../declarations/traitmethodaliasdeclaration.h"
0029 #include "../declarations/traitmemberaliasdeclaration.h"
0030 
0031 #include "../parser/phpast.h"
0032 #include "../parser/parsesession.h"
0033 
0034 #include "../helper.h"
0035 #include "../expressionvisitor.h"
0036 
0037 #include "predeclarationbuilder.h"
0038 #include <duchaindebug.h>
0039 
0040 #define ifDebug(x)
0041 
0042 using namespace KDevelop;
0043 
0044 namespace Php
0045 {
0046 
0047 DeclarationBuilder::FindVariableResults::FindVariableResults()
0048 : find(true)
0049 , isArray(false)
0050 , node(nullptr)
0051 {
0052 
0053 }
0054 
0055 void DeclarationBuilder::getVariableIdentifier(VariableAst* node,
0056                                                 QualifiedIdentifier &identifier,
0057                                                 QualifiedIdentifier &parent,
0058                                                 AstNode* &targetNode,
0059                                                 bool &arrayAccess)
0060 {
0061     parent = QualifiedIdentifier();
0062     if ( node->variablePropertiesSequence ) {
0063         // at least one "->" in the assignment target
0064         // => find he parent of the target
0065         // => find the target (last object property)
0066         if ( node->variablePropertiesSequence->count() == 1 ) {
0067             // $parent->target
0068             ///TODO: $parent[0]->target = ... (we don't know the type of [0] yet, need proper array handling first)
0069             if ( node->var && node->var->baseVariable && node->var->baseVariable->var
0070                 && !node->var->baseVariable->offsetItemsSequence ) {
0071                 parent = identifierForNode(
0072                     node->var->baseVariable->var->variable
0073                 );
0074             }
0075         } else {
0076             // $var->...->parent->target
0077             ///TODO: $var->...->parent[0]->target = ... (we don't know the type of [0] yet, need proper array handling first)
0078             const KDevPG::ListNode< VariableObjectPropertyAst* >* parentNode = node->variablePropertiesSequence->at(
0079                 node->variablePropertiesSequence->count() - 2
0080             );
0081             if ( parentNode->element && parentNode->element->variableProperty
0082                 && parentNode->element->variableProperty->objectProperty
0083                 && parentNode->element->variableProperty->objectProperty->objectDimList
0084                 && parentNode->element->variableProperty->objectProperty->objectDimList->variableName
0085                 && !parentNode->element->variableProperty->objectProperty->objectDimList->offsetItemsSequence ) {
0086                 parent = identifierForNode(
0087                     parentNode->element->variableProperty->objectProperty->objectDimList->variableName->name
0088                 );
0089             }
0090         }
0091 
0092         if ( !parent.isEmpty() ) {
0093             const KDevPG::ListNode< VariableObjectPropertyAst* >* tNode = node->variablePropertiesSequence->at(
0094                 node->variablePropertiesSequence->count() - 1
0095             );
0096             if ( tNode->element && tNode->element->variableProperty
0097                 && tNode->element->variableProperty->objectProperty
0098                 && tNode->element->variableProperty->objectProperty->objectDimList
0099                 && tNode->element->variableProperty->objectProperty->objectDimList->variableName ) {
0100                 arrayAccess = (bool) tNode->element->variableProperty->objectProperty->objectDimList->offsetItemsSequence;
0101                 identifier = identifierForNode(
0102                     tNode->element->variableProperty->objectProperty->objectDimList->variableName->name
0103                 );
0104                 targetNode = tNode->element->variableProperty->objectProperty->objectDimList->variableName->name;
0105             }
0106         }
0107     } else {
0108         // simple assignment to $var
0109         if ( node->var && node->var->baseVariable && node->var->baseVariable->var ) {
0110             arrayAccess = (bool) node->var->baseVariable->offsetItemsSequence;
0111             identifier = identifierForNode(
0112                 node->var->baseVariable->var->variable
0113             );
0114             targetNode = node->var->baseVariable->var->variable;
0115         }
0116     }
0117 }
0118 
0119 ReferencedTopDUContext DeclarationBuilder::build(const IndexedString& url, AstNode* node,
0120                                                  const ReferencedTopDUContext& updateContext_)
0121 {
0122     ReferencedTopDUContext updateContext(updateContext_);
0123     //Run DeclarationBuilder twice, to find uses of declarations that are
0124     //declared after the use. ($a = new Foo; class Foo {})
0125     {
0126         PreDeclarationBuilder prebuilder(&m_types, &m_functions, &m_namespaces,
0127                                          &m_upcomingClassVariables, m_editor);
0128         updateContext = prebuilder.build(url, node, updateContext);
0129         m_actuallyRecompiling = prebuilder.didRecompile();
0130     }
0131 
0132     // now skip through some things the DeclarationBuilderBase (ContextBuilder) would do,
0133     // most significantly don't clear imported parent contexts
0134     m_isInternalFunctions = url == internalFunctionFile();
0135     if ( m_isInternalFunctions ) {
0136         m_reportErrors = false;
0137     } else if ( ICore::self() ) {
0138         m_reportErrors = ICore::self()->languageController()->completionSettings()->highlightSemanticProblems();
0139     }
0140 
0141     return ContextBuilderBase::build(url, node, updateContext);
0142 }
0143 
0144 void DeclarationBuilder::startVisiting(AstNode* node)
0145 {
0146     setRecompiling(m_actuallyRecompiling);
0147     setCompilingContexts(false);
0148     DeclarationBuilderBase::startVisiting(node);
0149 }
0150 
0151 void DeclarationBuilder::closeDeclaration()
0152 {
0153     if (currentDeclaration() && lastType()) {
0154         DUChainWriteLocker lock(DUChain::lock());
0155         currentDeclaration()->setType(lastType());
0156     }
0157 
0158     eventuallyAssignInternalContext();
0159 
0160     DeclarationBuilderBase::closeDeclaration();
0161 }
0162 
0163 void DeclarationBuilder::classContextOpened(DUContext* context)
0164 {
0165     DUChainWriteLocker lock(DUChain::lock());
0166     currentDeclaration()->setInternalContext(context);
0167 }
0168 
0169 void DeclarationBuilder::visitClassDeclarationStatement(ClassDeclarationStatementAst * node)
0170 {
0171     ClassDeclaration* classDec = openTypeDeclaration(node->className, ClassDeclarationData::Class);
0172     openType(classDec->abstractType());
0173     DeclarationBuilderBase::visitClassDeclarationStatement(node);
0174     {
0175         DUChainWriteLocker lock;
0176         classDec->updateCompletionCodeModelItem();
0177     }
0178     closeType();
0179     closeDeclaration();
0180     m_upcomingClassVariables.clear();
0181 
0182     QString className = classDec->prettyName().str();
0183 
0184     if (isReservedClassName(className)) {
0185         reportError(i18n("Cannot use '%1' as class name as it is reserved", className), node->className);
0186     }
0187 }
0188 
0189 void DeclarationBuilder::visitInterfaceDeclarationStatement(InterfaceDeclarationStatementAst *node)
0190 {
0191     ClassDeclaration* interfaceDec = openTypeDeclaration(node->interfaceName, ClassDeclarationData::Interface);
0192     openType(interfaceDec->abstractType());
0193     DeclarationBuilderBase::visitInterfaceDeclarationStatement(node);
0194     closeType();
0195     closeDeclaration();
0196 
0197     QString interfaceName = interfaceDec->prettyName().str();
0198 
0199     if (isReservedClassName(interfaceName)) {
0200         reportError(i18n("Cannot use '%1' as class name as it is reserved", interfaceName), node->interfaceName);
0201     }
0202 }
0203 
0204 void DeclarationBuilder::visitTraitDeclarationStatement(TraitDeclarationStatementAst * node)
0205 {
0206     ClassDeclaration* traitDec = openTypeDeclaration(node->traitName, ClassDeclarationData::Trait);
0207     openType(traitDec->abstractType());
0208     DeclarationBuilderBase::visitTraitDeclarationStatement(node);
0209     closeType();
0210     closeDeclaration();
0211     m_upcomingClassVariables.clear();
0212 
0213     QString traitName = traitDec->prettyName().str();
0214 
0215     if (isReservedClassName(traitName)) {
0216         reportError(i18n("Cannot use '%1' as class name as it is reserved", traitName), node->traitName);
0217     }
0218 }
0219 
0220 ClassDeclaration* DeclarationBuilder::openTypeDeclaration(IdentifierAst* name, ClassDeclarationData::ClassType type)
0221 {
0222     ClassDeclaration* classDec = m_types.value(name->string, nullptr);
0223     Q_ASSERT(classDec);
0224     isGlobalRedeclaration(identifierForNode(name), name, ClassDeclarationType);
0225     Q_ASSERT(classDec->classType() == type);
0226     Q_UNUSED(type);
0227 
0228     // seems like we have to do that manually, else the usebuilder crashes...
0229     setEncountered(classDec);
0230     openDeclarationInternal(classDec);
0231 
0232     return classDec;
0233 }
0234 
0235 bool DeclarationBuilder::isBaseMethodRedeclaration(const IdentifierPair &ids, ClassDeclaration *curClass,
0236         ClassStatementAst *node)
0237 {
0238     DUChainWriteLocker lock(DUChain::lock());
0239     while (curClass->baseClassesSize() > 0) {
0240         StructureType::Ptr type;
0241         FOREACH_FUNCTION(const BaseClassInstance& base, curClass->baseClasses) {
0242             DUChainReadLocker lock(DUChain::lock());
0243             type = base.baseClass.type<StructureType>();
0244             if (!type) {
0245                 continue;
0246             }
0247             ClassDeclaration *nextClass = dynamic_cast<ClassDeclaration*>(type->declaration(currentContext()->topContext()));
0248             if (!nextClass || nextClass->classType() != ClassDeclarationData::Class) {
0249                 type.reset();
0250                 continue;
0251             }
0252             curClass = nextClass;
0253             break;
0254         }
0255         if (!type) {
0256             break;
0257         }
0258         {
0259             if (!type->internalContext(currentContext()->topContext())) {
0260                 continue;
0261             }
0262             foreach(Declaration * dec, type->internalContext(currentContext()->topContext())->findLocalDeclarations(ids.second.first(), startPos(node)))
0263             {
0264                 if (dec->isFunctionDeclaration()) {
0265                     ClassMethodDeclaration* func = dynamic_cast<ClassMethodDeclaration*>(dec);
0266                     if (!func || !wasEncountered(func)) {
0267                         continue;
0268                     }
0269                     // we cannot redeclare final classes ever
0270                     if (func->isFinal()) {
0271                         reportRedeclarationError(dec, node->methodName);
0272                         return true;
0273                     }
0274                     // also we may not redeclare an already abstract method, we would have to implement it
0275                     // TODO: original error message?
0276                     // -> Can't inherit abstract function class::func() (previously declared in otherclass)
0277                     else if (func->isAbstract() && node->modifiers->modifiers & ModifierAbstract) {
0278                         reportRedeclarationError(dec, node->methodName);
0279                         return true;
0280                     }
0281                 }
0282             }
0283         }
0284     }
0285     return false;
0286 }
0287 
0288 void DeclarationBuilder::visitClassStatement(ClassStatementAst *node)
0289 {
0290     setComment(formatComment(node, m_editor));
0291 
0292     ClassDeclaration *parent =  dynamic_cast<ClassDeclaration*>(currentDeclaration());
0293     Q_ASSERT(parent);
0294 
0295     if (node->methodName) {
0296         //method declaration
0297 
0298         IdentifierPair ids = identifierPairForNode(node->methodName);
0299         if (m_reportErrors) {   // check for redeclarations
0300             Q_ASSERT(currentContext()->type() == DUContext::Class);
0301             bool localError = false;
0302             {
0303                 DUChainWriteLocker lock(DUChain::lock());
0304                 foreach(Declaration * dec, currentContext()->findLocalDeclarations(ids.second.first(), startPos(node->methodName)))
0305                 {
0306                     if (wasEncountered(dec) && dec->isFunctionDeclaration() && !dynamic_cast<TraitMethodAliasDeclaration*>(dec)) {
0307                         reportRedeclarationError(dec, node->methodName);
0308                         localError = true;
0309                         break;
0310                     }
0311                 }
0312             }
0313 
0314             if (!localError) {
0315                 // if we have no local error, check that we don't try to overwrite a final method of a baseclass
0316                 isBaseMethodRedeclaration(ids, parent, node);
0317             }
0318         }
0319 
0320         {
0321             DUChainWriteLocker lock(DUChain::lock());
0322             ClassMethodDeclaration* dec = openDefinition<ClassMethodDeclaration>(ids.second, editorFindRange(node->methodName, node->methodName));
0323             dec->setPrettyName(ids.first);
0324             dec->clearDefaultParameters();
0325             dec->setKind(Declaration::Type);
0326             if (node->modifiers->modifiers & ModifierPublic) {
0327                 dec->setAccessPolicy(Declaration::Public);
0328             } else if (node->modifiers->modifiers & ModifierProtected) {
0329                 dec->setAccessPolicy(Declaration::Protected);
0330             } else if (node->modifiers->modifiers & ModifierPrivate) {
0331                 dec->setAccessPolicy(Declaration::Private);
0332             }
0333             if (node->modifiers->modifiers & ModifierStatic) {
0334                 dec->setStatic(true);
0335             }
0336             if (parent->classType() == ClassDeclarationData::Interface) {
0337                 if (m_reportErrors) {
0338                     if (node->modifiers->modifiers & ModifierFinal || node->modifiers->modifiers & ModifierAbstract) {
0339                         reportError(i18n("Access type for interface method %1 must be omitted.",
0340                                          dec->toString()), node->modifiers);
0341                     }
0342                     if (!isEmptyMethodBody(node->methodBody)) {
0343                         reportError(i18n("Interface function %1 cannot contain body.",
0344                                          dec->toString()), node->methodBody);
0345                     }
0346                 }
0347                 // handle interface methods like abstract methods
0348                 dec->setIsAbstract(true);
0349             } else {
0350                 if (node->modifiers->modifiers & ModifierAbstract) {
0351                     if (!m_reportErrors) {
0352                         dec->setIsAbstract(true);
0353                     } else {
0354                         if (parent->classModifier() != ClassDeclarationData::Abstract && parent->classType() != ClassDeclarationData::Trait) {
0355                             reportError(i18n("Class %1 contains abstract method %2 and must therefore be declared abstract "
0356                                              "or implement the method.",
0357                                              parent->identifier().toString(),
0358                                              dec->identifier().toString()),
0359                                         node->modifiers);
0360                         } else if (!isEmptyMethodBody(node->methodBody)) {
0361                             reportError(i18n("Abstract function %1 cannot contain body.",
0362                                              dec->toString()), node->methodBody);
0363                         } else if (node->modifiers->modifiers & ModifierFinal) {
0364                             reportError(i18n("Cannot use the final modifier on an abstract class member."),
0365                                         node->modifiers);
0366                         } else {
0367                             dec->setIsAbstract(true);
0368                         }
0369                     }
0370                 } else if (node->modifiers->modifiers & ModifierFinal) {
0371                     dec->setIsFinal(true);
0372                 }
0373                 if (m_reportErrors && !dec->isAbstract() && isEmptyMethodBody(node->methodBody)) {
0374                     reportError(i18n("Non-abstract method %1 must contain body.", dec->toString()), node->methodBody);
0375                 }
0376             }
0377         }
0378 
0379         DeclarationBuilderBase::visitClassStatement(node);
0380 
0381         closeDeclaration();
0382     } else if (node->traitsSequence) {
0383         DeclarationBuilderBase::visitClassStatement(node);
0384 
0385         importTraitMethods(node);
0386     } else if (node->constsSequence) {
0387         if (node->modifiers) {
0388             m_currentModifers = node->modifiers->modifiers;
0389             if (m_reportErrors) {
0390                 // have to report the errors here to get a good problem range
0391                 if (m_currentModifers & ModifierFinal) {
0392                     reportError(i18n("Cannot use 'final' as constant modifier"), node->modifiers);
0393                 }
0394                 if (m_currentModifers & ModifierStatic) {
0395                     reportError(i18n("Cannot use 'static' as constant modifier"), node->modifiers);
0396                 }
0397                 if (m_currentModifers & ModifierAbstract) {
0398                     reportError(i18n("Cannot use 'abstract' as constant modifier"), node->modifiers);
0399                 }
0400             }
0401         } else {
0402             m_currentModifers = 0;
0403         }
0404         DeclarationBuilderBase::visitClassStatement(node);
0405         m_currentModifers = 0;
0406     } else {
0407         if (node->modifiers) {
0408             m_currentModifers = node->modifiers->modifiers;
0409             if (m_reportErrors) {
0410                 // have to report the errors here to get a good problem range
0411                 if (m_currentModifers & ModifierFinal) {
0412                     reportError(i18n("Properties cannot be declared final."), node->modifiers);
0413                 }
0414                 if (m_currentModifers & ModifierAbstract) {
0415                     reportError(i18n("Properties cannot be declared abstract."), node->modifiers);
0416                 }
0417             }
0418         } else {
0419             m_currentModifers = 0;
0420         }
0421         DeclarationBuilderBase::visitClassStatement(node);
0422         m_currentModifers = 0;
0423     }
0424 }
0425 
0426 void DeclarationBuilder::importTraitMethods(ClassStatementAst *node)
0427 {
0428     // Add trait members that don't need special handling
0429     const KDevPG::ListNode< NamespacedIdentifierAst* >* it = node->traitsSequence->front();
0430     DUChainWriteLocker lock;
0431     forever {
0432         DeclarationPointer dec =  findDeclarationImport(ClassDeclarationType, identifierForNamespace(it->element, m_editor));
0433 
0434         if (!dec || !dec->internalContext()) {
0435             break;
0436         }
0437 
0438         QVector <Declaration*> declarations = dec.data()->internalContext()->localDeclarations(nullptr);
0439         QVector <Declaration*> localDeclarations = currentContext()->localDeclarations(nullptr);
0440 
0441         ifDebug(qCDebug(DUCHAIN) << "Importing from" << dec.data()->identifier().toString() << "to" << currentContext()->localScopeIdentifier().toString();)
0442 
0443         foreach (Declaration* import, declarations) {
0444             Declaration* found = nullptr;
0445             foreach (Declaration* local, localDeclarations) {
0446                 ifDebug(qCDebug(DUCHAIN) << "Comparing" << import->identifier().toString() << "with" << local->identifier().toString();)
0447                 if (auto trait = dynamic_cast<TraitMethodAliasDeclaration*>(local)) {
0448                     if (trait->aliasedDeclaration().data() == import) {
0449                         ifDebug(qCDebug(DUCHAIN) << "Already imported";)
0450                         found = local;
0451                         break;
0452                     }
0453                     if (local->identifier() == import->identifier()) {
0454                         ClassMethodDeclaration* importMethod = dynamic_cast<ClassMethodDeclaration*>(import);
0455                         if (trait->isOverriding(import->context()->indexedLocalScopeIdentifier())) {
0456                             ifDebug(qCDebug(DUCHAIN) << "Is overridden";)
0457                             found = local;
0458                             break;
0459                         } else if (importMethod) {
0460                             reportError(
0461                                 i18n("Trait method %1 has not been applied, because there are collisions with other trait methods on %2")
0462                                 .arg(importMethod->prettyName().str(),
0463                                      dynamic_cast<ClassDeclaration*>(currentDeclaration())->prettyName().str())
0464                                 , it->element, IProblem::Error
0465                             );
0466                             found = local;
0467                             break;
0468                         }
0469                     }
0470                 }
0471                 if (auto trait = dynamic_cast<TraitMemberAliasDeclaration*>(local)) {
0472                     if (trait->aliasedDeclaration().data() == import) {
0473                         ifDebug(qCDebug(DUCHAIN) << "Already imported";)
0474                         found = local;
0475                         break;
0476                     }
0477                 }
0478                 if (local->identifier() == import->identifier()) {
0479                     if (dynamic_cast<ClassMemberDeclaration*>(local) && dynamic_cast<ClassMemberDeclaration*>(import)) {
0480                         found = local;
0481                         break;
0482                     }
0483                 }
0484             }
0485 
0486             if (found) {
0487                 setEncountered(found);
0488                 continue;
0489             }
0490 
0491             ifDebug(qCDebug(DUCHAIN) << "Importing new declaration";)
0492 
0493             CursorInRevision cursor = m_editor->findRange(it->element).start;
0494 
0495             if (auto olddec = dynamic_cast<const ClassMethodDeclaration*>(import)) {
0496                 TraitMethodAliasDeclaration* newdec = openDefinition<TraitMethodAliasDeclaration>(olddec->qualifiedIdentifier(), RangeInRevision(cursor, cursor));
0497                 openAbstractType(olddec->abstractType());
0498                 newdec->setPrettyName(olddec->prettyName());
0499                 newdec->setAccessPolicy(olddec->accessPolicy());
0500                 newdec->setKind(Declaration::Type);
0501                 newdec->setAliasedDeclaration(IndexedDeclaration(olddec));
0502                 newdec->setStatic(olddec->isStatic());
0503                 closeType();
0504                 closeDeclaration();
0505             } else if (auto olddec = dynamic_cast<const ClassMemberDeclaration*>(import)) {
0506                 TraitMemberAliasDeclaration* newdec = openDefinition<TraitMemberAliasDeclaration>(olddec->qualifiedIdentifier(), RangeInRevision(cursor, cursor));
0507                 openAbstractType(olddec->abstractType());
0508                 newdec->setAccessPolicy(olddec->accessPolicy());
0509                 newdec->setKind(Declaration::Instance);
0510                 newdec->setAliasedDeclaration(IndexedDeclaration(olddec));
0511                 newdec->setStatic(olddec->isStatic());
0512                 closeType();
0513                 closeDeclaration();
0514             }
0515 
0516         }
0517 
0518         if ( it->hasNext() ) {
0519             it = it->next;
0520         } else {
0521             break;
0522         }
0523     }
0524 }
0525 
0526 void DeclarationBuilder::visitClassExtends(ClassExtendsAst *node)
0527 {
0528     addBaseType(node->identifier);
0529 }
0530 
0531 void DeclarationBuilder::visitClassImplements(ClassImplementsAst *node)
0532 {
0533     const KDevPG::ListNode<NamespacedIdentifierAst*> *__it = node->implementsSequence->front(), *__end = __it;
0534     do {
0535         addBaseType(__it->element);
0536         __it = __it->next;
0537     } while (__it != __end);
0538     DeclarationBuilderBase::visitClassImplements(node);
0539 }
0540 
0541 void DeclarationBuilder::visitClassVariable(ClassVariableAst *node)
0542 {
0543     QualifiedIdentifier name = identifierForNode(node->variable);
0544     if (m_reportErrors) {   // check for redeclarations
0545         DUChainWriteLocker lock(DUChain::lock());
0546         Q_ASSERT(currentContext()->type() == DUContext::Class);
0547         foreach(Declaration * dec, currentContext()->findLocalDeclarations(name.first(), startPos(node)))
0548         {
0549             if (wasEncountered(dec) && !dec->isFunctionDeclaration() && dec->abstractType() && !(dec->abstractType()->modifiers() & AbstractType::ConstModifier)) {
0550                 reportRedeclarationError(dec, node);
0551                 break;
0552             }
0553         }
0554     }
0555     openClassMemberDeclaration(node->variable, name);
0556     DeclarationBuilderBase::visitClassVariable(node);
0557     closeDeclaration();
0558 }
0559 
0560 void DeclarationBuilder::openClassMemberDeclaration(AstNode* node, const QualifiedIdentifier &name)
0561 {
0562     DUChainWriteLocker lock(DUChain::lock());
0563 
0564     // dirty hack: declarations of class members outside the class context would
0565     //             make the class context encompass the newRange. This is not what we want.
0566     RangeInRevision oldRange = currentContext()->range();
0567 
0568     RangeInRevision newRange = editorFindRange(node, node);
0569     openDefinition<ClassMemberDeclaration>(name, newRange);
0570 
0571     ClassMemberDeclaration* dec = dynamic_cast<ClassMemberDeclaration*>(currentDeclaration());
0572     Q_ASSERT(dec);
0573     if (m_currentModifers & ModifierPublic) {
0574         dec->setAccessPolicy(Declaration::Public);
0575     } else if (m_currentModifers & ModifierProtected) {
0576         dec->setAccessPolicy(Declaration::Protected);
0577     } else if (m_currentModifers & ModifierPrivate) {
0578         dec->setAccessPolicy(Declaration::Private);
0579     }
0580     if (m_currentModifers & ModifierStatic) {
0581         dec->setStatic(true);
0582     }
0583     dec->setKind(Declaration::Instance);
0584 
0585     currentContext()->setRange(oldRange);
0586 }
0587 
0588 void DeclarationBuilder::declareClassMember(DUContext *parentCtx, AbstractType::Ptr type,
0589                                                 const QualifiedIdentifier& identifier,
0590                                                 AstNode* node )
0591 {
0592     if ( m_upcomingClassVariables.contains(identifier) ) {
0593         if (m_actuallyRecompiling) {
0594             DUChainWriteLocker lock;
0595             if (Declaration* dec = currentContext()->findDeclarationAt(startPos(node))) {
0596                 if (dynamic_cast<ClassMemberDeclaration*>(dec)) {
0597                     // invalidate declaration, it got added
0598                     // see also bug https://bugs.kde.org/show_bug.cgi?id=241750
0599                     delete dec;
0600                 }
0601             }
0602         }
0603         return;
0604     }
0605 
0606     DUChainWriteLocker lock(DUChain::lock());
0607 
0608     // this member should be public and non-static
0609     m_currentModifers = ModifierPublic;
0610     injectContext(parentCtx);
0611     openClassMemberDeclaration(node, identifier);
0612     m_currentModifers = 0;
0613     //own closeDeclaration() that doesn't use lastType()
0614     currentDeclaration()->setType(type);
0615     eventuallyAssignInternalContext();
0616     DeclarationBuilderBase::closeDeclaration();
0617     closeInjectedContext();
0618 }
0619 
0620 void DeclarationBuilder::visitConstantDeclaration(ConstantDeclarationAst *node)
0621 {
0622     DUChainWriteLocker lock(DUChain::lock());
0623     if (m_reportErrors) {
0624         // check for redeclarations
0625         foreach(Declaration * dec, currentContext()->findLocalDeclarations(identifierForNode(node->identifier).first(), startPos(node->identifier)))
0626         {
0627             if (wasEncountered(dec) && !dec->isFunctionDeclaration() && dec->abstractType() && dec->abstractType()->modifiers() & AbstractType::ConstModifier) {
0628                 reportRedeclarationError(dec, node->identifier);
0629                 break;
0630             }
0631         }
0632     }
0633     ClassMemberDeclaration* dec = openDefinition<ClassMemberDeclaration>(identifierForNode(node->identifier), m_editor->findRange(node->identifier));
0634     {
0635         DUChainWriteLocker lock(DUChain::lock());
0636         dec->setAccessPolicy(Declaration::Public);
0637         dec->setStatic(true);
0638         dec->setKind(Declaration::Instance);
0639     }
0640     DeclarationBuilderBase::visitConstantDeclaration(node);
0641     closeDeclaration();
0642 }
0643 
0644 void DeclarationBuilder::visitClassConstantDeclaration(ClassConstantDeclarationAst *node)
0645 {
0646     DUChainWriteLocker lock;
0647     if (m_reportErrors) {
0648         // Check for constants in traits
0649         if (isMatch(currentDeclaration(), ClassDeclarationType)) {
0650             ClassDeclaration *parent =  dynamic_cast<ClassDeclaration*>(currentDeclaration());
0651             Q_ASSERT(parent);
0652 
0653             if (parent->classType() == ClassDeclarationData::Trait) {
0654                 reportError(i18n("Traits cannot have constants."), node);
0655             }
0656         }
0657 
0658         // check for 'class' constant
0659         if (identifierForNode(node->identifier).toString().toLower() == QLatin1String("class"))
0660         {
0661             reportError(i18n("A class constant must not be called 'class'; it is reserved for class name fetching"), node);
0662         }
0663 
0664         // check for redeclarations
0665         foreach(Declaration * dec, currentContext()->findLocalDeclarations(identifierForNode(node->identifier).first(), startPos(node->identifier)))
0666         {
0667             if (wasEncountered(dec) && !dec->isFunctionDeclaration() && dec->abstractType() && dec->abstractType()->modifiers() & AbstractType::ConstModifier) {
0668                 reportRedeclarationError(dec, node->identifier);
0669                 break;
0670             }
0671         }
0672     }
0673     ClassMemberDeclaration* dec = openDefinition<ClassMemberDeclaration>(identifierForNode(node->identifier), m_editor->findRange(node->identifier));
0674     if (m_currentModifers & ModifierProtected) {
0675         dec->setAccessPolicy(Declaration::Protected);
0676     } else if (m_currentModifers & ModifierPrivate) {
0677         dec->setAccessPolicy(Declaration::Private);
0678     } else {
0679         dec->setAccessPolicy(Declaration::Public);
0680     }
0681     dec->setStatic(true);
0682     dec->setKind(Declaration::Instance);
0683     lock.unlock();
0684 
0685     DeclarationBuilderBase::visitClassConstantDeclaration(node);
0686     closeDeclaration();
0687 }
0688 
0689 void DeclarationBuilder::visitTraitAliasStatement(TraitAliasStatementAst *node)
0690 {
0691     DUChainWriteLocker lock;
0692 
0693     DeclarationPointer dec = findDeclarationImport(ClassDeclarationType, identifierForNamespace(node->importIdentifier->identifier, m_editor));
0694 
0695     if (dec && dec.data()->internalContext()) {
0696         createTraitAliasDeclarations(node, dec);
0697     }
0698 
0699     lock.unlock();
0700     DeclarationBuilderBase::visitTraitAliasStatement(node);
0701 }
0702 
0703 void DeclarationBuilder::createTraitAliasDeclarations(TraitAliasStatementAst *node, DeclarationPointer dec)
0704 {
0705     QualifiedIdentifier original = identifierPairForNode(node->importIdentifier->methodIdentifier).second;
0706     QList <Declaration*> list = dec.data()->internalContext()->findLocalDeclarations(original.last(), dec.data()->internalContext()->range().start);
0707 
0708     QualifiedIdentifier alias;
0709     if (node->aliasIdentifier) {
0710         alias = identifierPairForNode(node->aliasIdentifier).second;
0711     } else if (node->aliasNonModifierIdentifier) {
0712         alias = identifierPairForNode(node->aliasNonModifierIdentifier).second;
0713     } else {
0714         alias = original;
0715     }
0716 
0717     if (!list.isEmpty()) {
0718         ClassMethodDeclaration* olddec = dynamic_cast<ClassMethodDeclaration*>(list.first());
0719         TraitMethodAliasDeclaration* newdec;
0720 
0721         // no existing declaration found, create one
0722         if (node->aliasIdentifier || node->aliasNonModifierIdentifier) {
0723             if (node->aliasIdentifier) {
0724                 newdec = openDefinition<TraitMethodAliasDeclaration>(alias, m_editor->findRange(node->aliasIdentifier));
0725                 newdec->setPrettyName(identifierPairForNode(node->aliasIdentifier).first);
0726             } else {
0727                 newdec = openDefinition<TraitMethodAliasDeclaration>(alias, m_editor->findRange(node->aliasNonModifierIdentifier));
0728                 newdec->setPrettyName(identifierPairForNode(node->aliasNonModifierIdentifier).first);
0729             }
0730             newdec->setAccessPolicy(olddec->accessPolicy());
0731             openAbstractType(olddec->abstractType());
0732             if (node->modifiers) {
0733                 if (node->modifiers->modifiers & ModifierPublic) {
0734                     newdec->setAccessPolicy(Declaration::Public);
0735                 } else if (node->modifiers->modifiers & ModifierProtected) {
0736                     newdec->setAccessPolicy(Declaration::Protected);
0737                 } else if (node->modifiers->modifiers & ModifierPrivate) {
0738                     newdec->setAccessPolicy(Declaration::Private);
0739                 }
0740 
0741                 if (node->modifiers->modifiers & ModifierAbstract) {
0742                     reportError(i18n("Cannot use 'abstract' as method modifier"), node->modifiers, IProblem::Error);
0743                 }
0744                 if (node->modifiers->modifiers & ModifierFinal) {
0745                     reportError(i18n("Cannot use 'final' as method modifier"), node->modifiers, IProblem::Error);
0746                 }
0747                 if (node->modifiers->modifiers & ModifierStatic) {
0748                     reportError(i18n("Cannot use 'static' as method modifier"), node->modifiers, IProblem::Error);
0749                 }
0750             }
0751         } else {
0752             CursorInRevision cursor = m_editor->findRange(node->importIdentifier).start;
0753             newdec = openDefinition<TraitMethodAliasDeclaration>(alias, RangeInRevision(cursor, cursor));
0754             newdec->setPrettyName(identifierPairForNode(node->importIdentifier->methodIdentifier).first);
0755             newdec->setAccessPolicy(olddec->accessPolicy());
0756             openAbstractType(olddec->abstractType());
0757 
0758             if (node->modifiers) {
0759                 if (node->modifiers->modifiers & ModifierPublic) {
0760                     newdec->setAccessPolicy(Declaration::Public);
0761                 } else if (node->modifiers->modifiers & ModifierProtected) {
0762                     newdec->setAccessPolicy(Declaration::Protected);
0763                 } else if (node->modifiers->modifiers & ModifierPrivate) {
0764                     newdec->setAccessPolicy(Declaration::Private);
0765                 }
0766 
0767                 if (node->modifiers->modifiers & ModifierAbstract) {
0768                     reportError(i18n("Cannot use 'abstract' as method modifier"), node->modifiers, IProblem::Error);
0769                 }
0770                 if (node->modifiers->modifiers & ModifierFinal) {
0771                     reportError(i18n("Cannot use 'final' as method modifier"), node->modifiers, IProblem::Error);
0772                 }
0773                 if (node->modifiers->modifiers & ModifierStatic) {
0774                     reportError(i18n("Cannot use 'static' as method modifier"), node->modifiers, IProblem::Error);
0775                 }
0776             }
0777         }
0778         newdec->setKind(Declaration::Type);
0779         newdec->setAliasedDeclaration(IndexedDeclaration(olddec));
0780         newdec->setStatic(olddec->isStatic());
0781 
0782         QVector <IndexedQualifiedIdentifier> ids;
0783 
0784         if (node->conflictIdentifierSequence) {
0785             const KDevPG::ListNode< NamespacedIdentifierAst* >* it = node->conflictIdentifierSequence->front();
0786             forever {
0787                 DeclarationPointer dec =  findDeclarationImport(ClassDeclarationType, identifierForNamespace(it->element, m_editor));
0788                 if (dec) {
0789                     ids.append(IndexedQualifiedIdentifier(dec.data()->qualifiedIdentifier()));
0790                 }
0791 
0792                 if ( it->hasNext() ) {
0793                     it = it->next;
0794                 } else {
0795                     break;
0796                 }
0797             }
0798 
0799             newdec->setOverrides(ids);
0800         }
0801 
0802         closeType();
0803         closeDeclaration();
0804     }
0805 }
0806 
0807 void DeclarationBuilder::visitParameterList(ParameterListAst* node)
0808 {
0809     PushValue<ParameterAst*> push(m_functionDeclarationPreviousArgument, nullptr);
0810 
0811     DeclarationBuilderBase::visitParameterList(node);
0812 }
0813 
0814 void DeclarationBuilder::visitParameter(ParameterAst *node)
0815 {
0816     AbstractFunctionDeclaration* funDec = dynamic_cast<AbstractFunctionDeclaration*>(currentDeclaration());
0817     Q_ASSERT(funDec);
0818 
0819     if (node->defaultValue) {
0820         QString symbol = m_editor->parseSession()->symbol(node->defaultValue);
0821         funDec->addDefaultParameter(IndexedString(symbol));
0822         if (node->isVariadic != -1) {
0823             reportError(i18n("Variadic parameter cannot have a default value"), node->defaultValue);
0824         } else if (node->parameterType && node->parameterType->typehint && hasClassTypehint(node->parameterType->typehint, m_editor) &&
0825                 symbol.compare(QLatin1String("null"), Qt::CaseInsensitive) != 0) {
0826             reportError(i18n("Default value for parameters with a class type hint can only be NULL."), node->defaultValue);
0827         }
0828     } else {
0829         funDec->addDefaultParameter(IndexedString{});
0830     }
0831     {
0832         // create variable declaration for argument
0833         DUChainWriteLocker lock(DUChain::lock());
0834         RangeInRevision newRange = editorFindRange(node->variable, node->variable);
0835         VariableDeclaration *dec = openDefinition<VariableDeclaration>(identifierForNode(node->variable), newRange);
0836         dec->setKind(Declaration::Instance);
0837         dec->setVariadic(node->isVariadic != -1);
0838     }
0839 
0840     DeclarationBuilderBase::visitParameter(node);
0841 
0842     if (m_functionDeclarationPreviousArgument && m_functionDeclarationPreviousArgument->isVariadic != -1) {
0843         reportError(i18n("Only the last parameter can be variadic."), m_functionDeclarationPreviousArgument);
0844     }
0845 
0846     closeDeclaration();
0847 
0848     m_functionDeclarationPreviousArgument = node;
0849 }
0850 
0851 void DeclarationBuilder::visitFunctionDeclarationStatement(FunctionDeclarationStatementAst* node)
0852 {
0853     isGlobalRedeclaration(identifierForNode(node->functionName), node->functionName, FunctionDeclarationType);
0854 
0855     FunctionDeclaration* dec = m_functions.value(node->functionName->string, nullptr);
0856     Q_ASSERT(dec);
0857     // seems like we have to set that, else the usebuilder crashes
0858 
0859     DeclarationBuilderBase::setEncountered(dec);
0860 
0861     openDeclarationInternal(dec);
0862     openType(dec->abstractType());
0863 
0864     DeclarationBuilderBase::visitFunctionDeclarationStatement(node);
0865 
0866     closeType();
0867     closeDeclaration();
0868 }
0869 
0870 void DeclarationBuilder::visitGenericTypeHint(GenericTypeHintAst* node) {
0871     if (node->genericType && isGenericClassTypehint(node->genericType, m_editor)) {
0872         NamespacedIdentifierAst* typehintNode = node->genericType;
0873         const KDevPG::ListNode< IdentifierAst* >* it = typehintNode->namespaceNameSequence->back();
0874         QString className = m_editor->parseSession()->symbol(it->element);
0875 
0876         if (isReservedClassName(className)) {
0877             reportError(i18n("Cannot use '%1' as class name as it is reserved", className), typehintNode);
0878         }
0879     }
0880 }
0881 
0882 void DeclarationBuilder::visitClosure(ClosureAst* node)
0883 {
0884     setComment(formatComment(node, editor()));
0885     {
0886         DUChainWriteLocker lock;
0887         FunctionDeclaration *dec = openDefinition<FunctionDeclaration>(QualifiedIdentifier(),
0888                                                                        editor()->findRange(node->startToken));
0889         dec->setKind(Declaration::Type);
0890         dec->clearDefaultParameters();
0891     }
0892 
0893     DeclarationBuilderBase::visitClosure(node);
0894 
0895     closeDeclaration();
0896 }
0897 void DeclarationBuilder::visitLexicalVar(LexicalVarAst* node)
0898 {
0899     DeclarationBuilderBase::visitLexicalVar(node);
0900 
0901     QualifiedIdentifier id = identifierForNode(node->variable);
0902     DUChainWriteLocker lock;
0903     if ( recompiling() ) {
0904         // sadly we can't use findLocalDeclarations() here, since it un-aliases declarations
0905         foreach ( Declaration* dec, currentContext()->localDeclarations() ) {
0906             if ( dynamic_cast<AliasDeclaration*>(dec) && dec->identifier() == id.first() ) {
0907                 // don't redeclare but reuse the existing declaration
0908                 encounter(dec);
0909                 return;
0910             }
0911         }
0912     }
0913 
0914     // no existing declaration found, create one
0915     foreach(Declaration* aliasedDeclaration, currentContext()->findDeclarations(id)) {
0916         if (aliasedDeclaration->kind() == Declaration::Instance) {
0917             AliasDeclaration* dec = openDefinition<AliasDeclaration>(id, editor()->findRange(node->variable));
0918             dec->setAliasedDeclaration(aliasedDeclaration);
0919             closeDeclaration();
0920             break;
0921         }
0922     }
0923 }
0924 
0925 bool DeclarationBuilder::isGlobalRedeclaration(const QualifiedIdentifier &identifier, AstNode* node,
0926         DeclarationType type)
0927 {
0928     if (!m_reportErrors) {
0929         return false;
0930     }
0931     ///TODO: method redeclaration etc.
0932     if (type != ClassDeclarationType
0933             && type != FunctionDeclarationType
0934             && type != ConstantDeclarationType) {
0935         // the other types can be redeclared
0936         return false;
0937     }
0938 
0939     DUChainWriteLocker lock(DUChain::lock());
0940     QList<Declaration*> declarations = currentContext()->topContext()->findDeclarations( identifier, startPos(node) );
0941     foreach(Declaration* dec, declarations) {
0942         if (wasEncountered(dec) && isMatch(dec, type)) {
0943             reportRedeclarationError(dec, node);
0944             return true;
0945         }
0946     }
0947     return false;
0948 }
0949 
0950 void DeclarationBuilder::reportRedeclarationError(Declaration* declaration, AstNode* node)
0951 {
0952     if (declaration->range().contains(startPos(node))) {
0953         // make sure this is not a wrongly reported redeclaration error
0954         return;
0955     }
0956     if (declaration->context()->topContext()->url() == internalFunctionFile()) {
0957         reportError(i18n("Cannot redeclare PHP internal %1.", declaration->toString()), node);
0958     } else if (auto trait = dynamic_cast<TraitMemberAliasDeclaration*>(declaration)) {
0959         reportError(
0960             i18n("%1 and %2 define the same property (%3) in the composition of %1. This might be incompatible, to improve maintainability consider using accessor methods in traits instead.")
0961             .arg(dynamic_cast<ClassDeclaration*>(currentDeclaration())->prettyName().str(),
0962                  dynamic_cast<ClassDeclaration*>(trait->aliasedDeclaration().data()->context()->owner())->prettyName().str(),
0963                  dynamic_cast<ClassMemberDeclaration*>(trait)->identifier().toString()), node, IProblem::Warning
0964         );
0965     } else {
0966         ///TODO: try to shorten the filename by removing the leading path to the current project
0967         reportError(
0968             i18n("Cannot redeclare %1, already declared in %2 on line %3.",
0969                  declaration->toString(), declaration->context()->topContext()->url().str(), declaration->range().start.line + 1
0970                 ), node
0971         );
0972     }
0973 }
0974 void DeclarationBuilder::visitOuterTopStatement(OuterTopStatementAst* node)
0975 {
0976     //docblock of an AssignmentExpression
0977     setComment(formatComment(node, m_editor));
0978     m_lastTopStatementComment = m_editor->parseSession()->docComment(node->startToken);
0979 
0980     DeclarationBuilderBase::visitOuterTopStatement(node);
0981 }
0982 
0983 void DeclarationBuilder::visitAssignmentExpression(AssignmentExpressionAst* node)
0984 {
0985     if ( node->assignmentExpressionEqual ) {
0986         PushValue<FindVariableResults> restore(m_findVariable);
0987 
0988         DeclarationBuilderBase::visitAssignmentExpression(node);
0989     } else {
0990         DeclarationBuilderBase::visitAssignmentExpression(node);
0991     }
0992 }
0993 
0994 void DeclarationBuilder::visitVariable(VariableAst* node)
0995 {
0996     if ( m_findVariable.find ) {
0997         getVariableIdentifier(node, m_findVariable.identifier, m_findVariable.parentIdentifier,
0998                               m_findVariable.node, m_findVariable.isArray);
0999         m_findVariable.find = false;
1000     }
1001     DeclarationBuilderBase::visitVariable(node);
1002 }
1003 
1004 void DeclarationBuilder::declareVariable(DUContext* parentCtx, AbstractType::Ptr type,
1005                                             const QualifiedIdentifier& identifier,
1006                                             AstNode* node)
1007 {
1008     DUChainWriteLocker lock(DUChain::lock());
1009 
1010     // we must not re-assign $this in a class context
1011     /// Qualified identifier for 'this'
1012     static const QualifiedIdentifier thisQId(QStringLiteral("this"));
1013     if ( identifier == thisQId
1014             && currentContext()->parentContext()
1015             && currentContext()->parentContext()->type() == DUContext::Class ) {
1016 
1017         // checks if imports \ArrayAccess
1018         ClassDeclaration* currentClass = dynamic_cast<ClassDeclaration*>(currentContext()->parentContext()->owner());
1019         ClassDeclaration* arrayAccess = nullptr;
1020 
1021         auto imports = currentContext()->parentContext()->importedParentContexts();
1022         for( const DUContext::Import& ctx : imports ) {
1023             DUContext* import = ctx.context(topContext());
1024             if(import->type() == DUContext::Class) {
1025                 ClassDeclaration* importedClass = dynamic_cast<ClassDeclaration*>(import->owner());
1026                 if(importedClass) {
1027                     if(importedClass->prettyName().str() == "ArrayAccess" && importedClass->classType() == ClassDeclarationData::ClassType::Interface && !import->parentContext()->owner()) {
1028                         arrayAccess = importedClass;
1029                     }
1030                 }
1031             }
1032         }
1033 
1034         IntegralType* thisVar = static_cast<IntegralType*>(type.data());
1035         // check if this is used as array
1036         if(arrayAccess && currentClass && thisVar && thisVar->dataType() == AbstractType::TypeArray)
1037         {
1038             uint noOfFunc = 0;
1039             auto declarations = currentContext()->parentContext()->localDeclarations();
1040             // check if class implements all 4 functions
1041             for(auto &dec : declarations) {
1042                 if(dec->isFunctionDeclaration()) {
1043                     QualifiedIdentifier func = dec->qualifiedIdentifier();
1044                     QString funcname = func.last().identifier().str();
1045                     if(funcname == "offsetexists" || funcname == "offsetget" || funcname == "offsetset" || funcname == "offsetunset") {
1046                         noOfFunc++;
1047                     }
1048                 }
1049             }
1050 
1051             if(noOfFunc < 4) {
1052                 // check if class is not abstract
1053                 if(currentClass->classModifier() != ClassDeclarationData::ClassModifier::Abstract) {
1054                     reportError(i18n("Class %1 contains %2 abstract methods and must therefore be declared abstract or implement the remaining methods.",currentClass->prettyName().str(),4-noOfFunc), QList<AstNode*>() << node);
1055                 }
1056             }
1057 
1058             return;
1059         }
1060 
1061         reportError(i18n("Cannot re-assign $this."), QList<AstNode*>() << node);
1062         return;
1063     }
1064 
1065     const RangeInRevision newRange = editorFindRange(node, node);
1066 
1067     // check if this variable is already declared
1068     {
1069         QList< Declaration* > decs = parentCtx->findDeclarations(identifier.first(), startPos(node), nullptr, DUContext::DontSearchInParent);
1070         if ( !decs.isEmpty() ) {
1071             QList< Declaration* >::const_iterator it = decs.constEnd() - 1;
1072             while ( true ) {
1073                 // we expect that the list of declarations has the newest declaration at back
1074                 if ( dynamic_cast<VariableDeclaration*>( *it ) ) {
1075                     if (!wasEncountered(*it)) {
1076                         encounter(*it);
1077                         // force new range https://bugs.kde.org/show_bug.cgi?id=262189,
1078                         // might be wrong when we had syntax errors in there before
1079                         (*it)->setRange(newRange);
1080                     }
1081                     if ( (*it)->abstractType() && !(*it)->abstractType()->equals(type.data()) ) {
1082                         // if it's currently mixed and we now get something more definite, use that instead
1083                         if ( auto rType = (*it)->abstractType().dynamicCast<ReferenceType>() ) {
1084                             if ( auto integral = rType->baseType().dynamicCast<IntegralType>() ) {
1085                                 if ( integral->dataType() == IntegralType::TypeMixed ) {
1086                                     // referenced mixed to referenced @p type
1087                                     ReferenceType::Ptr newType(new ReferenceType());
1088                                     newType->setBaseType(type);
1089                                     (*it)->setType(newType);
1090                                     return;
1091                                 }
1092                             }
1093                         }
1094                         if ( auto integral = (*it)->abstractType().dynamicCast<IntegralType>() ) {
1095                             if ( integral->dataType() == IntegralType::TypeMixed ) {
1096                                 // mixed to @p type
1097                                 (*it)->setType(type);
1098                                 return;
1099                             }
1100                         }
1101                         // else make it unsure
1102                         auto unsure = (*it)->abstractType().dynamicCast<UnsureType>();
1103                         // maybe it's referenced?
1104                         auto rType = (*it)->abstractType().dynamicCast<ReferenceType>();
1105                         if ( !unsure && rType ) {
1106                             unsure = rType->baseType().dynamicCast<UnsureType>();
1107                         }
1108                         if ( !unsure ) {
1109                             unsure = UnsureType::Ptr(new UnsureType());
1110                             if ( rType ) {
1111                                 unsure->addType(rType->baseType()->indexed());
1112                             } else {
1113                                 unsure->addType((*it)->indexedType());
1114                             }
1115                         }
1116                         unsure->addType(type->indexed());
1117                         if ( rType ) {
1118                             rType->setBaseType(AbstractType::Ptr(unsure.data()));
1119                             (*it)->setType(rType);
1120                         } else {
1121                             (*it)->setType(unsure);
1122                         }
1123                     }
1124                     return;
1125                 }
1126                 if ( it == decs.constBegin() ) {
1127                     break;
1128                 }
1129                 --it;
1130             }
1131         }
1132     }
1133 
1134     VariableDeclaration *dec = openDefinition<VariableDeclaration>(identifier, newRange);
1135     dec->setKind(Declaration::Instance);
1136     if (!m_lastTopStatementComment.isEmpty()) {
1137         QRegExp rx("(\\*|///)\\s*@superglobal");
1138         if (rx.indexIn(m_lastTopStatementComment) != -1) {
1139             dec->setSuperglobal(true);
1140         }
1141     }
1142     //own closeDeclaration() that doesn't use lastType()
1143     dec->setType(type);
1144 
1145     // variable declarations are not namespaced in PHP
1146     if (currentContext()->type() == DUContext::Namespace) {
1147         dec->setContext(currentContext()->topContext());
1148     }
1149 
1150     eventuallyAssignInternalContext();
1151     DeclarationBuilderBase::closeDeclaration();
1152 }
1153 
1154 DUContext* getClassContext(const QualifiedIdentifier &identifier, DUContext* currentCtx) {
1155     /// Qualified identifier for 'this'
1156     static const QualifiedIdentifier thisQId(QStringLiteral("this"));
1157     if ( identifier == thisQId ) {
1158         if ( currentCtx->parentContext() && currentCtx->parentContext()->type() == DUContext::Class ) {
1159             return currentCtx->parentContext();
1160         }
1161     } else {
1162         DUChainReadLocker lock(DUChain::lock());
1163         foreach( Declaration* parent, currentCtx->topContext()->findDeclarations(identifier) ) {
1164             if ( StructureType::Ptr ctype = parent->type<StructureType>() ) {
1165                 return ctype->internalContext(currentCtx->topContext());
1166             }
1167         }
1168         ///TODO: if we can't find anything here we might have to use the findDeclarationImport helper
1169     }
1170     return nullptr;
1171 }
1172 
1173 ///TODO: we need to handle assignment to array-members properly
1174 ///      currently we just make sure the array is declared, but don't know
1175 ///      anything about its contents
1176 void DeclarationBuilder::visitAssignmentExpressionEqual(AssignmentExpressionEqualAst *node)
1177 {
1178     DeclarationBuilderBase::visitAssignmentExpressionEqual(node);
1179 
1180     bool alreadyDeclared = false;
1181 
1182     // check for already declared class members
1183     if (!m_findVariable.identifier.isEmpty() && !m_findVariable.parentIdentifier.isEmpty()) {
1184         DUContext* ctx = getClassContext(m_findVariable.parentIdentifier, currentContext());
1185         if (ctx) {
1186             DUChainReadLocker lock(DUChain::lock());
1187             ifDebug(qCDebug(DUCHAIN) << "checking if already declared: " << m_findVariable.identifier.toString();)
1188             QList<Declaration*> decs;
1189             foreach ( Declaration* dec, currentContext()->findDeclarations(m_findVariable.identifier) ) {
1190                 if ( dec->kind() == Declaration::Kind::Instance) {
1191                     if (dec->range() == editorFindRange(m_findVariable.node)) {
1192                         // Don't reuse previous declarations as the type might have changed.
1193                         continue;
1194                     }
1195 
1196                     ClassMemberDeclaration *classDec = dynamic_cast<ClassMemberDeclaration*>(dec);
1197 
1198                     if (classDec && classDec->accessPolicy() == Declaration::Private) {
1199                         if (currentContext()->parentContext() == dec->context()) {
1200                             decs << dec;
1201                             ifDebug(qCDebug(DUCHAIN) << "found class property:" << dec->toString();)
1202                         }
1203                     } else {
1204                         decs << dec;
1205                         ifDebug(qCDebug(DUCHAIN) << "found class property:" << dec->toString();)
1206                     }
1207                 }
1208             }
1209             lock.unlock();
1210 
1211             if (!decs.isEmpty()) {
1212                 Declaration * dec = decs.last();
1213 
1214                 if (dec) {
1215                     encounter(dec);
1216                     alreadyDeclared = true;
1217                     IntegralType::Ptr type = dec->type<IntegralType>();
1218 
1219                     if (type && type->dataType() == IntegralType::TypeNull) {
1220                         DUChainWriteLocker wlock;
1221                         dec->setAbstractType(currentAbstractType());
1222                     }
1223                 }
1224             }
1225 
1226             lock.lock();
1227             if (decs.isEmpty() && (!currentContext()->parentContext() || !currentContext()->parentContext()->imports(ctx))) {
1228                 ifDebug(qCDebug(DUCHAIN) << "nothing found in current context, look in class context of parent";)
1229                 QList<Declaration*> decs;
1230                 foreach ( Declaration* dec, ctx->findDeclarations(m_findVariable.identifier) ) {
1231                     if ( dec->kind() == Declaration::Kind::Instance) {
1232                         if (dec->range() == editorFindRange(m_findVariable.node)) {
1233                             // Don't reuse previous declarations as the type might have changed.
1234                             continue;
1235                         }
1236 
1237                         ifDebug(qCDebug(DUCHAIN) << "found class property:" << dec->toString();)
1238                         decs << dec;
1239                     }
1240                 }
1241                 lock.unlock();
1242 
1243                 if (!decs.isEmpty()) {
1244                     Declaration * dec = decs.last();
1245 
1246                     if (dec) {
1247                         alreadyDeclared = true;
1248                         IntegralType::Ptr type = dec->type<IntegralType>();
1249 
1250                         // check for redeclaration of private or protected stuff
1251                         DUContext *parentCtx = currentContext()->parentContext();
1252                         ClassMemberDeclaration *classDec = dynamic_cast<ClassMemberDeclaration*>(dec);
1253 
1254                         if (classDec && classDec->accessPolicy() == Declaration::Private && classDec->context() != parentCtx) {
1255                             reportError(i18n("Cannot access private property %1",
1256                                                 classDec->toString()), m_findVariable.node);
1257                         } else if (classDec && classDec->accessPolicy() == Declaration::Protected && classDec->context() != parentCtx) {
1258                             reportError(i18n("Cannot access protected property %1",
1259                                                 classDec->toString()), m_findVariable.node);
1260                         } else if (type && type->dataType() == IntegralType::TypeNull) {
1261                             DUChainWriteLocker wlock;
1262                             dec->setAbstractType(currentAbstractType());
1263                         }
1264                     }
1265                 }
1266             }
1267         }
1268     }
1269 
1270     if ( !alreadyDeclared && !m_findVariable.identifier.isEmpty() && currentAbstractType()) {
1271         ifDebug(qCDebug(DUCHAIN) << "not yet declared: " << m_findVariable.identifier.toString();)
1272         //create new declaration assignments to not-yet declared variables and class members
1273 
1274         AbstractType::Ptr type;
1275         if ( m_findVariable.isArray ) {
1276             // implicit array declaration
1277             type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray));
1278         } else {
1279             type = currentAbstractType();
1280         }
1281 
1282         if ( !m_findVariable.parentIdentifier.isEmpty() ) {
1283             // assignment to class members
1284 
1285             if ( DUContext* ctx = getClassContext(m_findVariable.parentIdentifier, currentContext()) ) {
1286                 declareClassMember(ctx, type, m_findVariable.identifier, m_findVariable.node);
1287             }
1288         } else {
1289             // assignment to other variables
1290             declareVariable(currentContext(), type, m_findVariable.identifier, m_findVariable.node );
1291         }
1292     }
1293 }
1294 
1295 void DeclarationBuilder::visitFunctionCall(FunctionCallAst* node)
1296 {
1297     QualifiedIdentifier id;
1298     if (!m_isInternalFunctions) {
1299         FunctionType::Ptr oldFunction = m_currentFunctionType;
1300 
1301         DeclarationPointer dec;
1302         if ( node->stringFunctionName ) {
1303             dec = findDeclarationImport(FunctionDeclarationType, node->stringFunctionName);
1304 
1305             if (!dec) {
1306                 dec = findDeclarationImport(FunctionDeclarationType, node->stringFunctionName, GlobalScope);
1307             }
1308         } else if ( node->stringFunctionNameOrClass ) {
1309             id = identifierForNamespace(node->stringFunctionNameOrClass, m_editor);
1310             dec = findDeclarationImport(FunctionDeclarationType, id);
1311 
1312             if (!dec) {
1313                 id.setExplicitlyGlobal(true);
1314                 dec = findDeclarationImport(FunctionDeclarationType, id);
1315             }
1316         } else {
1317             ///TODO: node->varFunctionName
1318         }
1319 
1320         if ( dec ) {
1321             m_currentFunctionType = dec->type<FunctionType>();
1322         } else {
1323             m_currentFunctionType = nullptr;
1324         }
1325 
1326         DeclarationBuilderBase::visitFunctionCall(node);
1327 
1328         m_currentFunctionType = oldFunction;
1329     } else {
1330         // optimize for internal function file
1331         DeclarationBuilderBase::visitFunctionCall(node);
1332     }
1333 
1334     if (node->stringFunctionNameOrClass && !node->stringFunctionName && !node->varFunctionName) {
1335         if (id.toString(RemoveExplicitlyGlobalPrefix) == QLatin1String("define")
1336                 && node->stringParameterList && node->stringParameterList->parametersSequence
1337                 && node->stringParameterList->parametersSequence->count() > 0) {
1338             //constant, defined through define-function
1339 
1340             //find name of the constant (first argument of the function call)
1341             CommonScalarAst* scalar = findCommonScalar(node->stringParameterList->parametersSequence->at(0)->element);
1342             if (scalar && scalar->string != -1) {
1343                 QString constant = m_editor->parseSession()->symbol(scalar->string);
1344                 constant = constant.mid(1, constant.length() - 2);
1345                 RangeInRevision newRange = editorFindRange(scalar, scalar);
1346                 AbstractType::Ptr type;
1347                 if (node->stringParameterList->parametersSequence->count() > 1) {
1348                     type = getTypeForNode(node->stringParameterList->parametersSequence->at(1)->element);
1349                     Q_ASSERT(type);
1350                     type->setModifiers(type->modifiers() | AbstractType::ConstModifier);
1351                 } // TODO: else report error?
1352                 DUChainWriteLocker lock;
1353                 // find fitting context to put define in,
1354                 // pick first namespace or global context otherwise
1355                 DUContext* ctx = currentContext();
1356                 while (ctx->type() != DUContext::Namespace && ctx->parentContext()) {
1357                     ctx = ctx->parentContext();
1358                 }
1359                 injectContext(ctx); //constants are always global
1360                 QualifiedIdentifier identifier(constant);
1361                 isGlobalRedeclaration(identifier, scalar, ConstantDeclarationType);
1362                 Declaration* dec = openDefinition<Declaration>(identifier, newRange);
1363                 dec->setKind(Declaration::Instance);
1364                 if (type) {
1365                     dec->setType(type);
1366                     injectType(type);
1367                 }
1368                 closeDeclaration();
1369                 closeInjectedContext();
1370             }
1371         }
1372     }
1373 }
1374 
1375 void DeclarationBuilder::visitFunctionCallParameterList(FunctionCallParameterListAst* node)
1376 {
1377     PushValue<FunctionCallParameterListElementAst*> push(m_functionCallPreviousArgument, nullptr);
1378     PushValue<int> pos(m_functionCallParameterPos, 0);
1379 
1380     DeclarationBuilderBase::visitFunctionCallParameterList(node);
1381 }
1382 
1383 void DeclarationBuilder::visitFunctionCallParameterListElement(FunctionCallParameterListElementAst* node)
1384 {
1385     PushValue<FindVariableResults> restore(m_findVariable);
1386 
1387     DeclarationBuilderBase::visitFunctionCallParameterListElement(node);
1388 
1389     if ( m_findVariable.node && m_currentFunctionType &&
1390             m_currentFunctionType->arguments().count() > m_functionCallParameterPos) {
1391         ReferenceType::Ptr refType = m_currentFunctionType->arguments()
1392                                         .at(m_functionCallParameterPos).dynamicCast<ReferenceType>();
1393         if ( refType ) {
1394             // this argument is referenced, so if the node contains undeclared variables we have
1395             // to declare them with a NULL type, see also:
1396             // https://de.php.net/manual/en/language.references.whatdo.php
1397 
1398             // declare with NULL type, just like PHP does
1399             declareFoundVariable(AbstractType::Ptr(new IntegralType(IntegralType::TypeNull)));
1400         }
1401     }
1402 
1403     if (m_functionCallPreviousArgument && m_functionCallPreviousArgument->isVariadic != -1 && node->isVariadic == -1) {
1404         reportError(i18n("Cannot use positional argument after argument unpacking"), node);
1405     }
1406 
1407     m_functionCallPreviousArgument = node;
1408 
1409     ++m_functionCallParameterPos;
1410 }
1411 
1412 void DeclarationBuilder::visitAssignmentListElement(AssignmentListElementAst* node)
1413 {
1414     PushValue<FindVariableResults> restore(m_findVariable);
1415 
1416     DeclarationBuilderBase::DefaultVisitor::visitAssignmentListElement(node);
1417 
1418     if ( m_findVariable.node ) {
1419         ///TODO: get a proper type here, if possible
1420         declareFoundVariable(AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed)));
1421     }
1422 }
1423 
1424 void DeclarationBuilder::declareFoundVariable(AbstractType::Ptr type)
1425 {
1426     Q_ASSERT(m_findVariable.node);
1427 
1428     ///TODO: support something like: foo($var[0])
1429     if ( !m_findVariable.isArray ) {
1430         DUContext *ctx = nullptr;
1431         if ( m_findVariable.parentIdentifier.isEmpty() ) {
1432             ctx = currentContext();
1433         } else {
1434             ctx = getClassContext(m_findVariable.parentIdentifier, currentContext());
1435         }
1436         if ( ctx ) {
1437             bool isDeclared = false;
1438             {
1439                 DUChainWriteLocker lock(DUChain::lock());
1440                 RangeInRevision range = m_editor->findRange(m_findVariable.node);
1441                 foreach ( Declaration* dec, ctx->findDeclarations(m_findVariable.identifier) ) {
1442                     if ( dec->kind() == Declaration::Instance ) {
1443                         if (!wasEncountered(dec) || (dec->context() == ctx && range < dec->range())) {
1444                             // just like a "redeclaration", hence we must update the range
1445                             // TODO: do the same for all other uses of "encounter"?
1446                             dec->setRange(editorFindRange(m_findVariable.node));
1447                             encounter(dec);
1448                         }
1449                         isDeclared = true;
1450                         break;
1451                     }
1452                 }
1453             }
1454             if ( !isDeclared && m_findVariable.parentIdentifier.isEmpty() ) {
1455                 // check also for global vars
1456                 isDeclared = findDeclarationImport(GlobalVariableDeclarationType, m_findVariable.identifier);
1457             }
1458             if ( !isDeclared ) {
1459                 // couldn't find the dec, declare it
1460                 if ( !m_findVariable.parentIdentifier.isEmpty() ) {
1461                     declareClassMember(ctx, type, m_findVariable.identifier, m_findVariable.node);
1462                 } else {
1463                     declareVariable(ctx, type, m_findVariable.identifier, m_findVariable.node);
1464                 }
1465             }
1466         }
1467     }
1468 }
1469 
1470 void DeclarationBuilder::visitStatement(StatementAst* node)
1471 {
1472     DeclarationBuilderBase::visitStatement(node);
1473 
1474     if (node->foreachVariable) {
1475         PushValue<FindVariableResults> restore(m_findVariable);
1476         visitForeachVariable(node->foreachVariable);
1477         if (m_findVariable.node) {
1478             declareFoundVariable(lastType());
1479         }
1480     }
1481 
1482     if (node->foreachVarAsVar) {
1483         PushValue<FindVariableResults> restore(m_findVariable);
1484         visitForeachVariable(node->foreachVarAsVar);
1485         if (m_findVariable.node) {
1486             declareFoundVariable(lastType());
1487         }
1488     }
1489 
1490     if (node->foreachExprAsVar) {
1491         PushValue<FindVariableResults> restore(m_findVariable);
1492         visitVariable(node->foreachExprAsVar);
1493         if (m_findVariable.node) {
1494             declareFoundVariable(lastType());
1495         }
1496     }
1497 
1498 }
1499 
1500 void DeclarationBuilder::visitStaticVar(StaticVarAst* node)
1501 {
1502     DeclarationBuilderBase::visitStaticVar(node);
1503 
1504     DUChainWriteLocker lock(DUChain::lock());
1505     openDefinition<VariableDeclaration>(identifierForNode(node->var),
1506                                         editorFindRange(node->var, node->var));
1507     currentDeclaration()->setKind(Declaration::Instance);
1508 
1509     closeDeclaration();
1510 }
1511 
1512 void DeclarationBuilder::visitGlobalVar(GlobalVarAst* node)
1513 {
1514     DeclarationBuilderBase::visitGlobalVar(node);
1515     if (node->var) {
1516         QualifiedIdentifier id = identifierForNode(node->var);
1517         if ( recompiling() ) {
1518             DUChainWriteLocker lock(DUChain::lock());
1519             // sadly we can't use findLocalDeclarations() here, since it un-aliases declarations
1520             foreach ( Declaration* dec, currentContext()->localDeclarations() ) {
1521                 if ( dynamic_cast<AliasDeclaration*>(dec) && dec->identifier() == id.first() ) {
1522                     // don't redeclare but reuse the existing declaration
1523                     encounter(dec);
1524                     return;
1525                 }
1526             }
1527         }
1528         // no existing declaration found, create one
1529         DeclarationPointer aliasedDeclaration = findDeclarationImport(GlobalVariableDeclarationType, node->var);
1530         if (aliasedDeclaration) {
1531             DUChainWriteLocker lock(DUChain::lock());
1532             AliasDeclaration* dec = openDefinition<AliasDeclaration>(id, m_editor->findRange(node->var));
1533             dec->setAliasedDeclaration(aliasedDeclaration.data());
1534             closeDeclaration();
1535         }
1536     }
1537 }
1538 
1539 void DeclarationBuilder::visitCatchItem(CatchItemAst *node)
1540 {
1541     DeclarationBuilderBase::visitCatchItem(node);
1542 
1543     DUChainWriteLocker lock(DUChain::lock());
1544     openDefinition<VariableDeclaration>(identifierForNode(node->var),
1545                                         editorFindRange(node->var, node->var));
1546     currentDeclaration()->setKind(Declaration::Instance);
1547     closeDeclaration();
1548 }
1549 
1550 void DeclarationBuilder::visitUnaryExpression(UnaryExpressionAst* node)
1551 {
1552     DeclarationBuilderBase::visitUnaryExpression(node);
1553     IndexedString includeFile = getIncludeFileForNode(node, m_editor);
1554     if ( !includeFile.isEmpty() ) {
1555         DUChainWriteLocker lock;
1556         TopDUContext* includedCtx = DUChain::self()->chainForDocument(includeFile);
1557         if ( !includedCtx ) {
1558             // invalid include
1559             return;
1560         }
1561 
1562         QualifiedIdentifier identifier(includeFile.str());
1563 
1564         foreach ( Declaration* dec, includedCtx->findDeclarations(identifier, CursorInRevision(0, 1)) ) {
1565             if ( dec->kind() == Declaration::Import ) {
1566                 encounter(dec);
1567                 return;
1568             }
1569         }
1570         injectContext(includedCtx);
1571         openDefinition<Declaration>(identifier, RangeInRevision(0, 0, 0, 0));
1572         currentDeclaration()->setKind(Declaration::Import);
1573         eventuallyAssignInternalContext();
1574         DeclarationBuilderBase::closeDeclaration();
1575         closeInjectedContext();
1576     }
1577 }
1578 
1579 void DeclarationBuilder::openNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier, const RangeInRevision& range)
1580 {
1581     NamespaceDeclaration* dec = m_namespaces.value(node->string, nullptr);
1582     Q_ASSERT(dec);
1583     DeclarationBuilderBase::setEncountered(dec);
1584     openDeclarationInternal(dec);
1585 
1586     DeclarationBuilderBase::openNamespace(parent, node, identifier, range);
1587 }
1588 
1589 void DeclarationBuilder::closeNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier)
1590 {
1591     DeclarationBuilderBase::closeNamespace(parent, node, identifier);
1592     closeDeclaration();
1593 }
1594 
1595 void DeclarationBuilder::visitUseStatement(UseStatementAst* node)
1596 {
1597     if ( node->useFunction != -1 )
1598     {
1599         m_useNamespaceType = FunctionDeclarationType;
1600     }
1601     else if ( node->useConst != -1 )
1602     {
1603         m_useNamespaceType = ConstantDeclarationType;
1604     }
1605     else
1606     {
1607         m_useNamespaceType = ClassDeclarationType;
1608     }
1609     DeclarationBuilderBase::visitUseStatement(node);
1610 }
1611 
1612 void DeclarationBuilder::visitUseNamespaceOrUseGroupedNamespace(UseNamespaceOrUseGroupedNamespaceAst* node)
1613 {
1614     if (node->compoundNamespace) {
1615         // TODO
1616     } else {
1617         visitNonGroupedUseNamespace(node);
1618     }
1619 }
1620 
1621 void DeclarationBuilder::visitNonGroupedUseNamespace(UseNamespaceOrUseGroupedNamespaceAst* node)
1622 {
1623     DUChainWriteLocker lock;
1624     bool isConstIdentifier = ( m_useNamespaceType == ConstantDeclarationType );
1625 
1626     if ( currentContext()->type() != DUContext::Namespace &&
1627             !node->aliasIdentifier && node->identifier->namespaceNameSequence->count() == 1 ) {
1628         reportError(i18n("The use statement with non-compound name '%1' has no effect.",
1629                         identifierForNode(node->identifier->namespaceNameSequence->front()->element).toString()),
1630                     node->identifier, IProblem::Warning);
1631         return;
1632     }
1633     IdentifierAst* idNode = node->aliasIdentifier ? node->aliasIdentifier : node->identifier->namespaceNameSequence->back()->element;
1634     IdentifierPair id = identifierPairForNode(idNode, isConstIdentifier);
1635 
1636     ///TODO: case insensitive!
1637     QualifiedIdentifier qid = identifierForNamespace(node->identifier, m_editor, isConstIdentifier);
1638 
1639     DeclarationPointer dec = findDeclarationImport(m_useNamespaceType, qid);
1640     if (!dec && !qid.explicitlyGlobal()) {
1641         QualifiedIdentifier globalQid = qid;
1642         globalQid.setExplicitlyGlobal(true);
1643         dec = findDeclarationImport(m_useNamespaceType, globalQid);
1644     }
1645 
1646     if (dec)
1647     {
1648         // Check for a name conflict
1649         DeclarationPointer dec2 = findDeclarationImport(m_useNamespaceType, id.second);
1650 
1651         if (dec2 && dec2->context()->scopeIdentifier() == currentContext()->scopeIdentifier() &&
1652             dec2->context()->topContext() == currentContext()->topContext() &&
1653             dec2->identifier().toString() == id.second.toString())
1654         {
1655             reportError(i18n("Cannot use '%1' as '%2' because the name is already in use.",
1656                             dec.data()->identifier().toString(), id.second.toString()),
1657                         node->identifier, IProblem::Error);
1658             return;
1659         }
1660 
1661         AliasDeclaration* decl = openDefinition<AliasDeclaration>(id.second, m_editor->findRange(idNode));
1662         decl->setAliasedDeclaration(dec.data());
1663     }
1664     else
1665     {
1666         // NamespaceAliasDeclarations can't use a global import identifier
1667         qid.setExplicitlyGlobal(false);
1668 
1669         NamespaceAliasDeclaration* decl = openDefinition<NamespaceAliasDeclaration>(id.second,
1670                                                                                     m_editor->findRange(idNode));
1671         decl->setImportIdentifier( qid );
1672         decl->setPrettyName( id.first );
1673         decl->setKind(Declaration::NamespaceAlias);
1674     }
1675     closeDeclaration();
1676 
1677     if (node->aliasIdentifier) {
1678         QString aliasName = m_editor->parseSession()->symbol(node->aliasIdentifier);
1679 
1680         if (isReservedClassName(aliasName)) {
1681             reportError(i18n("Cannot use %1 as %2 because '%2' is a special class name", qid.toString(), aliasName), node->aliasIdentifier);
1682         }
1683     }
1684 }
1685 
1686 void DeclarationBuilder::visitVarExpression(VarExpressionAst* node)
1687 {
1688     DeclarationBuilderBase::visitVarExpression(node);
1689 
1690     if (node->isGenerator != -1 && currentContext()->type() != DUContext::Other) {
1691         reportError(i18n("The 'yield' expression can only be used inside a function"), node);
1692     }
1693 }
1694 
1695 void DeclarationBuilder::updateCurrentType()
1696 {
1697     DUChainWriteLocker lock(DUChain::lock());
1698     currentDeclaration()->setAbstractType(currentAbstractType());
1699 }
1700 
1701 void DeclarationBuilder::supportBuild(AstNode* node, DUContext* context)
1702 {
1703     // generally we are the second pass through the doc (see PreDeclarationBuilder)
1704     // so notify our base about it
1705     setCompilingContexts(false);
1706     DeclarationBuilderBase::supportBuild(node, context);
1707 }
1708 
1709 void DeclarationBuilder::closeContext()
1710 {
1711     if (currentContext()->type() == DUContext::Function) {
1712         Q_ASSERT(currentDeclaration<AbstractFunctionDeclaration>());
1713         currentDeclaration<AbstractFunctionDeclaration>()->setInternalFunctionContext(currentContext());
1714     }
1715     // We don't want the first pass to clean up stuff, since
1716     // there is lots of stuff we visit/encounter here first.
1717     // So we clean things up here.
1718     setCompilingContexts(true);
1719     DeclarationBuilderBase::closeContext();
1720     setCompilingContexts(false);
1721 }
1722 
1723 void DeclarationBuilder::encounter(Declaration* dec)
1724 {
1725     // when we are recompiling, it's important to mark decs as encountered
1726     // and update their comments
1727     if ( recompiling() && !wasEncountered(dec) ) {
1728         dec->setComment(comment());
1729         setEncountered(dec);
1730     }
1731 }
1732 
1733 bool DeclarationBuilder::isReservedClassName(QString className)
1734 {
1735     return className.compare(QLatin1String("string"), Qt::CaseInsensitive) == 0
1736             || className.compare(QLatin1String("bool"), Qt::CaseInsensitive) == 0
1737             || className.compare(QLatin1String("int"), Qt::CaseInsensitive) == 0
1738             || className.compare(QLatin1String("float"), Qt::CaseInsensitive) == 0
1739             || className.compare(QLatin1String("iterable"), Qt::CaseInsensitive) == 0
1740             || className.compare(QLatin1String("object"), Qt::CaseInsensitive) == 0
1741             || className.compare(QLatin1String("null"), Qt::CaseInsensitive) == 0
1742             || className.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0
1743             || className.compare(QLatin1String("false"), Qt::CaseInsensitive) == 0;
1744 }
1745 
1746 
1747 }