// 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                                            

#include "CodeWeaver.h"
// #include "IntroductionInfo.h"
// #include "PointCutInfo.h"
#include "AspectInfo.h"
#include "AdviceInfo.h"
#include "JoinPointLoc.h"
#include "JoinPointPlan.h"
#include "JPAdvice.h"
// #include "ThisJoinPoint.h"
// #include "AspectDb.h"
#include "ACUnit.h"
// #include "JoinPoint.h"
#include "Naming.h"
#include "IntroductionUnit.h"
#include "NamespaceAC.h"

#include "Puma/ErrorSink.h"
#include "Puma/ACTree.h"
#include "Puma/ACAspectInfo.h"
#include "Puma/CProtection.h"
#include "Puma/CTemplateInfo.h"
#include "Puma/CClassInfo.h"
#include "Puma/CUnionInfo.h"
#include "Puma/CAttributeInfo.h"
#include "Puma/CFileInfo.h"
#include "Puma/CArgumentInfo.h"
#include "Puma/CFunctionInfo.h"
#include "Puma/CProject.h"
#include "Puma/FileUnit.h"
#include "Puma/CClassDatabase.h"

void CodeWeaver::type_check (CRecord *rec, const string &name, bool result) {

  // are we in a class (and not in a struct)?
  bool in_class = (rec->ClassInfo () && !rec->ClassInfo ()->isStruct ());
  
  // create the code
  ostringstream code;
  code << endl;
  if (in_class)
    code << "public:" << endl;
  code << "  virtual bool " << name << " () const { return " 
       << (result ? "true" : "false") << "; }"	<< endl;
  if (in_class)
    code << "private:" << endl;
  code << ends;
  
  // paste the function after "{" of the class/struct/union definition
  Token *inspos = ((CT_ClassDef*)rec->Tree ())->Members ()->token ();
  const WeavePos &pos = weave_pos (inspos, WeavePos::WP_AFTER);
  paste (pos, code.str ());
}

void CodeWeaver::add_intro_include (JPL_Class *jpl, IntroductionInfo *ii) {

  assert (jpl && (jpl->type() == JoinPointLoc::Class ||
    jpl->type () == JoinPointLoc::Aspect));

  if (ii->type () == IntroductionInfo::INTRO_SLICE_DECL ||
      ii->type () == IntroductionInfo::INTRO_SLICE_REF) {
    CObjectInfo *obj = ii->object (0);
    assert (obj && obj->Tree ());
    assert (obj->Tree ()->NodeName () == CT_ClassSliceDecl::NodeId ());
    CT_ClassSliceDecl *csd = (CT_ClassSliceDecl*)obj->Tree ();
    // first the includes for the class decl intros
    Unit *su = (Unit*)csd->token ()->belonging_to ();
    Unit *iu = jpl->unit ();
    if (IntroductionUnit::cast (iu) == 0) // TODO: no intros into intros
      _slice_includes.insert (iu, su);
    // now the intros for the non-inline slice members
    CClassDatabase *db = obj->ClassDB ();
    ACSliceInfo *acsi = db->SliceInfo (obj);
    assert (acsi);
    for (int m = 0; m < acsi->members (); m++) {
      CT_Intro *intro = acsi->member (m);
      CSourceInfo *si = jpl->class_info ()->SourceInfo ();
      bool in_header = (strcmp (si->FileName (),
                                si->FileInfo ()->Primary ()->name ()) != 0);
      if (in_header) {
        // check if there is a link-once code element in the class
        CObjectInfo *loo = jpl->link_once_object ();
        // return silently if this is only a declaration
        if (!loo || loo->Scope () == jpl->class_info ())
          continue;
      }
      iu = si->FileInfo ()->Primary ();
      su = (Unit*)intro->token ()->belonging_to ();
      if (IntroductionUnit::cast (iu) == 0) // TODO: no intros into intros
        _slice_includes.insert (iu, su);
    }
    return;
  }
  
  // old-style intros ...
  Unit *su = (Unit*)&ii->unit ();
  Unit *iu = jpl->unit ();
  
  // handle the case of non-inline introductions
  if (ii->prot () == CProtection::PROT_NONE) {
    CSourceInfo *si = jpl->class_info ()->SourceInfo ();
    bool in_header = (strcmp (si->FileName (),
                              si->FileInfo ()->Primary ()->name ()) != 0);
                              
    if (in_header) {
      // check if there is a link-once code element in the class
      CObjectInfo *loo = jpl->link_once_object ();

      // TODO: for now loo has to != 0, later we can exploit the proj. repo
      if (!loo) {
        // error handling in introduce ()
        return;
      }
      
      // return silently if this is only a declaration
      if (loo->Scope () == jpl->class_info ())
        return;
    }
    
    iu = si->FileInfo ()->Primary ();
  }

  // Introductions into introductions are not supported, yet
  if (IntroductionUnit::cast (iu) != 0)
    return;
  
  _slice_includes.insert (iu, su);
}

void CodeWeaver::add_aspect_include (JoinPointLoc *jpl, AspectInfo *ai,
                                     ACAspectInfo *acai, AspectRef::Kind kind) {
  Unit *iu;

  if (jpl && jpl->type () == JoinPointLoc::MethodCall &&
      ((JPL_Code*)jpl)->is_pseudo ())
    return;

  // TODO: find out what this 'if' is good for ;-)
  if (!jpl)
    iu = acai->ClassInfo ()->SourceInfo ()->FileInfo ()->Primary ();
  else {
    iu = jpl->unit ();
  }

  // if the 'insert unit' is an 'introduction unit', find the intro target unit
  IntroductionUnit *intro_unit = 0;
  while ((intro_unit = IntroductionUnit::cast (iu)) != 0)
    iu = intro_unit->target_unit ();
  
  _aspect_includes.insert (iu, ai, acai, kind);
}

void CodeWeaver::aspect_includes (CProject &project, Token *first) {
  Unit *primary = (Unit*)first->belonging_to ();

  // weave the aspect includes in all registered unit
  for (AspectIncludes::const_iterator iter = _aspect_includes.begin ();
    iter != _aspect_includes.end (); ++iter) {

    // determine the insertion position for the current unit
    Unit *unit = _aspect_includes.unit (iter);
    bool is_primary = (unit == primary);
    Token *inspos = is_primary ? first : (Token*)unit->first ();

    // generate the includes for the current unit
    string includes = _aspect_includes.generate (project, iter);
    
    // paste the includes (and optional guard head) at the beginning
    paste (weave_pos (inspos, WeavePos::WP_BEFORE), includes);
  }
}

void CodeWeaver::slice_includes (CProject &project, Token *first) {
  Unit *primary = (Unit*)first->belonging_to ();

  // weave the aspect includes in all registered unit
  for (SliceIncludes::const_iterator iter = _slice_includes.begin ();
    iter != _slice_includes.end (); ++iter) {

    // avoid a manipulation error, because the directive is unbalanced
    ignore_unbalanced ();

    // determine the insertion position for the current unit
    Unit *unit = _slice_includes.unit (iter);
    bool is_primary = (unit == primary);
    Token *inspos = is_primary ? first : (Token*)unit->first ();

    // Find out if this unit has already been handled in the first phase.
    // In this case no include guard has to be generated.
    bool guard = (!is_primary);
    
    // generate the includes for the current unit
    string includes = _slice_includes.generate (project, iter);
    
    // generate the include guard prologue for the header file
    if (guard) {
      ostringstream guard_head;
      guard_head << "#ifndef ";
      Naming::guard (guard_head, (FileUnit*)unit);
      guard_head << endl << "#define ";
      Naming::guard (guard_head, (FileUnit*)unit);
      guard_head << endl << ends;
      includes += guard_head.str ();
    }
    
    // paste the includes (and optional guard head) at the beginning
    paste (weave_pos (inspos, WeavePos::WP_BEFORE), includes);
    
    // generate the #endif for the guard if needed
    if (guard) {
      ostringstream guard_tail;
      guard_tail << "#endif // ";
      Naming::guard (guard_tail, (FileUnit*)unit);
      guard_tail << endl << ends;
      paste (weave_pos ((Token*)unit->last (), WeavePos::WP_AFTER),
        guard_tail.str ());
    }
    
    // re-enable the manipulator preprocessor directive balance check
    check_unbalanced ();
  }
}

void CodeWeaver::insert_namespace_ac_before (Token *inspos) {
  paste (weave_pos (inspos, WeavePos::WP_BEFORE),
    NamespaceAC::def (_problems._size_type));
}


void CodeWeaver::to_class (ACAspectInfo *ai) {
  const WeavePos &from =
    weave_pos (ai->ClassInfo ()->Tree ()->token (), WeavePos::WP_BEFORE);
  const WeavePos &to =
    weave_pos (ai->ClassInfo ()->Tree ()->token (), WeavePos::WP_AFTER);
  replace (from, to, "class");
}


