10 #include "../utils/Matchers.h" 11 #include "../utils/OptionsUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 22 namespace cppcoreguidelines {
27 Matcher<FunctionDecl> hasAnyListedName(
const std::string &FunctionNames) {
28 const std::vector<std::string> NameList =
30 return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
35 Options.store(Opts,
"LegacyResourceProducers", LegacyResourceProducers);
36 Options.store(Opts,
"LegacyResourceConsumers", LegacyResourceConsumers);
41 void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
42 if (!getLangOpts().CPlusPlus11)
45 const auto OwnerDecl = typeAliasTemplateDecl(hasName(
"::gsl::owner"));
46 const auto IsOwnerType = hasType(OwnerDecl);
48 const auto LegacyCreatorFunctions = hasAnyListedName(LegacyResourceProducers);
49 const auto LegacyConsumerFunctions =
50 hasAnyListedName(LegacyResourceConsumers);
54 const auto CreatesLegacyOwner =
55 callExpr(callee(functionDecl(LegacyCreatorFunctions)));
59 const auto LegacyOwnerCast =
60 castExpr(hasSourceExpression(CreatesLegacyOwner));
63 const auto LegacyOwnerConsumers = functionDecl(LegacyConsumerFunctions);
65 const auto CreatesOwner =
68 functionDecl(returns(qualType(hasDeclaration(OwnerDecl)))))),
69 CreatesLegacyOwner, LegacyOwnerCast);
71 const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwner);
77 declRefExpr(unless(ConsideredOwner)).bind(
"deleted_variable")))
89 callExpr(callee(LegacyOwnerConsumers),
90 hasAnyArgument(expr(unless(ignoringImpCasts(ConsideredOwner)),
91 hasType(pointerType()))))
92 .bind(
"legacy_consumer"),
97 Finder->addMatcher(binaryOperator(matchers::isAssignmentOperator(),
99 hasRHS(unless(ConsideredOwner)))
100 .bind(
"owner_assignment"),
105 namedDecl(varDecl(hasInitializer(unless(ConsideredOwner)), IsOwnerType)
106 .bind(
"owner_initialization")),
109 const auto HasConstructorInitializerForOwner =
110 has(cxxConstructorDecl(forEachConstructorInitializer(
112 isMemberInitializer(), forField(IsOwnerType),
116 allOf(unless(ConsideredOwner), unless(parenListExpr()))))
117 .bind(
"owner_member_initializer"))));
121 Finder->addMatcher(cxxRecordDecl(HasConstructorInitializerForOwner),
this);
125 Finder->addMatcher(binaryOperator(matchers::isAssignmentOperator(),
126 hasLHS(unless(IsOwnerType)),
127 hasRHS(CreatesOwner))
128 .bind(
"bad_owner_creation_assignment"),
134 namedDecl(varDecl(eachOf(allOf(hasInitializer(CreatesOwner),
135 unless(IsOwnerType)),
136 allOf(hasInitializer(ConsideredOwner),
137 hasType(autoType().bind(
"deduced_type")))))
138 .bind(
"bad_owner_creation_variable")),
144 callExpr(forEachArgumentWithParam(
145 expr(unless(ConsideredOwner)).bind(
"expected_owner_argument"),
146 parmVarDecl(IsOwnerType))),
151 Finder->addMatcher(callExpr(forEachArgumentWithParam(
152 expr(CreatesOwner).bind(
"bad_owner_creation_argument"),
153 parmVarDecl(unless(IsOwnerType))
154 .bind(
"bad_owner_creation_parameter"))),
160 functionDecl(hasDescendant(returnStmt(hasReturnValue(ConsideredOwner))
161 .bind(
"bad_owner_return")),
162 unless(returns(qualType(hasDeclaration(OwnerDecl)))))
163 .bind(
"function_decl"),
170 has(fieldDecl(IsOwnerType).bind(
"undestructed_owner_member")),
171 anyOf(unless(has(cxxDestructorDecl())),
172 has(cxxDestructorDecl(anyOf(isDefaulted(), isDeleted())))))
173 .bind(
"non_destructor_class"),
177 void OwningMemoryCheck::check(
const MatchFinder::MatchResult &
Result) {
178 const auto &Nodes = Result.Nodes;
180 bool CheckExecuted =
false;
181 CheckExecuted |= handleDeletion(Nodes);
182 CheckExecuted |= handleLegacyConsumers(Nodes);
183 CheckExecuted |= handleExpectedOwner(Nodes);
184 CheckExecuted |= handleAssignmentAndInit(Nodes);
185 CheckExecuted |= handleAssignmentFromNewOwner(Nodes);
186 CheckExecuted |= handleReturnValues(Nodes);
187 CheckExecuted |= handleOwnerMembers(Nodes);
189 assert(CheckExecuted &&
190 "None of the subroutines executed, logic error in matcher!");
193 bool OwningMemoryCheck::handleDeletion(
const BoundNodes &Nodes) {
195 const auto *DeleteStmt = Nodes.getNodeAs<CXXDeleteExpr>(
"delete_expr");
196 const auto *DeletedVariable =
197 Nodes.getNodeAs<DeclRefExpr>(
"deleted_variable");
201 diag(DeleteStmt->getBeginLoc(),
202 "deleting a pointer through a type that is " 203 "not marked 'gsl::owner<>'; consider using a " 204 "smart pointer instead")
205 << DeletedVariable->getSourceRange();
209 const ValueDecl *Decl = DeletedVariable->getDecl();
210 diag(Decl->getBeginLoc(),
"variable declared here", DiagnosticIDs::Note)
211 << Decl->getSourceRange();
218 bool OwningMemoryCheck::handleLegacyConsumers(
const BoundNodes &Nodes) {
220 const auto *LegacyConsumer = Nodes.getNodeAs<CallExpr>(
"legacy_consumer");
225 if (LegacyConsumer) {
226 diag(LegacyConsumer->getBeginLoc(),
227 "calling legacy resource function without passing a 'gsl::owner<>'")
228 << LegacyConsumer->getSourceRange();
234 bool OwningMemoryCheck::handleExpectedOwner(
const BoundNodes &Nodes) {
236 const auto *ExpectedOwner = Nodes.getNodeAs<Expr>(
"expected_owner_argument");
240 diag(ExpectedOwner->getBeginLoc(),
241 "expected argument of type 'gsl::owner<>'; got %0")
242 << ExpectedOwner->getType() << ExpectedOwner->getSourceRange();
249 bool OwningMemoryCheck::handleAssignmentAndInit(
const BoundNodes &Nodes) {
250 const auto *OwnerAssignment =
251 Nodes.getNodeAs<BinaryOperator>(
"owner_assignment");
252 const auto *OwnerInitialization =
253 Nodes.getNodeAs<VarDecl>(
"owner_initialization");
254 const auto *OwnerInitializer =
255 Nodes.getNodeAs<CXXCtorInitializer>(
"owner_member_initializer");
258 if (OwnerAssignment) {
259 diag(OwnerAssignment->getBeginLoc(),
260 "expected assignment source to be of type 'gsl::owner<>'; got %0")
261 << OwnerAssignment->getRHS()->getType()
262 << OwnerAssignment->getSourceRange();
267 if (OwnerInitialization) {
268 diag(OwnerInitialization->getBeginLoc(),
269 "expected initialization with value of type 'gsl::owner<>'; got %0")
270 << OwnerInitialization->getAnyInitializer()->getType()
271 << OwnerInitialization->getSourceRange();
276 if (OwnerInitializer) {
277 diag(OwnerInitializer->getSourceLocation(),
278 "expected initialization of owner member variable with value of type " 279 "'gsl::owner<>'; got %0")
282 << OwnerInitializer->getInit()->getType()
283 << OwnerInitializer->getSourceRange();
291 bool OwningMemoryCheck::handleAssignmentFromNewOwner(
const BoundNodes &Nodes) {
292 const auto *BadOwnerAssignment =
293 Nodes.getNodeAs<BinaryOperator>(
"bad_owner_creation_assignment");
294 const auto *BadOwnerInitialization =
295 Nodes.getNodeAs<VarDecl>(
"bad_owner_creation_variable");
297 const auto *BadOwnerArgument =
298 Nodes.getNodeAs<Expr>(
"bad_owner_creation_argument");
299 const auto *BadOwnerParameter =
300 Nodes.getNodeAs<ParmVarDecl>(
"bad_owner_creation_parameter");
303 if (BadOwnerAssignment) {
304 diag(BadOwnerAssignment->getBeginLoc(),
305 "assigning newly created 'gsl::owner<>' to non-owner %0")
306 << BadOwnerAssignment->getLHS()->getType()
307 << BadOwnerAssignment->getSourceRange();
312 if (BadOwnerInitialization) {
313 diag(BadOwnerInitialization->getBeginLoc(),
314 "initializing non-owner %0 with a newly created 'gsl::owner<>'")
315 << BadOwnerInitialization->getType()
316 << BadOwnerInitialization->getSourceRange();
323 if (Nodes.getNodeAs<AutoType>(
"deduced_type")) {
324 diag(BadOwnerInitialization->getBeginLoc(),
325 "type deduction did not result in an owner", DiagnosticIDs::Note);
332 if (BadOwnerArgument) {
333 assert(BadOwnerParameter &&
334 "parameter for the problematic argument not found");
335 diag(BadOwnerArgument->getBeginLoc(),
"initializing non-owner argument of " 336 "type %0 with a newly created " 338 << BadOwnerParameter->getType() << BadOwnerArgument->getSourceRange();
344 bool OwningMemoryCheck::handleReturnValues(
const BoundNodes &Nodes) {
347 const auto *BadReturnType = Nodes.getNodeAs<ReturnStmt>(
"bad_owner_return");
348 const auto *Function = Nodes.getNodeAs<FunctionDecl>(
"function_decl");
354 diag(BadReturnType->getBeginLoc(),
355 "returning a newly created resource of " 356 "type %0 or 'gsl::owner<>' from a " 357 "function whose return type is not 'gsl::owner<>'")
358 << Function->getReturnType() << BadReturnType->getSourceRange();
366 bool OwningMemoryCheck::handleOwnerMembers(
const BoundNodes &Nodes) {
369 const auto *BadClass = Nodes.getNodeAs<CXXRecordDecl>(
"non_destructor_class");
373 const auto *DeclaredOwnerMember =
374 Nodes.getNodeAs<FieldDecl>(
"undestructed_owner_member");
375 assert(DeclaredOwnerMember &&
376 "match on class with bad destructor but without a declared owner");
378 diag(DeclaredOwnerMember->getBeginLoc(),
379 "member variable of type 'gsl::owner<>' requires the class %0 to " 380 "implement a destructor to release the owned resource")
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
std::map< std::string, std::string > OptionMap
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result