diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2017-06-05 12:40:03 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2017-06-05 12:40:03 +0000 |
commit | d6f929a22be467bf8cf89eafd5e022a081a45488 (patch) | |
tree | 1b5bbdd4ad39d7120d3ce359d3940da2c22c97d1 /lib/StaticAnalyzer | |
parent | d5e54601f1177956d8206c08b1c8d7d5fd8e2407 (diff) |
[analyzer] Nullability: fix notes around synthesized ObjC property accessors.
Nullable-to-nonnull checks used to crash when the custom bug visitor was trying
to add its notes to autosynthesized accessors of Objective-C properties.
Now we avoid this, mostly automatically outside of checker control, by
moving the diagnostic to the parent stack frame where the accessor has been
called.
Differential revision: https://reviews.llvm.org/D32437
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@304710 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp | 2 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 46 |
2 files changed, 45 insertions, 3 deletions
diff --git a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 41999d2527..fa9a317683 100644 --- a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -326,7 +326,7 @@ NullabilityChecker::NullabilityBugVisitor::VisitNode(const ExplodedNode *N, // Retrieve the associated statement. const Stmt *S = TrackedNullab->getNullabilitySource(); - if (!S) { + if (!S || S->getLocStart().isInvalid()) { S = PathDiagnosticLocation::getStmt(N); } diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 7c5ee3b259..6aa6da560e 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -694,7 +694,30 @@ PathDiagnosticLocation::create(const ProgramPoint& P, return PathDiagnosticLocation(S, SMng, P.getLocationContext()); } +static const LocationContext * +findTopAutosynthesizedParentContext(const LocationContext *LC) { + assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized()); + const LocationContext *ParentLC = LC->getParent(); + assert(ParentLC && "We don't start analysis from autosynthesized code"); + while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) { + LC = ParentLC; + ParentLC = LC->getParent(); + assert(ParentLC && "We don't start analysis from autosynthesized code"); + } + return LC; +} + const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { + // We cannot place diagnostics on autosynthesized code. + // Put them onto the call site through which we jumped into autosynthesized + // code for the first time. + const LocationContext *LC = N->getLocationContext(); + if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) { + // It must be a stack frame because we only autosynthesize functions. + return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC)) + ->getCallSite(); + } + // Otherwise, see if the node's program point directly points to a statement. ProgramPoint P = N->getLocation(); if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) return SP->getStmt(); @@ -912,6 +935,17 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); + + // Autosynthesized property accessors are special because we'd never + // pop back up to non-autosynthesized code until we leave them. + // This is not generally true for autosynthesized callees, which may call + // non-autosynthesized callbacks. + // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag + // defaults to false. + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Callee)) + IsCalleeAnAutosynthesizedPropertyAccessor = ( + MD->isPropertyAccessor() && + CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); } static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, @@ -986,7 +1020,11 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, std::shared_ptr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallEnterEvent() const { - if (!Callee) + // We do not produce call enters and call exits for autosynthesized property + // accessors. We do generally produce them for other functions coming from + // the body farm because they may call callbacks that bring us back into + // visible code. + if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor) return nullptr; SmallString<256> buf; @@ -1020,7 +1058,11 @@ PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { std::shared_ptr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallExitEvent() const { - if (NoExit) + // We do not produce call enters and call exits for autosynthesized property + // accessors. We do generally produce them for other functions coming from + // the body farm because they may call callbacks that bring us back into + // visible code. + if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor) return nullptr; SmallString<256> buf; |