File indexing completed on 2024-05-05 16:42:26

0001 /*
0002     SPDX-FileCopyrightText: 2013 Sven Brauch <svenbrauch@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "correctionhelper.h"
0008 #include "helpers.h"
0009 #include "declarationbuilder.h"
0010 
0011 #include <language/duchain/duchain.h>
0012 #include <language/duchain/duchainlock.h>
0013 #include <language/duchain/declaration.h>
0014 
0015 #include <QDebug>
0016 #include "duchaindebug.h"
0017 
0018 
0019 #include <QFile>
0020 
0021 using namespace KDevelop;
0022 
0023 namespace Python {
0024 
0025 CorrectionHelper::CorrectionHelper(const IndexedString& _url, DeclarationBuilder* builder)
0026 {
0027     m_contextStack.push(nullptr);
0028     auto absolutePath = Helper::getCorrectionFile(_url.toUrl());
0029 
0030     if ( !absolutePath.isValid() || absolutePath.isEmpty() || ! QFile::exists(absolutePath.path()) ) {
0031         return;
0032     }
0033     qCDebug(KDEV_PYTHON_DUCHAIN) << "Found correction file for " << _url.str() << ": " << absolutePath.path();
0034 
0035     const IndexedString indexedPath(absolutePath);
0036     DUChainReadLocker lock;
0037     m_hintTopContext = DUChain::self()->chainForDocument(indexedPath);
0038     qCDebug(KDEV_PYTHON_DUCHAIN) << "got top context for" << absolutePath << m_hintTopContext;
0039     m_contextStack.top() = m_hintTopContext.data();
0040     if ( ! m_hintTopContext ) {
0041         // The file exists, but was not parsed yet. Schedule it, and re-schedule the current one too.
0042         Helper::scheduleDependency(indexedPath, builder->jobPriority());
0043         builder->addUnresolvedImport(indexedPath);
0044     }
0045 }
0046 
0047 CorrectionHelper::~CorrectionHelper()
0048 {
0049     Q_ASSERT(m_contextStack.size() == 1);
0050     Q_ASSERT(m_contextStack.top() == m_hintTopContext.data());
0051 }
0052 
0053 void CorrectionHelper::enter(const KDevelop::Identifier& identifier)
0054 {
0055     DUContext* current = m_contextStack.top();
0056     if ( ! current ) {
0057         // no hints for the parent object, so no hints for its children either
0058         m_contextStack.push(nullptr);
0059         return;
0060     }
0061 
0062     DUChainReadLocker lock;
0063     const QList<Declaration*> decls = current->findDeclarations(identifier);
0064     if ( decls.isEmpty() ) {
0065         // no hints for the current object
0066         m_contextStack.push(nullptr);
0067         return;
0068     }
0069 
0070     qCDebug(KDEV_PYTHON_DUCHAIN) << "Looking in " << identifier.toString();
0071     // there's a hint declaration for this object, put it on the stack
0072     DUContext* internal = decls.first()->internalContext();
0073     m_contextStack.push(internal);
0074     return;
0075 }
0076 
0077 AbstractType::Ptr CorrectionHelper::hintForLocal(const QString &local) const
0078 {
0079     return hintFor(KDevelop::Identifier(QLatin1String("l_") + local));
0080 }
0081 
0082 AbstractType::Ptr CorrectionHelper::returnTypeHint() const
0083 {
0084     return hintFor(KDevelop::Identifier(QLatin1String("returns")));
0085 }
0086 
0087 AbstractType::Ptr CorrectionHelper::hintFor(const KDevelop::Identifier &identifier) const
0088 {
0089     DUContext* current = m_contextStack.top();
0090     AbstractType::Ptr hint;
0091     if ( ! current ) {
0092         return hint;
0093     }
0094     const QList<Declaration*> decls = current->findDeclarations(identifier);
0095     if ( decls.isEmpty() ) {
0096         return hint;
0097     }
0098 
0099     qCDebug(KDEV_PYTHON_DUCHAIN) << "Found specified correct type for " << identifier.toString() << decls.first()->abstractType()->toString();
0100     return decls.first()->abstractType();
0101 }
0102 
0103 
0104 CorrectionHelper::Recursion CorrectionHelper::enterClass(const QString& identifier)
0105 {
0106     enter(KDevelop::Identifier(QLatin1String("class_") + identifier));
0107     return CorrectionHelper::Recursion(this);
0108 }
0109 
0110 CorrectionHelper::Recursion CorrectionHelper::enterFunction(const QString &identifier)
0111 {
0112     enter(KDevelop::Identifier(QLatin1String("function_") + identifier));
0113     return CorrectionHelper::Recursion(this);
0114 }
0115 
0116 void CorrectionHelper::leave()
0117 {
0118     m_contextStack.pop();
0119 }
0120 
0121 }