//===--- DeclRefExprUtils.cpp - clang-tidy---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "DeclRefExprUtils.h" #include "Matchers.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include <cassert> namespace clang::tidy::utils::decl_ref_expr { usingnamespace::clang::ast_matchers; SmallPtrSet; namespace { template <typename S> bool isSetDifferenceEmpty(const S &S1, const S &S2) { … } // Extracts all Nodes keyed by ID from Matches and inserts them into Nodes. template <typename Node> void extractNodesByIdTo(ArrayRef<BoundNodes> Matches, StringRef ID, SmallPtrSet<const Node *, 16> &Nodes) { … } // Returns true if both types refer to the same type, // ignoring the const-qualifier. bool isSameTypeIgnoringConst(QualType A, QualType B) { … } // Returns true if `D` and `O` have the same parameter types. bool hasSameParameterTypes(const CXXMethodDecl &D, const CXXMethodDecl &O) { … } // If `D` has a const-qualified overload with otherwise identical // ref-qualifiers and parameter types, returns that overload. const CXXMethodDecl *findConstOverload(const CXXMethodDecl &D) { … } // Returns true if both types are pointers or reference to the same type, // ignoring the const-qualifier. bool pointsToSameTypeIgnoringConst(QualType A, QualType B) { … } // Return true if non-const member function `M` likely does not mutate `*this`. // // Note that if the member call selects a method/operator `f` that // is not const-qualified, then we also consider that the object is // not mutated if: // - (A) there is a const-qualified overload `cf` of `f` that has // the // same ref-qualifiers; // - (B) * `f` returns a value, or // * if `f` returns a `T&`, `cf` returns a `const T&` (up to // possible aliases such as `reference` and // `const_reference`), or // * if `f` returns a `T*`, `cf` returns a `const T*` (up to // possible aliases). // - (C) the result of the call is not mutated. // // The assumption that `cf` has the same semantics as `f`. // For example: // - In `std::vector<T> v; const T t = v[...];`, we consider that // expression `v[...]` does not mutate `v` as // `T& std::vector<T>::operator[]` has a const overload // `const T& std::vector<T>::operator[] const`, and the // result expression of type `T&` is only used as a `const T&`; // - In `std::map<K, V> m; V v = m.at(...);`, we consider // `m.at(...)` to be an immutable access for the same reason. // However: // - In `std::map<K, V> m; const V v = m[...];`, We consider that // `m[...]` mutates `m` as `V& std::map<K, V>::operator[]` does // not have a const overload. // - In `std::vector<T> v; T& t = v[...];`, we consider that // expression `v[...]` mutates `v` as the result is kept as a // mutable reference. // // This function checks (A) ad (B), but the caller should make sure that the // object is not mutated through the return value. bool isLikelyShallowConst(const CXXMethodDecl &M) { … } // 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) { … } } // namespace SmallPtrSet<const DeclRefExpr *, 16> constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context, int Indirections) { … } bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, ASTContext &Context, int Indirections) { … } SmallPtrSet<const DeclRefExpr *, 16> allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context) { … } SmallPtrSet<const DeclRefExpr *, 16> allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context) { … } bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl, ASTContext &Context) { … } bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl, ASTContext &Context) { … } } // namespace clang::tidy::utils::decl_ref_expr