void CodeWeaver::invocation_functions (ACAspectInfo *ai, Token *first,
                                       const string &decls,
                                       const string &defs) {
        
//  Unit *aspect_unit  = (Unit*)ai->ClassInfo ()->SourceInfo ()->StartToken ()->
//                       token ()->belonging_to ();
//  Unit *primary_unit = (Unit*)first->belonging_to ();
//
//  const WeavePos &decl_pos = weave_pos ((aspect_unit == primary_unit) ? 
//                                         first : (Token*)aspect_unit->first (),
//                                         WeavePos::WP_BEFORE);
//  paste (decl_pos, decls);
  
  const WeavePos &def_pos = weave_pos (((CT_ClassDef*)ai->ClassInfo ()->
                                        Tree ())->ObjDecl ()->end_token (),
                                        WeavePos::WP_AFTER);
  paste (def_pos, defs);
}


void CodeWeaver::declare_function (CFunctionInfo *advice_func, 
				   CTree *advice_decl) {
  // Create a member function of the aspect that contains the advice code

  CT_FctDef *fctdef = (CT_FctDef*)advice_func->Tree ();
  CT_ArgDeclList *args = ((CT_FctDeclarator*)fctdef->Declarator ())->
    Arguments ();
     
  const WeavePos &after_args =
    weave_pos (args->end_token (), WeavePos::WP_AFTER);
   
  // duplicate the arguments
  copy (args, after_args);
   
  // create and insert the function name
  ostringstream func_decl;
  func_decl << " {}" << endl << "public: "
            << "void __" << (advice_func->Name () + 1) << " " << ends;
  paste (after_args, func_decl.str ());
                    
  // set the protection
  if (advice_func->Protection () != CProtection::PROT_PUBLIC) {
    paste (weave_pos (fctdef->end_token (), WeavePos::WP_AFTER),
      protection_string (advice_func->Protection ()));
  }
}


void CodeWeaver::declare_friends (CClassInfo *cls, list<CClassInfo*> &friends) {
  CClassInfo *def = (CClassInfo*)cls->DefObject ();
  
  // check if the class is generated by a macro
  if (def->Tree ()->token ()->is_macro_generated ()) {
    if (_problems._warn_macro) {
      _err << sev_warning << def->Tree ()->token ()->location ()
           << "class '" << def->QualName () << "' defined by macro"
           << endMessage;
    }
    return;
  }
    
  ostringstream friend_decls;
  ostringstream forward_decls;
  
  // close namespaces for the forward declarations
  close_namespace (forward_decls, cls);
  
  // add all forward and friend declarations
  for (list<CClassInfo*>::iterator iter = friends.begin ();
       iter != friends.end (); ++iter) {
         
    // if this is the aspect itself, skip this one
    if (def == (*iter)->DefObject ())
      continue;
  
    friend_decls << "  friend class ::" << (*iter)->QualName () << ";" << endl;
    forward_decls << "class " << (*iter)->Name () << ";" << endl;
  }
  
  // re-open the namespace
  open_namespace (forward_decls, cls);
  
  // insert the friend declarations into the class
  Token *inspos = ((CT_ClassDef*)def->Tree ())->Members ()->token ();
  paste (weave_pos (inspos, WeavePos::WP_AFTER), friend_decls.str ());

  // generate forward declarations iff this is no nested class
  if (!(nscope (def) && nscope (def)->ClassInfo ())) {
    // insert a forward declaration in front of the class
    inspos = def->TemplateInfo () ?
             def->TemplateInfo ()->Tree ()->token () :
             ((CT_ClassDef*)def->Tree ())->ObjDecl ()->token ();
    paste (weave_pos (inspos, WeavePos::WP_BEFORE), forward_decls.str ());
  }
}


void CodeWeaver::open_namespace (ostream &out, CClassInfo *cls) {
  bool is_template = cls->TemplateInfo ();
  CObjectInfo *obj = is_template ? (CObjectInfo*)cls->TemplateInfo () : cls;

  Array<CObjectInfo*> namespaces;
  while (!obj->Scope ()->GlobalScope () && obj->Scope ()->NamespaceInfo ()) {
    obj = obj->Scope ();
    namespaces.append (obj);
  }

  for (int i = namespaces.length () - 1; i >= 0; i--) {
    out << "namespace " << namespaces[i]->Name () << " {" << endl;
  }
}


void CodeWeaver::close_namespace (ostream &out, CClassInfo *cls) {
  bool is_template = cls->TemplateInfo ();
  CObjectInfo *obj = is_template ? (CObjectInfo*)cls->TemplateInfo () : cls;

  ostringstream ns_close;
  while (!obj->Scope ()->GlobalScope () && obj->Scope ()->NamespaceInfo ()) {
    obj = obj->Scope ();
    out << "} // closed " << obj->QualName () << endl;
  }
}


void CodeWeaver::introduce (JPL_Class *loc, CTree *decl,
                            CProtection::Type prot, Token *primary_end) {
  // name of the target class
  ostringstream target;
  target << " " << loc->class_info ()->QualName () << " " << ends;

  if (prot != CProtection::PROT_NONE) {
//    // An introduction inside the class
//    CClassInfo *cls = loc->class_info ();
//
//    // paste declaration before "}" of the class definition
//    Token *inspos = ((CT_ClassDef*)cls->DefObject ()->
//                    Tree ())->Members ()->end_token ();
//    const WeavePos &pos = weave_pos (inspos, WeavePos::WP_BEFORE);
//g++" -v -Dslice=_slice -I"../include" -O2 -Wall -D_REENTRANT -D_GNU_SOURCE -DPIC -fPIC -c -xc++ "os-unix.acc" -xnone -I"." -o "os-unix.pic.o"
//    // paste 'private:', 'protected', or 'public'      
//    paste (pos, protection_string (prot));
//
//    // copy the declaration
//    // replace all names of the aspect in the introduction with the name
//    // of the target class
//    CT_Intro *intro = (CT_Intro*)decl;
//    int start = 0;
//    for (int i = 0; i < intro->NameIndices (); i++) {
//      int index = intro->NameIndex (i);
//      if (index > start) {
//        copy (weave_pos (intro->Entry (start)->token (),
//                         WeavePos::WP_BEFORE),
//              weave_pos (intro->Entry (index - 1)->end_token (),
//                         WeavePos::WP_AFTER),
//              pos);
//      }
//      paste (pos, target.str ());
//      start = index + 1;
//    }
//    if (start < intro->Entries ()) {
//      copy (weave_pos (intro->Entry (start)->token (),
//                       WeavePos::WP_BEFORE),
//            weave_pos (intro->Entry (intro->Entries () - 1)->end_token (),
//                       WeavePos::WP_AFTER),
//            pos);
//    }
//
//    // paste 'private:' afterwards
//    paste (pos, protection_string (CProtection::PROT_PRIVATE));
  }
  else {
    // an external introduction

    CSourceInfo *si = loc->class_info ()->SourceInfo ();
    bool in_header = (strcmp (si->FileName (),
                              si->FileInfo ()->Primary ()->name ()) != 0);
                              
    if (in_header) {
      // check if there is a link-once code element in the class
      CObjectInfo *loo = loc->link_once_object ();

      // TODO: for now loo has to != 0, later we can exploit the proj. repo
      if (!loo) {
        _err << sev_warning << decl->token ()->location () 
             << "cannot introduce non-inline function or static attribute"
             << " into \"class " << loc->class_info ()->QualName ()
             << "\". It has to contain link-once code." << endMessage;
        return;
      }
      
      // return silently if this is only a declaration
      if (loo->Scope () == loc->class_info ())
        return;
    }
    
    // insert the copy of the declaration at the end of the translation unit
    const WeavePos &pos = weave_pos (primary_end, WeavePos::WP_AFTER);

    // TODO: this loop has to be executed in a different order than the loop
    //       for the introduction of inline members. The reason is the
    //       tranformation system: here we have an WP_AFTER position while
    //       the other loop has a WP_BEFORE position. That's ugly!
    
    // replace all names of the aspect in the introduction with the name
    // of the target class
    CT_Intro *intro = (CT_Intro*)decl;
    ostringstream target_qual, target_unqual;
    target_unqual << " " << loc->class_info ()->Name () << " " << ends;
    target_qual << " " << loc->class_info ()->QualName () << " " << ends;
    int start = intro->Entries () - 1;
    for (int i = intro->NameIndices () - 1; i >= 0; i--) {
      int index = intro->NameToIndex (i);
      if (index < start) {
        copy (weave_pos (intro->Entry (index + 1)->token (),
                         WeavePos::WP_BEFORE),
              weave_pos (intro->Entry (start)->end_token (),
                         WeavePos::WP_AFTER),
              pos);
      }
      if (intro->NameQual (i))
        paste (pos, target_qual.str ());
      else
        paste (pos, target_unqual.str ());
      start = intro->NameIndex (i) - 1;
    }
    if (start >= 0) {
      copy (weave_pos (intro->Entry (0)->token (),
                       WeavePos::WP_BEFORE),
            weave_pos (intro->Entry (start)->end_token (),
                       WeavePos::WP_AFTER),
            pos);
    }
  }
}

