Skip to content

Commit a9ac2f1

Browse files
Address feedback, separate compares from recurses, format.
1 parent 80a4077 commit a9ac2f1

File tree

3 files changed

+125
-38
lines changed

3 files changed

+125
-38
lines changed

c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ where
3030
f1.getDeclaration() = f2.getDeclaration() and
3131
//return type check
3232
(
33-
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig, interestedInFunctions/2>::equalReturnTypes(f1, f2) and
33+
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig, interestedInFunctions/2>::equalReturnTypes(f1,
34+
f2) and
3435
case = "return type" and
3536
pluralDo = "does"
3637
or
3738
//parameter type check
38-
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig, interestedInFunctions/2>::equalParameterTypes(f1, f2) and
39+
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig, interestedInFunctions/2>::equalParameterTypes(f1,
40+
f2) and
3941
case = "parameter types" and
4042
pluralDo = "do"
4143
or
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
- `RULE-8-3`, `RULE-8-4`, `DCL40-C`, `RULE-23-5`: `DeclarationsOfAFunctionSameNameAndType.ql`, `DeclarationsOfAnObjectSameNameAndType.ql`, `CompatibleDeclarationOfFunctionDefined.ql`, `CompatibleDeclarationObjectDefined.ql`, `IncompatibleFunctionDeclarations.ql`, `DangerousDefaultSelectionForPointerInGeneric.ql`:
22
- Added pragmas to alter join order on function parameter equivalence (names and types).
33
- Refactored expression which the optimizer was confused by, and compiled into a cartesian product.
4-
- Altered the module `Compatible.qll` to only perform expensive equality checks on types that are compared to a non identical other type, and those reachable from those types in the type graph. Types that are identical will trivially be considered equivalent.
4+
- Altered the module `Compatible.qll` to compute equality in two stages. Firstly, all pairs of possible type comparisons (including recursive comparisons) are found, then those pairwise comparisons are evaluated in a second stage. This greatly reduces the number of comparisons and greatly improves performance.
55
- `RULE-23-5`: `DangerousDefaultSelectionForPointerInGeneric.ql`:
66
- Altered the module `SimpleAssignment.qll` in accordance with the changes to `Compatible.qll`.

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

Lines changed: 120 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -217,48 +217,61 @@ signature predicate interestedInEquality(Type a, Type b);
217217
* A module to check the equivalence of two types, as defined by the provided `TypeEquivalenceSig`.
218218
*
219219
* For performance reasons, this module is designed to be used with a predicate
220-
* `interestedInEquality` that restricts the set of considered types.
220+
* `interestedInEquality` that restricts the set of considered pairwise comparisons.
221221
*
222222
* To use this module, define a `TypeEquivalenceSig` module and implement a subset of `Type` that
223223
* selects the relevant root types to be considered. Then use the predicate `equalTypes(a, b)`.
224224
* Note that `equalTypes(a, b)` only holds if `interestedIn(a, b)` holds. A type is always
225225
* considered to be equal to itself, and this module does not support configurations that declare
226-
* otherwise.
226+
* otherwise. Additionally, `interestedIn(a, b)` implies `interestedIn(b, a)`.
227227
*
228-
* Further, `interestedInEquality(a, a)` is treated differently from `interestedInEquality(a, b)`,
229-
* assuming that `a` and `b` are not identical. This is so that we can construct a set of types
230-
* that are not identical, but still may be equivalent by the specified configuration. We also must
231-
* consider all types that are reachable from these types, as the equivalence relation is
232-
* recursive. Therefore, this module is more performant when most comparisons are identical, and
233-
* only a few are not.
228+
* This module will recursively select pairs of types to be compared. For instance, if
229+
* `interestedInEquality(a, b)` holds, then types `a` and `b` will be compared. If
230+
* `Config::equalPointerTypes(a, b, true)` holds, then the pointed-to types of `a` and `b` will be
231+
* compared. However, if `Config::equalPointerTypes(a, b, false)` holds, then `a` and `b` will be
232+
* compared, but their pointed-to types will not. Similarly, inner types will not be compared if
233+
* `Config::overrideTypeComparison(a, b, _)` holds. For detail, see the module predicates
234+
* `recurses` and `compares`.
234235
*/
235236
module TypeEquivalence<TypeEquivalenceSig Config, interestedInEquality/2 interestedIn> {
236-
237237
/**
238238
* Performance related predicate to force top down rather than bottom up evaluation of type
239239
* equivalence.
240+
*
241+
* This interoperates with the predicate `recurses` to find types that will be compared, along
242+
* with the inner types of those types that will be compared. See `recurses` for cases where this
243+
* algorithm will or will not recurse. We still need to know which types are compared, even if
244+
* we do not recurse on them, in order to properly constrain `equalTypes(x, y)` to hold for types
245+
* such as leaf types, where we do not recurse during comparison.
246+
*
247+
* At each stage of recursion, we specify `pragma[only_bind_into]` to ensure that the
248+
* prior `recurses` results are considered first in the pipeline.
240249
*/
241250
predicate compares(Type t1, Type t2) {
242-
interestedIn(t1, t2)
251+
// Base case: config specifies that these root types will be compared.
252+
interestedInUnordered(t1, t2)
243253
or
254+
// If derived types are compared, their base types must be compared.
244255
exists(DerivedType t1Derived, DerivedType t2Derived |
245256
not t1Derived instanceof SpecifiedType and
246257
not t2Derived instanceof SpecifiedType and
247-
compares(pragma[only_bind_into](t1Derived), pragma[only_bind_into](t2Derived)) and
258+
recurses(pragma[only_bind_into](t1Derived), pragma[only_bind_into](t2Derived)) and
248259
t1 = t1Derived.getBaseType() and
249260
t2 = t2Derived.getBaseType()
250261
)
251262
or
263+
// If specified types are compared, their unspecified types must be compared.
252264
exists(SpecifiedType t1Spec, SpecifiedType t2Spec |
253-
compares(pragma[only_bind_into](t1Spec), pragma[only_bind_into](t2Spec)) and
265+
recurses(pragma[only_bind_into](t1Spec), pragma[only_bind_into](t2Spec)) and
254266
(
255267
t1 = unspecify(t1Spec) and
256268
t2 = unspecify(t2Spec)
257269
)
258270
)
259271
or
272+
// If function types are compared, their return types and parameter types must be compared.
260273
exists(FunctionType t1Func, FunctionType t2Func |
261-
compares(pragma[only_bind_into](t1Func), pragma[only_bind_into](t2Func)) and
274+
recurses(pragma[only_bind_into](t1Func), pragma[only_bind_into](t2Func)) and
262275
(
263276
t1 = t1Func.getReturnType() and
264277
t2 = t2Func.getReturnType()
@@ -270,13 +283,79 @@ module TypeEquivalence<TypeEquivalenceSig Config, interestedInEquality/2 interes
270283
)
271284
)
272285
or
286+
// If the config says to resolve typedefs, and a typedef type is compared to a non-typedef
287+
// type, then the non-typedef type must be compared to the base type of the typedef.
273288
Config::resolveTypedefs() and
274289
exists(TypedefType tdtype |
275290
tdtype.getBaseType() = t1 and
276-
compares(pragma[only_bind_into](tdtype), t2)
291+
recurses(pragma[only_bind_into](tdtype), t2)
277292
or
278293
tdtype.getBaseType() = t2 and
279-
compares(t1, pragma[only_bind_into](tdtype))
294+
recurses(t1, pragma[only_bind_into](tdtype))
295+
)
296+
or
297+
// If two typedef types are compared, then their base types must be compared.
298+
exists(TypedefType t1Typedef, TypedefType t2Typedef |
299+
recurses(pragma[only_bind_into](t1Typedef), pragma[only_bind_into](t2Typedef)) and
300+
(
301+
t1 = t1Typedef.getBaseType() and
302+
t2 = t2Typedef.getBaseType()
303+
)
304+
)
305+
}
306+
307+
/**
308+
* Performance related predicate to force top down rather than bottom up evaluation of type
309+
* equivalence.
310+
*
311+
* This predicate is used to determine whether we should recurse on a type. It is used in
312+
* conjunction with the `compares` predicate to only recurse on types that are being compared.
313+
*
314+
* We don't recurse on identical types, as they are already equal. We also don't recurse on
315+
* types that are overriden by `Config::overrideTypeComparison`, as that predicate determines
316+
* their equalivance.
317+
*
318+
* For the other types, we have a set of predicates such as `Config::equalPointerTypes` that
319+
* holds for `(x, y, true)` if the types `x` and `y` should be considered equivalent when the
320+
* pointed-to types of `x` and `y` are equivalent. If the predicate does not hold, or holds for
321+
* `(x, y, false)`, then we do not recurse on the types.
322+
*
323+
* We do not recurse on leaf types.
324+
*/
325+
private predicate recurses(Type t1, Type t2) {
326+
// We only recurse on types we are comparing.
327+
compares(pragma[only_bind_into](t1), pragma[only_bind_into](t2)) and
328+
// We don't recurse on identical types, as they are already equal.
329+
not t1 = t2 and
330+
// We don't recurse on overriden comparisons
331+
not Config::overrideTypeComparison(t1, t2, _) and
332+
(
333+
// These pointer types are equal if their base types are equal: recurse.
334+
Config::equalPointerTypes(t1, t2, true)
335+
or
336+
// These array types are equal if their base types are equal: recurse.
337+
Config::equalArrayTypes(t1, t2, true)
338+
or
339+
// These reference types are equal if their base types are equal: recurse.
340+
Config::equalReferenceTypes(t1, t2, true)
341+
or
342+
// These routine types are equal if their return and parameter types are equal: recurse.
343+
Config::equalRoutineTypes(t1, t2, true, true)
344+
or
345+
// These function pointer-ish types are equal if their return and parameter types are equal: recurse.
346+
Config::equalFunctionPointerIshTypes(t1, t2, true, true)
347+
or
348+
// These typedef types are equal if their base types are equal: recurse.
349+
Config::equalTypedefTypes(t1, t2, true)
350+
or
351+
// These specified types are equal if their unspecified types are equal: recurse.
352+
Config::equalSpecifiedTypes(t1, t2, true)
353+
or
354+
// We resolve typedefs, and one of these types is a typedef type: recurse.
355+
Config::resolveTypedefs() and
356+
t1 instanceof TypedefType
357+
or
358+
t2 instanceof TypedefType
280359
)
281360
}
282361

@@ -288,27 +367,32 @@ module TypeEquivalence<TypeEquivalenceSig Config, interestedInEquality/2 interes
288367
*/
289368
predicate equalTypes(Type t1, Type t2) {
290369
compares(pragma[only_bind_into](t1), pragma[only_bind_into](t2)) and
291-
if Config::overrideTypeComparison(t1, t2, _)
292-
then Config::overrideTypeComparison(t1, t2, true)
293-
else
294-
if t1 instanceof TypedefType and Config::resolveTypedefs()
295-
then equalTypes(t1.(TypedefType).getBaseType(), t2)
370+
(
371+
t1 = t2
372+
or
373+
not t1 = t2 and
374+
if Config::overrideTypeComparison(t1, t2, _)
375+
then Config::overrideTypeComparison(t1, t2, true)
296376
else
297-
if t2 instanceof TypedefType and Config::resolveTypedefs()
298-
then equalTypes(t1, t2.(TypedefType).getBaseType())
299-
else (
300-
not t1 instanceof DerivedType and
301-
not t2 instanceof DerivedType and
302-
not t1 instanceof TypedefType and
303-
not t2 instanceof TypedefType and
304-
equalLeafRelation(t1, t2)
305-
or
306-
equalDerivedTypes(t1, t2)
307-
or
308-
equalTypedefTypes(t1, t2)
309-
or
310-
equalFunctionTypes(t1, t2)
311-
)
377+
if t1 instanceof TypedefType and Config::resolveTypedefs()
378+
then equalTypes(t1.(TypedefType).getBaseType(), t2)
379+
else
380+
if t2 instanceof TypedefType and Config::resolveTypedefs()
381+
then equalTypes(t1, t2.(TypedefType).getBaseType())
382+
else (
383+
not t1 instanceof DerivedType and
384+
not t2 instanceof DerivedType and
385+
not t1 instanceof TypedefType and
386+
not t2 instanceof TypedefType and
387+
equalLeafRelation(t1, t2)
388+
or
389+
equalDerivedTypes(t1, t2)
390+
or
391+
equalTypedefTypes(t1, t2)
392+
or
393+
equalFunctionTypes(t1, t2)
394+
)
395+
)
312396
}
313397

314398
/** Whether two types will be compared, regardless of order (a, b) or (b, a). */
@@ -408,6 +492,7 @@ module FunctionDeclarationTypeEquivalence<
408492
}
409493

410494
predicate equalReturnTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
495+
interestedInFunctions(f1, f2) and
411496
TypeEquivalence<Config, interestedInReturnTypes/2>::equalTypes(f1.getType(), f2.getType())
412497
}
413498

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy