Skip to content

Commit dd8135c

Browse files
Add comments to new shared APIs.
1 parent 1b83422 commit dd8135c

File tree

3 files changed

+109
-10
lines changed

3 files changed

+109
-10
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import cpp
2+
3+
/**
4+
* A predicate to simplify getting a namespace for a template parameter, since
5+
* `TemplateParameterType`'s `getNamespace()` has no result, and `enclosingElement()` has no result,
6+
* and there are multiple cases to navigate to work around this.
7+
*/
8+
Namespace getTemplateParameterNamespace(TypeTemplateParameter param) {
9+
exists(Declaration decl |
10+
param = decl.(TemplateClass).getATemplateArgument() or
11+
param = decl.(TemplateVariable).getATemplateArgument() or
12+
param = decl.(TemplateFunction).getATemplateArgument()
13+
|
14+
result = decl.getNamespace()
15+
)
16+
}

cpp/common/src/codingstandards/cpp/types/Predicate.qll

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
1+
/**
2+
* A library for handling "predicate" types, which are function parameters in the standard library.
3+
*
4+
* For example, `std::sort` takes a predicate as its third argument, and `std::set` takes a
5+
* predicate as its second template parameter. Predicates are always template parameters, and we
6+
* can identify them by their name -- this is what MISRA expects us to do.
7+
*/
8+
19
import cpp
210
private import codingstandards.cpp.StdNamespace
11+
private import codingstandards.cpp.ast.Templates
312
private import codingstandards.cpp.types.Templates
413
private import semmle.code.cpp.dataflow.new.DataFlow
514

6-
Namespace getTemplateParameterNamespace(TypeTemplateParameter param) {
7-
exists(Declaration decl |
8-
param = decl.(TemplateClass).getATemplateArgument() or
9-
param = decl.(TemplateVariable).getATemplateArgument() or
10-
param = decl.(TemplateFunction).getATemplateArgument()
11-
|
12-
result = decl.getNamespace()
13-
)
14-
}
15-
15+
/**
16+
* A "predicate" type parameter as defined by MISRA, which is a standard library function named
17+
* "Compare" or "Predicate" or "BinaryPredicate" in the standard library.
18+
*
19+
* To be more widely useful, we match more flexibly on the name, as `_Compare` is also common, etc.
20+
*
21+
* To get a particular `Type` that is _used_ as a predicate type, see `getASubstitutedType()`,
22+
* rather than the type parameter itself, see `getASubstitutedType()`.
23+
*/
1624
class PredicateType extends TypeTemplateParameter {
1725
PredicateType() {
1826
this.getName().matches(["%Compare%", "%Predicate%"]) and
1927
getTemplateParameterNamespace(this) instanceof StdNS
2028
}
2129

30+
/**
31+
* Get a type that is used (anywhere, via some substitution) as this predicate type parameter.
32+
*
33+
* For example, `std::sort(..., ..., [](int a, int b) { return a < b; })` creates a `Closure`
34+
* type, and substitutes that closure type for the predicate type parameter of `std::sort`.
35+
*/
2236
Type getASubstitutedType(Substitution sub) { result = sub.getSubstitutedTypeForParameter(this) }
2337
}
2438

39+
/**
40+
* A class type that has been substituted for a predicate type parameter, and has an `operator()`
41+
* member function.
42+
*
43+
* For example, the closure type in `std::sort(..., ..., [](int a, int b) { return a < b; })` is a
44+
* `PredicateFunctionObject`, and so is any `std::less<int>` that is used as a predicate type
45+
* parameter, etc.
46+
*
47+
* This does not cover function pointer types, as these are not class types.
48+
*/
2549
class PredicateFunctionObject extends Class {
2650
PredicateType pred;
2751
Function operator;
@@ -33,13 +57,38 @@ class PredicateFunctionObject extends Class {
3357
operator.getName() = "operator()"
3458
}
3559

60+
/**
61+
* Get the predicate type parameter that this function object is being substituted for.
62+
*/
3663
PredicateType getPredicateType() { result = pred }
3764

65+
/**
66+
* Get the `operator()` function that this function object defines. This is the function that will
67+
* be invoked and essentially defines the predicate behavior.
68+
*/
3869
Function getCallOperator() { result = operator }
3970

71+
/**
72+
* Get the `Substitution` object that makes this type a `PredicateFunctionObject`.
73+
*
74+
* This is a particular instantiation of some template that contains a predicate type parameter,
75+
* which is substituted by this type in that instantiation. The `Substitution` object may refer
76+
* to a `TemplateClass`, `TemplateVariable`, or `TemplateFunction`.
77+
*/
4078
Substitution getSubstitution() { result = sub }
4179
}
4280

