Skip to content

Commit 94d915f

Browse files
committed
C++: Support concept id expressions
1 parent e236ce3 commit 94d915f

File tree

3 files changed

+109
-3
lines changed

3 files changed

+109
-3
lines changed

cpp/ql/lib/semmle/code/cpp/Concept.qll

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,104 @@ class NestedRequirementExpr extends Expr, @nested_requirement {
153153

154154
/**
155155
* A C++ concept id expression.
156+
*
157+
* For example, if:
158+
* ```cpp
159+
* template<typename T, T X> concept C = ...;
160+
* ...
161+
* requires { C<int, 1>; };
162+
* ```
163+
* then `C<int, 1>` is a concept id expression that refers to
164+
* the concept `C`.
156165
*/
157166
class ConceptIdExpr extends RequirementExpr, @concept_id {
158-
override string toString() { result = "concept<...>" }
167+
override string toString() {
168+
exists(string name |
169+
concept_templates(this.getConcept(), name, _) and
170+
result = name + "<...>"
171+
)
172+
}
159173

160174
override string getAPrimaryQlClass() { result = "ConceptIdExpr" }
175+
176+
/**
177+
* Holds if the concept id is used as a type constraint.
178+
*
179+
* In this case, the first template argument is implicit.
180+
*/
181+
predicate isTypeConstraint() { is_type_constraint(underlyingElement(this)) }
182+
183+
/**
184+
* Gets the concept this concept id refers to.
185+
*/
186+
Concept getConcept() { concept_instantiation(underlyingElement(this), unresolveElement(result)) }
187+
188+
/**
189+
* Gets a template argument passed to the concept.
190+
*/
191+
final Locatable getATemplateArgument() { result = this.getTemplateArgument(_) }
192+
193+
/**
194+
* Gets the kind of a non-type template argument passed to the concept.
195+
*/
196+
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
197+
198+
/**
199+
* Gets the `i`th template argument passed to the concept.
200+
*
201+
* For example, if:
202+
* ```cpp
203+
* template<typename T, T X> concept C = ...;
204+
* ...
205+
* requires { C<int, 1>; };
206+
* ```
207+
* then `getTemplateArgument(0)` yields `int`, and `getTemplateArgument(1)`
208+
* yields `1`.
209+
*
210+
* If the concept id is a type constraint, then `getTemplateArgument(0)`
211+
* will not yield a result.
212+
*/
213+
final Locatable getTemplateArgument(int index) {
214+
if exists(this.getTemplateArgumentValue(index))
215+
then result = this.getTemplateArgumentValue(index)
216+
else result = this.getTemplateArgumentType(index)
217+
}
218+
219+
/**
220+
* Gets the kind of the `i`th template argument value passed to the concept.
221+
*
222+
* For example, if:
223+
* ```cpp
224+
* template<typename T, T X> concept C = ...;
225+
* ...
226+
* requires { C<int, 1>; };
227+
* ```
228+
* then `getTemplateArgumentKind(1)` yields `int`, and there is no result for
229+
* `getTemplateArgumentKind(0)`.
230+
*/
231+
final Locatable getTemplateArgumentKind(int index) {
232+
exists(this.getTemplateArgumentValue(index)) and
233+
result = this.getTemplateArgumentType(index)
234+
}
235+
236+
/**
237+
* Gets the number of template arguments passed to the concept.
238+
*/
239+
final int getNumberOfTemplateArguments() {
240+
result = count(int i | exists(this.getTemplateArgument(i)))
241+
}
242+
243+
private Type getTemplateArgumentType(int index) {
244+
exists(int i | if this.isTypeConstraint() then i = index - 1 else i = index |
245+
concept_template_argument(underlyingElement(this), i, unresolveElement(result))
246+
)
247+
}
248+
249+
private Expr getTemplateArgumentValue(int index) {
250+
exists(int i | if this.isTypeConstraint() then i = index - 1 else i = index |
251+
concept_template_argument_value(underlyingElement(this), i, unresolveElement(result))
252+
)
253+
}
161254
}
162255

163256
/**
@@ -177,7 +270,7 @@ class Concept extends Declaration, @concept_template {
177270
override string getName() { concept_templates(underlyingElement(this), result, _) }
178271

179272
/**
180-
* Get the constraint expression of the concept.
273+
* Gets the constraint expression of the concept.
181274
*
182275
* For example, in
183276
* ```cpp
@@ -187,4 +280,12 @@ class Concept extends Declaration, @concept_template {
187280
* the constraint expression is `true`.
188281
*/
189282
Expr getExpr() { result.getParent() = this }
283+
284+
/**
285+
* Gets a concept id expression that refers to this concept
286+
*/
287+
ConceptIdExpr getAReferringConceptIdExpr() {
288+
this = result.getConcept() and
289+
exists(result.getATemplateArgument())
290+
}
190291
}

cpp/ql/lib/semmle/code/cpp/Declaration.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class Declaration extends Locatable, @declaration {
235235
*
236236
* `Foo<int, 1> bar;`
237237
*
238-
* Will have `getTemplateArgument())` return `int`, and
238+
* Will have `getTemplateArgument(0)` return `int`, and
239239
* `getTemplateArgument(1)` return `1`.
240240
*/
241241
final Locatable getTemplateArgument(int index) {

cpp/ql/lib/semmlecode.cpp.dbscheme

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,11 @@ concept_templates(
883883
string name: string ref,
884884
int location: @location_default ref
885885
);
886+
concept_instantiation(
887+
unique int to: @concept_id ref,
888+
int from: @concept_template ref
889+
);
890+
is_type_constraint(int concept_id: @concept_id ref);
886891
concept_template_argument(
887892
int concept_id: @concept ref,
888893
int index: int ref,

0 commit comments

Comments
 (0)