From 57a5c6b56c782d578d86cbf2e58bb403719afdee Mon Sep 17 00:00:00 2001 From: Alexander Kornienko Date: Mon, 16 Mar 2015 00:32:25 +0000 Subject: [PATCH] Move remove-cstr-calls from a standalone executable to a clang-tidy check readability-redundant-string-cstr http://reviews.llvm.org/D7318 Patch by Richard Thomson! llvm-svn: 232338 --- clang-tools-extra/CMakeLists.txt | 1 - .../clang-tidy/readability/CMakeLists.txt | 1 + .../readability/ReadabilityTidyModule.cpp | 16 +- .../readability/RedundantStringCStrCheck.cpp | 138 ++++++++++++ .../readability/RedundantStringCStrCheck.h | 32 +++ clang-tools-extra/remove-cstr-calls/CMakeLists.txt | 17 -- clang-tools-extra/remove-cstr-calls/Makefile | 25 --- .../remove-cstr-calls/RemoveCStrCalls.cpp | 237 --------------------- clang-tools-extra/test/CMakeLists.txt | 1 - .../readability-redundant-string-cstr.cpp | 42 ++++ clang-tools-extra/test/remove-cstr-calls/basic.cpp | 39 ---- 11 files changed, 222 insertions(+), 327 deletions(-) create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h delete mode 100644 clang-tools-extra/remove-cstr-calls/CMakeLists.txt delete mode 100644 clang-tools-extra/remove-cstr-calls/Makefile delete mode 100644 clang-tools-extra/remove-cstr-calls/RemoveCStrCalls.cpp create mode 100644 clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp delete mode 100644 clang-tools-extra/test/remove-cstr-calls/basic.cpp diff --git a/clang-tools-extra/CMakeLists.txt b/clang-tools-extra/CMakeLists.txt index 852fde0..428ed80 100644 --- a/clang-tools-extra/CMakeLists.txt +++ b/clang-tools-extra/CMakeLists.txt @@ -2,7 +2,6 @@ add_subdirectory(clang-apply-replacements) add_subdirectory(clang-modernize) add_subdirectory(clang-rename) add_subdirectory(modularize) -add_subdirectory(remove-cstr-calls) if(CLANG_ENABLE_STATIC_ANALYZER) add_subdirectory(clang-tidy) endif() diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index ca6456f..ed344c5 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_library(clangTidyReadabilityModule FunctionSizeCheck.cpp NamespaceCommentCheck.cpp ReadabilityTidyModule.cpp + RedundantStringCStrCheck.cpp RedundantSmartptrGetCheck.cpp ShrinkToFitCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index e868303..0d3c46b 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -15,6 +15,7 @@ #include "ElseAfterReturnCheck.h" #include "FunctionSizeCheck.h" #include "RedundantSmartptrGetCheck.h" +#include "RedundantStringCStrCheck.h" #include "ShrinkToFitCheck.h" namespace clang { @@ -34,19 +35,20 @@ public: "readability-function-size"); CheckFactories.registerCheck( "readability-redundant-smartptr-get"); - CheckFactories.registerCheck( - "readability-shrink-to-fit"); + CheckFactories.registerCheck( + "readability-redundant-string-cstr"); + CheckFactories.registerCheck("readability-shrink-to-fit"); } }; -} // namespace readability +// Register the ReadabilityModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add + X("readability-module", "Adds readability-related checks."); -// Register the MiscTidyModule using this statically initialized variable. -static ClangTidyModuleRegistry::Add -X("readability-module", "Adds readability-related checks."); +} // namespace readability // This anchor is used to force the linker to link in the generated object file -// and thus register the MiscModule. +// and thus register the ReadabilityModule. volatile int ReadabilityModuleAnchorSource = 0; } // namespace tidy diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp new file mode 100644 index 0000000..7081995 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp @@ -0,0 +1,138 @@ +//===- RedundantStringCStrCheck.cpp - Check for redundant c_str calls -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a check for redundant calls of c_str() on strings. +// +//===----------------------------------------------------------------------===// + +#include "RedundantStringCStrCheck.h" +#include "clang/Lex/Lexer.h" + +namespace clang { + +using namespace ast_matchers; + +namespace { + +template +StringRef getText(const ast_matchers::MatchFinder::MatchResult &Result, + T const &Node) { + return Lexer::getSourceText( + CharSourceRange::getTokenRange(Node.getSourceRange()), + *Result.SourceManager, Result.Context->getLangOpts()); +} + +// Return true if expr needs to be put in parens when it is an argument of a +// prefix unary operator, e.g. when it is a binary or ternary operator +// syntactically. +bool needParensAfterUnaryOperator(const Expr &ExprNode) { + if (isa(&ExprNode) || + isa(&ExprNode)) { + return true; + } + if (const auto *Op = dyn_cast(&ExprNode)) { + return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus && + Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call && + Op->getOperator() != OO_Subscript; + } + return false; +} + +// Format a pointer to an expression: prefix with '*' but simplify +// when it already begins with '&'. Return empty string on failure. +std::string +formatDereference(const ast_matchers::MatchFinder::MatchResult &Result, + const Expr &ExprNode) { + if (const auto *Op = dyn_cast(&ExprNode)) { + if (Op->getOpcode() == UO_AddrOf) { + // Strip leading '&'. + return getText(Result, *Op->getSubExpr()->IgnoreParens()); + } + } + StringRef Text = getText(Result, ExprNode); + if (Text.empty()) + return std::string(); + // Add leading '*'. + if (needParensAfterUnaryOperator(ExprNode)) { + return (llvm::Twine("*(") + Text + ")").str(); + } + return (llvm::Twine("*") + Text).str(); +} + +const char StringConstructor[] = + "::std::basic_string, std::allocator >" + "::basic_string"; + +const char StringCStrMethod[] = + "::std::basic_string, std::allocator >" + "::c_str"; + +} // end namespace + +namespace tidy { +namespace readability { + +void RedundantStringCStrCheck::registerMatchers( + ast_matchers::MatchFinder *Finder) { + Finder->addMatcher( + constructExpr( + hasDeclaration(methodDecl(hasName(StringConstructor))), + argumentCountIs(2), + // The first argument must have the form x.c_str() or p->c_str() + // where the method is string::c_str(). We can use the copy + // constructor of string instead (or the compiler might share + // the string object). + hasArgument( + 0, memberCallExpr(callee(memberExpr().bind("member")), + callee(methodDecl(hasName(StringCStrMethod))), + on(expr().bind("arg"))).bind("call")), + // The second argument is the alloc object which must not be + // present explicitly. + hasArgument(1, defaultArgExpr())), + this); + Finder->addMatcher( + constructExpr( + // Implicit constructors of these classes are overloaded + // wrt. string types and they internally make a StringRef + // referring to the argument. Passing a string directly to + // them is preferred to passing a char pointer. + hasDeclaration( + methodDecl(anyOf(hasName("::llvm::StringRef::StringRef"), + hasName("::llvm::Twine::Twine")))), + argumentCountIs(1), + // The only argument must have the form x.c_str() or p->c_str() + // where the method is string::c_str(). StringRef also has + // a constructor from string which is more efficient (avoids + // strlen), so we can construct StringRef from the string + // directly. + hasArgument( + 0, memberCallExpr(callee(memberExpr().bind("member")), + callee(methodDecl(hasName(StringCStrMethod))), + on(expr().bind("arg"))).bind("call"))), + this); +} + +void RedundantStringCStrCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getStmtAs("call"); + const auto *Arg = Result.Nodes.getStmtAs("arg"); + bool Arrow = Result.Nodes.getStmtAs("member")->isArrow(); + // Replace the "call" node with the "arg" node, prefixed with '*' + // if the call was using '->' rather than '.'. + std::string ArgText = + Arrow ? formatDereference(Result, *Arg) : getText(Result, *Arg).str(); + if (ArgText.empty()) + return; + + diag(Call->getLocStart(), "redundant call to `c_str()`") + << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText); +} + +} // namespace readability +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h new file mode 100644 index 0000000..e1a9126 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h @@ -0,0 +1,32 @@ +//===--- RedundantStringCStrCheck.h - clang-tidy ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSTRINGCSTRCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSTRINGCSTRCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// \brief Finds unnecessary calls to std::string::c_str(). +class RedundantStringCStrCheck : public ClangTidyCheck { +public: + RedundantStringCStrCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSTRINGCSTRCHECK_H diff --git a/clang-tools-extra/remove-cstr-calls/CMakeLists.txt b/clang-tools-extra/remove-cstr-calls/CMakeLists.txt deleted file mode 100644 index ba27280..0000000 --- a/clang-tools-extra/remove-cstr-calls/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Support - ) - -add_clang_executable(remove-cstr-calls - RemoveCStrCalls.cpp - ) - -target_link_libraries(remove-cstr-calls - clangAST - clangASTMatchers - clangBasic - clangFrontend - clangLex - clangTooling - clangToolingCore - ) diff --git a/clang-tools-extra/remove-cstr-calls/Makefile b/clang-tools-extra/remove-cstr-calls/Makefile deleted file mode 100644 index b4110c1..0000000 --- a/clang-tools-extra/remove-cstr-calls/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -##===- tools/extra/remove-cstr-calls/Makefile --------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. - -TOOLNAME = remove-cstr-calls -NO_INSTALL = 1 - -# No plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - -include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option -USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ - clangToolingCore.a clangRewriteFrontend.a clangRewrite.a \ - clangParse.a clangSema.a clangAnalysis.a \ - clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a - -include $(CLANG_LEVEL)/Makefile diff --git a/clang-tools-extra/remove-cstr-calls/RemoveCStrCalls.cpp b/clang-tools-extra/remove-cstr-calls/RemoveCStrCalls.cpp deleted file mode 100644 index 247795f..0000000 --- a/clang-tools-extra/remove-cstr-calls/RemoveCStrCalls.cpp +++ /dev/null @@ -1,237 +0,0 @@ -//===- examples/Tooling/RemoveCStrCalls.cpp - Redundant c_str call removal ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements a tool that prints replacements that remove redundant -// calls of c_str() on strings. -// -// Usage: -// remove-cstr-calls ... -// -// Where is a CMake build directory in which a file named -// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in -// CMake to get this output). -// -// ... specify the paths of files in the CMake source tree. This path -// is looked up in the compile command database. If the path of a file is -// absolute, it needs to point into CMake's source tree. If the path is -// relative, the current working directory needs to be in the CMake source -// tree and the file must be in a subdirectory of the current working -// directory. "./" prefixes in the relative files will be automatically -// removed, but the rest of a relative path must be a suffix of a path in -// the compile command line database. -// -// For example, to use remove-cstr-calls on all files in a subtree of the -// source tree, use: -// -// /path/in/subtree $ find . -name '*.cpp'| -// xargs remove-cstr-calls /path/to/build -// -//===----------------------------------------------------------------------===// - -#include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Lex/Lexer.h" -#include "clang/Tooling/CompilationDatabase.h" -#include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace clang; -using namespace clang::ast_matchers; -using namespace llvm; -using clang::tooling::newFrontendActionFactory; -using clang::tooling::Replacement; -using clang::tooling::CompilationDatabase; - -// FIXME: Pull out helper methods in here into more fitting places. - -// Returns the text that makes up 'node' in the source. -// Returns an empty string if the text cannot be found. -template -static std::string getText(const SourceManager &SourceManager, const T &Node) { - SourceLocation StartSpellingLocation = - SourceManager.getSpellingLoc(Node.getLocStart()); - SourceLocation EndSpellingLocation = - SourceManager.getSpellingLoc(Node.getLocEnd()); - if (!StartSpellingLocation.isValid() || !EndSpellingLocation.isValid()) { - return std::string(); - } - bool Invalid = true; - const char *Text = - SourceManager.getCharacterData(StartSpellingLocation, &Invalid); - if (Invalid) { - return std::string(); - } - std::pair Start = - SourceManager.getDecomposedLoc(StartSpellingLocation); - std::pair End = - SourceManager.getDecomposedLoc(Lexer::getLocForEndOfToken( - EndSpellingLocation, 0, SourceManager, LangOptions())); - if (Start.first != End.first) { - // Start and end are in different files. - return std::string(); - } - if (End.second < Start.second) { - // Shuffling text with macros may cause this. - return std::string(); - } - return std::string(Text, End.second - Start.second); -} - -// Return true if expr needs to be put in parens when it is an argument of a -// prefix unary operator, e.g. when it is a binary or ternary operator -// syntactically. -static bool needParensAfterUnaryOperator(const Expr &ExprNode) { - if (dyn_cast(&ExprNode) || - dyn_cast(&ExprNode)) { - return true; - } - if (const CXXOperatorCallExpr *op = - dyn_cast(&ExprNode)) { - return op->getNumArgs() == 2 && - op->getOperator() != OO_PlusPlus && - op->getOperator() != OO_MinusMinus && - op->getOperator() != OO_Call && - op->getOperator() != OO_Subscript; - } - return false; -} - -// Format a pointer to an expression: prefix with '*' but simplify -// when it already begins with '&'. Return empty string on failure. -static std::string formatDereference(const SourceManager &SourceManager, - const Expr &ExprNode) { - if (const clang::UnaryOperator *Op = - dyn_cast(&ExprNode)) { - if (Op->getOpcode() == UO_AddrOf) { - // Strip leading '&'. - return getText(SourceManager, *Op->getSubExpr()->IgnoreParens()); - } - } - const std::string Text = getText(SourceManager, ExprNode); - if (Text.empty()) return std::string(); - // Add leading '*'. - if (needParensAfterUnaryOperator(ExprNode)) { - return std::string("*(") + Text + ")"; - } - return std::string("*") + Text; -} - -namespace { -class FixCStrCall : public ast_matchers::MatchFinder::MatchCallback { - public: - FixCStrCall(tooling::Replacements *Replace) - : Replace(Replace) {} - - virtual void run(const ast_matchers::MatchFinder::MatchResult &Result) { - const CallExpr *Call = - Result.Nodes.getStmtAs("call"); - const Expr *Arg = - Result.Nodes.getStmtAs("arg"); - const bool Arrow = - Result.Nodes.getStmtAs("member")->isArrow(); - // Replace the "call" node with the "arg" node, prefixed with '*' - // if the call was using '->' rather than '.'. - const std::string ArgText = Arrow ? - formatDereference(*Result.SourceManager, *Arg) : - getText(*Result.SourceManager, *Arg); - if (ArgText.empty()) return; - - Replace->insert(Replacement(*Result.SourceManager, Call, ArgText)); - } - - private: - tooling::Replacements *Replace; -}; -} // end namespace - -const char *StringConstructor = - "::std::basic_string, std::allocator >" - "::basic_string"; - -const char *StringCStrMethod = - "::std::basic_string, std::allocator >" - "::c_str"; - -cl::opt BuildPath( - cl::Positional, - cl::desc("")); - -cl::list SourcePaths( - cl::Positional, - cl::desc(" [... ]"), - cl::OneOrMore); - -int main(int argc, const char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(); - std::unique_ptr Compilations( - tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv)); - cl::ParseCommandLineOptions(argc, argv); - if (!Compilations) { - std::string ErrorMessage; - Compilations = - CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage); - if (!Compilations) - llvm::report_fatal_error(ErrorMessage); - } - tooling::RefactoringTool Tool(*Compilations, SourcePaths); - ast_matchers::MatchFinder Finder; - FixCStrCall Callback(&Tool.getReplacements()); - Finder.addMatcher( - constructExpr( - hasDeclaration(methodDecl(hasName(StringConstructor))), - argumentCountIs(2), - // The first argument must have the form x.c_str() or p->c_str() - // where the method is string::c_str(). We can use the copy - // constructor of string instead (or the compiler might share - // the string object). - hasArgument( - 0, - id("call", memberCallExpr( - callee(id("member", memberExpr())), - callee(methodDecl(hasName(StringCStrMethod))), - on(id("arg", expr()))))), - // The second argument is the alloc object which must not be - // present explicitly. - hasArgument( - 1, - defaultArgExpr())), - &Callback); - Finder.addMatcher( - constructExpr( - // Implicit constructors of these classes are overloaded - // wrt. string types and they internally make a StringRef - // referring to the argument. Passing a string directly to - // them is preferred to passing a char pointer. - hasDeclaration(methodDecl(anyOf( - hasName("::llvm::StringRef::StringRef"), - hasName("::llvm::Twine::Twine")))), - argumentCountIs(1), - // The only argument must have the form x.c_str() or p->c_str() - // where the method is string::c_str(). StringRef also has - // a constructor from string which is more efficient (avoids - // strlen), so we can construct StringRef from the string - // directly. - hasArgument( - 0, - id("call", memberCallExpr( - callee(id("member", memberExpr())), - callee(methodDecl(hasName(StringCStrMethod))), - on(id("arg", expr())))))), - &Callback); - return Tool.runAndSave(newFrontendActionFactory(&Finder).get()); -} diff --git a/clang-tools-extra/test/CMakeLists.txt b/clang-tools-extra/test/CMakeLists.txt index 298fa28..8f09531 100644 --- a/clang-tools-extra/test/CMakeLists.txt +++ b/clang-tools-extra/test/CMakeLists.txt @@ -42,7 +42,6 @@ set(CLANG_TOOLS_TEST_DEPS clang-tidy modularize pp-trace - remove-cstr-calls # Unit tests ExtraToolsUnitTests diff --git a/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp b/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp new file mode 100644 index 0000000..42f4307 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp @@ -0,0 +1,42 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-redundant-string-cstr %t +// REQUIRES: shell + +namespace std { +template +class allocator {}; +template +class char_traits {}; +template +struct basic_string { + basic_string(); + basic_string(const C *p, const A &a = A()); + const C *c_str() const; +}; +typedef basic_string, std::allocator> string; +} +namespace llvm { +struct StringRef { + StringRef(const char *p); + StringRef(const std::string &); +}; +} + +void f1(const std::string &s) { + f1(s.c_str()); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to `c_str()` [readability-redundant-string-cstr] + // CHECK-FIXES: {{^ }}f1(s);{{$}} +} +void f2(const llvm::StringRef r) { + std::string s; + f2(s.c_str()); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}} + // CHECK-FIXES: {{^ }}std::string s;{{$}} + // CHECK-FIXES-NEXT: {{^ }}f2(s);{{$}} +} +void f3(const llvm::StringRef &r) { + std::string s; + f3(s.c_str()); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}} + // CHECK-FIXES: {{^ }}std::string s;{{$}} + // CHECK-FIXES-NEXT: {{^ }}f3(s);{{$}} +} diff --git a/clang-tools-extra/test/remove-cstr-calls/basic.cpp b/clang-tools-extra/test/remove-cstr-calls/basic.cpp deleted file mode 100644 index b63488d..0000000 --- a/clang-tools-extra/test/remove-cstr-calls/basic.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: remove-cstr-calls . %t.cpp -- -// RUN: FileCheck -input-file=%t.cpp %s -// REQUIRES: shell - -namespace std { -template class allocator {}; -template class char_traits {}; -template struct basic_string { - basic_string(); - basic_string(const C *p, const A& a = A()); - const C *c_str() const; -}; -typedef basic_string, std::allocator > string; -} -namespace llvm { -struct StringRef { - StringRef(const char *p); - StringRef(const std::string &); -}; -} - -void f1(const std::string &s) { - f1(s.c_str()); - // CHECK: void f1 - // CHECK-NEXT: f1(s) -} -void f2(const llvm::StringRef r) { - std::string s; - f2(s.c_str()); - // CHECK: std::string s; - // CHECK-NEXT: f2(s) -} -void f3(const llvm::StringRef &r) { - std::string s; - f3(s.c_str()); - // CHECK: std::string s; - // CHECK: f3(s) -} -- 2.7.4