// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

// AspectC++ includes
#include "Transformer.h"
#include "JPAdvice.h"
#include "PointCutEvaluator.h"
#include "MemberProtections.h"
#include "PointCut.h"
#include "PointCutContext.h"
#include "IntroductionInfo.h"
#include "AdviceInfo.h"
#include "AspectInfo.h"
#include "JoinPointPlan.h"
#include "Plan.h"
#include "Repository.h"
#include "PointCutContext.h"
#include "CFlow.h"
#include "BackEndProblems.h"
#include "ACConfig.h"
#include "Introducer.h"

// PUMA includes
#include "Puma/CProject.h"
#include "Puma/CCSemVisitor.h"
#include "Puma/VerboseMgr.h"
#include "Puma/CFunctionInfo.h"
#include "Puma/CArgumentInfo.h"
#include "Puma/CTranslationUnit.h"
#include "Puma/CClassDatabase.h"
#include "Puma/ACAspectInfo.h"
#include "Puma/ACIntroductionInfo.h"
#include "Puma/ACPointcutInfo.h"
#include "Puma/ACTree.h"
#include "Puma/CPrintVisitor.h"

// C++ includes
#include <sstream>
using std::stringstream;
using std::endl;
using std::ends;

void Transformer::work (Unit *unit, Token *primary_start, Token *primary_end) {

  // set the start and end token of the unit
  _primary_start = primary_start;
  _primary_end   = primary_end;
  
  // determine back-end compiler problems and setup code weaver
  BackEndProblems back_end_problems;
  back_end_problems._local_class     = _conf.problem_local_class ();
  back_end_problems._spec_scope      = _conf.problem_spec_scope ();
  back_end_problems._size_type       = _conf.size_type ();
  back_end_problems._warn_macro      = _conf.warn_macro();
  back_end_problems._warn_deprecated = _conf.warn_deprecated();
  _code_weaver.problems (back_end_problems);
  
  // perform the transformation
  CTranslationUnit *tunit1 = 0;
  PointCutContext *context1 = 0;
  Plan plan (_err);
  
  bool ok = (phase1 (unit, tunit1, context1, plan) &&
             phase2 (unit, tunit1, *context1, plan));
  if (tunit1)
    delete tunit1;
  if (context1)
    delete context1;
  if (!ok)
    _vm << "Aborting" << endvm;
}

bool Transformer::phase1 (Unit *unit, CTranslationUnit *&tunit,
                          PointCutContext *&context, Plan &plan) {

  _vm << "Inserting namespace AC" << endvm;
  // in front of start!
  _code_weaver.insert_namespace_ac_before ((Token*)unit->first ());
  _code_weaver.commit ();
  
  _vm << "Parsing ..." << endvm;
  // parse the translation unit, but ignore function bodies
  unsigned options = _parser.Options ();
  _parser.Options (options | CCParser::SKIP_FCT_BODY);
  tunit = _parser.parse (*unit, _project);
  _parser.Options (options);
  // do semantic analysis of expressions
  _sem_visitor.run (tunit->tree ());
  
  if (_err.severity () >= sev_error)
    return false;

//  tunit->unit ()->print(cout);
//  CPrintVisitor printer;
//  printer.print (tunit->tree (), cout);

  //    Some debugging code:
  //    tunit->unit ()->print(cout);
  //    CPrintVisitor printer;
  //    printer.print (tunit->tree (), cout);
  //    tunit->db ().Dump (cout, 2);
  
  context = new PointCutContext (*tunit);
  
  _repo.setup (unit);

  _vm << "Setting Aspect Access Priviledges ..." << endvm;
  aspect_priviledges (*tunit);
  
  _vm << "Weaving Introductions ..." << endvm;
  introductions (*tunit, *context, plan);
      
  _vm << "Weaving Advice Declarations ..." << endvm;
  advice (*tunit);
  
  _vm << "Weaving Singleton Aspects ..." << endvm;
  singleton_aspects (*tunit);

  _vm << "Slice/Intro Includes ..." << endvm;
  _code_weaver.slice_includes (_project, _primary_start);

  _vm << "Commiting" << endvm;
  _code_weaver.commit ();

//    _vm << "Stage1 save!" << endvm;
//    _project.save();
//    _vm << " done." << endvm;
//	exit(1);

  return (_err.severity () < sev_error);
}

