Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / clang / rewrite_scoped_refptr / RewriteScopedRefptr.cpp
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
3 // found in the LICENSE file.
4 //
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
7 // the .get() method.
8
9 #include <algorithm>
10 #include <memory>
11 #include <string>
12
13 #include "clang/AST/ASTContext.h"
14 #include "clang/ASTMatchers/ASTMatchers.h"
15 #include "clang/ASTMatchers/ASTMatchersMacros.h"
16 #include "clang/ASTMatchers/ASTMatchFinder.h"
17 #include "clang/Basic/SourceManager.h"
18 #include "clang/Frontend/FrontendActions.h"
19 #include "clang/Lex/Lexer.h"
20 #include "clang/Tooling/CommonOptionsParser.h"
21 #include "clang/Tooling/Refactoring.h"
22 #include "clang/Tooling/Tooling.h"
23 #include "llvm/Support/CommandLine.h"
24
25 using namespace clang::ast_matchers;
26 using clang::tooling::CommonOptionsParser;
27 using clang::tooling::Replacement;
28 using clang::tooling::Replacements;
29 using llvm::StringRef;
30
31 namespace clang {
32 namespace ast_matchers {
33
34 const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
35     conversionDecl;
36
37 AST_MATCHER(QualType, isBoolean) {
38   return Node->isBooleanType();
39 }
40
41 }  // namespace ast_matchers
42 }  // namespace clang
43
44 namespace {
45
46 // Returns true if expr needs to be put in parens (eg: when it is an operator
47 // syntactically).
48 bool NeedsParens(const clang::Expr* expr) {
49   if (llvm::dyn_cast<clang::UnaryOperator>(expr) ||
50       llvm::dyn_cast<clang::BinaryOperator>(expr) ||
51       llvm::dyn_cast<clang::ConditionalOperator>(expr)) {
52     return true;
53   }
54   // Calls to an overloaded operator also need parens, except for foo(...) and
55   // foo[...] expressions.
56   if (const clang::CXXOperatorCallExpr* op =
57           llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
58     return op->getOperator() != clang::OO_Call &&
59            op->getOperator() != clang::OO_Subscript;
60   }
61   return false;
62 }
63
64 class GetRewriterCallback : public MatchFinder::MatchCallback {
65  public:
66   explicit GetRewriterCallback(Replacements* replacements)
67       : replacements_(replacements) {}
68   virtual void run(const MatchFinder::MatchResult& result) override;
69
70  private:
71   Replacements* const replacements_;
72 };
73
74 void GetRewriterCallback::run(const MatchFinder::MatchResult& result) {
75   const clang::CXXMemberCallExpr* const implicit_call =
76       result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("call");
77   const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
78
79   if (!implicit_call || !arg)
80     return;
81
82   clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
83       result.SourceManager->getSpellingLoc(arg->getLocStart()),
84       result.SourceManager->getSpellingLoc(arg->getLocEnd()));
85   if (!range.isValid())
86     return;  // TODO(rsleevi): Log an error?
87
88   // Handle cases where an implicit cast is being done by dereferencing a
89   // pointer to a scoped_refptr<> (sadly, it happens...)
90   //
91   // This rewrites both "*foo" and "*(foo)" as "foo->get()".
92   if (const clang::UnaryOperator* op =
93           llvm::dyn_cast<clang::UnaryOperator>(arg)) {
94     if (op->getOpcode() == clang::UO_Deref) {
95       const clang::Expr* const sub_expr =
96           op->getSubExpr()->IgnoreParenImpCasts();
97       clang::CharSourceRange sub_expr_range =
98           clang::CharSourceRange::getTokenRange(
99               result.SourceManager->getSpellingLoc(sub_expr->getLocStart()),
100               result.SourceManager->getSpellingLoc(sub_expr->getLocEnd()));
101       if (!sub_expr_range.isValid())
102         return;  // TODO(rsleevi): Log an error?
103       std::string inner_text = clang::Lexer::getSourceText(
104           sub_expr_range, *result.SourceManager, result.Context->getLangOpts());
105       if (inner_text.empty())
106         return;  // TODO(rsleevi): Log an error?
107
108       if (NeedsParens(sub_expr)) {
109         inner_text.insert(0, "(");
110         inner_text.append(")");
111       }
112       inner_text.append("->get()");
113       replacements_->insert(
114           Replacement(*result.SourceManager, range, inner_text));
115       return;
116     }
117   }
118
119   std::string text = clang::Lexer::getSourceText(
120       range, *result.SourceManager, result.Context->getLangOpts());
121   if (text.empty())
122     return;  // TODO(rsleevi): Log an error?
123
124   // Unwrap any temporaries - for example, custom iterators that return
125   // scoped_refptr<T> as part of operator*. Any such iterators should also
126   // be declaring a scoped_refptr<T>* operator->, per C++03 24.4.1.1 (Table 72)
127   if (const clang::CXXBindTemporaryExpr* op =
128           llvm::dyn_cast<clang::CXXBindTemporaryExpr>(arg)) {
129     arg = op->getSubExpr();
130   }
131
132   // Handle iterators (which are operator* calls, followed by implicit
133   // conversions) by rewriting *it as it->get()
134   if (const clang::CXXOperatorCallExpr* op =
135           llvm::dyn_cast<clang::CXXOperatorCallExpr>(arg)) {
136     if (op->getOperator() == clang::OO_Star) {
137       // Note that this doesn't rewrite **it correctly, since it should be
138       // rewritten using parens, e.g. (*it)->get(). However, this shouldn't
139       // happen frequently, if at all, since it would likely indicate code is
140       // storing pointers to a scoped_refptr in a container.
141       text.erase(0, 1);
142       text.append("->get()");
143       replacements_->insert(Replacement(*result.SourceManager, range, text));
144       return;
145     }
146   }
147
148   // The only remaining calls should be non-dereferencing calls (eg: member
149   // calls), so a simple ".get()" appending should suffice.
150   if (NeedsParens(arg)) {
151     text.insert(0, "(");
152     text.append(")");
153   }
154   text.append(".get()");
155   replacements_->insert(Replacement(*result.SourceManager, range, text));
156 }
157
158 class VarRewriterCallback : public MatchFinder::MatchCallback {
159  public:
160   explicit VarRewriterCallback(Replacements* replacements)
161       : replacements_(replacements) {}
162   virtual void run(const MatchFinder::MatchResult& result) override;
163
164  private:
165   Replacements* const replacements_;
166 };
167
168 void VarRewriterCallback::run(const MatchFinder::MatchResult& result) {
169   const clang::CXXMemberCallExpr* const implicit_call =
170       result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("call");
171   const clang::DeclaratorDecl* const var_decl =
172       result.Nodes.getNodeAs<clang::DeclaratorDecl>("var");
173
174   if (!implicit_call || !var_decl)
175     return;
176
177   const clang::TypeSourceInfo* tsi = var_decl->getTypeSourceInfo();
178
179   clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
180       result.SourceManager->getSpellingLoc(tsi->getTypeLoc().getBeginLoc()),
181       result.SourceManager->getSpellingLoc(tsi->getTypeLoc().getEndLoc()));
182   if (!range.isValid())
183     return;
184
185   std::string text = clang::Lexer::getSourceText(
186       range, *result.SourceManager, result.Context->getLangOpts());
187   if (text.empty())
188     return;
189   text.erase(text.rfind('*'));
190
191   std::string replacement_text("scoped_refptr<");
192   replacement_text += text;
193   replacement_text += ">";
194
195   replacements_->insert(
196       Replacement(*result.SourceManager, range, replacement_text));
197 }
198
199 }  // namespace
200
201 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
202
203 int main(int argc, const char* argv[]) {
204   llvm::cl::OptionCategory category("Remove scoped_refptr conversions");
205   CommonOptionsParser options(argc, argv, category);
206   clang::tooling::ClangTool tool(options.getCompilations(),
207                                  options.getSourcePathList());
208
209   MatchFinder match_finder;
210   Replacements replacements;
211
212   // Finds all calls to conversion operator member function. This catches calls
213   // to "operator T*", "operator Testable", and "operator bool" equally.
214   auto base_matcher = memberCallExpr(
215       thisPointerType(recordDecl(isSameOrDerivedFrom("::scoped_refptr"),
216                                  isTemplateInstantiation())),
217       callee(conversionDecl()));
218
219   // The heuristic for whether or not a conversion is 'unsafe'. An unsafe
220   // conversion is one where a temporary scoped_refptr<T> is converted to
221   // another type. The matcher provides an exception for a temporary
222   // scoped_refptr that is the result of an operator call. In this case, assume
223   // that it's the result of an iterator dereference, and the container itself
224   // retains the necessary reference, since this is a common idiom to see in
225   // loop bodies.
226   auto is_unsafe_conversion =
227       bindTemporaryExpr(unless(has(operatorCallExpr())));
228
229   auto safe_conversion_matcher = memberCallExpr(
230       base_matcher, on(id("arg", expr(unless(is_unsafe_conversion)))));
231
232   auto unsafe_conversion_matcher =
233       memberCallExpr(base_matcher, on(id("arg", is_unsafe_conversion)));
234
235   // This catches both user-defined conversions (eg: "operator bool") and
236   // standard conversion sequence (C++03 13.3.3.1.1), such as converting a
237   // pointer to a bool.
238   auto implicit_to_bool =
239       implicitCastExpr(hasImplicitDestinationType(isBoolean()));
240
241   // Avoid converting calls to of "operator Testable" -> "bool" and calls of
242   // "operator T*" -> "bool".
243   auto bool_conversion_matcher = hasParent(
244       expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool)))));
245
246   // Find all calls to an operator overload that do NOT (ultimately) result in
247   // being cast to a bool - eg: where it's being converted to T* and rewrite
248   // them to add a call to get().
249   //
250   // All bool conversions will be handled with the Testable trick, but that
251   // can only be used once "operator T*" is removed, since otherwise it leaves
252   // the call ambiguous.
253   GetRewriterCallback get_callback(&replacements);
254   match_finder.addMatcher(id("call", safe_conversion_matcher), &get_callback);
255
256   // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*.
257   VarRewriterCallback var_callback(&replacements);
258   match_finder.addMatcher(
259       id("var",
260          varDecl(hasInitializer(ignoringImpCasts(exprWithCleanups(
261                      has(id("call", unsafe_conversion_matcher))))),
262                  hasType(pointerType()))),
263       &var_callback);
264   match_finder.addMatcher(
265       constructorDecl(forEachConstructorInitializer(allOf(
266           withInitializer(ignoringImpCasts(
267               exprWithCleanups(has(id("call", unsafe_conversion_matcher))))),
268           forField(id("var", fieldDecl(hasType(pointerType()))))))),
269       &var_callback);
270
271   std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
272       clang::tooling::newFrontendActionFactory(&match_finder);
273   int result = tool.run(factory.get());
274   if (result != 0)
275     return result;
276
277   // Serialization format is documented in tools/clang/scripts/run_tool.py
278   llvm::outs() << "==== BEGIN EDITS ====\n";
279   for (const auto& r : replacements) {
280     std::string replacement_text = r.getReplacementText().str();
281     std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
282     llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
283                  << r.getLength() << ":" << replacement_text << "\n";
284   }
285   llvm::outs() << "==== END EDITS ====\n";
286
287   return 0;
288 }