10 #include "../utils/OptionsUtils.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/ASTMatchers/ASTMatchersInternal.h"
15 #include "clang/ASTMatchers/ASTMatchersMacros.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/raw_ostream.h"
28 return Node.hasTrivialDefaultConstructor();
31 return Node.hasTrivialCopyAssignment() && Node.hasTrivialCopyConstructor();
35 return ast_matchers::internal::HasNameMatcher(String).matchesNode(Node);
56 "operator==",
"operator!=",
"operator<",
57 "operator>",
"operator<=",
"operator>="};
68 llvm::SmallString<512> Buffer;
72 NonTrivialTypesLibcMemoryCallsCheck::NonTrivialTypesLibcMemoryCallsCheck(
75 MemSetNames(Options.get(
"MemSetNames",
"")),
76 MemCpyNames(Options.get(
"MemCpyNames",
"")),
77 MemCmpNames(Options.get(
"MemCmpNames",
"")) {}
87 MatchFinder *Finder) {
88 using namespace ast_matchers::internal;
89 auto IsStructPointer = [](Matcher<CXXRecordDecl> Constraint = anything(),
91 return expr(unaryOperator(
93 hasUnaryOperand(declRefExpr(
94 allOf(hasType(cxxRecordDecl(Constraint)),
95 hasType(Bind ? qualType().bind(
"Record") : qualType()))))));
98 expr(sizeOfExpr(hasArgumentOfType(equalsBoundNode(
"Record"))));
99 auto ArgChecker = [&](Matcher<CXXRecordDecl> RecordConstraint,
100 BindableMatcher<Stmt> SecondArg) {
101 return allOf(argumentCountIs(3),
102 hasArgument(0, IsStructPointer(RecordConstraint,
true)),
103 hasArgument(1, SecondArg), hasArgument(2, IsRecordSizeOf));
110 expr(integerLiteral(equals(0)))))
111 .bind(
"lazyConstruct"),
116 ArgChecker(unless(isTriviallyCopyable()), IsStructPointer()))
124 .bind(
"lazyCompare"),
129 const MatchFinder::MatchResult &Result) {
130 if (
const auto *Caller = Result.Nodes.getNodeAs<CallExpr>(
"lazyConstruct")) {
131 diag(Caller->getBeginLoc(),
"calling %0 on a non-trivially default "
132 "constructible class is undefined")
133 << cast<NamedDecl>(Caller->getCalleeDecl());
135 if (
const auto *Caller = Result.Nodes.getNodeAs<CallExpr>(
"lazyCopy")) {
136 diag(Caller->getBeginLoc(),
137 "calling %0 on a non-trivially copyable class is undefined")
138 << cast<NamedDecl>(Caller->getCalleeDecl());
140 if (
const auto *Caller = Result.Nodes.getNodeAs<CallExpr>(
"lazyCompare")) {
141 diag(Caller->getBeginLoc(),
142 "consider using comparison operators instead of calling %0")
143 << cast<NamedDecl>(Caller->getCalleeDecl());