clang-tools 10.0.0

MisplacedOperatorInStrlenInAllocCheck.cpp
Go to the documentation of this file.
1 //===--- MisplacedOperatorInStrlenInAllocCheck.cpp - clang-tidy------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "MisplacedOperatorInStrlenInAllocCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12
13 using namespace clang::ast_matchers;
14
15 namespace clang {
16 namespace tidy {
17 namespace bugprone {
18
19 void MisplacedOperatorInStrlenInAllocCheck::registerMatchers(
20 MatchFinder *Finder) {
21 const auto StrLenFunc = functionDecl(anyOf(
22 hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"),
23 hasName("::std::strnlen"), hasName("::strnlen_s"),
24 hasName("::std::strnlen_s"), hasName("::wcslen"),
25 hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"),
26 hasName("::wcsnlen_s"), hasName("std::wcsnlen_s")));
27
28 const auto BadUse =
29 callExpr(callee(StrLenFunc),
30 hasAnyArgument(ignoringImpCasts(
31 binaryOperator(
32 hasOperatorName("+"),
33 hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))
34 .bind("BinOp"))))
35 .bind("StrLen");
36
37 const auto BadArg = anyOf(
38 allOf(unless(binaryOperator(
39 hasOperatorName("+"), hasLHS(BadUse),
40 hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))),
41 hasDescendant(BadUse)),
42 BadUse);
43
44 const auto Alloc0Func =
45 functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"),
46 hasName("::alloca"), hasName("std::alloca")));
47 const auto Alloc1Func =
48 functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"),
49 hasName("::realloc"), hasName("std::realloc")));
50
51 const auto Alloc0FuncPtr =
52 varDecl(hasType(isConstQualified()),
53 hasInitializer(ignoringParenImpCasts(
54 declRefExpr(hasDeclaration(Alloc0Func)))));
55 const auto Alloc1FuncPtr =
56 varDecl(hasType(isConstQualified()),
57 hasInitializer(ignoringParenImpCasts(
58 declRefExpr(hasDeclaration(Alloc1Func)))));
59
60 Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))),
61 hasArgument(0, BadArg))
62 .bind("Alloc"),
63 this);
64 Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))),
65 hasArgument(1, BadArg))
66 .bind("Alloc"),
67 this);
68 Finder->addMatcher(
69 cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this);
70 }
71
72 void MisplacedOperatorInStrlenInAllocCheck::check(
73 const MatchFinder::MatchResult &Result) {
74 const Expr *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc");
75 if (!Alloc)
76 Alloc = Result.Nodes.getNodeAs<CXXNewExpr>("Alloc");
77 assert(Alloc && "Matched node bound by 'Alloc' shoud be either 'CallExpr'"
78 " or 'CXXNewExpr'");
79
80 const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen");
81 const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp");
82
83 const StringRef StrLenText = Lexer::getSourceText(
84 CharSourceRange::getTokenRange(StrLen->getSourceRange()),
85 *Result.SourceManager, getLangOpts());
86 const StringRef Arg0Text = Lexer::getSourceText(
87 CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()),
88 *Result.SourceManager, getLangOpts());
89 const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text));
90 const StringRef StrLenEnd = StrLenText.substr(
91 StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size());
92
93 const StringRef LHSText = Lexer::getSourceText(
94 CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()),
95 *Result.SourceManager, getLangOpts());
96 const StringRef RHSText = Lexer::getSourceText(
97 CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()),
98 *Result.SourceManager, getLangOpts());
99
100 auto Hint = FixItHint::CreateReplacement(
101 StrLen->getSourceRange(),
102 (StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str());
103
104 diag(Alloc->getBeginLoc(),
105 "addition operator is applied to the argument of %0 instead of its "
106 "result")
107 << StrLen->getDirectCallee()->getName() << Hint;
108 }
109
110 } // namespace bugprone
111 } // namespace tidy
112 } // namespace clang
clang::ast_matchers
Definition: AbseilMatcher.h:14
MisplacedOperatorInStrlenInAllocCheck.h
clang::clangd::getTokenRange
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Definition: SourceCode.cpp:227
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27