Initial check in
Bug: 137197907
diff --git a/src/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp b/src/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp
new file mode 100644
index 0000000..83ddbcf
--- /dev/null
+++ b/src/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp
@@ -0,0 +1,113 @@
+//===--- MisplacedOperatorInStrlenInAllocCheck.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 "MisplacedOperatorInStrlenInAllocCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void MisplacedOperatorInStrlenInAllocCheck::registerMatchers(
+ MatchFinder *Finder) {
+ const auto StrLenFunc = functionDecl(anyOf(
+ hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"),
+ hasName("::std::strnlen"), hasName("::strnlen_s"),
+ hasName("::std::strnlen_s"), hasName("::wcslen"),
+ hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"),
+ hasName("::wcsnlen_s"), hasName("std::wcsnlen_s")));
+
+ const auto BadUse =
+ callExpr(callee(StrLenFunc),
+ hasAnyArgument(ignoringImpCasts(
+ binaryOperator(
+ hasOperatorName("+"),
+ hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))
+ .bind("BinOp"))))
+ .bind("StrLen");
+
+ const auto BadArg = anyOf(
+ allOf(unless(binaryOperator(
+ hasOperatorName("+"), hasLHS(BadUse),
+ hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))),
+ hasDescendant(BadUse)),
+ BadUse);
+
+ const auto Alloc0Func =
+ functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"),
+ hasName("::alloca"), hasName("std::alloca")));
+ const auto Alloc1Func =
+ functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"),
+ hasName("::realloc"), hasName("std::realloc")));
+
+ const auto Alloc0FuncPtr =
+ varDecl(hasType(isConstQualified()),
+ hasInitializer(ignoringParenImpCasts(
+ declRefExpr(hasDeclaration(Alloc0Func)))));
+ const auto Alloc1FuncPtr =
+ varDecl(hasType(isConstQualified()),
+ hasInitializer(ignoringParenImpCasts(
+ declRefExpr(hasDeclaration(Alloc1Func)))));
+
+ Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))),
+ hasArgument(0, BadArg))
+ .bind("Alloc"),
+ this);
+ Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))),
+ hasArgument(1, BadArg))
+ .bind("Alloc"),
+ this);
+ Finder->addMatcher(
+ cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this);
+}
+
+void MisplacedOperatorInStrlenInAllocCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const Expr *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc");
+ if (!Alloc)
+ Alloc = Result.Nodes.getNodeAs<CXXNewExpr>("Alloc");
+ assert(Alloc && "Matched node bound by 'Alloc' shoud be either 'CallExpr'"
+ " or 'CXXNewExpr'");
+
+ const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen");
+ const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp");
+
+ const StringRef StrLenText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(StrLen->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ const StringRef Arg0Text = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text));
+ const StringRef StrLenEnd = StrLenText.substr(
+ StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size());
+
+ const StringRef LHSText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ const StringRef RHSText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+
+ auto Hint = FixItHint::CreateReplacement(
+ StrLen->getSourceRange(),
+ (StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str());
+
+ diag(Alloc->getBeginLoc(),
+ "addition operator is applied to the argument of %0 instead of its "
+ "result")
+ << StrLen->getDirectCallee()->getName() << Hint;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang