Skip to content

Commit 60ae374

Browse files
authored
Merge pull request #18366 from github/jketema/template-parameters-5
C++: Support concept id expressions
2 parents ca05697 + ac05bfc commit 60ae374

File tree

12 files changed

+10907
-1111
lines changed

12 files changed

+10907
-1111
lines changed

cpp/downgrades/7eeff19bf7c89a350d3e43516a33c98a270cb057/old.dbscheme

Lines changed: 2382 additions & 0 deletions
Large diffs are not rendered by default.

cpp/downgrades/7eeff19bf7c89a350d3e43516a33c98a270cb057/semmlecode.cpp.dbscheme

Lines changed: 2377 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
description: Support concept id expressions
2+
compatibility: full
3+
concept_instantiation.rel: delete
4+
is_type_constraint.rel: delete
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: feature
3+
---
4+
* A new class `ConceptIdExpr` was introduced, which represents C++20 concept id expressions.
5+

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

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,107 @@ 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+
result = this.getConcept().getName() + "<...>"
169+
or
170+
// The following is for backward compatibility with databases created with
171+
// CodeQL 2.19.3, 2.19.4, and 2.20.0. Those databases include concept id
172+
// expressions, but do not include concept template information.
173+
not exists(this.getConcept()) and
174+
result = "concept<...>"
175+
}
159176

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

163259
/**
@@ -187,4 +283,9 @@ class Concept extends Declaration, @concept_template {
187283
* the constraint expression is `std::is_same<T, int>::value`.
188284
*/
189285
Expr getExpr() { result.getParent() = this }
286+
287+
/**
288+
* Gets a concept id expression that refers to this concept
289+
*/
290+
ConceptIdExpr getAReferringConceptIdExpr() { this = result.getConcept() }
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/semmle/code/cpp/PrintAST.qll

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ private Declaration getAnEnclosingDeclaration(Locatable ast) {
8888
or
8989
result = ast.(Initializer).getDeclaration()
9090
or
91+
exists(ConceptIdExpr concept | ast = concept.getATemplateArgument() |
92+
result = concept.getEnclosingFunction()
93+
)
94+
or
9195
result = ast
9296
}
9397

@@ -107,6 +111,12 @@ private newtype TPrintAstNode =
107111
TRequiresExprParametersNode(RequiresExpr req) {
108112
shouldPrintDeclaration(getAnEnclosingDeclaration(req))
109113
} or
114+
TConceptIdExprArgumentsNode(ConceptIdExpr concept) {
115+
shouldPrintDeclaration(getAnEnclosingDeclaration(concept))
116+
} or
117+
TConceptIdExprTypeArgumentNode(Type type, ConceptIdExpr concept, int childIndex) {
118+
type = concept.getTemplateArgument(childIndex)
119+
} or
110120
TConstructorInitializersNode(Constructor ctor) {
111121
ctor.hasEntryPoint() and
112122
shouldPrintDeclaration(ctor)
@@ -357,6 +367,26 @@ class StringLiteralNode extends ExprNode {
357367
override string getValue() { result = "\"" + escapeString(expr.getValue()) + "\"" }
358368
}
359369

370+
/**
371+
* A node representing a `ConceptIdExpr`.
372+
*/
373+
class ConceptIdExprNode extends ExprNode {
374+
override ConceptIdExpr expr;
375+
376+
override PrintAstNode getChildInternal(int childIndex) {
377+
result = super.getChildInternal(childIndex)
378+
or
379+
childIndex = -1 and
380+
result.(ConceptIdExprArgumentsNode).getConceptIdExpr() = expr
381+
}
382+
383+
override string getChildAccessorPredicateInternal(int childIndex) {
384+
result = super.getChildAccessorPredicateInternal(childIndex)
385+
or
386+
childIndex = -1 and result = "<args>"
387+
}
388+
}
389+
360390
/**
361391
* A node representing a `Conversion`.
362392
*/
@@ -593,6 +623,63 @@ class InitializerNode extends AstNode {
593623
}
594624
}
595625

