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: 2011-2014 Sven Brauch <svenbrauch@googlemail.com> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #ifndef PYTHON_DECLARATIONBUILDER_H 0010 #define PYTHON_DECLARATIONBUILDER_H 0011 0012 #include <language/duchain/builders/abstracttypebuilder.h> 0013 #include <language/duchain/builders/abstractdeclarationbuilder.h> 0014 0015 #include <QList> 0016 0017 #include "contextbuilder.h" 0018 #include "declarations/functiondeclaration.h" 0019 #include "ast.h" 0020 0021 namespace Python 0022 { 0023 0024 class CorrectionHelper; 0025 0026 typedef KDevelop::AbstractTypeBuilder<Ast, Identifier, ContextBuilder> TypeBuilderBase; 0027 0028 typedef KDevelop::AbstractDeclarationBuilder<Ast, Identifier, TypeBuilderBase> DeclarationBuilderBase; 0029 0030 class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase 0031 { 0032 public: 0033 DeclarationBuilder(PythonEditorIntegrator* editor, int ownPriority); 0034 ~DeclarationBuilder() override; 0035 0036 /** 0037 * @brief Entry function, called by KDevPlatform. 0038 */ 0039 ReferencedTopDUContext build(const IndexedString& url, Ast* node, 0040 const ReferencedTopDUContext& updateContext = ReferencedTopDUContext()) override; 0041 0042 /** 0043 * @brief Set whether the current running pass is the first or the second one. 0044 * @param prebuilding true if first pass, false if second 0045 */ 0046 void setPrebuilding(bool prebuilding); 0047 0048 /** 0049 * @brief Priority of this parse job. 0050 */ 0051 int jobPriority() const; 0052 0053 /** 0054 * @brief Get the docstring which belongs to the given body 0055 * @param body Body of statements which is in the documented function or class 0056 */ 0057 QString getDocstring(QList<Ast*> body) const; 0058 0059 /** 0060 * @brief Construct the dotted name of a module from an import ... from ... as statement. 0061 * 0062 * @param node the import ... from node 0063 * @param alias the ... as ... node 0064 * @param intermediate an additional string to prepend to the module name (dot is added internally) 0065 */ 0066 QString buildModuleNameFromNode(ImportFromAst* node, AliasAst* alias, const QString& intermediate) const; 0067 0068 /** 0069 * @brief Get a list of all module names which were not found while parsing. 0070 */ 0071 QVector<IndexedString> missingModules() const { 0072 return m_missingModules; 0073 } 0074 0075 protected: 0076 /// AST visitor functions 0077 void visitClassDefinition(ClassDefinitionAst* node) override; 0078 void visitFunctionDefinition(FunctionDefinitionAst* node) override; 0079 void visitAssignment(AssignmentAst* node) override; 0080 void visitAnnotationAssignment(AnnotationAssignmentAst* node) override; 0081 void visitAssignmentExpression(AssignmentExpressionAst* node) override; 0082 void visitFor(ForAst* node) override; 0083 void visitImport(ImportAst* node) override; 0084 void visitImportFrom(ImportFromAst* node) override; 0085 void visitArguments(ArgumentsAst* node) override; 0086 void visitExceptionHandler(ExceptionHandlerAst* node) override; 0087 void visitReturn(ReturnAst* node) override; 0088 void visitCode(CodeAst* node) override; 0089 void visitCall(CallAst* node) override; 0090 void visitYield(YieldAst* node) override; 0091 void visitWithItem(WithItemAst* node) override; 0092 void visitLambda(LambdaAst* node) override; 0093 void visitComprehension(ComprehensionAst* node) override; 0094 void visitGlobal(GlobalAst* node) override; 0095 void visitAssertion(AssertionAst* node) override; 0096 void visitIf(IfAst* node) override; 0097 void visitString(StringAst* node) override; 0098 void visitMatch(MatchAst* node) override; 0099 void visitNode(Ast* node) override; 0100 0101 protected: 0102 enum VisitVariableFlags { 0103 NoVisitVariableFlags = 0x0, 0104 AbortIfReopenMismatch = 0x1 0105 }; 0106 /// Visitor helper functions 0107 template<typename T> T* visitVariableDeclaration(Python::Ast* node, Declaration* previous=nullptr, 0108 AbstractType::Ptr type = AbstractType::Ptr(), 0109 VisitVariableFlags flags=NoVisitVariableFlags); 0110 template<typename T> T* visitVariableDeclaration(Identifier* node, Declaration* previous=nullptr, 0111 AbstractType::Ptr type = AbstractType::Ptr(), 0112 VisitVariableFlags flags=NoVisitVariableFlags); 0113 0114 protected: 0115 /** 0116 * @brief Applies docstring hints, such as "addsType" 0117 * @param node the called function 0118 * @param function the declaration which belongs to @p node 0119 * 0120 * Used for example in a = []; a.append(3) to set the type of a to "list of int". 0121 */ 0122 void applyDocstringHints(CallAst* node, Python::FunctionDeclaration::Ptr function); 0123 0124 /** 0125 * @brief Try to deduce types of function arguments from a call and stores it in the duchain 0126 * @param node the called function or class (i.e. constructor) 0127 * @param called the declaration which belongs to @p node 0128 * 0129 * Used for example in def f(x): pass; a = f(3) to set the type of x to "int" 0130 */ 0131 void addArgumentTypeHints(CallAst* node, DeclarationPointer called); 0132 0133 /** 0134 * @brief Adjust the type of foo in an expression like assert isinstance(fooinstance, Foo) 0135 * Does nothing if the given expression isn't of any of the forms 0136 * a) isinstance(fooinstance, Foo) 0137 * b) type(fooinstance) == Foo */ 0138 void adjustForTypecheck(ExpressionAst* check, bool useUnsure); 0139 /// Helper for the above 0140 void adjustExpressionsForTypecheck(ExpressionAst* adjust, ExpressionAst* from, bool useUnsure); 0141 0142 /// Represents a single source type in a tuple assignment. 0143 struct SourceType { 0144 AbstractType::Ptr type; 0145 DeclarationPointer declaration; 0146 bool isAlias; 0147 }; 0148 0149 /** @brief If sourceType is a container that can be unpacked into outTypes, do so. */ 0150 void tryUnpackType(AbstractType::Ptr sourceType, QVector<AbstractType::Ptr>& outTypes, int starred); 0151 0152 /** 0153 * @brief Handle a variable assignment to @p name and give it the type @p element. 0154 */ 0155 void assignToName(NameAst* name, const SourceType& element); 0156 0157 /** 0158 * @brief Handle assignment to subscript @p subscript with rhs type @p element. 0159 */ 0160 void assignToSubscript(SubscriptAst* subscript, const SourceType& element); 0161 0162 /** 0163 * @brief Handle assignment to an attribute @p attribute with rhs type @p element. 0164 */ 0165 void assignToAttribute(AttributeAst* attribute, const SourceType& element); 0166 0167 /** 0168 * @brief Handle assignment to a target @p target with rhs type @p element. 0169 */ 0170 void assignToTuple(TupleAst* tuple, const SourceType& element); 0171 0172 /** 0173 * @brief Handle assignment to a target @p target with rhs type @p element. 0174 */ 0175 void assignToUnknown(ExpressionAst* target, const AbstractType::Ptr type); 0176 void assignToUnknown(ExpressionAst* target, const SourceType& element); 0177 0178 /** 0179 * @brief Find all existing declarations for the identifier @p node 0180 */ 0181 QList<Declaration*> existingDeclarationsForNode(Identifier* node); 0182 0183 enum FitDeclarationType { 0184 NoTypeRequired, 0185 InstanceDeclarationType, 0186 AliasDeclarationType, 0187 FunctionDeclarationType 0188 }; 0189 FitDeclarationType kindForType(AbstractType::Ptr type, bool isAlias = false); 0190 0191 /** 0192 * @brief schedule an object to be deleted when the declaration builder is destroyed 0193 * this is used to bypass the automated duchain cleanup for imports */ 0194 void scheduleForDeletion(DUChainBase* d, bool doschedule = true); 0195 0196 /** 0197 * @brief python-specific version of openDeclaration which scans for existing declarations in previous versions of 0198 * this top-context in a more intelligent way. 0199 * Use this in normal declaratonbuilder code if you can't use visitVariableDeclaration. */ 0200 template<typename T> T* eventuallyReopenDeclaration(Python::Identifier* name, FitDeclarationType mustFitType); 0201 0202 template<typename T> QList<Declaration*> reopenFittingDeclaration(QList<Declaration*> declarations, 0203 FitDeclarationType mustFitType, 0204 RangeInRevision updateRangeTo, Declaration** ok); 0205 0206 /** 0207 * @brief Create a declaration for an import statement. 0208 * 0209 * @param dottedName The dotted name of the module, like "random.randint". 0210 * @param declarationIdentifier provides the name and range 0211 * @param rangeNode can be used to override the declarationIdentifier's range, if required. Defaults to 0. 0212 * @param problemEncountered the encountered problem, if there's any 0213 * @return :Declaration* the declaration created, or 0 if none was found. 0214 **/ 0215 Declaration* createModuleImportDeclaration(QString dottedName, QString declarationName, Python::Identifier* declarationIdentifier, 0216 ProblemPointer& problemEncountered, Python::Ast* rangeNode = nullptr); 0217 /** 0218 * @brief Create a tree of declarations for the specified list. 0219 * Give the list ["foo","bar","baz"], and you'll get a declaration "foo" containing "bar" in its internal context, 0220 * "bar" containing "baz" etc. 0221 * This is used in import handling. 0222 * This function automatically updates existing declaration trees to the maximum level possible! Thus, 0223 * if you call this with ["foo", "bar"], then ["foo", "baz"], "baz" will be added to "foo". 0224 * 0225 * @warning The DUChain must not be locked when this is called. 0226 * 0227 * @param nameComponents the list of names to create declarations for 0228 * @param declarationIdentifier provides the name and range 0229 * @param innerCtx the internalContext() to set on the last created declaration. Either this or aliasDeclaration must be provided! 0230 * @param aliasDeclaration the declaration to alias with the last created declaration 0231 * @param range can be used to override the declarationIdentifier's range, if required. Defaults to an invalid range. 0232 * @return :Declaration* the top level declaration created 0233 **/ 0234 Declaration* createDeclarationTree(const QStringList& nameComponents, Identifier* declarationIdentifier, 0235 const ReferencedTopDUContext& innerCtx, Declaration* aliasDeclaration = nullptr, 0236 const RangeInRevision& range = RangeInRevision::invalid()); 0237 0238 /** 0239 * @brief Find a declaration specified by "foo.bar.baz" in the given top context. 0240 * 0241 * @param dottedNameIdentifier string list of module names, starting with the most general one. 0242 * @param ctx top context to search 0243 * @return :Declaration* declaration if found, 0 otherwise. 0244 * 0245 * This will traverse nested classes and properties until the list of passed names is exhausted. 0246 * @warning The DUChain must not be locked. 0247 **/ 0248 Declaration* findDeclarationInContext(QStringList dottedNameIdentifier, TopDUContext* ctx) const; 0249 0250 private: 0251 template<class T> T* openDeclaration(Identifier* name, DeclarationFlags flags = NoFlags) 0252 { 0253 T* decl = DeclarationBuilderBase::openDeclaration<T>(KDevelop::Identifier(name->value), 0254 editorFindRange(name, name), flags); 0255 decl->setAlwaysForceDirect(true); 0256 return decl; 0257 }; 0258 void closeDeclaration() override; 0259 0260 private: 0261 /// HACK: List of items to delete after parsing finishes, to work around the built-in cleanup logic 0262 QList<DUChainBase*> m_scheduledForDeletion; 0263 QScopedPointer<CorrectionHelper> m_correctionHelper; 0264 int m_ownPriority = 0; 0265 QVector<StructureType::Ptr> m_currentClassTypes; 0266 // missing modules, for not reporting them as unknown variables 0267 QVector<IndexedString> m_missingModules; 0268 0269 StringAst* m_lastComment = nullptr; 0270 }; 0271 0272 } 0273 0274 #endif 0275 // kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on