1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "TemporaryLifetimeBoundChecker.h"
6 #include "CustomMatchers.h"
7 #include "clang/Lex/Lexer.h"
9 void TemporaryLifetimeBoundChecker::registerMatchers(MatchFinder
*AstMatcher
) {
10 // Look for a call to a MOZ_LIFETIME_BOUND member function
11 auto isTemporaryLifetimeBoundCall
=
13 onImplicitObjectArgument(anyOf(has(cxxTemporaryObjectExpr()),
14 has(materializeTemporaryExpr()))),
15 callee(functionDecl(isMozTemporaryLifetimeBound())))
18 // XXX This definitely does not catch everything relevant. In particular, the
19 // matching on conditionalOperator would need to be recursive. But it's a
21 auto hasTemporaryLifetimeBoundCall
=
22 anyOf(isTemporaryLifetimeBoundCall
,
24 anyOf(hasFalseExpression(isTemporaryLifetimeBoundCall
),
25 hasTrueExpression(isTemporaryLifetimeBoundCall
))));
27 AstMatcher
->addMatcher(
28 returnStmt(hasReturnValue(
29 allOf(exprWithCleanups().bind("expr-with-cleanups"),
30 ignoringParenCasts(hasTemporaryLifetimeBoundCall
))))
34 AstMatcher
->addMatcher(
35 varDecl(hasType(references(cxxRecordDecl())),
37 allOf(exprWithCleanups(),
38 ignoringParenCasts(hasTemporaryLifetimeBoundCall
))))
43 void TemporaryLifetimeBoundChecker::check(
44 const MatchFinder::MatchResult
&Result
) {
45 const auto *Call
= Result
.Nodes
.getNodeAs
<CXXMemberCallExpr
>("call");
46 const auto *ReturnStatement
=
47 Result
.Nodes
.getNodeAs
<ReturnStmt
>("return-stmt");
48 const auto *ReferenceVarDecl
= Result
.Nodes
.getNodeAs
<VarDecl
>("var-decl");
50 const char ErrorReturn
[] =
51 "cannot return result of lifetime-bound function %0 on "
52 "temporary of type %1";
54 const char ErrorBindToReference
[] =
55 "cannot bind result of lifetime-bound function %0 on "
56 "temporary of type %1 to reference, does not extend lifetime";
58 const char NoteCalledFunction
[] = "member function declared here";
60 // We are either a return statement...
61 if (ReturnStatement
) {
62 const auto *ExprWithCleanups
=
63 Result
.Nodes
.getNodeAs
<Expr
>("expr-with-cleanups");
64 if (!ExprWithCleanups
->isLValue()) {
68 const auto Range
= ReturnStatement
->getSourceRange();
70 diag(Range
.getBegin(), ErrorReturn
, DiagnosticIDs::Error
)
71 << Range
<< Call
->getMethodDecl()
72 << Call
->getImplicitObjectArgument()
74 .withoutLocalFastQualifiers();
77 // ... or a variable declaration that declare a reference
78 if (ReferenceVarDecl
) {
79 const auto Range
= ReferenceVarDecl
->getSourceRange();
81 diag(Range
.getBegin(), ErrorBindToReference
, DiagnosticIDs::Error
)
82 << Range
<< Call
->getMethodDecl()
83 << Call
->getImplicitObjectArgument()
85 .withoutLocalFastQualifiers();
88 const auto *MethodDecl
= Call
->getMethodDecl();
89 diag(MethodDecl
->getCanonicalDecl()->getLocation(), NoteCalledFunction
,