mirror of
https://github.com/github/codeql.git
synced 2025-12-25 05:06:34 +01:00
170 lines
5.7 KiB
Plaintext
170 lines
5.7 KiB
Plaintext
/**
|
|
* 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) }
|
|
}
|