Skip to content

Commit 2a7b326

Browse files
committed
updates from review and improvements
1 parent e3064b6 commit 2a7b326

File tree

3 files changed

+104
-30
lines changed

3 files changed

+104
-30
lines changed

clang-tools-extra/clang-tidy/bugprone/MisleadingSetterOfReferenceCheck.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ namespace clang::tidy::bugprone {
1616

1717
void MisleadingSetterOfReferenceCheck::registerMatchers(MatchFinder *Finder) {
1818
auto RefField =
19-
fieldDecl(unless(isPublic()),
20-
hasType(referenceType(pointee(equalsBoundNode("type")))))
19+
fieldDecl(unless(isPublic()), hasType(hasCanonicalType(referenceType(
20+
pointee(equalsBoundNode("type"))))))
2121
.bind("member");
22-
auto AssignLHS =
23-
memberExpr(hasObjectExpression(cxxThisExpr()), member(RefField));
24-
auto DerefOperand = expr(ignoringParenImpCasts(
22+
auto AssignLHS = memberExpr(
23+
hasObjectExpression(ignoringParenCasts(cxxThisExpr())), member(RefField));
24+
auto DerefOperand = expr(ignoringParenCasts(
2525
declRefExpr(to(parmVarDecl(equalsBoundNode("parm"))))));
26-
auto AssignRHS = expr(ignoringParenImpCasts(
26+
auto AssignRHS = expr(ignoringParenCasts(
2727
unaryOperator(hasOperatorName("*"), hasUnaryOperand(DerefOperand))));
2828

2929
auto BinaryOpAssign = binaryOperator(hasOperatorName("="), hasLHS(AssignLHS),
@@ -35,11 +35,14 @@ void MisleadingSetterOfReferenceCheck::registerMatchers(MatchFinder *Finder) {
3535
compoundStmt(statementCountIs(1),
3636
anyOf(has(BinaryOpAssign), has(CXXOperatorCallAssign)));
3737
auto BadSetFunction =
38-
cxxMethodDecl(parameterCountIs(1), isPublic(),
39-
hasAnyParameter(parmVarDecl(hasType(pointerType(pointee(
40-
qualType().bind("type")))))
41-
.bind("parm")),
42-
hasBody(SetBody))
38+
cxxMethodDecl(
39+
parameterCountIs(1), isPublic(),
40+
hasParameter(
41+
0,
42+
parmVarDecl(hasType(hasCanonicalType(pointerType(pointee(qualType(
43+
hasCanonicalType(qualType().bind("type"))))))))
44+
.bind("parm")),
45+
hasBody(SetBody))
4346
.bind("bad-set-function");
4447
Finder->addMatcher(BadSetFunction, this);
4548
}
@@ -50,8 +53,9 @@ void MisleadingSetterOfReferenceCheck::check(
5053
const auto *Member = Result.Nodes.getNodeAs<FieldDecl>("member");
5154

5255
diag(Found->getBeginLoc(),
53-
"function \'%0\' can be mistakenly used in order to change the "
54-
"reference \'%1\' instead of the value of it")
56+
"function '%0' can be mistakenly used in order to change the "
57+
"reference '%1' instead of the value of it; consider not using a "
58+
"pointer as argument")
5559
<< Found->getName() << Member->getName();
5660
}
5761

clang-tools-extra/docs/clang-tidy/checks/bugprone/misleading-setter-of-reference.rst

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
bugprone-misleading-setter-of-reference
44
=======================================
55

6-
Finds setter-like functions that take a pointer parameter and set a (non-const)
7-
reference with the pointed value. The fact that a setter function takes a
8-
pointer might cause the belief that an internal reference (if it would be a
9-
pointer) is changed instead of the pointed-to (or referenced) value.
6+
Finds setter-like member functions that take a pointer parameter and set a
7+
(non-const) reference member of the same class with the pointed value.
8+
9+
The factthat a setter function takes a pointer might cause the belief that an
10+
internal reference (if it would be a pointer) is changed instead of the
11+
pointed-to (or referenced) value.
1012

1113
Only member functions are detected which have a single parameter and contain a
12-
single (maybe overloaded) assignment operator call.
14+
single (maybe overloaded) assignment operator call. The changed member variable
15+
must be private (or protected) for the checker to detect the fault (a public
16+
member can be changed anyway without a set function).
1317

1418
Example:
1519

@@ -18,15 +22,10 @@ Example:
1822
class Widget {
1923
int& ref_; // non-const reference member
2024
public:
21-
// non-copyable
22-
Widget(const Widget&) = delete;
23-
// non-movable
24-
Widget(Widget&&) = delete;
25-
26-
Widget(int& value) : ref_(value) {}
27-
28-
// Potentially dangerous setter that could lead to unintended behaviour
29-
void setRef(int* ptr) {
25+
Widget(int &value) : ref_(value) {}
26+
27+
// Warning: Potentially dangerous setter that could lead to unintended behaviour
28+
void setRef(int *ptr) {
3029
ref_ = *ptr; // This assigns to the referenced value, not changing what ref_ references
3130
}
3231
};
@@ -40,3 +39,9 @@ Example:
4039
// but it actually modifies value1 to be 100
4140
w.setRef(&value2); // value1 is now 100, ref_ still references value1
4241
}
42+
43+
Possible fixes:
44+
- Change the parameter of the "set" function to non-pointer or const reference
45+
type.
46+
- Change the type of the member variable to a pointer and in the "set"
47+
function assign a value to the pointer (without dereference).

clang-tools-extra/test/clang-tidy/checkers/bugprone/misleading-setter-of-reference.cpp

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
struct X {
44
X &operator=(const X &) { return *this; }
5+
private:
56
int &Mem;
7+
friend class Test1;
68
};
79

810
class Test1 {
@@ -15,15 +17,15 @@ class Test1 {
1517

1618
Test1(X &MemX, int &MemI, long &MemL) : MemX(MemX), MemI(MemI), MemL(MemL), MemLPub(MemL) {}
1719
void setI(int *NewValue) {
18-
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setI' can be mistakenly used in order to change the reference 'MemI' instead of the value of it [bugprone-misleading-setter-of-reference]
20+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setI' can be mistakenly used in order to change the reference 'MemI' instead of the value of it
1921
MemI = *NewValue;
2022
}
2123
void setL(long *NewValue) {
22-
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setL' can be mistakenly used in order to change the reference 'MemL' instead of the value of it [bugprone-misleading-setter-of-reference]
24+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setL' can be mistakenly used in order to change the reference 'MemL' instead of the value of it
2325
MemL = *NewValue;
2426
}
2527
void setX(X *NewValue) {
26-
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setX' can be mistakenly used in order to change the reference 'MemX' instead of the value of it [bugprone-misleading-setter-of-reference]
28+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setX' can be mistakenly used in order to change the reference 'MemX' instead of the value of it
2729
MemX = *NewValue;
2830
}
2931
void set1(int *NewValue) {
@@ -48,3 +50,66 @@ class Test1 {
4850
MemL = *NewValue;
4951
}
5052
};
53+
54+
class Base {
55+
protected:
56+
int &MemI;
57+
};
58+
59+
class Derived : public Base {
60+
public:
61+
void setI(int *NewValue) {
62+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setI' can be mistakenly used in order to change the reference 'MemI' instead of the value of it
63+
MemI = *NewValue;
64+
}
65+
};
66+
67+
using UIntRef = unsigned int &;
68+
using UIntPtr = unsigned int *;
69+
using UInt = unsigned int;
70+
71+
class AliasTest {
72+
UIntRef Value1;
73+
UInt &Value2;
74+
unsigned int &Value3;
75+
public:
76+
void setValue1(UIntPtr NewValue) {
77+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setValue1' can be mistakenly used in order to change the reference 'Value1' instead of the value of it
78+
Value1 = *NewValue;
79+
}
80+
void setValue2(unsigned int *NewValue) {
81+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setValue2' can be mistakenly used in order to change the reference 'Value2' instead of the value of it
82+
Value2 = *NewValue;
83+
}
84+
void setValue3(UInt *NewValue) {
85+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setValue3' can be mistakenly used in order to change the reference 'Value3' instead of the value of it
86+
Value3 = *NewValue;
87+
}
88+
};
89+
90+
template <typename T>
91+
class TemplateTest {
92+
T &Mem;
93+
public:
94+
void setValue(T *NewValue) {
95+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setValue' can be mistakenly used in order to change the reference 'Mem' instead of the value of it
96+
Mem = *NewValue;
97+
}
98+
};
99+
100+
void f_TTChar(TemplateTest<char> *);
101+
void f_TTChar(TemplateTest<float> *);
102+
103+
template <typename T>
104+
class AddMember {
105+
protected:
106+
T &Value;
107+
};
108+
109+
class TemplateBaseTest : public AddMember<int> {
110+
public:
111+
void setValue(int *NewValue) {
112+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'setValue' can be mistakenly used in order to change the reference 'Value' instead of the value of it
113+
Value = *NewValue;
114+
}
115+
};

0 commit comments

Comments
 (0)