File indexing completed on 2024-04-21 15:25:24

0001 /*
0002     SPDX-FileCopyrightText: 2011-2012 Sven Brauch <svenbrauch@googlemail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef GLOBALHELPERS_H
0008 #define GLOBALHELPERS_H
0009 
0010 #include "pythonduchainexport.h"
0011 #include "types/unsuretype.h"
0012 #include "ast.h"
0013 
0014 #include <interfaces/iproject.h>
0015 #include <language/duchain/declaration.h>
0016 #include <language/duchain/types/unsuretype.h>
0017 #include <language/duchain/topducontext.h>
0018 #include <language/duchain/types/structuretype.h>
0019 #include <language/duchain/types/integraltype.h>
0020 #include <language/duchain/classdeclaration.h>
0021 #include <language/duchain/functiondeclaration.h>
0022 
0023 #include <QList>
0024 
0025 #include <functional>
0026 
0027 #include "declarations/functiondeclaration.h"
0028 
0029 using namespace KDevelop;
0030 
0031 namespace Python {
0032 
0033 class KDEVPYTHONDUCHAIN_EXPORT Helper {
0034 public:
0035     /** get search paths for python files **/
0036     static QVector<QUrl> getSearchPaths(const QUrl& workingOnDocument);
0037     static QStringList dataDirs;
0038     static IndexedString documentationFile;
0039     static QStringList correctionFileDirs;
0040     static QString localCorrectionFileDir;
0041     static DUChainPointer<TopDUContext> documentationFileContext;
0042 
0043     static QStringList getDataDirs();
0044     static IndexedString getDocumentationFile();
0045     static ReferencedTopDUContext getDocumentationFileContext();
0046 
0047     static QUrl getCorrectionFile(const QUrl& document);
0048     static QUrl getLocalCorrectionFile(const QUrl& document);
0049 
0050     static QMutex cacheMutex;
0051     static QMap<IProject*, QVector<QUrl>> cachedCustomIncludes;
0052     static QMap<IProject*, QVector<QUrl>> cachedSearchPaths;
0053 
0054     static QMutex projectPathLock;
0055     static QVector<QUrl> projectSearchPaths;
0056 
0057     static AbstractType::Ptr extractTypeHints(AbstractType::Ptr type);
0058 
0059     /**
0060      * @brief Get the declaration of 'accessed.attribute', or return null.
0061      *
0062      * @param accessed Type (Structure or Unsure) that should have this attribute.
0063      * @param attribute Which attribute to look for.
0064      * @param topContext Top context (for this file?)
0065      * @return Declaration* of the attribute, or null.
0066      *  If UnsureType with >1 matching attributes, returns an arbitrary choice.
0067      **/
0068     static KDevelop::Declaration* accessAttribute(const KDevelop::AbstractType::Ptr accessed,
0069                                                   const KDevelop::IndexedIdentifier& attribute,
0070                                                   const KDevelop::TopDUContext* topContext);
0071 
0072     static KDevelop::Declaration* accessAttribute(const KDevelop::AbstractType::Ptr accessed,
0073         const QString& attribute, const KDevelop::TopDUContext* topContext) {
0074         return accessAttribute(accessed, IndexedIdentifier(KDevelop::Identifier(attribute)), topContext);
0075     }
0076 
0077     static AbstractType::Ptr resolveAliasType(const AbstractType::Ptr eventualAlias);
0078 
0079     /**
0080      * @brief Get the content type(s) of something that is an iterable.
0081      *
0082      * @param iterable Type to get the contents of. Can be an unsure.
0083      * @return KDevelop::AbstractType::Ptr Content type. Might be an unsure.
0084      */
0085     static AbstractType::Ptr contentOfIterable(const AbstractType::Ptr iterable, const TopDUContext* topContext);
0086 
0087     /**
0088      * @brief Get a list of types inside the passed type which match the specified filter.
0089      * The filter will be matched against the type only if it is not an unsure type,
0090      * or else against all types inside that unsure type.
0091      * @param type The type to search
0092      * @param accept Filter function, return true if you want the type.
0093      * @return QList< KDevelop::AbstractType::Ptr > list of types accepted by the filter.
0094      */
0095     template <typename T>
0096     static QList<typename T::Ptr> filterType(AbstractType::Ptr type, std::function<bool(AbstractType::Ptr)> accept,
0097                                              std::function<typename T::Ptr(AbstractType::Ptr)> map =
0098                                              std::function<typename T::Ptr(AbstractType::Ptr)>())
0099     {
0100         QList<typename T::Ptr> types;
0101         if ( ! type ) {
0102             return types;
0103         }
0104         if ( type->whichType() == KDevelop::AbstractType::TypeUnsure ) {
0105             auto unsure = type.staticCast<UnsureType>();
0106             for ( unsigned int i = 0; i < unsure->typesSize(); i++ ) {
0107                 AbstractType::Ptr t = unsure->types()[i].abstractType();
0108                 if ( accept(t) ) {
0109                     types << ( map ? map(t) : t.dynamicCast<T>() );
0110                 }
0111             }
0112         }
0113         else if ( accept(type) ) {
0114             types << ( map ? map(type) : type.dynamicCast<T>() );
0115         }
0116         return types;
0117     }
0118 
0119     static void scheduleDependency(const IndexedString& dependency, int betterThanPriority);
0120 
0121     static KDevelop::IndexedDeclaration declarationUnderCursor(bool allowUse = true);
0122 
0123     struct FuncInfo { FunctionDeclaration* declaration; bool isConstructor; };
0124     /**
0125      * @brief Finds whether the specified called declaration is a function declaration, and if not,
0126      *        checks for a class declaration; then returns the constructor
0127      *
0128      * @param called the declaration to check
0129      * @param isAlias whether the called declaration aliases a class or function definition.
0130      * @return the function pointer which was found, or an invalid pointer, and a bool
0131      *         which is true when it is a constructor
0132      **/
0133     static FuncInfo functionForCalled(Declaration* called, bool isAlias=true);
0134 
0135     static bool docstringContainsHint(const QString& comment, const QString& hintName, QStringList* args = nullptr) {
0136         // TODO cache types! this is horribly inefficient
0137         const QString search = "! " + hintName + " !";
0138         int index = comment.indexOf(search);
0139         if ( index >= 0 ) {
0140             if ( args ) {
0141                 int eol = comment.indexOf('\n', index);
0142                 int start = index+search.size()+1;
0143                 QString decl = comment.mid(start, eol-start);
0144                 *args = decl.split(' ');
0145             }
0146             return true;
0147         }
0148         return false;
0149     }
0150 
0151     /**
0152      * @copydoc TypeUtils::mergeTypes
0153      */
0154     static AbstractType::Ptr mergeTypes(AbstractType::Ptr type, const AbstractType::Ptr newType);
0155 
0156     /**
0157      * @brief Like mergeTypes(), but merges a list of types into a newly allocated type.
0158      * Returns mixed if the list is empty.
0159      * @return KDevelop::AbstractType::Ptr an unsure type consisting of all types in the list.
0160      */
0161     template <typename T>
0162     static AbstractType::Ptr foldTypes(QList<T> types, std::function<AbstractType::Ptr(const T&)> transform
0163                                                      = std::function<AbstractType::Ptr(const T&)>())
0164     {
0165         AbstractType::Ptr result(new IntegralType(IntegralType::TypeMixed));
0166         for ( T type : types ) {
0167             result = Helper::mergeTypes(result, transform ? transform(type) : type);
0168         }
0169         return result;
0170     };
0171 
0172     /** check whether the argument is a null, mixed, or none integral type **/
0173     static bool isUsefulType(AbstractType::Ptr type);
0174 
0175     enum ContextSearchFlags {
0176         NoFlags,
0177         PublicOnly
0178     };
0179 
0180     /**
0181     * @brief Find all internal contexts for this class and its base classes recursively
0182     *
0183     * @param classType Type object for the class to search contexts
0184     * @param context TopContext for finding the declarations for types
0185     * @return list of contexts which were found
0186     **/
0187     static QVector<DUContext*> internalContextsForClass(const KDevelop::StructureType::Ptr classType,
0188                                                         const TopDUContext* context,
0189                                                         ContextSearchFlags flags = NoFlags, int depth = 0);
0190     /**
0191       * @brief Resolve the given declaration if it is an alias declaration.
0192       *
0193       * @param decl the declaration to resolve
0194       * @return :Declaration* decl if not an alias declaration, decl->aliasedDeclaration().data otherwise
0195       * DUChain must be read locked
0196       **/
0197     static Declaration* resolveAliasDeclaration(Declaration* decl);
0198 
0199     static Declaration* declarationForName(const QString& name, const CursorInRevision& location,
0200                                           DUChainPointer<const DUContext> context);
0201 
0202     static Declaration* declarationForName(const Python::NameAst* name, CursorInRevision location,
0203                                            DUChainPointer<const DUContext> context);
0204 
0205     static QString getPythonExecutablePath(IProject* project);
0206 };
0207 
0208 }
0209 
0210 #endif
0211