Bug 1658004 [wpt PR 24923] - [EventTiming] Improve some of the flaky tests, a=testonly
[gecko.git] / build / clang-plugin / TemporaryLifetimeBoundChecker.cpp
blobdc66f62b0d3a141d4fa5eb139eeb4b2ea91ff912
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 =
12 cxxMemberCallExpr(
13 onImplicitObjectArgument(anyOf(has(cxxTemporaryObjectExpr()),
14 has(materializeTemporaryExpr()))),
15 callee(functionDecl(isMozTemporaryLifetimeBound())))
16 .bind("call");
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
20 // start.
21 auto hasTemporaryLifetimeBoundCall =
22 anyOf(isTemporaryLifetimeBoundCall,
23 conditionalOperator(
24 anyOf(hasFalseExpression(isTemporaryLifetimeBoundCall),
25 hasTrueExpression(isTemporaryLifetimeBoundCall))));
27 AstMatcher->addMatcher(
28 returnStmt(hasReturnValue(
29 allOf(exprWithCleanups().bind("expr-with-cleanups"),
30 ignoringParenCasts(hasTemporaryLifetimeBoundCall))))
31 .bind("return-stmt"),
32 this);
34 AstMatcher->addMatcher(
35 varDecl(hasType(references(cxxRecordDecl())),
36 hasInitializer(
37 allOf(exprWithCleanups(),
38 ignoringParenCasts(hasTemporaryLifetimeBoundCall))))
39 .bind("var-decl"),
40 this);
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()) {
65 return;
68 const auto Range = ReturnStatement->getSourceRange();
70 diag(Range.getBegin(), ErrorReturn, DiagnosticIDs::Error)
71 << Range << Call->getMethodDecl()
72 << Call->getImplicitObjectArgument()
73 ->getType()
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()
84 ->getType()
85 .withoutLocalFastQualifiers();
88 const auto *MethodDecl = Call->getMethodDecl();
89 diag(MethodDecl->getCanonicalDecl()->getLocation(), NoteCalledFunction,
90 DiagnosticIDs::Note);