diff options
author | Alexander Kornienko <alexfh@google.com> | 2015-09-10 16:37:46 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2015-09-10 16:37:46 +0000 |
commit | 7532d3e93d3980d628f10c63c2bc97bca2e7c2c1 (patch) | |
tree | 39a8b5ff46f69b31cdaacdf4b95512a9a63bd93c /clang-tools-extra/clang-tidy/misc/SizeofContainerCheck.cpp | |
parent | e3b1f2b7658ea22b13d6bae34f5ac4c9f4dc8fc6 (diff) | |
download | bcm5719-llvm-7532d3e93d3980d628f10c63c2bc97bca2e7c2c1.tar.gz bcm5719-llvm-7532d3e93d3980d628f10c63c2bc97bca2e7c2c1.zip |
[clang-tidy] Add misc-sizeof-container check to find sizeof() uses on stl
containers.
Summary:
sizeof(some_std_string) is likely to be an error. This check finds this
pattern and suggests using .size() instead.
Reviewers: djasper, klimek, aaron.ballman
Subscribers: aaron.ballman, cfe-commits
Differential Revision: http://reviews.llvm.org/D12759
llvm-svn: 247297
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc/SizeofContainerCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/misc/SizeofContainerCheck.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/SizeofContainerCheck.cpp b/clang-tools-extra/clang-tidy/misc/SizeofContainerCheck.cpp new file mode 100644 index 00000000000..44753b93382 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/SizeofContainerCheck.cpp @@ -0,0 +1,83 @@ +//===--- SizeofContainerCheck.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 "SizeofContainerCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +namespace { + +bool needsParens(const Expr *E) { + E = E->IgnoreImpCasts(); + if (isa<BinaryOperator>(E) || isa<ConditionalOperator>(E)) + return true; + if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(E)) { + return Op->getNumArgs() == 2 && Op->getOperator() != OO_Call && + Op->getOperator() != OO_Subscript; + } + return false; +} + +} // anonymous namespace + +void SizeofContainerCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + expr(unless(isInTemplateInstantiation()), + expr(sizeOfExpr(has(expr(hasType(hasCanonicalType(hasDeclaration( + recordDecl(matchesName("^(::std::|::string)"), + hasMethod(methodDecl(hasName("size"), isPublic(), + isConst())))))))))) + .bind("sizeof"), + // Ignore ARRAYSIZE(<array of containers>) pattern. + unless(hasAncestor(binaryOperator( + anyOf(hasOperatorName("/"), hasOperatorName("%")), + hasLHS(ignoringParenCasts(sizeOfExpr(expr()))), + hasRHS(ignoringParenCasts(equalsBoundNode("sizeof"))))))), + this); +} + +void SizeofContainerCheck::check(const MatchFinder::MatchResult &Result) { + const auto *SizeOf = + Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof"); + + SourceLocation SizeOfLoc = SizeOf->getLocStart(); + auto Diag = diag(SizeOfLoc, "sizeof() doesn't return the size of the " + "container; did you mean .size()?"); + + // Don't generate fixes for macros. + if (SizeOfLoc.isMacroID()) + return; + + SourceLocation RParenLoc = SizeOf->getRParenLoc(); + + // sizeof argument is wrapped in a single ParenExpr. + const auto *Arg = cast<ParenExpr>(SizeOf->getArgumentExpr()); + + if (needsParens(Arg->getSubExpr())) { + Diag << FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(SizeOfLoc, SizeOfLoc)) + << FixItHint::CreateInsertion(RParenLoc.getLocWithOffset(1), + ".size()"); + } else { + Diag << FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(SizeOfLoc, Arg->getLParen())) + << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(RParenLoc, RParenLoc), + ".size()"); + } +} + +} // namespace tidy +} // namespace clang + |