void CodeWeaver::baseclass (JPL_Class &loc, JPP_Class &plan) {
  CClassInfo *cls = loc.class_info ();

  // let the plan generate the baseclass list
  string bcl = plan.gen_baseclass_list ();
  if (bcl != "") {
    bcl = string (cls->BaseClasses () == 0 ? " :" : ",") + bcl;
    // paste the new base before "{" of the class definition's member list
    const WeavePos &pos = weave_pos (((CT_ClassDef*)cls->DefObject ()->
                                      Tree ())->Members ()->token (),
                                      WeavePos::WP_BEFORE);
    paste (pos, bcl);
  }
}

// void CodeWeaver::inherited (JPL_Class *loc, IntroductionInfo *intro)
//  {
//    TN_ClassInfo *cls = loc->class_info ();

//    const char *prot = intro->def_node ()->protection ();

//    for (unsigned f = 0; f < cls->Functions (); f++)
//     {
//       TN_FunctionInfo *func = cls->Function (f);
//       if (!func->isInherited () || func->isVirtual ())
// 	 continue;
      
//       if(!((strcmp (prot, "private") == 0  &&
// 	    func->Protection () == TN_ObjectInfo::PRIVATE) ||
// 	   (strcmp (prot, "protected") == 0  &&
// 	    func->Protection () == TN_ObjectInfo::PROTECTED) ||
// 	   (strcmp (prot, "public") == 0  &&
// 	    func->Protection () == TN_ObjectInfo::PUBLIC)))
// 	 continue;

//       // This check is too simple, it forgets the argument types
//       unsigned args = func->BaseObject ()->FunctionInfo ()->Arguments ();
//       int number = -1;
//       for (unsigned l = 0; l < cls->Functions (); l++)
//        {
// 	 TN_FunctionInfo *cmp = cls->Function (l);
// 	 if (cmp->isInherited ())
// 	    cmp = cmp->BaseObject ()->FunctionInfo ();

// 	 if (f != l &&
// 	     strcmp (func->Name (), cmp->Name ()) == 0 &&
// 	     args == cmp->Arguments ())
// 	  {
// 	    number = (int)l;
// 	    break;
// 	  }
//        }

//       if (number != -1)
//        {
// 	 _err << sev_warning << "Function " << func->Name ()
// 	      << " is inherited more than once by class "
// 	      << cls->Name () << ": "
// 	      << cls->Function (number)->BaseObject ()->QualName () 
// 	      << " and " << func->BaseObject ()->QualName ()
// 	      << endMessage;
// 	 continue;
//        }
      
//       CUnit *out = new_intro_unit (intro);

//       *out << prot << ":" << endl;

//       func = func->BaseObject ();
//       TN_TypeInfo *ftype = func->TypeInfo ();

//       *out << "inline ";
//       if (func->isVirtual ())
// 	 *out << "virtual ";
//       else if (func->defStatic ())
// 	 *out << "static ";
//       stringstream sig;
//       if (func->isOperator ())
// 	 sig << "operator ";
//       sig << func->Name ();
//       sig << " (";
//       replacement_fct_args (sig, func, true, true);
//       sig << ")";
//       if (ftype->isConst ())
// 	 sig << " const";
//       if (ftype->isVolatile ())
// 	 sig << " volatile";
//       sig << ends;
//       TN_TypeInfo *result_type = ftype->BaseType ();
//       result_type->TypeText (*out, sig.str ().data ());
      
//       // generate the function body
//       *out << endl;
//       *out << " {" << endl;
//       *out << "   ";
//       if (!result_type->isVoid ())
// 	 *out << "return ";
//       if (func->Scope ()->ClassInfo ())
// 	 *out << "::" << func->Scope ()->ClassInfo ()->QualName () << "::";
//       if (func->isOperator ())
// 	 *out << "operator ";
//       *out << func->Name () << "(";
//       for (unsigned a = 0; a < func->Arguments (); a++)
//        {
// 	 if (a > 0)
// 	    *out << ", ";
// 	 *out << "arg" << a;
//        }
//       *out << ");" << endl;
//       *out << " }" << endl;
//       *out << endu;
   
//       // paste the function behind "{" of the class definition
//       Token *inspos = cls->DefNode ()->son (2)->token ();

//       _commander.paste (inspos, out);
//     }
//  }

void CodeWeaver::singleton (ACAspectInfo *ai) {
  if (ai->aspect_of ()) {
    // if necessary, rename aspectOf to aspectof  
    if (strcmp (ai->aspect_of ()->Name (), "aspectOf") == 0) {
      CT_FctDef *fctdef = (CT_FctDef*)ai->aspect_of ()->Tree ();
      CT_SimpleName *name = ((CT_Declarator*)fctdef->Declarator ())->Name ();
      name = name->Name (); // if it is qualified
      const WeavePos &name_start =
        weave_pos (name->token (), WeavePos::WP_BEFORE);
      const WeavePos &name_end =
        weave_pos (name->end_token (), WeavePos::WP_AFTER);
      replace (name_start, name_end, "aspectof");
    }
  }
  else {
    // paste __instance declaration after "{" of the aspect definition
    Token *member_list = ((CT_ClassDef*)ai->ClassInfo ()->Tree ())->
      Members ()->token ();
    const WeavePos &pos = weave_pos (member_list, WeavePos::WP_AFTER);
    
    ostringstream func;
    func << endl
      << "public:" << endl
      << "  static " << ai->name () << " *aspectof () {" << endl
      << "    static " << ai->name () << " __instance;" << endl
      << "    return &__instance;" << endl
      << "  }" << endl
      << "  static " << ai->name () << " *aspectOf () {" << endl
      << "    return aspectof ();" << endl
      << "  }" << endl
      << "private:" << endl << ends;
    
    paste (pos, func.str ());
  }
}

// generate the code, which proceeds an intercepted flow of control, e.g.
// continues a call or execution
void CodeWeaver::make_proceed_code (ostream &out, JoinPointLoc *badly_typed_loc,
                                    bool action, int max_depth) {
  JPL_Code *loc = (JPL_Code*)badly_typed_loc;
  // set flags that describe the kind of join point
  bool is_exec = false, is_call = false, is_cons = false, is_dest = false;  
  if (loc->type () == JoinPointLoc::Method)
    is_exec = true;
  else if (loc->type () == JoinPointLoc::MethodCall)
    is_call = true;
  else if (loc->type () == JoinPointLoc::Construction)
    is_cons = true;
  else if (loc->type () == JoinPointLoc::Destruction)
    is_dest = true;
  else
    return; // should not happen!

  // find out which function has to be called 
  CFunctionInfo *dstfunc = (is_exec ? ((JPL_Method*)loc)->func_info () :
                           (is_call ? ((JPL_MethodCall*)loc)->called ():
                           (is_cons ? ((JPL_Construction*)loc)->func_info () :
                           (is_dest ? ((JPL_Destruction*)loc)->func_info () :
                           0))));
  bool obj_needed = needs_this (dstfunc);
  
  bool local_class = (is_call && !_problems._local_class &&
                      !((JPL_MethodCall*)loc)->in_member_init () &&
                      ((JPL_MethodCall*)loc)->needs_rights ());
  bool havefuncptr = (is_call && ((JPL_MethodCall*)loc)->needs_rights () &&
                      (!local_class || max_depth > 0));
                      
  // nothing is done to proceed implicitly defined special member fcts
  if ((is_cons || is_dest) && dstfunc->isBuiltin ())
    return;

  // create a local class that enters/leaves the cflow triggers
  const CFlowList &cflows = _code_plan->cflows ();
  if (cflows.size () > 0) {
    out << "{" << endl;
    cflows.gen_trigger_obj (out);
  }

  // generate the 'result =' code
  CTypeInfo *result_type = 
    dstfunc->isConversion () ? dstfunc->ConversionType () :
    dstfunc->TypeInfo ()->BaseType ();
    
  if (action)
    make_action_result_assignment(out, result_type);
  else
    make_result_assignment(out, result_type);
  
  // if we call the function with a function pointer there must be one more br.
  if (havefuncptr)
    out << "(";
      
  // if an object is needed for the call, issue 'obj->'
  if (obj_needed) {
    if (is_call) {
      if (action) {
        out << "((";
        Naming::tjp_struct (out, loc, 0);
        out << "::Target*)_target)->";
      }
      else {
        out << "dstthis->";
      }
    }
    else if (is_exec || is_cons || is_dest) {
      if (action) {
        out << "((";
        Naming::tjp_struct (out, loc, 0);
        out << "::That*)_that)->";
      }
      else {
        out << "this->";
      }
    }
  }
  
  // generate the function name
  if (is_exec || (!dstfunc->isBuiltin () && (is_cons || is_dest))) {
    if (!obj_needed && nscope (dstfunc))
      out << "::" << nscope (dstfunc)->QualName () << "::";
    // use __old_<name> for execution join points
    Naming::exec_inner (out, loc);
  } else if (is_call) {
    if (havefuncptr) {
      if (action) {
        out << "**(";
//        if (dstfunc->isMethod () && !dstfunc->isStaticMethod ()) 
//          CTypeMemberPointer (dstfunc->TypeInfo (),
//                              dstfunc->Record ()).TypeText (out, "*",
//                                                            true, true);
//        else
//          CTypePointer (dstfunc->TypeInfo ()).TypeText (out, "*", true, true);
        if (dstfunc->isMethod ()) 
          CTypePointer (dstfunc->TypeInfo ()).TypeText (out, "*", false, true);
        out << ")_fptr";
      } else {
        out << "*fptr";
      }
    }
    else {
      // destination function name
      if (((JPL_MethodCall*)loc)->is_qualified () ||
          dstfunc->isStaticMethod () || !dstfunc->isMethod ()) {
        out << "::";
        if (nscope (dstfunc))
          out << nscope (dstfunc)->QualName () << "::";
      }
  
      out << dstfunc->Name ();
    }
  }

  // if this was a call via pointer we need a closing bracket
  if (havefuncptr)
    out << ")";
    
  // destination function arguments
  out << "(";
  for (int a = 0 ; a < loc->arg_count (); a++) {
    if (a > 0) out << ", ";
    if (action) {
      // make sure that if the argument type was a reference we use the
      // referred type here
      out << "*((";
      Naming::tjp_struct (out, loc, 0);
      out << "::Arg<" << a << ">::ReferredType*)_args[" << a << "])";
    }
    else
      out << "arg" << a;
  }
  out << ")";
  // new: bracket if we have a result assignment
  if (!(result_type->isVoid () || result_type->isUndefined ()))
    out << ")";
    
  out << ";" << endl;
    
  if (cflows.size () > 0)
    out << "}" << endl;
}

