-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathParameter.qll
More file actions
171 lines (157 loc) · 5.66 KB
/
Parameter.qll
File metadata and controls
171 lines (157 loc) · 5.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**
* Provides a class that models parameters to functions.
*/
import semmle.code.cpp.Location
import semmle.code.cpp.Declaration
private import semmle.code.cpp.internal.ResolveClass
/**
* A C/C++ function parameter, catch block parameter, or requires expression parameter.
* For example the function parameter `p` and the catch block parameter `e` in the following
* code:
* ```
* void myFunction(int p) {
* try {
* ...
* } catch (const std::exception &e) {
* ...
* }
* }
* ```
*
* For catch block parameters and expression , there is a one-to-one
* correspondence between the `Parameter` and its `VariableDeclarationEntry`.
*
* For function parameters, there is a one-to-many relationship between
* `Parameter` and `ParameterDeclarationEntry`, because one function can
* have multiple declarations.
*/
class Parameter extends LocalScopeVariable, @parameter {
/**
* Gets the canonical name, or names, of this parameter.
*
* The canonical names are the first non-empty category from the
* following list:
* 1. The name given to the parameter at the function's definition or
* (for catch block parameters) at the catch block.
* 2. A name given to the parameter at a function declaration.
* 3. The name "(unnamed parameter i)" where i is the index of the parameter.
*/
override string getName() {
exists(VariableDeclarationEntry vde |
vde = this.getANamedDeclarationEntry() and result = vde.getName()
|
vde.isDefinition() or not this.getANamedDeclarationEntry().isDefinition()
)
or
not exists(this.getANamedDeclarationEntry()) and
result = "(unnamed parameter " + this.getIndex().toString() + ")"
}
override string getAPrimaryQlClass() { result = "Parameter" }
/**
* Gets the name of this parameter, including it's type.
*
* For example: `int p`.
*/
string getTypedName() {
exists(string typeString, string nameString |
(
if exists(this.getType().getName())
then typeString = this.getType().getName()
else typeString = ""
) and
(if exists(this.getName()) then nameString = this.getName() else nameString = "") and
(
if typeString != "" and nameString != ""
then result = typeString + " " + nameString
else result = typeString + nameString
)
)
}
private VariableDeclarationEntry getANamedDeclarationEntry() {
result = this.getAnEffectiveDeclarationEntry() and
exists(string name | var_decls(unresolveElement(result), _, _, name, _) | name != "")
}
/**
* Gets a declaration entry corresponding to this declaration.
*
* This predicate is the same as getADeclarationEntry(), except that for
* parameters of instantiated function templates, gives the declaration
* entry of the prototype instantiation of the parameter (as
* non-prototype instantiations don't have declaration entries of their
* own).
*/
private VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
if this.getFunction().isConstructedFrom(_)
then
exists(Function prototypeInstantiation |
prototypeInstantiation.getParameter(this.getIndex()) = result.getVariable() and
this.getFunction().isConstructedFrom(prototypeInstantiation)
)
else result = this.getADeclarationEntry()
}
/**
* Holds if this parameter has a name.
*
* In other words, this predicate holds precisely when the result of
* `getName()` is not "(unnamed parameter i)" (where `i` is the index
* of the parameter).
*/
predicate isNamed() { exists(this.getANamedDeclarationEntry()) }
/**
* Gets the function to which this parameter belongs, if it is a function
* parameter.
*/
override Function getFunction() {
params(underlyingElement(this), unresolveElement(result), _, _)
}
/**
* Gets the catch block to which this parameter belongs, if it is a catch
* block parameter.
*/
BlockStmt getCatchBlock() { params(underlyingElement(this), unresolveElement(result), _, _) }
/**
* Gets the requires expression to which the parameter belongs, if it is a
* requires expression parameter.
*/
RequiresExpr getRequiresExpr() { params(underlyingElement(this), unresolveElement(result), _, _) }
/**
* Gets the zero-based index of this parameter.
*
* For catch block parameters, this is always zero.
*/
int getIndex() { params(underlyingElement(this), _, result, _) }
/**
* Gets the type of this parameter.
*
* Function parameters of array type are a special case in C/C++,
* as they are syntactic sugar for parameters of pointer type. The
* result is an array type for such parameters.
*/
override Type getType() { params(underlyingElement(this), _, _, unresolveElement(result)) }
/**
* Gets the canonical location, or locations, of this parameter.
*
* 1. For catch block parameters, gets the obvious location.
* 2. For parameters of functions which have a definition, gets the
* location within the function definition.
* 3. For parameters of functions which don't have a definition, gets all
* of the declaration locations.
*/
override Location getLocation() {
exists(VariableDeclarationEntry vde |
vde = this.getAnEffectiveDeclarationEntry() and result = vde.getLocation()
|
vde.isDefinition() or not this.getAnEffectiveDeclarationEntry().isDefinition()
)
}
}
/**
* An `int` that is a parameter index for some function. This is needed for binding in certain cases.
*/
class ParameterIndex extends int {
ParameterIndex() {
exists(Parameter p | this = p.getIndex()) or
exists(Call c | exists(c.getArgument(this))) or // permit indexing varargs
this = -1 // used for `this`
}
}