From ecf3c53eba465cce554eccc90549207f14e20726 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 20 Dec 2024 13:12:10 +0100 Subject: [PATCH] C++: Introduce `SizeofPackOperator` subclasses for expressions and types Note that template template parameters are considered types in this context. --- .../change-notes/2024-12-20-sizeof-pack.md | 4 ++ cpp/ql/lib/semmle/code/cpp/PrintAST.qll | 2 + cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll | 52 +++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 cpp/ql/lib/change-notes/2024-12-20-sizeof-pack.md diff --git a/cpp/ql/lib/change-notes/2024-12-20-sizeof-pack.md b/cpp/ql/lib/change-notes/2024-12-20-sizeof-pack.md new file mode 100644 index 00000000000..cf613501479 --- /dev/null +++ b/cpp/ql/lib/change-notes/2024-12-20-sizeof-pack.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* A new classes `SizeofPackExprOperator` and `SizeofPackTypeOperator` were introduced, which represent the C++ `sizeof...` operator taking an expression and a type argument, respectively. diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll index 7a6307898ef..492788202b4 100644 --- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll @@ -1056,6 +1056,8 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) or expr.(SizeofExprOperator).getExprOperand() = ele and pred = "getExprOperand()" or + expr.(SizeofPackExprOperator).getExprOperand() = ele and pred = "getExprOperand()" + or expr.(StmtExpr).getStmt() = ele and pred = "getStmt()" or expr.(ThrowExpr).getExpr() = ele and pred = "getExpr()" diff --git a/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll index 85293cc7313..83364e422eb 100644 --- a/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/lib/semmle/code/cpp/exprs/Cast.qll @@ -684,7 +684,8 @@ class TypeidOperator extends Expr, @type_id { } /** - * A C++11 `sizeof...` expression which determines the size of a template parameter pack. + * A C++11 `sizeof...` expression which determines the size of a template + * parameter pack. * * This expression only appears in templates themselves - in any actual * instantiations, "sizeof...(x)" will be replaced by its integer value. @@ -694,15 +695,56 @@ class TypeidOperator extends Expr, @type_id { * ``` */ class SizeofPackOperator extends Expr, @sizeof_pack { - override string toString() { result = "sizeof...(...)" } - - override string getAPrimaryQlClass() { result = "SizeofPackOperator" } - override predicate mayBeImpure() { none() } override predicate mayBeGloballyImpure() { none() } } +/** + * A C++11 `sizeof...` expression which determines the size of a template + * parameter pack and whose operand is an expression. + * + * This expression only appears in templates themselves - in any actual + * instantiations, "sizeof...(x)" will be replaced by its integer value. + * ``` + * template < typename... T > + * int count ( T &&... t ) { return sizeof... ( t ); } + * ``` + */ +class SizeofPackExprOperator extends SizeofPackOperator { + SizeofPackExprOperator() { exists(this.getChild(0)) } + + override string getAPrimaryQlClass() { result = "SizeofPackExprOperator" } + + /** Gets the contained expression. */ + Expr getExprOperand() { result = this.getChild(0) } + + override string toString() { result = "sizeof...()" } +} + +/** + * A C++11 `sizeof...` expression which determines the size of a template + * parameter pack and whose operand is an type name or a template template + * parameter. + * + * This expression only appears in templates themselves - in any actual + * instantiations, "sizeof...(x)" will be replaced by its integer value. + * ``` + * template < typename... T > + * int count ( T &&... t ) { return sizeof... ( T ); } + * ``` + */ +class SizeofPackTypeOperator extends SizeofPackOperator { + SizeofPackTypeOperator() { sizeof_bind(underlyingElement(this), _) } + + override string getAPrimaryQlClass() { result = "SizeofPackTypeOperator" } + + /** Gets the contained type. */ + Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } + + override string toString() { result = "sizeof...(" + this.getTypeOperand().getName() + ")" } +} + /** * A C/C++ sizeof expression. */