Skip to content

Commit

Permalink
[analyzer][UninitializedObjectChecker] Fixed captured lambda variable…
Browse files Browse the repository at this point in the history
… name

Differential Revision: https://reviews.llvm.org/D48291

llvm-svn: 336995
  • Loading branch information
Szelethus committed Jul 13, 2018
1 parent 7212cc0 commit 8c11909
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 21 deletions.
39 changes: 21 additions & 18 deletions clang/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
Expand Up @@ -232,6 +232,10 @@ static bool isPrimitiveType(const QualType &T) {
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.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -581,30 +585,14 @@ const FieldDecl *FieldChainInfo::getEndOfChain() const {
// "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;

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(
Expand All @@ -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() ? "->" : ".");
}

Expand Down Expand Up @@ -676,6 +664,21 @@ static void printNoteMessage(llvm::raw_ostream &Out,
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(
Expand Down
51 changes: 48 additions & 3 deletions clang/test/Analysis/cxx-uninitialized-object.cpp
Expand Up @@ -736,6 +736,22 @@ void fMemsetTest2() {
// Lambda tests.
//===----------------------------------------------------------------------===//

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;
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
//===----------------------------------------------------------------------===//
Expand Down

0 comments on commit 8c11909

Please sign in to comment.