forked from OSchip/llvm-project
118 lines
4.9 KiB
C++
118 lines
4.9 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 {
|
|
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));
|
|
|
|
Finder->addMatcher(
|
|
unaryOperator(
|
|
unless(isExpansionInSystemHeader()), hasOperatorName("&"),
|
|
hasUnaryOperand(anyOf(
|
|
ignoringParenImpCasts(
|
|
cxxOperatorCallExpr(
|
|
callee(cxxMethodDecl(hasName("operator[]"))
|
|
.bind("operator[]")),
|
|
argumentCountIs(2),
|
|
hasArgument(
|
|
0,
|
|
anyOf(ignoringParenImpCasts(
|
|
declRefExpr(
|
|
to(varDecl(anyOf(
|
|
hasType(Container),
|
|
hasType(references(Container))))))
|
|
.bind("var")),
|
|
ignoringParenImpCasts(hasDescendant(
|
|
declRefExpr(
|
|
to(varDecl(anyOf(
|
|
hasType(Container),
|
|
hasType(pointsTo(Container)),
|
|
hasType(references(Container))))))
|
|
.bind("var"))))),
|
|
hasArgument(1,
|
|
ignoringParenImpCasts(
|
|
integerLiteral(equals(0)).bind("zero"))))
|
|
.bind("operator-call")),
|
|
ignoringParenImpCasts(
|
|
cxxMemberCallExpr(
|
|
hasDescendant(
|
|
declRefExpr(to(varDecl(anyOf(
|
|
hasType(Container),
|
|
hasType(references(Container))))))
|
|
.bind("var")),
|
|
argumentCountIs(1),
|
|
hasArgument(0,
|
|
ignoringParenImpCasts(
|
|
integerLiteral(equals(0)).bind("zero"))))
|
|
.bind("member-call")),
|
|
ignoringParenImpCasts(
|
|
arraySubscriptExpr(
|
|
hasLHS(ignoringParenImpCasts(
|
|
declRefExpr(to(varDecl(anyOf(
|
|
hasType(Container),
|
|
hasType(references(Container))))))
|
|
.bind("var"))),
|
|
hasRHS(ignoringParenImpCasts(
|
|
integerLiteral(equals(0)).bind("zero"))))
|
|
.bind("array-subscript")))))
|
|
.bind("address-of"),
|
|
this);
|
|
}
|
|
|
|
void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) {
|
|
const auto *UO = Result.Nodes.getNodeAs<UnaryOperator>("address-of");
|
|
const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>("var");
|
|
|
|
std::string ReplacementText;
|
|
ReplacementText = std::string(Lexer::getSourceText(
|
|
CharSourceRange::getTokenRange(DRE->getSourceRange()),
|
|
*Result.SourceManager, getLangOpts()));
|
|
if (DRE->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
|