forked from OSchip/llvm-project
119 lines
4.4 KiB
C++
119 lines
4.4 KiB
C++
//===--- ContainerDataPointerCheck.cpp - clang-tidy -----------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ContainerDataPointerCheck.h"
|
|
|
|
#include "clang/Lex/Lexer.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
namespace clang {
|
|
namespace tidy {
|
|
namespace readability {
|
|
|
|
constexpr llvm::StringLiteral ContainerExprName = "container-expr";
|
|
constexpr llvm::StringLiteral DerefContainerExprName = "deref-container-expr";
|
|
constexpr llvm::StringLiteral AddrOfContainerExprName =
|
|
"addr-of-container-expr";
|
|
constexpr llvm::StringLiteral AddressOfName = "address-of";
|
|
|
|
ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
|
|
ClangTidyContext *Context)
|
|
: ClangTidyCheck(Name, Context) {}
|
|
|
|
void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) {
|
|
const auto Record =
|
|
cxxRecordDecl(
|
|
isSameOrDerivedFrom(
|
|
namedDecl(
|
|
has(cxxMethodDecl(isPublic(), hasName("data")).bind("data")))
|
|
.bind("container")))
|
|
.bind("record");
|
|
|
|
const auto NonTemplateContainerType =
|
|
qualType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(Record))));
|
|
const auto TemplateContainerType =
|
|
qualType(hasUnqualifiedDesugaredType(templateSpecializationType(
|
|
hasDeclaration(classTemplateDecl(has(Record))))));
|
|
|
|
const auto Container =
|
|
qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
|
|
|
|
const auto ContainerExpr = anyOf(
|
|
unaryOperator(
|
|
hasOperatorName("*"),
|
|
hasUnaryOperand(
|
|
expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
|
|
.bind(ContainerExprName),
|
|
unaryOperator(hasOperatorName("&"),
|
|
hasUnaryOperand(expr(anyOf(hasType(Container),
|
|
hasType(references(Container))))
|
|
.bind(AddrOfContainerExprName)))
|
|
.bind(ContainerExprName),
|
|
expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
|
|
hasType(references(Container))))
|
|
.bind(ContainerExprName));
|
|
|
|
const auto Zero = integerLiteral(equals(0));
|
|
|
|
const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
|
|
|
|
Finder->addMatcher(
|
|
unaryOperator(
|
|
unless(isExpansionInSystemHeader()), hasOperatorName("&"),
|
|
hasUnaryOperand(expr(
|
|
anyOf(cxxOperatorCallExpr(SubscriptOperator, argumentCountIs(2),
|
|
hasArgument(0, ContainerExpr),
|
|
hasArgument(1, Zero)),
|
|
cxxMemberCallExpr(SubscriptOperator, on(ContainerExpr),
|
|
argumentCountIs(1), hasArgument(0, Zero)),
|
|
arraySubscriptExpr(hasLHS(ContainerExpr), hasRHS(Zero))))))
|
|
.bind(AddressOfName),
|
|
this);
|
|
}
|
|
|
|
void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) {
|
|
const auto *UO = Result.Nodes.getNodeAs<UnaryOperator>(AddressOfName);
|
|
const auto *CE = Result.Nodes.getNodeAs<Expr>(ContainerExprName);
|
|
const auto *DCE = Result.Nodes.getNodeAs<Expr>(DerefContainerExprName);
|
|
const auto *ACE = Result.Nodes.getNodeAs<Expr>(AddrOfContainerExprName);
|
|
|
|
if (!UO || !CE)
|
|
return;
|
|
|
|
if (DCE && !CE->getType()->isPointerType())
|
|
CE = DCE;
|
|
else if (ACE)
|
|
CE = ACE;
|
|
|
|
SourceRange SrcRange = CE->getSourceRange();
|
|
|
|
std::string ReplacementText{
|
|
Lexer::getSourceText(CharSourceRange::getTokenRange(SrcRange),
|
|
*Result.SourceManager, getLangOpts())};
|
|
|
|
if (!isa<DeclRefExpr, ArraySubscriptExpr, CXXOperatorCallExpr, CallExpr>(CE))
|
|
ReplacementText = "(" + ReplacementText + ")";
|
|
|
|
if (CE->getType()->isPointerType())
|
|
ReplacementText += "->data()";
|
|
else
|
|
ReplacementText += ".data()";
|
|
|
|
FixItHint Hint =
|
|
FixItHint::CreateReplacement(UO->getSourceRange(), ReplacementText);
|
|
diag(UO->getBeginLoc(),
|
|
"'data' should be used for accessing the data pointer instead of taking "
|
|
"the address of the 0-th element")
|
|
<< Hint;
|
|
}
|
|
} // namespace readability
|
|
} // namespace tidy
|
|
} // namespace clang
|