From: George Karpenkov Date: Fri, 30 Nov 2018 02:17:57 +0000 (+0000) Subject: [analyzer] Print a fully qualified name for functions in RetainCountChecker diagnostics X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=06d1de83f0578f4eca6cab53cce1945aec66161e;p=clang [analyzer] Print a fully qualified name for functions in RetainCountChecker diagnostics Attempt to get a fully qualified name from AST if an SVal corresponding to the object is not available. Differential Revision: https://reviews.llvm.org/D55034 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@347944 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp index 8758091a9b..ce824ba077 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp @@ -173,10 +173,19 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, os << "Object loaded from instance variable"; } else { if (const CallExpr *CE = dyn_cast(S)) { - // Get the name of the callee (if it is available). + // Get the name of the callee (if it is available) + // from the tracked SVal. SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); - if (const FunctionDecl *FD = X.getAsFunctionDecl()) { - os << "Call to function '" << *FD << '\''; + const FunctionDecl *FD = X.getAsFunctionDecl(); + + // If failed, try to get it from AST. + if (!FD) + FD = dyn_cast(CE->getCalleeDecl()); + + if (const auto *MD = dyn_cast(CE->getCalleeDecl())) { + os << "Call to method '" << MD->getQualifiedNameAsString() << '\''; + } else if (FD) { + os << "Call to function '" << FD->getQualifiedNameAsString() << '\''; } else { os << "function call"; } diff --git a/test/Analysis/osobject-retain-release.cpp b/test/Analysis/osobject-retain-release.cpp index d53ebbab5f..6b31632b03 100644 --- a/test/Analysis/osobject-retain-release.cpp +++ b/test/Analysis/osobject-retain-release.cpp @@ -60,14 +60,19 @@ void check_custom_iterator_rule(OSArray *arr) { it->release(); } +void check_iterator_leak(OSArray *arr) { + arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type struct OSIterator * with a +1 retain count}} +} // expected-note{{Object leaked: allocated object of type struct OSIterator * is not referenced later}} + // expected-warning@-1{{Potential leak of an object of type struct OSIterator *}}n this execution path and has a retain count of +1}} + void check_no_invalidation() { - OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} + OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} OtherStruct::doNothingToArray(arr); } // expected-warning{{Potential leak of an object stored into 'arr'}} // expected-note@-1{{Object leaked}} void check_no_invalidation_other_struct() { - OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} + OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} OtherStruct other(arr); // expected-warning{{Potential leak}} // expected-note@-1{{Object leaked}} } @@ -94,8 +99,8 @@ struct ArrayOwner : public OSObject { }; OSArray *generateArray() { - return OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} - // expected-note@-1{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} + return OSArray::withCapacity(10); // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} + // expected-note@-1{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} } unsigned int check_leak_good_error_message() { @@ -164,7 +169,7 @@ unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) { } void check_dynamic_cast_null_branch(OSObject *obj) { - OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}} + OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}} OSArray *arr = OSDynamicCast(OSArray, obj); if (!arr) // expected-note{{Taking true branch}} return; // expected-warning{{Potential leak of an object stored into 'arr1'}} @@ -173,7 +178,7 @@ void check_dynamic_cast_null_branch(OSObject *obj) { } void check_dynamic_cast_null_check() { - OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}} + OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}} // expected-warning@-1{{Potential leak of an object}} // expected-note@-2{{Object leaked}} if (!arr) @@ -182,14 +187,14 @@ void check_dynamic_cast_null_check() { } void use_after_release() { - OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} + OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} arr->release(); // expected-note{{Object released}} arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}} // expected-note@-1{{Reference-counted object is used after it is released}} } void potential_leak() { - OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} + OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}} arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}} arr->getCount(); @@ -240,7 +245,7 @@ unsigned int no_warn_ok_release(ArrayOwner *owner) { } unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) { - OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type OSArray with a +0 retain count}} + OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}} arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} return arr->getCount();