bool Transformer::phase2 (Unit *unit, CTranslationUnit *tunit1,
                          PointCutContext &context1, Plan &plan1) {

  _vm << "Parsing again ..." << endvm;
  
  // parse the translation unit, but ignore function bodies
  Introducer introducer (_code_weaver, _parser, plan1);
  _parser.introducer (&introducer);
  CTranslationUnit *tunit = _parser.parse (*unit, _project);
  _parser.introducer (0);

  // do semantic analysis of expressions
  _sem_visitor.run (tunit->tree ());

  if (_err.severity () >= sev_error) {
    // TODO: delete takes too much time and has no real use for ac++
    // so we skip it for now 
    // delete tunit;
    return false;
  }

//#ifdef TRY_INTRODUCER
//  cout << "Printing semantic database..." << endl;
//  tunit->db ().Dump (cout, 10);
//#endif // TRY_INTRODUCER
  
  //    CPrintVisitor printer;
  //    printer.print (tunit->tree (), cout);
  
  PointCutContext context (*tunit);
  
  _vm << "Weaving Join Points ..." << endvm;
  join_points (*tunit, context);
      
  _vm << "Final cleanup" << endvm;
  cleanup (*tunit);
  
  _vm << "Commiting" << endvm;
  _code_weaver.commit ();

  // TODO: delete takes too much time and has no real use for ac++
  // so we skip it for now 
  // delete tunit;
  
  _repo.cleanup ();
  return (_err.severity () < sev_error);
}


void Transformer::aspect_priviledges (CTranslationUnit &tunit) {
  CClassDatabase &db = tunit.db ();
  list<CClassInfo*> friends;
  for (int a = 0; a < db.AspectInfos (); a++) {
    CClassInfo *aspect_cls = db.AspectInfo (a)->ClassInfo ();
    if (!aspect_cls->Tree () ||
        !aspect_cls->ClassDB()->Project ()->
        isBelow (aspect_cls->SourceInfo ()->SrcUnit ()))
      continue;
    friends.push_back (aspect_cls);
  }
  if (!friends.empty ()) {
    for (unsigned c = 0; c < db.ClassInfos (); c++) {
      CClassInfo *cls = db.ClassInfo (c);
      if (!cls->Tree () ||
        !cls->ClassDB()->Project ()->isBelow (cls->SourceInfo ()->SrcUnit ()))
        continue;
        
      // Don't add friend declarations in the AC namespace definitions
      CScopeInfo *scope = cls->Scope ();
      while (!scope->GlobalScope ()) {
        if (strcmp (scope->QualName (), "AC") == 0)
          break;
        scope = scope->Parent ();
      }
      if (!scope->GlobalScope ())
        continue;
      _code_weaver.declare_friends (cls, friends);
    }
  }
}
      

void Transformer::cleanup (CTranslationUnit &tunit) {
  CClassDatabase &db = tunit.db ();

  // replace keyword "aspect" with "class" and remove advice
  for (int a = 0; a < db.AspectInfos (); a++) {
    ACAspectInfo *acai = db.AspectInfo (a);

    // remove advice declarations
    for (int adv = 0; adv < acai->AdviceNodes (); adv++)
      _code_weaver.kill (acai->AdviceNode (adv));

    _code_weaver.to_class (acai);
  }
      
  // delete all pointcut definitions that are left
  for (int p = 0; p < db.PointcutInfos (); p++)
    _code_weaver.kill (db.PointcutInfo (p)->def_node ());
}


