NoQ accepted this revision.
NoQ added a comment.

Ok, let's land this one and see how it goes! I'm looking forward to seeing the 
follow-up patches.



================
Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:359-372
+  // Checking bases.
+  const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+  if (!CXXRD)
+    return ContainsUninitField;
+
+  for (const CXXBaseSpecifier BaseSpec : CXXRD->bases()) {
+    const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
----------------
Szelethus wrote:
> Szelethus wrote:
> > NoQ wrote:
> > > Szelethus wrote:
> > > > NoQ wrote:
> > > > > Are there many warnings that will be caused by this but won't be 
> > > > > caused by conducting the check for the constructor-within-constructor 
> > > > > that's currently disabled? Not sure - is it even syntactically 
> > > > > possible to not initialize the base class?
> > > > I'm not a 100% sure what you mean. Can you clarify?
> > > > >Not sure - is it even syntactically possible to not initialize the 
> > > > >base class?
> > > > If I understand the question correctly, no, as far as I know.
> > > You have a check for `isCalledByConstructor()` in order to skip base 
> > > class constructors but then you check them manually. That's a lot of 
> > > code, but it seems that the same result could have been achieved by 
> > > simply skipping the descent into the base class.
> > > 
> > > Same question for class-type fields, actually.
> > >Same question for class-type fields, actually.
> > 
> > My problem with that approach is that the same uninitialized field could've 
> > been emitted multiple times in different warnings. From an earlier 
> > conversation (assume that its run in pedantic mode):
> > 
> > >For this code snippet:
> > >
> > > ```
> > >struct A {
> > >   struct B {
> > >      int x, y;
> > >      
> > >      B() {}
> > >   } b;
> > >   int w;
> > >
> > >   A() {
> > >      b = B();
> > >   }
> > >};
> > >```
> > >the warning message after a call to `A::A()` would be "3 uninitialized 
> > >fields[...]", and for `B::B()` inside `A`s constructor would be "2 
> > >uninitialized fields[...]", so it wouldn't be filtered out.
> > 
> > In my opinion, if `A` contains a field of type `B`, it should be the 
> > responsibility of `A`'s constructors to initialize those fields properly.
> > >You have a check for isCalledByConstructor() in order to skip base class 
> > >constructors but then you check them manually. That's a lot of code, but 
> > >it seems that the same result could have been achieved by simply skipping 
> > >the descent into the base class.
> > I also believe that a constructor "should be held responsible" for the 
> > initialization of the inherited data members. However, in the case of base 
> > classes, uniqueing isn't an issue, as in this case:
> > ```
> > struct B {
> >   int a;
> >   B() {}
> > };
> > 
> > struct D : public B {
> >   int b;
> >   D() {}
> > };
> > ```
> > a call to `D::D()` would not check the inherited member (`a`), if I didn't 
> > implement it explicitly. That also means that if `isCalledByConstructor` 
> > was refactored to not filter out base classes, we would get two warning 
> > each with a single note, reporting `b` and `a` respectively. (I haven't 
> > actually checked it, but its a reasonable assumption)
> > 
> > Actually, I'm not 100% sure which approach is better: a warning for each 
> > base, or one warning for the object, bases included. I personally think one 
> > warning per object results in the best user experience.
> > 
> > I like both ideas, but I think if we'd come to the conclusion that a 
> > warning per base should be the way to go, it should definitely be 
> > implemented in a followup patch, as `isCalledByConstructor` is already in 
> > line for some major refactoring.
> > 
> > What do you think? :)
> >[...]but it seems that the same result could have been achieved by simply 
> >skipping the descent into the base class.
> I can't edit inline comments sadly, but I'd just like to point out that it 
> wouldn't achieve the same thing, as highlighted above. But, both solution 
> would be okay.
I still don't fully understand the reasoning behind who's responsible for 
initializing the field, i.e., the exact rule that you're enforcing seems to 
cause warnings to depend heavily on meta-information such as where does the 
analysis start, which is confusing. Because we're trying to enforce a coding 
guideline here, i believe that the guideline itself should be transparent and 
easy to explain. In particular, it should be obvious to the user which 
constructor is responsible for initializing a field, and by obvious i mean it 
should be obvious both from the guideline itself and from the analyzer's 
warning, and both of them should be the same "obvious".


https://reviews.llvm.org/D45532



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

Reply via email to