[clang-tools-extra] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 23 08:10:34 PST 2024
================
@@ -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
More information about the cfe-commits
mailing list