81+
/**
82+
* Gets a function access where the purpose of that access is to pass the accessed function as a
83+
* predicate argument to a standard library template.
84+
*
85+
* For example, in `std::sort(..., ..., myCompare)`, where `myCompare` is a function, then
86+
* `myCompare` will be converted into a function pointer and that function pointer will be used as
87+
* a predicate in that `std::sort` call.
88+
*
89+
* This is more complex to identify than `PredicateFunctionObject` because the addressee of the
90+
* function pointer is not necessarily statically known.
91+
*/
4392
class PredicateFunctionPointerUse extends FunctionAccess {
4493
Expr functionPointerArgument;
4594
FunctionCall templateFunctionCall;
@@ -62,5 +111,8 @@ class PredicateFunctionPointerUse extends FunctionAccess {
62111
)
63112
}
64113

114+
/**
115+
* Get the predicate type parameter that this function pointer is being substituted for.
116+
*/
65117
PredicateType getPredicateType() { result = pred }
66118
}

cpp/common/src/codingstandards/cpp/types/Templates.qll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,48 @@ private newtype TSubstitution =
55
TFunctionSubstitution(FunctionTemplateInstantiation fti) or
66
TVariableSubstitution(VariableTemplateInstantiation vti)
77

8+
/**
9+
* A class to facilitate working with template substitutions, especially since templates may be a
10+
* `TemplateClass`, `TemplateFunction`, or `TemplateVariable`, which complicates their usage.
11+
*
12+
* A `Substitution` in particular refers to an instantiation of that template of some kind, and
13+
* allows analysis of which parameters were substituted with which types in that instatiation.
14+
*/
815
class Substitution extends TSubstitution {
916
ClassTemplateInstantiation asClassSubstitution() { this = TClassSubstitution(result) }
1017

1118
FunctionTemplateInstantiation asFunctionSubstitution() { this = TFunctionSubstitution(result) }
1219

1320
VariableTemplateInstantiation asVariableSubstitution() { this = TVariableSubstitution(result) }
1421

22+
/**
23+
* Get the nth template parameter type of the template that is being substituted.
24+
*
25+
* For example, in `std::vector<int>`, the 0th template parameter is `typename T`.
26+
*/
1527
TypeTemplateParameter getTemplateParameter(int index) {
1628
result = this.asClassSubstitution().getTemplate().getTemplateArgument(index) or
1729
result = this.asFunctionSubstitution().getTemplate().getTemplateArgument(index) or
1830
result = this.asVariableSubstitution().getTemplate().getTemplateArgument(index)
1931
}
2032

33+
/**
34+
* Get the type that is substituting the nth template parameter in this substitution.
35+
*
36+
* For example, in `std::vector<int>`, the 0th substituted type is `int`.
37+
*/
2138
Type getSubstitutedType(int index) {
2239
result = this.asClassSubstitution().getTemplateArgument(index) or
2340
result = this.asFunctionSubstitution().getTemplateArgument(index) or
2441
result = this.asVariableSubstitution().getTemplateArgument(index)
2542
}
2643

44+
/**
45+
* Get the type that is substituting the given template parameter in this substitution.
46+
*
47+
* For example, in `std::vector<int>`, this predicate matches the given type `int` with the type
48+
* parameter `typename T`.
49+
*/
2750
Type getSubstitutedTypeForParameter(TypeTemplateParameter param) {
2851
exists(int idx |
2952
this.getTemplateParameter(idx) = param and
@@ -37,6 +60,14 @@ class Substitution extends TSubstitution {
3760
result = this.asVariableSubstitution().toString()
3861
}
3962

63+
/**
64+
* Get a `Locatable` that represents a where this substitution was declared in the source code.
65+
*
66+
* The result may be a `TypeMention`, `Call`, etc. depending on the kind of template and how it is
67+
* being used, but it handles the various template cases for you.
68+
*
69+
* Note that this instantiation may have been declared in multiple places.
70+
*/
4071
Locatable getASubstitutionSite() {
4172
result.(TypeMention).getMentionedType() = this.asClassSubstitution()
4273
or

0 commit comments

Comments
 (0)