steveire marked an inline comment as done.
steveire added inline comments.

================
Comment at: include/clang/AST/TextNodeDumper.h:28
                                            const comments::FullComment *> {
+  TextTreeStructure &TreeStructure;
   raw_ostream &OS;
----------------
steveire wrote:
> aaron.ballman wrote:
> > steveire wrote:
> > > aaron.ballman wrote:
> > > > This makes me a bit wary because you create a node dumper in the same 
> > > > situations you make a tree structure object, but now there's a strict 
> > > > ordering between the two object creations. If you're doing this 
> > > > construction local to a function, you wind up with a dangling reference 
> > > > unless you're careful (which is unfortunate, but not the end of the 
> > > > world). If you're doing this construction as part of a constructor's 
> > > > initializer list, you now have to properly order the member 
> > > > declarations within the class and that is also unfortunate. Given that 
> > > > those are the two common scenarios for how I envision constructing an 
> > > > ast dump of some kind, I worry about the fragility. e.g.,
> > > > ```
> > > > unique_ptr<ASTConsumer> createASTDumper(...) {
> > > >   TextTreeStructure TreeStructure;
> > > >   TextNodeDumper NodeDumper(TreeStructure); // Oops, dangling reference
> > > >   return make_unique<MySuperAwesomeASTDumper>(TreeStructure, 
> > > > NodeDumper, ...);
> > > > }
> > > > 
> > > > // vs
> > > > 
> > > > struct MySuperAwesomeASTDumper : ... {
> > > >   MySuperAwesomeASTDumper() : TreeStructure(...), 
> > > > NodeDumper(TreeStructure, ...) {}
> > > > private:
> > > >   TextTreeStructure TreeStructure; // This order is now SUPER important
> > > >   TextNodeDumper NodeDumper;
> > > > };
> > > > ```
> > > > There's a part of me that wonders if a better approach is to have this 
> > > > object passed to the `dumpFoo()` calls as a reference parameter. This 
> > > > way, the caller is still responsible for creating an object, but the 
> > > > creation order between the tree and the node dumper isn't as fragile.
> > > In your first snippet there is a dangling reference because the author of 
> > > `MySuperAwesomeASTDumper` decided to make the members references. If the 
> > > members are references, code like your first snippet will cause dangling 
> > > references and nothing can prevent that. Adding `TreeStructure&` to Visit 
> > > methods as you suggested does not prevent it.
> > > 
> > > The only solution is make the `MySuperAwesomeASTDumper` not use member 
> > > references (ie your second snippet). The order is then in fact not 
> > > problematic because "taking a reference to an uninitialized object is 
> > > legal".
> > >  The order is then in fact not problematic because "taking a reference to 
> > > an uninitialized object is legal".
> > 
> > This presumes that the constructors aren't using those references to the 
> > uninitialized object, which would be illegal. That's what I mean about this 
> > being very fragile -- if the stars line up correctly, everything works 
> > fine, but if the stars aren't aligned just right, you get really hard 
> > problems to track down.
> Actually 'the stars would have to line up in a particular way' in order to 
> reach the scenario you are concerned about. What would have to happen is:
> 
> * This patch gets in as-is
> * Someone in the future reorders the members 
> * But they don't reorder the init-list
> * They build on a platform without -Wreorder (only MSVC?) enabled in the 
> build.
> * That passes review
> * Other users update their checkout and everyone else also ignores the 
> -Wreorder warning.
> 
> That is a vanishingly likely scenario. It's just unreasonable to consider 
> that as a reason to create a broken interface.
> 
> And it would be a broken interface.
> 
> After the refactoring is complete, we have something like 
> 
> ```
> class ASTDumper
>     : public ASTDumpTraverser<ASTDumper, TextTreeStructure, TextNodeDumper> {
>   TextTreeStructure TreeStructure;
>   TextNodeDumper NodeDumper;
> public:
>   TextTreeStructure &getTreeStructure() { return TreeStructure; }
>   TextNodeDumper &getNodeDumper() { return NodeDumper; }
> 
>   ASTDumper(raw_ostream &OS, const SourceManager *SM)
>       : TreeStructure(OS),
>         NodeDumper(TreeStructure, OS, SM) {}
> };
> 
> ```
> 
> In the case, of the `ASTDumper`, the `TextNodeDumper` uses the 
> `TextTreeStructure`.
> 
> However, in the case of any other subclass of `ASTDumpTraverser`, the 
> `NodeDumper` type does not depend on the `TreeStructure` type. The 
> `ASTDumpTraverser` should not pass the `TreeStructure` to the 
> `NodeDumper`because the `ASTDumpTraverser` should not assume the `NodeDumper` 
> needs the `ASTDumpTraverser`. 
> 
> That is true in one concrete case (the `TextNodeDumper`), but not in general. 
> You would be encoding an assumption about a concrete `NodeDumper` 
> implementation in the generic `ASTDumpTraverser`.
> 
> That is an interface violation which is definitely not justified by your 
> far-fetched scenario of someone re-ordering the members in the future and 
> ignoring `-Wreorder`.
Should be "should not assume the `NodeDumper` needs the `TreeStructure`", sorry.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55337/new/

https://reviews.llvm.org/D55337



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

Reply via email to