// create an action wrapper function, which may be invoked by 'proceed()'
void CodeWeaver::make_action_wrapper(ostream &impl, JoinPointLoc *loc,
                                     JPAdvice *jpa) {
  // generate the action function, which is used to obtain an action object
  impl << "  AC::Action &action() {" << endl;
  impl << "    _wrapper = &";
  Naming::action_wrapper (impl, loc, jpa->depth ());
  impl << ";" << endl;
  impl << "    return *this;" << endl;
  impl << "  }" << endl;

  // make the function static if it is defined in class scope
  impl << "  static void ";
  Naming::action_wrapper (impl, loc, jpa->depth ());
  impl << " (AC::Action &action) {" << endl;
  // convert the action object ref into a TJP_... object ref and call proceed
  impl << "    ((";
  Naming::tjp_struct (impl, loc, jpa->depth ());
  impl << "&)action).proceed ();" << endl;

  impl << "  }" << endl;
}

// create the 'proceed()' function for the current level
void CodeWeaver::make_proceed_func(ostream &impl, JoinPointLoc *loc,
                                   JPAdvice *jpa) {
  // the signature
  impl << "  void proceed () {" << endl;

  if (jpa->depth() == 0) {
    // this is a proceed function for the last around advice
    make_proceed_code (impl, loc, true, jpa->max_depth ());
  }
  else {
    // generate advice calls
    make_advice_calls (impl, jpa->next (), loc, true);
  }
  impl << "  }" << endl;
}

// insert TJP class definition before join point
void CodeWeaver::make_tjp_struct(ostream &out, JoinPointLoc *loc,
                                 JPAdvice *jpa) {

  // recursively call the function for the previous TJP classes
  if (jpa->depth () > 0) {
    make_tjp_struct (out, loc, jpa->next ());
  }
  
  // generate the definition
  out << endl;
  const ThisJoinPoint &tjp = jpa->root ()->tjp ();
  tjp.gen_tjp_struct (out, (JPL_Code*)loc, _problems, jpa->depth ());
  
  // generate the proceed function for the current structure
  if (jpa->around () &&
      (jpa->around ()->code ().this_join_point ().proceed () ||
       jpa->around ()->code ().this_join_point ().action() ||
       !jpa->around ()->pointcut ().cflow_triggers ().empty ()))
    make_proceed_func (out, loc, jpa);
  
  // generate action wrapper if needed
  if (jpa->around () && jpa->around ()->code ().this_join_point ().action())
    make_action_wrapper (out, loc, jpa);
  
  // closing bracket of the TJP class! Opened in gen_tjp_struct.
  out << "};" << endl;
  
  if (jpa->depth () == 0) {
    stringstream jpname;
    Naming::tjp_struct (jpname, loc, 0);
    jpname << ends;
    jpa->root ()->gen_binding_templates (out, jpname.str ().data (), _problems);
  }
  
  out << endl;
}

void CodeWeaver::make_tjp_common_init(ostream &code, JoinPointLoc *badly_typed_loc,
				      JPAdvice *jpa) {
  JPL_Code *loc = (JPL_Code*)badly_typed_loc;
  const ThisJoinPoint &tjp = jpa->tjp ();
  JoinPointLoc::join_point_type jptype = loc->type ();

  bool local_class = false, havefuncptr = false;
  // determine the weaving parameters
  if (jptype == JoinPointLoc::MethodCall) {
    local_class = (!_problems._local_class &&
                   !((JPL_MethodCall*)loc)->in_member_init () &&
                   ((JPL_MethodCall*)loc)->needs_rights ());
    havefuncptr = (((JPL_MethodCall*)loc)->needs_rights () &&
                   (!local_class || jpa->depth () > 0));
  }

  if (tjp.pointer_needed ()) {    

    int args = ((JPL_Code*)loc)->arg_count ();
    if (tjp.arg() || tjp.useAction() ||
        (tjp.proceed () && loc->proceed_needs_args ())) {
      if (args) {
        code << "  void *";
        Naming::tjp_args_array(code, loc);
        code << "[] = { ";
        for (int i = 0; i < args; i++) {
          if (i > 0) code << ", ";
          code << "(void*)&arg" << i;
        }
        code << " };" << endl;
      }
    }
    
    code << "  ";
    Naming::tjp_struct(code, loc, jpa->depth ());
    code << " ";
    Naming::tjp_instance(code, loc);
    code << ";" << endl;

    if (tjp.arg() || tjp.useAction() ||
        (tjp.proceed () && loc->proceed_needs_args ())) {
      code << "  ";
      Naming::tjp_instance(code, loc);
      code << "._args = ";
      if (args)
        Naming::tjp_args_array(code, loc);
      else
        code << "0";
      code << ";" << endl;
    }
    
    if (tjp.result() || tjp.useAction() ||
        (tjp.proceed () && loc->proceed_needs_result ())) {
      code << "  ";
      Naming::tjp_instance(code, loc);
      code << "._result = ";
      CTypeInfo *rtype = ((JPL_Code*)loc)->result_type ().type_info ();
      if (!(rtype->isVoid() || rtype->isUndefined ())) {
        if (tjp.useAction ())
          code << "(void*)";
        code << "&(";
        Naming::tjp_struct (code, loc, jpa->depth ());
        code << "::Result&)result";
      } else {
        code << "0";
      }
      code << ";" << endl;
    }
    
    if (tjp.target() || tjp.useAction() ||
        (tjp.proceed () && loc->proceed_needs_target ())) {
      code << "  ";
      Naming::tjp_instance(code, loc);
      code << "._target = ";
      if (loc->tjp_target () && needs_this (loc->tjp_target())) {
        code << " (";
        if (tjp.useAction ())
          code << "void*)";
        else {
          Naming::tjp_struct(code, loc, jpa->depth ());
          code << "::Target*)";
        }
        switch (jptype) {
          case JoinPointLoc::Construction:
          case JoinPointLoc::Destruction:
          case JoinPointLoc::Method:
            code << "this";
            break;
          case JoinPointLoc::MethodCall:
            code << "dstthis";
            break;
          default:
            code << " 0";
    	  }
      } else {
        code << " 0";
      }
      code << ";" << endl;
    }

    if (tjp.that() || tjp.useAction() ||
        (tjp.proceed () && loc->proceed_needs_that ())) {
      code << "  ";
      Naming::tjp_instance(code, loc);
      code << "._that = ";
      if (loc->tjp_that () && needs_this (loc->tjp_that())) {
        code << " (";
        if (tjp.useAction ())
          code << "void*)";
        else {
          Naming::tjp_struct(code, loc, jpa->depth ());
          code << "::That*)";
        }
        switch (jptype) {
          case JoinPointLoc::Construction:
          case JoinPointLoc::Destruction:
          case JoinPointLoc::Method:
            code << "this";
            break;
          case JoinPointLoc::MethodCall:
            code << "srcthis";
            break;
          default:
            code << " 0";
        }
      } else {
        code << " 0";
      }
      code << ";" << endl;
    }
    
    if (tjp.useAction () ||
        (tjp.proceed () && loc->proceed_needs_fptr ())) {
      code << "  ";
      Naming::tjp_instance(code, loc);
      code << "._fptr = ";
      if (havefuncptr)
        code << "&fptr";
      else  
        code << "0";
      code << ";" << endl;
    }
  }
}

