Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Python: Extend ExceptionTypes API
Adds support for finding instances, and adds things like a
`BaseException` convenience class.
  • Loading branch information
tausbn committed Apr 8, 2026
commit 6efedb7d000f515af1eabdb8ec0febd3751465b6
Original file line number Diff line number Diff line change
Expand Up @@ -2199,12 +2199,27 @@ module ExceptionTypes {
/** Gets a string representation of this exception type. */
string toString() { result = this.getName() }

/** Holds if this exception type may be raised at control flow node `r`. */
predicate isRaisedAt(ControlFlowNode r) {
exists(Expr raised |
raised = r.getNode().(Raise).getRaised() and
/** Gets a data-flow node that refers to an instance of this exception type. */
DataFlow::Node getAnInstance() { none() }

/** Holds if this is a legal exception type (a subclass of `BaseException`). */
predicate isLegalExceptionType() { this.getADirectSuperclass*() instanceof BaseException }

/**
* Holds if this exception type is raised by `r`, either as a class reference
* (e.g. `raise ValueError`) or as an instantiation (e.g. `raise ValueError("msg")`).
*/
predicate isRaisedBy(Raise r) {
exists(Expr raised | raised = r.getRaised() |
this.getAUse().asExpr() in [raised, raised.(Call).getFunc()]
or
this.getAnInstance().asExpr() = raised
)
}

/** Holds if this exception type may be raised at control flow node `r`. */
predicate isRaisedAt(ControlFlowNode r) {
this.isRaisedBy(r.getNode())
or
exists(Function callee |
resolveCall(r, callee, _) and
Expand All @@ -2231,7 +2246,7 @@ module ExceptionTypes {
or
// A bare `except:` handles everything
not exists(handler.getNode().(ExceptStmt).getType()) and
this.(BuiltinExceptType).getName() = "BaseException"
this instanceof BaseException
}

/**
Expand Down Expand Up @@ -2261,6 +2276,8 @@ module ExceptionTypes {

override DataFlow::Node getAUse() { result = classTracker(cls) }

override DataFlow::Node getAnInstance() { result = classInstanceTracker(cls) }

override ExceptType getADirectSuperclass() {
result.(UserExceptType).asClass() = getADirectSuperclass(cls)
or
Expand All @@ -2285,7 +2302,11 @@ module ExceptionTypes {

override string getName() { result = name }

override DataFlow::Node getAUse() { API::builtin(name).asSource().flowsTo(result) }
override DataFlow::Node getAUse() { result = API::builtin(name).getAValueReachableFromSource() }

override DataFlow::Node getAnInstance() {
result = API::builtin(name).getAnInstance().getAValueReachableFromSource()
}

override ExceptType getADirectSuperclass() {
builtinExceptionSubclass(result.(BuiltinExceptType).asBuiltinName(), name) and
Expand All @@ -2303,6 +2324,16 @@ module ExceptionTypes {
}
}

/** The builtin `BaseException` type. */
class BaseException extends BuiltinExceptType {
BaseException() { name = "BaseException" }
}

/** The builtin `NameError` exception type. */
class NameError extends BuiltinExceptType {
NameError() { name = "NameError" }
}

/**
* Holds if the exception edge from `r` to `handler` is unlikely because
* none of the exception types that `r` may raise are handled by `handler`.
Expand Down