7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " LostStdMoveCheck.h"
10
- #include " ../utils/DeclRefExprUtils.h"
11
10
#include " clang/ASTMatchers/ASTMatchFinder.h"
12
11
#include " clang/Lex/Lexer.h"
13
12
14
13
using namespace clang ::ast_matchers;
15
14
16
15
namespace clang ::tidy::performance {
17
16
18
- using utils::decl_ref_expr::allDeclRefExprs;
17
+ template <typename Node>
18
+ void extractNodesByIdTo (ArrayRef<BoundNodes> Matches, StringRef ID,
19
+ llvm::SmallPtrSet<const Node*, 16 >& Nodes) {
20
+ for (const BoundNodes& Match : Matches)
21
+ Nodes.insert (Match.getNodeAs <Node>(ID));
22
+ }
23
+
24
+ llvm::SmallPtrSet<const DeclRefExpr*, 16 > allDeclRefExprsHonourLambda (
25
+ const VarDecl& VarDecl, const Decl& Decl, ASTContext& Context) {
26
+ auto Matches = match (
27
+ decl (forEachDescendant (
28
+ declRefExpr (to (varDecl (equalsNode (&VarDecl))),
29
+
30
+ unless (hasAncestor (lambdaExpr (hasAnyCapture (lambdaCapture (
31
+ capturesVar (varDecl (equalsNode (&VarDecl))))))))
32
+
33
+ )
34
+ .bind (" declRef" ))),
35
+ Decl, Context);
36
+ llvm::SmallPtrSet<const DeclRefExpr*, 16 > DeclRefs;
37
+ extractNodesByIdTo (Matches, " declRef" , DeclRefs);
38
+ return DeclRefs;
39
+ }
19
40
20
41
static const Expr* getLastVarUsage (const VarDecl& Var, const Decl& Func,
21
42
ASTContext& Context) {
22
- auto Exprs = allDeclRefExprs (Var, Func, Context);
43
+ auto Exprs = allDeclRefExprsHonourLambda (Var, Func, Context);
23
44
24
45
const Expr* LastExpr = nullptr ;
25
46
for (const clang::DeclRefExpr* Expr : Exprs) {
@@ -36,17 +57,16 @@ AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) {
36
57
}
37
58
38
59
void LostStdMoveCheck::registerMatchers (MatchFinder* Finder) {
39
- auto returnParent =
60
+ auto ReturnParent =
40
61
hasParent (expr (hasParent (cxxConstructExpr (hasParent (returnStmt ())))));
41
62
42
- auto outermostExpr = expr (unless (hasParent (expr ())));
43
- auto leafStatement =
44
- stmt (outermostExpr, unless (hasDescendant (outermostExpr)));
63
+ auto OutermostExpr = expr (unless (hasParent (expr ())));
64
+ auto LeafStatement = stmt (OutermostExpr);
45
65
46
66
Finder->addMatcher (
47
67
declRefExpr (
48
68
// not "return x;"
49
- unless (returnParent ),
69
+ unless (ReturnParent ),
50
70
51
71
unless (hasType (namedDecl (hasName (" ::std::string_view" )))),
52
72
@@ -58,14 +78,17 @@ void LostStdMoveCheck::registerMatchers(MatchFinder* Finder) {
58
78
hasDeclaration (cxxRecordDecl (hasTrivialMoveConstructor ()))))),
59
79
60
80
// Not in a cycle
61
- unless (hasAncestor (forStmt ())), unless (hasAncestor (doStmt ())),
81
+ unless (hasAncestor (forStmt ())),
82
+
83
+ unless (hasAncestor (doStmt ())),
84
+
62
85
unless (hasAncestor (whileStmt ())),
63
86
64
87
// only non-X&
65
88
unless (hasDeclaration (
66
89
varDecl (hasType (qualType (lValueReferenceType ()))))),
67
90
68
- hasAncestor (leafStatement .bind (" leaf_statement" )),
91
+ hasAncestor (LeafStatement .bind (" leaf_statement" )),
69
92
70
93
hasDeclaration (
71
94
varDecl (hasAncestor (functionDecl ().bind (" func" ))).bind (" decl" )),
@@ -86,13 +109,6 @@ void LostStdMoveCheck::registerMatchers(MatchFinder* Finder) {
86
109
this );
87
110
}
88
111
89
- template <typename Node>
90
- void extractNodesByIdTo (ArrayRef<BoundNodes> Matches, StringRef ID,
91
- llvm::SmallPtrSet<const Node*, 16 >& Nodes) {
92
- for (const BoundNodes& Match : Matches)
93
- Nodes.insert (Match.getNodeAs <Node>(ID));
94
- }
95
-
96
112
void LostStdMoveCheck::check (const MatchFinder::MatchResult& Result) {
97
113
const auto * MatchedDecl = Result.Nodes .getNodeAs <VarDecl>(" decl" );
98
114
const auto * MatchedFunc = Result.Nodes .getNodeAs <FunctionDecl>(" func" );
@@ -101,21 +117,35 @@ void LostStdMoveCheck::check(const MatchFinder::MatchResult& Result) {
101
117
const auto * MatchedLeafStatement =
102
118
Result.Nodes .getNodeAs <Stmt>(" leaf_statement" );
103
119
104
- if (MatchedUseCall) return ;
120
+ if (MatchedUseCall) {
121
+ return ;
122
+ }
105
123
106
124
const Expr* LastUsage =
107
125
getLastVarUsage (*MatchedDecl, *MatchedFunc, *Result.Context );
108
- if (LastUsage == nullptr ) return ;
109
126
110
- if (LastUsage->getBeginLoc () > MatchedUse->getBeginLoc ()) {
127
+ if (LastUsage && LastUsage ->getBeginLoc () > MatchedUse->getBeginLoc ()) {
111
128
// "use" is not the last reference to x
112
129
return ;
113
130
}
114
131
132
+ if (LastUsage &&
133
+ LastUsage->getSourceRange () != MatchedUse->getSourceRange ()) {
134
+ return ;
135
+ }
136
+
115
137
// Calculate X usage count in the statement
116
138
llvm::SmallPtrSet<const DeclRefExpr*, 16 > DeclRefs;
117
139
ArrayRef<BoundNodes> Matches = match (
118
- findAll (declRefExpr (to (varDecl (equalsNode (MatchedDecl)))).bind (" ref" )),
140
+ findAll (declRefExpr (
141
+
142
+ to (varDecl (equalsNode (MatchedDecl))),
143
+
144
+ unless (hasAncestor (lambdaExpr (hasAnyCapture (lambdaCapture (
145
+ capturesVar (varDecl (equalsNode (MatchedDecl))))))))
146
+
147
+ )
148
+ .bind (" ref" )),
119
149
*MatchedLeafStatement, *Result.Context );
120
150
extractNodesByIdTo (Matches, " ref" , DeclRefs);
121
151
if (DeclRefs.size () > 1 ) {
@@ -125,12 +155,21 @@ void LostStdMoveCheck::check(const MatchFinder::MatchResult& Result) {
125
155
126
156
const SourceManager& Source = Result.Context ->getSourceManager ();
127
157
const auto Range =
128
- CharSourceRange::getTokenRange (LastUsage ->getSourceRange ());
158
+ CharSourceRange::getTokenRange (MatchedUse ->getSourceRange ());
129
159
const StringRef NeedleExprCode =
130
160
Lexer::getSourceText (Range, Source, Result.Context ->getLangOpts ());
131
- diag (LastUsage->getBeginLoc (), " could be std::move()" )
132
- << FixItHint::CreateReplacement (
133
- Range, (" std::move(" + NeedleExprCode + " )" ).str ());
161
+
162
+ if (NeedleExprCode == " =" ) {
163
+
164
+ diag (MatchedUse->getBeginLoc (), " could be std::move()" )
165
+ << FixItHint::CreateInsertion (
166
+ MatchedUse->getBeginLoc (),
167
+ (" std::move(" + MatchedDecl->getName () + " )," ).str ());
168
+ } else {
169
+ diag (MatchedUse->getBeginLoc (), " could be std::move()" )
170
+ << FixItHint::CreateReplacement (
171
+ Range, (" std::move(" + NeedleExprCode + " )" ).str ());
172
+ }
134
173
}
135
174
136
175
} // namespace clang::tidy::performance
0 commit comments