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 }