From 3b6878da3ded77aa86ee1032c84900633cfad236 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 26 Dec 2024 11:12:17 +0100 Subject: [PATCH] C++: Add support for requires clauses and constraints on template parameters --- cpp/ql/lib/semmle/code/cpp/Function.qll | 21 +++++++++++++++ .../lib/semmle/code/cpp/TemplateParameter.qll | 7 +++++ cpp/ql/lib/semmle/code/cpp/UserType.qll | 5 ++++ cpp/ql/lib/semmle/code/cpp/Variable.qll | 5 ++++ cpp/ql/lib/semmlecode.cpp.dbscheme | 27 +++++++++++++++++++ 5 files changed, 65 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/Function.qll b/cpp/ql/lib/semmle/code/cpp/Function.qll index d2caa56c9f8c8..cb3b00b64ade9 100644 --- a/cpp/ql/lib/semmle/code/cpp/Function.qll +++ b/cpp/ql/lib/semmle/code/cpp/Function.qll @@ -715,6 +715,27 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * specification. */ predicate isNoExcept() { fun_decl_empty_noexcept(underlyingElement(this)) } + + /** + * Gets a requires clause if this declaration is a template with such a clause. + */ + Expr getARequiresClause() { fun_requires(underlyingElement(this), _, unresolveElement(result)) } + + /** + * Gets the requires clause that appears after the template argument list if this + * declaration is a template with such a clause. + */ + Expr getTemplateRequiresClause() { + fun_requires(underlyingElement(this), 1, unresolveElement(result)) + } + + /** + * Gets the requires clause that appears after the declarator if this declaration + * is a template with such a clause. + */ + Expr getFunctionRequiresClause() { + fun_requires(underlyingElement(this), 2, unresolveElement(result)) + } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll b/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll index c127af22a9d63..d6c4b1a8121a1 100644 --- a/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll +++ b/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll @@ -59,6 +59,13 @@ class TypeTemplateParameter extends UserType, TemplateParameterImpl { override string getAPrimaryQlClass() { result = "TypeTemplateParameter" } override predicate involvesTemplateParameter() { any() } + + /** + * Get the type constraint of this type template parameter. + */ + Expr getTypeConstraint() { + type_template_type_constraint(underlyingElement(this), unresolveElement(result)) + } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/UserType.qll b/cpp/ql/lib/semmle/code/cpp/UserType.qll index 9d85f555ec1af..439ed84e05e84 100644 --- a/cpp/ql/lib/semmle/code/cpp/UserType.qll +++ b/cpp/ql/lib/semmle/code/cpp/UserType.qll @@ -129,4 +129,9 @@ class TypeDeclarationEntry extends DeclarationEntry, @type_decl { * class or typedef. */ predicate isTopLevel() { type_decl_top(underlyingElement(this)) } + + /** + * Gets the requires clause if this declaration is a template with such a clause. + */ + Expr getRequiresClause() { type_requires(underlyingElement(this), unresolveElement(result)) } } diff --git a/cpp/ql/lib/semmle/code/cpp/Variable.qll b/cpp/ql/lib/semmle/code/cpp/Variable.qll index 3bf408820fcba..8e68cc1927f72 100644 --- a/cpp/ql/lib/semmle/code/cpp/Variable.qll +++ b/cpp/ql/lib/semmle/code/cpp/Variable.qll @@ -278,6 +278,11 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl { /** Holds if this declaration is a template specialization. */ predicate isSpecialization() { var_specialized(underlyingElement(this)) } + + /** + * Gets the requires clause if this declaration is a template with such a clause. + */ + Expr getRequiresClause() { var_requires(underlyingElement(this), unresolveElement(result)) } } /** diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme index 9a9d9e573a326..8b8d0274ce0ab 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme @@ -480,6 +480,20 @@ fun_decl_typedef_type( int typedeftype_id: @usertype ref ); +/* +case @fun_requires.kind of + 1 = @template_attached +| 2 = @function_attached +; +*/ + +#keyset[id, kind] +fun_requires( + int id: @fun_decl ref, + int kind: int ref, + int constraint: @expr ref +); + param_decl_bind( unique int id: @var_decl ref, int index: int ref, @@ -501,6 +515,10 @@ var_decl_specifiers( string name: string ref ) is_structured_binding(unique int id: @variable ref); +var_requires( + unique int id: @var_decl ref, + int constraint: @expr ref +); type_decls( unique int id: @type_decl, @@ -511,6 +529,10 @@ type_def(unique int id: @type_decl ref); type_decl_top( unique int type_decl: @type_decl ref ); +type_requires( + unique int id: @type_decl ref, + int constraint: @expr ref +); namespace_decls( unique int id: @namespace_decl, @@ -790,6 +812,11 @@ nontype_template_parameters( int id: @expr ref ); +type_template_type_constraint( + unique int id: @usertype ref, + int constraint: @expr ref +); + mangled_name( unique int id: @declaration ref, int mangled_name : @mangledname,