1f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// found in the LICENSE file.
4f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch//
5f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// This implements a Clang tool to rewrite all instances of
6f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// scoped_refptr<T>'s implicit cast to T (operator T*) to an explicit call to
7f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// the .get() method.
8f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
9f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include <assert.h>
10f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include <algorithm>
11f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include <memory>
12f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include <string>
13f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
14f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/AST/ASTContext.h"
15f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/ASTMatchers/ASTMatchers.h"
16f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/ASTMatchers/ASTMatchersMacros.h"
17f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/ASTMatchers/ASTMatchFinder.h"
18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/Basic/SourceManager.h"
19f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/Frontend/FrontendActions.h"
20f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/Lex/Lexer.h"
21f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/Tooling/CommonOptionsParser.h"
22f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/Tooling/Refactoring.h"
23f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "clang/Tooling/Tooling.h"
24f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "llvm/Support/CommandLine.h"
25f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "llvm/Support/TargetSelect.h"
26f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
27f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochusing namespace clang::ast_matchers;
28f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochusing clang::tooling::CommonOptionsParser;
29f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochusing clang::tooling::Replacement;
30f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochusing clang::tooling::Replacements;
31f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochusing llvm::StringRef;
32f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
33f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochnamespace clang {
34f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochnamespace ast_matchers {
35f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
36f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochconst internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
37f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    conversionDecl;
38f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
39f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochAST_MATCHER(QualType, isBoolean) {
40f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return Node->isBooleanType();
41f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
42f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
43f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}  // namespace ast_matchers
44f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}  // namespace clang
45f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
46f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochnamespace {
47f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
48f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// Returns true if expr needs to be put in parens (eg: when it is an operator
49f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch// syntactically).
50f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochbool NeedsParens(const clang::Expr* expr) {
51f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (llvm::dyn_cast<clang::UnaryOperator>(expr) ||
52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      llvm::dyn_cast<clang::BinaryOperator>(expr) ||
53f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      llvm::dyn_cast<clang::ConditionalOperator>(expr)) {
54f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    return true;
55f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
56f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Calls to an overloaded operator also need parens, except for foo(...) and
57f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // foo[...] expressions.
58f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (const clang::CXXOperatorCallExpr* op =
59f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
60f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    return op->getOperator() != clang::OO_Call &&
61f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch           op->getOperator() != clang::OO_Subscript;
62f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
63f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return false;
64f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
65f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
66f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochReplacement RewriteImplicitToExplicitConversion(
67f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    const MatchFinder::MatchResult& result,
68f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    const clang::Expr* expr) {
69f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
70f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result.SourceManager->getSpellingLoc(expr->getLocStart()),
71f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result.SourceManager->getSpellingLoc(expr->getLocEnd()));
72f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  assert(range.isValid() && "Invalid range!");
73f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
74f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Handle cases where an implicit cast is being done by dereferencing a
75f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // pointer to a scoped_refptr<> (sadly, it happens...)
76f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //
77f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // This rewrites both "*foo" and "*(foo)" as "foo->get()".
78f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (const clang::UnaryOperator* op =
79f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          llvm::dyn_cast<clang::UnaryOperator>(expr)) {
80f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    if (op->getOpcode() == clang::UO_Deref) {
81f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      const clang::Expr* const sub_expr =
82f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          op->getSubExpr()->IgnoreParenImpCasts();
83f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      clang::CharSourceRange sub_expr_range =
84f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          clang::CharSourceRange::getTokenRange(
85f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch              result.SourceManager->getSpellingLoc(sub_expr->getLocStart()),
86f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch              result.SourceManager->getSpellingLoc(sub_expr->getLocEnd()));
87f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      assert(sub_expr_range.isValid() && "Invalid subexpression range!");
88f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
89f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      std::string inner_text = clang::Lexer::getSourceText(
90f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          sub_expr_range, *result.SourceManager, result.Context->getLangOpts());
91f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      assert(!inner_text.empty() && "No text for subexpression!");
92f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      if (NeedsParens(sub_expr)) {
93f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        inner_text.insert(0, "(");
94f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        inner_text.append(")");
95f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      }
96f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      inner_text.append("->get()");
97f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      return Replacement(*result.SourceManager, range, inner_text);
98f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    }
99f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
100f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
101f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  std::string text = clang::Lexer::getSourceText(
102f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      range, *result.SourceManager, result.Context->getLangOpts());
103f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  assert(!text.empty() && "No text for expression!");
104f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Unwrap any temporaries - for example, custom iterators that return
106f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // scoped_refptr<T> as part of operator*. Any such iterators should also
107f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // be declaring a scoped_refptr<T>* operator->, per C++03 24.4.1.1 (Table 72)
108f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (const clang::CXXBindTemporaryExpr* op =
109f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          llvm::dyn_cast<clang::CXXBindTemporaryExpr>(expr)) {
110f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    expr = op->getSubExpr();
111f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
112f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
113f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Handle iterators (which are operator* calls, followed by implicit
114f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // conversions) by rewriting *it as it->get()
115f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (const clang::CXXOperatorCallExpr* op =
116f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
117f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    if (op->getOperator() == clang::OO_Star) {
118f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      // Note that this doesn't rewrite **it correctly, since it should be
119f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      // rewritten using parens, e.g. (*it)->get(). However, this shouldn't
120f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      // happen frequently, if at all, since it would likely indicate code is
121f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      // storing pointers to a scoped_refptr in a container.
122f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      text.erase(0, 1);
123f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      text.append("->get()");
124f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      return Replacement(*result.SourceManager, range, text);
125f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    }
126f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
127f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
128f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // The only remaining calls should be non-dereferencing calls (eg: member
129f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // calls), so a simple ".get()" appending should suffice.
130f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (NeedsParens(expr)) {
131f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    text.insert(0, "(");
132f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    text.append(")");
133f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
134f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  text.append(".get()");
135f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return Replacement(*result.SourceManager, range, text);
136f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
137f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
138f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochReplacement RewriteRawPtrToScopedRefptr(const MatchFinder::MatchResult& result,
139f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                        clang::SourceLocation begin,
140f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                        clang::SourceLocation end) {
141f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
142f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result.SourceManager->getSpellingLoc(begin),
143f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result.SourceManager->getSpellingLoc(end));
144f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  assert(range.isValid() && "Invalid range!");
145f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
146f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  std::string text = clang::Lexer::getSourceText(
147f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      range, *result.SourceManager, result.Context->getLangOpts());
148f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  text.erase(text.rfind('*'));
149f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
150f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  std::string replacement_text("scoped_refptr<");
151f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  replacement_text += text;
152f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  replacement_text += ">";
153f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
154f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return Replacement(*result.SourceManager, range, replacement_text);
155f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
156f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
157f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochclass GetRewriterCallback : public MatchFinder::MatchCallback {
158f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch public:
159f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  explicit GetRewriterCallback(Replacements* replacements)
160f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      : replacements_(replacements) {}
161f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  virtual void run(const MatchFinder::MatchResult& result) override;
162f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
163f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch private:
164f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Replacements* const replacements_;
165f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch};
166f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
167f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid GetRewriterCallback::run(const MatchFinder::MatchResult& result) {
168f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
169f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  assert(arg && "Unexpected match! No Expr captured!");
17062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  auto err =
17162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      replacements_->add(RewriteImplicitToExplicitConversion(result, arg));
17262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  assert(!err);
173f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
174f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
175f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochclass VarRewriterCallback : public MatchFinder::MatchCallback {
176f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch public:
177f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  explicit VarRewriterCallback(Replacements* replacements)
178f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      : replacements_(replacements) {}
179f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  virtual void run(const MatchFinder::MatchResult& result) override;
180f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
181f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch private:
182f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Replacements* const replacements_;
183f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch};
184f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
185f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid VarRewriterCallback::run(const MatchFinder::MatchResult& result) {
186f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  const clang::DeclaratorDecl* const var_decl =
187f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result.Nodes.getNodeAs<clang::DeclaratorDecl>("var");
188f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  assert(var_decl && "Unexpected match! No VarDecl captured!");
189f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
190f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  const clang::TypeSourceInfo* tsi = var_decl->getTypeSourceInfo();
191f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
192f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // TODO(dcheng): This mishandles a case where a variable has multiple
193f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // declarations, e.g.:
194f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //
195f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // in .h:
196f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Foo* my_global_magical_foo;
197f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //
198f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // in .cc:
199f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Foo* my_global_magical_foo = CreateFoo();
200f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //
201f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // In this case, it will only rewrite the .cc definition. Oh well. This should
202f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // be rare enough that these cases can be manually handled, since the style
203f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // guide prohibits globals of non-POD type.
20462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  auto err = replacements_->add(RewriteRawPtrToScopedRefptr(
205f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result, tsi->getTypeLoc().getBeginLoc(), tsi->getTypeLoc().getEndLoc()));
20662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  assert(!err);
207f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
208f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
209f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochclass FunctionRewriterCallback : public MatchFinder::MatchCallback {
210f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch public:
211f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  explicit FunctionRewriterCallback(Replacements* replacements)
212f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      : replacements_(replacements) {}
213f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  virtual void run(const MatchFinder::MatchResult& result) override;
214f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
215f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch private:
216f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Replacements* const replacements_;
217f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch};
218f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
219f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid FunctionRewriterCallback::run(const MatchFinder::MatchResult& result) {
220f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  const clang::FunctionDecl* const function_decl =
221f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result.Nodes.getNodeAs<clang::FunctionDecl>("fn");
222f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  assert(function_decl && "Unexpected match! No FunctionDecl captured!");
223f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
224f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // If matched against an implicit conversion to a DeclRefExpr, make sure the
225f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // referenced declaration is of class type, e.g. the tool skips trying to
226f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // chase pointers/references to determine if the pointee is a scoped_refptr<T>
227f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // with local storage. Instead, let a human manually handle those cases.
228f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  const clang::VarDecl* const var_decl =
229f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      result.Nodes.getNodeAs<clang::VarDecl>("var");
230f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (var_decl && !var_decl->getTypeSourceInfo()->getType()->isClassType()) {
231f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    return;
232f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
233f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
234f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  for (clang::FunctionDecl* f : function_decl->redecls()) {
235f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    clang::SourceRange range = f->getReturnTypeSourceRange();
23662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    auto err = replacements_->add(
237f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        RewriteRawPtrToScopedRefptr(result, range.getBegin(), range.getEnd()));
23862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    assert(!err);
239f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
240f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
241f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
242f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochclass MacroRewriterCallback : public MatchFinder::MatchCallback {
243f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch public:
244f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  explicit MacroRewriterCallback(Replacements* replacements)
245f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      : replacements_(replacements) {}
246f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  virtual void run(const MatchFinder::MatchResult& result) override;
247f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
248f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch private:
249f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Replacements* const replacements_;
250f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch};
251f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
252f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochvoid MacroRewriterCallback::run(const MatchFinder::MatchResult& result) {
253f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  const clang::Expr* const expr = result.Nodes.getNodeAs<clang::Expr>("expr");
254f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  assert(expr && "Unexpected match! No Expr captured!");
25562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  auto err =
25662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      replacements_->add(RewriteImplicitToExplicitConversion(result, expr));
25762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  assert(!err);
258f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
259f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
260f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}  // namespace
261f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
262f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochstatic llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
263f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
264f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochint main(int argc, const char* argv[]) {
265f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // TODO(dcheng): Clang tooling should do this itself.
266f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // http://llvm.org/bugs/show_bug.cgi?id=21627
267f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  llvm::InitializeNativeTarget();
268f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  llvm::InitializeNativeTargetAsmParser();
269f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  llvm::cl::OptionCategory category("Remove scoped_refptr conversions");
270f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  CommonOptionsParser options(argc, argv, category);
271f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  clang::tooling::ClangTool tool(options.getCompilations(),
272f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                 options.getSourcePathList());
273f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
274f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  MatchFinder match_finder;
275f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  Replacements replacements;
276f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
277f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto is_scoped_refptr = cxxRecordDecl(isSameOrDerivedFrom("::scoped_refptr"),
278f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                        isTemplateInstantiation());
279f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
280f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Finds all calls to conversion operator member function. This catches calls
281f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // to "operator T*", "operator Testable", and "operator bool" equally.
282f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto base_matcher =
283f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      cxxMemberCallExpr(thisPointerType(is_scoped_refptr),
284f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                        callee(conversionDecl()), on(id("arg", expr())));
285f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
286f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // The heuristic for whether or not converting a temporary is 'unsafe'. An
287f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // unsafe conversion is one where a temporary scoped_refptr<T> is converted to
288f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // another type. The matcher provides an exception for a temporary
289f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // scoped_refptr that is the result of an operator call. In this case, assume
290f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // that it's the result of an iterator dereference, and the container itself
291f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // retains the necessary reference, since this is a common idiom to see in
292f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // loop bodies.
293f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto is_unsafe_temporary_conversion =
294f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      on(cxxBindTemporaryExpr(unless(has(cxxOperatorCallExpr()))));
295f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
296f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Returning a scoped_refptr<T> as a T* is considered unsafe if either are
297f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // true:
298f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // - The scoped_refptr<T> is a temporary.
299f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // - The scoped_refptr<T> has local lifetime.
300f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto returned_as_raw_ptr = hasParent(
301f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      returnStmt(hasAncestor(id("fn", functionDecl(returns(pointerType()))))));
302f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // This matcher intentionally matches more than it should. For example, this
303f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // will match:
304f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //   scoped_refptr<Foo>& foo = some_other_foo;
305f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //   return foo;
306f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // The matcher callback filters out VarDecls that aren't a scoped_refptr<T>,
307f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // so those cases can be manually handled.
308f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto is_local_variable =
309f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      on(declRefExpr(to(id("var", varDecl(hasLocalStorage())))));
310f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto is_unsafe_return =
311f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      anyOf(allOf(hasParent(implicitCastExpr(returned_as_raw_ptr)),
312f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                  is_local_variable),
313f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            allOf(hasParent(implicitCastExpr(
314f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                      hasParent(exprWithCleanups(returned_as_raw_ptr)))),
315f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                  is_unsafe_temporary_conversion));
316f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
317f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // This catches both user-defined conversions (eg: "operator bool") and
318f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // standard conversion sequence (C++03 13.3.3.1.1), such as converting a
319f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // pointer to a bool.
320f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto implicit_to_bool =
321f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      implicitCastExpr(hasImplicitDestinationType(isBoolean()));
322f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
323f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Avoid converting calls to of "operator Testable" -> "bool" and calls of
324f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // "operator T*" -> "bool".
325f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto bool_conversion_matcher = hasParent(
326f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool)))));
327f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
328f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto is_logging_helper =
329f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      functionDecl(anyOf(hasName("CheckEQImpl"), hasName("CheckNEImpl")));
330f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto is_gtest_helper = functionDecl(
331f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      anyOf(cxxMethodDecl(ofClass(cxxRecordDecl(isSameOrDerivedFrom(
332f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                              hasName("::testing::internal::EqHelper")))),
333f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                          hasName("Compare")),
334f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch            hasName("::testing::internal::CmpHelperNE")));
335f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  auto is_gtest_assertion_result_ctor =
336f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      cxxConstructorDecl(ofClass(cxxRecordDecl(
337f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          isSameOrDerivedFrom(hasName("::testing::AssertionResult")))));
338f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
339f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Find all calls to an operator overload that are 'safe'.
340f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  //
341f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // All bool conversions will be handled with the Testable trick, but that
342f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // can only be used once "operator T*" is removed, since otherwise it leaves
343f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // the call ambiguous.
344f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  GetRewriterCallback get_callback(&replacements);
345f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  match_finder.addMatcher(
346f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      cxxMemberCallExpr(
347f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          base_matcher,
348f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          // Excluded since the conversion may be unsafe.
349f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          unless(anyOf(is_unsafe_temporary_conversion, is_unsafe_return)),
350f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          // Excluded since the conversion occurs inside a helper function that
351f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          // the macro wraps. Letting this callback handle the rewrite would
352f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          // result in an incorrect replacement that changes the helper function
353f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          // itself. Instead, the right replacement is to rewrite the macro's
354f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          // arguments.
355f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          unless(hasAncestor(decl(anyOf(is_logging_helper, is_gtest_helper,
356f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                        is_gtest_assertion_result_ctor))))),
357f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      &get_callback);
358f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
359f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*.
360f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  VarRewriterCallback var_callback(&replacements);
36162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  auto initialized_with_temporary = has(ignoringImpCasts(
36262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      cxxMemberCallExpr(base_matcher, is_unsafe_temporary_conversion)));
36362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  match_finder.addMatcher(
36462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      id("var", varDecl(hasInitializer(initialized_with_temporary),
36562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                        hasType(pointerType()))),
36662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      &var_callback);
367f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  match_finder.addMatcher(
368f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      cxxConstructorDecl(forEachConstructorInitializer(
369f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          allOf(withInitializer(initialized_with_temporary),
370f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                forField(id("var", fieldDecl(hasType(pointerType()))))))),
371f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      &var_callback);
372f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
373f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Rewrite functions that unsafely turn a scoped_refptr<T> into a T* when
374f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // returning a value.
375f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  FunctionRewriterCallback fn_callback(&replacements);
376f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  match_finder.addMatcher(cxxMemberCallExpr(base_matcher, is_unsafe_return),
377f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                          &fn_callback);
378f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
379f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Rewrite logging / gtest expressions that result in an implicit conversion.
380f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Luckily, the matchers don't need to handle the case where one of the macro
381f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // arguments is NULL, such as:
382f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // CHECK_EQ(my_scoped_refptr, NULL)
383f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // because it simply doesn't compile--since NULL is actually of integral type,
384f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // this doesn't trigger scoped_refptr<T>'s implicit conversion. Since there is
385f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // no comparison overload for scoped_refptr<T> and int, this fails to compile.
386f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  MacroRewriterCallback macro_callback(&replacements);
387f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // CHECK_EQ/CHECK_NE helpers.
388f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  match_finder.addMatcher(
38962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      callExpr(callee(is_logging_helper), argumentCountIs(3),
39062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch               hasAnyArgument(ignoringParenImpCasts(
39162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                   id("expr", expr(hasType(is_scoped_refptr))))),
39262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch               hasAnyArgument(ignoringParenImpCasts(hasType(pointerType()))),
393f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch               hasArgument(2, stringLiteral())),
394f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      &macro_callback);
395f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // ASSERT_EQ/ASSERT_NE/EXPECT_EQ/EXPECT_EQ, which use the same underlying
396f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // helper functions. Even though gtest has special handling for pointer to
397f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // NULL comparisons, it doesn't trigger in this case, so no special handling
398f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // is needed for the replacements.
399f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  match_finder.addMatcher(
400f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      callExpr(callee(is_gtest_helper),
401f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch               argumentCountIs(4),
402f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch               hasArgument(0, stringLiteral()),
403f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch               hasArgument(1, stringLiteral()),
404f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch               hasAnyArgument(id("expr", expr(hasType(is_scoped_refptr)))),
405f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch               hasAnyArgument(hasType(pointerType()))),
406f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      &macro_callback);
407f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // ASSERT_TRUE/EXPECT_TRUE helpers. Note that this matcher doesn't need to
408f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // handle ASSERT_FALSE/EXPECT_FALSE, because it gets coerced to bool before
409f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // being passed as an argument to AssertionResult's constructor. As a result,
410f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // GetRewriterCallback handles this case properly since the conversion isn't
411f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // hidden inside AssertionResult, and the generated replacement properly
412f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // rewrites the macro argument.
413f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // However, the tool does need to handle the _TRUE counterparts, since the
414f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // conversion occurs inside the constructor in those cases.
415f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  match_finder.addMatcher(
416f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      cxxConstructExpr(
417f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          argumentCountIs(2),
418f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          hasArgument(0, id("expr", expr(hasType(is_scoped_refptr)))),
419f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          hasDeclaration(is_gtest_assertion_result_ctor)),
420f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      &macro_callback);
421f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
422f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
423f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      clang::tooling::newFrontendActionFactory(&match_finder);
424f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  int result = tool.run(factory.get());
425f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (result != 0)
426f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    return result;
427f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
428f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Serialization format is documented in tools/clang/scripts/run_tool.py
429f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  llvm::outs() << "==== BEGIN EDITS ====\n";
430f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  for (const auto& r : replacements) {
431f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    std::string replacement_text = r.getReplacementText().str();
432f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
433f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() << ":::"
434f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                 << r.getLength() << ":::" << replacement_text << "\n";
435f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  }
436f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  llvm::outs() << "==== END EDITS ====\n";
437f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
438f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return 0;
439f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
440