Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -26,6 +26,7 @@ RedundantStringInitCheck.cpp SimplifyBooleanExprCheck.cpp StaticDefinitionInAnonymousNamespaceCheck.cpp + StrlenArgumentCheck.cpp UniqueptrDeleteReleaseCheck.cpp LINK_LIBS Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -33,6 +33,7 @@ #include "RedundantStringInitCheck.h" #include "SimplifyBooleanExprCheck.h" #include "StaticDefinitionInAnonymousNamespaceCheck.h" +#include "StrlenArgumentCheck.h" #include "UniqueptrDeleteReleaseCheck.h" namespace clang { @@ -72,6 +73,8 @@ "readability-redundant-member-init"); CheckFactories.registerCheck( "readability-static-definition-in-anonymous-namespace"); + CheckFactories.registerCheck( + "readability-strlen-argument"); CheckFactories.registerCheck( "readability-named-parameter"); CheckFactories.registerCheck( Index: clang-tidy/readability/StrlenArgumentCheck.h =================================================================== --- clang-tidy/readability/StrlenArgumentCheck.h +++ clang-tidy/readability/StrlenArgumentCheck.h @@ -0,0 +1,35 @@ +//===--- StrlenArgumentCheck.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_STRLEN_ARGUMENT_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRLEN_ARGUMENT_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Detect pointer addition in strlen() argument. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-strlen-argument.html +class StrlenArgumentCheck : public ClangTidyCheck { +public: + StrlenArgumentCheck(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_STRLEN_ARGUMENT_H Index: clang-tidy/readability/StrlenArgumentCheck.cpp =================================================================== --- clang-tidy/readability/StrlenArgumentCheck.cpp +++ clang-tidy/readability/StrlenArgumentCheck.cpp @@ -0,0 +1,48 @@ +//===--- StrlenArgumentCheck.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 "StrlenArgumentCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +void StrlenArgumentCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("strlen"))), + hasAnyArgument(ignoringParenImpCasts( + binaryOperator(hasOperatorName("+")).bind("B")))) + .bind("CE"), + this); +} + +void StrlenArgumentCheck::check(const MatchFinder::MatchResult &Result) { + const auto *B = Result.Nodes.getNodeAs("B"); + const auto *CE = Result.Nodes.getNodeAs("CE"); + auto D = + diag(B->getExprLoc(), "strlen() argument has pointer addition, it is " + "recommended to subtract the result instead."); + if (!B->getRHS()->getType()->isAnyPointerType()) { + SourceLocation LHSEndLoc = Lexer::getLocForEndOfToken( + B->getLHS()->getLocEnd(), 0, *Result.SourceManager, getLangOpts()); + D << FixItHint::CreateInsertion(LHSEndLoc, ")") + << FixItHint::CreateInsertion(CE->getLocStart(), "(") + << FixItHint::CreateReplacement( + SourceRange(B->getExprLoc(), B->getExprLoc()), "-"); + } +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -169,4 +169,5 @@ readability-redundant-string-init readability-simplify-boolean-expr readability-static-definition-in-anonymous-namespace + readability-strlen-argument readability-uniqueptr-delete-release Index: docs/clang-tidy/checks/readability-strlen-argument.rst =================================================================== --- docs/clang-tidy/checks/readability-strlen-argument.rst +++ docs/clang-tidy/checks/readability-strlen-argument.rst @@ -0,0 +1,18 @@ +.. title:: clang-tidy - readability-strlen-argument + +readability-strlen-argument +=========================== + +This checker will detect addition in strlen() argument. Example code: + +.. code-block:: c++ + + strlen(str + 10) + +With -fix that becomes: + +.. code-block:: c++ + + (strlen(str) - 10) + +For readability it is considered better to subtract the result outside the strlen(). Index: test/clang-tidy/readability-strlen-argument.cpp =================================================================== --- test/clang-tidy/readability-strlen-argument.cpp +++ test/clang-tidy/readability-strlen-argument.cpp @@ -0,0 +1,25 @@ +// RUN: %check_clang_tidy %s readability-strlen-argument %t + +typedef __typeof(sizeof(int)) size_t; +size_t strlen(const char *s); + +void warn1(const char *Str) { + int X; + + // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: strlen() argument has pointer addition, it is recommended to subtract the result instead. [readability-strlen-argument] + X = strlen(Str + 10); + // CHECK-FIXES: {{^}} X = (strlen(Str) - 10);{{$}} + + // CHECK-MESSAGES: :[[@LINE+1]]:17: warning: strlen() argument has pointer addition, it is recommended to subtract the result instead. [readability-strlen-argument] + X = strlen(10 + Str); +} + +struct S { + char *P; +}; +void warn2(const struct S &Par) { + int X; + // CHECK-MESSAGES: :[[@LINE+1]]:20: warning: strlen() argument has pointer addition, it is recommended to subtract the result instead. [readability-strlen-argument] + X = strlen(Par.P + 10); + // CHECK-FIXES: {{^}} X = (strlen(Par.P) - 10);{{$}} +}