File indexing completed on 2024-05-05 16:42:27
0001 /* 0002 SPDX-FileCopyrightText: 2007 Piyush verma <piyush.verma@gmail.com> 0003 SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de> 0004 SPDX-FileCopyrightText: 2010-2016 Sven Brauch <svenbrauch@googlemail.com> 0005 SPDX-FileCopyrightText: 2016 Francis Herne <mail@flherne.uk> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "declarationbuilder.h" 0011 #include "duchain/declarations/functiondeclaration.h" 0012 0013 #include "types/hintedtype.h" 0014 #include "types/unsuretype.h" 0015 #include "types/nonetype.h" 0016 #include "types/indexedcontainer.h" 0017 #include "contextbuilder.h" 0018 #include "expressionvisitor.h" 0019 #include "pythoneditorintegrator.h" 0020 #include "helpers.h" 0021 #include "assistants/missingincludeassistant.h" 0022 #include "correctionhelper.h" 0023 0024 #include <language/duchain/classdeclaration.h> 0025 #include <language/duchain/functiondeclaration.h> 0026 #include <language/duchain/declaration.h> 0027 #include <language/duchain/duchain.h> 0028 #include <language/duchain/types/alltypes.h> 0029 #include <language/duchain/builders/abstracttypebuilder.h> 0030 #include <language/duchain/aliasdeclaration.h> 0031 #include <language/duchain/duchainutils.h> 0032 #include <language/backgroundparser/backgroundparser.h> 0033 #include <language/backgroundparser/parsejob.h> 0034 #include <interfaces/ilanguagecontroller.h> 0035 0036 #include <QByteArray> 0037 #include <QtGlobal> 0038 0039 #include <QDebug> 0040 #include "duchaindebug.h" 0041 0042 #include <functional> 0043 0044 using namespace KTextEditor; 0045 using namespace KDevelop; 0046 0047 namespace Python 0048 { 0049 0050 DeclarationBuilder::DeclarationBuilder(Python::PythonEditorIntegrator* editor, int ownPriority) 0051 : DeclarationBuilderBase() 0052 , m_ownPriority(ownPriority) 0053 { 0054 setEditor(editor); 0055 } 0056 0057 DeclarationBuilder:: ~DeclarationBuilder() 0058 { 0059 if ( ! m_scheduledForDeletion.isEmpty() ) { 0060 DUChainWriteLocker lock; 0061 foreach ( DUChainBase* d, m_scheduledForDeletion ) { 0062 delete d; 0063 } 0064 m_scheduledForDeletion.clear(); 0065 } 0066 } 0067 0068 void DeclarationBuilder::setPrebuilding(bool prebuilding) 0069 { 0070 m_prebuilding = prebuilding; 0071 } 0072 0073 ReferencedTopDUContext DeclarationBuilder::build(const IndexedString& url, Ast* node, 0074 const ReferencedTopDUContext& updateContext_) 0075 { 0076 ReferencedTopDUContext updateContext(updateContext_); 0077 m_correctionHelper.reset(new CorrectionHelper(url, this)); 0078 0079 // The declaration builder needs to run twice, so it can resolve uses of e.g. functions 0080 // which are called before they are defined (which is easily possible, due to python's dynamic nature). 0081 if ( ! m_prebuilding ) { 0082 DeclarationBuilder* prebuilder = new DeclarationBuilder(editor(), m_ownPriority); 0083 prebuilder->m_currentlyParsedDocument = currentlyParsedDocument(); 0084 prebuilder->setPrebuilding(true); 0085 prebuilder->m_futureModificationRevision = m_futureModificationRevision; 0086 updateContext = prebuilder->build(url, node, updateContext); 0087 delete prebuilder; 0088 qCDebug(KDEV_PYTHON_DUCHAIN) << "Second declarationbuilder pass"; 0089 } 0090 else { 0091 qCDebug(KDEV_PYTHON_DUCHAIN) << "Prebuilding declarations"; 0092 } 0093 return DeclarationBuilderBase::build(url, node, updateContext); 0094 } 0095 0096 int DeclarationBuilder::jobPriority() const 0097 { 0098 return m_ownPriority; 0099 } 0100 0101 void DeclarationBuilder::closeDeclaration() 0102 { 0103 if ( lastContext() ) { 0104 DUChainReadLocker lock(DUChain::lock()); 0105 currentDeclaration()->setKind(Declaration::Type); 0106 } 0107 0108 Q_ASSERT(currentDeclaration()->alwaysForceDirect()); 0109 0110 eventuallyAssignInternalContext(); 0111 0112 DeclarationBuilderBase::closeDeclaration(); 0113 } 0114 0115 template<typename T> T* DeclarationBuilder::eventuallyReopenDeclaration(Identifier* name, FitDeclarationType mustFitType) 0116 { 0117 QList<Declaration*> existingDeclarations = existingDeclarationsForNode(name); 0118 0119 Declaration* dec = nullptr; 0120 reopenFittingDeclaration<T>(existingDeclarations, mustFitType, editorFindRange(name, name), &dec); 0121 bool declarationOpened = (bool) dec; 0122 if ( ! declarationOpened ) { 0123 dec = openDeclaration<T>(name); 0124 } 0125 Q_ASSERT(dynamic_cast<T*>(dec)); 0126 return static_cast<T*>(dec); 0127 } 0128 0129 template<typename T> T* DeclarationBuilder::visitVariableDeclaration(Ast* node, Declaration* previous, 0130 AbstractType::Ptr type, VisitVariableFlags flags) 0131 { 0132 if ( node->astType == Ast::NameAstType ) { 0133 NameAst* currentVariableDefinition = static_cast<NameAst*>(node); 0134 // those contexts can invoke a variable declaration 0135 // this prevents "bar" from being declared in something like "foo = bar" 0136 // This is just a sanity check, the code should never request creation of a variable 0137 // in such cases. 0138 if ( currentVariableDefinition->context != ExpressionAst::Context::Store ) { 0139 return nullptr; 0140 } 0141 return visitVariableDeclaration<T>(currentVariableDefinition->identifier, previous, type, flags); 0142 } 0143 else if ( node->astType == Ast::IdentifierAstType ) { 0144 return visitVariableDeclaration<T>(static_cast<Identifier*>(node), previous, type, flags); 0145 } 0146 else { 0147 qCWarning(KDEV_PYTHON_DUCHAIN) << "cannot create variable declaration for non-(name|identifier) AST, this is a programming error"; 0148 return static_cast<T*>(nullptr); 0149 } 0150 } 0151 0152 QList< Declaration* > DeclarationBuilder::existingDeclarationsForNode(Identifier* node) 0153 { 0154 return currentContext()->findDeclarations( 0155 identifierForNode(node).last(), CursorInRevision::invalid(), nullptr, 0156 (DUContext::SearchFlag) (DUContext::DontSearchInParent | DUContext::DontResolveAliases) 0157 ); 0158 } 0159 0160 DeclarationBuilder::FitDeclarationType DeclarationBuilder::kindForType(AbstractType::Ptr type, bool isAlias) 0161 { 0162 if ( type ) { 0163 if ( type->whichType() == AbstractType::TypeFunction ) { 0164 return FunctionDeclarationType; 0165 } 0166 } 0167 if ( isAlias ) { 0168 return AliasDeclarationType; 0169 } 0170 return InstanceDeclarationType; 0171 } 0172 0173 template<typename T> QList<Declaration*> DeclarationBuilder::reopenFittingDeclaration( 0174 QList<Declaration*> declarations, FitDeclarationType mustFitType, 0175 RangeInRevision updateRangeTo, Declaration** ok ) 0176 { 0177 // Search for a declaration from a previous parse pass which should be re-used 0178 QList<Declaration*> remainingDeclarations; 0179 *ok = nullptr; 0180 foreach ( Declaration* d, declarations ) { 0181 Declaration* fitting = dynamic_cast<T*>(d); 0182 if ( ! fitting ) { 0183 // Only use a declaration if the type matches 0184 qCDebug(KDEV_PYTHON_DUCHAIN) << "skipping" << d->toString() << "which could not be cast to the requested type"; 0185 continue; 0186 } 0187 // Do not use declarations which have been encountered previously; 0188 // this function only handles declarations from previous parser passes which have not 0189 // been encountered yet in this pass 0190 bool reallyEncountered = wasEncountered(d) && ! m_scheduledForDeletion.contains(d); 0191 bool invalidType = false; 0192 if ( d->abstractType() && mustFitType != NoTypeRequired ) { 0193 invalidType = ( ( d->isFunctionDeclaration() ) != ( mustFitType == FunctionDeclarationType ) ); 0194 if ( ! invalidType ) { 0195 invalidType = ( ( dynamic_cast<AliasDeclaration*>(d) != nullptr ) != ( mustFitType == AliasDeclarationType ) ); 0196 } 0197 } 0198 if ( fitting && ! reallyEncountered && ! invalidType ) { 0199 if ( d->topContext() == currentContext()->topContext() ) { 0200 openDeclarationInternal(d); 0201 d->setRange(updateRangeTo); 0202 *ok = d; 0203 setEncountered(d); 0204 break; 0205 } 0206 else { 0207 qCDebug(KDEV_PYTHON_DUCHAIN) << "Not opening previously existing declaration because it's in another top context"; 0208 } 0209 } 0210 else if ( ! invalidType ) { 0211 remainingDeclarations << d; 0212 } 0213 } 0214 return remainingDeclarations; 0215 } 0216 0217 template<typename T> T* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Declaration* previous, 0218 AbstractType::Ptr type, VisitVariableFlags flags) 0219 { 0220 DUChainWriteLocker lock; 0221 RangeInRevision range = editorFindRange(node, node); 0222 // ask the correction file library if there's a user-specified type for this object 0223 if ( AbstractType::Ptr hint = m_correctionHelper->hintForLocal(node->value) ) { 0224 type = hint; 0225 } 0226 0227 // If no type is known, display "mixed". 0228 if ( ! type ) { 0229 type = AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed)); 0230 } 0231 0232 QList<Declaration*> existingDeclarations; 0233 if ( previous ) { 0234 existingDeclarations << previous; 0235 } 0236 else { 0237 // declarations declared at an earlier range in this top-context 0238 existingDeclarations = existingDeclarationsForNode(node); 0239 } 0240 0241 // declaration existing in a previous version of this top-context 0242 Declaration* dec = nullptr; 0243 existingDeclarations = reopenFittingDeclaration<T>(existingDeclarations, kindForType(type), range, &dec); 0244 bool declarationOpened = (bool) dec; 0245 if ( flags & AbortIfReopenMismatch && previous && ! declarationOpened ) { 0246 return nullptr; 0247 } 0248 0249 // tells whether the declaration found for updating is in the same top context 0250 bool inSameTopContext = true; 0251 // tells whether there's fitting declarations to update (update is not the same as re-open! one is for 0252 // code which uses the same variable twice, the other is for multiple passes of the parser) 0253 bool haveFittingDeclaration = false; 0254 if ( ! existingDeclarations.isEmpty() && existingDeclarations.last() ) { 0255 Declaration* d = Helper::resolveAliasDeclaration(existingDeclarations.last()); 0256 DUChainReadLocker lock; 0257 if ( d && d->topContext() != topContext() ) { 0258 inSameTopContext = false; 0259 } 0260 if ( dynamic_cast<T*>(existingDeclarations.last()) ) { 0261 haveFittingDeclaration = true; 0262 } 0263 } 0264 if ( currentContext() && currentContext()->type() == DUContext::Class && ! haveFittingDeclaration ) { 0265 // If the current context is a class, then this is a class member variable. 0266 if ( ! dec ) { 0267 dec = openDeclaration<ClassMemberDeclaration>(node); 0268 Q_ASSERT(! declarationOpened); 0269 declarationOpened = true; 0270 } 0271 if ( declarationOpened ) { 0272 DeclarationBuilderBase::closeDeclaration(); 0273 } 0274 dec->setType(AbstractType::Ptr(type)); 0275 dec->setKind(KDevelop::Declaration::Instance); 0276 } else if ( ! haveFittingDeclaration ) { 0277 // This name did not previously appear in the user code, so a new variable is declared 0278 // check whether a declaration from a previous parser pass must be updated 0279 if ( ! dec ) { 0280 dec = openDeclaration<T>(node); 0281 Q_ASSERT(! declarationOpened); 0282 declarationOpened = true; 0283 } 0284 if ( declarationOpened ) { 0285 DeclarationBuilderBase::closeDeclaration(); 0286 } 0287 0288 AbstractType::Ptr newType; 0289 if ( currentContext()->type() == DUContext::Function ) { 0290 // check for argument type hints (those are created when calling functions) 0291 AbstractType::Ptr hints = Helper::extractTypeHints(dec->abstractType()); 0292 if ( hints.dynamicCast<IndexedContainer>() || hints.dynamicCast<ListType>() ) { 0293 // This only happens when the type hint is a tuple, which means the vararg/kwarg of a function is being processed. 0294 newType = hints; 0295 } 0296 else { 0297 newType = Helper::mergeTypes(hints, type); 0298 } 0299 } 0300 else { 0301 newType = type; 0302 } 0303 dec->setType(newType); 0304 dec->setKind(KDevelop::Declaration::Instance); 0305 } 0306 else if ( inSameTopContext ) { 0307 // The name appeared previously in the user code, so no new variable is declared, but just 0308 // the type is modified accordingly. 0309 dec = existingDeclarations.last(); 0310 AbstractType::Ptr currentType = dec->abstractType(); 0311 AbstractType::Ptr newType = type; 0312 if ( newType ) { 0313 if ( currentType && currentType->indexed() != newType->indexed() ) { 0314 // If the previous and new type are different, use an unsure type 0315 dec->setType(Helper::mergeTypes(currentType, newType)); 0316 } 0317 else { 0318 // If no type was set previously, use only the new one. 0319 dec->setType(AbstractType::Ptr(type)); 0320 } 0321 } 0322 } 0323 0324 T* result = dynamic_cast<T*>(dec); 0325 if ( ! result ) qCWarning(KDEV_PYTHON_DUCHAIN) << "variable declaration does not have the expected type"; 0326 return result; 0327 } 0328 0329 void DeclarationBuilder::visitCode(CodeAst* node) 0330 { 0331 Q_ASSERT(currentlyParsedDocument().toUrl().isValid()); 0332 m_unresolvedImports.clear(); 0333 DeclarationBuilderBase::visitCode(node); 0334 } 0335 0336 void DeclarationBuilder::visitExceptionHandler(ExceptionHandlerAst* node) 0337 { 0338 if ( node->name ) { 0339 // Python allows to assign the caught exception to a variable; create that variable if required. 0340 ExpressionVisitor v(currentContext()); 0341 v.visitNode(node->type); 0342 visitVariableDeclaration<Declaration>(node->name, nullptr, v.lastType()); 0343 } 0344 DeclarationBuilderBase::visitExceptionHandler(node); 0345 } 0346 0347 void DeclarationBuilder::visitWithItem(WithItemAst* node) 0348 { 0349 if ( node->optionalVars ) { 0350 // For statements like "with open(f) as x", a new variable must be created; do this here. 0351 ExpressionVisitor v(currentContext()); 0352 v.visitNode(node->contextExpression); 0353 auto mgrType = v.lastType(); 0354 auto enterType = mgrType; // If we can't find __enter__(), assume it returns `self` like file objects. 0355 0356 static const IndexedIdentifier enterId(KDevelop::Identifier("__enter__")); 0357 0358 DUChainReadLocker lock; 0359 if ( auto enterFunc = dynamic_cast<FunctionDeclaration*>( 0360 Helper::accessAttribute(mgrType, enterId, topContext()))) { 0361 if ( auto enterFuncType = enterFunc->type<FunctionType>() ) { 0362 enterType = enterFuncType->returnType(); 0363 } 0364 } 0365 lock.unlock(); 0366 // This may be any assignable expression, e.g. `with foo() as bar[3]: ...` 0367 assignToUnknown(node->optionalVars, enterType); 0368 } 0369 Python::AstDefaultVisitor::visitWithItem(node); 0370 } 0371 0372 void DeclarationBuilder::visitFor(ForAst* node) 0373 { 0374 if ( node->iterator ) { 0375 ExpressionVisitor v(currentContext()); 0376 v.visitNode(node->iterator); 0377 assignToUnknown(node->target, Helper::contentOfIterable(v.lastType(), topContext())); 0378 } 0379 Python::ContextBuilder::visitFor(node); 0380 } 0381 0382 Declaration* DeclarationBuilder::findDeclarationInContext(QStringList dottedNameIdentifier, TopDUContext* ctx) const 0383 { 0384 DUChainReadLocker lock(DUChain::lock()); 0385 DUContext* currentContext = ctx; 0386 // TODO make this a bit faster, it wastes time 0387 Declaration* lastAccessedDeclaration = nullptr; 0388 int i = 0; 0389 int identifierCount = dottedNameIdentifier.length(); 0390 foreach ( const QString& currentIdentifier, dottedNameIdentifier ) { 0391 Q_ASSERT(currentContext); 0392 i++; 0393 QList<Declaration*> declarations = currentContext->findDeclarations(QualifiedIdentifier(currentIdentifier).first(), 0394 CursorInRevision::invalid(), nullptr, DUContext::NoFiltering); 0395 // break if the list of identifiers is not yet totally worked through and no 0396 // declaration with an internal context was found 0397 if ( declarations.isEmpty() || ( !declarations.last()->internalContext() && identifierCount != i ) ) { 0398 qCDebug(KDEV_PYTHON_DUCHAIN) << "Declaration not found: " << dottedNameIdentifier << "in top context" << ctx->url().toUrl().path(); 0399 return nullptr; 0400 } 0401 else { 0402 lastAccessedDeclaration = declarations.last(); 0403 currentContext = lastAccessedDeclaration->internalContext(); 0404 } 0405 } 0406 return lastAccessedDeclaration; 0407 } 0408 0409 QString DeclarationBuilder::buildModuleNameFromNode(ImportFromAst* node, AliasAst* alias, const QString& intermediate) const 0410 { 0411 QString moduleName = alias->name->value; 0412 if ( ! intermediate.isEmpty() ) { 0413 moduleName.prepend('.').prepend(intermediate); 0414 } 0415 if ( node->module ) { 0416 moduleName.prepend('.').prepend(node->module->value); 0417 } 0418 // To handle relative imports correctly, add node level in the beginning of the path 0419 // This will allow findModulePath to deduce module search direcotry properly 0420 moduleName.prepend(QString(node->level, '.')); 0421 return moduleName; 0422 } 0423 0424 void DeclarationBuilder::visitImportFrom(ImportFromAst* node) 0425 { 0426 Python::AstDefaultVisitor::visitImportFrom(node); 0427 QString moduleName; 0428 QString declarationName; 0429 foreach ( AliasAst* name, node->names ) { 0430 // iterate over all the names that are imported, like "from foo import bar as baz, bang as asdf" 0431 Identifier* declarationIdentifier = nullptr; 0432 declarationName.clear(); 0433 if ( name->asName ) { 0434 // use either the alias ("as foo"), or the object name itself if no "as" is given 0435 declarationIdentifier = name->asName; 0436 declarationName = name->asName->value; 0437 } 0438 else { 0439 declarationIdentifier = name->name; 0440 declarationName = name->name->value; 0441 } 0442 // This is a bit hackish, it tries to find the specified object twice twice -- once it tries to 0443 // import the name from a module's __init__.py file, and once from a "real" python file 0444 // TODO improve this code-wise 0445 ProblemPointer problem(nullptr); 0446 QString intermediate; 0447 moduleName = buildModuleNameFromNode(node, name, intermediate); 0448 Declaration* success = createModuleImportDeclaration(moduleName, declarationName, declarationIdentifier, problem); 0449 if ( ! success && (node->module || node->level) ) { 0450 ProblemPointer problem_init(nullptr); 0451 intermediate = QString("__init__"); 0452 moduleName = buildModuleNameFromNode(node, name, intermediate); 0453 success = createModuleImportDeclaration(moduleName, declarationName, declarationIdentifier, problem_init); 0454 } 0455 if ( ! success && problem ) { 0456 DUChainWriteLocker lock; 0457 topContext()->addProblem(problem); 0458 } 0459 } 0460 } 0461 0462 void DeclarationBuilder::visitComprehension(ComprehensionAst* node) 0463 { 0464 Python::AstDefaultVisitor::visitComprehension(node); 0465 ExpressionVisitor v(currentContext()); 0466 v.visitNode(node->iterator); 0467 assignToUnknown(node->target, Helper::contentOfIterable(v.lastType(), topContext())); 0468 } 0469 0470 void DeclarationBuilder::visitImport(ImportAst* node) 0471 { 0472 Python::ContextBuilder::visitImport(node); 0473 DUChainWriteLocker lock; 0474 foreach ( AliasAst* name, node->names ) { 0475 QString moduleName = name->name->value; 0476 // use alias if available, name otherwise 0477 Identifier* declarationIdentifier = name->asName ? name->asName : name->name; 0478 ProblemPointer problem(nullptr); 0479 createModuleImportDeclaration(moduleName, declarationIdentifier->value, declarationIdentifier, problem); 0480 if ( problem ) { 0481 DUChainWriteLocker lock; 0482 topContext()->addProblem(problem); 0483 } 0484 } 0485 } 0486 0487 void DeclarationBuilder::scheduleForDeletion(DUChainBase* d, bool doschedule) 0488 { 0489 if ( doschedule ) { 0490 m_scheduledForDeletion.append(d); 0491 } 0492 else { 0493 m_scheduledForDeletion.removeAll(d); 0494 } 0495 } 0496 0497 0498 Declaration* DeclarationBuilder::createDeclarationTree(const QStringList& nameComponents, Identifier* declarationIdentifier, 0499 const ReferencedTopDUContext& innerCtx, Declaration* aliasDeclaration, 0500 const RangeInRevision& range) 0501 { 0502 // This actually handles two use cases which are very similar -- thus this check: 0503 // There might be either one declaration which should be imported from another module, 0504 // or there might be a whole context. In "import foo.bar", the "bar" might be either 0505 // a single class/function/whatever, or a whole file to import. 0506 // NOTE: The former case can't actually happen in python, it's not allowed. However, 0507 // it is still handled here, because it's very useful for documentation files (pyQt for example 0508 // makes heavy use of that feature). 0509 Q_ASSERT( ( innerCtx.data() || aliasDeclaration ) && "exactly one of innerCtx or aliasDeclaration must be provided"); 0510 Q_ASSERT( ( !innerCtx.data() || !aliasDeclaration ) && "exactly one of innerCtx or aliasDeclaration must be provided"); 0511 0512 qCDebug(KDEV_PYTHON_DUCHAIN) << "creating declaration tree for" << nameComponents; 0513 0514 Declaration* lastDeclaration = nullptr; 0515 int depth = 0; 0516 0517 // check for already existing trees to update 0518 for ( int i = nameComponents.length() - 1; i >= 0; i-- ) { 0519 QStringList currentName; 0520 for ( int j = 0; j < i; j++ ) { 0521 currentName.append(nameComponents.at(j)); 0522 } 0523 lastDeclaration = findDeclarationInContext(currentName, topContext()); 0524 if ( lastDeclaration && (!range.isValid() || lastDeclaration->range() < range) ) { 0525 depth = i; 0526 break; 0527 } 0528 } 0529 0530 DUContext* extendingPreviousImportCtx = nullptr; 0531 QStringList remainingNameComponents; 0532 bool injectingContext = false; 0533 if ( lastDeclaration && lastDeclaration->internalContext() ) { 0534 qCDebug(KDEV_PYTHON_DUCHAIN) << "Found existing import statement while creating declaration for " << declarationIdentifier->value; 0535 for ( int i = depth; i < nameComponents.length(); i++ ) { 0536 remainingNameComponents.append(nameComponents.at(i)); 0537 } 0538 extendingPreviousImportCtx = lastDeclaration->internalContext(); 0539 injectContext(extendingPreviousImportCtx); 0540 injectingContext = true; 0541 qCDebug(KDEV_PYTHON_DUCHAIN) << "remaining identifiers:" << remainingNameComponents; 0542 } 0543 else { 0544 remainingNameComponents = nameComponents; 0545 extendingPreviousImportCtx = topContext(); 0546 } 0547 0548 // now, proceed in creating the declaration tree with whatever context 0549 QList<Declaration*> openedDeclarations; 0550 QList<StructureType::Ptr> openedTypes; 0551 QList<DUContext*> openedContexts; 0552 0553 RangeInRevision displayRange = RangeInRevision::invalid(); 0554 0555 DUChainWriteLocker lock; 0556 for ( int i = 0; i < remainingNameComponents.length(); i++ ) { 0557 // Iterate over all the names, and create a declaration + sub-context for each of them 0558 const QString& component = remainingNameComponents.at(i); 0559 Identifier temporaryIdentifier(component); 0560 Declaration* d = nullptr; 0561 temporaryIdentifier.copyRange(declarationIdentifier); 0562 temporaryIdentifier.endCol = temporaryIdentifier.startCol; 0563 temporaryIdentifier.startCol += 1; 0564 displayRange = editorFindRange(&temporaryIdentifier, &temporaryIdentifier); // TODO fixme 0565 0566 bool done = false; 0567 if ( aliasDeclaration && i == remainingNameComponents.length() - 1 ) { 0568 // it's the last level, so if we have an alias declaration create it and stop 0569 if ( aliasDeclaration->isFunctionDeclaration() 0570 || dynamic_cast<ClassDeclaration*>(aliasDeclaration) 0571 || dynamic_cast<AliasDeclaration*>(aliasDeclaration) 0572 ) { 0573 aliasDeclaration = Helper::resolveAliasDeclaration(aliasDeclaration); 0574 AliasDeclaration* adecl = eventuallyReopenDeclaration<AliasDeclaration>(&temporaryIdentifier, 0575 AliasDeclarationType); 0576 if ( adecl ) { 0577 adecl->setAliasedDeclaration(aliasDeclaration); 0578 } 0579 d = adecl; 0580 closeDeclaration(); 0581 } 0582 else { 0583 d = visitVariableDeclaration<Declaration>(&temporaryIdentifier); 0584 d->setAbstractType(aliasDeclaration->abstractType()); 0585 } 0586 openedDeclarations.append(d); 0587 done = true; 0588 } 0589 0590 if ( ! done ) { 0591 // create the next level of the tree hierarchy if not done yet. 0592 d = visitVariableDeclaration<Declaration>(&temporaryIdentifier); 0593 } 0594 if ( d ) { 0595 if ( topContext() != currentContext() ) { 0596 d->setRange(RangeInRevision(currentContext()->range().start, currentContext()->range().start)); 0597 } 0598 else { 0599 d->setRange(displayRange); 0600 } 0601 d->setAutoDeclaration(true); 0602 currentContext()->createUse(d->ownIndex(), d->range()); 0603 qCDebug(KDEV_PYTHON_DUCHAIN) << "really encountered:" << d << "; scheduled:" << m_scheduledForDeletion; 0604 qCDebug(KDEV_PYTHON_DUCHAIN) << d->toString(); 0605 scheduleForDeletion(d, false); 0606 qCDebug(KDEV_PYTHON_DUCHAIN) << "scheduled:" << m_scheduledForDeletion; 0607 } 0608 if ( done ) break; 0609 0610 qCDebug(KDEV_PYTHON_DUCHAIN) << "creating context for " << component; 0611 0612 // otherwise, create a new "level" entry (a pseudo type + context + declaration which contains all imported items) 0613 StructureType::Ptr moduleType = StructureType::Ptr(new StructureType()); 0614 openType(moduleType); 0615 0616 // the identifier is needed so the context does not get re-opened if 0617 // more contexts are opened for other files with the same range 0618 Python::Identifier contextIdentifier(component); 0619 auto moduleContext = openContext(declarationIdentifier, KDevelop::DUContext::Other, &contextIdentifier); 0620 openedContexts.append(moduleContext); 0621 0622 foreach ( Declaration* local, currentContext()->localDeclarations() ) { 0623 // keep all the declarations until the builder finished 0624 // kdevelop would otherwise delete them as soon as the context is closed 0625 if ( ! wasEncountered(local) ) { 0626 setEncountered(local); 0627 scheduleForDeletion(local, true); 0628 } 0629 } 0630 0631 openedDeclarations.append(d); 0632 openedTypes.append(moduleType); 0633 if ( i == remainingNameComponents.length() - 1 ) { 0634 if ( innerCtx ) { 0635 qCDebug(KDEV_PYTHON_DUCHAIN) << "adding imported context to inner declaration"; 0636 currentContext()->addImportedParentContext(innerCtx); 0637 } 0638 else if ( aliasDeclaration ) { 0639 qCDebug(KDEV_PYTHON_DUCHAIN) << "setting alias declaration on inner declaration"; 0640 } 0641 } 0642 } 0643 for ( int i = openedContexts.length() - 1; i >= 0; i-- ) { 0644 // Close all the declarations and contexts opened previosly, and assign the types. 0645 qCDebug(KDEV_PYTHON_DUCHAIN) << "closing context"; 0646 closeType(); 0647 closeContext(); 0648 auto d = openedDeclarations.at(i); 0649 // because no context will be opened for an alias declaration, this will not happen if there's one 0650 if ( d ) { 0651 openedTypes[i]->setDeclaration(d); 0652 d->setType(openedTypes.at(i)); 0653 d->setInternalContext(openedContexts.at(i)); 0654 } 0655 } 0656 0657 if ( injectingContext ) { 0658 closeInjectedContext(); 0659 } 0660 0661 if ( ! openedDeclarations.isEmpty() ) { 0662 // return the lowest-level element in the tree, for the caller to do stuff with 0663 return openedDeclarations.last(); 0664 } 0665 else return nullptr; 0666 } 0667 0668 Declaration* DeclarationBuilder::createModuleImportDeclaration(QString moduleName, QString declarationName, 0669 Identifier* declarationIdentifier, 0670 ProblemPointer& problemEncountered, Ast* rangeNode) 0671 { 0672 // Search the disk for a python file which contains the requested declaration 0673 auto moduleInfo = findModulePath(moduleName, currentlyParsedDocument().toUrl()); 0674 RangeInRevision range(RangeInRevision::invalid()); 0675 if ( rangeNode ) { 0676 range = rangeForNode(rangeNode, false); 0677 } 0678 else { 0679 range = rangeForNode(declarationIdentifier, false); 0680 } 0681 Q_ASSERT(range.isValid()); 0682 0683 qCDebug(KDEV_PYTHON_DUCHAIN) << "Found module path [path/path in file]: " << moduleInfo; 0684 qCDebug(KDEV_PYTHON_DUCHAIN) << "Declaration identifier:" << declarationIdentifier->value; 0685 DUChainWriteLocker lock; 0686 const IndexedString modulePath = IndexedString(moduleInfo.first); 0687 ReferencedTopDUContext moduleContext = DUChain::self()->chainForDocument(modulePath); 0688 lock.unlock(); 0689 Declaration* resultingDeclaration = nullptr; 0690 if ( ! moduleInfo.first.isValid() ) { 0691 // The file was not found -- this is either an error in the user's code, 0692 // a missing module, or a C module (.so) which is unreadable for kdevelop 0693 // TODO imrpove error handling in case the module exists as a shared object or .pyc file only 0694 qCDebug(KDEV_PYTHON_DUCHAIN) << "invalid or non-existent URL:" << moduleInfo; 0695 KDevelop::Problem *p = new Python::MissingIncludeProblem(moduleName, currentlyParsedDocument()); 0696 p->setFinalLocation(DocumentRange(currentlyParsedDocument(), range.castToSimpleRange())); 0697 p->setSource(KDevelop::IProblem::SemanticAnalysis); 0698 p->setSeverity(KDevelop::IProblem::Warning); 0699 p->setDescription(i18n("Module \"%1\" not found", moduleName)); 0700 m_missingModules.append(IndexedString(moduleName)); 0701 problemEncountered = p; 0702 return nullptr; 0703 } 0704 if ( ! moduleContext ) { 0705 // schedule the include file for parsing, and schedule the current one for reparsing after that is done 0706 qCDebug(KDEV_PYTHON_DUCHAIN) << "No module context, recompiling"; 0707 m_unresolvedImports.append(modulePath); 0708 Helper::scheduleDependency(modulePath, m_ownPriority); 0709 // parseDocuments() must *not* be called from a background thread! 0710 // KDevelop::ICore::self()->languageController()->backgroundParser()->parseDocuments(); 0711 return nullptr; 0712 } 0713 if ( moduleInfo.second.isEmpty() ) { 0714 // import the whole module 0715 resultingDeclaration = createDeclarationTree(declarationName.split("."), 0716 declarationIdentifier, moduleContext, nullptr, range); 0717 auto initFile = QStringLiteral("/__init__.py"); 0718 auto path = moduleInfo.first.path(); 0719 if ( path.endsWith(initFile) ) { 0720 // if the __init__ file is imported, import all the other files in that directory as well 0721 QDir dir(path.left(path.size() - initFile.size())); 0722 dir.setNameFilters({"*.py"}); 0723 dir.setFilter(QDir::Files); 0724 auto files = dir.entryList(); 0725 foreach ( const auto& file, files ) { 0726 if ( file == QStringLiteral("__init__.py") ) { 0727 continue; 0728 } 0729 const auto filePath = declarationName.split(".") << file.left(file.lastIndexOf(".py")); 0730 const auto fileUrl = QUrl::fromLocalFile(dir.path() + "/" + file); 0731 ReferencedTopDUContext fileContext; 0732 { 0733 DUChainReadLocker lock; 0734 fileContext = DUChain::self()->chainForDocument(IndexedString(fileUrl)); 0735 } 0736 if ( fileContext ) { 0737 Identifier id = *declarationIdentifier; 0738 id.value.append(".").append(filePath.last()); 0739 createDeclarationTree(filePath, 0740 &id, fileContext, nullptr); 0741 } 0742 else { 0743 m_unresolvedImports.append(IndexedString(fileUrl)); 0744 Helper::scheduleDependency(IndexedString(fileUrl), m_ownPriority); 0745 } 0746 } 0747 } 0748 } 0749 else { 0750 // import a specific declaration from the given file 0751 lock.lock(); 0752 if ( declarationIdentifier->value == "*" ) { 0753 qCDebug(KDEV_PYTHON_DUCHAIN) << "Importing * from module"; 0754 currentContext()->addImportedParentContext(moduleContext); 0755 } 0756 else { 0757 qCDebug(KDEV_PYTHON_DUCHAIN) << "Got module, importing declaration: " << moduleInfo.second; 0758 Declaration* originalDeclaration = findDeclarationInContext(moduleInfo.second, moduleContext); 0759 if ( originalDeclaration ) { 0760 DUChainWriteLocker lock(DUChain::lock()); 0761 resultingDeclaration = createDeclarationTree(declarationName.split("."), declarationIdentifier, 0762 ReferencedTopDUContext(nullptr), originalDeclaration, 0763 editorFindRange(declarationIdentifier, declarationIdentifier)); 0764 } 0765 else { 0766 KDevelop::Problem *p = new Python::MissingIncludeProblem(moduleName, currentlyParsedDocument()); 0767 p->setFinalLocation(DocumentRange(currentlyParsedDocument(), range.castToSimpleRange())); // TODO ok? 0768 p->setSource(KDevelop::IProblem::SemanticAnalysis); 0769 p->setSeverity(KDevelop::IProblem::Warning); 0770 p->setDescription(i18n("Declaration for \"%1\" not found in specified module", moduleInfo.second.join("."))); 0771 problemEncountered = p; 0772 } 0773 } 0774 } 0775 return resultingDeclaration; 0776 } 0777 0778 void DeclarationBuilder::visitYield(YieldAst* node) 0779 { 0780 // Functions containing "yield" statements will return lists in our abstraction. 0781 // The content type of that list can be guessed from the yield statements. 0782 AstDefaultVisitor::visitYield(node); 0783 0784 // Determine the type of the argument to "yield", like "int" in "yield 3" 0785 ExpressionVisitor v(currentContext()); 0786 v.visitNode(node->value); 0787 AbstractType::Ptr encountered = v.lastType(); 0788 0789 // In some obscure (or wrong) cases, "yield" might appear outside of a function body, 0790 // so check for that here. 0791 if ( ! node->value || ! hasCurrentType() ) { 0792 return; 0793 } 0794 0795 TypePtr<FunctionType> t = currentType<FunctionType>(); 0796 if ( ! t ) { 0797 return; 0798 } 0799 if ( auto previous = t->returnType().dynamicCast<ListType>() ) { 0800 // If the return type of the function already is set to a list, *add* the encountered type 0801 // to its possible content types. 0802 DUChainWriteLocker lock; 0803 previous->addContentType<Python::UnsureType>(encountered); 0804 t->setReturnType(previous); 0805 } 0806 else { 0807 // Otherwise, create a new container type, and set it as the function's return type. 0808 DUChainWriteLocker lock; 0809 auto container = ExpressionVisitor::typeObjectForIntegralType<ListType>("list"); 0810 if ( container ) { 0811 openType(container); 0812 container->addContentType<Python::UnsureType>(encountered); 0813 t->setReturnType(Helper::mergeTypes(t->returnType(), container)); 0814 closeType(); 0815 } 0816 } 0817 } 0818 0819 void DeclarationBuilder::visitLambda(LambdaAst* node) 0820 { 0821 DUChainWriteLocker lock; 0822 // A context must be opened, because the lamdba's arguments are local to the lambda: 0823 // d = lambda x: x*2; print x # <- gives an error 0824 openContext(node, editorFindRange(node, node->body), DUContext::Other); 0825 foreach ( ArgAst* argument, node->arguments->arguments ) { 0826 visitVariableDeclaration<Declaration>(argument->argumentName); 0827 } 0828 visitNodeList(node->arguments->defaultValues); 0829 if (node->arguments->vararg) { 0830 visitVariableDeclaration<Declaration>(node->arguments->vararg->argumentName); 0831 } 0832 if (node->arguments->kwarg) { 0833 visitVariableDeclaration<Declaration>(node->arguments->kwarg->argumentName); 0834 } 0835 visitNode(node->body); 0836 closeContext(); 0837 } 0838 0839 void DeclarationBuilder::applyDocstringHints(CallAst* node, FunctionDeclaration::Ptr function) 0840 { 0841 ExpressionVisitor v(currentContext()); 0842 v.visitNode(static_cast<AttributeAst*>(node->function)->value); 0843 0844 // Don't do anything if the object the function is being called on is not a container. 0845 auto container = v.lastType().dynamicCast<ListType>(); 0846 if ( ! container || ! function ) { 0847 return; 0848 } 0849 // Don't do updates to pre-defined functions. 0850 if ( ! v.lastDeclaration() || v.lastDeclaration()->topContext()->url() == Helper::getDocumentationFile() ) { 0851 return; 0852 } 0853 // Check for the different types of modifiers such a function can have 0854 QStringList args; 0855 QHash< QString, std::function<void()> > items; 0856 items["addsTypeOfArg"] = [&]() { 0857 const int offset = ! args.isEmpty() ? (int) args.at(0).toUInt() : 0; 0858 if ( node->arguments.length() <= offset ) { 0859 return; 0860 } 0861 // Check which type should be added to the list 0862 ExpressionVisitor argVisitor(currentContext()); 0863 argVisitor.visitNode(node->arguments.at(offset)); 0864 // Actually add that type 0865 if ( ! argVisitor.lastType() ) { 0866 return; 0867 } 0868 DUChainWriteLocker wlock; 0869 qCDebug(KDEV_PYTHON_DUCHAIN) << "Adding content type: " << argVisitor.lastType()->toString(); 0870 container->addContentType<Python::UnsureType>(argVisitor.lastType()); 0871 v.lastDeclaration()->setType(container); 0872 }; 0873 items["addsTypeOfArgContent"] = [&]() { 0874 const int offset = ! args.isEmpty() ? (int) args.at(0).toUInt() : 0; 0875 if ( node->arguments.length() <= offset ) { 0876 return; 0877 } 0878 ExpressionVisitor argVisitor(currentContext()); 0879 argVisitor.visitNode(node->arguments.at(offset)); 0880 if ( argVisitor.lastType() ) { 0881 DUChainWriteLocker wlock; 0882 auto contentType = Helper::contentOfIterable(argVisitor.lastType(), topContext()); 0883 container->addContentType<Python::UnsureType>(contentType); 0884 v.lastDeclaration()->setType(container); 0885 } 0886 }; 0887 auto docstring = function->comment(); 0888 if ( ! docstring.isEmpty() ) { 0889 foreach ( const auto& key, items.keys() ) { 0890 if ( Helper::docstringContainsHint(docstring, key, &args) ) { 0891 items[key](); 0892 } 0893 } 0894 } 0895 } 0896 0897 void DeclarationBuilder::addArgumentTypeHints(CallAst* node, DeclarationPointer called) 0898 { 0899 DUChainReadLocker lock; 0900 auto funcInfo = Helper::functionForCalled(called.data()); 0901 auto function = funcInfo.declaration; 0902 0903 if ( ! function ) { 0904 return; 0905 } 0906 if ( function->topContext()->url() == Helper::getDocumentationFile() ) { 0907 return; 0908 } 0909 // Note: within this function: 0910 // - 'parameters' refers to the parameters of the function definition. 0911 // - 'arguments' refers to the arguments of the function call. 0912 0913 DUContext* parameterContext = DUChainUtils::argumentContext(function); 0914 FunctionType::Ptr functionType = function->type<FunctionType>(); 0915 if ( ! parameterContext || ! functionType ) { 0916 return; 0917 } 0918 QVector<Declaration*> parameters = parameterContext->localDeclarations(); 0919 if ( parameters.isEmpty() ) { 0920 return; 0921 } 0922 const int specialParamsCount = (function->vararg() != -1) + (function->kwarg() != -1); 0923 0924 // Look for the "self" in the argument list, the type of that should not be updated. 0925 bool hasSelfParam = false; 0926 if ( ( function->context()->type() == DUContext::Class || funcInfo.isConstructor ) 0927 && ! function->isStatic() ) 0928 { 0929 // ... unless for some reason the function only has *vararg, **kwarg as parameters 0930 // (this could happen for example if the method is static but kdev-python does not know, 0931 // or if the user just made a mistake in his code) 0932 if ( specialParamsCount < parameters.size() ) { 0933 hasSelfParam = true; 0934 } 0935 } 0936 0937 lock.unlock(); 0938 0939 bool explicitSelfArgument = false; 0940 if ( hasSelfParam && ! function->isClassMethod() && node->function->astType == Ast::AttributeAstType ) { 0941 // Calling an attribute, e.g. `instance.foo(arg)` or `MyClass.foo(instance, arg)`. 0942 ExpressionVisitor valueVisitor(currentContext()); 0943 valueVisitor.visitNode(static_cast<AttributeAst*>(node->function)->value); 0944 if ( valueVisitor.lastDeclaration().dynamicCast<ClassDeclaration>() && valueVisitor.isAlias() ) { 0945 // Function is attribute of a class _type_ (not instance), so first arg is used as `self`. 0946 explicitSelfArgument = true; 0947 } 0948 } 0949 0950 int currentParamIndex = hasSelfParam; 0951 int currentArgumentIndex = explicitSelfArgument; 0952 int indexInVararg = -1; 0953 int paramsAvailable = qMin(functionType->arguments().length(), parameters.size()); 0954 int argsAvailable = node->arguments.size(); 0955 bool atVararg = false; 0956 0957 // Iterate over all the arguments, trying to guess the type of the object being 0958 // passed as an argument, and update the parameter accordingly. 0959 // Stop if more parameters supplied than possible, and we're not at the vararg. 0960 for ( ; ( atVararg || currentParamIndex < paramsAvailable ) && currentArgumentIndex < argsAvailable; 0961 currentArgumentIndex++ ) 0962 { 0963 atVararg = atVararg || currentParamIndex == function->vararg(); // Not >=, nonexistent vararg is -1. 0964 0965 ExpressionAst* arg = node->arguments.at(currentArgumentIndex); 0966 0967 ExpressionVisitor argumentVisitor(currentContext()); 0968 argumentVisitor.visitNode(arg); 0969 AbstractType::Ptr argumentType = argumentVisitor.lastType(); 0970 0971 // Update the parameter type: change both the type of the function argument, 0972 // and the type of the declaration which belongs to that argument 0973 HintedType::Ptr addType = HintedType::Ptr(new HintedType()); 0974 openType(addType); 0975 addType->setType(argumentVisitor.lastType()); 0976 addType->setCreatedBy(topContext(), m_futureModificationRevision); 0977 closeType(); 0978 0979 DUChainWriteLocker wlock; 0980 if ( atVararg ) { 0981 indexInVararg++; 0982 Declaration* parameter = parameters.at(function->vararg()); 0983 IndexedContainer::Ptr varargContainer = parameter->type<IndexedContainer>(); 0984 if ( ! varargContainer ) continue; 0985 if ( varargContainer->typesCount() > indexInVararg ) { 0986 AbstractType::Ptr oldType = varargContainer->typeAt(indexInVararg).abstractType(); 0987 AbstractType::Ptr newType = Helper::mergeTypes(oldType, addType); 0988 varargContainer->replaceType(indexInVararg, newType); 0989 } 0990 else { 0991 varargContainer->addEntry(addType); 0992 } 0993 parameter->setAbstractType(varargContainer); 0994 } 0995 else { 0996 if ( ! argumentType ) continue; 0997 AbstractType::Ptr newType = Helper::mergeTypes(parameters.at(currentParamIndex)->abstractType(), 0998 addType); 0999 // TODO this does not correctly update the types in quickopen! Investigate why. 1000 functionType->removeArgument(currentParamIndex); 1001 functionType->addArgument(newType, currentParamIndex); 1002 function->setAbstractType(functionType); 1003 parameters.at(currentParamIndex)->setType(newType); 1004 currentParamIndex++; 1005 } 1006 } 1007 1008 // **kwargs is always the last parameter 1009 MapType::Ptr kwargsDict; 1010 if ( function->kwarg() != -1 ) { 1011 kwargsDict = parameters.last()->abstractType().dynamicCast<MapType>(); 1012 } 1013 lock.unlock(); 1014 DUChainWriteLocker wlock; 1015 foreach ( KeywordAst* keyword, node->keywords ) { 1016 wlock.unlock(); 1017 ExpressionVisitor argumentVisitor(currentContext()); 1018 argumentVisitor.visitNode(keyword->value); 1019 if ( ! argumentVisitor.lastType() ) { 1020 continue; 1021 } 1022 wlock.lock(); 1023 bool matchedNamedParam = false; 1024 HintedType::Ptr addType = HintedType::Ptr(new HintedType()); 1025 if ( keyword->argumentName ) { 1026 openType(addType); 1027 addType->setType(argumentVisitor.lastType()); 1028 addType->setCreatedBy(topContext(), m_futureModificationRevision); 1029 closeType(); 1030 for (int ip = currentParamIndex; ip < paramsAvailable; ++ip ) { 1031 if ( parameters.at(ip)->identifier().toString() != keyword->argumentName->value ) { 1032 continue; 1033 } 1034 matchedNamedParam = true; 1035 auto newType = Helper::mergeTypes(parameters.at(ip)->abstractType(), addType); 1036 functionType->removeArgument(ip); 1037 functionType->addArgument(newType, ip); 1038 parameters.at(ip)->setType(newType); 1039 } 1040 } 1041 else if ( auto unpackedDict = argumentVisitor.lastType().dynamicCast<MapType>() ) { 1042 // 'keyword is actually an unpacked dict: `foo(**{'a': 12}). 1043 openType(addType); 1044 addType->setType(unpackedDict->contentType().abstractType()); 1045 addType->setCreatedBy(topContext(), m_futureModificationRevision); 1046 closeType(); 1047 } 1048 else { // Maybe the dict type wasn't loaded yet, or something else happened. 1049 continue; 1050 } 1051 if ( ! matchedNamedParam && kwargsDict ) { 1052 DUChainWriteLocker lock; 1053 kwargsDict->addContentType<Python::UnsureType>(addType); 1054 parameters.last()->setAbstractType(kwargsDict); 1055 } 1056 } 1057 function->setAbstractType(functionType); 1058 } 1059 1060 void DeclarationBuilder::visitMatch(MatchAst* node) 1061 { 1062 // What are we matching? 1063 ExpressionVisitor subjectVisitor(currentContext()); 1064 subjectVisitor.visitNode(node->subject); 1065 1066 for (auto* matchCase: node->cases) { 1067 if (!matchCase || !matchCase->pattern) { 1068 continue; 1069 } 1070 DUChainWriteLocker lock; 1071 // We only support some forms for now. 1072 switch (matchCase->pattern->astType) { 1073 case Ast::MatchSequenceAstType: { 1074 auto* seq = static_cast<MatchSequenceAst*>(matchCase->pattern); 1075 for (auto* element: seq->patterns) { 1076 if (element->astType != Ast::MatchAsAstType) { 1077 continue; 1078 } 1079 auto* asElement = static_cast<MatchAsAst*>(element); 1080 auto type = Helper::contentOfIterable(subjectVisitor.lastType(), topContext()); 1081 visitVariableDeclaration<Declaration>(asElement->name, nullptr, type); 1082 } 1083 break; 1084 } 1085 1086 case Ast::MatchAsAstType: { 1087 auto* as = static_cast<MatchAsAst*>(matchCase->pattern); 1088 if (!as->name) { 1089 break; 1090 } 1091 visitVariableDeclaration<Declaration>(as->name, nullptr, subjectVisitor.lastType()); 1092 break; 1093 } 1094 1095 default: 1096 break; 1097 } 1098 } 1099 1100 Python::AstDefaultVisitor::visitMatch(node); 1101 } 1102 1103 void DeclarationBuilder::visitCall(CallAst* node) 1104 { 1105 Python::AstDefaultVisitor::visitCall(node); 1106 // Find the function being called; this code also handles cases where non-names 1107 // are called, for example: 1108 // class myclass(): 1109 // def myfun(self): return 3 1110 // l = [myclass()] 1111 // x = l[0].myfun() # the called object is actually l[0].myfun 1112 // In the above example, this call will be evaluated to "myclass.myfun" in the following statement. 1113 ExpressionVisitor functionVisitor(currentContext()); 1114 functionVisitor.visitNode(node); 1115 1116 if ( node->function && node->function->astType == Ast::AttributeAstType && functionVisitor.lastDeclaration() ) { 1117 // Some special functions, like "append", update the content of the object they operate on. 1118 // Find the object the function is called on, like for d = [1, 2, 3]; d.append(5), this will give "d" 1119 FunctionDeclaration::Ptr function = functionVisitor.lastDeclaration().dynamicCast<FunctionDeclaration>(); 1120 applyDocstringHints(node, function); 1121 } 1122 if ( ! m_prebuilding ) { 1123 return; 1124 } 1125 1126 // The following code will try to update types of function parameters based on what is passed 1127 // for those when the function is used. 1128 // In case of this code: 1129 // def foo(arg): print arg 1130 // foo(3) 1131 // the following will change the type of "arg" to be "int" when it processes the second line. 1132 addArgumentTypeHints(node, functionVisitor.lastDeclaration()); 1133 } 1134 1135 void DeclarationBuilder::assignToName(NameAst* target, const DeclarationBuilder::SourceType& element) 1136 { 1137 if ( element.isAlias ) { 1138 DUChainWriteLocker lock; 1139 AliasDeclaration* decl = eventuallyReopenDeclaration<AliasDeclaration>(target->identifier, AliasDeclarationType); 1140 decl->setAliasedDeclaration(element.declaration.data()); 1141 closeDeclaration(); 1142 } 1143 else { 1144 DUChainWriteLocker lock; 1145 Declaration* dec = visitVariableDeclaration<Declaration>(target, nullptr, element.type); 1146 if ( dec && m_lastComment && ! m_lastComment->usedAsComment ) { 1147 dec->setComment(m_lastComment->value); 1148 m_lastComment->usedAsComment = true; 1149 } 1150 /** DEBUG **/ 1151 if ( element.type && dec ) { 1152 Q_ASSERT(dec->abstractType()); 1153 } 1154 /** END DEBUG **/ 1155 } 1156 } 1157 1158 void DeclarationBuilder::assignToSubscript(SubscriptAst* subscript, const DeclarationBuilder::SourceType& element) 1159 { 1160 ExpressionAst* v = subscript->value; 1161 if ( ! element.type ) { 1162 return; 1163 } 1164 ExpressionVisitor targetVisitor(currentContext()); 1165 targetVisitor.visitNode(v); 1166 auto list = targetVisitor.lastType().dynamicCast<ListType>(); 1167 if ( list ) { 1168 DUChainWriteLocker lock; 1169 list->addContentType<Python::UnsureType>(element.type); 1170 } 1171 auto map = list.dynamicCast<MapType>(); 1172 if ( map ) { 1173 if ( subscript->slice && subscript->slice->astType != Ast::SliceAstType) { 1174 ExpressionVisitor keyVisitor(currentContext()); 1175 keyVisitor.visitNode(subscript->slice); 1176 AbstractType::Ptr key = keyVisitor.lastType(); 1177 if ( key ) { 1178 map->addKeyType<Python::UnsureType>(key); 1179 } 1180 } 1181 } 1182 DeclarationPointer lastDecl = targetVisitor.lastDeclaration(); 1183 if ( list && lastDecl ) { 1184 DUChainWriteLocker lock; 1185 lastDecl->setAbstractType(list); 1186 } 1187 } 1188 1189 void DeclarationBuilder::assignToAttribute(AttributeAst* attrib, const DeclarationBuilder::SourceType& element) 1190 { 1191 // visit the base expression before the dot 1192 ExpressionVisitor checkPreviousAttributes(currentContext()); 1193 checkPreviousAttributes.visitNode(attrib->value); 1194 DeclarationPointer parentObjectDeclaration = checkPreviousAttributes.lastDeclaration(); 1195 1196 DUContextPointer internal(nullptr); 1197 1198 if ( ! parentObjectDeclaration ) { 1199 qCDebug(KDEV_PYTHON_DUCHAIN) << "No declaration for attribute base, aborting creation of attribute"; 1200 return; 1201 } 1202 // if foo is a class, this is like foo.bar = 3 1203 if ( parentObjectDeclaration->internalContext() ) { 1204 internal = parentObjectDeclaration->internalContext(); 1205 } 1206 // while this is like A = foo(); A.bar = 3 1207 else { 1208 DUChainReadLocker lock; 1209 auto structure = parentObjectDeclaration->abstractType().dynamicCast<StructureType>(); 1210 if ( ! structure || ! structure->declaration(topContext()) ) { 1211 return; 1212 } 1213 parentObjectDeclaration = structure->declaration(topContext()); 1214 internal = parentObjectDeclaration->internalContext(); 1215 } 1216 if ( ! internal ) { 1217 qCDebug(KDEV_PYTHON_DUCHAIN) << "No internal context for structure type, aborting creation of attribute declaration"; 1218 return; 1219 } 1220 1221 Declaration* attributeDeclaration = nullptr; 1222 { 1223 DUChainReadLocker lock; 1224 attributeDeclaration = Helper::accessAttribute(parentObjectDeclaration->abstractType(), 1225 attrib->attribute->value, topContext()); 1226 } 1227 1228 if ( ! attributeDeclaration || ! wasEncountered(attributeDeclaration) ) { 1229 // inject a new attribute into the class type 1230 DUContext* previousContext = currentContext(); 1231 bool isAlreadyOpen = contextAlreadyOpen(internal); 1232 if ( isAlreadyOpen ) { 1233 activateAlreadyOpenedContext(internal); 1234 visitVariableDeclaration<ClassMemberDeclaration>( 1235 attrib->attribute, attributeDeclaration, element.type, AbortIfReopenMismatch 1236 ); 1237 closeAlreadyOpenedContext(internal); 1238 } 1239 else { 1240 injectContext(internal.data()); 1241 1242 Declaration* dec = visitVariableDeclaration<ClassMemberDeclaration>( 1243 attrib->attribute, attributeDeclaration, element.type, AbortIfReopenMismatch 1244 ); 1245 if ( dec ) { 1246 dec->setRange(RangeInRevision(internal->range().start, internal->range().start)); 1247 dec->setAutoDeclaration(true); 1248 DUChainWriteLocker lock; 1249 previousContext->createUse(dec->ownIndex(), editorFindRange(attrib, attrib)); 1250 } 1251 1252 closeInjectedContext(); 1253 } 1254 } 1255 else { 1256 DUChainWriteLocker lock; 1257 // the declaration is already there, just update the type 1258 if ( ! attributeDeclaration->type<FunctionType>() ) { 1259 auto newType = Helper::mergeTypes(attributeDeclaration->abstractType(), element.type); 1260 attributeDeclaration->setAbstractType(newType); 1261 } 1262 } 1263 } 1264 1265 void DeclarationBuilder::tryUnpackType(AbstractType::Ptr sourceType, QVector<AbstractType::Ptr>& outTypes, int starred) { 1266 if ( const auto indexed = sourceType.dynamicCast<IndexedContainer>() ) { 1267 int spare = indexed->typesCount() - outTypes.length(); 1268 if ( spare < -1 || (starred == -1 && spare != 0) ) { 1269 return; // Wrong number of elements to unpack. 1270 } 1271 for ( int i_out = 0, i_in = 0; i_out < outTypes.length(); ++i_out ) { 1272 if ( i_out == starred ) { // PEP-3132. Made into list in assignToTuple(). 1273 for (; spare >= 0; --spare, ++i_in ) { 1274 auto content = indexed->typeAt(i_in).abstractType(); 1275 outTypes[i_out] = Helper::mergeTypes(outTypes.at(i_out), content); 1276 } 1277 } else { 1278 auto content = indexed->typeAt(i_in).abstractType(); 1279 outTypes[i_out] = Helper::mergeTypes(outTypes.at(i_out), content); 1280 ++i_in; 1281 } 1282 } 1283 } else { 1284 auto content = Helper::contentOfIterable(sourceType, topContext()); 1285 if ( !Helper::isUsefulType(content) ) { 1286 return; 1287 } 1288 for (auto out = outTypes.begin(); out != outTypes.end(); ++out) { 1289 *out = Helper::mergeTypes(*out, content); 1290 } 1291 } 1292 } 1293 1294 void DeclarationBuilder::assignToTuple(TupleAst* tuple, const SourceType& element) { 1295 int starred = -1; // Index (if any) of PEP-3132 starred assignment. 1296 for (int ii = 0; ii < tuple->elements.length(); ++ii) { 1297 if (tuple->elements.at(ii)->astType == Ast::StarredAstType) { 1298 starred = ii; 1299 break; 1300 } 1301 } 1302 1303 QVector<AbstractType::Ptr> outTypes(tuple->elements.length()); 1304 1305 if ( auto unsure = element.type.dynamicCast<UnsureType>() ) { 1306 FOREACH_FUNCTION ( const auto& type, unsure->types ) { 1307 tryUnpackType(type.abstractType(), outTypes, starred); 1308 } 1309 } else { 1310 tryUnpackType(element.type, outTypes, starred); 1311 } 1312 1313 for (int ii = 0; ii < outTypes.length(); ++ii) { 1314 const auto sourceType = outTypes.at(ii); 1315 auto target = tuple->elements.at(ii); 1316 if ( target->astType == Ast::StarredAstType ) { 1317 DUChainReadLocker lock; 1318 auto listType = ExpressionVisitor::typeObjectForIntegralType<ListType>("list"); 1319 lock.unlock(); 1320 if (listType) { 1321 listType->addContentType<Python::UnsureType>(sourceType); 1322 assignToUnknown(static_cast<StarredAst*>(target)->value, listType); 1323 } 1324 } else { 1325 assignToUnknown(target, sourceType); 1326 } 1327 } 1328 } 1329 1330 void DeclarationBuilder::assignToUnknown(ExpressionAst* target, const AbstractType::Ptr type) { 1331 auto source = SourceType{ 1332 type, 1333 DeclarationPointer(), 1334 false 1335 }; 1336 assignToUnknown(target, source); 1337 } 1338 1339 void DeclarationBuilder::assignToUnknown(ExpressionAst* target, const DeclarationBuilder::SourceType& element) { 1340 // Must be a nicer way to do this. 1341 if ( target->astType == Ast::TupleAstType ) { 1342 // Assignments of the form "a, b = 1, 2" or "a, b = c" 1343 assignToTuple(static_cast<TupleAst*>(target), element); 1344 } 1345 else if ( target->astType == Ast::NameAstType ) { 1346 // Assignments of the form "a = 3" 1347 assignToName(static_cast<NameAst*>(target), element); 1348 } 1349 else if ( target->astType == Ast::SubscriptAstType ) { 1350 // Assignments of the form "a[0] = 3" 1351 assignToSubscript(static_cast<SubscriptAst*>(target), element); 1352 } 1353 else if ( target->astType == Ast::AttributeAstType ) { 1354 // Assignments of the form "a.b = 3" 1355 assignToAttribute(static_cast<AttributeAst*>(target), element); 1356 } 1357 } 1358 1359 void DeclarationBuilder::visitAssignment(AssignmentAst* node) 1360 { 1361 AstDefaultVisitor::visitAssignment(node); 1362 1363 ExpressionVisitor v(currentContext()); 1364 v.visitNode(node->value); 1365 auto sourceType = SourceType{ 1366 v.lastType(), 1367 DeclarationPointer(Helper::resolveAliasDeclaration(v.lastDeclaration().data())), 1368 v.isAlias() 1369 }; 1370 1371 foreach(ExpressionAst* target, node->targets) { 1372 assignToUnknown(target, sourceType); 1373 } 1374 } 1375 1376 void DeclarationBuilder::visitAnnotationAssignment(AnnotationAssignmentAst* node) { 1377 AstDefaultVisitor::visitAnnotationAssignment(node); 1378 1379 ExpressionVisitor v(currentContext()); 1380 v.visitNode(node->target); 1381 v.visitNode(node->value); 1382 auto assignType = v.lastType(); // Never mind aliasing, why annotate that? 1383 v.visitNode(node->annotation); 1384 assignType = Helper::mergeTypes(assignType, v.lastType()); 1385 assignToUnknown(node->target, assignType); 1386 } 1387 1388 void DeclarationBuilder::visitAssignmentExpression(AssignmentExpressionAst* node) { 1389 AstDefaultVisitor::visitAssignmentExpression(node); 1390 1391 ExpressionVisitor v(currentContext()); 1392 v.visitNode(node->value); 1393 assignToUnknown(node->target, v.lastType()); 1394 } 1395 1396 void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) 1397 { 1398 visitNodeList(node->decorators); 1399 visitNodeList(node->baseClasses); 1400 const CorrectionHelper::Recursion r(m_correctionHelper->enterClass(node->name->value)); 1401 1402 StructureType::Ptr type(new StructureType()); 1403 1404 DUChainWriteLocker lock; 1405 ClassDeclaration* dec = eventuallyReopenDeclaration<ClassDeclaration>(node->name, NoTypeRequired); 1406 eventuallyAssignInternalContext(); 1407 1408 dec->setKind(KDevelop::Declaration::Type); 1409 dec->clearBaseClasses(); 1410 dec->setClassType(ClassDeclarationData::Class); 1411 1412 auto docstring = getDocstring(node->body); 1413 dec->setComment(docstring); 1414 if ( ! docstring.isEmpty() ) { 1415 // check whether this is a type container (list, dict, ...) or just a "normal" class 1416 if ( Helper::docstringContainsHint(docstring, "TypeContainer") ) { 1417 ListType* container = nullptr; 1418 if ( Helper::docstringContainsHint(docstring, "hasTypedKeys") ) { 1419 container = new MapType(); 1420 } 1421 else { 1422 container = new ListType(); 1423 } 1424 type = StructureType::Ptr(container); 1425 } 1426 if ( Helper::docstringContainsHint(docstring, "IndexedTypeContainer") ) { 1427 IndexedContainer* container = new IndexedContainer(); 1428 type = StructureType::Ptr(container); 1429 } 1430 } 1431 lock.unlock(); 1432 foreach ( ExpressionAst* c, node->baseClasses ) { 1433 // Iterate over all the base classes, and add them to the duchain. 1434 ExpressionVisitor v(currentContext()); 1435 v.visitNode(c); 1436 if ( v.lastType() && v.lastType()->whichType() == AbstractType::TypeStructure ) { 1437 auto baseClassType = v.lastType().staticCast<StructureType>(); 1438 BaseClassInstance base; 1439 base.baseClass = baseClassType->indexed(); 1440 base.access = KDevelop::Declaration::Public; 1441 lock.lock(); 1442 dec->addBaseClass(base); 1443 lock.unlock(); 1444 } 1445 } 1446 lock.lock(); 1447 // every python class inherits from "object". 1448 // We use this to add all the __str__, __get__, ... methods. 1449 if ( dec->baseClassesSize() == 0 && node->name->value != "object" ) { 1450 DUChainWriteLocker wlock; 1451 ReferencedTopDUContext docContext = Helper::getDocumentationFileContext(); 1452 if ( docContext ) { 1453 QList<Declaration*> object = docContext->findDeclarations( 1454 QualifiedIdentifier("object") 1455 ); 1456 if ( ! object.isEmpty() && object.first()->abstractType() ) { 1457 Declaration* objDecl = object.first(); 1458 BaseClassInstance base; 1459 base.baseClass = objDecl->abstractType()->indexed(); 1460 // this can be queried from autocompletion or elsewhere to hide the items, if required; 1461 // of course, it's not private strictly speaking 1462 base.access = KDevelop::Declaration::Private; 1463 dec->addBaseClass(base); 1464 } 1465 } 1466 } 1467 1468 type->setDeclaration(dec); 1469 dec->setType(type); 1470 1471 openType(type); 1472 m_currentClassTypes.append(type); 1473 1474 // needs to be done here, so the assignment of the internal context happens before visiting the body 1475 openContextForClassDefinition(node); 1476 dec->setInternalContext(currentContext()); 1477 1478 lock.unlock(); 1479 visitNodeList(node->body); 1480 lock.lock(); 1481 1482 closeContext(); 1483 m_currentClassTypes.removeLast(); 1484 closeType(); 1485 closeDeclaration(); 1486 } 1487 1488 void DeclarationBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) 1489 { 1490 const CorrectionHelper::Recursion r(m_correctionHelper->enterFunction(node->name->value)); 1491 1492 // Search for an eventual containing class declaration; 1493 // if that exists, then this function is a member function 1494 DeclarationPointer eventualParentDeclaration(currentDeclaration()); 1495 FunctionType::Ptr type(new FunctionType()); 1496 1497 DUChainWriteLocker lock; 1498 FunctionDeclaration* dec = eventuallyReopenDeclaration<FunctionDeclaration>(node->name, 1499 FunctionDeclarationType); 1500 1501 Q_ASSERT(dec->isFunctionDeclaration()); 1502 1503 // check for documentation 1504 dec->setComment(getDocstring(node->body)); 1505 1506 openType(type); 1507 dec->setInSymbolTable(false); 1508 dec->setType(type); 1509 1510 lock.unlock(); 1511 dec->setStatic(false); 1512 dec->setClassMethod(false); 1513 dec->setProperty(false); 1514 foreach ( auto decorator, node->decorators) { 1515 visitNode(decorator); 1516 switch (decorator->astType) { 1517 case Ast::AttributeAstType: { 1518 auto attr = static_cast<AttributeAst*>(decorator)->attribute->value; 1519 if ( attr == QStringLiteral("setter") || 1520 attr == QStringLiteral("getter") || 1521 attr == QStringLiteral("deleter") ) 1522 dec->setProperty(true); 1523 break; 1524 } 1525 case Ast::NameAstType: { 1526 auto name = static_cast<NameAst*>(decorator)->identifier->value; 1527 if ( name == QStringLiteral("staticmethod") ) 1528 dec->setStatic(true); 1529 else if ( name == QStringLiteral("classmethod") ) 1530 dec->setClassMethod(true); 1531 else if ( name == QStringLiteral("property") ) 1532 dec->setProperty(true); 1533 break; 1534 } 1535 default: {} 1536 } 1537 } 1538 visitFunctionArguments(node); 1539 visitFunctionBody(node); 1540 lock.lock(); 1541 1542 closeDeclaration(); 1543 eventuallyAssignInternalContext(); 1544 1545 closeType(); 1546 1547 // python methods don't have their parents attributes directly inside them 1548 if ( eventualParentDeclaration && eventualParentDeclaration->internalContext() && dec->internalContext() ) { 1549 dec->internalContext()->removeImportedParentContext(eventualParentDeclaration->internalContext()); 1550 } 1551 1552 { 1553 static IndexedString constructorName("__init__"); 1554 DUChainWriteLocker lock(DUChain::lock()); 1555 if ( dec->identifier().identifier() == constructorName ) { 1556 // the constructor returns an instance of the object, 1557 // nice to display it in tooltips etc. 1558 type->setReturnType(currentType<AbstractType>()); 1559 } 1560 if ( ! type->returnType() ) { 1561 type->setReturnType(AbstractType::Ptr(new NoneType())); 1562 } 1563 dec->setType(type); 1564 } 1565 1566 if ( ! dec->isStatic() ) { 1567 DUContext* args = DUChainUtils::argumentContext(dec); 1568 if ( args ) { 1569 QVector<Declaration*> parameters = args->localDeclarations(); 1570 static IndexedString newMethodName("__new__"); 1571 static IndexedString selfArgumentName("self"); 1572 static IndexedString clsArgumentName("cls"); 1573 if ( currentContext()->type() == DUContext::Class && ! parameters.isEmpty() && ! dec->isClassMethod() ) { 1574 QString description; 1575 if ( dec->identifier().identifier() == newMethodName 1576 && parameters[0]->identifier().identifier() != clsArgumentName ) 1577 { 1578 description = i18n("First argument of __new__ method is not called cls, this is deprecated"); 1579 } 1580 else if ( dec->identifier().identifier() != newMethodName 1581 && parameters[0]->identifier().identifier() != selfArgumentName ) 1582 { 1583 description = i18n("First argument of class method is not called self, this is deprecated"); 1584 } 1585 if ( ! description.isEmpty() ) { 1586 DUChainWriteLocker lock; 1587 KDevelop::Problem *p = new KDevelop::Problem(); 1588 p->setDescription(description); 1589 p->setFinalLocation(DocumentRange(currentlyParsedDocument(), parameters[0]->range().castToSimpleRange())); 1590 p->setSource(KDevelop::IProblem::SemanticAnalysis); 1591 p->setSeverity(KDevelop::IProblem::Warning); 1592 ProblemPointer ptr(p); 1593 topContext()->addProblem(ptr); 1594 } 1595 } 1596 else if ( currentContext()->type() == DUContext::Class && parameters.isEmpty() ) { 1597 DUChainWriteLocker lock; 1598 KDevelop::Problem *p = new KDevelop::Problem(); 1599 // only mark first line 1600 p->setFinalLocation(DocumentRange(currentlyParsedDocument(), KTextEditor::Range(node->startLine, node->startCol, node->startLine, 10000))); 1601 p->setSource(KDevelop::IProblem::SemanticAnalysis); 1602 p->setSeverity(KDevelop::IProblem::Warning); 1603 p->setDescription(i18n("Non-static class method without arguments, must have at least one (self)")); 1604 ProblemPointer ptr(p); 1605 topContext()->addProblem(ptr); 1606 } 1607 } 1608 } 1609 1610 if ( AbstractType::Ptr hint = m_correctionHelper->returnTypeHint() ) { 1611 type->setReturnType(hint); 1612 dec->setType(type); 1613 } 1614 1615 // check for (python3) function annotations 1616 if ( node->returns ) { 1617 lock.unlock(); 1618 ExpressionVisitor v(currentContext()); 1619 v.visitNode(node->returns); 1620 lock.lock(); 1621 if ( v.lastType() && v.isAlias() ) { 1622 type->setReturnType(Helper::mergeTypes(type->returnType(), v.lastType())); 1623 dec->setType(type); 1624 } 1625 else if ( ! v.isAlias()) { 1626 qCDebug(KDEV_PYTHON_DUCHAIN) << "not updating function return type because expression is not a type object"; 1627 } 1628 } 1629 1630 lock.lock(); 1631 dec->setInSymbolTable(true); 1632 } 1633 1634 QString DeclarationBuilder::getDocstring(QList< Python::Ast* > body) const 1635 { 1636 if ( ! body.isEmpty() && body.first()->astType == Ast::ExpressionAstType 1637 && static_cast<ExpressionAst*>(body.first())->value->astType == Ast::StringAstType ) 1638 { 1639 // If the first statement in a function/class body is a string, then that is the docstring. 1640 StringAst* docstring = static_cast<StringAst*>(static_cast<ExpressionAst*>(body.first())->value); 1641 docstring->usedAsComment = true; 1642 return docstring->value.trimmed(); 1643 } 1644 return QString(); 1645 } 1646 1647 void DeclarationBuilder::visitAssertion(AssertionAst* node) 1648 { 1649 adjustForTypecheck(node->condition, false); 1650 Python::AstDefaultVisitor::visitAssertion(node); 1651 } 1652 1653 void DeclarationBuilder::visitIf(IfAst* node) 1654 { 1655 adjustForTypecheck(node->condition, true); 1656 Python::AstDefaultVisitor::visitIf(node); 1657 } 1658 1659 void DeclarationBuilder::adjustForTypecheck(Python::ExpressionAst* check, bool useUnsure) 1660 { 1661 if ( ! check ) return; 1662 if ( check->astType == Ast::UnaryOperationAstType 1663 && static_cast<UnaryOperationAst*>(check)->type == Ast::UnaryOperatorNot ) 1664 { 1665 // It could be something like " if not isinstance(foo, Bar): return None ". 1666 check = static_cast<UnaryOperationAst*>(check)->operand; 1667 } 1668 if ( check->astType == Ast::CallAstType ) { 1669 // Is this a call of the form "isinstance(foo, bar)"? 1670 CallAst* call = static_cast<CallAst*>(check); 1671 if ( ! call->function ) { 1672 return; 1673 } 1674 if ( call->function->astType != Ast::NameAstType ) { 1675 return; 1676 } 1677 const QString functionName = static_cast<Python::NameAst*>(call->function)->identifier->value; 1678 if ( functionName != QLatin1String("isinstance") ) { 1679 return; 1680 } 1681 if ( call->arguments.length() != 2 ) { 1682 return; 1683 } 1684 adjustExpressionsForTypecheck(call->arguments.at(0), call->arguments.at(1), useUnsure); 1685 } 1686 else if ( check->astType == Ast::CompareAstType ) { 1687 // Is this a call of the form "type(ainstance) == a"? 1688 CompareAst* compare = static_cast<CompareAst*>(check); 1689 if ( compare->operators.size() != 1 || compare->comparands.size() != 1 ) { 1690 return; 1691 } 1692 if ( compare->operators.first() != Ast::ComparisonOperatorEquals ) { 1693 return; 1694 } 1695 ExpressionAst* c1 = compare->comparands.first(); 1696 ExpressionAst* c2 = compare->leftmostElement; 1697 if ( ! ( (c1->astType == Ast::CallAstType) ^ (c2->astType == Ast::CallAstType) ) ) { 1698 // Exactly one of the two must be a call. TODO: support adjusting function return types 1699 return; 1700 } 1701 CallAst* typecall = static_cast<CallAst*>(c1->astType == Ast::CallAstType ? c1 : c2); 1702 if ( ! typecall->function || typecall->function->astType != Ast::NameAstType || typecall->arguments.length() != 1 ) { 1703 return; 1704 } 1705 const QString functionName = static_cast<Python::NameAst*>(typecall->function)->identifier->value; 1706 if ( functionName != QLatin1String("type") ) { 1707 return; 1708 } 1709 adjustExpressionsForTypecheck(typecall->arguments.at(0), c1->astType == Ast::CallAstType ? c2 : c1, useUnsure); 1710 } 1711 } 1712 1713 void DeclarationBuilder::adjustExpressionsForTypecheck(Python::ExpressionAst* adjustExpr, Python::ExpressionAst* from, bool useUnsure) 1714 { 1715 // Find types of the two arguments 1716 ExpressionVisitor first(currentContext()); 1717 ExpressionVisitor second(currentContext()); 1718 first.visitNode(adjustExpr); 1719 second.visitNode(from); 1720 AbstractType::Ptr hint; 1721 DeclarationPointer adjust; 1722 if ( second.isAlias() && second.lastType() ) { 1723 hint = second.lastType(); 1724 adjust = first.lastDeclaration(); 1725 } 1726 if ( ! adjust || adjust->isFunctionDeclaration() ) { 1727 // no declaration for the thing to verify, can't adjust it. 1728 return; 1729 } 1730 else if ( adjust->topContext() == Helper::getDocumentationFileContext() ) { 1731 // do not motify types in the doc context 1732 return; 1733 } 1734 DUChainWriteLocker lock; 1735 if ( useUnsure ) { 1736 adjust->setAbstractType(Helper::mergeTypes(adjust->abstractType(), hint)); 1737 } 1738 else { 1739 adjust->setAbstractType(hint); 1740 } 1741 } 1742 1743 void DeclarationBuilder::visitReturn(ReturnAst* node) 1744 { 1745 static auto noneType = AbstractType::Ptr(new NoneType()); 1746 1747 if ( auto function = currentType<FunctionType>() ) { 1748 // Statements with no explicit value return `None`. 1749 auto encountered = noneType; 1750 if ( node->value ) { 1751 // Find the type of the object being "return"ed 1752 ExpressionVisitor v(currentContext()); 1753 v.visitNode(node->value); 1754 encountered = v.lastType(); 1755 } 1756 // Update the containing function's return type 1757 DUChainWriteLocker lock; 1758 function->setReturnType(Helper::mergeTypes(function->returnType(), encountered)); 1759 } else { 1760 DUChainWriteLocker lock; 1761 KDevelop::Problem *p = new KDevelop::Problem(); 1762 p->setFinalLocation(DocumentRange(currentlyParsedDocument(), node->range())); // only mark first line 1763 p->setSource(KDevelop::IProblem::SemanticAnalysis); 1764 p->setDescription(i18n("Return statement not within function declaration")); 1765 ProblemPointer ptr(p); 1766 topContext()->addProblem(ptr); 1767 } 1768 DeclarationBuilderBase::visitReturn(node); 1769 } 1770 1771 void DeclarationBuilder::visitArguments( ArgumentsAst* node ) 1772 { 1773 if ( ! currentDeclaration() || ! currentDeclaration()->isFunctionDeclaration() ) { 1774 return; 1775 } 1776 FunctionDeclaration* workingOnDeclaration = static_cast<FunctionDeclaration*>(Helper::resolveAliasDeclaration(currentDeclaration())); 1777 workingOnDeclaration->clearDefaultParameters(); 1778 if ( ! hasCurrentType() || ! currentType<FunctionType>() ) { 1779 return; 1780 } 1781 FunctionType::Ptr type = currentType<FunctionType>(); 1782 bool isFirst = true; 1783 int defaultParametersCount = node->defaultValues.length(); 1784 int parametersCount = node->arguments.length(); 1785 int firstDefaultParameterOffset = parametersCount - defaultParametersCount; 1786 1787 int defaultKwParametersCount = node->defaultKwValues.length(); 1788 int kwonlyCount = node->kwonlyargs.length(); 1789 int posonlyCount = node->posonlyargs.length(); 1790 int totalArgCount = parametersCount + posonlyCount + kwonlyCount; 1791 int firstDefaultKwParameterOffset = totalArgCount - defaultKwParametersCount; 1792 int currentIndex = 0; 1793 foreach ( ArgAst* arg, node->posonlyargs + node->arguments + node->kwonlyargs ) { 1794 // Iterate over all the function's arguments, create declarations, and add the arguments 1795 // to the functions FunctionType. 1796 currentIndex += 1; 1797 1798 if ( ! arg->argumentName ) { 1799 continue; 1800 } 1801 1802 // Create a variable declaration for the parameter, to be used in the function body. 1803 Declaration* paramDeclaration = nullptr; 1804 if ( currentIndex == 1 && workingOnDeclaration->isClassMethod() ) { 1805 DUChainWriteLocker lock; 1806 AliasDeclaration* decl = eventuallyReopenDeclaration<AliasDeclaration>(arg->argumentName, 1807 AliasDeclarationType); 1808 if ( ! m_currentClassTypes.isEmpty() ) { 1809 auto classDecl = m_currentClassTypes.last()->declaration(topContext()); 1810 1811 decl->setAliasedDeclaration(classDecl); 1812 } 1813 closeDeclaration(); 1814 paramDeclaration = decl; 1815 } 1816 else { 1817 paramDeclaration = visitVariableDeclaration<Declaration>(arg->argumentName); 1818 } 1819 if ( ! paramDeclaration ) { 1820 qCDebug(KDEV_PYTHON_DUCHAIN) << "could not create parameter declaration!"; 1821 continue; 1822 } 1823 1824 AbstractType::Ptr argumentType(new IntegralType(IntegralType::TypeMixed)); 1825 if ( arg->annotation ) { 1826 ExpressionVisitor v(currentContext()); 1827 v.visitNode(arg->annotation); 1828 if ( v.lastType() && v.isAlias() ) { 1829 DUChainWriteLocker lock; 1830 argumentType = Helper::mergeTypes(paramDeclaration->abstractType(), v.lastType()); 1831 } 1832 } 1833 else if ( currentIndex > firstDefaultParameterOffset && currentIndex <= node->arguments.size() ) { 1834 // Handle arguments with default values, like def foo(bar = 3): pass 1835 // Find type of given default value, and assign it to the declaration 1836 ExpressionVisitor v(currentContext()); 1837 v.visitNode(node->defaultValues.at(currentIndex - firstDefaultParameterOffset - 1)); 1838 if ( v.lastType() ) { 1839 argumentType = v.lastType(); 1840 } 1841 // TODO add the real expression from the document here as default value 1842 workingOnDeclaration->addDefaultParameter(IndexedString("...")); 1843 } 1844 else if ( currentIndex > firstDefaultKwParameterOffset && currentIndex <= totalArgCount ) { 1845 // Handle kw only arguments with default values, like def foo(*, bar = 3): pass 1846 // Find type of given default value, and assign it to the declaration 1847 ExpressionVisitor v(currentContext()); 1848 v.visitNode(node->defaultKwValues.at(currentIndex - firstDefaultKwParameterOffset - 1)); 1849 if ( v.lastType() ) { 1850 argumentType = v.lastType(); 1851 } 1852 // TODO add the real expression from the document here as default value 1853 workingOnDeclaration->addDefaultParameter(IndexedString("...")); 1854 } 1855 1856 1857 if ( isFirst && ! workingOnDeclaration->isStatic() && currentContext() && currentContext()->parentContext() ) { 1858 DUChainReadLocker lock; 1859 if ( currentContext()->parentContext()->type() == DUContext::Class ) { 1860 argumentType = m_currentClassTypes.last(); 1861 isFirst = false; 1862 } 1863 } 1864 1865 DUChainWriteLocker lock; 1866 paramDeclaration->setAbstractType(Helper::mergeTypes(paramDeclaration->abstractType(), argumentType)); 1867 type->addArgument(argumentType); 1868 } 1869 // Handle *args, **kwargs, and assign them a list / dictionary type. 1870 if ( node->vararg ) { 1871 // inject the vararg at the correct place 1872 int atIndex = 0; 1873 int useIndex = -1; 1874 foreach ( ArgAst* arg, node->arguments ) { 1875 if ( node->vararg && workingOnDeclaration->vararg() == -1 && node->vararg->appearsBefore(arg) ) { 1876 useIndex = atIndex; 1877 } 1878 atIndex += 1; 1879 } 1880 if ( useIndex == -1 ) { 1881 // if the vararg does not appear in the middle of the params, place it at the end. 1882 // this is new in python3, you can do like def fun(a, b, *c, z): pass 1883 useIndex = type->arguments().size(); 1884 } 1885 DUChainReadLocker lock; 1886 IndexedContainer::Ptr tupleType = ExpressionVisitor::typeObjectForIntegralType<IndexedContainer>("tuple"); 1887 lock.unlock(); 1888 if ( tupleType ) { 1889 visitVariableDeclaration<Declaration>(node->vararg->argumentName, nullptr, tupleType); 1890 workingOnDeclaration->setVararg(atIndex); 1891 type->addArgument(tupleType, useIndex); 1892 } 1893 } 1894 1895 if ( node->kwarg ) { 1896 DUChainReadLocker lock; 1897 AbstractType::Ptr stringType = ExpressionVisitor::typeObjectForIntegralType<AbstractType>("str"); 1898 auto dictType = ExpressionVisitor::typeObjectForIntegralType<MapType>("dict"); 1899 lock.unlock(); 1900 if ( dictType && stringType ) { 1901 dictType->addKeyType<Python::UnsureType>(stringType); 1902 visitVariableDeclaration<Declaration>(node->kwarg->argumentName, nullptr, dictType); 1903 type->addArgument(dictType); 1904 workingOnDeclaration->setKwarg(type->arguments().size() - 1); 1905 } 1906 } 1907 } 1908 1909 void DeclarationBuilder::visitString(StringAst* node) { 1910 if ( node->parent && node->parent->astType == Ast::ExpressionAstType ) { 1911 m_lastComment = node; 1912 } 1913 DeclarationBuilderBase::visitString(node); 1914 } 1915 1916 void DeclarationBuilder::visitNode(Ast* node) { 1917 DeclarationBuilderBase::visitNode(node); 1918 if ( node && node->astType >= Ast::StatementAstType && node->astType <= Ast::LastStatementType) { 1919 m_lastComment = nullptr; 1920 } 1921 } 1922 1923 void DeclarationBuilder::visitGlobal(GlobalAst* node) 1924 { 1925 TopDUContext* top = topContext(); 1926 foreach ( Identifier *id, node->names ) { 1927 QualifiedIdentifier qid = identifierForNode(id); 1928 DUChainWriteLocker lock; 1929 QList< Declaration* > existing = top->findLocalDeclarations(qid.first()); 1930 if ( ! existing.empty() ) { 1931 AliasDeclaration* ndec = openDeclaration<AliasDeclaration>(id); 1932 ndec->setAliasedDeclaration(existing.first()); 1933 closeDeclaration(); 1934 } 1935 else { 1936 injectContext(top); 1937 Declaration* dec = visitVariableDeclaration<Declaration>(id); 1938 dec->setRange(editorFindRange(id, id)); 1939 dec->setAutoDeclaration(true); 1940 closeContext(); 1941 AliasDeclaration* ndec = openDeclaration<AliasDeclaration>(id); 1942 ndec->setAliasedDeclaration(dec); 1943 closeDeclaration(); 1944 } 1945 } 1946 } 1947 1948 } 1949 1950