/** * Provides classes representing Python classes. */ import python /** * An (artificial) expression corresponding to a class definition. * It is recommended to use `ClassDef` instead. */ class ClassExpr extends ClassExpr_ { /** Gets the metaclass expression */ Expr getMetaClass() { if major_version() = 3 then exists(Keyword metacls | this.getAKeyword() = metacls and metacls.getArg() = "metaclass" and result = metacls.getValue() ) else exists(Assign a | a = this.getInnerScope().getAStmt() and a.getATarget().(Name).getId() = "__metaclass__" and result = a.getValue() ) } /** Gets the nth keyword argument of this class definition. */ override DictUnpackingOrKeyword getKeyword(int index) { result = this.getKeywords().getItem(index) } /** Gets a keyword argument of this class definition. */ override DictUnpackingOrKeyword getAKeyword() { result = this.getKeywords().getAnItem() } override Expr getASubExpression() { result = this.getABase() or result = this.getAKeyword().getValue() or result = this.getKwargs() or result = this.getStarargs() } /** Gets a call corresponding to a decorator of this class definition. */ Call getADecoratorCall() { result.getArg(0) = this or result.getArg(0) = this.getADecoratorCall() } /** Gets a decorator of this function expression */ Expr getADecorator() { result = this.getADecoratorCall().getFunc() } override AstNode getAChildNode() { result = this.getASubExpression() or result = this.getInnerScope() } /** Gets a tuple (*) argument of this class definition. */ Expr getStarargs() { result = this.getABase().(Starred).getValue() } /** Gets a dictionary (**) argument of this class definition. */ Expr getKwargs() { result = this.getAKeyword().(DictUnpacking).getValue() } } /** A class statement. Note that ClassDef extends Assign as a class definition binds the newly created class */ class ClassDef extends Assign { /* syntax: class name(...): ... */ ClassDef() { /* This is an artificial assignment the rhs of which is a (possibly decorated) ClassExpr */ exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall()) } override string toString() { result = "ClassDef" } /** Gets the class for this statement */ Class getDefinedClass() { exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall() | result = c.getInnerScope() ) } override Stmt getLastStatement() { result = this.getDefinedClass().getLastStatement() } } /** The scope of a class. This is the scope of all the statements within the class definition */ class Class extends Class_, Scope, AstNode { /** Gets a defined init method of this class */ Function getInitMethod() { result.getScope() = this and result.isInitMethod() } /** Gets a method defined in this class */ Function getAMethod() { result.getScope() = this } override Location getLocation() { py_scope_location(result, this) } /** Gets the scope (module, class or function) in which this class is defined */ override Scope getEnclosingScope() { result = this.getParent().getScope() } /** Use getEnclosingScope() instead */ override Scope getScope() { result = this.getParent().getScope() } override string toString() { result = "Class " + this.getName() } /** Gets the statements forming the body of this class */ override StmtList getBody() { result = Class_.super.getBody() } /** Gets the nth statement in the class */ override Stmt getStmt(int index) { result = Class_.super.getStmt(index) } /** Gets a statement in the class */ override Stmt getAStmt() { result = Class_.super.getAStmt() } /** Gets the name used to define this class */ override string getName() { result = Class_.super.getName() } /** Holds if this expression may have a side effect (as determined purely from its syntax). */ predicate hasSideEffects() { any() } /** Holds if this is probably a mixin (has 'mixin' or similar in name or docstring) */ predicate isProbableMixin() { ( this.getName().toLowerCase().matches("%mixin%") or this.getDocString().getText().toLowerCase().matches("%mixin%") or this.getDocString().getText().toLowerCase().matches("%mix-in%") ) } override AstNode getAChildNode() { result = this.getAStmt() } /** Gets a decorator of this class. */ Expr getADecorator() { result = this.getParent().getADecorator() } /** Gets the metaclass expression */ Expr getMetaClass() { result = this.getParent().getMetaClass() } /** Gets the ClassObject corresponding to this class */ ClassObject getClassObject() { result.getOrigin() = this.getParent() } /** Gets the nth base of this class definition. */ Expr getBase(int index) { result = this.getParent().getBase(index) } /** Gets a base of this class definition. */ Expr getABase() { result = this.getParent().getABase() } /** Gets the metrics for this class */ ClassMetrics getMetrics() { result = this } /** * Gets the qualified name for this class. * Should return the same name as the `__qualname__` attribute on classes in Python 3. */ string getQualifiedName() { this.getScope() instanceof Module and result = this.getName() or exists(string enclosing_name | enclosing_name = this.getScope().(Function).getQualifiedName() or enclosing_name = this.getScope().(Class).getQualifiedName() | result = enclosing_name + "." + this.getName() ) } override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) } override predicate contains(AstNode inner) { Scope.super.contains(inner) } }