File indexing completed on 2024-05-12 04:38:05

0001 /*
0002     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2007-2009 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #ifndef KDEVPLATFORM_TOPDUCONTEXT_H
0009 #define KDEVPLATFORM_TOPDUCONTEXT_H
0010 
0011 #include "ducontext.h"
0012 #include <language/util/setrepository.h>
0013 #include <QMetaType>
0014 
0015 template <class T>
0016 class QExplicitlySharedDataPointer;
0017 
0018 namespace KDevelop {
0019 class IAstContainer;
0020 class QualifiedIdentifier;
0021 class DUChain;
0022 class ParsingEnvironmentFile;
0023 class TopDUContextData;
0024 class TopDUContextLocalPrivate;
0025 class IndexedTopDUContext;
0026 //   class TopDUContextDynamicData;
0027 class Problem;
0028 class DeclarationChecker;
0029 class TopDUContext;
0030 
0031 struct KDEVPLATFORMLANGUAGE_EXPORT RecursiveImportRepository
0032 {
0033     static Utils::BasicSetRepository* repository();
0034 };
0035 
0036 ///Maps an imported top-context to a pair:
0037 ///1. The distance to the top-context, and 2. The next step towards the top-context
0038 ///in the chain.
0039 using RecursiveImports = QHash<const TopDUContext*, QPair<int, const TopDUContext*>>;
0040 
0041 using TopDUContextPointer = DUChainPointer<TopDUContext>;
0042 
0043 using ProblemPointer = QExplicitlySharedDataPointer<Problem>;
0044 
0045 ///KDevelop can unload unused top-context at any time. To prevent unloading,
0046 ///keep a ReferencedTopDUContext.
0047 class KDEVPLATFORMLANGUAGE_EXPORT ReferencedTopDUContext
0048 {
0049 public:
0050     ReferencedTopDUContext(TopDUContext* context = nullptr);
0051     ReferencedTopDUContext(const ReferencedTopDUContext& rhs);
0052     ~ReferencedTopDUContext();
0053 
0054     ReferencedTopDUContext& operator=(const ReferencedTopDUContext& rhs);
0055 
0056     inline TopDUContext* data() const
0057     {
0058         return m_topContext;
0059     }
0060 
0061     inline operator TopDUContext*() const {
0062         return m_topContext;
0063     }
0064 
0065     inline bool operator==(const ReferencedTopDUContext& rhs) const
0066     {
0067         return m_topContext == rhs.m_topContext;
0068     }
0069 
0070     inline bool operator!=(const ReferencedTopDUContext& rhs) const
0071     {
0072         return m_topContext != rhs.m_topContext;
0073     }
0074 
0075     inline TopDUContext* operator->() const
0076     {
0077         return m_topContext;
0078     }
0079 
0080     inline uint hash() const
0081     {
0082         return ( uint )((( quint64 )m_topContext) * 37);
0083     }
0084 
0085 private:
0086     TopDUContext* m_topContext;
0087 };
0088 
0089 /**
0090  * The top context in a definition-use chain for one source file.
0091  *
0092  * Implements SymbolTable lookups and locking for the chain.
0093  *
0094  * Contexts and Classes can only be found through TopDUContext if they are in the symbol table.
0095  * @see DUContext::setInSymbolTable, Declaration::setInSymbolTable
0096  *
0097  * \todo move the registration with DUChain here
0098  *
0099  * @warning Do not delete top-contexts directly, use DUChain::removeDocumentChain instead.
0100  */
0101 class KDEVPLATFORMLANGUAGE_EXPORT TopDUContext
0102     : public DUContext
0103 {
0104 public:
0105     explicit TopDUContext(const IndexedString& url, const RangeInRevision& range,
0106                           ParsingEnvironmentFile* file = nullptr);
0107     explicit TopDUContext(TopDUContextData& data);
0108 
0109     TopDUContext& operator=(const TopDUContext& rhs) = delete;
0110 
0111     TopDUContext* topContext() const override;
0112 
0113     ///Returns an indexed representation of this top-context. Indexed representations stay valid even if the top-context is unloaded.
0114     IndexedTopDUContext indexed() const;
0115 
0116     uint ownIndex() const;
0117 
0118     IndexedString url() const override;
0119 
0120     /**
0121      * @see ParsingEnvironmentFile
0122      * May return zero if no file was set.
0123      * */
0124     QExplicitlySharedDataPointer<ParsingEnvironmentFile> parsingEnvironmentFile() const;
0125 
0126     /// Returns true if this object is being deleted, otherwise false.
0127     bool deleting() const;
0128 
0129     /// Returns true if this object is registered in the du-chain. If it is not, all sub-objects(context, declarations, etc.) can be changed
0130     bool inDUChain() const override;
0131     /// This flag is only used by DUChain, never change it from outside.
0132     void setInDuChain(bool);
0133 
0134     /// Whether this top-context has a stored version on disk
0135     bool isOnDisk() const;
0136 
0137     /**
0138      * Returns a list of all problems encountered while parsing this top-context.
0139      * Does not include the problems of imported contexts.
0140      * */
0141     QList<ProblemPointer> problems() const;
0142 
0143     /**
0144      * Add a parsing-problem to this context.
0145      *
0146      * \note you must be holding a write lock when you access this function.
0147      * */
0148     void addProblem(const ProblemPointer& problem);
0149 
0150     /**
0151      * Clear the list of problems
0152      *
0153      * \note you must be holding a write lock when you access this function.
0154      */
0155     void clearProblems();
0156 
0157     /**
0158      * Set the list of problems, replacing all existing ones.
0159      *
0160      * \note you must be holding a write lock when you access this function.
0161      */
0162     void setProblems(const QList<ProblemPointer>& pointers);
0163 
0164     /**
0165      * Determine if this chain imports another chain recursively.
0166      *
0167      * This uses the imports-cache for speedup if it is available, thus it is not necessarily 100% correct
0168      * if the cache is not up-to-date.
0169      *
0170      * \note you must be holding a read but not a write chain lock when you access this function.
0171      */
0172     bool imports(const DUContext* origin, const CursorInRevision& position) const override;
0173 
0174     enum {
0175         Identity = 4
0176     };
0177 
0178     enum Feature : quint16 {
0179         ///Top-context features standard that can be requested from the duchain, and that are stored in the features() member.
0180         Empty = 0, //Only the top-context structure (imports etc.) is built, but no declarations and no contexts
0181         SimplifiedVisibleDeclarationsAndContexts = 2, //The top-context should only contain publicly simplified accessible declarations and contexts, without doing type look-up,
0182         //without extended information like function-argument declarations, etc., imported contexts can be parsed with 'Empty' features
0183         //This flag essentially leads to a ctags-like processing level.
0184         VisibleDeclarationsAndContexts = SimplifiedVisibleDeclarationsAndContexts + 4, //Default: The top-context should only contain publicly accessible declarations and contexts
0185         AllDeclarationsAndContexts = VisibleDeclarationsAndContexts + 8, //The top-context should also contain non-public declarations and contexts, but no uses
0186         AllDeclarationsContextsAndUses = 16 + AllDeclarationsAndContexts, //The top-context should contain uses and all declarations + contexts
0187         AST = 32,         //Signalizes that the ast() should be filled
0188         AllDeclarationsContextsUsesAndAST = AST | AllDeclarationsContextsAndUses, //Convenience flag, combining AST and AllDeclarationsContextsAndUses
0189 
0190         ///Additional update-flags that have a special meaning during updating, but are not set stored into a top-context
0191         Recursive = 64, //Request the given features on all recursively imported contexts. Only the features are applied recursively (including AST)
0192         ForceUpdate = 128, //Enforce updating the top-context
0193         ForceUpdateRecursive = ForceUpdate | 256, //Enforce updating the top-context and all its imports
0194 
0195         ///You can define own language-dependent features behind this flag
0196         LastFeature = 512
0197     };
0198     Q_DECLARE_FLAGS(Features, Feature)
0199 
0200     ///Returns the currently active features of this top-context. The features will include AST if ast() is valid.
0201     Features features() const;
0202     ///Set the features of this top-context. These features are ignored: AST, ForceUpdate, and ForceUpdateRecursive.
0203     void setFeatures(Features);
0204 
0205     /**
0206      * Retrieves or creates a local index that is to be used for referencing the given @param declaration
0207      * in local uses. Also registers this context as a user of the declaration.
0208      * @param create If this is false, only already registered indices will be returned.
0209      *               If the declaration is not registered, std::numeric_limits<int>::max() is returned
0210      *
0211      * The duchain must be write-locked if create is true, else it must at least be read-locked.
0212      * */
0213     int indexForUsedDeclaration(Declaration* declaration, bool create = true);
0214 
0215     /**
0216      * Tries to retrieve the used declaration
0217      * @param declarationIndex The index of the declaration which have to be retrieved
0218      * */
0219     Declaration* usedDeclarationForIndex(unsigned int declarationIndex) const;
0220 
0221     /**
0222      * You can use this before you rebuild all uses. This does not affect any uses directly,
0223      * it only invalidates the mapping of declarationIndices to Declarations.
0224      *
0225      * usedDeclarationForIndex(..) must not be called until the use has gotten a new index through
0226      * indexForUsedDeclaration(..).
0227      * */
0228     void clearUsedDeclarationIndices();
0229 
0230     /**
0231      * Recursively deletes all contained uses, declaration-indices, etc.
0232      */
0233     void deleteUsesRecursively() override;
0234 
0235     /**
0236      * Returns the AST Container, that contains the AST created during parsing.
0237      * This is only created if you request the AST feature for parsing.
0238      * It may be discarded at any time. Every update without the AST feature will discard it.
0239      * The actual contents is language-specific.
0240      *
0241      * @todo Figure out logic to get rid of AST when it is not needed/useful
0242      */
0243     QExplicitlySharedDataPointer<IAstContainer> ast() const;
0244 
0245     /**
0246      * Sets the AST Container.
0247      */
0248     void setAst(const QExplicitlySharedDataPointer<IAstContainer>& ast);
0249 
0250     /**
0251      * Utility function to clear the AST Container
0252      */
0253     void clearAst();
0254 
0255     ///@param temporary If this is true, importers of this context will not be notified of the new imports. This greatly increases performance while removing the context,
0256     ///but creates in inconsistent import-structure. Therefore it is only suitable for temporary imports. These imports will not be visible from contexts that import this one.
0257     ///When this top-context does not own its private data, the import is added locally only to this context, not into the shared data.
0258     void addImportedParentContext(DUContext* context,
0259                                   const CursorInRevision& position = CursorInRevision(), bool anonymous = false,
0260                                   bool temporary = false) override;
0261     ///Use this for mass-adding of imported contexts, it is faster than adding them individually.
0262     ///@param temporary If this is true, importers of this context will not be notified of the new imports. This greatly increases performance while removing the context,
0263     ///but creates in inconsistent import-structure. Therefore it is only suitable for temporary imports. These imports will not be visible from contexts that import this one.
0264     ///When this top-context does not own its private data, the import is added locally only to this context, not into the shared data.
0265     virtual void addImportedParentContexts(const QVector<QPair<TopDUContext*, CursorInRevision>>& contexts,
0266                                            bool temporary = false);
0267 
0268     ///When this top-context does not own its private data, the import is removed locally only from this context, not from the shared data.
0269     void removeImportedParentContext(DUContext* context) override;
0270     ///Use this for mass-removing of imported contexts, it is faster than removing them individually.
0271     ///When this top-context does not own its private data, the import is removed locally only from this context, not from the shared data.
0272     virtual void removeImportedParentContexts(const QList<TopDUContext*>& contexts);
0273 
0274     ///When this top-context does not own its private data, only the local imports of this context are removed, not those from the shared data.
0275     void clearImportedParentContexts() override;
0276 
0277     using IndexedRecursiveImports = Utils::StorableSet<IndexedTopDUContext, IndexedTopDUContextIndexConversion, RecursiveImportRepository,
0278         true>;
0279 
0280     QVector<Import> importedParentContexts() const override;
0281 
0282     QVector<DUContext*> importers() const override;
0283 
0284     ///Returns all currently loade importers
0285     virtual QList<DUContext*> loadedImporters() const;
0286 
0287     CursorInRevision importPosition(const DUContext* target) const override;
0288 
0289     ///Returns the set of all recursively imported top-contexts. If import-caching is used, this returns the cached set.
0290     ///The list also contains this context itself. This set is used to determine declaration-visibility from within this top-context.
0291     const IndexedRecursiveImports& recursiveImportIndices() const;
0292 
0293     /**
0294      * Updates the cache of recursive imports. When you call this, from that moment on the set returned by recursiveImportIndices() is fixed, until
0295      * you call it again to update them. If your language has a very complex often-changing import-structure,
0296      * like for example in the case of C++, it is recommended to call this during while parsing, instead of using
0297      * the expensive builtin implicit mechanism.
0298      * Note that if you use caching, you _must_ call this before you see any visibility-effect after adding imports.
0299      *
0300      * Using import-caching has another big advantage: A top-context can be loaded without loading all its imports.
0301      *
0302      * Note: This is relatively expensive since it requires loading all imported contexts.
0303      *
0304      * When this is called, the top-context must already be registered in the duchain.
0305      */
0306     void updateImportsCache();
0307 
0308     bool usingImportsCache() const;
0309 
0310     bool findDeclarationsInternal(const SearchItem::PtrList& identifiers, const CursorInRevision& position,
0311                                   const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source,
0312                                   SearchFlags flags, uint depth) const override;
0313 
0314 protected:
0315     void setParsingEnvironmentFile(ParsingEnvironmentFile*);
0316 
0317     /**
0318      * Does the same as DUContext::updateAliases, except that it uses the symbol-store, and processes the whole identifier.
0319      * @param canBeNamespace whether the searched identifier may be a namespace.
0320      * If this is true, namespace-aliasing is applied to the last elements of the identifiers.
0321      * */
0322     template <class Acceptor>
0323     void applyAliases(const SearchItem::PtrList& identifiers, Acceptor& accept, const CursorInRevision& position,
0324                       bool canBeNamespace) const;
0325 
0326 protected:
0327     ~TopDUContext() override;
0328 
0329     void clearFeaturesSatisfied();
0330     void rebuildDynamicData(DUContext* parent, uint ownIndex) override;
0331     //Must be called after all imported top-contexts were loaded into the du-chain
0332     void rebuildDynamicImportStructure();
0333 
0334     struct AliasChainElement;
0335     struct FindDeclarationsAcceptor;
0336     struct DeclarationChecker;
0337     struct ApplyAliasesBuddyInfo;
0338 
0339     template <class Acceptor>
0340     bool applyAliases(const QualifiedIdentifier& previous, const SearchItem::Ptr& identifier, Acceptor& acceptor,
0341                       const CursorInRevision& position, bool canBeNamespace, ApplyAliasesBuddyInfo* buddy,
0342                       uint recursionDepth) const;
0343     //Same as imports, without the slow access-check, for internal usage
0344     bool importsPrivate(const DUContext* origin, const CursorInRevision& position) const;
0345     DUCHAIN_DECLARE_DATA(TopDUContext)
0346 
0347     ///Called by DUChain::removeDocumentChain to destroy this top-context.
0348     void deleteSelf();
0349 
0350     //Most of these classes need access to m_dynamicData
0351     friend class DUChain;
0352     friend class DUChainPrivate;
0353     friend class TopDUContextData;
0354     friend class TopDUContextLocalPrivate;
0355     friend class TopDUContextDynamicData;
0356     friend class Declaration;
0357     friend class DUContext;
0358     friend class Problem;
0359     friend class IndexedDeclaration;
0360     friend class IndexedDUContext;
0361     friend class LocalIndexedDeclaration;
0362     friend class LocalIndexedDUContext;
0363     friend class LocalIndexedProblem;
0364     friend class DeclarationId;
0365     friend class ParsingEnvironmentFile;
0366 
0367     TopDUContextLocalPrivate* m_local;
0368 
0369     class TopDUContextDynamicData* m_dynamicData;
0370 };
0371 
0372 /**
0373  * Returns all uses of the given declaration within this top-context and all sub-contexts
0374  * */
0375 KDEVPLATFORMLANGUAGE_EXPORT QVector<RangeInRevision> allUses(TopDUContext* context, Declaration* declaration,
0376                                                              bool noEmptyRanges = false);
0377 
0378 inline uint qHash(const ReferencedTopDUContext& ctx)
0379 {
0380     return ctx.hash();
0381 }
0382 
0383 Q_DECLARE_OPERATORS_FOR_FLAGS(TopDUContext::Features)
0384 }
0385 
0386 Q_DECLARE_TYPEINFO(KDevelop::ReferencedTopDUContext, Q_MOVABLE_TYPE);
0387 Q_DECLARE_METATYPE(KDevelop::ReferencedTopDUContext)
0388 
0389 #endif // KDEVPLATFORM_TOPDUCONTEXT_H