From ade47d3d67635baf9580da797370fd0e3d395b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Wed, 19 Jun 2013 23:55:47 +0200 Subject: [PATCH] make it easy to get a parent of an AST node Clang API doesn't provide this, but it's occasionally needed, and so far the way has been inspecting the highest possible node in AST and walking down and remembering, which is complicated, error-prone and annoying. Change-Id: Id5b72cb5ebfc069e90efe6d673c0ef18ebcdab61 --- compilerplugins/clang/plugin.cxx | 65 ++++++++++++++++++++++++++++++++ compilerplugins/clang/plugin.hxx | 9 +++++ 2 files changed, 74 insertions(+) diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx index 330090811423..6611606d793f 100644 --- a/compilerplugins/clang/plugin.cxx +++ b/compilerplugins/clang/plugin.cxx @@ -67,6 +67,71 @@ void Plugin::registerPlugin( Plugin* (*create)( CompilerInstance&, Rewriter& ), PluginHandler::registerPlugin( create, optionName, isRewriter ); } +unordered_map< const Stmt*, const Stmt* > Plugin::parents; + +const Stmt* Plugin::parentStmt( const Stmt* stmt ) + { + if( parents.empty()) + buildParents( compiler ); + assert( parents.count( stmt ) == 1 ); + return parents[ stmt ]; + } + +Stmt* Plugin::parentStmt( Stmt* stmt ) + { + if( parents.empty()) + buildParents( compiler ); + assert( parents.count( stmt ) == 1 ); + return const_cast< Stmt* >( parents[ stmt ] ); + } + +namespace +{ +class ParentBuilder + : public RecursiveASTVisitor< ParentBuilder > + { + public: + bool VisitFunctionDecl( const FunctionDecl* function ); + void walk( const Stmt* stmt ); + unordered_map< const Stmt*, const Stmt* >* parents; + }; + +bool ParentBuilder::VisitFunctionDecl( const FunctionDecl* function ) + { +// if( ignoreLocation( declaration )) +// return true; ??? + if( !function->doesThisDeclarationHaveABody()) + return true; + const Stmt* body = function->getBody(); + (*parents)[ body ] = NULL; // no parent + walk( body ); + return true; + } + +void ParentBuilder::walk( const Stmt* stmt ) + { + for( ConstStmtIterator it = stmt->child_begin(); + it != stmt->child_end(); + ++it ) + { + if( *it != NULL ) + { + (*parents)[ *it ] = stmt; + walk( *it ); + } + } + } + +} // namespace + +void Plugin::buildParents( CompilerInstance& compiler ) + { + assert( parents.empty()); + ParentBuilder builder; + builder.parents = &parents; + builder.TraverseDecl( compiler.getASTContext().getTranslationUnitDecl()); + } + ///// RewritePlugin::RewritePlugin( CompilerInstance& compiler, Rewriter& rewriter ) diff --git a/compilerplugins/clang/plugin.hxx b/compilerplugins/clang/plugin.hxx index 9c9ce7b72f55..56dee27ef913 100644 --- a/compilerplugins/clang/plugin.hxx +++ b/compilerplugins/clang/plugin.hxx @@ -19,6 +19,7 @@ #include #include #include +#include #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 2 #include @@ -54,10 +55,18 @@ class Plugin bool ignoreLocation( const Decl* decl ); bool ignoreLocation( const Stmt* stmt ); CompilerInstance& compiler; + /** + Returns the parent of the given AST node. Clang's internal AST representation doesn't provide this information, + it can only provide children, but getting the parent is often useful for inspecting a part of the AST. + */ + const Stmt* parentStmt( const Stmt* stmt ); + Stmt* parentStmt( Stmt* stmt ); private: static void registerPlugin( Plugin* (*create)( CompilerInstance&, Rewriter& ), const char* optionName, bool isRewriter ); template< typename T > static Plugin* createHelper( CompilerInstance& compiler, Rewriter& rewriter ); enum { isRewriter = false }; + static unordered_map< const Stmt*, const Stmt* > parents; + static void buildParents( CompilerInstance& compiler ); }; /**