@@ -31,19 +31,25 @@ void MinMaxUseInitializerListCheck::registerMatchers(MatchFinder *Finder) {
31
31
Finder->addMatcher (
32
32
callExpr (
33
33
callee (functionDecl (hasName (" ::std::max" ))),
34
- hasAnyArgument (callExpr (callee (functionDecl (hasName (" ::std::max" ))))),
34
+ anyOf (hasArgument (
35
+ 0 , callExpr (callee (functionDecl (hasName (" ::std::max" ))))),
36
+ hasArgument (
37
+ 1 , callExpr (callee (functionDecl (hasName (" ::std::max" )))))),
35
38
unless (
36
39
hasParent (callExpr (callee (functionDecl (hasName (" ::std::max" )))))))
37
- .bind (" maxCall " ),
40
+ .bind (" topCall " ),
38
41
this );
39
42
40
43
Finder->addMatcher (
41
44
callExpr (
42
45
callee (functionDecl (hasName (" ::std::min" ))),
43
- hasAnyArgument (callExpr (callee (functionDecl (hasName (" ::std::min" ))))),
46
+ anyOf (hasArgument (
47
+ 0 , callExpr (callee (functionDecl (hasName (" ::std::min" ))))),
48
+ hasArgument (
49
+ 1 , callExpr (callee (functionDecl (hasName (" ::std::min" )))))),
44
50
unless (
45
51
hasParent (callExpr (callee (functionDecl (hasName (" ::std::min" )))))))
46
- .bind (" minCall " ),
52
+ .bind (" topCall " ),
47
53
this );
48
54
}
49
55
@@ -53,29 +59,112 @@ void MinMaxUseInitializerListCheck::registerPPCallbacks(
53
59
}
54
60
55
61
void MinMaxUseInitializerListCheck::check (
56
- const MatchFinder::MatchResult &Result) {
57
- const auto *MaxCall = Result.Nodes .getNodeAs <CallExpr>(" maxCall" );
58
- const auto *MinCall = Result.Nodes .getNodeAs <CallExpr>(" minCall" );
62
+ const MatchFinder::MatchResult &Match) {
63
+ const CallExpr *TopCall = Match.Nodes .getNodeAs <CallExpr>(" topCall" );
64
+ MinMaxUseInitializerListCheck::FindArgsResult Result =
65
+ findArgs (Match, TopCall);
59
66
60
- const CallExpr *TopCall = MaxCall ? MaxCall : MinCall;
61
- if (!TopCall) {
67
+ if (!Result.First || !Result.Last || Result.Args .size () <= 2 ) {
62
68
return ;
63
69
}
64
- const QualType ResultType =
65
- TopCall->getDirectCallee ()->getReturnType ().getNonReferenceType ();
66
70
67
- const Expr *FirstArg = nullptr ;
68
- const Expr *LastArg = nullptr ;
69
- std::vector<const Expr *> Args;
70
- findArgs (TopCall, &FirstArg, &LastArg, Args);
71
+ std::string ReplacementText = generateReplacement (Match, TopCall, Result);
71
72
72
- if (!FirstArg || !LastArg || Args.size () <= 2 ) {
73
- return ;
73
+ diag (TopCall->getBeginLoc (),
74
+ " do not use nested std::%0 calls, use %1 instead" )
75
+ << TopCall->getDirectCallee ()->getName () << ReplacementText
76
+ << FixItHint::CreateReplacement (
77
+ CharSourceRange::getTokenRange (TopCall->getBeginLoc (),
78
+ TopCall->getEndLoc ()),
79
+ ReplacementText)
80
+ << Inserter.createMainFileIncludeInsertion (" <algorithm>" );
81
+ }
82
+
83
+ MinMaxUseInitializerListCheck::FindArgsResult
84
+ MinMaxUseInitializerListCheck::findArgs (const MatchFinder::MatchResult &Match,
85
+ const CallExpr *Call) {
86
+ FindArgsResult Result;
87
+ Result.First = nullptr ;
88
+ Result.Last = nullptr ;
89
+ Result.Compare = nullptr ;
90
+
91
+ if (Call->getNumArgs () > 2 ) {
92
+ auto argIterator = Call->arguments ().begin ();
93
+ std::advance (argIterator, 2 );
94
+ Result.Compare = *argIterator;
74
95
}
75
96
76
- std::string ReplacementText = " {" ;
77
- for (const Expr *Arg : Args) {
97
+ for (const Expr *Arg : Call->arguments ()) {
98
+ if (!Result.First )
99
+ Result.First = Arg;
100
+
101
+ const CallExpr *InnerCall = dyn_cast<CallExpr>(Arg);
102
+ if (InnerCall && InnerCall->getDirectCallee () &&
103
+ InnerCall->getDirectCallee ()->getNameAsString () ==
104
+ Call->getDirectCallee ()->getNameAsString ()) {
105
+ FindArgsResult InnerResult = findArgs (Match, InnerCall);
106
+
107
+ bool processInnerResult = false ;
108
+
109
+ if (!Result.Compare && !InnerResult.Compare )
110
+ processInnerResult = true ;
111
+ else if (Result.Compare && InnerResult.Compare &&
112
+ Lexer::getSourceText (CharSourceRange::getTokenRange (
113
+ Result.Compare ->getSourceRange ()),
114
+ *Match.SourceManager ,
115
+ Match.Context ->getLangOpts ()) ==
116
+ Lexer::getSourceText (
117
+ CharSourceRange::getTokenRange (
118
+ InnerResult.Compare ->getSourceRange ()),
119
+ *Match.SourceManager , Match.Context ->getLangOpts ()))
120
+ processInnerResult = true ;
121
+
122
+ if (processInnerResult) {
123
+ Result.Args .insert (Result.Args .end (), InnerResult.Args .begin (),
124
+ InnerResult.Args .end ());
125
+ continue ;
126
+ }
127
+ }
128
+
129
+ if (Arg == Result.Compare )
130
+ continue ;
131
+
132
+ Result.Args .push_back (Arg);
133
+ Result.Last = Arg;
134
+ }
135
+
136
+ return Result;
137
+ }
138
+
139
+ std::string MinMaxUseInitializerListCheck::generateReplacement (
140
+ const MatchFinder::MatchResult &Match, const CallExpr *TopCall,
141
+ const FindArgsResult Result) {
142
+ std::string ReplacementText =
143
+ Lexer::getSourceText (
144
+ CharSourceRange::getTokenRange (
145
+ TopCall->getBeginLoc (),
146
+ Result.First ->getBeginLoc ().getLocWithOffset (-1 )),
147
+ *Match.SourceManager , Match.Context ->getLangOpts ())
148
+ .str () +
149
+ " {" ;
150
+ const QualType ResultType =
151
+ TopCall->getDirectCallee ()->getReturnType ().getNonReferenceType ();
152
+
153
+ for (const Expr *Arg : Result.Args ) {
78
154
QualType ArgType = Arg->getType ();
155
+
156
+ // check if expression is std::min or std::max
157
+ if (const auto *InnerCall = dyn_cast<CallExpr>(Arg)) {
158
+ if (InnerCall->getDirectCallee () &&
159
+ InnerCall->getDirectCallee ()->getNameAsString () !=
160
+ TopCall->getDirectCallee ()->getNameAsString ()) {
161
+ FindArgsResult innerResult = findArgs (Match, InnerCall);
162
+ ReplacementText += generateReplacement (Match, InnerCall, innerResult) +=
163
+ " })" ;
164
+ continue ;
165
+ }
166
+ }
167
+
79
168
bool CastNeeded =
80
169
ArgType.getCanonicalType () != ResultType.getCanonicalType ();
81
170
@@ -84,55 +173,22 @@ void MinMaxUseInitializerListCheck::check(
84
173
85
174
ReplacementText += Lexer::getSourceText (
86
175
CharSourceRange::getTokenRange (Arg->getSourceRange ()),
87
- *Result .SourceManager , Result .Context ->getLangOpts ());
176
+ *Match .SourceManager , Match .Context ->getLangOpts ());
88
177
89
178
if (CastNeeded)
90
179
ReplacementText += " )" ;
91
180
ReplacementText += " , " ;
92
181
}
93
182
ReplacementText = ReplacementText.substr (0 , ReplacementText.size () - 2 ) + " }" ;
94
-
95
- diag (TopCall->getBeginLoc (),
96
- " do not use nested std::%0 calls, use %1 instead" )
97
- << TopCall->getDirectCallee ()->getName () << ReplacementText
98
- << FixItHint::CreateReplacement (
99
- CharSourceRange::getTokenRange (
100
- FirstArg->getBeginLoc (),
101
- Lexer::getLocForEndOfToken (TopCall->getEndLoc (), 0 ,
102
- Result.Context ->getSourceManager (),
103
- Result.Context ->getLangOpts ())
104
- .getLocWithOffset (-2 )),
105
- ReplacementText)
106
- << Inserter.createMainFileIncludeInsertion (" <algorithm>" );
107
- }
108
-
109
- void MinMaxUseInitializerListCheck::findArgs (const CallExpr *Call,
110
- const Expr **First,
111
- const Expr **Last,
112
- std::vector<const Expr *> &Args) {
113
- if (!Call) {
114
- return ;
115
- }
116
-
117
- const FunctionDecl *Callee = Call->getDirectCallee ();
118
- if (!Callee) {
119
- return ;
183
+ if (Result.Compare ) {
184
+ ReplacementText += " , " ;
185
+ ReplacementText += Lexer::getSourceText (
186
+ CharSourceRange::getTokenRange (Result.Compare ->getSourceRange ()),
187
+ *Match.SourceManager , Match.Context ->getLangOpts ());
120
188
}
189
+ ReplacementText += " )" ;
121
190
122
- for (const Expr *Arg : Call->arguments ()) {
123
- if (!*First)
124
- *First = Arg;
125
-
126
- const CallExpr *InnerCall = dyn_cast<CallExpr>(Arg);
127
- if (InnerCall && InnerCall->getDirectCallee () &&
128
- InnerCall->getDirectCallee ()->getNameAsString () ==
129
- Call->getDirectCallee ()->getNameAsString ()) {
130
- findArgs (InnerCall, First, Last, Args);
131
- } else
132
- Args.push_back (Arg);
133
-
134
- *Last = Arg;
135
- }
191
+ return ReplacementText;
136
192
}
137
193
138
194
} // namespace clang::tidy::modernize
0 commit comments