8
8
#include " clang/Analysis/Analyses/ExprMutationAnalyzer.h"
9
9
#include " clang/AST/Expr.h"
10
10
#include " clang/AST/OperationKinds.h"
11
+ #include " clang/AST/Stmt.h"
11
12
#include " clang/ASTMatchers/ASTMatchFinder.h"
12
13
#include " clang/ASTMatchers/ASTMatchers.h"
14
+ #include " clang/ASTMatchers/ASTMatchersMacros.h"
13
15
#include " llvm/ADT/STLExtras.h"
16
+ #include " llvm/Support/Casting.h"
14
17
15
18
namespace clang {
16
19
using namespace ast_matchers ;
@@ -22,7 +25,6 @@ using namespace ast_matchers;
22
25
// - ConditionalOperator
23
26
// - BinaryConditionalOperator
24
27
static bool canExprResolveTo (const Expr *Source, const Expr *Target) {
25
-
26
28
const auto IgnoreDerivedToBase = [](const Expr *E, auto Matcher) {
27
29
if (Matcher (E))
28
30
return true ;
@@ -92,6 +94,8 @@ static bool canExprResolveTo(const Expr *Source, const Expr *Target) {
92
94
93
95
namespace {
94
96
97
+ AST_MATCHER (Type, isDependentType) { return Node.isDependentType (); }
98
+
95
99
AST_MATCHER_P (LambdaExpr, hasCaptureInit, const Expr *, E) {
96
100
return llvm::is_contained (Node.capture_inits (), E);
97
101
}
@@ -112,6 +116,53 @@ AST_MATCHER_P(Stmt, canResolveToExpr, const Stmt *, Inner) {
112
116
return canExprResolveTo (Exp, Target);
113
117
}
114
118
119
+ class ExprPointeeResolve {
120
+ const Expr *T;
121
+
122
+ bool resolveExpr (const Expr *E) {
123
+ if (E == T)
124
+ return true ;
125
+
126
+ if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
127
+ if (BO->isAdditiveOp ())
128
+ return (resolveExpr (BO->getLHS ()) || resolveExpr (BO->getRHS ()));
129
+ if (BO->isCommaOp ())
130
+ return resolveExpr (BO->getRHS ());
131
+ return false ;
132
+ }
133
+
134
+ if (const auto *PE = dyn_cast<ParenExpr>(E))
135
+ return resolveExpr (PE->getSubExpr ());
136
+
137
+ if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
138
+ const CastKind kind = ICE->getCastKind ();
139
+ if (kind == CK_LValueToRValue || kind == CK_DerivedToBase ||
140
+ kind == CK_UncheckedDerivedToBase)
141
+ return resolveExpr (ICE->getSubExpr ());
142
+ return false ;
143
+ }
144
+
145
+ if (const auto *ACE = dyn_cast<AbstractConditionalOperator>(E))
146
+ return resolve (ACE->getTrueExpr ()) || resolve (ACE->getFalseExpr ());
147
+
148
+ return false ;
149
+ }
150
+
151
+ public:
152
+ ExprPointeeResolve (const Expr *T) : T(T) {}
153
+ bool resolve (const Expr *S) { return resolveExpr (S); }
154
+ };
155
+
156
+ AST_MATCHER_P (Stmt, canResolveToExprPointee, const Stmt *, T) {
157
+ auto *Exp = dyn_cast<Expr>(&Node);
158
+ if (!Exp)
159
+ return true ;
160
+ auto *Target = dyn_cast<Expr>(T);
161
+ if (!Target)
162
+ return false ;
163
+ return ExprPointeeResolve{Target}.resolve (Exp);
164
+ }
165
+
115
166
// Similar to 'hasAnyArgument', but does not work because 'InitListExpr' does
116
167
// not have the 'arguments()' method.
117
168
AST_MATCHER_P (InitListExpr, hasAnyInit, ast_matchers::internal::Matcher<Expr>,
@@ -219,7 +270,14 @@ const Stmt *ExprMutationAnalyzer::Analyzer::findMutation(const Decl *Dec) {
219
270
220
271
const Stmt *
221
272
ExprMutationAnalyzer::Analyzer::findPointeeMutation (const Expr *Exp) {
222
- return findMutationMemoized (Exp, {/* TODO*/ }, Memorized.PointeeResults );
273
+ return findMutationMemoized (
274
+ Exp,
275
+ {
276
+ &ExprMutationAnalyzer::Analyzer::findPointeeValueMutation,
277
+ &ExprMutationAnalyzer::Analyzer::findPointeeMemberMutation,
278
+ &ExprMutationAnalyzer::Analyzer::findPointeeToNonConst,
279
+ },
280
+ Memorized.PointeeResults );
223
281
}
224
282
225
283
const Stmt *
@@ -388,7 +446,8 @@ ExprMutationAnalyzer::Analyzer::findDirectMutation(const Expr *Exp) {
388
446
// references.
389
447
const auto NonConstRefParam = forEachArgumentWithParamType (
390
448
anyOf (canResolveToExpr (Exp),
391
- memberExpr (hasObjectExpression (canResolveToExpr (Exp)))),
449
+ memberExpr (
450
+ hasObjectExpression (ignoringImpCasts (canResolveToExpr (Exp))))),
392
451
nonConstReferenceType ());
393
452
const auto NotInstantiated = unless (hasDeclaration (isInstantiated ()));
394
453
@@ -654,6 +713,83 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
654
713
return nullptr ;
655
714
}
656
715
716
+ const Stmt *
717
+ ExprMutationAnalyzer::Analyzer::findPointeeValueMutation (const Expr *Exp) {
718
+ const auto Matches = match (
719
+ stmt (forEachDescendant (
720
+ expr (anyOf (
721
+ // deref by *
722
+ unaryOperator (hasOperatorName (" *" ),
723
+ hasUnaryOperand (canResolveToExprPointee (Exp))),
724
+ // deref by []
725
+ arraySubscriptExpr (hasBase (canResolveToExprPointee (Exp)))))
726
+ .bind (NodeID<Expr>::value))),
727
+ Stm, Context);
728
+ return findExprMutation (Matches);
729
+ }
730
+
731
+ const Stmt *
732
+ ExprMutationAnalyzer::Analyzer::findPointeeMemberMutation (const Expr *Exp) {
733
+ const Stmt *MemberCallExpr = selectFirst<Stmt>(
734
+ " stmt" , match (stmt (forEachDescendant (
735
+ cxxMemberCallExpr (on (canResolveToExprPointee (Exp)),
736
+ unless (isConstCallee ()))
737
+ .bind (" stmt" ))),
738
+ Stm, Context));
739
+ if (MemberCallExpr)
740
+ return MemberCallExpr;
741
+ const auto Matches =
742
+ match (stmt (forEachDescendant (
743
+ memberExpr (hasObjectExpression (canResolveToExprPointee (Exp)))
744
+ .bind (NodeID<Expr>::value))),
745
+ Stm, Context);
746
+ return findExprMutation (Matches);
747
+ }
748
+
749
+ const Stmt *
750
+ ExprMutationAnalyzer::Analyzer::findPointeeToNonConst (const Expr *Exp) {
751
+ const auto NonConstPointerOrDependentType =
752
+ type (anyOf (nonConstPointerType (), isDependentType ()));
753
+
754
+ // assign
755
+ const auto InitToNonConst =
756
+ varDecl (hasType (NonConstPointerOrDependentType),
757
+ hasInitializer (expr (canResolveToExprPointee (Exp)).bind (" stmt" )));
758
+ const auto AssignToNonConst =
759
+ binaryOperation (hasOperatorName (" =" ),
760
+ hasLHS (expr (hasType (NonConstPointerOrDependentType))),
761
+ hasRHS (canResolveToExprPointee (Exp)));
762
+ // arguments like
763
+ const auto ArgOfInstantiationDependent = allOf (
764
+ hasAnyArgument (canResolveToExprPointee (Exp)), isInstantiationDependent ());
765
+ const auto ArgOfNonConstParameter = forEachArgumentWithParamType (
766
+ canResolveToExprPointee (Exp), NonConstPointerOrDependentType);
767
+ const auto CallLikeMatcher =
768
+ anyOf (ArgOfNonConstParameter, ArgOfInstantiationDependent);
769
+ const auto PassAsNonConstArg =
770
+ expr (anyOf (cxxUnresolvedConstructExpr (ArgOfInstantiationDependent),
771
+ cxxConstructExpr (CallLikeMatcher), callExpr (CallLikeMatcher),
772
+ parenListExpr (has (canResolveToExprPointee (Exp))),
773
+ initListExpr (hasAnyInit (canResolveToExprPointee (Exp)))));
774
+ // cast
775
+ const auto CastToNonConst =
776
+ explicitCastExpr (hasSourceExpression (canResolveToExprPointee (Exp)),
777
+ hasDestinationType (NonConstPointerOrDependentType));
778
+
779
+ // capture
780
+ // FIXME: false positive if the pointee does not change in lambda
781
+ const auto CaptureNoConst = lambdaExpr (hasCaptureInit (Exp));
782
+
783
+ const auto Matches =
784
+ match (stmt (anyOf (forEachDescendant (
785
+ stmt (anyOf (AssignToNonConst, PassAsNonConstArg,
786
+ CastToNonConst, CaptureNoConst))
787
+ .bind (" stmt" )),
788
+ forEachDescendant (decl (InitToNonConst)))),
789
+ Stm, Context);
790
+ return selectFirst<Stmt>(" stmt" , Matches);
791
+ }
792
+
657
793
FunctionParmMutationAnalyzer::FunctionParmMutationAnalyzer (
658
794
const FunctionDecl &Func, ASTContext &Context,
659
795
ExprMutationAnalyzer::Memoized &Memorized)
0 commit comments