void CodeWeaver::make_result_type (ostream &out, CTypeInfo *type,
  bool reference) {
  if (type->isVoid () || type->isUndefined ())
    out << "void";
  else if (type->isAddress ())
    type->BaseType ()->TypeText (out, reference ? "*&" : "*", true, true);
  else
    type->TypeText (out, reference ? "&" : "", true, true);
}

void CodeWeaver::make_result_declaration(ostream &out, CTypeInfo *type) {
  if (!(type->isVoid () || type->isUndefined ())) {
    out << "  AC::ResultBuffer< ";
    make_result_type (out, type, false);
    out << " > result;" << endl;
  }
}

void CodeWeaver::make_result_assignment(ostream &out, CTypeInfo *type) {
  if (!(type->isVoid() || type->isUndefined ()))  {
    out << "  ::new (&result) ";
    make_result_type (out, type->UnqualType (), false);
    out << " (";
    if (type->isAddress ())
      out << "&";
  }
}

void CodeWeaver::make_action_result_assignment(ostream &out, CTypeInfo *type) {
  if (!(type->isVoid() || type->isUndefined ()))  {
    out << "  ::new ((AC::ResultBuffer< ";
    make_result_type (out, type, false);
    out << " >*)_result) ";
    make_result_type (out, type, false);
    out << " (";
    if (type->isAddress ())
      out << "&";
  }  
}

void CodeWeaver::make_result_return(ostream &out, CTypeInfo *type) {
  if (!(type->isVoid () || type->isUndefined ())) {
    out << "  return ";
    if (type->isAddress ())
      out << "*";
    out << "(";
    make_result_type (out, type, true);
    out << ")result;" << endl;
  }
}

void CodeWeaver::cons_join_point (JPL_Construction *loc, JPP_Code &plan) {
  if (loc->assoc_obj ()->FunctionInfo ()->isBuiltin ())
    gen_special_member_function (loc, plan);
  else
    wrap_function (loc, plan);
}
  
void CodeWeaver::dest_join_point (JPL_Destruction *loc, JPP_Code &plan) {
  if (loc->assoc_obj ()->FunctionInfo ()->isBuiltin ())
    gen_special_member_function (loc, plan);
  else
    wrap_function (loc, plan);
}
  

// checks whether an implicitely defined constructor or destructor may be
// generated
bool CodeWeaver::check_special_member_function (CFunctionInfo *func) {
  // the argument should be a valid class member
  assert (func && func->ClassScope ());
  CClassInfo *cls = func->ClassScope ()->ClassInfo ();

  // check if any base class has a private constructor/copy constructor/destr.
  for (unsigned b = 0; b < cls->BaseClasses (); b++) {
    CClassInfo *base = cls->BaseClass (b)->Class ();
    for (unsigned f = 0; f < base->Functions (); f++) {
      CFunctionInfo *curr = base->Function (f);
      if ((curr->isConstructor () && func->isConstructor () &&
           curr->Arguments () == func->Arguments ()) ||
          (curr->isDestructor () && func->isDestructor ())) {
        if (curr->Protection () == CProtection::PROT_PRIVATE ||
            !check_special_member_function (curr))
          return false; // function or any base is private -> problem!
      }
    }
  }
  return true; // no problem
}


void CodeWeaver::gen_special_member_function (JoinPointLoc *loc,
                                              JPP_Code &plan) {
  _code_plan = &plan;

  ostringstream code;
  JPAdvice *ejpa = plan.jp_advice ();
  CFunctionInfo *func = loc->assoc_obj ()->FunctionInfo ();
  assert (func && func->ClassScope ());
  CClassInfo *cls = func->ClassScope ()->ClassInfo ();

  // check if the special member would have to call a private member
  if (!check_special_member_function (func))
    return; // can be ignored, because the implicit special member can't be
            // called anyway

  Token *inspos = ((CT_ClassDef*)cls->Tree ())->Members ()->end_token ();
    
  // create thisJoinPoint class
  ejpa->mergeTJPFlags();
  if (ejpa->tjp ().type_needed ()) {
    ostringstream wrappers;
    make_tjp_struct(wrappers, loc, ejpa);
    wrappers << ends;
    paste (weave_pos (inspos, WeavePos::WP_BEFORE), wrappers.str ());
  }

  // generate the function itself  
  code << endl << "public:" << endl << "inline " << func->Name ();
  
  // constructors or destructors don't have more than one argument
  assert (func->Arguments () <= 1);
  
  if (func->Arguments () == 0) {
    // default constructor or destructor
    code << " () {" << endl;
  }
  else {
    CT_ClassDef *cd = (CT_ClassDef*)cls->Tree ();
    // wrap attributes that are non-static arrays in a class.
    wrap_attribute_arrays (cd->Members ());
    // the same for introduced members
    if (cd->IntroMembers ()) {
      wrap_attribute_arrays ((CT_MembList*)cd->IntroMembers ());
    }
    
    // generate the copy constructor
    code << " (";
    func->Argument (0u)->TypeInfo ()->TypeText (code, "arg0");
    code << ") ";
    // copy the baseclass members
    bool first_initializer = true;
    for (unsigned b = 0; b < cls->BaseClasses (); b++) {
      if (first_initializer) {
        first_initializer = false;
        code << ": ";
      }
      else
        code << ", ";
      CClassInfo *base = cls->BaseClass (b)->ClassPseudoInstance () ?
        cls->BaseClass (b)->ClassPseudoInstance () :
        cls->BaseClass (b)->Class ();
      code << *base->TypeInfo () << " (arg0)";
    }

    set<CUnionInfo*> anon_unions;
    for (unsigned a = 0; a < cls->Attributes (); a++) {
      CAttributeInfo *attr = cls->Attribute (a);

      // only certain members are initialized
      if (attr->isStatic () || attr->isAnonymous () || attr->EnumeratorInfo ())
        continue;

      // attributes that are member of anonymous unions have to be copied
      // differently
      if (attr->Scope ()->isUnion ()) {
        anon_unions.insert (attr->Scope ()->UnionInfo ());
        continue;
      }
        
      // write ':' or ','
      if (first_initializer) {
        first_initializer = false;
        code << ": ";
      }
      else
        code << ", ";
      // initialize the member by copy-constructor
      code << attr->Name () << " (arg0." << attr->Name () << ")";
    }
    code << " {" << endl;

    // copy anonymous unions
    int count = 0;
    for (set<CUnionInfo*>::const_iterator iter = anon_unions.begin ();
      iter != anon_unions.end (); ++iter, ++count) {
      CUnionInfo *curr_union = *iter;
      CAttributeInfo *attr = curr_union->Attribute (0);
      // anonymous unions are very simple to copy. They have no base classes,
      // no function members, no static members, ...
      
      // create a named local copy of the union definition 
      code << "  union __ac_union_" << count << " ";
      print_tree (code, ((CT_UnionDef*)curr_union->Tree ())->Members ());
      code << ";" << endl;
      code << "  *(union __ac_union_" << count << "*)&" << attr->Name ()
           << " = *(union __ac_union_" << count << "*)&arg0."
           << attr->Name () << ";" << endl;
    }
  }

  // generate common JoinPoint initialization
  make_tjp_common_init(code, loc, ejpa);
    
  // generate calls to advice code or original function
  make_advice_calls(code, ejpa, loc);

  code << endl << "}" << endl << ends;
 
  // insert the definition
  paste (weave_pos (inspos, WeavePos::WP_BEFORE), code.str ());
}

