<div dir="ltr"><div class="gmail_quote">On Thu, Apr 2, 2015 at 12:56 AM David Bakin <<a href="mailto:davidbak@gmail.com">davidbak@gmail.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><p>Hi!</p><p>I started working with Clang a couple of weeks ago with an aim to developing a<br>small project that would be useful to me (perhaps to others as well) and to get<br>involved with the clang project and community.  After a couple of weeks of<br>experimentation I've reached the point where it would be helpful to ask for<br>advice.</p><div>(By way of background I have had commercial development experience with compiler<br>development, which is somewhat dated but still relevant, but I have no experience</div><div>with using or modifying either LLVM or Clang.)</div><p>I'd like to briefly describe two versions of my project and then ask for your<br>advice on the best way to proceed.</p><p>I want to "break encapsulation" on C++ classes to better enable unit testing of<br>legacy code (or just plain poorly written code) that can't be refactored, for<br>which developing better tests is a higher priority (given the constraints I'm<br>subject to) than changing the design.</p><p>I have two approaches in mind:</p><p>The first (which I've tested by hand) is to build a C++ source-to-source<br>processor that given a source file and some class names will parse the<br>translation unit and then emit two files: first, a C++ header that will contain<br>the named classes (but renamed) with all methods and fields in the same order as<br>the original but where all access is public (and it will also have the<br>appropriate #includes), and second, an assembly language file of thunks that<br>will implement the methods of the new proxy class by jumping to the methods of<br>the original class (and this file needs the mangled names of original and proxy<br>class methods).  So that to write a unit test you create this proxy header and<br>use it (by a cast) on your objects-under-test and by linking with the assembly<br>thunks you can transparently access all public/protected/private methods and<br>fields of your instance in hand.  (As I've said, this works when I've done it<br>by hand.)</p></div></blockquote><div><br></div><div>This sounds very close to #define private public before including the headers. Any reason this does not work for you? (for protected things, you can probably derive from the classes and provide accessors that way)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><p>The second approach is to use Clang/LLVM as a C++ compiler (not just the front<br>end of a tool) by inventing a new statement which is like a reverse friend<br>declaration, with its own special keyword.  Placed in a method it will name a<br>class or method that you want to "break encapsulation" of.  And it will act is<br>if the class or method named has a friend declaration pointing back to the<br>method with the break declaration statement.  With its own keyword that can<br>easily be grepped for you can make sure this statement is used only in unit<br>tests and not production code.  (In fact, it could be enabled as any other<br>language extension only if a compiler switch is present, and so you could easily<br>ensure that only unit test projects have that compiler switch.)</p><p>Here are my questions about these approaches:</p><p>1.  What packaged Clang functionality do I need?</p><p>    a. Can approach 1 be done with strictly libclang (using the AST and the lexer<br>       to guide modification of the source and to identify methods that need<br>       assembly thunks)?  Or do I need to step up to LibTooling + LibASTMatchers<br>       (or LibAST).  Or does it need a plugin?  What is your recommendation?</p></div></blockquote><div><br></div><div>I'd probably go with libtooling. You usually want to use libclang, if you need a tool that you want to ship to customers, so that you need a stable interface for them to work against. Libtooling gives you more power at the cost of integrating with upstream clang changes (the core interfaces don't change that wildly though, usually mostly when we allow clang to use more parts of a new C++ standard). Plugins are more for when you want to do some extra checking as part of every build.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><p>    b. Can approach 2 be done with LibTooling + LibASTMatchers + minimal changes<br>       to clang so it accepts the new grammar with new AST nodes to match.  My<br>       idea there is, having parsed and traversed my new "break encapsulation"<br>       declarations, to go right to the definitions of the targeted class and<br>       modify the AST in-place to have an actual friend declaration pointing<br>       back, and then to finish the compilation of the modified AST.</p></div></blockquote><div><br></div><div>I think both approaches are overengineering the problem.</div><div>Often there are much simpler approaches; I recommend Feather's "Working Effectively with Legacy Code", which has many great ideas on how to minimally change legacy systems to get access points for unit tests.</div><div><a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052</a><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><p>2.  How much of this work can be done on the Windows platform with Clang?  And<br>    can it be done with Visual Studio or do I need to use an alternate native<br>    compiler for Windows?</p><p>    I've become aware of restrictions of developing on the Windows platform.<br>    Leave aside restrictions on what you can do with Clang/LLVM as a compiler<br>    on Windows (e.g., at this time no exceptions or anything else that requires<br>    compiler-rt) which would only affect my second approach.  Even so I've found<br>    things that make Windows/Visual Studio less than a perfect development<br>    environment for Clang.</p><p>    For example, I can't confirm my compiled Clang/LLVM is correct (using the VS<br>    12 Win64) platform because even though it compiles without error and the<br>    unit tests all pass I can't successfully run the "command line tests"<br>    (<a href="http://clang.llvm.org/hacking.html#testingCommands" target="_blank">http://clang.llvm.org/hacking.html#testingCommands</a>) as I reported here<br>    earlier (<a href="http://lists.cs.uiuc.edu/pipermail/cfe-dev/2015-March/042170.html" target="_blank">http://lists.cs.uiuc.edu/pipermail/cfe-dev/2015-March/042170.html</a>) - I<br>    got some help from the community there but the thread petered out and I've<br>    been unable to continue with them.  (Just for reference I've attached to<br>    this email my last log of running the tests, with 122 unexpected failures<br>    which are all some kind of lock error I don't understand.)</p><p>    Anyway, if I continue with the Windows platform can I be successful (or<br>    should I switch to Linux)?</p><p>This email has been quite long, and I apologize, but I'd really appreciate your<br>help.  I'd like to start my Clang/LLVM development with some chance of success<br>without getting greatly frustrated by not knowing some basic things that everyone<br>who is working in the code "just knows" from experience.  So thanks in advance!<br>And I hope to contribute back to the Clang/LLVM community in the future ...</p><p>-- David Bakin<br></p></div>
______________________________<u></u>_________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@cs.uiuc.edu" target="_blank">cfe-dev@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/cfe-dev</a><br>
</blockquote></div></div>