@@ -125,3 +125,89 @@ Type baseType(Type t) {
125125 // Make sure that the type has a size and that it isn't ambiguous.
126126 strictcount ( result .getSize ( ) ) = 1
127127}
128+
129+ /**
130+ * A `Type` that may be a pointer, array, or reference, to a const or a non-const type.
131+ *
132+ * For example, `const int*`, `int* const`, `const int* const`, `int*`, `int&`, `const int&` are all
133+ * `PointerLikeType`s, while `int`, `int&&`, and `const int` are not.
134+ *
135+ * To check if a `PointerLikeType` points/refers to a const-qualified type, use the `pointsToConst()`
136+ * predicate.
137+ */
138+ class PointerLikeType extends Type {
139+ Type innerType ;
140+ Type outerType ;
141+
142+ PointerLikeType ( ) {
143+ innerType = this .( UnspecifiedPointerOrArrayType ) .getBaseType ( ) and
144+ outerType = this
145+ or
146+ innerType = this .( LValueReferenceType ) .getBaseType ( ) and
147+ outerType = this
148+ or
149+ exists ( PointerLikeType stripped |
150+ stripped = this .stripTopLevelSpecifiers ( ) and not stripped = this
151+ |
152+ innerType = stripped .getInnerType ( ) and
153+ outerType = stripped .getOuterType ( )
154+ )
155+ }
156+
157+ /**
158+ * Gets the pointed to or referred to type, for instance `int` for `int*` or `const int&`.
159+ */
160+ Type getInnerType ( ) { result = innerType }
161+
162+ /**
163+ * Gets the resolved pointer, array, or reference type itself, for instance `int*` in `int* const`.
164+ *
165+ * Removes cv-qualification and resolves typedefs and decltypes and specifiers via
166+ * `stripTopLevelSpecifiers()`.
167+ */
168+ Type getOuterType ( ) { result = outerType }
169+
170+ /**
171+ * Holds when this type points to const -- for example, `const int*` and `const int&` point to
172+ * const, while `int*`, `int *const` and `int&` do not.
173+ */
174+ predicate pointsToConst ( ) { innerType .isConst ( ) }
175+
176+ /**
177+ * Holds when this type points to non-const -- for example, `int*` and `int&` and `int *const`
178+ * point to non-const, while `const int*`, `const int&` do not.
179+ */
180+ predicate pointsToNonConst ( ) { not innerType .isConst ( ) }
181+ }
182+
183+ /**
184+ * Gets usages of this parameter that maintain pointer-like semantics -- typically this means
185+ * either a normal access, or switching between pointers and reference semantics.
186+ *
187+ * Examples of accesses with pointer-like semantics include:
188+ * - `ref` in `int &x = ref`, or `&ref` in `int *x = &ref`;
189+ * - `ptr` in `int *x = ptr`, or `*ptr` in `int &x = *ptr`;
190+ *
191+ * In the above examples, we can still access the value pointed to by `ref` or `ptr` through the
192+ * expression.
193+ *
194+ * Examples of non-pointer-like semantics include:
195+ * - `ref` in `int x = ref` and `*ptr` in `int x = *ptr`;
196+ *
197+ * In the above examples, the value pointed to by `ref` or `ptr` is copied and the expression
198+ * refers to a new/different object.
199+ */
200+ Expr getAPointerLikeAccessOf ( Expr expr ) {
201+ exists ( PointerLikeType pointerLikeType | pointerLikeType = expr .getType ( ) |
202+ result = expr
203+ or
204+ // For reference parameters, also consider accesses to the parameter itself as accesses to the referent
205+ pointerLikeType .getOuterType ( ) instanceof ReferenceType and
206+ result .( AddressOfExpr ) .getOperand ( ) = expr
207+ or
208+ // A pointer is dereferenced, but the result is not copied
209+ pointerLikeType .getOuterType ( ) instanceof PointerType and
210+ result .( PointerDereferenceExpr ) .getOperand ( ) = expr and
211+ not any ( ReferenceDereferenceExpr rde ) .getExpr ( ) = result .getConversion + ( )
212+ )
213+ }
0 commit comments