[analyzer] Fix property access kind detection inside parentheses.

'(self.prop)' produces a surprising AST where ParenExpr
resides inside `PseudoObjectExpr.

This breaks ObjCMethodCall::getMessageKind() which in turn causes us
to perform unnecessary dynamic dispatch bifurcation when evaluating
body-farmed property accessors, which in turn causes us
to explore infeasible paths.
This commit is contained in:
Artem Dergachev 2021-10-14 20:32:54 -07:00
parent effbf0bdd0
commit 12cbc8cbf0
2 changed files with 35 additions and 4 deletions

View File

@ -1039,12 +1039,12 @@ const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const {
static const Expr *
getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr *POE) {
const Expr *Syntactic = POE->getSyntacticForm();
const Expr *Syntactic = POE->getSyntacticForm()->IgnoreParens();
// This handles the funny case of assigning to the result of a getter.
// This can happen if the getter returns a non-const reference.
if (const auto *BO = dyn_cast<BinaryOperator>(Syntactic))
Syntactic = BO->getLHS();
Syntactic = BO->getLHS()->IgnoreParens();
return Syntactic;
}

View File

@ -1,5 +1,35 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-objc-root-class %s -verify
// expected-no-diagnostics
// RUN: %clang_analyze_cc1 -w %s -verify \
// RUN: -analyzer-checker=core,alpha.core,debug.ExprInspection
#ifdef HEADER // A clever trick to avoid splitting up the test.
@interface NSObject
@end
@interface HeaderClass : NSObject
@property NSObject *prop;
@end
#else
#define HEADER
#include "ObjCProperties.m"
@implementation HeaderClass
- (void)foo {
if ((self.prop)) {
}
// This test tests that no dynamic bifurcation is performed on the property.
// The TRUE/FALSE dilemma correctly arises from eagerly-assume behavior
// inside the if-statement. The dynamic bifurcation at (self.prop) inside
// the if-statement was causing an UNKNOWN to show up as well due to
// extra parentheses being caught inside PseudoObjectExpr.
// This should not be UNKNOWN.
clang_analyzer_eval(self.prop); // expected-warning{{TRUE}}
// expected-warning@-1{{FALSE}}
}
@end
// The point of this test cases is to exercise properties in the static
// analyzer
@ -19,3 +49,4 @@
return self;
}
@end
#endif