void Transformer::introductions (CTranslationUnit &tunit,
				 PointCutContext &context, Plan &plan) {
  CClassDatabase &db = tunit.db ();

  for (int a = 0; a < db.AspectInfos (); a++) {
    ACAspectInfo *acai = db.AspectInfo (a);

    if (acai->is_abstract ())
      continue;
    context.aspect_info (acai);

    _vm << "intros for " << acai->name () << endvm;
    // create a pointcut evaluator
    PointCutEvaluator eva (_err, context);

    // now handle the introductions of this aspect
    AspectInfo *ai = plan.addAspect (acai);
    
    // add all the introductions (including inherited ones) to the aspect
    collect_intros (plan, db, ai, acai);

    _vm++;
    int i = 0;
    for (list<IntroductionInfo *>::iterator iter = ai->intro_infos ().begin ();
      iter != ai->intro_infos ().end (); ++iter, ++i) {
      IntroductionInfo *ii = (*iter);
      ACIntroductionInfo *acii = ii->ac_info ();
      CT_AdviceDecl *ad = acii->def_node ();

      ii->print (_vm);
      _vm << endvm;

      // check whether the slice is defined
      if (ii->type () == IntroductionInfo::INTRO_SLICE_DECL ||
          ii->type () == IntroductionInfo::INTRO_SLICE_REF) {
        ACSliceInfo *acsi = db.SliceInfo (ii->object(0));
        assert (acsi);
        if (!acsi->definition ()) {
          _err << sev_error << ad->token ()->location ()
               << "undefined slice '" << ii->object (0)->QualName ()
               << "' used in advice" << endMessage;
          continue;
        }
        if (acsi->type () == ACSliceInfo::SL_UNION) {
          _err << sev_error << ad->token ()->location ()
               << "union slices are not supported by ac++, yet" << endMessage;
          continue;
        }
      }
      else {
        if (_conf.warn_deprecated ())
          _err << sev_warning << ad->token ()->location ()
               << "deprecated introduction syntax, "
               << "use slice instead." << endMessage;
      }
      
      // evaluate the pointcut for this introduction
      PointCut target_scopes;
      Binding binding;
      eva.work (target_scopes, binding, ad->Pointcut (),
        (JoinPointLoc::join_point_type)
        (JoinPointLoc::Class | JoinPointLoc::Aspect));
      assert (!binding._used);
      if (_err.severity () >= sev_error)
        continue;

      // do the introduction into all classes refered by the pointcut
      _vm++;
      for (PointCut::iterator iter = target_scopes.begin ();
           iter != target_scopes.end (); ++iter) {
        const JoinPoint& jp = *iter;

        assert (jp.type () == JoinPointLoc::Class ||
                jp.type () == JoinPointLoc::Aspect);

        CClassInfo *cls = ((JPL_Class*)jp.location ())->class_info ();

        if (!cls->ClassDB()->Project ()->
            isBelow (cls->SourceInfo ()->SrcUnit ()))
          continue;

        _vm << "into " << cls->Name () << endvm;

        // consider the introduction in the big plan
        plan.consider (jp.location (), ii);

        // don't forget to include the aspect header, where some code is
        // introduced
        _code_weaver.add_intro_include ((JPL_Class*)jp.location (), ii);
      }  
      _vm--;

      // update the project repository
      _repo.update (*ii, target_scopes);
    }
    _vm--;
  }

  if (_err.severity () >= sev_error)
    return;

  _vm << "Aspect ordering ..." << endvm;
  orderings(tunit, plan, context, false);

  // now do the final checks on the accumulated plan
  _vm << "Final checks before weaving introductions" << endvm;
  plan.check ();

  // Don't weave if there were errors in the planning phase
  if (_err.severity () >= sev_error)
    return;

  _vm << "Class Join Points" << endvm;
  _vm++;
  for (int i = 0; i < plan.class_jp_plans (); i++) {
    JPP_Class &jp_plan = plan.class_jp_plan (i);
    JPL_Class &jp_loc = plan.class_jp_loc (i);
    
    _vm << jp_loc.signature () << endvm;

    // introduce base classes
    _code_weaver.baseclass (jp_loc, jp_plan);
    
    // handle other intros
    for (int i = 0; i < jp_plan.otherIntros (); i++) {
      IntroductionInfo *ii = jp_plan.otherIntro (i);
      
      if (ii->type () == IntroductionInfo::INTRO_SLICE_DECL ||
          ii->type () == IntroductionInfo::INTRO_SLICE_REF) {
        ACSliceInfo *acsi = db.SliceInfo (ii->object(0))->definition ();
        for (int m = 0; m < acsi->members (); m++)
          _code_weaver.introduce (&jp_loc, acsi->member (m),
            CProtection::PROT_NONE, _primary_end);
      }
      else {
        _code_weaver.introduce (&jp_loc, ii->tree ()->Decl (), ii->prot (),
          _primary_end);
      }
    }
  }
  _vm--;

  // now delete all slice definitions
  for (int s = 0; s < db.SliceInfos (); s++) {
    ACSliceInfo *acsi = db.SliceInfo (s);
    // first all members
    for (int sm = 0; sm < acsi->members (); sm++) {
      CT_Intro *member = acsi->member (sm);
      _code_weaver.kill (member);
    }
    // now the main definition
    if (!acsi->in_advice ())
      _code_weaver.kill (acsi->def_node ());
  }
  
  // finally remove the introductions from the code
  for (int i = 0; i < plan.intros (); i++)
    _code_weaver.kill (plan.intro (i)->tree ());
    
  return;
}

