Skip to content

Commit 4c18d09

Browse files
committed
[clang-tidy] support return c ? a : b; in bugprone-return-const-ref-from-parameter
A `const &` parameter can also be returned via a conditional operator: `c ? a : b`. This change adds support for diagnosing returning these parameters with conditional operators.
1 parent fc7a893 commit 4c18d09

File tree

3 files changed

+36
-16
lines changed

3 files changed

+36
-16
lines changed

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "ReturnConstRefFromParameterCheck.h"
10+
#include "clang/AST/Expr.h"
1011
#include "clang/ASTMatchers/ASTMatchFinder.h"
1112
#include "clang/ASTMatchers/ASTMatchers.h"
1213

@@ -15,20 +16,24 @@ using namespace clang::ast_matchers;
1516
namespace clang::tidy::bugprone {
1617

1718
void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) {
18-
Finder->addMatcher(
19-
returnStmt(
20-
hasReturnValue(declRefExpr(
21-
to(parmVarDecl(hasType(hasCanonicalType(
22-
qualType(lValueReferenceType(pointee(
23-
qualType(isConstQualified()))))
24-
.bind("type"))))
25-
.bind("param")))),
26-
hasAncestor(
27-
functionDecl(hasReturnTypeLoc(loc(qualType(
28-
hasCanonicalType(equalsBoundNode("type"))))))
29-
.bind("func")))
30-
.bind("ret"),
31-
this);
19+
const auto DRef =
20+
declRefExpr(
21+
to(parmVarDecl(hasType(hasCanonicalType(
22+
qualType(lValueReferenceType(pointee(
23+
qualType(isConstQualified()))))
24+
.bind("type"))))
25+
.bind("param")))
26+
.bind("dref");
27+
const auto Func =
28+
functionDecl(hasReturnTypeLoc(loc(
29+
qualType(hasCanonicalType(equalsBoundNode("type"))))))
30+
.bind("func");
31+
32+
Finder->addMatcher(returnStmt(hasReturnValue(DRef), hasAncestor(Func)), this);
33+
Finder->addMatcher(conditionalOperator(eachOf(hasTrueExpression(DRef),
34+
hasFalseExpression(DRef)),
35+
hasAncestor(Func)),
36+
this);
3237
}
3338

3439
static bool isSameTypeIgnoringConst(QualType A, QualType B) {
@@ -85,8 +90,8 @@ void ReturnConstRefFromParameterCheck::check(
8590
const MatchFinder::MatchResult &Result) {
8691
const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
8792
const auto *PD = Result.Nodes.getNodeAs<ParmVarDecl>("param");
88-
const auto *R = Result.Nodes.getNodeAs<ReturnStmt>("ret");
89-
const SourceRange Range = R->getRetValue()->getSourceRange();
93+
const auto *DRef = Result.Nodes.getNodeAs<DeclRefExpr>("dref");
94+
const SourceRange Range = DRef->getSourceRange();
9095
if (Range.isInvalid())
9196
return;
9297

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ Changes in existing checks
108108
<clang-tidy/checks/bugprone/casting-through-void>` check to suggest replacing
109109
the offending code with ``reinterpret_cast``, to more clearly express intent.
110110

111+
- Improved :doc:`bugprone-return-const-ref-from-parameter
112+
<clang-tidy/checks/bugprone/return-const-ref-from-parameter>` check to
113+
diagnose potential dangling references when returning a ``const &`` parameter
114+
by using the conditional operator ``cond ? var1 : var2``.
115+
116+
111117
- Improved :doc:`modernize-use-std-format
112118
<clang-tidy/checks/modernize/use-std-format>` check to support replacing
113119
member function calls too.

clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ int const &f3(TConstRef a) { return a; }
2727
int const &f4(TConst &a) { return a; }
2828
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter
2929

30+
int const &f5(TConst &a) { return true ? a : a; }
31+
// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: returning a constant reference parameter
32+
// CHECK-MESSAGES: :[[@LINE-2]]:46: warning: returning a constant reference parameter
33+
3034
template <typename T>
3135
const T& tf1(const T &a) { return a; }
3236
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter
@@ -47,6 +51,11 @@ template <typename T>
4751
const T& itf4(typename ConstRef<T>::type a) { return a; }
4852
// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter
4953

54+
template <typename T>
55+
const T& itf5(const T &a) { return true ? a : a; }
56+
// CHECK-MESSAGES: :[[@LINE-1]]:43: warning: returning a constant reference parameter
57+
// CHECK-MESSAGES: :[[@LINE-2]]:47: warning: returning a constant reference parameter
58+
5059
void instantiate(const int &param, const float &paramf, int &mut_param, float &mut_paramf) {
5160
itf1(0);
5261
itf1(param);

0 commit comments

Comments
 (0)