| Index: tools/clang/rewrite_scoped_ptr_ctor_null/RewriteScopedPtrCtorNull.cpp
|
| diff --git a/tools/clang/empty_string/EmptyStringConverter.cpp b/tools/clang/rewrite_scoped_ptr_ctor_null/RewriteScopedPtrCtorNull.cpp
|
| similarity index 68%
|
| copy from tools/clang/empty_string/EmptyStringConverter.cpp
|
| copy to tools/clang/rewrite_scoped_ptr_ctor_null/RewriteScopedPtrCtorNull.cpp
|
| index 421f964bbd6d4967ab6779ad9f74c0dce82ffeb0..c1b25edf18053f0c80cdc2b94815388477685b60 100644
|
| --- a/tools/clang/empty_string/EmptyStringConverter.cpp
|
| +++ b/tools/clang/rewrite_scoped_ptr_ctor_null/RewriteScopedPtrCtorNull.cpp
|
| @@ -21,18 +21,16 @@ using clang::ast_matchers::argumentCountIs;
|
| using clang::ast_matchers::bindTemporaryExpr;
|
| using clang::ast_matchers::constructorDecl;
|
| using clang::ast_matchers::constructExpr;
|
| -using clang::ast_matchers::defaultArgExpr;
|
| using clang::ast_matchers::expr;
|
| using clang::ast_matchers::forEach;
|
| using clang::ast_matchers::has;
|
| using clang::ast_matchers::hasArgument;
|
| using clang::ast_matchers::hasDeclaration;
|
| -using clang::ast_matchers::hasName;
|
| +using clang::ast_matchers::matchesName;
|
| using clang::ast_matchers::id;
|
| using clang::ast_matchers::methodDecl;
|
| using clang::ast_matchers::newExpr;
|
| using clang::ast_matchers::ofClass;
|
| -using clang::ast_matchers::stringLiteral;
|
| using clang::ast_matchers::varDecl;
|
| using clang::tooling::CommonOptionsParser;
|
| using clang::tooling::Replacement;
|
| @@ -40,9 +38,16 @@ using clang::tooling::Replacements;
|
|
|
| namespace {
|
|
|
| +bool IsNullConstant(const clang::Expr& expr, clang::ASTContext* context) {
|
| + return expr.isNullPointerConstant(*context,
|
| + clang::Expr::NPC_ValueDependentIsNotNull) !=
|
| + clang::Expr::NPCK_NotNull;
|
| +}
|
| +
|
| // Handles replacements for stack and heap-allocated instances, e.g.:
|
| -// std::string a("");
|
| -// std::string* b = new std::string("");
|
| +// scoped_ptr<T> a(NULL);
|
| +// scoped_ptr<T>* b = new scoped_ptr<T>(NULL);
|
| +// ...though the latter should be pretty rare.
|
| class ConstructorCallback : public MatchFinder::MatchCallback {
|
| public:
|
| ConstructorCallback(Replacements* replacements)
|
| @@ -54,7 +59,7 @@ class ConstructorCallback : public MatchFinder::MatchCallback {
|
| Replacements* const replacements_;
|
| };
|
|
|
| -// Handles replacements for invocations of std::string("") in an initializer
|
| +// Handles replacements for invocations of scoped_ptr<T>(NULL) in an initializer
|
| // list.
|
| class InitializerCallback : public MatchFinder::MatchCallback {
|
| public:
|
| @@ -67,9 +72,8 @@ class InitializerCallback : public MatchFinder::MatchCallback {
|
| Replacements* const replacements_;
|
| };
|
|
|
| -// Handles replacements for invocations of std::string("") in a temporary
|
| -// context, e.g. FunctionThatTakesString(std::string("")). Note that this
|
| -// handles implicits construction of std::string as well.
|
| +// Handles replacements for invocations of scoped_ptr<T>(NULL) in a temporary
|
| +// context, e.g. return scoped_ptr<T>(NULL).
|
| class TemporaryCallback : public MatchFinder::MatchCallback {
|
| public:
|
| TemporaryCallback(Replacements* replacements) : replacements_(replacements) {}
|
| @@ -96,32 +100,26 @@ class EmptyStringConverter {
|
| };
|
|
|
| void EmptyStringConverter::SetupMatchers(MatchFinder* match_finder) {
|
| - const clang::ast_matchers::StatementMatcher& constructor_call =
|
| - id("call",
|
| - constructExpr(
|
| - hasDeclaration(methodDecl(ofClass(hasName("std::basic_string")))),
|
| - argumentCountIs(2),
|
| - hasArgument(0, id("literal", stringLiteral())),
|
| - hasArgument(1, defaultArgExpr())));
|
| -
|
| - // Note that expr(has()) in the matcher is significant; the Clang AST wraps
|
| - // calls to the std::string constructor with exprWithCleanups nodes. Without
|
| - // the expr(has()) matcher, the first and last rules would not match anything!
|
| - match_finder->addMatcher(varDecl(forEach(expr(has(constructor_call)))),
|
| + const char kPattern[] = "^::(scoped_ptr|scoped_ptr_malloc)$";
|
| + const clang::ast_matchers::StatementMatcher& constructor_call = id(
|
| + "call",
|
| + constructExpr(hasDeclaration(methodDecl(ofClass(matchesName(kPattern)))),
|
| + argumentCountIs(1),
|
| + hasArgument(0, id("arg", expr()))));
|
| +
|
| + match_finder->addMatcher(varDecl(forEach(constructor_call)),
|
| &constructor_callback_);
|
| match_finder->addMatcher(newExpr(has(constructor_call)),
|
| &constructor_callback_);
|
| match_finder->addMatcher(bindTemporaryExpr(has(constructor_call)),
|
| &temporary_callback_);
|
| - match_finder->addMatcher(
|
| - constructorDecl(forEach(expr(has(constructor_call)))),
|
| - &initializer_callback_);
|
| + match_finder->addMatcher(constructorDecl(forEach(constructor_call)),
|
| + &initializer_callback_);
|
| }
|
|
|
| void ConstructorCallback::run(const MatchFinder::MatchResult& result) {
|
| - const clang::StringLiteral* literal =
|
| - result.Nodes.getNodeAs<clang::StringLiteral>("literal");
|
| - if (literal->getLength() > 0)
|
| + const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
|
| + if (!IsNullConstant(*arg, result.Context))
|
| return;
|
|
|
| const clang::CXXConstructExpr* call =
|
| @@ -132,9 +130,8 @@ void ConstructorCallback::run(const MatchFinder::MatchResult& result) {
|
| }
|
|
|
| void InitializerCallback::run(const MatchFinder::MatchResult& result) {
|
| - const clang::StringLiteral* literal =
|
| - result.Nodes.getNodeAs<clang::StringLiteral>("literal");
|
| - if (literal->getLength() > 0)
|
| + const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
|
| + if (!IsNullConstant(*arg, result.Context))
|
| return;
|
|
|
| const clang::CXXConstructExpr* call =
|
| @@ -143,26 +140,23 @@ void InitializerCallback::run(const MatchFinder::MatchResult& result) {
|
| }
|
|
|
| void TemporaryCallback::run(const MatchFinder::MatchResult& result) {
|
| - const clang::StringLiteral* literal =
|
| - result.Nodes.getNodeAs<clang::StringLiteral>("literal");
|
| - if (literal->getLength() > 0)
|
| + const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
|
| + if (!IsNullConstant(*arg, result.Context))
|
| return;
|
|
|
| - const clang::CXXConstructExpr* call =
|
| - result.Nodes.getNodeAs<clang::CXXConstructExpr>("call");
|
| - // Differentiate between explicit and implicit calls to std::string's
|
| - // constructor. An implicitly generated constructor won't have a valid
|
| - // source range for the parenthesis. We do this because the matched expression
|
| - // for |call| in the explicit case doesn't include the closing parenthesis.
|
| - clang::SourceRange range = call->getParenRange();
|
| - if (range.isValid()) {
|
| - replacements_->insert(Replacement(*result.SourceManager, literal, ""));
|
| - } else {
|
| - replacements_->insert(
|
| - Replacement(*result.SourceManager,
|
| - call,
|
| - literal->isWide() ? "std::wstring()" : "std::string()"));
|
| - }
|
| + // TODO(dcheng): File a bug with clang. There should be an easier way to do
|
| + // this replacement, but getTokenRange(call->getParenRange()) and the obvious
|
| + // (but incorrect) arg both don't work. The former is presumably just buggy,
|
| + // while the latter probably has to do with the fact that NULL is actually a
|
| + // macro which expands to a built-in.
|
| + clang::SourceRange range = arg->getSourceRange();
|
| + clang::SourceRange expansion_range(
|
| + result.SourceManager->getExpansionLoc(range.getBegin()),
|
| + result.SourceManager->getExpansionLoc(range.getEnd()));
|
| + replacements_->insert(
|
| + Replacement(*result.SourceManager,
|
| + clang::CharSourceRange::getTokenRange(expansion_range),
|
| + ""));
|
| }
|
|
|
| } // namespace
|
| @@ -190,7 +184,8 @@ int main(int argc, const char* argv[]) {
|
| // TODO(dcheng): Use a more clever serialization.
|
| llvm::outs() << "==== BEGIN EDITS ====\n";
|
| for (Replacements::const_iterator it = replacements.begin();
|
| - it != replacements.end(); ++it) {
|
| + it != replacements.end();
|
| + ++it) {
|
| llvm::outs() << "r:" << it->getFilePath() << ":" << it->getOffset() << ":"
|
| << it->getLength() << ":" << it->getReplacementText() << "\n";
|
| }
|
|
|