void Transformer::orderings (CTranslationUnit &tunit, Plan& plan,
                             PointCutContext& context, bool purge) {

  CClassDatabase &db = tunit.db ();

  for (int a = 0; a < db.AspectInfos (); a++) {

    ACAspectInfo *acai = db.AspectInfo (a);
    if (acai->is_abstract ())
      continue;
    context.aspect_info (acai);
    
    // create a pointcut evaluator
    PointCutEvaluator eva (_err, context);

    // collect all order statements of this aspect and its parents
    Array<CT_AdviceDecl*> order_nodes;
    collect_ordering (db, acai, order_nodes);

    AspectInfo *ai = plan.getAspect (acai);
    
    _vm++;
    for (int i = 0; i < (int)order_nodes.length (); i++) {
      CT_AdviceDecl *ad = order_nodes[i];
      CT_OrderList *lst = ((CT_OrderDecl*)ad->Decl ())->OrderList ();

      _vm << acai->name() << ":";

      OrderInfo *order_info = plan.addOrder(ai, ad);
      
      // resolve all pointcut expressions first
      Array<ACAspectInfo*> *ais = new Array<ACAspectInfo*>[lst->Entries ()];

      for (int n = 0; n < lst->Entries (); n++) {

      	if (n != 0)
      	  _vm << " ->";

      	// evaluate the current pointcut
       	PointCut pct;
        Binding binding; // must be unused here
      	eva.work (pct, binding, lst->Entry (n), JoinPointLoc::Aspect);
        assert (!binding._used);

      	// check all join points in this pointcut
        for (PointCut::iterator iter = pct.begin ();
             iter != pct.end (); ++iter) {
          const JoinPoint &jp = *iter;

          // get the AspectInfo object of this aspect
      	  ACAspectInfo* ai = ((JPL_Aspect*)jp.location ())->aspect_info ();

      	  // remember this aspect
      	  ais[n].append (ai);

      	  _vm << " " << ai->name ();
      	}
      }
      _vm << endvm;

      // now collect pairs of order requirements
      Array<ACAspectInfo*> oai_l; // aspect with lower precedence
      Array<ACAspectInfo*> oai_h; // aspect with higher precedence

      for (int n = 1; n < lst->Entries (); n++)
        for (int h = 0; h < ais[n - 1].length (); h++)
          for (int l = 0; l < ais[n].length (); l++) {
      	    oai_h.append (ais[n - 1].lookup (h));
      	    oai_l.append (ais[n].lookup (l));
      	  }

      delete[] ais;

      // evaluate the pointcut for this ordering
      PointCut target;
      Binding binding;
      eva.work (target, binding, ad->Pointcut (), JoinPointLoc::Any);
      assert (!binding._used);

      // remember the ordering in all JPP refered by the pointcut
      for (PointCut::iterator iter = target.begin ();
           iter != target.end (); ++iter) {
        const JoinPoint &jp = *iter;
        // remember the ordering in the big plan
        for (int i = 0; i < oai_l.length (); i++)
          plan.consider (jp.location (), *oai_h[i], *oai_l[i]);
      }

      if (purge) _code_weaver.kill (ad);
      
      // update the project repository
      _repo.update (*order_info);
    }
    _vm--;
  }
}


