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