// wrap attributes that are non-static arrays in a class.
void CodeWeaver::wrap_attribute_arrays (CT_MembList *members) {
  for (int m = 0; m < members->Entries (); m++) {
    if (members->Entry (m)->NodeName () != CT_ObjDecl::NodeId ())
      continue;
    CT_ObjDecl *decl = (CT_ObjDecl*)members->Entry (m);
    CT_DeclSpecSeq *decl_specs = decl->DeclSpecs ();
    CT_DeclaratorList *dlist = decl->Declarators ();
    bool del_decl_specs = false;
    for (int init_decls = 0, s = 0; s < dlist->Sons (); s++) {
      if (dlist->Son (s)->NodeName () != CT_InitDeclarator::NodeId ())
        continue;
      CT_InitDeclarator *init_decl = (CT_InitDeclarator*)dlist->Son (s);
      CObjectInfo *obj = init_decl->SemObject ()->Object ();
      
      // if this object is a typedef, nothing is of interest here
      if (obj->TypedefInfo ())
        break;

      // replace comma with semi colon
      if (init_decls > 0) {
        // replace the "," of the init declarator list with ";" if needed
        CTree *comma = dlist->Son (s - 1);
        const WeavePos &from = weave_pos (comma->token (), WeavePos::WP_BEFORE);
        const WeavePos &to   = weave_pos (comma->token (), WeavePos::WP_AFTER);
        replace (from, to, ";");
      }      

      // only non-static arrays are to be wrapped
      if (obj->TypeInfo ()->TypeArray () && !obj->isStatic ()) {
        // it is a non-static array
      
        // generate the code of the wrapper class
        ostringstream wrapper_class_code;
        gen_wrapped_array (wrapper_class_code, obj);

        // replace the original init declarator with the wrapper object decl
        const WeavePos &from =
          weave_pos (init_decl->token (), WeavePos::WP_BEFORE);
        const WeavePos &to =
          weave_pos (init_decl->end_token (), WeavePos::WP_AFTER);
        replace (from, to, wrapper_class_code.str ());
        
        // if this is the first init declarator, remove the decl spec seq
        if (init_decls == 0)
          del_decl_specs = true;
      }
      else {
        // it is no array; copy the declaration specifier list
        if (decl_specs && decl_specs->token () && init_decls > 0) {
          const WeavePos &inspos =
            weave_pos (init_decl->token (), WeavePos::WP_BEFORE);
          copy (decl_specs, inspos);
          paste (inspos, " ");
        }
      }
      
      // this was an init declarator and not a comma
      init_decls++;
    }
    
    // delete the decl specs
    if (del_decl_specs && decl_specs && decl_specs->token ())
      kill (decl_specs);
  }
}

void CodeWeaver::gen_wrapped_array (ostream &out, CObjectInfo *obj) {
  assert (obj->TypeInfo ()->TypeArray ());
  CTypeArray *t_array = obj->TypeInfo ()->TypeArray ();
  out << endl;
  out << "  struct ";

  // generate name to satisfy VC++ 2002
  out << "__ac_wrapper_" << obj->Name ();
  
  out << " {" << endl;
  out << "    typedef ";
  t_array->BaseType ()->TypeText (out, "E", true, true);
  out << "; typedef E A[" << t_array->Dimension () << "]; A _data;" << endl;
  out << "    operator A& () { return _data; }" << endl;
  out << "    operator A& () const { return (A&)*(";
  CTypeArray *t_first_array = t_array;
  while (t_first_array->BaseType ()->TypeArray ())
    t_first_array = t_first_array->BaseType ()->TypeArray ();
  t_first_array->BaseType ()->TypeText (out, "*", true, true);
  out << ")_data; }" << endl;
  out << "    operator const A& () { return _data; }" << endl;
  out << "    operator const A& () const { return _data; }" << endl;
  out << "    operator void* () { return _data; }" << endl;
  out << "    operator void* () const { return (void*)_data; }" << endl;
  out << "    operator const void* () { return _data; }" << endl;
  out << "    operator const void* () const { return _data; }" << endl;
  out << "    template <typename I> E& operator [] (I i) "
      << "{ return _data[i]; } // for VC++ 2003" << endl;
  out << "    template <typename I> const E& operator [] (I i) const "
      << "{ return _data[i]; } // for VC++ 2003" << endl;
  out << "  } " << obj->Name () << ends;
}

void CodeWeaver::exec_join_point (JPL_Method *loc, JPP_Code &plan) {
  wrap_function (loc, plan);
}
  
void CodeWeaver::wrap_function (JPL_Code *loc, JPP_Code &plan) {
  _code_plan = &plan;
  
  CFunctionInfo *func = loc->assoc_obj ()->DefObject ()->FunctionInfo ();
  assert (func);

  // handle each declaration and the optional definition separately
  // every object info is stored in a cyclic list
  CFunctionInfo *def = 0;
  bool wrapped_decl = false;
  CFunctionInfo *curr = func;
  do {
    if (curr->isFctDef ())
      def = curr;
    else {
      if (wrap_function_decl (loc, curr))
        wrapped_decl = true;
    }
    curr = curr->NextObject ()->FunctionInfo ();
  }
  while (curr != func);
  
  // if a definition has been found, wrap it
  if (def)
    wrap_function_def (loc, def, wrapped_decl);
}

// create a new function implementation and paste it behind the original
void CodeWeaver::wrap_function_def (JPL_Code *loc, CFunctionInfo *func,
  bool wrapped_decl) {

  CT_FctDef *fctdef = (CT_FctDef*)func->Tree ();
  JPAdvice *ejpa = _code_plan->jp_advice ();
  ostringstream pre_sig, pre_body;
  
  bool have_pre_sig = false;
  pre_sig << endl;

  // the first is the declaration of the inner function (the original)
  // not necessary for methods and if there is a declaration anyway
  if (!func->isMethod () && !wrapped_decl) {
    have_pre_sig = true;
    pre_sig << loc->wrapper_function_signature (func, true) << ";" << endl;
  }
  
  // generate the JoinPoint class
  ejpa->mergeTJPFlags();
  if (ejpa->tjp ().type_needed ()) {
    have_pre_sig = true;
    if (fctdef->Linkage () && fctdef->Linkage ()->isList ())
      pre_sig << "}" << endl << endl;
    make_tjp_struct(pre_sig, loc, ejpa);
    if (fctdef->Linkage () && fctdef->Linkage ()->isList ())
      pre_sig << endl << "extern \"C\" {" << endl;
  }

  // paste pre-signature code in front of the old function signature
  if (have_pre_sig) { // check only for better readability
    Token *pre_sig_token = linkage_adjust (fctdef)->token ();
    paste (weave_pos (pre_sig_token, WeavePos::WP_BEFORE), pre_sig.str ());
  }
  
  // rename the arguments of the original declaration
  rename_args (func, "arg");

  // generate the body of the wrapper function
  CTypeFunction *ftype = func->TypeInfo ()->TypeFunction ();
  CTypeInfo *result_type = func->isConversion () ?
    func->ConversionType () : ftype->BaseType ();

  pre_body << "{" << endl;
  
  // declare the result object
  make_result_declaration(pre_body, result_type);

  // generate common JoinPoint initialization
  make_tjp_common_init(pre_body, loc, ejpa);
  
  // generate calls to advice code or original function
  make_advice_calls(pre_body, ejpa, loc);

  make_result_return(pre_body, result_type);
  pre_body << endl << "}" << endl;

  // generate the signature of the inner function (the original)
  // special treatment for operator new/delete/new[]/delete[]
  if (func->isMethod () && !func->isStaticMethod () && !needs_this (func))
    pre_body << "static ";
  // add a wrapper function declaration
  pre_body << loc->wrapper_function_signature (func, true);

  // insert the new body and new signature in front of the old body
  paste (weave_pos (fctdef->Body ()->token (), WeavePos::WP_BEFORE),
         pre_body.str ());
}

// create a new declaration for a wrapped function
bool CodeWeaver::wrap_function_decl (JPL_Code *loc, CFunctionInfo *func) {
 
  // first check if this declaration is built-in
  if (func->isBuiltin ())
    return false;
    
  // check if the function declaration belongs to the project
  // if it does not, we cannot insert the wrapper declaration
  Unit *unit = func->SourceInfo ()->SrcUnit ();
  if (!func->ClassDB ()->Project ()->isBelow (unit) &&
      !IntroductionUnit::cast (unit))
    return false;
    
  string inner_decl;
  if (func->ClassScope ())
    inner_decl += "public: ";
  // special treatment for operator new/delete/new[]/delete[]
  if (func->isMethod () && !func->isStaticMethod () && !needs_this (func))
    inner_decl += "static ";
  // add the wrapper function declaration
  inner_decl += loc->wrapper_function_signature (func->FunctionInfo (), false);
  inner_decl += ";";
  // switch to the right protection if needed
  if (func->Protection () != CProtection::PROT_NONE &&
      func->Protection () != CProtection::PROT_PUBLIC)
    inner_decl += protection_string (func->Protection ());
  else
    inner_decl += "\n";
  
  // move the generated declaration in front of the original declaration
  CT_ObjDecl *objdecl = ((CT_InitDeclarator*)func->Tree ())->ObjDecl ();

  // handle extern "C" declarations
  CTree *pos = linkage_adjust (objdecl);
  paste (weave_pos (pos->token (), WeavePos::WP_BEFORE), inner_decl);

  return true;
}