void Transformer::advice (CTranslationUnit &tunit)
 {
   CClassDatabase &db = tunit.db ();
   for (int a = 0; a < db.AspectInfos (); a++)
    {
      ACAspectInfo *ai = db.AspectInfo (a);

      _vm++;
      // handle all advice of this aspect
      for (int i = 0; i < ai->AdviceNodes (); i++) {
	CT_AdviceDecl *ad = ai->AdviceNode (i);
	CFunctionInfo *advice_func = ((CT_FctDef*)ad->Decl ())->Object ()->
	  FunctionInfo ();
	
	// handle only real advice here
	if (strncmp (advice_func->Name (), "%a", 2) != 0)
	  continue;
	
	// don't handle inherited advice here. This is done in the base class
	if (advice_func->BaseObject ())
	  continue;
	
	_vm << ai->ClassInfo ()->QualName () << "::" 
	    << advice_func->Name () << endvm;
	
	_code_weaver.declare_function (advice_func, ad); // first phase
      }
      _vm--;
    }

   return;
 }


void Transformer::singleton_aspects (CTranslationUnit &tunit) {
  CClassDatabase &db = tunit.db ();
  for (int a = 0; a < db.AspectInfos (); a++) {
    ACAspectInfo *ai = db.AspectInfo (a);

    if (ai->is_abstract ())
      continue;

    _code_weaver.singleton (ai);
  }
}

void Transformer::collect_intros (Plan &plan, CClassDatabase &db,
  AspectInfo *ai, ACAspectInfo *acai) {
  for (int i = 0; i < acai->IntroNodes (); i++)
    plan.addIntroduction (ai, acai->IntroNode (i));

  for (unsigned b = 0; b < acai->ClassInfo ()->BaseClasses (); b++) {
    CClassInfo *base = acai->ClassInfo ()->BaseClass (b)->Class ();
    ACAspectInfo *base_aspect = db.AspectInfo (base);
    if (base_aspect)
      collect_intros (plan, db, ai, base_aspect);
  }
}

void Transformer::collect_advice (CClassDatabase &db, ACAspectInfo *ai,
				  Array<CT_AdviceDecl*> &advice_nodes) {
  for (int i = 0; i < ai->AdviceNodes (); i++)
    advice_nodes.append (ai->AdviceNode (i));

  for (unsigned b = 0; b < ai->ClassInfo ()->BaseClasses (); b++) {
    CClassInfo *base = ai->ClassInfo ()->BaseClass (b)->Class ();
    ACAspectInfo *base_aspect = db.AspectInfo (base);
    if (base_aspect)
      collect_advice (db, base_aspect, advice_nodes);
  }
}

void Transformer::collect_ordering (CClassDatabase &db, ACAspectInfo *ai,
				    Array<CT_AdviceDecl*> &order_nodes) {
  for (int i = 0; i < ai->OrderNodes (); i++)
    order_nodes.append (ai->OrderNode (i));

  for (unsigned b = 0; b < ai->ClassInfo ()->BaseClasses (); b++) {
    CClassInfo *base = ai->ClassInfo ()->BaseClass (b)->Class ();
    ACAspectInfo *base_aspect = db.AspectInfo (base);
    if (base_aspect)
      collect_ordering (db, base_aspect, order_nodes);
  }
}