626+
/**
627+
* A node representing the arguments of a `ConceptIdExpr`.
628+
*/
629+
class ConceptIdExprArgumentsNode extends PrintAstNode, TConceptIdExprArgumentsNode {
630+
ConceptIdExpr concept;
631+
632+
ConceptIdExprArgumentsNode() { this = TConceptIdExprArgumentsNode(concept) }
633+
634+
final override string toString() { result = "" }
635+
636+
final override Location getLocation() { result = getRepresentativeLocation(concept) }
637+
638+
override PrintAstNode getChildInternal(int childIndex) {
639+
exists(Locatable arg | arg = concept.getTemplateArgument(childIndex) |
640+
result.(ConceptIdExprTypeArgumentNode).isArgumentNode(arg, concept, childIndex)
641+
or
642+
result.(ExprNode).getAst() = arg
643+
)
644+
}
645+
646+
override string getChildAccessorPredicateInternal(int childIndex) {
647+
exists(this.getChildInternal(childIndex)) and
648+
result = "getTemplateArgument(" + childIndex + ")"
649+
}
650+
651+
/**
652+
* Gets the `ConceptIdExpr` for which this node represents the parameters.
653+
*/
654+
final ConceptIdExpr getConceptIdExpr() { result = concept }
655+
}
656+
657+
/**
658+
* A node representing a type argument of a `ConceptIdExpr`.
659+
*/
660+
class ConceptIdExprTypeArgumentNode extends PrintAstNode, TConceptIdExprTypeArgumentNode {
661+
Type type;
662+
ConceptIdExpr concept;
663+
int index;
664+
665+
ConceptIdExprTypeArgumentNode() { this = TConceptIdExprTypeArgumentNode(type, concept, index) }
666+
667+
final override string toString() { result = qlClass(type) + type.toString() }
668+
669+
final override Location getLocation() { result = getRepresentativeLocation(type) }
670+
671+
override AstNode getChildInternal(int childIndex) { none() }
672+
673+
override string getChildAccessorPredicateInternal(int childIndex) { none() }
674+
675+
/**
676+
* Holds if `t` is the `i`th template argument of `c`.
677+
*/
678+
predicate isArgumentNode(Type t, ConceptIdExpr c, int i) {
679+
type = t and concept = c and index = i
680+
}
681+
}
682+
596683
/**
597684
* A node representing the parameters of a `Function`.
598685
*/
@@ -611,7 +698,7 @@ class FunctionParametersNode extends PrintAstNode, TFunctionParametersNode {
611698

612699
override string getChildAccessorPredicateInternal(int childIndex) {
613700
exists(this.getChildInternal(childIndex)) and
614-
result = "getParameter(" + childIndex.toString() + ")"
701+
result = "getParameter(" + childIndex + ")"
615702
}
616703

617704
/**
@@ -638,7 +725,7 @@ class RequiresExprParametersNode extends PrintAstNode, TRequiresExprParametersNo
638725

639726
override string getChildAccessorPredicateInternal(int childIndex) {
640727
exists(this.getChildInternal(childIndex)) and
641-
result = "getParameter(" + childIndex.toString() + ")"
728+
result = "getParameter(" + childIndex + ")"
642729
}
643730

644731
/**
@@ -665,7 +752,7 @@ class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializers
665752

666753
final override string getChildAccessorPredicateInternal(int childIndex) {
667754
exists(this.getChildInternal(childIndex)) and
668-
result = "getInitializer(" + childIndex.toString() + ")"
755+
result = "getInitializer(" + childIndex + ")"
669756
}
670757

671758
/**
@@ -692,7 +779,7 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
692779

693780
final override string getChildAccessorPredicateInternal(int childIndex) {
694781
exists(this.getChildInternal(childIndex)) and
695-
result = "getDestruction(" + childIndex.toString() + ")"
782+
result = "getDestruction(" + childIndex + ")"
696783
}
697784

698785
/**

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)