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

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

Issue 453873002: Implement rewrite logic for assigning a temporary scoped_refptr to T*. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Tighten matchers 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
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 <algorithm> 9 #include <algorithm>
10 #include <memory> 10 #include <memory>
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 // The only remaining calls should be non-dereferencing calls (eg: member 148 // The only remaining calls should be non-dereferencing calls (eg: member
149 // calls), so a simple ".get()" appending should suffice. 149 // calls), so a simple ".get()" appending should suffice.
150 if (NeedsParens(arg)) { 150 if (NeedsParens(arg)) {
151 text.insert(0, "("); 151 text.insert(0, "(");
152 text.append(")"); 152 text.append(")");
153 } 153 }
154 text.append(".get()"); 154 text.append(".get()");
155 replacements_->insert(Replacement(*result.SourceManager, range, text)); 155 replacements_->insert(Replacement(*result.SourceManager, range, text));
156 } 156 }
157 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 += ">";
Ryan Sleevi 2014/08/08 22:10:13 No IWYU implications?
dcheng 2014/08/09 21:00:21 If a function declaration is returning a scoped_re
194
195 replacements_->insert(
196 Replacement(*result.SourceManager, range, replacement_text));
197 }
198
158 } // namespace 199 } // namespace
159 200
160 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); 201 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
161 202
162 int main(int argc, const char* argv[]) { 203 int main(int argc, const char* argv[]) {
163 llvm::cl::OptionCategory category("Remove scoped_refptr conversions"); 204 llvm::cl::OptionCategory category("Remove scoped_refptr conversions");
164 CommonOptionsParser options(argc, argv, category); 205 CommonOptionsParser options(argc, argv, category);
165 clang::tooling::ClangTool tool(options.getCompilations(), 206 clang::tooling::ClangTool tool(options.getCompilations(),
166 options.getSourcePathList()); 207 options.getSourcePathList());
167 208
168 MatchFinder match_finder; 209 MatchFinder match_finder;
210 Replacements replacements;
169 211
170 // Finds all calls to conversion operator member function. This catches calls 212 // Finds all calls to conversion operator member function. This catches calls
171 // to "operator T*", "operator Testable", and "operator bool" equally. 213 // to "operator T*", "operator Testable", and "operator bool" equally.
172 StatementMatcher overloaded_call_matcher = memberCallExpr( 214 auto base_matcher = memberCallExpr(
mdempsky 2014/08/08 21:59:28 [Is C++11 allowed already, or are you just taking
dcheng 2014/08/09 21:00:21 As far as I can tell, it's already required to bui
173 thisPointerType(recordDecl(isSameOrDerivedFrom("::scoped_refptr"), 215 thisPointerType(recordDecl(isSameOrDerivedFrom("::scoped_refptr"),
174 isTemplateInstantiation())), 216 isTemplateInstantiation())),
175 callee(conversionDecl()), 217 callee(conversionDecl()));
176 on(id("arg", expr()))); 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)));
177 234
178 // This catches both user-defined conversions (eg: "operator bool") and 235 // This catches both user-defined conversions (eg: "operator bool") and
179 // standard conversion sequence (C++03 13.3.3.1.1), such as converting a 236 // standard conversion sequence (C++03 13.3.3.1.1), such as converting a
180 // pointer to a bool. 237 // pointer to a bool.
181 StatementMatcher implicit_to_bool = 238 auto implicit_to_bool =
182 implicitCastExpr(hasImplicitDestinationType(isBoolean())); 239 implicitCastExpr(hasImplicitDestinationType(isBoolean()));
183 240
184 // Avoid converting calls to of "operator Testable" -> "bool" and calls of 241 // Avoid converting calls to of "operator Testable" -> "bool" and calls of
185 // "operator T*" -> "bool". 242 // "operator T*" -> "bool".
186 StatementMatcher bool_conversion_matcher = hasParent(expr( 243 auto bool_conversion_matcher = hasParent(
187 anyOf(expr(implicit_to_bool), expr(hasParent(expr(implicit_to_bool)))))); 244 expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool)))));
188 245
189 // Find all calls to an operator overload that do NOT (ultimately) result in 246 // Find all calls to an operator overload that do NOT (ultimately) result in
190 // being cast to a bool - eg: where it's being converted to T* and rewrite 247 // being cast to a bool - eg: where it's being converted to T* and rewrite
191 // them to add a call to get(). 248 // them to add a call to get().
192 // 249 //
193 // All bool conversions will be handled with the Testable trick, but that 250 // All bool conversions will be handled with the Testable trick, but that
194 // can only be used once "operator T*" is removed, since otherwise it leaves 251 // can only be used once "operator T*" is removed, since otherwise it leaves
195 // the call ambiguous. 252 // the call ambiguous.
196 Replacements get_replacements; 253 GetRewriterCallback get_callback(&replacements);
197 GetRewriterCallback get_callback(&get_replacements); 254 match_finder.addMatcher(id("call", safe_conversion_matcher), &get_callback);
198 match_finder.addMatcher(id("call", expr(overloaded_call_matcher)),
199 &get_callback);
200 255
201 #if 0 256 // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*.
202 // Finds all temporary scoped_refptr<T>'s being assigned to a T*. Note that 257 VarRewriterCallback var_callback(&replacements);
203 // this will result in two callbacks--both the above callback to append get()
204 // and this callback will match.
205 match_finder.addMatcher( 258 match_finder.addMatcher(
206 id("var", 259 id("var",
207 varDecl(hasInitializer(ignoringImpCasts( 260 varDecl(hasInitializer(ignoringImpCasts(exprWithCleanups(
208 id("call", expr(overloaded_call_matcher)))), 261 has(id("call", unsafe_conversion_matcher))))),
209 hasType(pointerType()))), 262 hasType(pointerType()))),
210 &callback); 263 &var_callback);
211 match_finder.addMatcher( 264 match_finder.addMatcher(
212 binaryOperator( 265 constructorDecl(forEachConstructorInitializer(allOf(
213 hasOperatorName("="), 266 withInitializer(ignoringImpCasts(
214 hasLHS(declRefExpr(to(id("var", varDecl(hasType(pointerType())))))), 267 exprWithCleanups(has(id("call", unsafe_conversion_matcher))))),
215 hasRHS(ignoringParenImpCasts( 268 forField(id("var", fieldDecl(hasType(pointerType()))))))),
216 id("call", expr(overloaded_call_matcher))))), 269 &var_callback);
217 &callback);
218 #endif
219 270
220 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = 271 std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
221 clang::tooling::newFrontendActionFactory(&match_finder); 272 clang::tooling::newFrontendActionFactory(&match_finder);
222 int result = tool.run(factory.get()); 273 int result = tool.run(factory.get());
223 if (result != 0) 274 if (result != 0)
224 return result; 275 return result;
225 276
226 // Serialization format is documented in tools/clang/scripts/run_tool.py 277 // Serialization format is documented in tools/clang/scripts/run_tool.py
227 llvm::outs() << "==== BEGIN EDITS ====\n"; 278 llvm::outs() << "==== BEGIN EDITS ====\n";
228 for (const auto& r : get_replacements) { 279 for (const auto& r : replacements) {
229 std::string replacement_text = r.getReplacementText().str(); 280 std::string replacement_text = r.getReplacementText().str();
230 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); 281 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
231 llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":" 282 llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
232 << r.getLength() << ":" << replacement_text << "\n"; 283 << r.getLength() << ":" << replacement_text << "\n";
233 } 284 }
234 llvm::outs() << "==== END EDITS ====\n"; 285 llvm::outs() << "==== END EDITS ====\n";
235 286
236 return 0; 287 return 0;
237 } 288 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698