Author: szelethus Date: Fri Jul 13 05:54:47 2018 New Revision: 336995 URL: http://llvm.org/viewvc/llvm-project?rev=336995&view=rev Log: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name
Differential Revision: https://reviews.llvm.org/D48291 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp?rev=336995&r1=336994&r2=336995&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp Fri Jul 13 05:54:47 2018 @@ -232,6 +232,10 @@ static bool isPrimitiveType(const QualTy static void printNoteMessage(llvm::raw_ostream &Out, const FieldChainInfo &Chain); +/// Returns with Field's name. This is a helper function to get the correct name +/// even if Field is a captured lambda variable. +static StringRef getVariableName(const FieldDecl *Field); + //===----------------------------------------------------------------------===// // Methods for UninitializedObjectChecker. //===----------------------------------------------------------------------===// @@ -581,22 +585,6 @@ const FieldDecl *FieldChainInfo::getEndO // "uninitialized field 'this->x'", but we can't refer to 'x' directly, // we need an explicit namespace resolution whether the uninit field was // 'D1::x' or 'D2::x'. -// -// TODO: If a field in the fieldchain is a captured lambda parameter, this -// function constructs an empty string for it: -// -// template <class Callable> struct A { -// Callable c; -// A(const Callable &c, int) : c(c) {} -// }; -// -// int b; // say that this isn't zero initialized -// auto alwaysTrue = [&b](int a) { return true; }; -// -// A call with these parameters: A<decltype(alwaysTrue)>::A(alwaysTrue, int()) -// will emit a note with the message "uninitialized field: 'this->c.'". If -// possible, the lambda parameter name should be retrieved or be replaced with a -// "<lambda parameter>" or something similar. void FieldChainInfo::print(llvm::raw_ostream &Out) const { if (Chain.isEmpty()) return; @@ -604,7 +592,7 @@ void FieldChainInfo::print(llvm::raw_ost const llvm::ImmutableListImpl<const FieldRegion *> *L = Chain.getInternalPointer(); printTail(Out, L->getTail()); - Out << L->getHead()->getDecl()->getNameAsString(); + Out << getVariableName(L->getHead()->getDecl()); } void FieldChainInfo::printTail( @@ -615,7 +603,7 @@ void FieldChainInfo::printTail( printTail(Out, L->getTail()); const FieldDecl *Field = L->getHead()->getDecl(); - Out << Field->getNameAsString(); + Out << getVariableName(Field); Out << (Field->getType()->isPointerType() ? "->" : "."); } @@ -676,6 +664,21 @@ static void printNoteMessage(llvm::raw_o Out << "'"; } +static StringRef getVariableName(const FieldDecl *Field) { + // If Field is a captured lambda variable, Field->getName() will return with + // an empty string. We can however acquire it's name from the lambda's + // captures. + const auto *CXXParent = dyn_cast<CXXRecordDecl>(Field->getParent()); + + if (CXXParent && CXXParent->isLambda()) { + assert(CXXParent->captures_begin()); + auto It = CXXParent->captures_begin() + Field->getFieldIndex(); + return It->getCapturedVar()->getName(); + } + + return Field->getName(); +} + void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) { auto Chk = Mgr.registerChecker<UninitializedObjectChecker>(); Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption( Modified: cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp?rev=336995&r1=336994&r2=336995&view=diff ============================================================================== --- cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp (original) +++ cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp Fri Jul 13 05:54:47 2018 @@ -737,6 +737,22 @@ void fMemsetTest2() { //===----------------------------------------------------------------------===// template <class Callable> +struct LambdaThisTest { + Callable functor; + + LambdaThisTest(const Callable &functor, int) : functor(functor) { + // All good! + } +}; + +struct HasCapturableThis { + void fLambdaThisTest() { + auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash + LambdaThisTest<decltype(isEven)>(isEven, int()); + } +}; + +template <class Callable> struct LambdaTest1 { Callable functor; @@ -760,7 +776,7 @@ struct LambdaTest2 { void fLambdaTest2() { int b; - auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}} + auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}} LambdaTest2<decltype(equals)>(equals, int()); } #else @@ -782,8 +798,8 @@ void fLambdaTest2() { namespace LT3Detail { struct RecordType { - int x; // expected-note{{uninitialized field 'this->functor..x'}} - int y; // expected-note{{uninitialized field 'this->functor..y'}} + int x; // expected-note{{uninitialized field 'this->functor.rec1.x'}} + int y; // expected-note{{uninitialized field 'this->functor.rec1.y'}} }; } // namespace LT3Detail @@ -826,6 +842,35 @@ void fLambdaTest3() { } #endif //PEDANTIC +template <class Callable> +struct MultipleLambdaCapturesTest1 { + Callable functor; + int dontGetFilteredByNonPedanticMode = 0; + + MultipleLambdaCapturesTest1(const Callable &functor, int) : functor(functor) {} // expected-warning{{2 uninitialized field}} +}; + +void fMultipleLambdaCapturesTest1() { + int b1, b2 = 3, b3; + auto equals = [&b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b1'}} + // expected-note@-1{{uninitialized field 'this->functor.b3'}} + MultipleLambdaCapturesTest1<decltype(equals)>(equals, int()); +} + +template <class Callable> +struct MultipleLambdaCapturesTest2 { + Callable functor; + int dontGetFilteredByNonPedanticMode = 0; + + MultipleLambdaCapturesTest2(const Callable &functor, int) : functor(functor) {} // expected-warning{{1 uninitialized field}} +}; + +void fMultipleLambdaCapturesTest2() { + int b1, b2 = 3, b3; + auto equals = [b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b3'}} + MultipleLambdaCapturesTest2<decltype(equals)>(equals, int()); +} + //===----------------------------------------------------------------------===// // System header tests. //===----------------------------------------------------------------------===// _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits