diff options
Diffstat (limited to 'clang/lib/Analysis')
| -rw-r--r-- | clang/lib/Analysis/ExprMutationAnalyzer.cpp | 88 |
1 files changed, 86 insertions, 2 deletions
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index f4be35b3219..678eeebab2d 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -79,7 +79,8 @@ const Stmt *ExprMutationAnalyzer::findMutation(const Expr *Exp) { &ExprMutationAnalyzer::findArrayElementMutation, &ExprMutationAnalyzer::findCastMutation, &ExprMutationAnalyzer::findRangeLoopMutation, - &ExprMutationAnalyzer::findReferenceMutation}) { + &ExprMutationAnalyzer::findReferenceMutation, + &ExprMutationAnalyzer::findFunctionArgMutation}) { if (const Stmt *S = (this->*Finder)(Exp)) return Results[Exp] = S; } @@ -192,10 +193,15 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { // Used as non-const-ref argument when calling a function. // An argument is assumed to be non-const-ref when the function is unresolved. + // Instantiated template functions are not handled here but in + // findFunctionArgMutation which has additional smarts for handling forwarding + // references. const auto NonConstRefParam = forEachArgumentWithParam( equalsNode(Exp), parmVarDecl(hasType(nonConstReferenceType()))); + const auto NotInstantiated = unless(hasDeclaration(isInstantiated())); const auto AsNonConstRefArg = anyOf( - callExpr(NonConstRefParam), cxxConstructExpr(NonConstRefParam), + callExpr(NonConstRefParam, NotInstantiated), + cxxConstructExpr(NonConstRefParam, NotInstantiated), callExpr(callee(expr(anyOf(unresolvedLookupExpr(), unresolvedMemberExpr(), cxxDependentScopeMemberExpr(), hasType(templateTypeParmType())))), @@ -305,4 +311,82 @@ const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) { return findDeclMutation(Refs); } +const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) { + const auto NonConstRefParam = forEachArgumentWithParam( + equalsNode(Exp), + parmVarDecl(hasType(nonConstReferenceType())).bind("parm")); + const auto IsInstantiated = hasDeclaration(isInstantiated()); + const auto FuncDecl = hasDeclaration(functionDecl().bind("func")); + const auto Matches = match( + findAll(expr(anyOf(callExpr(NonConstRefParam, IsInstantiated, FuncDecl), + cxxConstructExpr(NonConstRefParam, IsInstantiated, + FuncDecl))) + .bind("expr")), + Stm, Context); + for (const auto &Nodes : Matches) { + const auto *Exp = Nodes.getNodeAs<Expr>("expr"); + const auto *Func = Nodes.getNodeAs<FunctionDecl>("func"); + if (!Func->getBody()) + return Exp; + + const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm"); + const ArrayRef<ParmVarDecl *> AllParams = + Func->getPrimaryTemplate()->getTemplatedDecl()->parameters(); + QualType ParmType = + AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(), + AllParams.size() - 1)] + ->getType(); + if (const auto *T = ParmType->getAs<PackExpansionType>()) + ParmType = T->getPattern(); + + // If param type is forwarding reference, follow into the function + // definition and see whether the param is mutated inside. + if (const auto *RefType = ParmType->getAs<RValueReferenceType>()) { + if (!RefType->getPointeeType().getQualifiers() && + RefType->getPointeeType()->getAs<TemplateTypeParmType>()) { + std::unique_ptr<FunctionParmMutationAnalyzer> &Analyzer = + FuncParmAnalyzer[Func]; + if (!Analyzer) + Analyzer.reset(new FunctionParmMutationAnalyzer(*Func, Context)); + if (Analyzer->findMutation(Parm)) + return Exp; + continue; + } + } + // Not forwarding reference. + return Exp; + } + return nullptr; +} + +FunctionParmMutationAnalyzer::FunctionParmMutationAnalyzer( + const FunctionDecl &Func, ASTContext &Context) + : BodyAnalyzer(*Func.getBody(), Context) { + if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(&Func)) { + // CXXCtorInitializer might also mutate Param but they're not part of + // function body, check them eagerly here since they're typically trivial. + for (const CXXCtorInitializer *Init : Ctor->inits()) { + ExprMutationAnalyzer InitAnalyzer(*Init->getInit(), Context); + for (const ParmVarDecl *Parm : Ctor->parameters()) { + if (Results.find(Parm) != Results.end()) + continue; + if (const Stmt *S = InitAnalyzer.findDeclMutation(Parm)) + Results[Parm] = S; + } + } + } +} + +const Stmt * +FunctionParmMutationAnalyzer::findMutation(const ParmVarDecl *Parm) { + const auto Memoized = Results.find(Parm); + if (Memoized != Results.end()) + return Memoized->second; + + if (const Stmt *S = BodyAnalyzer.findDeclMutation(Parm)) + return Results[Parm] = S; + + return Results[Parm] = nullptr; +} + } // namespace clang |

