clang  15.0.0git
ExprMutationAnalyzer.cpp
Go to the documentation of this file.
1 //===---------- ExprMutationAnalyzer.cpp ----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "clang/AST/Expr.h"
13 #include "llvm/ADT/STLExtras.h"
14 
15 namespace clang {
16 using namespace ast_matchers;
17 
18 namespace {
19 
20 AST_MATCHER_P(LambdaExpr, hasCaptureInit, const Expr *, E) {
21  return llvm::is_contained(Node.capture_inits(), E);
22 }
23 
24 AST_MATCHER_P(CXXForRangeStmt, hasRangeStmt,
25  ast_matchers::internal::Matcher<DeclStmt>, InnerMatcher) {
26  const DeclStmt *const Range = Node.getRangeStmt();
27  return InnerMatcher.matches(*Range, Finder, Builder);
28 }
29 
30 AST_MATCHER_P(Expr, maybeEvalCommaExpr, ast_matchers::internal::Matcher<Expr>,
31  InnerMatcher) {
32  const Expr *Result = &Node;
33  while (const auto *BOComma =
34  dyn_cast_or_null<BinaryOperator>(Result->IgnoreParens())) {
35  if (!BOComma->isCommaOp())
36  break;
37  Result = BOComma->getRHS();
38  }
39  return InnerMatcher.matches(*Result, Finder, Builder);
40 }
41 
42 AST_MATCHER_P(Stmt, canResolveToExpr, ast_matchers::internal::Matcher<Stmt>,
43  InnerMatcher) {
44  auto *Exp = dyn_cast<Expr>(&Node);
45  if (!Exp) {
46  return stmt().matches(Node, Finder, Builder);
47  }
48 
49  auto DerivedToBase = [](const ast_matchers::internal::Matcher<Expr> &Inner) {
50  return implicitCastExpr(anyOf(hasCastKind(CK_DerivedToBase),
51  hasCastKind(CK_UncheckedDerivedToBase)),
52  hasSourceExpression(Inner));
53  };
54  auto IgnoreDerivedToBase =
55  [&DerivedToBase](const ast_matchers::internal::Matcher<Expr> &Inner) {
56  return ignoringParens(expr(anyOf(Inner, DerivedToBase(Inner))));
57  };
58 
59  // The 'ConditionalOperator' matches on `<anything> ? <expr> : <expr>`.
60  // This matching must be recursive because `<expr>` can be anything resolving
61  // to the `InnerMatcher`, for example another conditional operator.
62  // The edge-case `BaseClass &b = <cond> ? DerivedVar1 : DerivedVar2;`
63  // is handled, too. The implicit cast happens outside of the conditional.
64  // This is matched by `IgnoreDerivedToBase(canResolveToExpr(InnerMatcher))`
65  // below.
66  auto const ConditionalOperator = conditionalOperator(anyOf(
67  hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))),
68  hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher)))));
69  auto const ElvisOperator = binaryConditionalOperator(anyOf(
70  hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))),
71  hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher)))));
72 
73  auto const ComplexMatcher = ignoringParens(
74  expr(anyOf(IgnoreDerivedToBase(InnerMatcher),
75  maybeEvalCommaExpr(IgnoreDerivedToBase(InnerMatcher)),
76  IgnoreDerivedToBase(ConditionalOperator),
77  IgnoreDerivedToBase(ElvisOperator))));
78 
79  return ComplexMatcher.matches(*Exp, Finder, Builder);
80 }
81 
82 // Similar to 'hasAnyArgument', but does not work because 'InitListExpr' does
83 // not have the 'arguments()' method.
84 AST_MATCHER_P(InitListExpr, hasAnyInit, ast_matchers::internal::Matcher<Expr>,
85  InnerMatcher) {
86  for (const Expr *Arg : Node.inits()) {
87  ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
88  if (InnerMatcher.matches(*Arg, Finder, &Result)) {
89  *Builder = std::move(Result);
90  return true;
91  }
92  }
93  return false;
94 }
95 
96 const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr>
97  cxxTypeidExpr;
98 
99 AST_MATCHER(CXXTypeidExpr, isPotentiallyEvaluated) {
100  return Node.isPotentiallyEvaluated();
101 }
102 
103 AST_MATCHER_P(GenericSelectionExpr, hasControllingExpr,
104  ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
105  return InnerMatcher.matches(*Node.getControllingExpr(), Finder, Builder);
106 }
107 
108 const auto nonConstReferenceType = [] {
109  return hasUnqualifiedDesugaredType(
110  referenceType(pointee(unless(isConstQualified()))));
111 };
112 
113 const auto nonConstPointerType = [] {
114  return hasUnqualifiedDesugaredType(
115  pointerType(pointee(unless(isConstQualified()))));
116 };
117 
118 const auto isMoveOnly = [] {
119  return cxxRecordDecl(
120  hasMethod(cxxConstructorDecl(isMoveConstructor(), unless(isDeleted()))),
121  hasMethod(cxxMethodDecl(isMoveAssignmentOperator(), unless(isDeleted()))),
122  unless(anyOf(hasMethod(cxxConstructorDecl(isCopyConstructor(),
123  unless(isDeleted()))),
124  hasMethod(cxxMethodDecl(isCopyAssignmentOperator(),
125  unless(isDeleted()))))));
126 };
127 
128 template <class T> struct NodeID;
129 template <> struct NodeID<Expr> { static constexpr StringRef value = "expr"; };
130 template <> struct NodeID<Decl> { static constexpr StringRef value = "decl"; };
131 constexpr StringRef NodeID<Expr>::value;
132 constexpr StringRef NodeID<Decl>::value;
133 
134 template <class T, class F = const Stmt *(ExprMutationAnalyzer::*)(const T *)>
135 const Stmt *tryEachMatch(ArrayRef<ast_matchers::BoundNodes> Matches,
136  ExprMutationAnalyzer *Analyzer, F Finder) {
137  const StringRef ID = NodeID<T>::value;
138  for (const auto &Nodes : Matches) {
139  if (const Stmt *S = (Analyzer->*Finder)(Nodes.getNodeAs<T>(ID)))
140  return S;
141  }
142  return nullptr;
143 }
144 
145 } // namespace
146 
148  return findMutationMemoized(Exp,
149  {&ExprMutationAnalyzer::findDirectMutation,
150  &ExprMutationAnalyzer::findMemberMutation,
151  &ExprMutationAnalyzer::findArrayElementMutation,
152  &ExprMutationAnalyzer::findCastMutation,
153  &ExprMutationAnalyzer::findRangeLoopMutation,
154  &ExprMutationAnalyzer::findReferenceMutation,
155  &ExprMutationAnalyzer::findFunctionArgMutation},
156  Results);
157 }
158 
160  return tryEachDeclRef(Dec, &ExprMutationAnalyzer::findMutation);
161 }
162 
164  return findMutationMemoized(Exp, {/*TODO*/}, PointeeResults);
165 }
166 
168  return tryEachDeclRef(Dec, &ExprMutationAnalyzer::findPointeeMutation);
169 }
170 
171 const Stmt *ExprMutationAnalyzer::findMutationMemoized(
172  const Expr *Exp, llvm::ArrayRef<MutationFinder> Finders,
173  ResultMap &MemoizedResults) {
174  const auto Memoized = MemoizedResults.find(Exp);
175  if (Memoized != MemoizedResults.end())
176  return Memoized->second;
177 
178  if (isUnevaluated(Exp))
179  return MemoizedResults[Exp] = nullptr;
180 
181  for (const auto &Finder : Finders) {
182  if (const Stmt *S = (this->*Finder)(Exp))
183  return MemoizedResults[Exp] = S;
184  }
185 
186  return MemoizedResults[Exp] = nullptr;
187 }
188 
189 const Stmt *ExprMutationAnalyzer::tryEachDeclRef(const Decl *Dec,
190  MutationFinder Finder) {
191  const auto Refs =
192  match(findAll(declRefExpr(to(equalsNode(Dec))).bind(NodeID<Expr>::value)),
193  Stm, Context);
194  for (const auto &RefNodes : Refs) {
195  const auto *E = RefNodes.getNodeAs<Expr>(NodeID<Expr>::value);
196  if ((this->*Finder)(E))
197  return E;
198  }
199  return nullptr;
200 }
201 
202 bool ExprMutationAnalyzer::isUnevaluated(const Stmt *Exp, const Stmt &Stm,
203  ASTContext &Context) {
204  return selectFirst<Stmt>(
205  NodeID<Expr>::value,
206  match(
207  findAll(
208  stmt(canResolveToExpr(equalsNode(Exp)),
209  anyOf(
210  // `Exp` is part of the underlying expression of
211  // decltype/typeof if it has an ancestor of
212  // typeLoc.
216  // `UnaryExprOrTypeTraitExpr` is unevaluated
217  // unless it's sizeof on VLA.
219  hasArgumentOfType(variableArrayType())))),
220  // `CXXTypeidExpr` is unevaluated unless it's
221  // applied to an expression of glvalue of
222  // polymorphic class type.
223  cxxTypeidExpr(
224  unless(isPotentiallyEvaluated())),
225  // The controlling expression of
226  // `GenericSelectionExpr` is unevaluated.
227  genericSelectionExpr(hasControllingExpr(
228  hasDescendant(equalsNode(Exp)))),
229  cxxNoexceptExpr())))))
230  .bind(NodeID<Expr>::value)),
231  Stm, Context)) != nullptr;
232 }
233 
234 bool ExprMutationAnalyzer::isUnevaluated(const Expr *Exp) {
235  return isUnevaluated(Exp, Stm, Context);
236 }
237 
238 const Stmt *
239 ExprMutationAnalyzer::findExprMutation(ArrayRef<BoundNodes> Matches) {
240  return tryEachMatch<Expr>(Matches, this, &ExprMutationAnalyzer::findMutation);
241 }
242 
243 const Stmt *
244 ExprMutationAnalyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) {
245  return tryEachMatch<Decl>(Matches, this, &ExprMutationAnalyzer::findMutation);
246 }
247 
248 const Stmt *ExprMutationAnalyzer::findExprPointeeMutation(
249  ArrayRef<ast_matchers::BoundNodes> Matches) {
250  return tryEachMatch<Expr>(Matches, this,
252 }
253 
254 const Stmt *ExprMutationAnalyzer::findDeclPointeeMutation(
255  ArrayRef<ast_matchers::BoundNodes> Matches) {
256  return tryEachMatch<Decl>(Matches, this,
258 }
259 
260 const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
261  // LHS of any assignment operators.
262  const auto AsAssignmentLhs = binaryOperator(
263  isAssignmentOperator(), hasLHS(canResolveToExpr(equalsNode(Exp))));
264 
265  // Operand of increment/decrement operators.
266  const auto AsIncDecOperand =
267  unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
268  hasUnaryOperand(canResolveToExpr(equalsNode(Exp))));
269 
270  // Invoking non-const member function.
271  // A member function is assumed to be non-const when it is unresolved.
272  const auto NonConstMethod = cxxMethodDecl(unless(isConst()));
273 
274  const auto AsNonConstThis = expr(anyOf(
275  cxxMemberCallExpr(callee(NonConstMethod),
276  on(canResolveToExpr(equalsNode(Exp)))),
277  cxxOperatorCallExpr(callee(NonConstMethod),
278  hasArgument(0, canResolveToExpr(equalsNode(Exp)))),
279  // In case of a templated type, calling overloaded operators is not
280  // resolved and modelled as `binaryOperator` on a dependent type.
281  // Such instances are considered a modification, because they can modify
282  // in different instantiations of the template.
283  binaryOperator(hasEitherOperand(
284  allOf(ignoringImpCasts(canResolveToExpr(equalsNode(Exp))),
285  isTypeDependent()))),
286  // Within class templates and member functions the member expression might
287  // not be resolved. In that case, the `callExpr` is considered to be a
288  // modification.
289  callExpr(
290  callee(expr(anyOf(unresolvedMemberExpr(hasObjectExpression(
291  canResolveToExpr(equalsNode(Exp)))),
292  cxxDependentScopeMemberExpr(hasObjectExpression(
293  canResolveToExpr(equalsNode(Exp)))))))),
294  // Match on a call to a known method, but the call itself is type
295  // dependent (e.g. `vector<T> v; v.push(T{});` in a templated function).
296  callExpr(allOf(isTypeDependent(),
297  callee(memberExpr(hasDeclaration(NonConstMethod),
298  hasObjectExpression(canResolveToExpr(
299  equalsNode(Exp)))))))));
300 
301  // Taking address of 'Exp'.
302  // We're assuming 'Exp' is mutated as soon as its address is taken, though in
303  // theory we can follow the pointer and see whether it escaped `Stm` or is
304  // dereferenced and then mutated. This is left for future improvements.
305  const auto AsAmpersandOperand =
306  unaryOperator(hasOperatorName("&"),
307  // A NoOp implicit cast is adding const.
308  unless(hasParent(implicitCastExpr(hasCastKind(CK_NoOp)))),
309  hasUnaryOperand(canResolveToExpr(equalsNode(Exp))));
310  const auto AsPointerFromArrayDecay =
311  castExpr(hasCastKind(CK_ArrayToPointerDecay),
313  has(canResolveToExpr(equalsNode(Exp))));
314  // Treat calling `operator->()` of move-only classes as taking address.
315  // These are typically smart pointers with unique ownership so we treat
316  // mutation of pointee as mutation of the smart pointer itself.
317  const auto AsOperatorArrowThis = cxxOperatorCallExpr(
319  callee(
320  cxxMethodDecl(ofClass(isMoveOnly()), returns(nonConstPointerType()))),
321  argumentCountIs(1), hasArgument(0, canResolveToExpr(equalsNode(Exp))));
322 
323  // Used as non-const-ref argument when calling a function.
324  // An argument is assumed to be non-const-ref when the function is unresolved.
325  // Instantiated template functions are not handled here but in
326  // findFunctionArgMutation which has additional smarts for handling forwarding
327  // references.
328  const auto NonConstRefParam = forEachArgumentWithParamType(
329  anyOf(canResolveToExpr(equalsNode(Exp)),
330  memberExpr(hasObjectExpression(canResolveToExpr(equalsNode(Exp))))),
331  nonConstReferenceType());
332  const auto NotInstantiated = unless(hasDeclaration(isInstantiated()));
333  const auto TypeDependentCallee =
336  hasType(templateTypeParmType()), isTypeDependent())));
337 
338  const auto AsNonConstRefArg = anyOf(
339  callExpr(NonConstRefParam, NotInstantiated),
340  cxxConstructExpr(NonConstRefParam, NotInstantiated),
341  callExpr(TypeDependentCallee,
342  hasAnyArgument(canResolveToExpr(equalsNode(Exp)))),
344  hasAnyArgument(canResolveToExpr(equalsNode(Exp)))),
345  // Previous False Positive in the following Code:
346  // `template <typename T> void f() { int i = 42; new Type<T>(i); }`
347  // Where the constructor of `Type` takes its argument as reference.
348  // The AST does not resolve in a `cxxConstructExpr` because it is
349  // type-dependent.
350  parenListExpr(hasDescendant(expr(canResolveToExpr(equalsNode(Exp))))),
351  // If the initializer is for a reference type, there is no cast for
352  // the variable. Values are cast to RValue first.
353  initListExpr(hasAnyInit(expr(canResolveToExpr(equalsNode(Exp))))));
354 
355  // Captured by a lambda by reference.
356  // If we're initializing a capture with 'Exp' directly then we're initializing
357  // a reference capture.
358  // For value captures there will be an ImplicitCastExpr <LValueToRValue>.
359  const auto AsLambdaRefCaptureInit = lambdaExpr(hasCaptureInit(Exp));
360 
361  // Returned as non-const-ref.
362  // If we're returning 'Exp' directly then it's returned as non-const-ref.
363  // For returning by value there will be an ImplicitCastExpr <LValueToRValue>.
364  // For returning by const-ref there will be an ImplicitCastExpr <NoOp> (for
365  // adding const.)
366  const auto AsNonConstRefReturn =
367  returnStmt(hasReturnValue(canResolveToExpr(equalsNode(Exp))));
368 
369  // It is used as a non-const-reference for initalizing a range-for loop.
370  const auto AsNonConstRefRangeInit = cxxForRangeStmt(
371  hasRangeInit(declRefExpr(allOf(canResolveToExpr(equalsNode(Exp)),
372  hasType(nonConstReferenceType())))));
373 
374  const auto Matches = match(
376  findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand,
377  AsNonConstThis, AsAmpersandOperand,
378  AsPointerFromArrayDecay, AsOperatorArrowThis,
379  AsNonConstRefArg, AsLambdaRefCaptureInit,
380  AsNonConstRefReturn, AsNonConstRefRangeInit))
381  .bind("stmt"))),
382  Stm, Context);
383  return selectFirst<Stmt>("stmt", Matches);
384 }
385 
386 const Stmt *ExprMutationAnalyzer::findMemberMutation(const Expr *Exp) {
387  // Check whether any member of 'Exp' is mutated.
388  const auto MemberExprs =
389  match(findAll(expr(anyOf(memberExpr(hasObjectExpression(
390  canResolveToExpr(equalsNode(Exp)))),
391  cxxDependentScopeMemberExpr(hasObjectExpression(
392  canResolveToExpr(equalsNode(Exp))))))
393  .bind(NodeID<Expr>::value)),
394  Stm, Context);
395  return findExprMutation(MemberExprs);
396 }
397 
398 const Stmt *ExprMutationAnalyzer::findArrayElementMutation(const Expr *Exp) {
399  // Check whether any element of an array is mutated.
400  const auto SubscriptExprs =
402  anyOf(hasBase(canResolveToExpr(equalsNode(Exp))),
403  hasBase(implicitCastExpr(
404  allOf(hasCastKind(CK_ArrayToPointerDecay),
405  hasSourceExpression(canResolveToExpr(
406  equalsNode(Exp))))))))
407  .bind(NodeID<Expr>::value)),
408  Stm, Context);
409  return findExprMutation(SubscriptExprs);
410 }
411 
412 const Stmt *ExprMutationAnalyzer::findCastMutation(const Expr *Exp) {
413  // If the 'Exp' is explicitly casted to a non-const reference type the
414  // 'Exp' is considered to be modified.
415  const auto ExplicitCast = match(
416  findAll(
417  stmt(castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))),
419  hasDestinationType(nonConstReferenceType()))))
420  .bind("stmt")),
421  Stm, Context);
422 
423  if (const auto *CastStmt = selectFirst<Stmt>("stmt", ExplicitCast))
424  return CastStmt;
425 
426  // If 'Exp' is casted to any non-const reference type, check the castExpr.
427  const auto Casts = match(
428  findAll(
429  expr(castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))),
431  hasDestinationType(nonConstReferenceType())),
432  implicitCastExpr(hasImplicitDestinationType(
433  nonConstReferenceType())))))
434  .bind(NodeID<Expr>::value)),
435  Stm, Context);
436 
437  if (const Stmt *S = findExprMutation(Casts))
438  return S;
439  // Treat std::{move,forward} as cast.
440  const auto Calls =
442  hasAnyName("::std::move", "::std::forward"))),
443  hasArgument(0, canResolveToExpr(equalsNode(Exp))))
444  .bind("expr")),
445  Stm, Context);
446  return findExprMutation(Calls);
447 }
448 
449 const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) {
450  // Keep the ordering for the specific initialization matches to happen first,
451  // because it is cheaper to match all potential modifications of the loop
452  // variable.
453 
454  // The range variable is a reference to a builtin array. In that case the
455  // array is considered modified if the loop-variable is a non-const reference.
456  const auto DeclStmtToNonRefToArray = declStmt(hasSingleDecl(varDecl(hasType(
457  hasUnqualifiedDesugaredType(referenceType(pointee(arrayType())))))));
458  const auto RefToArrayRefToElements = match(
460  hasLoopVariable(varDecl(hasType(nonConstReferenceType()))
461  .bind(NodeID<Decl>::value)),
462  hasRangeStmt(DeclStmtToNonRefToArray),
463  hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
464  .bind("stmt")),
465  Stm, Context);
466 
467  if (const auto *BadRangeInitFromArray =
468  selectFirst<Stmt>("stmt", RefToArrayRefToElements))
469  return BadRangeInitFromArray;
470 
471  // Small helper to match special cases in range-for loops.
472  //
473  // It is possible that containers do not provide a const-overload for their
474  // iterator accessors. If this is the case, the variable is used non-const
475  // no matter what happens in the loop. This requires special detection as it
476  // is then faster to find all mutations of the loop variable.
477  // It aims at a different modification as well.
478  const auto HasAnyNonConstIterator =
479  anyOf(allOf(hasMethod(allOf(hasName("begin"), unless(isConst()))),
480  unless(hasMethod(allOf(hasName("begin"), isConst())))),
481  allOf(hasMethod(allOf(hasName("end"), unless(isConst()))),
482  unless(hasMethod(allOf(hasName("end"), isConst())))));
483 
484  const auto DeclStmtToNonConstIteratorContainer = declStmt(
485  hasSingleDecl(varDecl(hasType(hasUnqualifiedDesugaredType(referenceType(
486  pointee(hasDeclaration(cxxRecordDecl(HasAnyNonConstIterator)))))))));
487 
488  const auto RefToContainerBadIterators =
490  hasRangeStmt(DeclStmtToNonConstIteratorContainer),
491  hasRangeInit(canResolveToExpr(equalsNode(Exp))))))
492  .bind("stmt")),
493  Stm, Context);
494 
495  if (const auto *BadIteratorsContainer =
496  selectFirst<Stmt>("stmt", RefToContainerBadIterators))
497  return BadIteratorsContainer;
498 
499  // If range for looping over 'Exp' with a non-const reference loop variable,
500  // check all declRefExpr of the loop variable.
501  const auto LoopVars =
503  hasLoopVariable(varDecl(hasType(nonConstReferenceType()))
504  .bind(NodeID<Decl>::value)),
505  hasRangeInit(canResolveToExpr(equalsNode(Exp))))),
506  Stm, Context);
507  return findDeclMutation(LoopVars);
508 }
509 
510 const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) {
511  // Follow non-const reference returned by `operator*()` of move-only classes.
512  // These are typically smart pointers with unique ownership so we treat
513  // mutation of pointee as mutation of the smart pointer itself.
514  const auto Ref =
517  callee(cxxMethodDecl(ofClass(isMoveOnly()),
518  returns(nonConstReferenceType()))),
519  argumentCountIs(1),
520  hasArgument(0, canResolveToExpr(equalsNode(Exp))))
521  .bind(NodeID<Expr>::value)),
522  Stm, Context);
523  if (const Stmt *S = findExprMutation(Ref))
524  return S;
525 
526  // If 'Exp' is bound to a non-const reference, check all declRefExpr to that.
527  const auto Refs = match(
529  varDecl(
530  hasType(nonConstReferenceType()),
531  hasInitializer(anyOf(canResolveToExpr(equalsNode(Exp)),
532  memberExpr(hasObjectExpression(
533  canResolveToExpr(equalsNode(Exp)))))),
534  hasParent(declStmt().bind("stmt")),
535  // Don't follow the reference in range statement, we've
536  // handled that separately.
538  cxxForRangeStmt(hasRangeStmt(equalsBoundNode("stmt"))))))))
539  .bind(NodeID<Decl>::value))),
540  Stm, Context);
541  return findDeclMutation(Refs);
542 }
543 
544 const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) {
545  const auto NonConstRefParam = forEachArgumentWithParam(
546  canResolveToExpr(equalsNode(Exp)),
547  parmVarDecl(hasType(nonConstReferenceType())).bind("parm"));
548  const auto IsInstantiated = hasDeclaration(isInstantiated());
549  const auto FuncDecl = hasDeclaration(functionDecl().bind("func"));
550  const auto Matches = match(
551  traverse(
552  TK_AsIs,
553  findAll(
554  expr(anyOf(callExpr(NonConstRefParam, IsInstantiated, FuncDecl,
555  unless(callee(namedDecl(hasAnyName(
556  "::std::move", "::std::forward"))))),
557  cxxConstructExpr(NonConstRefParam, IsInstantiated,
558  FuncDecl)))
559  .bind(NodeID<Expr>::value))),
560  Stm, Context);
561  for (const auto &Nodes : Matches) {
562  const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
563  const auto *Func = Nodes.getNodeAs<FunctionDecl>("func");
564  if (!Func->getBody() || !Func->getPrimaryTemplate())
565  return Exp;
566 
567  const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
568  const ArrayRef<ParmVarDecl *> AllParams =
569  Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
570  QualType ParmType =
571  AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(),
572  AllParams.size() - 1)]
573  ->getType();
574  if (const auto *T = ParmType->getAs<PackExpansionType>())
575  ParmType = T->getPattern();
576 
577  // If param type is forwarding reference, follow into the function
578  // definition and see whether the param is mutated inside.
579  if (const auto *RefType = ParmType->getAs<RValueReferenceType>()) {
580  if (!RefType->getPointeeType().getQualifiers() &&
581  RefType->getPointeeType()->getAs<TemplateTypeParmType>()) {
582  std::unique_ptr<FunctionParmMutationAnalyzer> &Analyzer =
583  FuncParmAnalyzer[Func];
584  if (!Analyzer)
585  Analyzer.reset(new FunctionParmMutationAnalyzer(*Func, Context));
586  if (Analyzer->findMutation(Parm))
587  return Exp;
588  continue;
589  }
590  }
591  // Not forwarding reference.
592  return Exp;
593  }
594  return nullptr;
595 }
596 
598  const FunctionDecl &Func, ASTContext &Context)
599  : BodyAnalyzer(*Func.getBody(), Context) {
600  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(&Func)) {
601  // CXXCtorInitializer might also mutate Param but they're not part of
602  // function body, check them eagerly here since they're typically trivial.
603  for (const CXXCtorInitializer *Init : Ctor->inits()) {
604  ExprMutationAnalyzer InitAnalyzer(*Init->getInit(), Context);
605  for (const ParmVarDecl *Parm : Ctor->parameters()) {
606  if (Results.find(Parm) != Results.end())
607  continue;
608  if (const Stmt *S = InitAnalyzer.findMutation(Parm))
609  Results[Parm] = S;
610  }
611  }
612  }
613 }
614 
615 const Stmt *
617  const auto Memoized = Results.find(Parm);
618  if (Memoized != Results.end())
619  return Memoized->second;
620 
621  if (const Stmt *S = BodyAnalyzer.findMutation(Parm))
622  return Results[Parm] = S;
623 
624  return Results[Parm] = nullptr;
625 }
626 
627 } // namespace clang
clang::ast_matchers::hasParent
const internal::ArgumentAdaptingMatcherFunc< internal::HasParentMatcher, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr >, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr > > hasParent
Matches AST nodes that have a parent that matches the provided matcher.
Definition: ASTMatchersInternal.cpp:1020
clang::ast_matchers::hasAnyName
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
Definition: ASTMatchersInternal.cpp:998
clang::ast_matchers::initListExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, InitListExpr > initListExpr
Matches init list expressions.
Definition: ASTMatchersInternal.cpp:849
Nodes
BoundNodesTreeBuilder Nodes
Definition: ASTMatchFinder.cpp:83
clang::ast_matchers::stmt
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
Definition: ASTMatchersInternal.cpp:810
clang::ast_matchers::anyOf
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
Definition: ASTMatchersInternal.cpp:990
clang::ast_matchers::findAll
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
Definition: ASTMatchers.h:3489
clang::ast_matchers::genericSelectionExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, GenericSelectionExpr > genericSelectionExpr
Matches C11 _Generic expression.
Definition: ASTMatchersInternal.cpp:944
clang::ParmVarDecl
Represents a parameter to a function.
Definition: Decl.h:1680
clang::ast_matchers::memberExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, MemberExpr > memberExpr
Matches member expressions.
Definition: ASTMatchersInternal.cpp:812
ExprMutationAnalyzer.h
clang::ast_matchers::allOf
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
Definition: ASTMatchersInternal.cpp:993
clang::ast_matchers::explicitCastExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, ExplicitCastExpr > explicitCastExpr
Matches explicit cast expressions.
Definition: ASTMatchersInternal.cpp:973
clang::ast_matchers::returnStmt
const internal::VariadicDynCastAllOfMatcher< Stmt, ReturnStmt > returnStmt
Matches return statements.
Definition: ASTMatchersInternal.cpp:903
clang::ast_matchers::cxxConstructorDecl
const internal::VariadicDynCastAllOfMatcher< Decl, CXXConstructorDecl > cxxConstructorDecl
Matches C++ constructor declarations.
Definition: ASTMatchersInternal.cpp:792
ASTMatchFinder.h
clang::FunctionParmMutationAnalyzer::FunctionParmMutationAnalyzer
FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context)
Definition: ExprMutationAnalyzer.cpp:597
clang::ast_matchers::traverse
internal::Matcher< T > traverse(TraversalKind TK, const internal::Matcher< T > &InnerMatcher)
Causes all nested matchers to be matched with the specified traversal kind.
Definition: ASTMatchers.h:815
clang::ast_matchers::forEachDescendant
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
Definition: ASTMatchersInternal.cpp:1015
clang::ast_matchers::cxxForRangeStmt
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXForRangeStmt > cxxForRangeStmt
Matches range-based for statements.
Definition: ASTMatchersInternal.cpp:897
clang::ast_matchers::typeLoc
const internal::VariadicAllOfMatcher< TypeLoc > typeLoc
Matches TypeLocs in the clang AST.
Definition: ASTMatchersInternal.cpp:774
clang::CodeGen::AlignmentSource::Decl
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
clang::ast_matchers::cxxOperatorCallExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXOperatorCallExpr > cxxOperatorCallExpr
Matches overloaded operator calls.
Definition: ASTMatchersInternal.cpp:887
clang::ast_matchers::cxxDependentScopeMemberExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDependentScopeMemberExpr > cxxDependentScopeMemberExpr
Matches member expressions where the actual member referenced could not be resolved because the base ...
Definition: ASTMatchersInternal.cpp:816
clang::ast_matchers::expr
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
Definition: ASTMatchersInternal.cpp:890
clang::ExprMutationAnalyzer
Analyzes whether any mutative operations are applied to an expression within a given statement.
Definition: ExprMutationAnalyzer.h:23
Node
DynTypedNode Node
Definition: ASTMatchFinder.cpp:68
clang::ast_matchers::cxxUnresolvedConstructExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXUnresolvedConstructExpr > cxxUnresolvedConstructExpr
Matches unresolved constructor call expressions.
Definition: ASTMatchersInternal.cpp:872
clang::ExprMutationAnalyzer::isUnevaluated
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm, ASTContext &Context)
Definition: ExprMutationAnalyzer.cpp:202
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:209
ASTMatchers.h
clang::ast_matchers::cxxMethodDecl
const internal::VariadicDynCastAllOfMatcher< Decl, CXXMethodDecl > cxxMethodDecl
Matches method declarations.
Definition: ASTMatchersInternal.cpp:799
clang::ast_matchers::unaryExprOrTypeTraitExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryExprOrTypeTraitExpr > unaryExprOrTypeTraitExpr
Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
Definition: ASTMatchersInternal.cpp:789
Expr.h
clang::ExprMutationAnalyzer::findPointeeMutation
const Stmt * findPointeeMutation(const Expr *Exp)
Definition: ExprMutationAnalyzer.cpp:163
clang::ast_matchers::cxxMemberCallExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXMemberCallExpr > cxxMemberCallExpr
Matches member call expressions.
Definition: ASTMatchersInternal.cpp:820
clang::ast_matchers::binaryOperator
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
Definition: ASTMatchersInternal.cpp:948
OperationKinds.h
clang::ast_matchers::parenListExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, ParenListExpr > parenListExpr
Matches paren list expressions.
Definition: ASTMatchersInternal.cpp:854
clang::ast_matchers::unless
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
Definition: ASTMatchersInternal.cpp:1026
clang::ast_matchers::arrayType
const AstTypeMatcher< ArrayType > arrayType
Matches all kinds of arrays.
Definition: ASTMatchersInternal.cpp:1035
clang::ast_matchers::hasAncestor
const internal::ArgumentAdaptingMatcherFunc< internal::HasAncestorMatcher, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr >, internal::TypeList< Decl, NestedNameSpecifierLoc, Stmt, TypeLoc, Attr > > hasAncestor
Matches AST nodes that have an ancestor that matches the provided matcher.
Definition: ASTMatchersInternal.cpp:1025
clang::transformer::EditKind::Range
@ Range
clang::ExprMutationAnalyzer::findMutation
const Stmt * findMutation(const Expr *Exp)
Definition: ExprMutationAnalyzer.cpp:147
clang::ast_matchers::unaryOperator
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryOperator > unaryOperator
Matches unary operator expressions.
Definition: ASTMatchersInternal.cpp:953
clang::ast_matchers::variableArrayType
const AstTypeMatcher< VariableArrayType > variableArrayType
Matches C arrays with a specified size that is not an integer-constant-expression.
Definition: ASTMatchersInternal.cpp:1042
clang::ast_matchers::castExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CastExpr > castExpr
Matches any cast nodes of Clang's AST.
Definition: ASTMatchersInternal.cpp:976
clang::TK_AsIs
@ TK_AsIs
Will traverse all child nodes.
Definition: ASTTypeTraits.h:40
llvm::ArrayRef
Definition: LLVM.h:34
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
clang::FunctionParmMutationAnalyzer::findMutation
const Stmt * findMutation(const ParmVarDecl *Parm)
Definition: ExprMutationAnalyzer.cpp:616
clang::ast_matchers::arraySubscriptExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, ArraySubscriptExpr > arraySubscriptExpr
Matches array subscript expressions.
Definition: ASTMatchersInternal.cpp:883
clang::ast_matchers::hasDescendant
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
Definition: ASTMatchersInternal.cpp:1011
clang::ast_matchers::callExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
Definition: ASTMatchersInternal.cpp:817
clang::ast_matchers::functionDecl
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
Definition: ASTMatchersInternal.cpp:806
clang::ast_matchers::declRefExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
Definition: ASTMatchersInternal.cpp:891
clang::ast_matchers::pointerType
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
Definition: ASTMatchersInternal.cpp:1051
clang::Builtin::ID
ID
Definition: Builtins.h:52
clang::ast_matchers::binaryConditionalOperator
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryConditionalOperator > binaryConditionalOperator
Matches binary conditional operator expressions (GNU extension).
Definition: ASTMatchersInternal.cpp:957
clang
Definition: CalledOnceCheck.h:17
clang::ast_matchers::referenceType
const AstTypeMatcher< ReferenceType > referenceType
Matches both lvalue and rvalue reference types.
Definition: ASTMatchersInternal.cpp:1053
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:70
clang::ast_matchers::AST_MATCHER
AST_MATCHER(FieldDecl, isBitField)
Matches non-static data members that are bit-fields.
Definition: ASTMatchers.h:691
clang::ast_matchers::match
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
Definition: ASTMatchFinder.h:312
clang::ast_matchers::hasName
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
Definition: ASTMatchers.h:3000
clang::ast_matchers::namedDecl
const internal::VariadicDynCastAllOfMatcher< Decl, NamedDecl > namedDecl
Matches a declaration of anything that could have a name.
Definition: ASTMatchersInternal.cpp:739
clang::ast_matchers::lambdaExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, LambdaExpr > lambdaExpr
Matches lambda expressions.
Definition: ASTMatchersInternal.cpp:818
clang::ast_matchers::unresolvedMemberExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, UnresolvedMemberExpr > unresolvedMemberExpr
Matches unresolved member expressions.
Definition: ASTMatchersInternal.cpp:814
clang::ast_matchers::unresolvedLookupExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, UnresolvedLookupExpr > unresolvedLookupExpr
Matches reference to a name that can be looked up during parsing but could not be resolved to a speci...
Definition: ASTMatchersInternal.cpp:862
clang::ast_matchers::cxxRecordDecl
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
Definition: ASTMatchersInternal.cpp:745
clang::ast_matchers::cxxNoexceptExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXNoexceptExpr > cxxNoexceptExpr
Matches noexcept expressions.
Definition: ASTMatchersInternal.cpp:881
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::ast_matchers::cxxConstructExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXConstructExpr > cxxConstructExpr
Matches constructor call expressions (including implicit ones).
Definition: ASTMatchersInternal.cpp:870
clang::CXXCtorInitializer
Represents a C++ base or member initializer.
Definition: DeclCXX.h:2205
clang::ast_matchers::varDecl
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
Definition: ASTMatchersInternal.cpp:802
clang::ast_matchers::has
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
Definition: ASTMatchersInternal.cpp:1009
clang::ast_matchers::hasDeclaration
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
Definition: ASTMatchers.h:3574
clang::ast_matchers::templateTypeParmType
const AstTypeMatcher< TemplateTypeParmType > templateTypeParmType
Matches template type parameter types.
Definition: ASTMatchersInternal.cpp:1065
clang::ast_matchers::implicitCastExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, ImplicitCastExpr > implicitCastExpr
Matches the implicit cast nodes of Clang's AST.
Definition: ASTMatchersInternal.cpp:975
clang::ast_matchers::declStmt
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclStmt > declStmt
Matches declaration statements.
Definition: ASTMatchersInternal.cpp:811
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1872
clang::ast_matchers::hasOverloadedOperatorName
internal::PolymorphicMatcher< internal::HasOverloadedOperatorNameMatcher, AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl), std::vector< std::string > > hasOverloadedOperatorName(StringRef Name)
Matches overloaded operator names.
Definition: ASTMatchers.h:3063
clang::ast_matchers::parmVarDecl
const internal::VariadicDynCastAllOfMatcher< Decl, ParmVarDecl > parmVarDecl
Matches parameter variable declarations.
Definition: ASTMatchersInternal.cpp:756
clang::ast_matchers::conditionalOperator
const internal::VariadicDynCastAllOfMatcher< Stmt, ConditionalOperator > conditionalOperator
Matches conditional operator expressions.
Definition: ASTMatchersInternal.cpp:955
clang::ast_matchers::AST_MATCHER_P
AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width)
Matches non-static data members that are bit-fields of the specified bit width.
Definition: ASTMatchers.h:708
clang::ast_matchers::sizeOfExpr
internal::BindableMatcher< Stmt > sizeOfExpr(const internal::Matcher< UnaryExprOrTypeTraitExpr > &InnerMatcher)
Same as unaryExprOrTypeTraitExpr, but only matching sizeof.
Definition: ASTMatchers.h:2979