Skip to content

Commit 00fa760

Browse files
committed
Change definition of out parameter and add exclusions
An out parameter is a non-const reference or pointer that is modified. We removed assignment operators and crement operators as exclusions to the modified property, because they should still be used to qualify an out parameter. Additionally we exclude user-defined non-member assignment operator and stream related operator parameters that are required to be passed by non-const reference.
1 parent c5fe049 commit 00fa760

File tree

3 files changed

+91
-26
lines changed

3 files changed

+91
-26
lines changed

cpp/autosar/src/rules/A8-4-8/OutputParametersUsed.ql

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,60 @@ import codingstandards.cpp.ConstHelpers
2323
import codingstandards.cpp.Operator
2424

2525
/**
26-
* Non-const T& and T* `Parameter`s to `Function`s
26+
* Holds if p is passed as a non-const reference or pointer and is modified.
27+
* This holds for in-out or out-only parameters.
2728
*/
28-
class NonConstReferenceOrPointerParameterCandidate extends FunctionParameter {
29-
NonConstReferenceOrPointerParameterCandidate() {
30-
this instanceof NonConstReferenceParameter
31-
or
32-
this instanceof NonConstPointerParameter
33-
}
29+
predicate isOutParameter(NonConstPointerorReferenceParameter p) {
30+
any(VariableEffect ve).getTarget() = p
31+
}
32+
33+
/**
34+
* Holds if parameter `p` is a parameter to a user defined assignment operator that
35+
* is defined outside of a class body.
36+
* These require an in-out parameter as the first argument.
37+
*/
38+
predicate isNonMemberUserAssignmentParameter(NonConstPointerorReferenceParameter p) {
39+
p.getFunction() instanceof UserAssignmentOperator and
40+
not p.isMember()
41+
}
42+
43+
/**
44+
* Holds if parameter `p` is a parameter to a stream insertion operator that
45+
* is defined outside of a class body.
46+
* These require an in-out parameter as the first argument.
47+
*
48+
* e.g., `std::ostream& operator<<(std::ostream& os, const T& obj)`
49+
*/
50+
predicate isStreamInsertionStreamParameter(NonConstPointerorReferenceParameter p) {
51+
exists(StreamInsertionOperator op | not op.isMember() | op.getParameter(0) = p)
3452
}
3553

36-
pragma[inline]
37-
predicate isFirstAccess(VariableAccess va) {
38-
not exists(VariableAccess otherVa |
39-
otherVa.getTarget() = va.getTarget() or
40-
otherVa.getQualifier().(VariableAccess).getTarget() = va.getTarget()
41-
|
42-
otherVa.getASuccessor() = va
54+
/**
55+
* Holds if parameter `p` is a parameter to a stream insertion operator that
56+
* is defined outside of a class body.
57+
* These require an in-out parameter as the first argument and an out parameter for the second.
58+
*
59+
* e.g., `std::istream& operator>>(std::istream& is, T& obj)`
60+
*/
61+
predicate isStreamExtractionParameter(NonConstPointerorReferenceParameter p) {
62+
exists(StreamExtractionOperator op | not op.isMember() |
63+
op.getParameter(0) = p
64+
or
65+
op.getParameter(1) = p
4366
)
4467
}
4568

46-
from NonConstReferenceOrPointerParameterCandidate p, VariableEffect ve
69+
predicate isException(NonConstPointerorReferenceParameter p) {
70+
isNonMemberUserAssignmentParameter(p) and p.getIndex() = 0
71+
or
72+
isStreamInsertionStreamParameter(p)
73+
or
74+
isStreamExtractionParameter(p)
75+
}
76+
77+
from NonConstPointerorReferenceParameter p
4778
where
4879
not isExcluded(p, ConstPackage::outputParametersUsedQuery()) and
49-
ve.getTarget() = p and
50-
isFirstAccess(ve.getAnAccess()) and
51-
not ve instanceof AnyAssignOperation and
52-
not ve instanceof CrementOperation
53-
select p, "Out parameter " + p.getName() + " that is modified before being read."
80+
isOutParameter(p) and
81+
not isException(p)
82+
select p, "Out parameter '" + p.getName() + "' used."
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
| test.cpp:5:22:5:24 | str | Out parameter str that is modified before being read. |
2-
| test.cpp:16:14:16:14 | i | Out parameter i that is modified before being read. |
3-
| test.cpp:21:14:21:14 | i | Out parameter i that is modified before being read. |
4-
| test.cpp:29:12:29:12 | a | Out parameter a that is modified before being read. |
5-
| test.cpp:33:12:33:12 | a | Out parameter a that is modified before being read. |
1+
| test.cpp:5:22:5:24 | str | Out parameter 'str' used. |
2+
| test.cpp:8:22:8:24 | str | Out parameter 'str' used. |
3+
| test.cpp:16:14:16:14 | i | Out parameter 'i' used. |
4+
| test.cpp:21:14:21:14 | i | Out parameter 'i' used. |
5+
| test.cpp:29:12:29:12 | a | Out parameter 'a' used. |
6+
| test.cpp:33:12:33:12 | a | Out parameter 'a' used. |

cpp/autosar/test/rules/A8-4-8/test.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ void f(int &i) { // COMPLIANT
55
void f1(std::string &str) { // NON_COMPLIANT
66
str = "replacement";
77
}
8-
void f2(std::string &str) { // COMPLIANT
8+
void f2(std::string &str) { // NON_COMPLIANT
99
str += "suffix";
1010
}
1111

@@ -37,3 +37,38 @@ void f7(A &a) { // NON_COMPLIANT
3737
void f8(int i) { // COMPLIANT
3838
i += 1;
3939
}
40+
41+
constexpr A &operator|=(
42+
A &lhs,
43+
const A &rhs) noexcept { // COMPLIANT - non-member user defined assignment
44+
// operators are considered an exception.
45+
return lhs;
46+
}
47+
48+
enum class byte : unsigned char {};
49+
constexpr byte &operator|(const byte &lhs, const byte &rhs) noexcept {
50+
return lhs | rhs;
51+
}
52+
constexpr byte &operator|=(
53+
byte &lhs,
54+
const byte rhs) noexcept { // COMPLIANT - non-member user defined assignment
55+
// operators are considered an exception.
56+
lhs = (lhs | rhs);
57+
return lhs;
58+
}
59+
60+
#include <iostream>
61+
std::ostream &operator<<(std::ostream &os,
62+
const byte &obj) { // COMPLIANT - insertion operators
63+
// are considered an exception.
64+
std::ostream other;
65+
os = other; // simulate modification
66+
return os;
67+
}
68+
69+
std::istream &operator>>(std::istream &is,
70+
byte &obj) { // COMPLIANT - extraction operators are
71+
// considered an exception.
72+
obj = static_cast<byte>('a'); // simulate modification
73+
return is;
74+
}

0 commit comments

Comments
 (0)