Commit 7ee5b51e authored by dcheng@chromium.org's avatar dcheng@chromium.org

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
parent bdbf5cb2
# 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
// 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;
}
// 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_
// 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();
}
// 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;
}
// 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;
}
// 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;
}
// 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();
}
}
// 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;
}
}
// 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();
}
}
// 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;
}
}
// 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();
}
// 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();
}
// 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);
}
// 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);
}
// 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);
}
// 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);
}
// 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());
}
// 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);
}
// 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);
}
// 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);
}
// 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();
}
// 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;
}
// 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();
}
// 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;
}
// 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());
}
// 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): ...@@ -81,6 +81,7 @@ def _ExtractEditsFromStdout(build_directory, stdout):
for line in lines[start_index + 1:end_index]: for line in lines[start_index + 1:end_index]:
try: try:
edit_type, path, offset, length, replacement = line.split(':', 4) 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 # Normalize the file path emitted by the clang tool to be relative to the
# current working directory. # current working directory.
path = os.path.relpath(os.path.join(build_directory, path)) path = os.path.relpath(os.path.join(build_directory, path))
......
...@@ -87,12 +87,12 @@ def main(argv): ...@@ -87,12 +87,12 @@ def main(argv):
with open(actual, 'r') as f: with open(actual, 'r') as f:
actual_output = f.readlines() actual_output = f.readlines()
if actual_output != expected_output: if actual_output != expected_output:
print '[ FAILED ] %s' % os.path.relpath(actual)
failed += 1 failed += 1
for line in difflib.unified_diff(expected_output, actual_output, for line in difflib.unified_diff(expected_output, actual_output,
fromfile=os.path.relpath(expected), fromfile=os.path.relpath(expected),
tofile=os.path.relpath(actual)): tofile=os.path.relpath(actual)):
sys.stdout.write(line) 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 # Don't clean up the file on failure, so the results can be referenced
# more easily. # more easily.
continue continue
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment