7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " ReturnConstRefFromParameterCheck.h"
10
- #include " ../utils/Matchers.h"
11
10
#include " clang/ASTMatchers/ASTMatchFinder.h"
12
11
#include " clang/ASTMatchers/ASTMatchers.h"
13
12
@@ -18,20 +17,82 @@ namespace clang::tidy::bugprone {
18
17
void ReturnConstRefFromParameterCheck::registerMatchers (MatchFinder *Finder) {
19
18
Finder->addMatcher (
20
19
returnStmt (
21
- hasReturnValue (declRefExpr (to (parmVarDecl (hasType (hasCanonicalType (
22
- qualType (matchers::isReferenceToConst ()).bind (" type" ))))))),
23
- hasAncestor (functionDecl (hasReturnTypeLoc (
24
- loc (qualType (hasCanonicalType (equalsBoundNode (" type" ))))))))
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" )))
25
30
.bind (" ret" ),
26
31
this );
27
32
}
28
33
34
+ static bool isSameTypeIgnoringConst (QualType A, QualType B) {
35
+ return A.getCanonicalType ().withConst () == B.getCanonicalType ().withConst ();
36
+ }
37
+
38
+ static bool isSameTypeIgnoringConstRef (QualType A, QualType B) {
39
+ return isSameTypeIgnoringConst (A.getCanonicalType ().getNonReferenceType (),
40
+ B.getCanonicalType ().getNonReferenceType ());
41
+ }
42
+
43
+ static bool hasSameParameterTypes (const FunctionDecl &FD, const FunctionDecl &O,
44
+ const ParmVarDecl &PD) {
45
+ if (FD.getNumParams () != O.getNumParams ())
46
+ return false ;
47
+ for (unsigned I = 0 , E = FD.getNumParams (); I < E; ++I) {
48
+ const ParmVarDecl *DPD = FD.getParamDecl (I);
49
+ const QualType OPT = O.getParamDecl (I)->getType ();
50
+ if (DPD == &PD) {
51
+ if (!llvm::isa<RValueReferenceType>(OPT) ||
52
+ !isSameTypeIgnoringConstRef (DPD->getType (), OPT))
53
+ return false ;
54
+ } else {
55
+ if (!isSameTypeIgnoringConst (DPD->getType (), OPT))
56
+ return false ;
57
+ }
58
+ }
59
+ return true ;
60
+ }
61
+
62
+ static const Decl *findRVRefOverload (const FunctionDecl &FD,
63
+ const ParmVarDecl &PD) {
64
+ // Actually it would be better to do lookup in caller site.
65
+ // But in most of cases, overloads of LVRef and RVRef will appear together.
66
+ // FIXME:
67
+ // 1. overload in anonymous namespace
68
+ // 2. forward reference
69
+ DeclContext::lookup_result LookupResult =
70
+ FD.getParent ()->lookup (FD.getNameInfo ().getName ());
71
+ if (LookupResult.isSingleResult ()) {
72
+ return nullptr ;
73
+ }
74
+ for (const Decl *Overload : LookupResult) {
75
+ if (Overload == &FD)
76
+ continue ;
77
+ if (const auto *O = dyn_cast<FunctionDecl>(Overload))
78
+ if (hasSameParameterTypes (FD, *O, PD))
79
+ return O;
80
+ }
81
+ return nullptr ;
82
+ }
83
+
29
84
void ReturnConstRefFromParameterCheck::check (
30
85
const MatchFinder::MatchResult &Result) {
86
+ const auto *FD = Result.Nodes .getNodeAs <FunctionDecl>(" func" );
87
+ const auto *PD = Result.Nodes .getNodeAs <ParmVarDecl>(" param" );
31
88
const auto *R = Result.Nodes .getNodeAs <ReturnStmt>(" ret" );
32
89
const SourceRange Range = R->getRetValue ()->getSourceRange ();
33
90
if (Range.isInvalid ())
34
91
return ;
92
+
93
+ if (findRVRefOverload (*FD, *PD) != nullptr )
94
+ return ;
95
+
35
96
diag (Range.getBegin (),
36
97
" returning a constant reference parameter may cause use-after-free "
37
98
" when the parameter is constructed from a temporary" )
0 commit comments