summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@suse.cz>2013-06-19 23:55:47 +0200
committerLuboš Luňák <l.lunak@suse.cz>2013-06-20 07:21:31 +0200
commitade47d3d67635baf9580da797370fd0e3d395b5a (patch)
treea7d8df61cf757c5db771167151800a3d399a2979 /compilerplugins
parentd0db3134653cfc0e3c59e25203728a02865ceead (diff)
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
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/plugin.cxx65
-rw-r--r--compilerplugins/clang/plugin.hxx9
2 files changed, 74 insertions, 0 deletions
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 <clang/Basic/SourceManager.h>
#include <clang/Frontend/CompilerInstance.h>
#include <set>
+#include <unordered_map>
#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 2
#include <clang/Rewrite/Rewriter.h>
@@ -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 );
};
/**