C++: Support concept id expressions

This commit is contained in:
Jeroen Ketema
2024-12-24 23:56:25 +01:00
parent 554ea29547
commit c48fcf1fb2
3 changed files with 111 additions and 2 deletions

View File

@@ -153,11 +153,110 @@ class NestedRequirementExpr extends Expr, @nested_requirement {
/**
* A C++ concept id expression.
*
* For example, if:
* ```cpp
* template<typename T, T X> concept C = ...;
* ...
* requires { C<int, 1>; };
* ```
* then `C<int, 1>` is a concept id expression that refers to
* the concept `C`.
*/
class ConceptIdExpr extends RequirementExpr, @concept_id {
override string toString() { result = "concept<...>" }
override string toString() {
exists(string name |
concept_templates(this.getConcept(), name, _) and
result = name + "<...>"
)
or
// The following is for backward compatibility with databases created with
// CodeQL 2.19.3, 2.19.4, and 2.20.0. Those databases include concept id
// expressions, but do not include concept template information.
not exists(this.getConcept()) and
result = "concept<...>"
}
override string getAPrimaryQlClass() { result = "ConceptIdExpr" }
/**
* Holds if the concept id is used as a type constraint.
*
* In this case, the first template argument is implicit.
*/
predicate isTypeConstraint() { is_type_constraint(underlyingElement(this)) }
/**
* Gets the concept this concept id refers to.
*/
Concept getConcept() { concept_instantiation(underlyingElement(this), unresolveElement(result)) }
/**
* Gets a template argument passed to the concept.
*/
final Locatable getATemplateArgument() { result = this.getTemplateArgument(_) }
/**
* Gets the kind of a non-type template argument passed to the concept.
*/
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
/**
* Gets the `i`th template argument passed to the concept.
*
* For example, if:
* ```cpp
* template<typename T, T X> concept C = ...;
* ...
* requires { C<int, 1>; };
* ```
* then `getTemplateArgument(0)` yields `int`, and `getTemplateArgument(1)`
* yields `1`.
*
* If the concept id is a type constraint, then `getTemplateArgument(0)`
* will not yield a result.
*/
final Locatable getTemplateArgument(int index) {
if exists(this.getTemplateArgumentValue(index))
then result = this.getTemplateArgumentValue(index)
else result = this.getTemplateArgumentType(index)
}
/**
* Gets the kind of the `i`th template argument value passed to the concept.
*
* For example, if:
* ```cpp
* template<typename T, T X> concept C = ...;
* ...
* requires { C<int, 1>; };
* ```
* then `getTemplateArgumentKind(1)` yields `int`, and there is no result for
* `getTemplateArgumentKind(0)`.
*/
final Locatable getTemplateArgumentKind(int index) {
exists(this.getTemplateArgumentValue(index)) and
result = this.getTemplateArgumentType(index)
}
/**
* Gets the number of template arguments passed to the concept.
*/
final int getNumberOfTemplateArguments() {
result = count(int i | exists(this.getTemplateArgument(i)))
}
private Type getTemplateArgumentType(int index) {
exists(int i | if this.isTypeConstraint() then i = index - 1 else i = index |
concept_template_argument(underlyingElement(this), i, unresolveElement(result))
)
}
private Expr getTemplateArgumentValue(int index) {
exists(int i | if this.isTypeConstraint() then i = index - 1 else i = index |
concept_template_argument_value(underlyingElement(this), i, unresolveElement(result))
)
}
}
/**
@@ -187,4 +286,9 @@ class Concept extends Declaration, @concept_template {
* the constraint expression is `std::is_same<T, int>::value`.
*/
Expr getExpr() { result.getParent() = this }
/**
* Gets a concept id expression that refers to this concept
*/
ConceptIdExpr getAReferringConceptIdExpr() { this = result.getConcept() }
}

View File

@@ -235,7 +235,7 @@ class Declaration extends Locatable, @declaration {
*
* `Foo<int, 1> bar;`
*
* Will have `getTemplateArgument())` return `int`, and
* Will have `getTemplateArgument(0)` return `int`, and
* `getTemplateArgument(1)` return `1`.
*/
final Locatable getTemplateArgument(int index) {

View File

@@ -883,6 +883,11 @@ concept_templates(
string name: string ref,
int location: @location_default ref
);
concept_instantiation(
unique int to: @concept_id ref,
int from: @concept_template ref
);
is_type_constraint(int concept_id: @concept_id ref);
concept_template_argument(
int concept_id: @concept ref,
int index: int ref,