From: Artem Dergachev Date: Mon, 1 Jul 2019 23:02:14 +0000 (+0000) Subject: [analyzer] NonnullGlobalConstants: Don't be confused by a _Nonnull attribute. X-Git-Tag: llvmorg-10-init~1520 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=512f4838c47c5bab13d8bb0eabc01d64222825ae;p=platform%2Fupstream%2Fllvm.git [analyzer] NonnullGlobalConstants: Don't be confused by a _Nonnull attribute. The NonnullGlobalConstants checker models the rule "it doesn't make sense to make a constant global pointer and initialize it to null"; it makes sure that whatever it's initialized with is known to be non-null. Ironically, annotating the type of the pointer as _Nonnull breaks the checker. Fix handling of the _Nonnull annotation so that it was instead one more reason to believe that the value is non-null. Differential Revision: https://reviews.llvm.org/D63956 llvm-svn: 364869 --- diff --git a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp index dd76fd2..43dbe57 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp @@ -106,14 +106,21 @@ bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const { return true; // Look through the typedefs. - while (auto *T = dyn_cast(Ty)) { - Ty = T->getDecl()->getUnderlyingType(); - - // It is sufficient for any intermediate typedef - // to be classified const. - HasConst = HasConst || Ty.isConstQualified(); - if (isNonnullType(Ty) && HasConst) - return true; + while (const Type *T = Ty.getTypePtr()) { + if (const auto *TT = dyn_cast(T)) { + Ty = TT->getDecl()->getUnderlyingType(); + // It is sufficient for any intermediate typedef + // to be classified const. + HasConst = HasConst || Ty.isConstQualified(); + if (isNonnullType(Ty) && HasConst) + return true; + } else if (const auto *AT = dyn_cast(T)) { + if (AT->getAttrKind() == attr::TypeNonNull) + return true; + Ty = AT->getModifiedType(); + } else { + return false; + } } return false; } diff --git a/clang/test/Analysis/nonnull-global-constants.mm b/clang/test/Analysis/nonnull-global-constants.mm index 7900b9d..9e1a588 100644 --- a/clang/test/Analysis/nonnull-global-constants.mm +++ b/clang/test/Analysis/nonnull-global-constants.mm @@ -101,3 +101,15 @@ extern CFBooleanRef kBoolMutable; void testNonnullNonconstBool() { clang_analyzer_eval(kBoolMutable); // expected-warning{{UNKNOWN}} } + +// If it's annotated as nonnull, it doesn't even need to be const. +extern CFStringRef _Nonnull str3; +void testNonnullNonconstCFString() { + clang_analyzer_eval(str3); // expected-warning{{TRUE}} +} + +// This one's nonnull for two reasons. +extern const CFStringRef _Nonnull str4; +void testNonnullNonnullCFString() { + clang_analyzer_eval(str4); // expected-warning{{TRUE}} +}