11 #include "../utils/Matchers.h" 12 #include "../utils/OptionsUtils.h" 13 #include "clang/AST/ASTContext.h" 14 #include "clang/ASTMatchers/ASTMatchFinder.h" 23 namespace cppcoreguidelines {
28 Matcher<FunctionDecl> hasAnyListedName(
const std::string &FunctionNames) {
29 const std::vector<std::string> NameList =
31 return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
36 Options.store(Opts,
"LegacyResourceProducers", LegacyResourceProducers);
37 Options.store(Opts,
"LegacyResourceConsumers", LegacyResourceConsumers);
42 void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
43 if (!getLangOpts().CPlusPlus11)
46 const auto OwnerDecl = typeAliasTemplateDecl(hasName(
"::gsl::owner"));
47 const auto IsOwnerType = hasType(OwnerDecl);
49 const auto LegacyCreatorFunctions = hasAnyListedName(LegacyResourceProducers);
50 const auto LegacyConsumerFunctions =
51 hasAnyListedName(LegacyResourceConsumers);
55 const auto CreatesLegacyOwner =
56 callExpr(callee(functionDecl(LegacyCreatorFunctions)));
60 const auto LegacyOwnerCast =
61 castExpr(hasSourceExpression(CreatesLegacyOwner));
64 const auto LegacyOwnerConsumers = functionDecl(LegacyConsumerFunctions);
66 const auto CreatesOwner =
69 functionDecl(returns(qualType(hasDeclaration(OwnerDecl)))))),
70 CreatesLegacyOwner, LegacyOwnerCast);
72 const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwner);
78 declRefExpr(unless(ConsideredOwner)).bind(
"deleted_variable")))
90 callExpr(callee(LegacyOwnerConsumers),
91 hasAnyArgument(expr(unless(ignoringImpCasts(ConsideredOwner)),
92 hasType(pointerType()))))
93 .bind(
"legacy_consumer"),
98 Finder->addMatcher(binaryOperator(matchers::isAssignmentOperator(),
100 hasRHS(unless(ConsideredOwner)))
101 .bind(
"owner_assignment"),
106 namedDecl(varDecl(hasInitializer(unless(ConsideredOwner)), IsOwnerType)
107 .bind(
"owner_initialization")),
110 const auto HasConstructorInitializerForOwner =
111 has(cxxConstructorDecl(forEachConstructorInitializer(
113 isMemberInitializer(), forField(IsOwnerType),
117 allOf(unless(ConsideredOwner), unless(parenListExpr()))))
118 .bind(
"owner_member_initializer"))));
122 Finder->addMatcher(cxxRecordDecl(HasConstructorInitializerForOwner),
this);
126 Finder->addMatcher(binaryOperator(matchers::isAssignmentOperator(),
127 hasLHS(unless(IsOwnerType)),
128 hasRHS(CreatesOwner))
129 .bind(
"bad_owner_creation_assignment"),
135 namedDecl(varDecl(eachOf(allOf(hasInitializer(CreatesOwner),
136 unless(IsOwnerType)),
137 allOf(hasInitializer(ConsideredOwner),
138 hasType(autoType().bind(
"deduced_type")))))
139 .bind(
"bad_owner_creation_variable")),
145 callExpr(forEachArgumentWithParam(
146 expr(unless(ConsideredOwner)).bind(
"expected_owner_argument"),
147 parmVarDecl(IsOwnerType))),
152 Finder->addMatcher(callExpr(forEachArgumentWithParam(
153 expr(CreatesOwner).bind(
"bad_owner_creation_argument"),
154 parmVarDecl(unless(IsOwnerType))
155 .bind(
"bad_owner_creation_parameter"))),
161 functionDecl(hasDescendant(returnStmt(hasReturnValue(ConsideredOwner))
162 .bind(
"bad_owner_return")),
163 unless(returns(qualType(hasDeclaration(OwnerDecl)))))
164 .bind(
"function_decl"),
171 has(fieldDecl(IsOwnerType).bind(
"undestructed_owner_member")),
172 anyOf(unless(has(cxxDestructorDecl())),
173 has(cxxDestructorDecl(anyOf(isDefaulted(), isDeleted())))))
174 .bind(
"non_destructor_class"),
178 void OwningMemoryCheck::check(
const MatchFinder::MatchResult &
Result) {
179 const auto &Nodes = Result.Nodes;
181 bool CheckExecuted =
false;
182 CheckExecuted |= handleDeletion(Nodes);
183 CheckExecuted |= handleLegacyConsumers(Nodes);
184 CheckExecuted |= handleExpectedOwner(Nodes);
185 CheckExecuted |= handleAssignmentAndInit(Nodes);
186 CheckExecuted |= handleAssignmentFromNewOwner(Nodes);
187 CheckExecuted |= handleReturnValues(Nodes);
188 CheckExecuted |= handleOwnerMembers(Nodes);
190 assert(CheckExecuted &&
191 "None of the subroutines executed, logic error in matcher!");
194 bool OwningMemoryCheck::handleDeletion(
const BoundNodes &Nodes) {
196 const auto *DeleteStmt = Nodes.getNodeAs<CXXDeleteExpr>(
"delete_expr");
197 const auto *DeletedVariable =
198 Nodes.getNodeAs<DeclRefExpr>(
"deleted_variable");
202 diag(DeleteStmt->getBeginLoc(),
203 "deleting a pointer through a type that is " 204 "not marked 'gsl::owner<>'; consider using a " 205 "smart pointer instead")
206 << DeletedVariable->getSourceRange();
210 const ValueDecl *Decl = DeletedVariable->getDecl();
211 diag(Decl->getBeginLoc(),
"variable declared here", DiagnosticIDs::Note)
212 << Decl->getSourceRange();
219 bool OwningMemoryCheck::handleLegacyConsumers(
const BoundNodes &Nodes) {
221 const auto *LegacyConsumer = Nodes.getNodeAs<CallExpr>(
"legacy_consumer");
226 if (LegacyConsumer) {
227 diag(LegacyConsumer->getBeginLoc(),
228 "calling legacy resource function without passing a 'gsl::owner<>'")
229 << LegacyConsumer->getSourceRange();
235 bool OwningMemoryCheck::handleExpectedOwner(
const BoundNodes &Nodes) {
237 const auto *ExpectedOwner = Nodes.getNodeAs<Expr>(
"expected_owner_argument");
241 diag(ExpectedOwner->getBeginLoc(),
242 "expected argument of type 'gsl::owner<>'; got %0")
243 << ExpectedOwner->getType() << ExpectedOwner->getSourceRange();
250 bool OwningMemoryCheck::handleAssignmentAndInit(
const BoundNodes &Nodes) {
251 const auto *OwnerAssignment =
252 Nodes.getNodeAs<BinaryOperator>(
"owner_assignment");
253 const auto *OwnerInitialization =
254 Nodes.getNodeAs<VarDecl>(
"owner_initialization");
255 const auto *OwnerInitializer =
256 Nodes.getNodeAs<CXXCtorInitializer>(
"owner_member_initializer");
259 if (OwnerAssignment) {
260 diag(OwnerAssignment->getBeginLoc(),
261 "expected assignment source to be of type 'gsl::owner<>'; got %0")
262 << OwnerAssignment->getRHS()->getType()
263 << OwnerAssignment->getSourceRange();
268 if (OwnerInitialization) {
269 diag(OwnerInitialization->getBeginLoc(),
270 "expected initialization with value of type 'gsl::owner<>'; got %0")
271 << OwnerInitialization->getAnyInitializer()->getType()
272 << OwnerInitialization->getSourceRange();
277 if (OwnerInitializer) {
278 diag(OwnerInitializer->getSourceLocation(),
279 "expected initialization of owner member variable with value of type " 280 "'gsl::owner<>'; got %0")
283 << OwnerInitializer->getInit()->getType()
284 << OwnerInitializer->getSourceRange();
292 bool OwningMemoryCheck::handleAssignmentFromNewOwner(
const BoundNodes &Nodes) {
293 const auto *BadOwnerAssignment =
294 Nodes.getNodeAs<BinaryOperator>(
"bad_owner_creation_assignment");
295 const auto *BadOwnerInitialization =
296 Nodes.getNodeAs<VarDecl>(
"bad_owner_creation_variable");
298 const auto *BadOwnerArgument =
299 Nodes.getNodeAs<Expr>(
"bad_owner_creation_argument");
300 const auto *BadOwnerParameter =
301 Nodes.getNodeAs<ParmVarDecl>(
"bad_owner_creation_parameter");
304 if (BadOwnerAssignment) {
305 diag(BadOwnerAssignment->getBeginLoc(),
306 "assigning newly created 'gsl::owner<>' to non-owner %0")
307 << BadOwnerAssignment->getLHS()->getType()
308 << BadOwnerAssignment->getSourceRange();
313 if (BadOwnerInitialization) {
314 diag(BadOwnerInitialization->getBeginLoc(),
315 "initializing non-owner %0 with a newly created 'gsl::owner<>'")
316 << BadOwnerInitialization->getType()
317 << BadOwnerInitialization->getSourceRange();
324 if (Nodes.getNodeAs<AutoType>(
"deduced_type")) {
325 diag(BadOwnerInitialization->getBeginLoc(),
326 "type deduction did not result in an owner", DiagnosticIDs::Note);
333 if (BadOwnerArgument) {
334 assert(BadOwnerParameter &&
335 "parameter for the problematic argument not found");
336 diag(BadOwnerArgument->getBeginLoc(),
"initializing non-owner argument of " 337 "type %0 with a newly created " 339 << BadOwnerParameter->getType() << BadOwnerArgument->getSourceRange();
345 bool OwningMemoryCheck::handleReturnValues(
const BoundNodes &Nodes) {
348 const auto *BadReturnType = Nodes.getNodeAs<ReturnStmt>(
"bad_owner_return");
349 const auto *Function = Nodes.getNodeAs<FunctionDecl>(
"function_decl");
355 diag(BadReturnType->getBeginLoc(),
356 "returning a newly created resource of " 357 "type %0 or 'gsl::owner<>' from a " 358 "function whose return type is not 'gsl::owner<>'")
359 << Function->getReturnType() << BadReturnType->getSourceRange();
367 bool OwningMemoryCheck::handleOwnerMembers(
const BoundNodes &Nodes) {
370 const auto *BadClass = Nodes.getNodeAs<CXXRecordDecl>(
"non_destructor_class");
374 const auto *DeclaredOwnerMember =
375 Nodes.getNodeAs<FieldDecl>(
"undestructed_owner_member");
376 assert(DeclaredOwnerMember &&
377 "match on class with bad destructor but without a declared owner");
379 diag(DeclaredOwnerMember->getBeginLoc(),
380 "member variable of type 'gsl::owner<>' requires the class %0 to " 381 "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
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//