Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp

Issue 488933002: Add handling for logging and gtest comparison macros. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments and exclusions Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/clang/rewrite_scoped_refptr/tests/gtest-expected.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // This implements a Clang tool to rewrite all instances of 5 // This implements a Clang tool to rewrite all instances of
6 // scoped_refptr<T>'s implicit cast to T (operator T*) to an explicit call to 6 // scoped_refptr<T>'s implicit cast to T (operator T*) to an explicit call to
7 // the .get() method. 7 // the .get() method.
8 8
9 #include <assert.h>
9 #include <algorithm> 10 #include <algorithm>
10 #include <memory> 11 #include <memory>
11 #include <string> 12 #include <string>
12 13
13 #include "clang/AST/ASTContext.h" 14 #include "clang/AST/ASTContext.h"
14 #include "clang/ASTMatchers/ASTMatchers.h" 15 #include "clang/ASTMatchers/ASTMatchers.h"
15 #include "clang/ASTMatchers/ASTMatchersMacros.h" 16 #include "clang/ASTMatchers/ASTMatchersMacros.h"
16 #include "clang/ASTMatchers/ASTMatchFinder.h" 17 #include "clang/ASTMatchers/ASTMatchFinder.h"
17 #include "clang/Basic/SourceManager.h" 18 #include "clang/Basic/SourceManager.h"
18 #include "clang/Frontend/FrontendActions.h" 19 #include "clang/Frontend/FrontendActions.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 // Calls to an overloaded operator also need parens, except for foo(...) and 55 // Calls to an overloaded operator also need parens, except for foo(...) and
55 // foo[...] expressions. 56 // foo[...] expressions.
56 if (const clang::CXXOperatorCallExpr* op = 57 if (const clang::CXXOperatorCallExpr* op =
57 llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) { 58 llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
58 return op->getOperator() != clang::OO_Call && 59 return op->getOperator() != clang::OO_Call &&
59 op->getOperator() != clang::OO_Subscript; 60 op->getOperator() != clang::OO_Subscript;
60 } 61 }
61 return false; 62 return false;
62 } 63 }
63 64
64 Replacement RewriteRawPtrToScopedRefptr(const MatchFinder::MatchResult& result, 65 Replacement RewriteImplicitToExplicitConversion(
65 clang::SourceLocation begin, 66 const MatchFinder::MatchResult& result,
66 clang::SourceLocation end) { 67 const clang::Expr* expr) {
67 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange( 68 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
68 result.SourceManager->getSpellingLoc(begin), 69 result.SourceManager->getSpellingLoc(expr->getLocStart()),
69 result.SourceManager->getSpellingLoc(end)); 70 result.SourceManager->getSpellingLoc(expr->getLocEnd()));
70 71 assert(range.isValid() && "Invalid range!");
dcheng 2014/08/20 07:02:30 This is apparently LLVM style.
71 std::string text = clang::Lexer::getSourceText(
72 range, *result.SourceManager, result.Context->getLangOpts());
73 text.erase(text.rfind('*'));
74
75 std::string replacement_text("scoped_refptr<");
76 replacement_text += text;
77 replacement_text += ">";
78
79 return Replacement(*result.SourceManager, range, replacement_text);
80 }
81
82 class GetRewriterCallback : public MatchFinder::MatchCallback {
83 public:
84 explicit GetRewriterCallback(Replacements* replacements)
85 : replacements_(replacements) {}
86 virtual void run(const MatchFinder::MatchResult& result) override;
87
88 private:
89 Replacements* const replacements_;
90 };
91
92 void GetRewriterCallback::run(const MatchFinder::MatchResult& result) {
93 const clang::CXXMemberCallExpr* const implicit_call =
94 result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("call");
95 const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
96
97 if (!implicit_call || !arg)
98 return;
99
100 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
101 result.SourceManager->getSpellingLoc(arg->getLocStart()),
102 result.SourceManager->getSpellingLoc(arg->getLocEnd()));
103 if (!range.isValid())
104 return; // TODO(rsleevi): Log an error?
105 72
106 // Handle cases where an implicit cast is being done by dereferencing a 73 // Handle cases where an implicit cast is being done by dereferencing a
107 // pointer to a scoped_refptr<> (sadly, it happens...) 74 // pointer to a scoped_refptr<> (sadly, it happens...)
108 // 75 //
109 // This rewrites both "*foo" and "*(foo)" as "foo->get()". 76 // This rewrites both "*foo" and "*(foo)" as "foo->get()".
110 if (const clang::UnaryOperator* op = 77 if (const clang::UnaryOperator* op =
111 llvm::dyn_cast<clang::UnaryOperator>(arg)) { 78 llvm::dyn_cast<clang::UnaryOperator>(expr)) {
112 if (op->getOpcode() == clang::UO_Deref) { 79 if (op->getOpcode() == clang::UO_Deref) {
113 const clang::Expr* const sub_expr = 80 const clang::Expr* const sub_expr =
114 op->getSubExpr()->IgnoreParenImpCasts(); 81 op->getSubExpr()->IgnoreParenImpCasts();
115 clang::CharSourceRange sub_expr_range = 82 clang::CharSourceRange sub_expr_range =
116 clang::CharSourceRange::getTokenRange( 83 clang::CharSourceRange::getTokenRange(
117 result.SourceManager->getSpellingLoc(sub_expr->getLocStart()), 84 result.SourceManager->getSpellingLoc(sub_expr->getLocStart()),
118 result.SourceManager->getSpellingLoc(sub_expr->getLocEnd())); 85 result.SourceManager->getSpellingLoc(sub_expr->getLocEnd()));
119 if (!sub_expr_range.isValid()) 86 assert(sub_expr_range.isValid() && "Invalid subexpression range!");
120 return; // TODO(rsleevi): Log an error? 87
121 std::string inner_text = clang::Lexer::getSourceText( 88 std::string inner_text = clang::Lexer::getSourceText(
122 sub_expr_range, *result.SourceManager, result.Context->getLangOpts()); 89 sub_expr_range, *result.SourceManager, result.Context->getLangOpts());
123 if (inner_text.empty()) 90 assert(!inner_text.empty() && "No text for subexpression!");
124 return; // TODO(rsleevi): Log an error?
125
126 if (NeedsParens(sub_expr)) { 91 if (NeedsParens(sub_expr)) {
127 inner_text.insert(0, "("); 92 inner_text.insert(0, "(");
128 inner_text.append(")"); 93 inner_text.append(")");
129 } 94 }
130 inner_text.append("->get()"); 95 inner_text.append("->get()");
131 replacements_->insert( 96 return Replacement(*result.SourceManager, range, inner_text);
132 Replacement(*result.SourceManager, range, inner_text));
133 return;
134 } 97 }
135 } 98 }
136 99
137 std::string text = clang::Lexer::getSourceText( 100 std::string text = clang::Lexer::getSourceText(
138 range, *result.SourceManager, result.Context->getLangOpts()); 101 range, *result.SourceManager, result.Context->getLangOpts());
139 if (text.empty()) 102 assert(!text.empty() && "No text for expression!");
140 return; // TODO(rsleevi): Log an error?
141 103
142 // Unwrap any temporaries - for example, custom iterators that return 104 // Unwrap any temporaries - for example, custom iterators that return
143 // scoped_refptr<T> as part of operator*. Any such iterators should also 105 // scoped_refptr<T> as part of operator*. Any such iterators should also
144 // be declaring a scoped_refptr<T>* operator->, per C++03 24.4.1.1 (Table 72) 106 // be declaring a scoped_refptr<T>* operator->, per C++03 24.4.1.1 (Table 72)
145 if (const clang::CXXBindTemporaryExpr* op = 107 if (const clang::CXXBindTemporaryExpr* op =
146 llvm::dyn_cast<clang::CXXBindTemporaryExpr>(arg)) { 108 llvm::dyn_cast<clang::CXXBindTemporaryExpr>(expr)) {
147 arg = op->getSubExpr(); 109 expr = op->getSubExpr();
148 } 110 }
149 111
150 // Handle iterators (which are operator* calls, followed by implicit 112 // Handle iterators (which are operator* calls, followed by implicit
151 // conversions) by rewriting *it as it->get() 113 // conversions) by rewriting *it as it->get()
152 if (const clang::CXXOperatorCallExpr* op = 114 if (const clang::CXXOperatorCallExpr* op =
153 llvm::dyn_cast<clang::CXXOperatorCallExpr>(arg)) { 115 llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
154 if (op->getOperator() == clang::OO_Star) { 116 if (op->getOperator() == clang::OO_Star) {
155 // Note that this doesn't rewrite **it correctly, since it should be 117 // Note that this doesn't rewrite **it correctly, since it should be
156 // rewritten using parens, e.g. (*it)->get(). However, this shouldn't 118 // rewritten using parens, e.g. (*it)->get(). However, this shouldn't
157 // happen frequently, if at all, since it would likely indicate code is 119 // happen frequently, if at all, since it would likely indicate code is
158 // storing pointers to a scoped_refptr in a container. 120 // storing pointers to a scoped_refptr in a container.
159 text.erase(0, 1); 121 text.erase(0, 1);
160 text.append("->get()"); 122 text.append("->get()");
161 replacements_->insert(Replacement(*result.SourceManager, range, text)); 123 return Replacement(*result.SourceManager, range, text);
162 return;
163 } 124 }
164 } 125 }
165 126
166 // The only remaining calls should be non-dereferencing calls (eg: member 127 // The only remaining calls should be non-dereferencing calls (eg: member
167 // calls), so a simple ".get()" appending should suffice. 128 // calls), so a simple ".get()" appending should suffice.
168 if (NeedsParens(arg)) { 129 if (NeedsParens(expr)) {
169 text.insert(0, "("); 130 text.insert(0, "(");
170 text.append(")"); 131 text.append(")");
171 } 132 }
172 text.append(".get()"); 133 text.append(".get()");
173 replacements_->insert(Replacement(*result.SourceManager, range, text)); 134 return Replacement(*result.SourceManager, range, text);
135 }
136
137 Replacement RewriteRawPtrToScopedRefptr(const MatchFinder::MatchResult& result,
dcheng 2014/08/20 07:02:30 This is just a move of the original code, re-addin
138 clang::SourceLocation begin,
139 clang::SourceLocation end) {
140 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
141 result.SourceManager->getSpellingLoc(begin),
142 result.SourceManager->getSpellingLoc(end));
143 assert(range.isValid() && "Invalid range!");
144
145 std::string text = clang::Lexer::getSourceText(
146 range, *result.SourceManager, result.Context->getLangOpts());
147 text.erase(text.rfind('*'));
148
149 std::string replacement_text("scoped_refptr<");
150 replacement_text += text;
151 replacement_text += ">";
152
153 return Replacement(*result.SourceManager, range, replacement_text);
154 }
155
156 class GetRewriterCallback : public MatchFinder::MatchCallback {
157 public:
158 explicit GetRewriterCallback(Replacements* replacements)
159 : replacements_(replacements) {}
160 virtual void run(const MatchFinder::MatchResult& result) override;
161
162 private:
163 Replacements* const replacements_;
164 };
165
166 void GetRewriterCallback::run(const MatchFinder::MatchResult& result) {
167 const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
168 assert(arg && "Unexpected match! No Expr captured!");
169 replacements_->insert(RewriteImplicitToExplicitConversion(result, arg));
174 } 170 }
175 171
176 class VarRewriterCallback : public MatchFinder::MatchCallback { 172 class VarRewriterCallback : public MatchFinder::MatchCallback {
177 public: 173 public:
178 explicit VarRewriterCallback(Replacements* replacements) 174 explicit VarRewriterCallback(Replacements* replacements)
179 : replacements_(replacements) {} 175 : replacements_(replacements) {}
180 virtual void run(const MatchFinder::MatchResult& result) override; 176 virtual void run(const MatchFinder::MatchResult& result) override;
181 177
182 private: 178 private:
183 Replacements* const replacements_; 179 Replacements* const replacements_;
184 }; 180 };
185 181
186 void VarRewriterCallback::run(const MatchFinder::MatchResult& result) { 182 void VarRewriterCallback::run(const MatchFinder::MatchResult& result) {
187 const clang::DeclaratorDecl* const var_decl = 183 const clang::DeclaratorDecl* const var_decl =
188 result.Nodes.getNodeAs<clang::DeclaratorDecl>("var"); 184 result.Nodes.getNodeAs<clang::DeclaratorDecl>("var");
189 185 assert(var_decl && "Unexpected match! No VarDecl captured!");
190 if (!var_decl)
191 return;
192 186
193 const clang::TypeSourceInfo* tsi = var_decl->getTypeSourceInfo(); 187 const clang::TypeSourceInfo* tsi = var_decl->getTypeSourceInfo();
194 188
195 // TODO(dcheng): This mishandles a case where a variable has multiple 189 // TODO(dcheng): This mishandles a case where a variable has multiple
196 // declarations, e.g.: 190 // declarations, e.g.:
197 // 191 //
198 // in .h: 192 // in .h:
199 // Foo* my_global_magical_foo; 193 // Foo* my_global_magical_foo;
200 // 194 //
201 // in .cc: 195 // in .cc:
(...skipping 12 matching lines...) Expand all
214 : replacements_(replacements) {} 208 : replacements_(replacements) {}
215 virtual void run(const MatchFinder::MatchResult& result) override; 209 virtual void run(const MatchFinder::MatchResult& result) override;
216 210
217 private: 211 private:
218 Replacements* const replacements_; 212 Replacements* const replacements_;
219 }; 213 };
220 214
221 void FunctionRewriterCallback::run(const MatchFinder::MatchResult& result) { 215 void FunctionRewriterCallback::run(const MatchFinder::MatchResult& result) {
222 const clang::FunctionDecl* const function_decl = 216 const clang::FunctionDecl* const function_decl =
223 result.Nodes.getNodeAs<clang::FunctionDecl>("fn"); 217 result.Nodes.getNodeAs<clang::FunctionDecl>("fn");
224 218 assert(function_decl && "Unexpected match! No FunctionDecl captured!");
225 if (!function_decl)
226 return;
227 219
228 // If matched against an implicit conversion to a DeclRefExpr, make sure the 220 // If matched against an implicit conversion to a DeclRefExpr, make sure the
229 // referenced declaration is of class type, e.g. the tool skips trying to 221 // referenced declaration is of class type, e.g. the tool skips trying to
230 // chase pointers/references to determine if the pointee is a scoped_refptr<T> 222 // chase pointers/references to determine if the pointee is a scoped_refptr<T>
231 // with local storage. Instead, let a human manually handle those cases. 223 // with local storage. Instead, let a human manually handle those cases.
232 const clang::VarDecl* const var_decl = 224 const clang::VarDecl* const var_decl =
233 result.Nodes.getNodeAs<clang::VarDecl>("var"); 225 result.Nodes.getNodeAs<clang::VarDecl>("var");
234 if (var_decl && !var_decl->getTypeSourceInfo()->getType()->isClassType()) { 226 if (var_decl && !var_decl->getTypeSourceInfo()->getType()->isClassType()) {
235 return; 227 return;
236 } 228 }
237 229
238 for (clang::FunctionDecl* f : function_decl->redecls()) { 230 for (clang::FunctionDecl* f : function_decl->redecls()) {
239 clang::SourceRange range = f->getReturnTypeSourceRange(); 231 clang::SourceRange range = f->getReturnTypeSourceRange();
240 replacements_->insert( 232 replacements_->insert(
241 RewriteRawPtrToScopedRefptr(result, range.getBegin(), range.getEnd())); 233 RewriteRawPtrToScopedRefptr(result, range.getBegin(), range.getEnd()));
242 } 234 }
243 } 235 }
244 236
237 class MacroRewriterCallback : public MatchFinder::MatchCallback {
238 public:
239 explicit MacroRewriterCallback(Replacements* replacements)
240 : replacements_(replacements) {}
241 virtual void run(const MatchFinder::MatchResult& result) override;
242
243 private:
244 Replacements* const replacements_;
245 };
246
247 void MacroRewriterCallback::run(const MatchFinder::MatchResult& result) {
248 const clang::Expr* const expr = result.Nodes.getNodeAs<clang::Expr>("expr");
249 assert(expr && "Unexpected match! No Expr captured!");
250 replacements_->insert(RewriteImplicitToExplicitConversion(result, expr));
251 }
252
245 } // namespace 253 } // namespace
246 254
247 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); 255 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
248 256
249 int main(int argc, const char* argv[]) { 257 int main(int argc, const char* argv[]) {
250 llvm::cl::OptionCategory category("Remove scoped_refptr conversions"); 258 llvm::cl::OptionCategory category("Remove scoped_refptr conversions");
251 CommonOptionsParser options(argc, argv, category); 259 CommonOptionsParser options(argc, argv, category);
252 clang::tooling::ClangTool tool(options.getCompilations(), 260 clang::tooling::ClangTool tool(options.getCompilations(),
253 options.getSourcePathList()); 261 options.getSourcePathList());
254 262
255 MatchFinder match_finder; 263 MatchFinder match_finder;
256 Replacements replacements; 264 Replacements replacements;
257 265
266 auto is_scoped_refptr = recordDecl(isSameOrDerivedFrom("::scoped_refptr"),
267 isTemplateInstantiation());
268
258 // Finds all calls to conversion operator member function. This catches calls 269 // Finds all calls to conversion operator member function. This catches calls
259 // to "operator T*", "operator Testable", and "operator bool" equally. 270 // to "operator T*", "operator Testable", and "operator bool" equally.
260 auto base_matcher = 271 auto base_matcher = memberCallExpr(thisPointerType(is_scoped_refptr),
261 id("call", 272 callee(conversionDecl()),
262 memberCallExpr( 273 on(id("arg", expr())));
263 thisPointerType(recordDecl(isSameOrDerivedFrom("::scoped_refptr"),
264 isTemplateInstantiation())),
265 callee(conversionDecl()),
266 on(id("arg", expr()))));
267 274
268 // The heuristic for whether or not converting a temporary is 'unsafe'. An 275 // The heuristic for whether or not converting a temporary is 'unsafe'. An
269 // unsafe conversion is one where a temporary scoped_refptr<T> is converted to 276 // unsafe conversion is one where a temporary scoped_refptr<T> is converted to
270 // another type. The matcher provides an exception for a temporary 277 // another type. The matcher provides an exception for a temporary
271 // scoped_refptr that is the result of an operator call. In this case, assume 278 // scoped_refptr that is the result of an operator call. In this case, assume
272 // that it's the result of an iterator dereference, and the container itself 279 // that it's the result of an iterator dereference, and the container itself
273 // retains the necessary reference, since this is a common idiom to see in 280 // retains the necessary reference, since this is a common idiom to see in
274 // loop bodies. 281 // loop bodies.
275 auto is_unsafe_temporary_conversion = 282 auto is_unsafe_temporary_conversion =
276 on(bindTemporaryExpr(unless(has(operatorCallExpr())))); 283 on(bindTemporaryExpr(unless(has(operatorCallExpr()))));
(...skipping 23 matching lines...) Expand all
300 // standard conversion sequence (C++03 13.3.3.1.1), such as converting a 307 // standard conversion sequence (C++03 13.3.3.1.1), such as converting a
301 // pointer to a bool. 308 // pointer to a bool.
302 auto implicit_to_bool = 309 auto implicit_to_bool =
303 implicitCastExpr(hasImplicitDestinationType(isBoolean())); 310 implicitCastExpr(hasImplicitDestinationType(isBoolean()));
304 311
305 // Avoid converting calls to of "operator Testable" -> "bool" and calls of 312 // Avoid converting calls to of "operator Testable" -> "bool" and calls of
306 // "operator T*" -> "bool". 313 // "operator T*" -> "bool".
307 auto bool_conversion_matcher = hasParent( 314 auto bool_conversion_matcher = hasParent(
308 expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool))))); 315 expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool)))));
309 316
317 auto is_logging_helper =
318 functionDecl(anyOf(hasName("CheckEQImpl"), hasName("CheckNEImpl")));
319 auto is_gtest_helper = functionDecl(
320 anyOf(methodDecl(ofClass(recordDecl(isSameOrDerivedFrom(
321 hasName("::testing::internal::EqHelper")))),
322 hasName("Compare")),
323 hasName("::testing::internal::CmpHelperNE")));
324 auto is_gtest_assertion_result_ctor = constructorDecl(ofClass(
325 recordDecl(isSameOrDerivedFrom(hasName("::testing::AssertionResult")))));
326
310 // Find all calls to an operator overload that are 'safe'. 327 // Find all calls to an operator overload that are 'safe'.
311 // 328 //
312 // All bool conversions will be handled with the Testable trick, but that 329 // All bool conversions will be handled with the Testable trick, but that
313 // can only be used once "operator T*" is removed, since otherwise it leaves 330 // can only be used once "operator T*" is removed, since otherwise it leaves
314 // the call ambiguous. 331 // the call ambiguous.
315 GetRewriterCallback get_callback(&replacements); 332 GetRewriterCallback get_callback(&replacements);
316 match_finder.addMatcher( 333 match_finder.addMatcher(
317 memberCallExpr( 334 memberCallExpr(
318 base_matcher, 335 base_matcher,
319 unless(anyOf(is_unsafe_temporary_conversion, is_unsafe_return))), 336 // Excluded since the conversion may be unsafe.
337 unless(anyOf(is_unsafe_temporary_conversion, is_unsafe_return)),
338 // Excluded since the conversion is deep inside a macro that needs to
339 // be specially handled.
340 unless(hasAncestor(decl(anyOf(is_logging_helper,
341 is_gtest_helper,
342 is_gtest_assertion_result_ctor))))),
320 &get_callback); 343 &get_callback);
321 344
322 // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*. 345 // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*.
323 VarRewriterCallback var_callback(&replacements); 346 VarRewriterCallback var_callback(&replacements);
324 auto initialized_with_temporary = ignoringImpCasts(exprWithCleanups( 347 auto initialized_with_temporary = ignoringImpCasts(exprWithCleanups(
325 has(memberCallExpr(base_matcher, is_unsafe_temporary_conversion)))); 348 has(memberCallExpr(base_matcher, is_unsafe_temporary_conversion))));
326 match_finder.addMatcher(id("var", 349 match_finder.addMatcher(id("var",
327 varDecl(hasInitializer(initialized_with_temporary), 350 varDecl(hasInitializer(initialized_with_temporary),
328 hasType(pointerType()))), 351 hasType(pointerType()))),
329 &var_callback); 352 &var_callback);
330 match_finder.addMatcher( 353 match_finder.addMatcher(
331 constructorDecl(forEachConstructorInitializer( 354 constructorDecl(forEachConstructorInitializer(
332 allOf(withInitializer(initialized_with_temporary), 355 allOf(withInitializer(initialized_with_temporary),
333 forField(id("var", fieldDecl(hasType(pointerType()))))))), 356 forField(id("var", fieldDecl(hasType(pointerType()))))))),
334 &var_callback); 357 &var_callback);
335 358
336 // Rewrite functions that unsafely turn a scoped_refptr<T> into a T* when 359 // Rewrite functions that unsafely turn a scoped_refptr<T> into a T* when
337 // returning a value. 360 // returning a value.
338 FunctionRewriterCallback fn_callback(&replacements); 361 FunctionRewriterCallback fn_callback(&replacements);
339 match_finder.addMatcher(memberCallExpr(base_matcher, is_unsafe_return), 362 match_finder.addMatcher(memberCallExpr(base_matcher, is_unsafe_return),
340 &fn_callback); 363 &fn_callback);
341 364
365 // Rewrite logging / gtest expressions that result in an implicit conversion.
366 // Luckily, the matchers don't need to handle the case where one of the macro
367 // arguments is NULL, such as:
368 // CHECK_EQ(my_scoped_refptr, NULL)
369 // because it simply doesn't compile--since NULL is actually of integral type,
370 // this doesn't trigger scoped_refptr<T>'s implicit conversion. Since there is
371 // no comparison overload for scoped_refptr<T> and int, this fails to compile.
372 MacroRewriterCallback macro_callback(&replacements);
373 // CHECK_EQ/CHECK_NE helpers.
374 match_finder.addMatcher(
375 callExpr(callee(is_logging_helper),
376 argumentCountIs(3),
377 hasAnyArgument(id("expr", expr(hasType(is_scoped_refptr)))),
378 hasAnyArgument(hasType(pointerType())),
379 hasArgument(2, stringLiteral())),
380 &macro_callback);
381 // ASSERT_EQ/ASSERT_NE/EXPECT_EQ/EXPECT_EQ, which use the same underlying
382 // helper functions. Even though gtest has special handling for pointer to
383 // NULL comparisons, it doesn't trigger in this case, so no special handling
384 // is needed for the replacements.
385 match_finder.addMatcher(
386 callExpr(callee(is_gtest_helper),
387 argumentCountIs(4),
388 hasArgument(0, stringLiteral()),
389 hasArgument(1, stringLiteral()),
390 hasAnyArgument(id("expr", expr(hasType(is_scoped_refptr)))),
391 hasAnyArgument(hasType(pointerType()))),
392 &macro_callback);
393 // ASSERT_TRUE/EXPECT_TRUE helpers. Note that this matcher doesn't need to
394 // handle ASSERT_FALSE/EXPECT_FALSE, because it gets coerced to bool before
395 // being passed as an argument to AssertionResult's constructor. As a result,
396 // GetRewriterCallback handles this case properly since the conversion isn't
397 // hidden inside AssertionResult, and the generated replacement properly
398 // rewrites the macro argument.
399 // However, the tool does need to handle the _TRUE counterparts, since the
400 // conversion occurs inside the constructor in those cases.
401 match_finder.addMatcher(
402 constructExpr(
403 argumentCountIs(2),
404 hasArgument(0, id("expr", expr(hasType(is_scoped_refptr)))),
405 hasDeclaration(is_gtest_assertion_result_ctor)),
406 &macro_callback);
407
342 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = 408 std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
343 clang::tooling::newFrontendActionFactory(&match_finder); 409 clang::tooling::newFrontendActionFactory(&match_finder);
344 int result = tool.run(factory.get()); 410 int result = tool.run(factory.get());
345 if (result != 0) 411 if (result != 0)
346 return result; 412 return result;
347 413
348 // Serialization format is documented in tools/clang/scripts/run_tool.py 414 // Serialization format is documented in tools/clang/scripts/run_tool.py
349 llvm::outs() << "==== BEGIN EDITS ====\n"; 415 llvm::outs() << "==== BEGIN EDITS ====\n";
350 for (const auto& r : replacements) { 416 for (const auto& r : replacements) {
351 std::string replacement_text = r.getReplacementText().str(); 417 std::string replacement_text = r.getReplacementText().str();
352 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); 418 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
353 llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":" 419 llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
354 << r.getLength() << ":" << replacement_text << "\n"; 420 << r.getLength() << ":" << replacement_text << "\n";
355 } 421 }
356 llvm::outs() << "==== END EDITS ====\n"; 422 llvm::outs() << "==== END EDITS ====\n";
357 423
358 return 0; 424 return 0;
359 } 425 }
OLDNEW
« no previous file with comments | « no previous file | tools/clang/rewrite_scoped_refptr/tests/gtest-expected.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698