void CodeWeaver::provide_typename (CTree *node) {
  // check for qualified names
  if (node->NodeName () == CT_SimpleName::NodeId ()) {
    CObjectInfo *obj = ((CT_SimpleName*)node)->Object ();
    if (obj && obj->ClassScope () && 
	      strcmp (obj->ClassScope ()->Name (), "JoinPoint") == 0 &&
	      obj->FunctionInfo () && obj->FunctionInfo ()->Arguments () == 0 &&
	      strcmp (obj->Name (), "arg") == 0) {

      paste (weave_pos (node->token (), WeavePos::WP_BEFORE), "template ");
    }
  }
  else if (node->NodeName () == CT_RootQualName::NodeId () ||
           node->NodeName () == CT_QualName::NodeId ()) {
    // this check is a workaround as long as templates are not instantiated
    CT_SimpleName *scp_name = (CT_SimpleName*)((CT_QualName*)node)->Entry (0);
    if (strcmp (scp_name->Text (), "JoinPoint") != 0)
      return;
    // workaround as long as JoinPoint::Arg<N>::Type is not resolved
    if (strcmp (((CT_QualName*)node)->Text (), "Type") == 0 ||
        strcmp (((CT_QualName*)node)->Text (), "ReferredType") == 0) {

      paste (weave_pos (node->token (), WeavePos::WP_BEFORE), "typename ");
    }
    else {
      // replace [::]JoinPoint::(That|Target|Result) with the generated typedef
      if (((CT_QualName*)node)->Entries () >= 2) {
        CT_SimpleName *field = (CT_SimpleName*)((CT_QualName*)node)->Entry (1);
        const char *field_text = field->Text ();
        if (strcmp (field_text, "That") == 0 ||
            strcmp (field_text, "Target") == 0 ||
            strcmp (field_text, "Result") == 0) {
          stringstream field_unit;
          Naming::tjp_typedef (field_unit, field_text);
          field_unit << ends;
          const WeavePos &qname_start =
            weave_pos (node->token (), WeavePos::WP_BEFORE);
          const WeavePos &qname_end =
            weave_pos (field->end_token (), WeavePos::WP_AFTER);
          replace (qname_start, qname_end, field_unit.str ());
        }
      }
    }
  } 
  else {
    // interate through child nodes
    for (int s = 0; s < node->Sons (); s++)
      provide_typename (node->Son (s));
  }
}


void CodeWeaver::provide_tjp (CFunctionInfo *func, ThisJoinPoint &tjp) {
  assert (func->Tree ());
  assert (func->NextObject ()->FunctionInfo () == func);
  
  CT_FctDef *fctdef = (CT_FctDef*)func->Tree ();        

  // if the function needs the type 'JoinPoint' it has to become a template
  // with 'JoinPoint' as template argument
  if (tjp.type_needed ()) {

    paste (weave_pos (fctdef->token (), WeavePos::WP_BEFORE),
           "template<class JoinPoint> ");

    // also generate some typedefs for That, Target, and Result
    // the corresponding typedef must replace each JoinPoint::XXX
    ostringstream typedefs;
    typedefs << endl;
    typedefs << "  typedef typename JoinPoint::That ";
    Naming::tjp_typedef (typedefs, "That");
    typedefs << ";" << endl;
    typedefs << "  typedef typename JoinPoint::Target ";
    Naming::tjp_typedef (typedefs, "Target");
    typedefs << ";" << endl;
    typedefs << "  typedef typename JoinPoint::Result ";
    Naming::tjp_typedef (typedefs, "Result");
    typedefs << ";" << endl;
    typedefs << ends;
    paste (weave_pos (fctdef->Body ()->token (), WeavePos::WP_AFTER),
           typedefs.str ());
  }
  
  // if a pointer 'tjp' is needed, there has to be an additional argument
  if (tjp.pointer_needed ()) {
    CT_Declarator *last_declarator;
    ((CT_Declarator*)fctdef->Declarator ())->Name (last_declarator);
    CTree *arg_tree = ((CT_FctDeclarator*)last_declarator)->Arguments ();
    ostringstream args;
    args << "JoinPoint *tjp";
    if (func->Arguments () > 0)
      args << ", ";
    args << ends;
    paste (weave_pos (arg_tree->token (), WeavePos::WP_AFTER), args.str ());
  }
  
  // if an alias 'thisJoinPoint' is needed, we must create one
  if (tjp.pointer_alias_needed ()) {
    paste (weave_pos (fctdef->Body ()->token (), WeavePos::WP_AFTER),
           "\n  JoinPoint *&thisJoinPoint = tjp;\n");
  }
  
  // insert 'typename' in front of JoinPoint::That, Target, ...
  provide_typename (fctdef->Body ());
}


void CodeWeaver::make_advice_call(ostream &out, JoinPointLoc *loc, 
				                          AdviceInfo *ai, bool inter, int depth) {

  CFunctionInfo *srcfunc, *dstfunc;
  const char *srcthis_name = "srcthis";
  
  if (loc->type () == JoinPointLoc::Method ||
      loc->type () == JoinPointLoc::Construction ||
      loc->type () == JoinPointLoc::Destruction) {
    srcfunc = loc->assoc_obj ()->DefObject ()->FunctionInfo ();
    dstfunc = 0;
    if (!inter)
      srcthis_name = "this";
  }
  else if (loc->type () == JoinPointLoc::MethodCall) {
    srcfunc = ((JPL_MethodCall*)loc)->caller ();
    dstfunc = ((JPL_MethodCall*)loc)->called ();
  }
  else {
    out << "// invalid join point type in make_advice_call" << endl;
    return; // should never happen
  }

  PointCut &pc = ai->pointcut ();
  PointCut::iterator jp_iter = pc.find (loc);
  assert (jp_iter != pc.end ());
  const JoinPoint &jp = *jp_iter;

  if (jp.condition ()) {
    out << "  if(";
    jp.condition ().gen_check (out, ai, srcthis_name);
    out << ") {" << endl;
  }

  // make the advice call itself
  stringstream tjp_tp;
  Naming::tjp_struct (tjp_tp, jp.location (), depth);
  tjp_tp << ends;
   
  stringstream tjp_obj;
  if (inter)
    tjp_obj << "this";
  else {
    tjp_obj << "&";
    Naming::tjp_instance (tjp_obj, jp.location ());
  }
  tjp_obj << ends;
   
  out << "  ";
  ai->gen_invocation_func_call (out, tjp_tp.str ().data (),
                                tjp_obj.str ().data ());
  out << endl;

  if (jp.condition ()) {
    out << "  }" << endl;
    if (ai->type () == ADVICE_AROUND) {
      out << "  else {" << endl << "    ";
      if (inter)
        out << tjp_tp.str ().data () << "::";
      else {
        Naming::tjp_instance(out, loc);
        out << ".";
      }
      out << "proceed ();" << endl << "  }" << endl;
    }
  }
}


void CodeWeaver::make_advice_calls (ostream &out, JPAdvice *jpa,
                                    JoinPointLoc *loc, bool inter) {
  for (int i = 0; i < jpa->before (); i++)
    make_advice_call (out, loc, jpa->before (i), inter, jpa->depth ());
  
  if (jpa->around ())
    make_advice_call (out, loc, jpa->around (), inter, jpa->depth ());
  else
    make_proceed_code (out, loc, inter, jpa->max_depth ());

  for (int i = 0; i < jpa->after (); i++)
    make_advice_call (out, loc, jpa->after (i), inter, jpa->depth ());
}