void Transformer::join_points (CTranslationUnit &tunit,
                               PointCutContext &context) {
  CClassDatabase &db = tunit.db ();
  Plan plan (_err);

  _vm++;

  _vm << "Advicecode manipulation" << endvm;
  // Iterate through advice
  for (int a = 0; a < db.AspectInfos (); a++) {
    ACAspectInfo *acai = db.AspectInfo (a);
    for (int i = 0; i < acai->AdviceNodes (); i++) {
      CT_AdviceDecl *ad = acai->AdviceNode (i);
      // register advice code in the big plan
      AdviceCode *code = plan.addAdviceCode (ad);
      // setup ThisJoinPoint object of this advice code
      code->this_join_point ().setup (code->function ());
      _code_weaver.provide_tjp (code->function (), code->this_join_point ());
    }
  }

  _vm << "Collecting Advice" << endvm;
  // Iterate through advice
  _vm++;

  // Create a pointcut evaluator
  PointCutEvaluator eva (_err, context);

  for (int a = 0; a < db.AspectInfos (); a++) {
    ACAspectInfo *acai = db.AspectInfo (a);

    // Don't weave advice of abstract aspects
    if (acai->is_abstract ())
      continue;

    context.aspect_info (acai);
    int index = 0; // CFlow index (each CFlow has a unique index per aspect)

    AspectInfo *ai = plan.addAspect (acai);

    // setup thisJoinPoint for aspectOf function, if there is one
    if (ai->aspectof()) {
      _vm << "Setting up thisJoinPoint for aspectof" << endvm;
     	ai->aspectof_this_join_point ().setup (ai->aspectof ());
      _vm << "Supplying aspectof() with JoinPoint and tjp if needed" << endvm;
      _code_weaver.provide_tjp (ai->aspectof (), ai->aspectof_this_join_point ());
    }

    // traverse inheritance tree and collect advice declarations
    Array<CT_AdviceDecl*> advice_nodes;
    collect_advice (db, acai, advice_nodes);

    // handle advice
    for (int i = 0; i < (int)advice_nodes.length (); i++) {
    	CT_AdviceDecl *ad = advice_nodes[i];
      AdviceInfo *advice_info = plan.addAdvice (ai, ad);

    	CFunctionInfo *adfunc = advice_info->code ().function ();

    	_vm << acai->name () << ": "  << adfunc->Name () << endvm;
    	_vm++;

    	// evaluate the pointcut, even inherited
    	_vm << "Evaluate Pointcut" << endvm;
    	PointCut &pc = advice_info->pointcut ();
      Binding &binding = advice_info->code ().binding ();
    	context.func (adfunc);
    	eva.work (pc, binding, ad->Pointcut (), JoinPointLoc::Code);
    	if (_err.severity () >= sev_error) {
  	    _vm--;
        continue;
      }

    	// Build a weaving plan for the join points
      for (PointCut::iterator iter = pc.begin ();
           iter != pc.end (); ++iter) {
        const JoinPoint &jp = *iter;

        // consider this joinpoint in the big plan
        plan.consider (jp.location (), jp.condition (), advice_info);

        // remember units for inclusion of aspect headers
        // TODO: AR_DEF shall soon be replace by AR_ADVICE!
        _code_weaver.add_aspect_include (jp.location (), ai, acai,
                                         AspectRef::AR_ADVICE);
      }

      // consider the cflow trigger needed for this advice in the plan
      const list<PointCut*> &trigger_pcs = pc.cflow_triggers();
      for (list<PointCut*>::const_iterator iter = trigger_pcs.begin ();
           iter != trigger_pcs.end (); ++iter, ++index) {
        PointCut *trigger_pc = *iter;
        // Consider a cflow trigger for every joinpoint is pointcut
        for (PointCut::iterator iter = trigger_pc->begin ();
             iter != trigger_pc->end (); ++iter) {
          const JoinPoint &jp = *iter;

          // consider this joinpoint in the big plan
          plan.consider (jp.location (), CFlow (advice_info, index));
          
          // remember units for inclusion of aspect headers
          _code_weaver.add_aspect_include (jp.location (), ai, acai,
                                           AspectRef::AR_DECL);
          
        }
      }
      
      // update the project repository
      _repo.update (*advice_info, pc);

      _vm--;
    }

    _code_weaver.invocation_functions (acai, _primary_start,
                                       ai->ifct_decls (), ai->ifct_defs ());
  }
  _vm--;

  _vm << "Aspect ordering ..." << endvm;
  orderings(tunit, plan, context, true);

  // now do the final checks on the accumulated plan
  _vm << "Final checks before weaving code join points" << endvm;
  plan.check ();

  // Don't weave if there were errors in the planning phase
  if (_err.severity () >= sev_error)
    return;

  _vm << "Type Check Functions" << endvm;
  _vm++;
  const TypeCheckSet &checks_false = plan.type_checks_false ();
  for (TypeCheckSet::const_iterator iter = checks_false.begin ();
       iter != checks_false.end (); ++iter) {
    _vm << "check for " << iter->second << " in "
        << iter->first->QualName () << " is false" << endvm;
    _code_weaver.type_check (iter->first, iter->second, false);
  }
  const TypeCheckSet &checks_true = plan.type_checks_true ();
  for (TypeCheckSet::const_iterator iter = checks_true.begin ();
       iter != checks_true.end (); ++iter) {
    _vm << "check for " << iter->second << " in "
        << iter->first->QualName () << " is true" << endvm;
    _code_weaver.type_check (iter->first, iter->second, true);
  }
  _vm--;
  
   _vm << "Call Join Points" << endvm;
   _vm++;
   for (int i = 0; i < plan.call_jp_plans (); i++) {
      JPP_Code &jp_plan = plan.call_jp_plan (i);
      JPL_MethodCall &jp_loc = plan.call_jp_loc (i);

      _vm << jp_loc.signature () << endvm;

      // handle call joinpoint itself
      _code_weaver.call_join_point (&jp_loc, jp_plan);
   }
   _vm--;

   _vm << "Execution Join Points" << endvm;
   _vm++;
   for (int i = 0; i < plan.exec_jp_plans (); i++)
    {
      JPP_Code &jp_plan = plan.exec_jp_plan (i);
      JPL_Method &jp_loc = plan.exec_jp_loc (i);

      _vm << jp_loc.signature () << endvm;

      // handle exec joinpoint itself
      _code_weaver.exec_join_point (&jp_loc, jp_plan);
    }
   _vm--;

   _vm << "Construction Join Points" << endvm;
   _vm++;
   for (int i = 0; i < plan.cons_jp_plans (); i++)
    {
      JPP_Code &jp_plan = plan.cons_jp_plan (i);
      JPL_Construction &jp_loc = plan.cons_jp_loc (i);

      _vm << jp_loc.signature () << endvm;

      // handle construction joinpoint itself
      _code_weaver.cons_join_point (&jp_loc, jp_plan);
    }
   _vm--;

   _vm << "Destruction Join Points" << endvm;
   _vm++;
   for (int i = 0; i < plan.dest_jp_plans (); i++)
    {
      JPP_Code &jp_plan = plan.dest_jp_plan (i);
      JPL_Destruction &jp_loc = plan.dest_jp_loc (i);

      _vm << jp_loc.signature () << endvm;

      // handle destruction joinpoint itself
      _code_weaver.dest_join_point (&jp_loc, jp_plan);
    }
   _vm--;

   _vm--;

   _vm << "Aspect Includes ..." << endvm;
   _code_weaver.aspect_includes (_project, _primary_start);
 }
   
