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

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

Issue 1611743002: Fix extra clang tools build. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 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
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 <assert.h>
10 #include <algorithm> 10 #include <algorithm>
11 #include <memory> 11 #include <memory>
12 #include <string> 12 #include <string>
13 13
14 #include "clang/AST/ASTContext.h" 14 #include "clang/AST/ASTContext.h"
15 #include "clang/ASTMatchers/ASTMatchers.h" 15 #include "clang/ASTMatchers/ASTMatchers.h"
16 #include "clang/ASTMatchers/ASTMatchersMacros.h" 16 #include "clang/ASTMatchers/ASTMatchersMacros.h"
17 #include "clang/ASTMatchers/ASTMatchFinder.h" 17 #include "clang/ASTMatchers/ASTMatchFinder.h"
18 #include "clang/Basic/SourceManager.h" 18 #include "clang/Basic/SourceManager.h"
19 #include "clang/Frontend/FrontendActions.h" 19 #include "clang/Frontend/FrontendActions.h"
20 #include "clang/Lex/Lexer.h" 20 #include "clang/Lex/Lexer.h"
21 #include "clang/Tooling/CommonOptionsParser.h" 21 #include "clang/Tooling/CommonOptionsParser.h"
22 #include "clang/Tooling/Refactoring.h" 22 #include "clang/Tooling/Refactoring.h"
23 #include "clang/Tooling/Tooling.h" 23 #include "clang/Tooling/Tooling.h"
24 #include "llvm/Support/CommandLine.h" 24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/support/TargetSelect.h" 25 #include "llvm/Support/TargetSelect.h"
26 26
27 using namespace clang::ast_matchers; 27 using namespace clang::ast_matchers;
28 using clang::tooling::CommonOptionsParser; 28 using clang::tooling::CommonOptionsParser;
29 using clang::tooling::Replacement; 29 using clang::tooling::Replacement;
30 using clang::tooling::Replacements; 30 using clang::tooling::Replacements;
31 using llvm::StringRef; 31 using llvm::StringRef;
32 32
33 namespace clang { 33 namespace clang {
34 namespace ast_matchers { 34 namespace ast_matchers {
35 35
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 llvm::InitializeNativeTarget(); 261 llvm::InitializeNativeTarget();
262 llvm::InitializeNativeTargetAsmParser(); 262 llvm::InitializeNativeTargetAsmParser();
263 llvm::cl::OptionCategory category("Remove scoped_refptr conversions"); 263 llvm::cl::OptionCategory category("Remove scoped_refptr conversions");
264 CommonOptionsParser options(argc, argv, category); 264 CommonOptionsParser options(argc, argv, category);
265 clang::tooling::ClangTool tool(options.getCompilations(), 265 clang::tooling::ClangTool tool(options.getCompilations(),
266 options.getSourcePathList()); 266 options.getSourcePathList());
267 267
268 MatchFinder match_finder; 268 MatchFinder match_finder;
269 Replacements replacements; 269 Replacements replacements;
270 270
271 auto is_scoped_refptr = recordDecl(isSameOrDerivedFrom("::scoped_refptr"), 271 auto is_scoped_refptr = cxxRecordDecl(isSameOrDerivedFrom("::scoped_refptr"),
272 isTemplateInstantiation()); 272 isTemplateInstantiation());
273 273
274 // Finds all calls to conversion operator member function. This catches calls 274 // Finds all calls to conversion operator member function. This catches calls
275 // to "operator T*", "operator Testable", and "operator bool" equally. 275 // to "operator T*", "operator Testable", and "operator bool" equally.
276 auto base_matcher = memberCallExpr(thisPointerType(is_scoped_refptr), 276 auto base_matcher =
277 callee(conversionDecl()), 277 cxxMemberCallExpr(thisPointerType(is_scoped_refptr),
278 on(id("arg", expr()))); 278 callee(conversionDecl()), on(id("arg", expr())));
279 279
280 // The heuristic for whether or not converting a temporary is 'unsafe'. An 280 // The heuristic for whether or not converting a temporary is 'unsafe'. An
281 // unsafe conversion is one where a temporary scoped_refptr<T> is converted to 281 // unsafe conversion is one where a temporary scoped_refptr<T> is converted to
282 // another type. The matcher provides an exception for a temporary 282 // another type. The matcher provides an exception for a temporary
283 // scoped_refptr that is the result of an operator call. In this case, assume 283 // scoped_refptr that is the result of an operator call. In this case, assume
284 // that it's the result of an iterator dereference, and the container itself 284 // that it's the result of an iterator dereference, and the container itself
285 // retains the necessary reference, since this is a common idiom to see in 285 // retains the necessary reference, since this is a common idiom to see in
286 // loop bodies. 286 // loop bodies.
287 auto is_unsafe_temporary_conversion = 287 auto is_unsafe_temporary_conversion =
288 on(bindTemporaryExpr(unless(has(operatorCallExpr())))); 288 on(cxxBindTemporaryExpr(unless(has(cxxOperatorCallExpr()))));
289 289
290 // Returning a scoped_refptr<T> as a T* is considered unsafe if either are 290 // Returning a scoped_refptr<T> as a T* is considered unsafe if either are
291 // true: 291 // true:
292 // - The scoped_refptr<T> is a temporary. 292 // - The scoped_refptr<T> is a temporary.
293 // - The scoped_refptr<T> has local lifetime. 293 // - The scoped_refptr<T> has local lifetime.
294 auto returned_as_raw_ptr = hasParent( 294 auto returned_as_raw_ptr = hasParent(
295 returnStmt(hasAncestor(id("fn", functionDecl(returns(pointerType())))))); 295 returnStmt(hasAncestor(id("fn", functionDecl(returns(pointerType()))))));
296 // This matcher intentionally matches more than it should. For example, this 296 // This matcher intentionally matches more than it should. For example, this
297 // will match: 297 // will match:
298 // scoped_refptr<Foo>& foo = some_other_foo; 298 // scoped_refptr<Foo>& foo = some_other_foo;
(...skipping 16 matching lines...) Expand all
315 implicitCastExpr(hasImplicitDestinationType(isBoolean())); 315 implicitCastExpr(hasImplicitDestinationType(isBoolean()));
316 316
317 // Avoid converting calls to of "operator Testable" -> "bool" and calls of 317 // Avoid converting calls to of "operator Testable" -> "bool" and calls of
318 // "operator T*" -> "bool". 318 // "operator T*" -> "bool".
319 auto bool_conversion_matcher = hasParent( 319 auto bool_conversion_matcher = hasParent(
320 expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool))))); 320 expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool)))));
321 321
322 auto is_logging_helper = 322 auto is_logging_helper =
323 functionDecl(anyOf(hasName("CheckEQImpl"), hasName("CheckNEImpl"))); 323 functionDecl(anyOf(hasName("CheckEQImpl"), hasName("CheckNEImpl")));
324 auto is_gtest_helper = functionDecl( 324 auto is_gtest_helper = functionDecl(
325 anyOf(methodDecl(ofClass(recordDecl(isSameOrDerivedFrom( 325 anyOf(cxxMethodDecl(ofClass(cxxRecordDecl(isSameOrDerivedFrom(
326 hasName("::testing::internal::EqHelper")))), 326 hasName("::testing::internal::EqHelper")))),
327 hasName("Compare")), 327 hasName("Compare")),
328 hasName("::testing::internal::CmpHelperNE"))); 328 hasName("::testing::internal::CmpHelperNE")));
329 auto is_gtest_assertion_result_ctor = constructorDecl(ofClass( 329 auto is_gtest_assertion_result_ctor =
330 recordDecl(isSameOrDerivedFrom(hasName("::testing::AssertionResult"))))); 330 cxxConstructorDecl(ofClass(cxxRecordDecl(
331 isSameOrDerivedFrom(hasName("::testing::AssertionResult")))));
331 332
332 // Find all calls to an operator overload that are 'safe'. 333 // Find all calls to an operator overload that are 'safe'.
333 // 334 //
334 // All bool conversions will be handled with the Testable trick, but that 335 // All bool conversions will be handled with the Testable trick, but that
335 // can only be used once "operator T*" is removed, since otherwise it leaves 336 // can only be used once "operator T*" is removed, since otherwise it leaves
336 // the call ambiguous. 337 // the call ambiguous.
337 GetRewriterCallback get_callback(&replacements); 338 GetRewriterCallback get_callback(&replacements);
338 match_finder.addMatcher( 339 match_finder.addMatcher(
339 memberCallExpr( 340 cxxMemberCallExpr(
340 base_matcher, 341 base_matcher,
341 // Excluded since the conversion may be unsafe. 342 // Excluded since the conversion may be unsafe.
342 unless(anyOf(is_unsafe_temporary_conversion, is_unsafe_return)), 343 unless(anyOf(is_unsafe_temporary_conversion, is_unsafe_return)),
343 // Excluded since the conversion occurs inside a helper function that 344 // Excluded since the conversion occurs inside a helper function that
344 // the macro wraps. Letting this callback handle the rewrite would 345 // the macro wraps. Letting this callback handle the rewrite would
345 // result in an incorrect replacement that changes the helper function 346 // result in an incorrect replacement that changes the helper function
346 // itself. Instead, the right replacement is to rewrite the macro's 347 // itself. Instead, the right replacement is to rewrite the macro's
347 // arguments. 348 // arguments.
348 unless(hasAncestor(decl(anyOf(is_logging_helper, 349 unless(hasAncestor(decl(anyOf(is_logging_helper, is_gtest_helper,
349 is_gtest_helper,
350 is_gtest_assertion_result_ctor))))), 350 is_gtest_assertion_result_ctor))))),
351 &get_callback); 351 &get_callback);
352 352
353 // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*. 353 // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*.
354 VarRewriterCallback var_callback(&replacements); 354 VarRewriterCallback var_callback(&replacements);
355 auto initialized_with_temporary = ignoringImpCasts(exprWithCleanups( 355 auto initialized_with_temporary = ignoringImpCasts(exprWithCleanups(
356 has(memberCallExpr(base_matcher, is_unsafe_temporary_conversion)))); 356 has(cxxMemberCallExpr(base_matcher, is_unsafe_temporary_conversion))));
357 match_finder.addMatcher(id("var", 357 match_finder.addMatcher(id("var",
358 varDecl(hasInitializer(initialized_with_temporary), 358 varDecl(hasInitializer(initialized_with_temporary),
359 hasType(pointerType()))), 359 hasType(pointerType()))),
360 &var_callback); 360 &var_callback);
361 match_finder.addMatcher( 361 match_finder.addMatcher(
362 constructorDecl(forEachConstructorInitializer( 362 cxxConstructorDecl(forEachConstructorInitializer(
363 allOf(withInitializer(initialized_with_temporary), 363 allOf(withInitializer(initialized_with_temporary),
364 forField(id("var", fieldDecl(hasType(pointerType()))))))), 364 forField(id("var", fieldDecl(hasType(pointerType()))))))),
365 &var_callback); 365 &var_callback);
366 366
367 // Rewrite functions that unsafely turn a scoped_refptr<T> into a T* when 367 // Rewrite functions that unsafely turn a scoped_refptr<T> into a T* when
368 // returning a value. 368 // returning a value.
369 FunctionRewriterCallback fn_callback(&replacements); 369 FunctionRewriterCallback fn_callback(&replacements);
370 match_finder.addMatcher(memberCallExpr(base_matcher, is_unsafe_return), 370 match_finder.addMatcher(cxxMemberCallExpr(base_matcher, is_unsafe_return),
371 &fn_callback); 371 &fn_callback);
372 372
373 // Rewrite logging / gtest expressions that result in an implicit conversion. 373 // Rewrite logging / gtest expressions that result in an implicit conversion.
374 // Luckily, the matchers don't need to handle the case where one of the macro 374 // Luckily, the matchers don't need to handle the case where one of the macro
375 // arguments is NULL, such as: 375 // arguments is NULL, such as:
376 // CHECK_EQ(my_scoped_refptr, NULL) 376 // CHECK_EQ(my_scoped_refptr, NULL)
377 // because it simply doesn't compile--since NULL is actually of integral type, 377 // because it simply doesn't compile--since NULL is actually of integral type,
378 // this doesn't trigger scoped_refptr<T>'s implicit conversion. Since there is 378 // this doesn't trigger scoped_refptr<T>'s implicit conversion. Since there is
379 // no comparison overload for scoped_refptr<T> and int, this fails to compile. 379 // no comparison overload for scoped_refptr<T> and int, this fails to compile.
380 MacroRewriterCallback macro_callback(&replacements); 380 MacroRewriterCallback macro_callback(&replacements);
(...skipping 19 matching lines...) Expand all
400 &macro_callback); 400 &macro_callback);
401 // ASSERT_TRUE/EXPECT_TRUE helpers. Note that this matcher doesn't need to 401 // ASSERT_TRUE/EXPECT_TRUE helpers. Note that this matcher doesn't need to
402 // handle ASSERT_FALSE/EXPECT_FALSE, because it gets coerced to bool before 402 // handle ASSERT_FALSE/EXPECT_FALSE, because it gets coerced to bool before
403 // being passed as an argument to AssertionResult's constructor. As a result, 403 // being passed as an argument to AssertionResult's constructor. As a result,
404 // GetRewriterCallback handles this case properly since the conversion isn't 404 // GetRewriterCallback handles this case properly since the conversion isn't
405 // hidden inside AssertionResult, and the generated replacement properly 405 // hidden inside AssertionResult, and the generated replacement properly
406 // rewrites the macro argument. 406 // rewrites the macro argument.
407 // However, the tool does need to handle the _TRUE counterparts, since the 407 // However, the tool does need to handle the _TRUE counterparts, since the
408 // conversion occurs inside the constructor in those cases. 408 // conversion occurs inside the constructor in those cases.
409 match_finder.addMatcher( 409 match_finder.addMatcher(
410 constructExpr( 410 cxxConstructExpr(
411 argumentCountIs(2), 411 argumentCountIs(2),
412 hasArgument(0, id("expr", expr(hasType(is_scoped_refptr)))), 412 hasArgument(0, id("expr", expr(hasType(is_scoped_refptr)))),
413 hasDeclaration(is_gtest_assertion_result_ctor)), 413 hasDeclaration(is_gtest_assertion_result_ctor)),
414 &macro_callback); 414 &macro_callback);
415 415
416 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = 416 std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
417 clang::tooling::newFrontendActionFactory(&match_finder); 417 clang::tooling::newFrontendActionFactory(&match_finder);
418 int result = tool.run(factory.get()); 418 int result = tool.run(factory.get());
419 if (result != 0) 419 if (result != 0)
420 return result; 420 return result;
421 421
422 // Serialization format is documented in tools/clang/scripts/run_tool.py 422 // Serialization format is documented in tools/clang/scripts/run_tool.py
423 llvm::outs() << "==== BEGIN EDITS ====\n"; 423 llvm::outs() << "==== BEGIN EDITS ====\n";
424 for (const auto& r : replacements) { 424 for (const auto& r : replacements) {
425 std::string replacement_text = r.getReplacementText().str(); 425 std::string replacement_text = r.getReplacementText().str();
426 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); 426 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
427 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() << ":::" 427 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() << ":::"
428 << r.getLength() << ":::" << replacement_text << "\n"; 428 << r.getLength() << ":::" << replacement_text << "\n";
429 } 429 }
430 llvm::outs() << "==== END EDITS ====\n"; 430 llvm::outs() << "==== END EDITS ====\n";
431 431
432 return 0; 432 return 0;
433 } 433 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698