Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -4,6 +4,7 @@ ArgumentCommentCheck.cpp AssertSideEffectCheck.cpp MisplacedConstCheck.cpp + ReplaceMemcpyCheck.cpp UnconventionalAssignOperatorCheck.cpp BoolPointerImplicitConversionCheck.cpp DanglingHandleCheck.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -13,6 +13,7 @@ #include "ArgumentCommentCheck.h" #include "AssertSideEffectCheck.h" #include "MisplacedConstCheck.h" +#include "ReplaceMemcpyCheck.h" #include "UnconventionalAssignOperatorCheck.h" #include "BoolPointerImplicitConversionCheck.h" #include "DanglingHandleCheck.h" @@ -64,6 +65,8 @@ "misc-assert-side-effect"); CheckFactories.registerCheck( "misc-misplaced-const"); + CheckFactories.registerCheck( + "misc-replace-memcpy"); CheckFactories.registerCheck( "misc-unconventional-assign-operator"); CheckFactories.registerCheck( Index: clang-tidy/misc/ReplaceMemcpyCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/ReplaceMemcpyCheck.h @@ -0,0 +1,38 @@ +//===--- ReplaceMemcpyCheck.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_MISC_REPLACE_MEMCPY_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_REPLACE_MEMCPY_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Replaces memcpy with std::copy +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-replace-memcpy.html +class ReplaceMemcpyCheck : public ClangTidyCheck { +public: + ReplaceMemcpyCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + + static StringRef GetText(const Expr *Expression, const SourceManager &SM, + const LangOptions &LangOpts); +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_REPLACE_MEMCPY_H Index: clang-tidy/misc/ReplaceMemcpyCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/ReplaceMemcpyCheck.cpp @@ -0,0 +1,60 @@ +//===--- ReplaceMemcpyCheck.cpp - clang-tidy-------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ReplaceMemcpyCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/FixIt.h" + +#include + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void ReplaceMemcpyCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("memcpy")))).bind("expr"), this); +} + +StringRef ReplaceMemcpyCheck::GetText(const Expr *Expression, + const SourceManager &SM, + const LangOptions &LangOpts) { + return Lexer::getSourceText( + CharSourceRange::getTokenRange(Expression->getSourceRange()), SM, + LangOpts); +} + +void ReplaceMemcpyCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedExpr = Result.Nodes.getNodeAs("expr"); + + if (MatchedExpr->getNumArgs() != 3) + return; + + const auto &SM = *Result.SourceManager; + const auto &LangOptions = Result.Context->getLangOpts(); + + StringRef Destination = GetText(MatchedExpr->getArg(0), SM, LangOptions); + StringRef Source = GetText(MatchedExpr->getArg(1), SM, LangOptions); + StringRef Count = GetText(MatchedExpr->getArg(2), SM, LangOptions); + + const std::string Insertion = "std::copy(" + Source.str() + ", (" + + Source.str() + ") + (" + Count.str() + "), " + + Destination.str() + ")"; + + diag(MatchedExpr->getExprLoc(), "Use std::copy instead of memcyp") + << FixItHint::CreateReplacement(MatchedExpr->getSourceRange(), Insertion); +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -29,6 +29,7 @@ cppcoreguidelines-pro-type-static-cast-downcast cppcoreguidelines-pro-type-union-access cppcoreguidelines-pro-type-vararg + cppcoreguidelines-slicing google-build-explicit-make-pair google-build-namespaces google-build-using-namespace @@ -72,6 +73,7 @@ misc-non-copyable-objects misc-pointer-and-integral-operation misc-redundant-expression + misc-replace-memcpy misc-sizeof-container misc-sizeof-expression misc-static-assert Index: docs/clang-tidy/checks/misc-replace-memcpy.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-replace-memcpy.rst @@ -0,0 +1,18 @@ +.. title:: clang-tidy - misc-replace-memcpy + +misc-replace-memcpy +=================== + +Replaces ``memcpy`` with ``std::copy``. This allows the compiler to decide on +the most performant implementationon. Parenthesis are added devensively to +preclude the summation from taking precedence. + +Example: + +.. code:: c++ + + std::memcpy(dest, source, sizeof dest); + + // transforms to: + + std::copy(source, (source) + (sizeof dest), dest); Index: test/clang-tidy/misc-replace-memcpy.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-replace-memcpy.cpp @@ -0,0 +1,23 @@ +// RUN: %check_clang_tidy %s misc-replace-memcpy %t + +#include +#include +#include + +void f() { + char foo[] = "foo", bar[3], baz[3]; + std::memcpy(bar, foo, sizeof bar); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Use std::copy instead of memcyp [misc-replace-memcpy] + // CHECK-FIXES: std::copy(foo, (foo) + (sizeof bar), bar); + + bool b = false; + std::memcpy(baz, b ? foo : bar, 3); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Use std::copy instead of memcyp [misc-replace-memcpy] + // CHECK-FIXES: std::copy(b ? foo : bar, (b ? foo : bar) + (3), baz); + + memcpy(bar, foo, sizeof bar); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Use std::copy instead of memcyp [misc-replace-memcpy] + // CHECK-FIXES: std::copy(foo, (foo) + (sizeof bar), bar); + + std::copy(foo, foo + sizeof bar, bar); +}