Inferno  0.2
identifier_tracker.hpp
Go to the documentation of this file.
00001 #ifndef IDENTIFIER_TRACKER
00002 #define IDENTIFIER_TRACKER
00003 
00004 #include "clang/Parse/Action.h"
00005 #include "rc_hold.hpp"
00006 //#include "tree/cpptree.hpp"
00007 
00008 // Semantic.
00009 class DeclSpec;
00010 class ObjCDeclSpec;
00011 class AttributeList;
00012 struct FieldDeclarator;
00013 // Parse.
00014 class Selector;
00015 // Lex.
00016 class Token;
00017 
00018 
00019 class IdentifierTracker
00020 {
00021     // The scope tree is made up of these. Each one represents an object, user type
00022     // or compound statement. II is null if no name; parent is null if in global (root)
00023     // scope. A TNode t should only have other TNodes pointing to it if it is a scope.
00024     // Example:
00025     // class C { void F() { struct S { int X; }; } };
00026     // has parent pointers as: X -> S -> F -> C -> (NULL)
00027     // F has no identifier info, since it's name is not relevent to scopes (anonymous scope)
00028     // All should have valid node pointers (TODO fill in for compound statements)
00029     // C, F, S should have clang scope cs filled in.      
00030   // TODO use Scope and Identifier instead of Node everywhere
00031     struct TNode
00032     {
00033         shared_ptr<TNode> parent;
00034         shared_ptr<Node> node;
00035         clang::Scope *cs; // Note: this is the *corresponding* scope, not the containing scope.
00036                           // Eg given struct A { int B; }; then A->cs is the struct scope and B->cs is NULL
00037         clang::IdentifierInfo *II;
00038     };
00039     
00040     // Our best effort to determine the current scope
00041     stack< shared_ptr<TNode> > scope_stack;
00042     
00043     // Every TNode we ever create goes in this list, and is never deleted. 
00044     deque< shared_ptr<TNode> > tnodes; 
00045     
00046     // Parser can "warn" us that the next clang::Scope we see will correspond to
00047     // the supplied node (a Record node in fact).
00048     stack< shared_ptr<Node> > next_record;
00049 
00050     // Enter a new scope - clang doesn't tell us when to do this, so we deduce from
00051     // calls to Add.
00052     shared_ptr<TNode> Find( shared_ptr<Node> node );
00053     void PushScope( clang::Scope *S, shared_ptr<TNode> ts );
00054     void NewScope( clang::Scope *S );
00055     string ToString( shared_ptr<TNode> ts );
00056     bool IsIdentical( shared_ptr<TNode> current, shared_ptr<TNode> ident );
00057     int IsMatch( const clang::IdentifierInfo *II, shared_ptr<TNode> current, shared_ptr<TNode> ident, bool recurse );
00058 
00059     shared_ptr<Node> global;
00060 
00061 public:
00062     IdentifierTracker( shared_ptr<Node> g );
00063     
00064     /// Associate supplied node with supplied identifier and scope. Will remain 
00065     /// until the scope is popped. S must be current scope due to implementation.
00066     void Add( clang::IdentifierInfo *II, shared_ptr<Node> node, clang::Scope *S );
00067   
00068     /// Push a scope based on supplied Inferno tree Node
00069     void PushScope( clang::Scope *S, shared_ptr<Node> n );
00070 
00071     /// Let identifier tracker know we saw a scope. We must do this before calling other functions so we
00072     /// catch all the scope changes that are not communicated to us any other way.
00073     void SeenScope( clang::Scope *S );
00074 
00075     /// ActOnPopScope - When a scope is popped, if any typedefs are now 
00076     /// out-of-scope, they are removed from the clang::IdentifierInfo::FETokenInfo field.
00077     virtual void PopScope(clang::Scope *S);
00078   
00079     // Extract the Declaration for the clang::Identifier. Where the identifier is differently declared
00080     // in nested scopes, we get the one that applies currently (which is the innermost one)  
00081     // Optionally: Can specify a C++ scope, which must match exactly (NULL, falls back to current scope)
00082     //             Can ask for the corresponding decl node for the found node
00083     //             Can turn off recursion so only a direct match allowed
00084     shared_ptr<Node> Get( const clang::IdentifierInfo *II, shared_ptr<Node> iscope = shared_ptr<Node>(), bool recurse = true );                                         
00085   
00086     // Version that just results NULL if identifier has not been added yet
00087     shared_ptr<Node> TryGet( const clang::IdentifierInfo *II, shared_ptr<Node> iscope = shared_ptr<Node>(), bool recurse = true );      
00088     
00089     // Indicate that the next Add() call will have the supplied node as parent.
00090     // Omit to clear (eg after the struct)
00091     void SetNextRecord( shared_ptr<Node> n = shared_ptr<Node>() )
00092     {
00093         TRACE("next record is %p\n", n.get() );
00094         
00095         if( n )
00096             next_record.push(n);
00097         else
00098         {
00099             ASSERT( !next_record.empty() );
00100             next_record.pop();
00101         }
00102     }                             
00103     
00104     shared_ptr<Node> GetCurrent()
00105     {
00106         return scope_stack.top()->node;
00107     }
00108 };
00109 
00110 #endif