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

Unified 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: more changes 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/clang/rewrite_scoped_refptr/tests/const-scoped_refptr&-to-raw-adds-get-expected.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
diff --git a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
index 3f83cec2fc556186a8af728bfe0b16ee4f9b9e2b..1365aaf8d1a15fdc3968ffa89c5518b6e75916a0 100644
--- a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
+++ b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
@@ -155,6 +155,47 @@ void GetRewriterCallback::run(const MatchFinder::MatchResult& result) {
replacements_->insert(Replacement(*result.SourceManager, range, text));
}
+class VarRewriterCallback : public MatchFinder::MatchCallback {
+ public:
+ explicit VarRewriterCallback(Replacements* replacements)
+ : replacements_(replacements) {}
+ virtual void run(const MatchFinder::MatchResult& result) override;
+
+ private:
+ Replacements* const replacements_;
+};
+
+void VarRewriterCallback::run(const MatchFinder::MatchResult& result) {
+ const clang::CXXMemberCallExpr* const implicit_call =
+ result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("call");
+ const clang::DeclaratorDecl* const var_decl =
+ result.Nodes.getNodeAs<clang::DeclaratorDecl>("var");
+
+ if (!implicit_call || !var_decl)
+ return;
+
+ const clang::TypeSourceInfo* tsi = var_decl->getTypeSourceInfo();
+
+ clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
+ result.SourceManager->getSpellingLoc(tsi->getTypeLoc().getBeginLoc()),
+ result.SourceManager->getSpellingLoc(tsi->getTypeLoc().getEndLoc()));
+ if (!range.isValid())
+ return;
+
+ std::string text = clang::Lexer::getSourceText(
+ range, *result.SourceManager, result.Context->getLangOpts());
+ if (text.empty())
+ return;
+ text.erase(text.rfind('*'));
+
+ std::string replacement_text("scoped_refptr<");
+ replacement_text += text;
+ replacement_text += ">";
+
+ replacements_->insert(
+ Replacement(*result.SourceManager, range, replacement_text));
+}
+
} // namespace
static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
@@ -166,25 +207,41 @@ int main(int argc, const char* argv[]) {
options.getSourcePathList());
MatchFinder match_finder;
+ Replacements replacements;
// Finds all calls to conversion operator member function. This catches calls
// to "operator T*", "operator Testable", and "operator bool" equally.
- StatementMatcher overloaded_call_matcher = memberCallExpr(
+ auto base_matcher = memberCallExpr(
thisPointerType(recordDecl(isSameOrDerivedFrom("::scoped_refptr"),
isTemplateInstantiation())),
- callee(conversionDecl()),
- on(id("arg", expr())));
+ callee(conversionDecl()));
+
+ // The heuristic for whether or not a conversion is 'unsafe'. An unsafe
+ // conversion is one where a temporary scoped_refptr<T> is converted to
+ // another type. The matcher provides an exception for a temporary
+ // scoped_refptr that is the result of an operator call. In this case, assume
+ // that it's the result of an iterator dereference, and the container itself
+ // retains the necessary reference, since this is a common idiom to see in
+ // loop bodies.
+ auto is_unsafe_conversion =
+ bindTemporaryExpr(unless(has(operatorCallExpr())));
+
+ auto safe_conversion_matcher = memberCallExpr(
+ base_matcher, on(id("arg", expr(unless(is_unsafe_conversion)))));
+
+ auto unsafe_conversion_matcher =
+ memberCallExpr(base_matcher, on(id("arg", is_unsafe_conversion)));
// This catches both user-defined conversions (eg: "operator bool") and
// standard conversion sequence (C++03 13.3.3.1.1), such as converting a
// pointer to a bool.
- StatementMatcher implicit_to_bool =
+ auto implicit_to_bool =
implicitCastExpr(hasImplicitDestinationType(isBoolean()));
// Avoid converting calls to of "operator Testable" -> "bool" and calls of
// "operator T*" -> "bool".
- StatementMatcher bool_conversion_matcher = hasParent(expr(
- anyOf(expr(implicit_to_bool), expr(hasParent(expr(implicit_to_bool))))));
+ auto bool_conversion_matcher = hasParent(
+ expr(anyOf(implicit_to_bool, expr(hasParent(implicit_to_bool)))));
// Find all calls to an operator overload that do NOT (ultimately) result in
// being cast to a bool - eg: where it's being converted to T* and rewrite
@@ -193,29 +250,23 @@ int main(int argc, const char* argv[]) {
// All bool conversions will be handled with the Testable trick, but that
// can only be used once "operator T*" is removed, since otherwise it leaves
// the call ambiguous.
- Replacements get_replacements;
- GetRewriterCallback get_callback(&get_replacements);
- match_finder.addMatcher(id("call", expr(overloaded_call_matcher)),
- &get_callback);
-
-#if 0
- // Finds all temporary scoped_refptr<T>'s being assigned to a T*. Note that
- // this will result in two callbacks--both the above callback to append get()
- // and this callback will match.
+ GetRewriterCallback get_callback(&replacements);
+ match_finder.addMatcher(id("call", safe_conversion_matcher), &get_callback);
+
+ // Find temporary scoped_refptr<T>'s being unsafely assigned to a T*.
+ VarRewriterCallback var_callback(&replacements);
match_finder.addMatcher(
id("var",
- varDecl(hasInitializer(ignoringImpCasts(
- id("call", expr(overloaded_call_matcher)))),
+ varDecl(hasInitializer(ignoringImpCasts(exprWithCleanups(
+ has(id("call", unsafe_conversion_matcher))))),
hasType(pointerType()))),
- &callback);
+ &var_callback);
match_finder.addMatcher(
- binaryOperator(
- hasOperatorName("="),
- hasLHS(declRefExpr(to(id("var", varDecl(hasType(pointerType())))))),
- hasRHS(ignoringParenImpCasts(
- id("call", expr(overloaded_call_matcher))))),
- &callback);
-#endif
+ constructorDecl(forEachConstructorInitializer(allOf(
+ withInitializer(ignoringImpCasts(
+ exprWithCleanups(has(id("call", unsafe_conversion_matcher))))),
+ forField(id("var", fieldDecl(hasType(pointerType()))))))),
+ &var_callback);
std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
clang::tooling::newFrontendActionFactory(&match_finder);
@@ -225,7 +276,7 @@ int main(int argc, const char* argv[]) {
// Serialization format is documented in tools/clang/scripts/run_tool.py
llvm::outs() << "==== BEGIN EDITS ====\n";
- for (const auto& r : get_replacements) {
+ for (const auto& r : replacements) {
std::string replacement_text = r.getReplacementText().str();
std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
« no previous file with comments | « no previous file | tools/clang/rewrite_scoped_refptr/tests/const-scoped_refptr&-to-raw-adds-get-expected.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698