-
Notifications
You must be signed in to change notification settings - Fork 77
Expand file tree
/
Copy pathInvalidSignatureForSpecialMemberFunction.ql
More file actions
106 lines (101 loc) · 3.62 KB
/
InvalidSignatureForSpecialMemberFunction.ql
File metadata and controls
106 lines (101 loc) · 3.62 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
/**
* @id cpp/misra/invalid-signature-for-special-member-function
* @name RULE-15-0-2: User-provided copy and move member functions of a class should have appropriate signatures
* @description Proper implementations of copy and move constructors and assignment operators ensure
* that resources are managed correctly.
* @kind problem
* @precision very-high
* @problem.severity warning
* @tags external/misra/id/rule-15-0-2
* scope/single-translation-unit
* correctness
* maintainability
* external/misra/enforcement/decidable
* external/misra/obligation/advisory
*/
import cpp
import codingstandards.cpp.misra
import codeql.util.Boolean
pragma[inline]
predicate checkSignature(
MemberFunction f, Boolean noexcept, Boolean lvalueQualified, Boolean rvalueRef, string err
) {
f.getNumberOfParameters() > 1 and
err = "has too many parameters"
or
noexcept = true and
not f.isNoExcept() and
err = "should be noexcept"
or
// Note: There is no check when `lvalueQualified` is false, only when true. `lvalueQualified` will
// only be false for constructors, and constructors cannot be ref-qualified.
lvalueQualified = true and
not f.isLValueRefQualified() and
err = "should be lvalue-qualified"
or
// Note: This case is also only here for completeness. `rvalueRef` is only true for move
// constructors and move assignment operators. However, these special member functions by
// definition must take an rvalue reference, so this case cannot hold.
rvalueRef = true and
not isRvalueRefX(f.getParameter(0).getType(), f.getDeclaringType()) and
err = "should take rvalue reference to class or struct type"
or
rvalueRef = false and
not isConstRefX(f.getParameter(0).getType(), f.getDeclaringType()) and
err = "should take const reference to class or struct type"
or
f.isVirtual() and
err = "should not be virtual"
or
not f instanceof Constructor and
not f.getType().(LValueReferenceType).getBaseType() = f.getDeclaringType() and
not f.getType() instanceof VoidType and
err = "should return void or lvalue reference to class or struct type"
or
// Note: this is here for completeness. It is a static error to declare copy or move constructors
// as `explicit`, so this cannot hold.
not f instanceof Constructor and
f.isExplicit() and
err = "should not be explicit"
}
predicate isRvalueRefX(Type t, Class x) {
// X &&
t.(RValueReferenceType).getBaseType() = x
}
predicate isConstRefX(Type t, Class x) {
exists(SpecifiedType st |
// X const &
st = t.(LValueReferenceType).getBaseType() and
st.getSpecifierString() = "const" and
st.getBaseType() = x
or
// const X &
st = t and
st.getSpecifierString() = "const" and
st.getBaseType().(LValueReferenceType).getBaseType() = x
)
}
from MemberFunction f, string err, string prefix
where
not isExcluded(f, Classes2Package::invalidSignatureForSpecialMemberFunctionQuery()) and
not f.isDeleted() and
not f.isDefaulted() and
not f.isCompilerGenerated() and
(
f instanceof CopyConstructor and
prefix = "Copy constructor" and
checkSignature(f, false, false, false, err)
or
f instanceof MoveConstructor and
prefix = "Move constructor" and
checkSignature(f, true, false, true, err)
or
f instanceof CopyAssignmentOperator and
prefix = "Copy assignment operator" and
checkSignature(f, false, true, false, err)
or
f instanceof MoveAssignmentOperator and
prefix = "Move assignment operator" and
checkSignature(f, true, true, true, err)
)
select f, prefix + " on type $@ " + err + ".", f.getDeclaringType(), f.getDeclaringType().getName()