scoped_refptr implicit conversion cleanup tool.
Adapted from rsleevi's original patch. The initial version of the tool rewrites all implicit conversions of scoped_refptr<T> to T*, even unsafe ones where a temporary scoped_refptr<T> is assigned to a T*. A small tweak/hack has also been added to run_tool.py to allow it to handle replacements that contain embedded newlines. BUG=110610 R=mdempsky@chromium.org, thakis@chromium.org Review URL: https://codereview.chromium.org/446203003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288163 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
tools/clang
rewrite_scoped_refptr
MakefileRewriteScopedRefptr.cpp
tests
scoped_refptr.htest1-expected.cctest1-original.cctest10-expected.cctest10-original.cctest11-expected.cctest11-original.cctest12-expected.cctest12-original.cctest2-expected.cctest2-original.cctest3-expected.cctest3-original.cctest4-expected.cctest4-original.cctest5-expected.cctest5-original.cctest6-expected.cctest6-original.cctest7-expected.cctest7-original.cctest8-expected.cctest8-original.cctest9-expected.cctest9-original.cc
scripts
25
tools/clang/rewrite_scoped_refptr/Makefile
Normal file
25
tools/clang/rewrite_scoped_refptr/Makefile
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
# This Makefile requires the LLVM build system. In order to build this tool,
|
||||
# please run tools/clang/scripts/build_tool.py.
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
|
||||
TOOLNAME = rewrite_scoped_refptr
|
||||
|
||||
NO_INSTALL = 1
|
||||
|
||||
include $(CLANG_LEVEL)/../../Makefile.config
|
||||
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
|
||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
|
||||
clangTooling.a clangParse.a clangSema.a \
|
||||
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
|
||||
clangStaticAnalyzerCore.a clangAnalysis.a clangRewriteFrontend.a \
|
||||
clangRewrite.a clangEdit.a clangAST.a clangLex.a clangBasic.a \
|
||||
clangASTMatchers.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
237
tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
Normal file
237
tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// This implements a Clang tool to rewrite all instances of
|
||||
// scoped_refptr<T>'s implicit cast to T (operator T*) to an explicit call to
|
||||
// the .get() method.
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/ASTMatchers/ASTMatchersMacros.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
using clang::tooling::CommonOptionsParser;
|
||||
using clang::tooling::Replacement;
|
||||
using clang::tooling::Replacements;
|
||||
using llvm::StringRef;
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
|
||||
conversionDecl;
|
||||
|
||||
AST_MATCHER(QualType, isBoolean) {
|
||||
return Node->isBooleanType();
|
||||
}
|
||||
|
||||
} // namespace ast_matchers
|
||||
} // namespace clang
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns true if expr needs to be put in parens (eg: when it is an operator
|
||||
// syntactically).
|
||||
bool NeedsParens(const clang::Expr* expr) {
|
||||
if (llvm::dyn_cast<clang::UnaryOperator>(expr) ||
|
||||
llvm::dyn_cast<clang::BinaryOperator>(expr) ||
|
||||
llvm::dyn_cast<clang::ConditionalOperator>(expr)) {
|
||||
return true;
|
||||
}
|
||||
// Calls to an overloaded operator also need parens, except for foo(...) and
|
||||
// foo[...] expressions.
|
||||
if (const clang::CXXOperatorCallExpr* op =
|
||||
llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
|
||||
return op->getOperator() != clang::OO_Call &&
|
||||
op->getOperator() != clang::OO_Subscript;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class GetRewriterCallback : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
explicit GetRewriterCallback(Replacements* replacements)
|
||||
: replacements_(replacements) {}
|
||||
virtual void run(const MatchFinder::MatchResult& result) override;
|
||||
|
||||
private:
|
||||
Replacements* const replacements_;
|
||||
};
|
||||
|
||||
void GetRewriterCallback::run(const MatchFinder::MatchResult& result) {
|
||||
const clang::CXXMemberCallExpr* const implicit_call =
|
||||
result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("call");
|
||||
const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
|
||||
|
||||
if (!implicit_call || !arg)
|
||||
return;
|
||||
|
||||
clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
|
||||
result.SourceManager->getSpellingLoc(arg->getLocStart()),
|
||||
result.SourceManager->getSpellingLoc(arg->getLocEnd()));
|
||||
if (!range.isValid())
|
||||
return; // TODO(rsleevi): Log an error?
|
||||
|
||||
// Handle cases where an implicit cast is being done by dereferencing a
|
||||
// pointer to a scoped_refptr<> (sadly, it happens...)
|
||||
//
|
||||
// This rewrites both "*foo" and "*(foo)" as "foo->get()".
|
||||
if (const clang::UnaryOperator* op =
|
||||
llvm::dyn_cast<clang::UnaryOperator>(arg)) {
|
||||
if (op->getOpcode() == clang::UO_Deref) {
|
||||
const clang::Expr* const sub_expr =
|
||||
op->getSubExpr()->IgnoreParenImpCasts();
|
||||
clang::CharSourceRange sub_expr_range =
|
||||
clang::CharSourceRange::getTokenRange(
|
||||
result.SourceManager->getSpellingLoc(sub_expr->getLocStart()),
|
||||
result.SourceManager->getSpellingLoc(sub_expr->getLocEnd()));
|
||||
if (!sub_expr_range.isValid())
|
||||
return; // TODO(rsleevi): Log an error?
|
||||
std::string inner_text = clang::Lexer::getSourceText(
|
||||
sub_expr_range, *result.SourceManager, result.Context->getLangOpts());
|
||||
if (inner_text.empty())
|
||||
return; // TODO(rsleevi): Log an error?
|
||||
|
||||
if (NeedsParens(sub_expr)) {
|
||||
inner_text.insert(0, "(");
|
||||
inner_text.append(")");
|
||||
}
|
||||
inner_text.append("->get()");
|
||||
replacements_->insert(
|
||||
Replacement(*result.SourceManager, range, inner_text));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string text = clang::Lexer::getSourceText(
|
||||
range, *result.SourceManager, result.Context->getLangOpts());
|
||||
if (text.empty())
|
||||
return; // TODO(rsleevi): Log an error?
|
||||
|
||||
// Unwrap any temporaries - for example, custom iterators that return
|
||||
// scoped_refptr<T> as part of operator*. Any such iterators should also
|
||||
// be declaring a scoped_refptr<T>* operator->, per C++03 24.4.1.1 (Table 72)
|
||||
if (const clang::CXXBindTemporaryExpr* op =
|
||||
llvm::dyn_cast<clang::CXXBindTemporaryExpr>(arg)) {
|
||||
arg = op->getSubExpr();
|
||||
}
|
||||
|
||||
// Handle iterators (which are operator* calls, followed by implicit
|
||||
// conversions) by rewriting *it as it->get()
|
||||
if (const clang::CXXOperatorCallExpr* op =
|
||||
llvm::dyn_cast<clang::CXXOperatorCallExpr>(arg)) {
|
||||
if (op->getOperator() == clang::OO_Star) {
|
||||
// Note that this doesn't rewrite **it correctly, since it should be
|
||||
// rewritten using parens, e.g. (*it)->get(). However, this shouldn't
|
||||
// happen frequently, if at all, since it would likely indicate code is
|
||||
// storing pointers to a scoped_refptr in a container.
|
||||
text.erase(0, 1);
|
||||
text.append("->get()");
|
||||
replacements_->insert(Replacement(*result.SourceManager, range, text));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The only remaining calls should be non-dereferencing calls (eg: member
|
||||
// calls), so a simple ".get()" appending should suffice.
|
||||
if (NeedsParens(arg)) {
|
||||
text.insert(0, "(");
|
||||
text.append(")");
|
||||
}
|
||||
text.append(".get()");
|
||||
replacements_->insert(Replacement(*result.SourceManager, range, text));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
llvm::cl::OptionCategory category("Remove scoped_refptr conversions");
|
||||
CommonOptionsParser options(argc, argv, category);
|
||||
clang::tooling::ClangTool tool(options.getCompilations(),
|
||||
options.getSourcePathList());
|
||||
|
||||
MatchFinder match_finder;
|
||||
|
||||
// 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(
|
||||
thisPointerType(recordDecl(isSameOrDerivedFrom("::scoped_refptr"),
|
||||
isTemplateInstantiation())),
|
||||
callee(conversionDecl()),
|
||||
on(id("arg", expr())));
|
||||
|
||||
// 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 =
|
||||
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))))));
|
||||
|
||||
// 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
|
||||
// them to add a call to get().
|
||||
//
|
||||
// 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.
|
||||
match_finder.addMatcher(
|
||||
id("var",
|
||||
varDecl(hasInitializer(ignoringImpCasts(
|
||||
id("call", expr(overloaded_call_matcher)))),
|
||||
hasType(pointerType()))),
|
||||
&callback);
|
||||
match_finder.addMatcher(
|
||||
binaryOperator(
|
||||
hasOperatorName("="),
|
||||
hasLHS(declRefExpr(to(id("var", varDecl(hasType(pointerType())))))),
|
||||
hasRHS(ignoringParenImpCasts(
|
||||
id("call", expr(overloaded_call_matcher))))),
|
||||
&callback);
|
||||
#endif
|
||||
|
||||
std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
|
||||
clang::tooling::newFrontendActionFactory(&match_finder);
|
||||
int result = tool.run(factory.get());
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
// Serialization format is documented in tools/clang/scripts/run_tool.py
|
||||
llvm::outs() << "==== BEGIN EDITS ====\n";
|
||||
for (const auto& r : get_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() << ":"
|
||||
<< r.getLength() << ":" << replacement_text << "\n";
|
||||
}
|
||||
llvm::outs() << "==== END EDITS ====\n";
|
||||
|
||||
return 0;
|
||||
}
|
43
tools/clang/rewrite_scoped_refptr/tests/scoped_refptr.h
Normal file
43
tools/clang/rewrite_scoped_refptr/tests/scoped_refptr.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SCOPED_REFPTR_H_
|
||||
#define SCOPED_REFPTR_H_
|
||||
|
||||
// Stub scoped_refptr<T> class that supports an implicit cast to T*.
|
||||
template <class T>
|
||||
class scoped_refptr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
scoped_refptr() : ptr_(0) {}
|
||||
scoped_refptr(T* p) : ptr_(p) {}
|
||||
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr(const scoped_refptr<U>& r)
|
||||
: ptr_(r.get()) {}
|
||||
|
||||
~scoped_refptr() {}
|
||||
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
scoped_refptr<T>& operator=(T* p) {
|
||||
ptr_ = p;
|
||||
return *this;
|
||||
}
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
|
||||
return *this = r.ptr_;
|
||||
}
|
||||
template <typename U>
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
|
||||
return *this = r.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
T* ptr_;
|
||||
};
|
||||
|
||||
#endif // SCOPED_REFPTR_H_
|
16
tools/clang/rewrite_scoped_refptr/tests/test1-expected.cc
Normal file
16
tools/clang/rewrite_scoped_refptr/tests/test1-expected.cc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
// Case 1: An example of an unsafe conversion, where the object is freed by
|
||||
// the time the function returns.
|
||||
Foo* GetBuggyFoo() {
|
||||
scoped_refptr<Foo> unsafe(new Foo);
|
||||
return unsafe.get();
|
||||
}
|
16
tools/clang/rewrite_scoped_refptr/tests/test1-original.cc
Normal file
16
tools/clang/rewrite_scoped_refptr/tests/test1-original.cc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
// Case 1: An example of an unsafe conversion, where the object is freed by
|
||||
// the time the function returns.
|
||||
Foo* GetBuggyFoo() {
|
||||
scoped_refptr<Foo> unsafe(new Foo);
|
||||
return unsafe;
|
||||
}
|
16
tools/clang/rewrite_scoped_refptr/tests/test10-expected.cc
Normal file
16
tools/clang/rewrite_scoped_refptr/tests/test10-expected.cc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
int TestsAScopedRefptr() {
|
||||
scoped_refptr<Foo> foo(new Foo);
|
||||
if (foo.get())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
16
tools/clang/rewrite_scoped_refptr/tests/test10-original.cc
Normal file
16
tools/clang/rewrite_scoped_refptr/tests/test10-original.cc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
int TestsAScopedRefptr() {
|
||||
scoped_refptr<Foo> foo(new Foo);
|
||||
if (foo)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
22
tools/clang/rewrite_scoped_refptr/tests/test11-expected.cc
Normal file
22
tools/clang/rewrite_scoped_refptr/tests/test11-expected.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
typedef std::vector<scoped_refptr<Foo> > FooList;
|
||||
|
||||
void TestsAScopedRefptr() {
|
||||
FooList list;
|
||||
list.push_back(new Foo);
|
||||
list.push_back(new Foo);
|
||||
for (FooList::const_iterator it = list.begin(); it != list.end(); ++it) {
|
||||
Foo* item = it->get();
|
||||
}
|
||||
}
|
22
tools/clang/rewrite_scoped_refptr/tests/test11-original.cc
Normal file
22
tools/clang/rewrite_scoped_refptr/tests/test11-original.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
typedef std::vector<scoped_refptr<Foo> > FooList;
|
||||
|
||||
void TestsAScopedRefptr() {
|
||||
FooList list;
|
||||
list.push_back(new Foo);
|
||||
list.push_back(new Foo);
|
||||
for (FooList::const_iterator it = list.begin(); it != list.end(); ++it) {
|
||||
Foo* item = *it;
|
||||
}
|
||||
}
|
45
tools/clang/rewrite_scoped_refptr/tests/test12-expected.cc
Normal file
45
tools/clang/rewrite_scoped_refptr/tests/test12-expected.cc
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, scoped_refptr<const Foo> > MyMap;
|
||||
|
||||
class MyIter
|
||||
: public std::iterator<std::input_iterator_tag, scoped_refptr<const Foo> > {
|
||||
public:
|
||||
MyIter() {}
|
||||
MyIter(const MyIter& other) : it_(other.it_) {}
|
||||
explicit MyIter(MyMap::const_iterator it) : it_(it) {}
|
||||
MyIter& operator++() {
|
||||
++it_;
|
||||
return *this;
|
||||
}
|
||||
const scoped_refptr<const Foo> operator*() { return it_->second; }
|
||||
bool operator!=(const MyIter& other) { return it_ != other.it_; }
|
||||
bool operator==(const MyIter& other) { return it_ == other.it_; }
|
||||
|
||||
private:
|
||||
MyMap::const_iterator it_;
|
||||
};
|
||||
|
||||
void TestsAScopedRefptr() {
|
||||
MyMap map;
|
||||
map["foo"] = new Foo;
|
||||
map["bar"] = new Foo;
|
||||
MyIter my_begin(map.begin());
|
||||
MyIter my_end(map.end());
|
||||
for (MyIter it = my_begin; it != my_end; ++it) {
|
||||
const Foo* item = NULL;
|
||||
item = it->get();
|
||||
}
|
||||
}
|
45
tools/clang/rewrite_scoped_refptr/tests/test12-original.cc
Normal file
45
tools/clang/rewrite_scoped_refptr/tests/test12-original.cc
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, scoped_refptr<const Foo> > MyMap;
|
||||
|
||||
class MyIter
|
||||
: public std::iterator<std::input_iterator_tag, scoped_refptr<const Foo> > {
|
||||
public:
|
||||
MyIter() {}
|
||||
MyIter(const MyIter& other) : it_(other.it_) {}
|
||||
explicit MyIter(MyMap::const_iterator it) : it_(it) {}
|
||||
MyIter& operator++() {
|
||||
++it_;
|
||||
return *this;
|
||||
}
|
||||
const scoped_refptr<const Foo> operator*() { return it_->second; }
|
||||
bool operator!=(const MyIter& other) { return it_ != other.it_; }
|
||||
bool operator==(const MyIter& other) { return it_ == other.it_; }
|
||||
|
||||
private:
|
||||
MyMap::const_iterator it_;
|
||||
};
|
||||
|
||||
void TestsAScopedRefptr() {
|
||||
MyMap map;
|
||||
map["foo"] = new Foo;
|
||||
map["bar"] = new Foo;
|
||||
MyIter my_begin(map.begin());
|
||||
MyIter my_end(map.end());
|
||||
for (MyIter it = my_begin; it != my_end; ++it) {
|
||||
const Foo* item = NULL;
|
||||
item = *it;
|
||||
}
|
||||
}
|
19
tools/clang/rewrite_scoped_refptr/tests/test2-expected.cc
Normal file
19
tools/clang/rewrite_scoped_refptr/tests/test2-expected.cc
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
// Case 2: An example of an unsafe conversion, where the scoped_refptr<> is
|
||||
// returned as a temporary, and as such both it and its object are only valid
|
||||
// for the duration of the full expression.
|
||||
scoped_refptr<Foo> GetBuggyFoo() {
|
||||
return new Foo;
|
||||
}
|
||||
void UseBuggyFoo() {
|
||||
Foo* unsafe = GetBuggyFoo();
|
||||
}
|
19
tools/clang/rewrite_scoped_refptr/tests/test2-original.cc
Normal file
19
tools/clang/rewrite_scoped_refptr/tests/test2-original.cc
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
// Case 2: An example of an unsafe conversion, where the scoped_refptr<> is
|
||||
// returned as a temporary, and as such both it and its object are only valid
|
||||
// for the duration of the full expression.
|
||||
scoped_refptr<Foo> GetBuggyFoo() {
|
||||
return new Foo;
|
||||
}
|
||||
void UseBuggyFoo() {
|
||||
Foo* unsafe = GetBuggyFoo();
|
||||
}
|
22
tools/clang/rewrite_scoped_refptr/tests/test3-expected.cc
Normal file
22
tools/clang/rewrite_scoped_refptr/tests/test3-expected.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
void ExpectsScopedRefptr(const scoped_refptr<Foo>& param) {
|
||||
Foo* foo = param.get();
|
||||
}
|
||||
|
||||
void CallExpectsScopedRefptr() {
|
||||
scoped_refptr<Foo> temp(new Foo);
|
||||
ExpectsScopedRefptr(temp);
|
||||
}
|
||||
|
||||
void CallExpectsScopedRefptrWithRawPtr() {
|
||||
ExpectsScopedRefptr(new Foo);
|
||||
}
|
22
tools/clang/rewrite_scoped_refptr/tests/test3-original.cc
Normal file
22
tools/clang/rewrite_scoped_refptr/tests/test3-original.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
void ExpectsScopedRefptr(const scoped_refptr<Foo>& param) {
|
||||
Foo* foo = param;
|
||||
}
|
||||
|
||||
void CallExpectsScopedRefptr() {
|
||||
scoped_refptr<Foo> temp(new Foo);
|
||||
ExpectsScopedRefptr(temp);
|
||||
}
|
||||
|
||||
void CallExpectsScopedRefptrWithRawPtr() {
|
||||
ExpectsScopedRefptr(new Foo);
|
||||
}
|
22
tools/clang/rewrite_scoped_refptr/tests/test4-expected.cc
Normal file
22
tools/clang/rewrite_scoped_refptr/tests/test4-expected.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
void CallExpectsRawPtrWithScopedRefptr() {
|
||||
scoped_refptr<Foo> ok(new Foo);
|
||||
ExpectsRawPtr(ok.get());
|
||||
}
|
||||
|
||||
void CallExpectsRawPtrWithRawPtr() {
|
||||
ExpectsRawPtr(new Foo);
|
||||
}
|
22
tools/clang/rewrite_scoped_refptr/tests/test4-original.cc
Normal file
22
tools/clang/rewrite_scoped_refptr/tests/test4-original.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
void CallExpectsRawPtrWithScopedRefptr() {
|
||||
scoped_refptr<Foo> ok(new Foo);
|
||||
ExpectsRawPtr(ok);
|
||||
}
|
||||
|
||||
void CallExpectsRawPtrWithRawPtr() {
|
||||
ExpectsRawPtr(new Foo);
|
||||
}
|
23
tools/clang/rewrite_scoped_refptr/tests/test5-expected.cc
Normal file
23
tools/clang/rewrite_scoped_refptr/tests/test5-expected.cc
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct Bar : public Foo {
|
||||
int another_dummy;
|
||||
};
|
||||
|
||||
// Ensure that the correct cast (the user-defined cast) is converted.
|
||||
void ExpectsRawFooPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
void CallExpectsRawFooPtrWithBar() {
|
||||
scoped_refptr<Bar> temp(new Bar);
|
||||
ExpectsRawFooPtr(temp.get());
|
||||
}
|
23
tools/clang/rewrite_scoped_refptr/tests/test5-original.cc
Normal file
23
tools/clang/rewrite_scoped_refptr/tests/test5-original.cc
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct Bar : public Foo {
|
||||
int another_dummy;
|
||||
};
|
||||
|
||||
// Ensure that the correct cast (the user-defined cast) is converted.
|
||||
void ExpectsRawFooPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
void CallExpectsRawFooPtrWithBar() {
|
||||
scoped_refptr<Bar> temp(new Bar);
|
||||
ExpectsRawFooPtr(temp);
|
||||
}
|
24
tools/clang/rewrite_scoped_refptr/tests/test6-expected.cc
Normal file
24
tools/clang/rewrite_scoped_refptr/tests/test6-expected.cc
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct Bar : public Foo {
|
||||
int another_dummy;
|
||||
};
|
||||
|
||||
// Ensure that scoped_refptr<A> -> scoped_refptr<B> conversions are not
|
||||
// converted.
|
||||
void ExpectsScopedPtr(const scoped_refptr<Foo>& foo) {
|
||||
scoped_refptr<Foo> temp(foo);
|
||||
}
|
||||
|
||||
void CallExpectsScopedPtrWithBar() {
|
||||
scoped_refptr<Bar> temp(new Bar);
|
||||
ExpectsScopedPtr(temp);
|
||||
}
|
24
tools/clang/rewrite_scoped_refptr/tests/test6-original.cc
Normal file
24
tools/clang/rewrite_scoped_refptr/tests/test6-original.cc
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct Bar : public Foo {
|
||||
int another_dummy;
|
||||
};
|
||||
|
||||
// Ensure that scoped_refptr<A> -> scoped_refptr<B> conversions are not
|
||||
// converted.
|
||||
void ExpectsScopedPtr(const scoped_refptr<Foo>& foo) {
|
||||
scoped_refptr<Foo> temp(foo);
|
||||
}
|
||||
|
||||
void CallExpectsScopedPtrWithBar() {
|
||||
scoped_refptr<Bar> temp(new Bar);
|
||||
ExpectsScopedPtr(temp);
|
||||
}
|
21
tools/clang/rewrite_scoped_refptr/tests/test7-expected.cc
Normal file
21
tools/clang/rewrite_scoped_refptr/tests/test7-expected.cc
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
// Ensure that de-referencing scoped_refptr<>'s are properly rewritten as
|
||||
// ->get() calls.
|
||||
Foo* GetHeapFoo() {
|
||||
scoped_refptr<Foo>* heap_allocated = new scoped_refptr<Foo>();
|
||||
*heap_allocated = new Foo;
|
||||
return heap_allocated->get();
|
||||
}
|
21
tools/clang/rewrite_scoped_refptr/tests/test7-original.cc
Normal file
21
tools/clang/rewrite_scoped_refptr/tests/test7-original.cc
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
// Ensure that de-referencing scoped_refptr<>'s are properly rewritten as
|
||||
// ->get() calls.
|
||||
Foo* GetHeapFoo() {
|
||||
scoped_refptr<Foo>* heap_allocated = new scoped_refptr<Foo>();
|
||||
*heap_allocated = new Foo;
|
||||
return *heap_allocated;
|
||||
}
|
26
tools/clang/rewrite_scoped_refptr/tests/test8-expected.cc
Normal file
26
tools/clang/rewrite_scoped_refptr/tests/test8-expected.cc
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct Bar : public Foo {
|
||||
int another_dummy;
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
// Ensure that de-referencing scoped_refptr<>'s are properly rewritten as
|
||||
// ->get() calls, and that the correct conversion is rewritten (eg: not the
|
||||
// Bar* -> Foo* conversion).
|
||||
Foo* GetHeapFoo() {
|
||||
scoped_refptr<Bar>* heap_allocated = new scoped_refptr<Bar>();
|
||||
*heap_allocated = new Bar;
|
||||
return heap_allocated->get();
|
||||
}
|
26
tools/clang/rewrite_scoped_refptr/tests/test8-original.cc
Normal file
26
tools/clang/rewrite_scoped_refptr/tests/test8-original.cc
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct Bar : public Foo {
|
||||
int another_dummy;
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* foo) {
|
||||
Foo* temp = foo;
|
||||
}
|
||||
|
||||
// Ensure that de-referencing scoped_refptr<>'s are properly rewritten as
|
||||
// ->get() calls, and that the correct conversion is rewritten (eg: not the
|
||||
// Bar* -> Foo* conversion).
|
||||
Foo* GetHeapFoo() {
|
||||
scoped_refptr<Bar>* heap_allocated = new scoped_refptr<Bar>();
|
||||
*heap_allocated = new Bar;
|
||||
return *heap_allocated;
|
||||
}
|
45
tools/clang/rewrite_scoped_refptr/tests/test9-expected.cc
Normal file
45
tools/clang/rewrite_scoped_refptr/tests/test9-expected.cc
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct HasAScopedRefptr {
|
||||
scoped_refptr<Foo> member;
|
||||
|
||||
const scoped_refptr<Foo>& GetMemberAsScopedRefptr() const { return member; }
|
||||
|
||||
Foo* GetMemberAsRawPtr() const { return member.get(); }
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* param) {
|
||||
Foo* temp = param;
|
||||
}
|
||||
|
||||
void ExpectsScopedRefptr(const scoped_refptr<Foo>& param) {
|
||||
Foo* temp = param.get();
|
||||
}
|
||||
|
||||
void CallsRawWithMemberScopedRefptr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsRawPtr(object.GetMemberAsScopedRefptr().get());
|
||||
}
|
||||
|
||||
void CallsRawWithMemberRawPtr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsRawPtr(object.GetMemberAsRawPtr());
|
||||
}
|
||||
|
||||
void CallsScopedWithMemberScopedRefptr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsScopedRefptr(object.GetMemberAsScopedRefptr());
|
||||
}
|
||||
|
||||
void CallsScopedWithMemberRawPtr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsScopedRefptr(object.GetMemberAsScopedRefptr());
|
||||
}
|
45
tools/clang/rewrite_scoped_refptr/tests/test9-original.cc
Normal file
45
tools/clang/rewrite_scoped_refptr/tests/test9-original.cc
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "scoped_refptr.h"
|
||||
|
||||
struct Foo {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct HasAScopedRefptr {
|
||||
scoped_refptr<Foo> member;
|
||||
|
||||
const scoped_refptr<Foo>& GetMemberAsScopedRefptr() const { return member; }
|
||||
|
||||
Foo* GetMemberAsRawPtr() const { return member; }
|
||||
};
|
||||
|
||||
void ExpectsRawPtr(Foo* param) {
|
||||
Foo* temp = param;
|
||||
}
|
||||
|
||||
void ExpectsScopedRefptr(const scoped_refptr<Foo>& param) {
|
||||
Foo* temp = param.get();
|
||||
}
|
||||
|
||||
void CallsRawWithMemberScopedRefptr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsRawPtr(object.GetMemberAsScopedRefptr());
|
||||
}
|
||||
|
||||
void CallsRawWithMemberRawPtr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsRawPtr(object.GetMemberAsRawPtr());
|
||||
}
|
||||
|
||||
void CallsScopedWithMemberScopedRefptr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsScopedRefptr(object.GetMemberAsScopedRefptr());
|
||||
}
|
||||
|
||||
void CallsScopedWithMemberRawPtr() {
|
||||
HasAScopedRefptr object;
|
||||
ExpectsScopedRefptr(object.GetMemberAsScopedRefptr());
|
||||
}
|
@ -81,6 +81,7 @@ def _ExtractEditsFromStdout(build_directory, stdout):
|
||||
for line in lines[start_index + 1:end_index]:
|
||||
try:
|
||||
edit_type, path, offset, length, replacement = line.split(':', 4)
|
||||
replacement = replacement.replace("\0", "\n");
|
||||
# Normalize the file path emitted by the clang tool to be relative to the
|
||||
# current working directory.
|
||||
path = os.path.relpath(os.path.join(build_directory, path))
|
||||
|
@ -87,12 +87,12 @@ def main(argv):
|
||||
with open(actual, 'r') as f:
|
||||
actual_output = f.readlines()
|
||||
if actual_output != expected_output:
|
||||
print '[ FAILED ] %s' % os.path.relpath(actual)
|
||||
failed += 1
|
||||
for line in difflib.unified_diff(expected_output, actual_output,
|
||||
fromfile=os.path.relpath(expected),
|
||||
tofile=os.path.relpath(actual)):
|
||||
sys.stdout.write(line)
|
||||
print '[ FAILED ] %s' % os.path.relpath(actual)
|
||||
# Don't clean up the file on failure, so the results can be referenced
|
||||
# more easily.
|
||||
continue
|
||||
|
Reference in New Issue
Block a user