Files
codeql/go/ql/lib/semmle/go/AST.qll
2026-03-13 15:03:02 +00:00

271 lines
8.1 KiB
Plaintext

/**
* Provides classes for working with AST nodes.
*/
overlay[local]
module;
import go
/**
* An AST node.
*/
class AstNode extends @node, Locatable {
/**
* Gets the `i`th child node of this node.
*
* Note that the precise indices of child nodes are considered an implementation detail
* and are subject to change without notice.
*/
AstNode getChild(int i) {
result = this.(ExprParent).getChildExpr(i) or
result = this.(GoModExprParent).getChildGoModExpr(i) or
result = this.(StmtParent).getChildStmt(i) or
result = this.(DeclParent).getDecl(i) or
result = this.(GenDecl).getSpec(i) or
result = this.(FieldParent).getField(i) or
result = this.(File).getCommentGroup(i) or
result = this.(CommentGroup).getComment(i)
}
/**
* Gets a child node of this node.
*/
AstNode getAChild() { result = this.getChild(_) }
/**
* Gets the number of child nodes of this node.
*/
int getNumChild() { result = count(this.getAChild()) }
/**
* Gets a child with the given index and of the given kind, if one exists.
* Note that a given parent can have multiple children with the same index but differing kind.
*/
private AstNode getChildOfKind(string kind, int i) {
kind = "expr" and result = this.(ExprParent).getChildExpr(i)
or
kind = "gomodexpr" and result = this.(GoModExprParent).getChildGoModExpr(i)
or
kind = "stmt" and result = this.(StmtParent).getChildStmt(i)
or
kind = "decl" and result = this.(DeclParent).getDecl(i)
or
kind = "spec" and result = this.(GenDecl).getSpec(i)
or
kind = "field" and result = this.(FieldParent).getField(i)
or
kind = "commentgroup" and result = this.(File).getCommentGroup(i)
or
kind = "comment" and result = this.(CommentGroup).getComment(i)
or
kind = "typeparamdecl" and result = this.(TypeParamDeclParent).getTypeParameterDecl(i)
}
/**
* Get an AstNode child, ordered by child kind and then by index.
*/
AstNode getUniquelyNumberedChild(int index) {
result =
rank[index + 1](AstNode child, string kind, int i |
child = this.getChildOfKind(kind, i)
|
child order by kind, i
)
}
/** Gets the parent node of this AST node, if any. */
AstNode getParent() { this = result.getAChild() }
/** Gets the parent node of this AST node, but without crossing function boundaries. */
private AstNode parentInSameFunction() {
result = this.getParent() and
not this instanceof FuncDef
}
/** Gets the innermost function definition to which this AST node belongs, if any. */
pragma[nomagic]
FuncDef getEnclosingFunction() { result = this.getParent().parentInSameFunction*() }
/** Gets the innermost block statement to which this AST node belongs, if any. */
BlockStmt getEnclosingBlock() {
exists(AstNode p | p = this.getParent() |
result = p
or
not p instanceof BlockStmt and
result = p.getEnclosingBlock()
)
}
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
*/
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
/**
* Gets the name of a primary CodeQL class to which this node belongs.
*
* For most nodes, this is simply the most precise syntactic category to which they belong;
* for example, `AddExpr` is a primary class, but `BinaryExpr` is not.
*
* For identifiers and selector expressions, the class describing what kind of entity they refer
* to (for example `FunctionName` or `TypeName`) is also considered primary. For such nodes,
* this predicate has multiple values.
*/
string getAPrimaryQlClass() { result = "???" }
override string toString() { result = "AST node" }
}
/**
* An AST node whose children include expressions.
*/
class ExprParent extends @exprparent, AstNode {
/**
* Gets the `i`th child expression of this node.
*
* Note that the precise indices of child expressions are considered an implementation detail
* and are subject to change without notice.
*/
Expr getChildExpr(int i) { exprs(result, _, this, i) }
/**
* Gets an expression that is a child node of this node in the AST.
*/
Expr getAChildExpr() { result = this.getChildExpr(_) }
/**
* Gets the number of child expressions of this node.
*/
int getNumChildExpr() { result = count(this.getAChildExpr()) }
}
/**
* An AST node whose children include go.mod expressions.
*/
class GoModExprParent extends @modexprparent, AstNode {
/**
* Gets the `i`th child expression of this node.
*
* Note that the precise indices of child expressions are considered an implementation detail
* and are subject to change without notice.
*/
GoModExpr getChildGoModExpr(int i) { modexprs(result, _, this, i) }
/**
* Gets an expression that is a child node of this node in the AST.
*/
GoModExpr getAChildGoModExpr() { result = this.getChildGoModExpr(_) }
/**
* Gets the number of child expressions of this node.
*/
int getNumChildGoModExpr() { result = count(this.getAChildGoModExpr()) }
}
/**
* An AST node whose children include statements.
*/
class StmtParent extends @stmtparent, AstNode {
/**
* Gets the `i`th child statement of this node.
*
* Note that the precise indices of child statements are considered an implementation detail
* and are subject to change without notice.
*/
Stmt getChildStmt(int i) { stmts(result, _, this, i) }
/**
* Gets a statement that is a child node of this node in the AST.
*/
Stmt getAChildStmt() { result = this.getChildStmt(_) }
/**
* Gets the number of child statements of this node.
*/
int getNumChildStmt() { result = count(this.getAChildStmt()) }
}
/**
* An AST node whose children include declarations.
*/
class DeclParent extends @declparent, AstNode {
/**
* Gets the `i`th child declaration of this node.
*
* Note that the precise indices of declarations are considered an implementation detail
* and are subject to change without notice.
*/
Decl getDecl(int i) { decls(result, _, this, i) }
/**
* Gets a child declaration of this node in the AST.
*/
Decl getADecl() { result = this.getDecl(_) }
/**
* Gets the number of child declarations of this node.
*/
int getNumDecl() { result = count(this.getADecl()) }
}
/**
* An AST node whose children include field declarations.
*
* A field declaration can be in a struct, a function (for parameter or result
* variables), or an interface (in which case it is a method or embedding spec).
*/
class FieldParent extends @fieldparent, AstNode {
/**
* Gets the `i`th field declaration of this node.
*
* Note that the precise indices of field declarations are considered an
* implementation detail and are subject to change without notice.
*/
FieldBase getField(int i) { fields(result, this, i) }
/**
* Gets a child field declaration of this node in the AST.
*/
FieldBase getAField() { result = this.getField(_) }
/**
* Gets the number of child field declarations of this node.
*/
int getNumFields() { result = count(this.getAField()) }
}
/**
* An AST node whose children include type parameter declarations.
*/
class TypeParamDeclParent extends @typeparamdeclparent, AstNode {
/**
* Gets the `i`th type parameter declaration of this node.
*
* Note that the precise indices of type parameters are considered an implementation detail
* and are subject to change without notice.
*/
TypeParamDecl getTypeParameterDecl(int i) { typeparamdecls(result, this, i) }
/**
* Gets a child field of this node in the AST.
*/
TypeParamDecl getATypeParameterDecl() { result = this.getTypeParameterDecl(_) }
}
/**
* An AST node which may induce a scope.
*
* The following nodes may induce scopes:
*
* - files
* - block statements, `if` statements, `switch` statements, `case` clauses, comm clauses, loops
* - function type expressions
*
* Note that functions themselves do not induce a scope, it is their type declaration that induces
* the scope.
*/
class ScopeNode extends @scopenode, AstNode {
/** Gets the scope induced by this node, if any. */
LocalScope getScope() { scopenodes(this, result) }
}