// this function weaves the invocation code for a tree of advice functions
// at a call join point
void CodeWeaver::call_join_point (JPL_MethodCall *loc, JPP_Code &plan) {
  // determine the weaving parameters
  bool local_class = (!_problems._local_class && !loc->in_member_init () &&
                      loc->needs_rights ());
  
  _code_plan = &plan;
  
  JPAdvice *cjpa = plan.jp_advice ();
  CObjectInfo *srcobj = loc->assoc_obj();
  CFunctionInfo *srcfunc = srcobj->FunctionInfo ();
  CFunctionInfo *dstfunc = loc->called();
  CTypeInfo *tdstfunc = dstfunc->TypeInfo()->TypeFunction();

  // generate and insert a forward declaration for the target function if needed
  if (srcfunc && srcfunc == dstfunc && !dstfunc->isMethod () &&
      dstfunc->NextObject () == dstfunc) {
    // TODO: a forward declaration has to be generated and default argument
    //       initializers have to be moved into the forward declaration
//    cout << "FORWARD" << endl;
  }
  
  // generate and insert the JoinPoint class
  cjpa->mergeTJPFlags();
  if (cjpa->tjp ().type_needed ()) {
    ostringstream tjp;
    make_tjp_struct (tjp, loc, cjpa);
    tjp << ends;
    // insert the definition
    const WeavePos &pos =
      weave_pos(loc->insertloc_tjp_struct (), WeavePos::WP_BEFORE);
    paste (pos, tjp.str ());
  }
  
  // generate replacement function for dstfunc
  ostringstream code;
  code << endl;

  // if this call is in a function body we generate a local call wrapper class
  if (local_class) {
    code << endl;
    code << "struct ";
    Naming::call_wrapper (code, loc, cjpa->depth ());
    code << " {" << endl;
  }

  // if the lexical scope in which the associated object of the call was
  // defined is a class scope (not global or namespace) the function definition
  // has to be preceded by a 'static' keyword to avoid an implicit 'this'.
  if (local_class || srcobj->Scope ()->ClassInfo ())
      code << "static ";
  code << "inline ";

  stringstream sig;
  stringstream new_call;
  stringstream asig;
  stringstream impl;

  if (local_class)
    sig << "invoke";
  else
    Naming::call_wrapper (sig, loc, cjpa->depth ());
  sig << " (";
  Naming::call_wrapper (new_call, loc, cjpa->depth ());
  if (local_class)
    new_call << "::invoke";
  new_call << " (";
  
  unsigned argnum = 0;
  bool havesrcthis = srcfunc && needs_this (srcfunc);
  bool havedstthis = needs_this (dstfunc);
  bool havefuncptr = (loc->needs_rights () &&
                     (!local_class || cjpa->depth () > 0));  

  const char *calltype = loc->CallExprNode ()->Son(0)->NodeName ();

  // source and destination this pointer arguments (if needed)
  if (havesrcthis) {
    sig << "::" << cscope (srcfunc)->QualName() << " *srcthis";
    new_call << "(::" << cscope (srcfunc)->QualName() << "*)this";
    argnum++;
  }

  if (havefuncptr) {
    if (argnum) {
      sig << ", ";
      new_call << ", ";
    }
    CClassInfo *srccls = cscope (srcfunc);
    CClassInfo *dstcls = cscope (dstfunc);
    bool in_derived =
      (srccls && dstcls && dstcls->isDerivedClass (srccls, true));
    if (in_derived)
      CTypePointer (srcfunc->TypeInfo ()).TypeText (sig, "fptr", true, true);
    else
      CTypePointer (dstfunc->TypeInfo ()).TypeText (sig, "fptr", true, true);
    new_call << "&::";
    if (dstfunc->isClassMember ()) {
      if (in_derived)
        new_call << srccls->QualName ();
      else
        new_call << dstfunc->Record ()->QualName ();
      new_call << "::" << dstfunc->Name ();
    }
    else
      new_call << dstfunc->QualName ();
    argnum++;
  }
  
  // analyse the target object of this call
  bool target_is_ptr;
  CT_Expression *target_expr = loc->target_expr (target_is_ptr);

  if (havedstthis) {
    if (argnum) {
      sig << ", ";
    }
    // TODO: the sig and new_call types must be checked. It is important
    // to have the type of the object, not the scope of the target function
    if (target_expr) {
      CTypeInfo *target_type = target_expr->Type ();
      while (target_type->TypeAddress ())
        target_type = target_type->BaseType ();
      target_type->TypeText (sig, target_is_ptr ? "dstthis" : " *dstthis",
                             true, true);
    }
    else
      sig << "::" << cscope (srcfunc)->QualName() << " *dstthis";
        
  // move/paste the target object pointer
    if (havesrcthis || havefuncptr)
      new_call << ",";
    if (target_expr) {
//      new_call << "(::" << cscope (dstfunc)->QualName() << "*)";
      if (!target_is_ptr)
        new_call << "&(";
    }
    else {
      new_call << "(::" << cscope (srcfunc)->QualName() << "*)this";
    }

    argnum++;
  }

  // argument list
  for (int a = 0 ; a < loc->arg_count (); a++) {
    if (argnum > 0)
    sig << ", ";
    stringstream arg_name;
    arg_name << "arg" << a << ends;
    CTypeInfo *type = loc->arg_type (a).type_info ();
    type->TypeText (sig, arg_name.str ().data (), true, true);
    argnum++;
  }
//  replacement_fct_args (sig, dstfunc, true, true);

  sig << ")" << ends;
  new_call << ends;
  
  // add result type
  CTypeInfo *result_type = dstfunc->isConversion () ? 
    dstfunc->ConversionType () : tdstfunc->BaseType ();
  result_type->TypeText(code, sig.str ().data (), true, true);

  // replacement function body
  code << "{" << endl;

  // declare the result store
  make_result_declaration(code, result_type);

  // generate common JoinPoint initialization
  make_tjp_common_init(code, loc, cjpa);

  // add calls to advice code
  make_advice_calls(code, cjpa, loc);

  make_result_return(code, result_type);

  code << " }" << endl;

  if (local_class) {
    code << "};" << endl;
  }

  code << ends;

  // now we perform the code manipulation

  // insert the call wrapper body
  if (local_class) {
    // opening "{"
    Token *inspos = ((CT_FctDef*)srcfunc->Tree ())->Body ()->token ();
    paste (weave_pos (inspos, WeavePos::WP_AFTER), code.str ());
  }
  else {
    CTree *pos;
    if (srcfunc) {
      CT_FctDef *fctdef = (CT_FctDef*)srcfunc->Tree ();
      pos = linkage_adjust (fctdef);
    }
    else
      pos = ((CT_InitDeclarator*)srcobj->Tree ())->ObjDecl ();
    paste (weave_pos (pos->token (), WeavePos::WP_BEFORE), code.str ());
  }

  // replace call with call to replacement function

  // paste the first (generated) part of the call (in front)
  paste (weave_pos (loc->CallExprNode ()->token (), WeavePos::WP_BEFORE),
         new_call.str ());
  
  // paste a closing bracket behind the call
  paste (weave_pos (loc->CallExprNode ()->end_token (), WeavePos::WP_AFTER),
         ")");
  
  // provide the other arguments

  CTree *node;
  // the destination function is a conversion function
  if (dstfunc->isConversion ()) {
    node = target_expr;
    assert (node);
    paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ")");
  }
  // call was a binary operator call
  else if (calltype == CT_BinaryExpr::NodeId ()) {
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (0);
    if (target_expr) {
      if (!target_is_ptr)
        paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ")");
    }
    else if ((havesrcthis || havefuncptr) && !havedstthis)
      paste (weave_pos (node->token (), WeavePos::WP_BEFORE), ",");
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (1);
    paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ",");
    kill (node);
  }
  // call was a unary operator call
  else if (calltype == CT_UnaryExpr::NodeId ()) {
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (0);
    kill (node);
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (1);
    if (target_expr) {
      if (!target_is_ptr)
        paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ")");
    }
    else if ((havesrcthis || havefuncptr) && !havedstthis)
      paste (weave_pos (node->token (), WeavePos::WP_BEFORE), ",");
  }
  // call was a postfix operator call
  else if (calltype == CT_PostfixExpr::NodeId ()) {
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (1);
    kill (node);
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (0);
    if (strcmp (dstfunc->Name (), "operator ++") == 0 ||
        strcmp (dstfunc->Name (), "operator --") == 0)
      paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ", 0");
    if (target_expr && !target_is_ptr)
      paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ")");
  }
  // call was an index operator call
  else if (calltype == CT_IndexExpr::NodeId ()) {
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (0);
    if (target_expr && !target_is_ptr)
      paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ")");
    // replace the opening '[' with ','
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (1);
    paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ",");
    kill (node);
    // delete the closing ']'
    node = ((CT_BinaryExpr*)loc->CallExprNode ()->Son (0))->Son (3);
    kill (node);
  }
  // call was an ordinary function call
  else {    
    if ((target_expr && !target_is_ptr) &&
         (calltype == CT_MembRefExpr::NodeId () ||
          calltype == CT_MembPtrExpr::NodeId ())) {
      node = loc->CallExprNode ()->Son (0);
      paste (weave_pos (node->end_token (), WeavePos::WP_AFTER), ")");
    }
    if (calltype == CT_MembRefExpr::NodeId () && havedstthis) {
      kill (((CT_MembRefExpr*)loc->CallExprNode ()->Son (0))->Son (1));
      kill (((CT_MembRefExpr*)loc->CallExprNode ()->Son (0))->Son (2));
    }
    else if (calltype == CT_MembPtrExpr::NodeId () && havedstthis) {
      kill (((CT_MembPtrExpr*)loc->CallExprNode ()->Son (0))->Son (1));
      kill (((CT_MembPtrExpr*)loc->CallExprNode ()->Son (0))->Son (2));
    }
    else
      kill (loc->CallExprNode ()->Son (0));
    CT_ExprList *args = loc->CallExprNode ()->Arguments ();
    if (!args) {
      _err << sev_warning << loc->CallExprNode ()->token ()->location ()
	   << "unsupported kind of call, cannot weave advice code"
	   << endMessage;
      return;
    }
    if (args->Entries () > 0 && (havedstthis|| havesrcthis || havefuncptr))
      paste (weave_pos (args->token (), WeavePos::WP_BEFORE), ",");
    kill (args->Son (0));
    kill (args->Son (args->Sons () - 1));
  }
}
