================ @@ -34,69 +36,185 @@ void extractNodesByIdTo(ArrayRef<BoundNodes> Matches, StringRef ID, Nodes.insert(Match.getNodeAs<Node>(ID)); } +// A matcher that matches DeclRefExprs that are used in ways such that the +// underlying declaration is not modified. +// If the declaration is of pointer type, `Indirections` specifies the level +// of indirection of the object whose mutations we are tracking. +// +// For example, given: +// ``` +// int i; +// int* p; +// p = &i; // (A) +// *p = 3; // (B) +// ``` +// +// `declRefExpr(to(varDecl(hasName("p"))), doesNotMutateObject(0))` matches +// (B), but `declRefExpr(to(varDecl(hasName("p"))), doesNotMutateObject(1))` +// matches (A). +// +AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) { + // We walk up the parents of the DeclRefExpr recursively until we end up on a + // parent that cannot modify the underlying object. There are a few kinds of + // expressions: + // - Those that cannot be used to mutate the underlying object. We can stop + // recursion there. + // - Those that can be used to mutate the underlying object in analyzable + // ways (such as taking the address or accessing a subobject). We have to + // examine the parents. + // - Those that we don't know how to analyze. In that case we stop there and + // we assume that they can mutate the underlying expression. + + struct StackEntry { + StackEntry(const Expr *E, int Indirections) + : E(E), Indirections(Indirections) {} + // The expression to analyze. + const Expr *E; + // The number of pointer indirections of the object being tracked (how + // many times an address was taken). + int Indirections; + }; + + llvm::SmallVector<StackEntry, 4> Stack; + Stack.emplace_back(&Node, Indirections); + auto &Ctx = Finder->getASTContext(); + + while (!Stack.empty()) { + const StackEntry Entry = Stack.back(); + Stack.pop_back(); + + // If the expression type is const-qualified at the appropriate indirection + // level then we can not mutate the object. + QualType Ty = Entry.E->getType().getCanonicalType(); + for (int I = 0; I < Entry.Indirections; ++I) { + assert(Ty->isPointerType()); + Ty = Ty->getPointeeType().getCanonicalType(); + } + if (Ty.isConstQualified()) { + continue; + } + + // Otherwise we have to look at the parents to see how the expression is + // used. + const auto Parents = Ctx.getParents(*Entry.E); ---------------- EugeneZelenko wrote:
Please don't use `auto` - type is not spelled. https://github.com/llvm/llvm-project/pull/82617 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits