[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-07-13 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rC336995: [analyzer][UninitializedObjectChecker] Fixed 
captured lambda variable name (authored by Szelethus, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D48291

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -232,6 +232,10 @@
 static void printNoteMessage(llvm::raw_ostream ,
  const FieldChainInfo );
 
+/// 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,30 +585,14 @@
 // "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  struct A {
-// Callable c;
-// A(const Callable , int) : c(c) {}
-//   };
-//
-//   int b; // say that this isn't zero initialized
-//   auto alwaysTrue = [](int a) { return true; };
-//
-// A call with these parameters: A::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
-// "" or something similar.
 void FieldChainInfo::print(llvm::raw_ostream ) const {
   if (Chain.isEmpty())
 return;
 
   const llvm::ImmutableListImpl *L =
   Chain.getInternalPointer();
   printTail(Out, L->getTail());
-  Out << L->getHead()->getDecl()->getNameAsString();
+  Out << getVariableName(L->getHead()->getDecl());
 }
 
 void FieldChainInfo::printTail(
@@ -615,7 +603,7 @@
 
   printTail(Out, L->getTail());
   const FieldDecl *Field = L->getHead()->getDecl();
-  Out << Field->getNameAsString();
+  Out << getVariableName(Field);
   Out << (Field->getType()->isPointerType() ? "->" : ".");
 }
 
@@ -676,6 +664,21 @@
   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(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 ) {
   auto Chk = Mgr.registerChecker();
   Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption(
Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -737,6 +737,22 @@
 //===--===//
 
 template 
+struct LambdaThisTest {
+  Callable functor;
+
+  LambdaThisTest(const Callable , int) : functor(functor) {
+// All good!
+  }
+};
+
+struct HasCapturableThis {
+  void fLambdaThisTest() {
+auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash
+LambdaThisTest(isEven, int());
+  }
+};
+
+template 
 struct LambdaTest1 {
   Callable functor;
 
@@ -760,7 +776,7 @@
 
 void fLambdaTest2() {
   int b;
-  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
+  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}}
   LambdaTest2(equals, int());
 }
 #else
@@ -782,8 +798,8 @@
 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 @@
 }
 #endif //PEDANTIC
 
+template 
+struct MultipleLambdaCapturesTest1 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest1(const Callable , int) : functor(functor) 

[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-07-13 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 155361.
Szelethus marked an inline comment as done.
Szelethus added a comment.

Thanks! :)

Rebased to https://reviews.llvm.org/rC336994.


https://reviews.llvm.org/D48291

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -737,6 +737,22 @@
 //===--===//
 
 template 
+struct LambdaThisTest {
+  Callable functor;
+
+  LambdaThisTest(const Callable , int) : functor(functor) {
+// All good!
+  }
+};
+
+struct HasCapturableThis {
+  void fLambdaThisTest() {
+auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash
+LambdaThisTest(isEven, int());
+  }
+};
+
+template 
 struct LambdaTest1 {
   Callable functor;
 
@@ -760,7 +776,7 @@
 
 void fLambdaTest2() {
   int b;
-  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
+  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}}
   LambdaTest2(equals, int());
 }
 #else
@@ -782,8 +798,8 @@
 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 @@
 }
 #endif //PEDANTIC
 
+template 
+struct MultipleLambdaCapturesTest1 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest1(const Callable , int) : functor(functor) {} // expected-warning{{2 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest1() {
+  int b1, b2 = 3, b3;
+  auto equals = [, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b1'}}
+  // expected-note@-1{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest1(equals, int());
+}
+
+template 
+struct MultipleLambdaCapturesTest2 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest2(const Callable , int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest2() {
+  int b1, b2 = 3, b3;
+  auto equals = [b1, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest2(equals, int());
+}
+
 //===--===//
 // System header tests.
 //===--===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -232,6 +232,10 @@
 static void printNoteMessage(llvm::raw_ostream ,
  const FieldChainInfo );
 
+/// 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,30 +585,14 @@
 // "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  struct A {
-// Callable c;
-// A(const Callable , int) : c(c) {}
-//   };
-//
-//   int b; // say that this isn't zero initialized
-//   auto alwaysTrue = [](int a) { return true; };
-//
-// A call with these parameters: A::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
-// "" or something similar.
 void FieldChainInfo::print(llvm::raw_ostream ) const {
   if (Chain.isEmpty())
 return;
 
   const llvm::ImmutableListImpl *L =
   Chain.getInternalPointer();
   printTail(Out, L->getTail());
-  Out << L->getHead()->getDecl()->getNameAsString();
+  Out << getVariableName(L->getHead()->getDecl());
 }
 
 void FieldChainInfo::printTail(
@@ -615,7 +603,7 @@
 
   printTail(Out, L->getTail());
   const FieldDecl *Field = 

[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-07-12 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ accepted this revision.
NoQ added a comment.

Looks good!




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:691
 
+StringRef getVariableName(const FieldDecl *Field) {
+  // If \p Field is a captured lambda variable, Field->getName() will return

Szelethus wrote:
> george.karpenkov wrote:
> > Is this a member method? Then it should be prefixed with a class name.
> > Currently it looks like you have a member method without an implementation 
> > and a separate C-style function?
> It is a statically defined method, and you can see its forward declaration in 
> the same diff.
> 
> Back when I started writing this checker, the amount of function laying in 
> the anonymous namespace was very few, but this has changed. I'll fix it 
> sometime because it's getting somewhat annoying (and is against the [[ 
> https://llvm.org/docs/CodingStandards.html | coding standards ]]).
Yeah, just make them `static`, it's easier to read 
(https://llvm.org/docs/CodingStandards.html#anonymous-namespaces).


https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-07-06 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus marked 3 inline comments as done.
Szelethus added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:691
 
+StringRef getVariableName(const FieldDecl *Field) {
+  // If \p Field is a captured lambda variable, Field->getName() will return

george.karpenkov wrote:
> Is this a member method? Then it should be prefixed with a class name.
> Currently it looks like you have a member method without an implementation 
> and a separate C-style function?
It is a statically defined method, and you can see its forward declaration in 
the same diff.

Back when I started writing this checker, the amount of function laying in the 
anonymous namespace was very few, but this has changed. I'll fix it sometime 
because it's getting somewhat annoying (and is against the [[ 
https://llvm.org/docs/CodingStandards.html | coding standards ]]).


https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-07-06 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 154420.
Szelethus added a comment.

Finding the correct captured variable now works with 
`FieldDecl::getFieldIndex()`.


https://reviews.llvm.org/D48291

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -737,6 +737,22 @@
 //===--===//
 
 template 
+struct LambdaThisTest {
+  Callable functor;
+
+  LambdaThisTest(const Callable , int) : functor(functor) {
+// All good!
+  }
+};
+
+struct HasCapturableThis {
+  void fLambdaThisTest() {
+auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash
+LambdaThisTest(isEven, int());
+  }
+};
+
+template 
 struct LambdaTest1 {
   Callable functor;
 
@@ -760,7 +776,7 @@
 
 void fLambdaTest2() {
   int b;
-  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
+  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}}
   LambdaTest2(equals, int());
 }
 #else
@@ -782,8 +798,8 @@
 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 @@
 }
 #endif //PEDANTIC
 
+template 
+struct MultipleLambdaCapturesTest1 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest1(const Callable , int) : functor(functor) {} // expected-warning{{2 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest1() {
+  int b1, b2 = 3, b3;
+  auto equals = [, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b1'}}
+  // expected-note@-1{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest1(equals, int());
+}
+
+template 
+struct MultipleLambdaCapturesTest2 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest2(const Callable , int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest2() {
+  int b1, b2 = 3, b3;
+  auto equals = [b1, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest2(equals, int());
+}
+
 //===--===//
 // System header tests.
 //===--===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -230,6 +230,10 @@
 /// Constructs a note message for a given FieldChainInfo object.
 void printNoteMessage(llvm::raw_ostream , const FieldChainInfo );
 
+/// Returns with Field's name. This is a helper function to get the correct name
+/// even if Field is a captured lambda variable.
+StringRef getVariableName(const FieldDecl *Field);
+
 } // end of anonymous namespace
 
 //===--===//
@@ -596,30 +600,14 @@
 // "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  struct A {
-// Callable c;
-// A(const Callable , int) : c(c) {}
-//   };
-//
-//   int b; // say that this isn't zero initialized
-//   auto alwaysTrue = [](int a) { return true; };
-//
-// A call with these parameters: A::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
-// "" or something similar.
 void FieldChainInfo::print(llvm::raw_ostream ) const {
   if (Chain.isEmpty())
 return;
 
   const llvm::ImmutableListImpl *L =
   Chain.getInternalPointer();
   printTail(Out, L->getTail());
-  Out << L->getHead()->getDecl()->getNameAsString();
+  Out << getVariableName(L->getHead()->getDecl());
 }
 
 void FieldChainInfo::printTail(
@@ -630,7 +618,7 @@
 
   printTail(Out, L->getTail());
   const FieldDecl *Field = L->getHead()->getDecl();
-  Out << Field->getNameAsString();
+  Out << getVariableName(Field);
   Out << 

[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-26 Thread George Karpenkov via Phabricator via cfe-commits
george.karpenkov requested changes to this revision.
george.karpenkov added a comment.
This revision now requires changes to proceed.

Looks like @NoQ had some valid comments as well.


https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-26 Thread George Karpenkov via Phabricator via cfe-commits
george.karpenkov added a comment.

Few more nits.




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:691
 
+StringRef getVariableName(const FieldDecl *Field) {
+  // If \p Field is a captured lambda variable, Field->getName() will return

Is this a member method? Then it should be prefixed with a class name.
Currently it looks like you have a member method without an implementation and 
a separate C-style function?



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:692
+StringRef getVariableName(const FieldDecl *Field) {
+  // If \p Field is a captured lambda variable, Field->getName() will return
+  // with an empty string. We can however acquire it's name by iterating over

Doxygen-style comments in LLVM start with a triple slash, and are located above 
the function. Then the tools for autocompletion (e.g. clangd) can pick them up.


https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-26 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:699
+for (const LambdaCapture  : CXXParent->captures()) {
+  if (L.getLocation() == Field->getLocation())
+return L.getCapturedVar()->getName();

Uhm, this source location comparison looks really flaky. Ideally we would have 
looked up by field and get the captured variable directly, but it seems that we 
don't have a ready-made method for this.

The second ideal thing would probably be a reverse variant of 
`CXXRecordDecl::getCaptureFields()`. Looking at how it's implemented, it seems 
that capture indix is in sync with field index. Because we have 
`FieldDecl::getFieldIndex()`, probably we could just lookup the captures array 
by that index?


https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-20 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 152105.
Szelethus added a comment.

Fixes according to inline comments.


https://reviews.llvm.org/D48291

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -737,6 +737,22 @@
 //===--===//
 
 template 
+struct LambdaThisTest {
+  Callable functor;
+
+  LambdaThisTest(const Callable , int) : functor(functor) {
+// All good!
+  }
+};
+
+struct HasCapturableThis {
+  void fLambdaThisTest() {
+auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash
+LambdaThisTest(isEven, int());
+  }
+};
+
+template 
 struct LambdaTest1 {
   Callable functor;
 
@@ -760,7 +776,7 @@
 
 void fLambdaTest2() {
   int b;
-  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
+  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}}
   LambdaTest2(equals, int());
 }
 #else
@@ -782,8 +798,8 @@
 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 @@
 }
 #endif //PEDANTIC
 
+template 
+struct MultipleLambdaCapturesTest1 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest1(const Callable , int) : functor(functor) {} // expected-warning{{2 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest1() {
+  int b1, b2 = 3, b3;
+  auto equals = [, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b1'}}
+  // expected-note@-1{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest1(equals, int());
+}
+
+template 
+struct MultipleLambdaCapturesTest2 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest2(const Callable , int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest2() {
+  int b1, b2 = 3, b3;
+  auto equals = [b1, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest2(equals, int());
+}
+
 //===--===//
 // System header tests.
 //===--===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -230,6 +230,10 @@
 /// Constructs a note message for a given FieldChainInfo object.
 void printNoteMessage(llvm::raw_ostream , const FieldChainInfo );
 
+/// Returns with Field's name. This is a helper function to get the correct name
+/// even if Field is a captured lambda variable.
+StringRef getVariableName(const FieldDecl *Field);
+
 } // end of anonymous namespace
 
 //===--===//
@@ -604,30 +608,14 @@
 // "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  struct A {
-// Callable c;
-// A(const Callable , int) : c(c) {}
-//   };
-//
-//   int b; // say that this isn't zero initialized
-//   auto alwaysTrue = [](int a) { return true; };
-//
-// A call with these parameters: A::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
-// "" or something similar.
 void FieldChainInfo::print(llvm::raw_ostream ) const {
   if (Chain.isEmpty())
 return;
 
   const llvm::ImmutableListImpl *L =
   Chain.getInternalPointer();
   printTail(Out, L->getTail());
-  Out << L->getHead()->getDecl()->getNameAsString();
+  Out << getVariableName(L->getHead()->getDecl());
 }
 
 void FieldChainInfo::printTail(
@@ -638,7 +626,7 @@
 
   printTail(Out, L->getTail());
   const FieldDecl *Field = L->getHead()->getDecl();
-  Out << Field->getNameAsString();
+  Out << getVariableName(Field);
   Out << (Field->getType()->isPointerType() ? "->" : ".");
 }
 
@@ 

[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-19 Thread George Karpenkov via Phabricator via cfe-commits
george.karpenkov added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:685
+
+  if (CXXParent && CXXParent->isLambda()) {
+CXXRecordDecl::capture_const_iterator CapturedVar =

Szelethus wrote:
> george.karpenkov wrote:
> > CXXParent is guaranteed to be non-null at this stage, otherwise dyn_cast 
> > fails
> I found this on 
> http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates:
> 
> >dyn_cast<>:
> >
> >The dyn_cast<> operator is a “checking cast” operation. It checks to see 
> > if the operand is of the specified type, and if so, returns a pointer to it 
> > (this operator does not work with references). If the operand is not of the 
> > correct type, a null pointer is returned.
> 
> So I guess this should be alright.
Oops sorry my bad.


Repository:
  rC Clang

https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-19 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:685
+
+  if (CXXParent && CXXParent->isLambda()) {
+CXXRecordDecl::capture_const_iterator CapturedVar =

george.karpenkov wrote:
> CXXParent is guaranteed to be non-null at this stage, otherwise dyn_cast fails
I found this on 
http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates:

>dyn_cast<>:
>
>The dyn_cast<> operator is a “checking cast” operation. It checks to see 
> if the operand is of the specified type, and if so, returns a pointer to it 
> (this operator does not work with references). If the operand is not of the 
> correct type, a null pointer is returned.

So I guess this should be alright.


Repository:
  rC Clang

https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-19 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Thanks for the review!

I spend some time thinking about the support for lambda functions, and I start 
to think that checking for lambda misuse shouldn't be the responsibility of 
this checker. I created a new revision for that discussion, I wouldn't like to 
abandon this one until I heard what you think of this! :)
https://reviews.llvm.org/D48318




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:687
+CXXRecordDecl::capture_const_iterator CapturedVar =
+std::find_if(CXXParent->captures_begin(), CXXParent->captures_end(),
+ [](const LambdaCapture ) {

george.karpenkov wrote:
> Could we just use a for-each here? Sorry for being opinionated, I'm pretty 
> sure it would be both shorter and more readable.
Great idea! :) I completely agree, to be honest I scratched my head too while I 
wrote it down.


Repository:
  rC Clang

https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-18 Thread George Karpenkov via Phabricator via cfe-commits
george.karpenkov requested changes to this revision.
george.karpenkov added a comment.
This revision now requires changes to proceed.

Looks good overall, but some nits inline.




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:682
 
+StringRef getVariableName(const FieldDecl *Field) {
+  const auto *CXXParent = dyn_cast(Field->getParent());

Can we have a comment explaining the semantics? From my understanding, you find 
a corresponding capture using a source location, and get a name from there.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:685
+
+  if (CXXParent && CXXParent->isLambda()) {
+CXXRecordDecl::capture_const_iterator CapturedVar =

CXXParent is guaranteed to be non-null at this stage, otherwise dyn_cast fails



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:687
+CXXRecordDecl::capture_const_iterator CapturedVar =
+std::find_if(CXXParent->captures_begin(), CXXParent->captures_end(),
+ [](const LambdaCapture ) {

Could we just use a for-each here? Sorry for being opinionated, I'm pretty sure 
it would be both shorter and more readable.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:689
+ [](const LambdaCapture ) {
+   return Field->getLocation().getRawEncoding() ==
+  L.getLocation().getRawEncoding();

That's exactly the semantics of the equality operator on source locations, so 
why not `Field->getLocation() == L.getLocation()` ?


Repository:
  rC Clang

https://reviews.llvm.org/D48291



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48291: [analyzer][UninitializedObjectChecker] Fixed captured lambda variable name

2018-06-18 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: xazax.hun, george.karpenkov, NoQ, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

Repository:
  rC Clang

https://reviews.llvm.org/D48291

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -737,6 +737,22 @@
 //===--===//
 
 template 
+struct LambdaThisTest {
+  Callable functor;
+
+  LambdaThisTest(const Callable , int) : functor(functor) {
+// All good!
+  }
+};
+
+struct HasCapturableThis {
+  void fLambdaThisTest() {
+auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash
+LambdaThisTest(isEven, int());
+  }
+};
+
+template 
 struct LambdaTest1 {
   Callable functor;
 
@@ -760,7 +776,7 @@
 
 void fLambdaTest2() {
   int b;
-  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
+  auto equals = [](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}}
   LambdaTest2(equals, int());
 }
 #else
@@ -782,8 +798,8 @@
 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 @@
 }
 #endif //PEDANTIC
 
+template 
+struct MultipleLambdaCapturesTest1 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest1(const Callable , int) : functor(functor) {} // expected-warning{{2 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest1() {
+  int b1, b2 = 3, b3;
+  auto equals = [, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b1'}}
+  // expected-note@-1{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest1(equals, int());
+}
+
+template 
+struct MultipleLambdaCapturesTest2 {
+  Callable functor;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  MultipleLambdaCapturesTest2(const Callable , int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest2() {
+  int b1, b2 = 3, b3;
+  auto equals = [b1, , ](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b3'}}
+  MultipleLambdaCapturesTest2(equals, int());
+}
+
 //===--===//
 // System header tests.
 //===--===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -230,6 +230,10 @@
 /// Constructs a note message for a given FieldChainInfo object.
 void printNoteMessage(llvm::raw_ostream , const FieldChainInfo );
 
+/// Returns with Field's name. This is a helper function to get the correct name
+/// even if Field is a captured lambda variable.
+StringRef getVariableName(const FieldDecl *Field);
+
 } // end of anonymous namespace
 
 //===--===//
@@ -594,30 +598,15 @@
 // "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  struct A {
-// Callable c;
-// A(const Callable , int) : c(c) {}
-//   };
-//
-//   int b; // say that this isn't zero initialized
-//   auto alwaysTrue = [](int a) { return true; };
-//
-// A call with these parameters: A::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
-// "" or something similar.
 void FieldChainInfo::print(llvm::raw_ostream ) const {
   if (Chain.isEmpty())
 return;
 
   const llvm::ImmutableListImpl *L =
   Chain.getInternalPointer();
   printTail(Out, L->getTail());
-  Out << L->getHead()->getDecl()->getNameAsString();
+
+  Out << getVariableName(L->getHead()->getDecl());
 }
 
 void FieldChainInfo::printTail(
@@ -628,7 +617,7 @@
 
   printTail(Out, L->getTail());
   const FieldDecl *Field = L->getHead()->getDecl();
-  Out << Field->getNameAsString();
+