libs/EDoc/Dictionary.cpp

Go to the documentation of this file.
00001 #warning "@@@Brendon Document the AddException function and friends that we just added."
00002 #warning "@@@Brendon Document the Function::on_processed members"
00003 /*******************************************************************************
00004 
00005    Copyright (C) 2007 by Brendon Costa
00006 
00007    This library is free software; you can redistribute it and/or modify 
00008    it under the terms of the "LGPL Like" License defined in the file COPYING 
00009    that should have been distributed along with this source.
00010 
00011    This library is distributed in the hope that it will be useful, 
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of 
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00014 
00015    You should have received a copy of the "LGPL Like" License 
00016    along with this library; see the file COPYING. if not, it can be 
00017    obtained from the EDoc++ website: 
00018    http://edoc.sourceforge.net/license.html
00019 
00020 *******************************************************************************/
00021 #include "config.h"
00022 
00023 #include "EDoc/Dictionary.h"
00024 #include "EDoc/Type.h"
00025 #include "EDoc/Function.h"
00026 #include "EDoc/FunctionType.h"
00027 #include "EDoc/File.h"
00028 #include "EDoc/PersistenceIFace.h"
00029 #include "EDoc/exceptions.h"
00030 #include "EDoc/Logger.h"
00031 #include "EDoc/utils.h"
00032 #include "EDoc/PStack.h"
00033 #include "EDoc/StackRef.h"
00034 #include "EDoc/NotificationIFace.h"
00035 #include "EDoc/TranslationUnit.h"
00036 
00037 #include "EDoc/persistence_data.h"
00038 #include "IndexedDictionary.h"
00039 
00040 #include <iomanip>
00041 #include <set>
00042 #include <algorithm>
00043 
00044 //===========================================================================
00045 /** \brief define a small macro that is called upon a merge error.
00046  */
00047 #define EDOC_MERGE_ERROR(Message) \
00048    EDOC_Error(Message); \
00049    EDOC_THROW_EXCEPTION(MergeException, "Failed merging dictionary.", Message);
00050 
00051 
00052 namespace EDoc
00053 {
00054    //==========================================================================
00055    /** \brief Returns true if the callgraph complexity of left is less than 
00056     * that of right.
00057     *
00058     * Complexity is defined by the following in order of precedence:
00059     *
00060     *    - Total number of unique calls to other functions 
00061     *       (Function::total_calls)
00062     *    - Functions part of circular callgraphs are more complex than 
00063     *       those that are not.
00064     *    - Functions part of circular callgraphs with more members in it
00065     *       are more complex than those that are not.
00066     *    - Finally we use the memory address of the circular set to order
00067     *       so that members in the same circular callgraph are next to 
00068     *       each other.
00069     *    .
00070     */
00071    static bool LessThanCallComplexity(const Function* left, 
00072       const Function* right)
00073    {
00074       // If total calls differs, then use that to determine order.
00075       if (left->total_calls != right->total_calls)
00076       {
00077          return left->total_calls < right->total_calls;
00078       }
00079       
00080       // If same number of unique calls, then order based on
00081       // circular callgraphs being "more complex" than others.
00082       
00083       // If the circular instances are both NULL OR both the same
00084       // then we are the same complexity.
00085       if (left->circular == right->circular)
00086       {
00087          return false;
00088       }
00089       
00090       // If one is circular and the other is not, then the one
00091       // that is not is less complex.
00092       if (!left->circular && right->circular)
00093       {
00094          return true;
00095       }
00096       else if (left->circular && !right->circular)
00097       {
00098          return false;
00099       }
00100 
00101       // Otherwise we have two functions both with the same total_calls
00102       // both in circular callgraphs, but both in different circles.
00103       
00104       // Will say circle with more members is more complex.
00105       if (left->circular->size() != right->circular->size())
00106       {
00107          return left->circular->size() < right->circular->size();
00108       }
00109       
00110       // If they are in different circles but both circles have the
00111       // same number of items in the circles, then we will just
00112       // sort based on the pointer address so that members in the
00113       // same circle are next to each other.
00114       return (uintptr_t)left->circular < (uintptr_t)right->circular;
00115    }
00116 
00117    //===========================================================================
00118    /** \brief 
00119     */
00120    static void AddRethrow(
00121       std::list<PropogatingException>& exceptions, 
00122       PropogatingException& exception,
00123       FunctionLoc& fcall,
00124       std::list<PropogatingException>& poss_curr_catch_types)
00125    {
00126       // We can "rethrow" one of any of the current possible catch type 
00127       // exceptions.
00128       EDOC_FOREACH(PropExcepList, it, poss_curr_catch_types)
00129       {
00130          // If fcall defines a "possible" rethrow OR
00131          // the pcct exception is a "possible" exception, then the resulting
00132          // exception is also not definite. 
00133          // I.e. 
00134          // It "may or may not be rethrown" (fcall.possible)
00135          // OR
00136          // It "may or may-not have propogated to this function through some
00137          // function pointer or virtual function call in the first place"
00138          // (it->possible).
00139          bool possible = fcall.possible | it->possible;
00140          
00141          // If exception we are re-throwing is not visible, then the result is
00142          // not visible. 
00143          // Likewise if the "rethrow" is not visible, then neithre is the
00144          // result.
00145          bool visible = exception.visible & it->visible;
00146          
00147          // For the exception being rethrown see if we already have 
00148          // an item in our list for it.
00149          PropogatingException* pe = NULL;
00150          EDOC_FOREACH(PropExcepList, jt, exceptions)
00151          {
00152             if (*jt == *it)
00153             {
00154                pe = &*jt;
00155                break;
00156             }
00157          }
00158 
00159          // If no item in our list for it then add one.
00160          if (!pe)
00161          {
00162             exceptions.push_back(*it);
00163             pe = &exceptions.back();
00164             pe->possible = possible;
00165             pe->visible = it->visible;
00166          }
00167          else
00168          {
00169             // If we have this exception in the list already,
00170             // then it is only going to result in a "possible" exception if both
00171             // the existing one in the list and the new one are both "possible".
00172             if (it->possible)
00173             {
00174                pe->possible = possible;
00175             }
00176             
00177             // result is only "invisible" if both item in list is invisible, and
00178             // new item is invisible.
00179             if (!it->visible)
00180             {
00181                pe->visible = visible;
00182             }
00183          }
00184          
00185 
00186          // Mark that the exception may be rethrown here.
00187          EDOC_Fine("Adding rethrow to exception: " 
00188             << pe->exception->type.value->GetDeclaredName());
00189          pe->rethrows.push_back(exception.exception);
00190       }
00191    }
00192 
00193    //===========================================================================
00194    /** \brief 
00195     */
00196    // exceptions : the current list of exceptions propogating from a function
00197    // fcall : The call to a function which resulted in the exception
00198    // exception : The exception belonging to function pointer to by fcall that
00199    //             we want to add to our list
00200    // poss_curr_catch_types : A list of exceptions that have been caught and are
00201    static inline bool AddPException(
00202       Dictionary& dict,
00203       std::list<PropogatingException>& exceptions, 
00204       PropogatingException& exception,
00205       FunctionLoc& fcall,
00206       std::list<PropogatingException>& poss_curr_catch_types)
00207    {
00208       // Specially handle the rethrow "..." case when we have a list of 
00209       // poss_curr_catch_types that can BE 'rethrown".
00210       if ((exception.exception->type.value->GetDeclaredName() == "...") &&
00211          poss_curr_catch_types.size())
00212       {
00213          AddRethrow(exceptions, exception, fcall, poss_curr_catch_types);
00214          return true;
00215       }
00216       
00217       // Otherwise if is a rethrow and nothing in catch list OR is any
00218       // exception other than a rethrow, then we will add the exception
00219       // to the list if it is not already in it.
00220       
00221       // First construct the propogating exception object for our list
00222       // from the one belonging to function pointer to by fcall.
00223       PropogatingException pe(dict, exception.exception, fcall);
00224       
00225       // If fcall is possible OR exception is possible, then this new 
00226       // exception should also be possible.
00227       pe.possible = fcall.possible | exception.possible;
00228       
00229       // Visibility porpogates only from the exception we are propogating.
00230       pe.visible = exception.visible;
00231       
00232 
00233       // See if the exception already exists in the list (Note: Exceptions
00234       // thrown from different locations or as a result of different function
00235       // calls are considered as different exceptions.)
00236       EDOC_FOREACH(PropExcepList, it, exceptions)
00237       {
00238          if (*it == pe)
00239          {
00240             EDOC_Finer("Exception already exists: " 
00241                << pe.exception->type.value->GetDeclaredName());
00242             
00243             // If we have this exception in the list already,
00244             // then it is only going to result in a "possible" exception if both
00245             // the existing one in the list and the new one are both "possible".
00246             if (it->possible)
00247             {
00248                it->possible = pe.possible;
00249             }
00250             
00251             if (!it->visible)
00252             {
00253                it->visible = pe.visible;
00254             }
00255             return false;
00256          }
00257       }
00258       
00259       EDOC_Fine("Adding new exception: " 
00260          << pe.exception->type.value->GetDeclaredName());
00261       exceptions.push_back(pe);
00262       return true;
00263    }
00264    
00265    
00266    //===========================================================================
00267    /** \brief 
00268     */
00269    static inline bool AddOException(
00270       Dictionary& dict,
00271       std::list<PropogatingException>& exceptions, 
00272       Exception& exception,
00273       std::list<PropogatingException>& poss_curr_catch_types)
00274    {
00275       // An originating exception is handled basically the same as a propogating
00276       // exception, except:
00277       //
00278       //    - The function call location is undefined
00279       //    - The function called to produce the exception is NULL
00280       //    - The cause is never a "possible" call giving rise to a "possible"
00281       //          exception
00282       //    - The cause is always visible, so never giving rise to an
00283       //       "invisible" propogating exception.
00284       
00285       // So we just create a "dummy" propogating exception to use for this
00286       // and call the propogating exception implementation.
00287       FunctionLoc dummy_fcall(dict, NULL, *dict.UNKNOWN_LOCATION);
00288       PropogatingException dummy_pe(dict, &exception, dummy_fcall);
00289       
00290       return AddPException(dict, exceptions, dummy_pe, dummy_fcall, 
00291          poss_curr_catch_types);
00292    }
00293 
00294 
00295    //===========================================================================
00296    /** \brief
00297     */
00298    static bool AddExceptions(
00299       std::list<PropogatingException>& exceptions, 
00300       std::list<PropogatingException>& add)
00301    {
00302       size_t added = 0;
00303       
00304       // For each exception in add:
00305       //    1) add it to exceptions if it is not already in there.
00306       //    2) if it is in there then append to its rethrows list the contents 
00307       //       of our rethrows list.
00308       EDOC_FOREACH(PropExcepList, it, add)
00309       {
00310          PropExcepList::iterator s = std::find(exceptions.begin(),
00311             exceptions.end(), *it);
00312          if (s != exceptions.end())
00313          {
00314             AppendUnique(s->rethrows, it->rethrows);
00315          }
00316          else
00317          {
00318             added++;
00319             exceptions.push_back(*it);
00320          }
00321       }
00322       return added;
00323    }
00324    //===========================================================================
00325 
00326 
00327 
00328 
00329 
00330    //===========================================================================
00331    static Dictionary* current = NULL;
00332    //===========================================================================
00333    Dictionary* GetCurrentDictionary()
00334    {
00335       return current;
00336    }
00337    //===========================================================================
00338    Dictionary* GetCurrentDictionaryAssert()
00339    {
00340       EDOC_ASSERT(current, "");
00341       return current;
00342    }
00343    //===========================================================================
00344    void SetCurrentDictionary(Dictionary* current_in)
00345    {
00346       current = current_in;
00347    }
00348    //===========================================================================
00349    Dictionary::Dictionary() :
00350       //CURRENT_EXCEPTION_TYPE(NULL),
00351       UNKNOWN_FILE(NULL),
00352       UNKNOWN_LOCATION(NULL),
00353       SUBSTITUTION_EXCEPTION_TYPE(NULL),
00354       files(*this),
00355       types(*this),
00356       function_types(*this),
00357       functions(*this)
00358    {
00359       GeneratePredefined();
00360    }
00361    //===========================================================================
00362    Dictionary::~Dictionary()
00363    {
00364       // We own the memory for the types and functions. So delete it now.
00365       EraseAll();
00366    }
00367    //===========================================================================
00368    void Dictionary::EraseAll()
00369    {
00370       MngObjPList objs = GetManagedObjects();
00371       EDOC_FOREACH(MngObjPList, it, objs)
00372       {
00373          (*it)->EraseAll();
00374       }
00375       
00376       //delete SUBSTITUTION_EXCEPTION_TYPE;
00377       SUBSTITUTION_EXCEPTION_TYPE = NULL;
00378 
00379       delete UNKNOWN_LOCATION;
00380       UNKNOWN_LOCATION = NULL;
00381 
00382       //delete UNKNOWN_FILE;
00383       UNKNOWN_FILE = NULL;
00384    }
00385    //===========================================================================
00386    void Dictionary::GeneratePredefined()
00387    {
00388       if (!UNKNOWN_FILE)
00389       {
00390          // First check to see if the "" file already exists and use that if so.
00391          File* file = files.AlwaysGet("");
00392          if (!file->IsPopulated())
00393          {
00394             file->key_name = "";
00395             file->index = -1;
00396 
00397             file->populated = true;
00398          }
00399          UNKNOWN_FILE = file;
00400       }
00401       
00402       if (!UNKNOWN_LOCATION)
00403       {
00404          UNKNOWN_LOCATION = new Location(this);
00405       }
00406 
00407       if (!SUBSTITUTION_EXCEPTION_TYPE)
00408       {
00409          Type* type = types.AlwaysGet("....");
00410          if (!type->IsPopulated())
00411          {
00412             type->name = "....";
00413             type->index = -1;
00414             type->external_linkage = false;
00415             type->translation_unit = TranslationUnit::GetUnknown();
00416             type->throw_type = type;
00417             type->root_type = type;
00418             
00419             // No other types are identical.
00420             // No other types (except ...) can be used to catch this type.
00421             type->loc = *UNKNOWN_LOCATION;
00422             type->referenced_in_files.push_back(
00423                const_cast<File*>(UNKNOWN_FILE));
00424             
00425             // This should never be in documentation anyway.
00426             type->visible = true;
00427 
00428             type->populated = true;
00429          }
00430          SUBSTITUTION_EXCEPTION_TYPE = type;
00431       }
00432    }
00433    //===========================================================================
00434    void Dictionary::Read(PersistenceIFace& file)
00435    {
00436       EraseAll();
00437       
00438       IndexedDictionary idict(*this);
00439 
00440       uint8_t record_type = file.ReadRecordType();
00441       if (record_type != VALUE_RECORD_TYPE_HEADER)
00442       {
00443          EDOC_THROW_EXCEPTION(FileIOException, "Invalid record type. "
00444             "Expected: " << (unsigned int)VALUE_RECORD_TYPE_HEADER 
00445             << ", Received: " << (unsigned int)record_type,
00446             "");
00447       }
00448 
00449       uint8_t version = file.ReadUInt8(KEY_EDOC_VERSION);
00450       EDOC_Fine("Version: " << (uint32_t)version);
00451       if (version != EDOC_FILE_VERSION)
00452       {
00453          EDOC_THROW_EXCEPTION(FileIOException, "Mismatching file version.",
00454             "EDoc version: " << PACKAGE_VERSION 
00455             << " can only load .edc files of version: " 
00456             << (unsigned int)EDOC_FILE_VERSION 
00457             << ", failed loading .edc file of version: " 
00458             << (unsigned int)version);
00459       }
00460       
00461       uint32_t size = 0;
00462       size = file.ReadUInt32(KEY_TRANSLATION_UNITS_LS);
00463       translation_units.erase(translation_units.begin(), 
00464          translation_units.end());
00465       for (size_t i = 0; i < size; i++)
00466       {
00467          translation_units.push_back(
00468             TranslationUnit::Create(file.ReadString(KEY_TRANSLATION_UNIT)));
00469       }
00470 
00471       std::vector<ManagedObject*> dict_stages = GetManagedObjectsVector();
00472       std::vector<IndexedObject*> idict_stages = idict.GetManagedObjects();
00473       EDOC_ASSERT(dict_stages.size() == idict_stages.size(), "");
00474       
00475       // Read each record and add it to the dict.
00476       int stage = 0;
00477       bool more_records = true;
00478       while (more_records)
00479       {
00480          try
00481          {
00482             record_type = file.ReadRecordType();
00483          }
00484          catch(EOFException& eofe)
00485          {
00486             // No more records to read.
00487             EDOC_Fine("Finished reading file.");
00488             more_records = false;
00489             break;
00490          }
00491 
00492          // Read the index for this item.
00493          uint32_t index = file.ReadUInt32(KEY_INDEX);
00494 
00495          int rt_stage = 0;
00496          if       (record_type == VALUE_RECORD_TYPE_FILE) rt_stage = 0;
00497          else if  (record_type == VALUE_RECORD_TYPE_TYPE) rt_stage = 1;
00498          else if  (record_type == VALUE_RECORD_TYPE_FUNCTION_TYPE) rt_stage = 2;
00499          else if  (record_type == VALUE_RECORD_TYPE_FUNCTION) rt_stage = 3;
00500          else
00501          {
00502             EDOC_THROW_EXCEPTION(FileIOException, "Invalid record type.", 
00503                "Record Type: " << (unsigned int)record_type);
00504          }
00505 
00506          // Ensure that the records are in the correct order.
00507          if (stage > rt_stage)
00508          {
00509             EDOC_THROW_EXCEPTION(FileIOException, 
00510                "File record found out of order.", "");
00511          }
00512          stage = rt_stage;
00513 
00514 
00515          // Obtain an object and populate it.
00516          EDOC_Finer("Reading record in stage: " << stage);
00517          StringIdentifiedObject* item = idict_stages[stage]->CAlwaysGet(index);
00518          EDOC_ASSERT(!item->IsPopulated(), "")
00519          item->Read(file, idict);
00520 
00521          // See if we already have an instance for it.
00522          EDOC_Finer("Ensuring uniqueness of record and inserting it into "
00523             "the dictionary: " << item->GetKeyName());
00524          if(dict_stages[stage]->CGet(item->GetKeyName()))
00525          {
00526             StringIdentifiedObject* item2 = 
00527                dict_stages[stage]->CGet(item->GetKeyName());
00528 
00529             EDOC_Debug("Item exists. "
00530                "Replacing stub: " << (void*)item2 
00531                << ", with populated: " << (void*)item 
00532                << ", for key: " << item->GetKeyName());
00533 
00534             // Then a file has previously been inserted as a place holder
00535             // based on its name. We will need to erase all references to
00536             // this "stub" and replace them with references to this populated
00537             // file instance.
00538             EDOC_ASSERT(!item2->IsPopulated(), "stage: " << stage 
00539                << ", item: " << item->GetKeyName() 
00540                << " has already been populated. This means there is a "
00541                "duplicate in the .edc file. "
00542                << "Item details: " << item->ToString());
00543 
00544             PStack stack;
00545             size_t replaced = ReplaceReferences(stack, item2, item);
00546             EDOC_ASSERT(replaced, "");
00547             dict_stages[stage]->CRemove(item);
00548             delete item2;
00549          }
00550          EDOC_Debug("Read stage: " << (unsigned int)stage 
00551             << ", item: " << item->GetKeyName());
00552          dict_stages[stage]->CAdd(item);
00553       }
00554 
00555       // Lets look at all the integer keyed instances and ensure that we have
00556       // them in our string keys maps.
00557       // We dont care so much if we have additional instances in our string
00558       // indexed dictionary as long as they have somehow been populated as
00559       // checked in the validate call.
00560       for (size_t i = 0; i < idict_stages.size(); i++)
00561       {
00562          EDOC_FOREACH(StrIDObjPMap, it, dict_stages[i]->items)
00563          {
00564             for (size_t j = 0; j < idict_stages[i]->items.size(); j++)
00565             {
00566                if (it->second == idict_stages[i]->items[j])
00567                {
00568                   idict_stages[i]->items[j] = NULL;
00569                   it->second->index = -1;
00570                }
00571             }
00572          }
00573          
00574          // After setting to NULL the ones we are using in the string indexed
00575          // dictionary. Assert if there are any left over.
00576          for (size_t j = 0; j < idict_stages[i]->items.size(); j++)
00577          {
00578             EDOC_ASSERT(!idict_stages[i]->items[j], 
00579                "Left-over item in indexed dictionary." 
00580                << "\nIndex: " 
00581                << idict_stages[i]->items[j]->index
00582                << "\nKey: " 
00583                << idict_stages[i]->items[j]->key_name);
00584          }
00585       }
00586       
00587       GeneratePredefined();
00588       #ifdef EDOC_ENABLE_VALIDATION
00589       Validate();
00590       #endif // EDOC_ENABLE_VALIDATION
00591    }
00592    //===========================================================================
00593    void Dictionary::Merge(const Dictionary& right)
00594    {
00595       if (&right == this)
00596       {
00597          return;
00598       }
00599 
00600       // Add any translation units from right to our list
00601       EDOC_FOREACH_CONST(TUnitPVec, it, right.translation_units)
00602       {
00603          PushBackUnique(translation_units, *it);
00604       }
00605 
00606       std::vector<ManagedObject*> objs = GetManagedObjectsVector();
00607       std::vector<const ManagedObject*> robjs = right.GetManagedObjectsVector();
00608       EDOC_ASSERT(objs.size() == robjs.size(), "");
00609       
00610       for (size_t i = 0; i < robjs.size(); i++)
00611       {
00612          EDOC_FOREACH_CONST(StrIDObjPMap, it, robjs[i]->items)
00613          {
00614             EDOC_Finer("Merging item: " << it->first);
00615             objs[i]->CAlwaysGet(it->first)->Merge(*it->second);
00616          }
00617       }
00618 
00619       #ifdef EDOC_ENABLE_VALIDATION
00620       Validate();
00621       #endif // EDOC_ENABLE_VALIDATION
00622    }
00623    //===========================================================================
00624    void Dictionary::Validate() const
00625    {
00626       // Ensure the predefined values are generated and correct.
00627       EDOC_ASSERT(UNKNOWN_FILE, "");
00628       EDOC_ASSERT(UNKNOWN_FILE->GetKeyName() == "", "");
00629       EDOC_ASSERT(files.Get(UNKNOWN_FILE->GetKeyName()) == UNKNOWN_FILE, "");
00630 
00631       EDOC_ASSERT(UNKNOWN_LOCATION, "");
00632       EDOC_ASSERT(!(*UNKNOWN_LOCATION), "");
00633 
00634       PStack stack;
00635       // @@@Brendon Update to use the managed object Validate instead of
00636       // accessing its private members directly.
00637       std::vector<const ManagedObject*> objs = GetManagedObjectsVector();
00638       for (size_t i = 0; i < objs.size(); i++)
00639       {
00640          objs[i]->Validate(stack, *this);
00641       }
00642       
00643       // @@@Brendon Any validation required for translation units?
00644    }
00645    //===========================================================================
00646    std::ostream& Dictionary::Print(std::ostream& out, std::string prefix) const
00647    {
00648       std::vector<const ManagedObject*> objs = GetManagedObjectsVector();
00649       for (size_t i = 0; i < objs.size(); i++)
00650       {
00651          objs[i]->Print(out, prefix);
00652       }
00653 
00654       return out;
00655    }
00656    //===========================================================================
00657    std::string Dictionary::ToString(std::string prefix) const
00658    {
00659       std::ostringstream stream;
00660       Print(stream, prefix);
00661       return stream.str();
00662    }
00663    //===========================================================================
00664    void Dictionary::Write(PersistenceIFace& file) const
00665    {
00666       // First we must give all functions and types a unique integer
00667       // identification number.
00668       uint32_t index = 0;
00669       std::vector<const ManagedObject*> objs = GetManagedObjectsVector();
00670       for (size_t i = 0; i < objs.size(); i++)
00671       {
00672          EDOC_FOREACH_CONST(StrIDObjPMap, it, objs[i]->items)
00673          {
00674             // Dont write the subst exception type to file.
00675             // The subst exception should only be used internally.
00676             // So should not be exported to file if an exception
00677             // references it and is exported to file then there is a bug
00678             // in the exception instance.
00679             if (it->second ==
00680                (StringIdentifiedObject*)SUBSTITUTION_EXCEPTION_TYPE)
00681             {
00682                continue;
00683             }
00684             EDOC_Finer("Giving index: " << index << " to item: " << it->first);
00685             it->second->index = index++;
00686             it->second->writing = true;
00687          }
00688       }
00689 
00690       file.WriteRecordType(VALUE_RECORD_TYPE_HEADER);
00691       file.WriteUInt8(KEY_EDOC_VERSION, EDOC_FILE_VERSION);
00692 
00693       file.WriteUInt32(KEY_TRANSLATION_UNITS_LS, translation_units.size());
00694       EDOC_FOREACH_CONST(TUnitPVec, it, translation_units)
00695       {
00696          file.WriteString(KEY_TRANSLATION_UNIT, (*it)->GetName());
00697       }
00698 
00699       for (size_t i = 0; i < objs.size(); i++)
00700       {
00701          // @@@Brendon Move this code into managed object?
00702          EDOC_FOREACH_CONST(StrIDObjPMap, it, objs[i]->items)
00703          {
00704             if (it->second == 
00705                (StringIdentifiedObject*)SUBSTITUTION_EXCEPTION_TYPE)
00706             {
00707                continue;
00708             }
00709             file.WriteRecordType(it->second->GetRecordType());
00710             file.WriteUInt32(KEY_INDEX, it->second->index);
00711             it->second->Write(file);
00712          }
00713       }
00714 
00715       // @@@Brendon This "writing" flag is not really a good idea. 
00716       // Reset the "writing" flag and indexes.
00717       objs = GetManagedObjectsVector();
00718       for (size_t i = 0; i < objs.size(); i++)
00719       {
00720          EDOC_FOREACH_CONST(StrIDObjPMap, it, objs[i]->items)
00721          {
00722             it->second->index = -1;
00723             it->second->writing = false;
00724          }
00725       }
00726    }
00727    //===========================================================================
00728    void Dictionary::ExpandCallGraph()
00729    {
00730       // Ensure that the functions which have had their addresses taken are
00731       // added to their corresponding types.
00732       UpdateFunctionAddressLists();
00733 
00734       // Expand the call graph for each function now that the derived virtuals
00735       // have been calculated.
00736       EDOC_FOREACH(StrIDObjPMap, it, functions.items)
00737       {
00738          dynamic_cast<Function*>(it->second)->ExpandCallGraph();
00739       }
00740       
00741       #ifdef EDOC_ENABLE_VALIDATION
00742       Validate();
00743       #endif // EDOC_ENABLE_VALIDATION
00744    }
00745    //===========================================================================
00746    void Dictionary::UpdateFunctionAddressLists()
00747    {
00748       EDOC_Fine("Cacheing all functions that have had their addresses taken.");
00749 
00750       // For each function type lets first erase its list of functions that have
00751       // had addresses taken.
00752       EDOC_FOREACH(StrIDObjPMap, it, function_types.items)
00753       {
00754          Erase(dynamic_cast<FunctionType*>(it->second)->addressed_functions);
00755          Erase(dynamic_cast<FunctionType*>(it->second)->equivilant);
00756       }
00757 
00758       
00759       // Update the equivilant lists for all function types.
00760       EDOC_FOREACH(StrIDObjPMap, it, function_types.items)
00761       {
00762          EDOC_FOREACH(StrIDObjPMap, it2, function_types.items)
00763          {
00764             if (dynamic_cast<FunctionType*>(it->second)->IsEquivilant(
00765                *dynamic_cast<FunctionType*>(it2->second)))
00766             {
00767                PushBackUnique(dynamic_cast<FunctionType*>(it->second)
00768                   ->equivilant, dynamic_cast<FunctionType*>(it2->second));
00769             }
00770          }
00771       }
00772 
00773 
00774 
00775       // For each function we will see if its address has been taken and if so
00776       // add it to the list for its type.
00777       EDOC_FOREACH(StrIDObjPMap, it, functions.items)
00778       {
00779          Function* func = dynamic_cast<Function*>(it->second);
00780          if (func->address_taken.size())
00781          {
00782             EDOC_Fine("Function: " << func->GetKeyName() 
00783                << " has its address taken and has been cached for type: " 
00784                << func->function_pointer_type->GetKeyName());
00785             
00786             for (size_t i = 0; i < 
00787                func->function_pointer_type->equivilant.size(); i++)
00788             {
00789                PushBackUnique(
00790                   func->function_pointer_type->equivilant[i]
00791                      ->addressed_functions, func);
00792             }
00793          }
00794       }
00795    }
00796    //===========================================================================
00797    // @@@Brendon Instead of doing special iteration over these i should just
00798    // make use of the GetCodeBlocks and use that as i am interested in a flat
00799    // view of it not the structured view.
00800    //===========================================================================
00801    static int CalculateTotalFunctionCalls(std::set<Function*>& processed, 
00802       std::vector<Function*>& curr_stack, 
00803       Function* f);
00804    //===========================================================================
00805    inline static int CalculateTotalFunctionCalls(
00806       std::set<Function*>& processed,
00807       std::vector<Function*>& curr_stack, 
00808       CodeBlock& cb)
00809    {
00810       int total_calls = 0;
00811 
00812       EDOC_FOREACH(FuncLocList, it, cb.function_calls)
00813       {
00814          total_calls += CalculateTotalFunctionCalls(processed, curr_stack, it->value);
00815       }
00816       
00817       EDOC_FOREACH(FuncLocList, it, cb.possible_function_calls)
00818       {
00819          total_calls += CalculateTotalFunctionCalls(processed, curr_stack, it->value);
00820       }
00821       
00822       EDOC_FOREACH(TryBlockList, it, cb.try_blocks)
00823       {
00824          total_calls += CalculateTotalFunctionCalls(processed, 
00825             curr_stack, *(*it).try_block);
00826          
00827          size_t len2 = it->catch_blocks.size();
00828          for (size_t j = 0; j < len2; j++)
00829          {
00830             total_calls += CalculateTotalFunctionCalls(processed, 
00831                curr_stack, *(*it).catch_blocks[j].catch_code);
00832          }
00833       }
00834       
00835       return total_calls;
00836    }
00837    //===========================================================================
00838    static int CalculateTotalFunctionCalls(
00839       std::set<Function*>& processed, 
00840       std::vector<Function*>& curr_stack, 
00841       Function* f)
00842    {
00843       // Note: The +1 is used to simplify the code a little. There is 
00844       // probably a better way to achieve it though. 
00845       //
00846       // It is to include the call to the
00847       // function currently being processed. In the case of the top level
00848       // function this means that there needs to be 1 subtracted from it as is
00849       // done in CalculatePropogatingExceptions()
00850 
00851       // Check to see if we have already included a count for this function
00852       if (processed.count(f))
00853       {
00854          // If we have, then we will not include it again,
00855          // however we will check to see if it is part of a
00856          // circular callgraph (for the top function) by checking to 
00857          // see if it is at the start of the current call stack.
00858          if (curr_stack.size() && *curr_stack.begin() == f)
00859          {
00860             // Then all functions from it to the end of the vector are part
00861             // of a circular callgraph.
00862 
00863             // First see if any of the functions have a circular set yet.
00864             // If so we will use that otherwise we will create one.
00865             std::set<Function*>* circular = NULL;
00866             std::set<std::set<Function*>* > to_merge;
00867             EDOC_FOREACH(std::vector<Function*>, jt, curr_stack)
00868             {
00869                if ((*jt)->circular)
00870                {
00871                   // If this is the first set instance, then 
00872                   // we will assume this is the instance we 
00873                   // will use
00874                   if (!circular)
00875                   {
00876                      circular = (*jt)->circular;
00877                   }
00878                   // If there are two set instances for the same circular
00879                   // function, then we should merge the two sets
00880                   // as they are part of one larger circular callgraph
00881                   else if ((*jt)->circular && circular != (*jt)->circular)
00882                   {
00883                      // Add to list to be merged and deleted
00884                      to_merge.insert((*jt)->circular);
00885                      
00886                      // No longer reference the old set but all 
00887                      // reference the same set now.
00888                      (*jt)->circular = NULL;
00889                   }
00890                }
00891             }
00892 
00893             // Merge contents of multiple "extra" sets into the 
00894             // single one referenced by "circular" and delete the
00895             // old sets that are no longer referenced.
00896             EDOC_FOREACH(std::set<std::set<Function*>* >, jt, to_merge)
00897             {
00898                EDOC_ASSERT(circular != *jt, "");
00899                EDOC_FOREACH(std::set<Function*>, kt, *(*jt))
00900                {
00901                   circular->insert(*kt);
00902                   EDOC_ASSERT((*kt)->circular == NULL || (*kt)->circular == *jt, "");
00903                   (*kt)->circular = NULL;
00904                }
00905                
00906                // delete the "extra" superfluous set.
00907                delete *jt;
00908             }
00909             Erase(to_merge);
00910 
00911             // Create a new circular set if none exists already.
00912             if (!circular)
00913             {
00914                circular = new std::set<Function*>();
00915             }
00916 
00917             // Now we add the items in the curr_stack to the set.
00918             EDOC_FOREACH(std::vector<Function*>, it, curr_stack)
00919             {
00920                circular->insert(*it);
00921             }
00922             
00923             // Finally we will set the circular member for each function
00924             // in the set to reference the single set.
00925             EDOC_FOREACH(std::set<Function*>, jt, *circular)
00926             {
00927                EDOC_ASSERT((*jt)->circular == NULL || (*jt)->circular == circular, "");
00928                (*jt)->circular = circular;
00929             }
00930 
00931             // We have now finished marking this function as part of a circular callgraph.
00932             EDOC_ASSERT(f->circular, "We never explicitly assigned to f->circuit but should have in the loop.");
00933          }
00934 
00935          return 0;
00936       }
00937       
00938       // Add this new function to the call stack and the processed set.
00939       processed.insert(f);
00940       curr_stack.push_back(f);
00941       
00942       // Count the functions that we call.
00943       int ret = CalculateTotalFunctionCalls(processed, curr_stack, f->implementation) + 1;
00944 
00945       // We are "exiting" this function so pop it off the call stack.
00946       EDOC_ASSERT(curr_stack.back() == f, "");
00947       curr_stack.pop_back();
00948       return ret;
00949    }
00950    //===========================================================================
00951 
00952    //===========================================================================
00953    void Dictionary::ErasePropogatingExceptions()
00954    {
00955       // Erase all propogating exception information.
00956       EDOC_FOREACH(StrIDObjPMap, it, functions.items)
00957       {
00958          Erase(dynamic_cast<Function*>(it->second)->propogating_exceptions);
00959          Erase(dynamic_cast<Function*>(it->second)->filtered_exceptions);
00960 
00961 
00962          dynamic_cast<Function*>(it->second)->
00963             calculated_propogating_exceptions = false;
00964          dynamic_cast<Function*>(it->second)->total_calls = -1;
00965          
00966          // Populate the originating exceptions function attribute.
00967          std::list<CodeBlock*> blocks = dynamic_cast<Function*>(
00968             it->second)->implementation.GetAllCodeBlocks();
00969 
00970          EDOC_FOREACH(CodeBlockPList, jt, blocks)
00971          {
00972             EDOC_FOREACH(ExcepList, kt, (*jt)->originating_exceptions)
00973             {
00974                kt->function = dynamic_cast<Function*>(it->second);
00975             }
00976          }
00977       }
00978    }
00979    //===========================================================================
00980    void Dictionary::CalculateCallComplexity(std::vector <Function*>& funcs)
00981    {
00982       // Before we try and calculate the prop exceptions lets try and sort the
00983       // list so that the funcs with the least dependencies are done first. This
00984       // will speed up execution a lot.
00985       
00986       // Classification is made based on hown many functions this function calls
00987       // both directly and indirectly.
00988       
00989       // The higher the count then the later this function is processed as it
00990       // most likely depends on functions that are processed before it. This
00991       // means we have as little "recalculation" as possible.
00992       funcs.resize(functions.items.size());
00993 
00994       EDOC_Debug("Calculating the callgraph complexity for each function.");
00995       size_t count = 0;
00996       EDOC_FOREACH(StrIDObjPMap, it, functions.items)
00997       {
00998          std::set<Function*> processed;
00999          std::vector<Function*> curr_stack;
01000          funcs[count] = dynamic_cast<Function*>(it->second);
01001          funcs[count]->total_calls = CalculateTotalFunctionCalls(
01002             processed, curr_stack, funcs[count]) - 1;
01003          count++;
01004       }
01005       
01006       EDOC_Debug("Sorting list of functions based on their "
01007          "callgraph complexity.");
01008       std::sort(funcs.begin(), funcs.end(), LessThanCallComplexity);
01009       for (size_t i = 0; i < funcs.size(); i++)
01010       {
01011          EDOC_Fine(i << ") calls: " << funcs[i]->total_calls << ": " 
01012             << funcs[i]->GetDeclaredName());
01013       }
01014    }
01015    //===========================================================================
01016    void Dictionary::CalculatePropogatingExceptions(
01017       std::vector <Function*>& sorted, FunctionProgressIFace* progress)
01018    {
01019       if (progress)
01020       {
01021          progress->Start(sorted.size());
01022       }
01023       
01024       // Calculate all propogating exception information from scratch using 
01025       // the now sorted list.
01026       for (size_t i = 0; i < sorted.size(); i++)
01027       {
01028          Function* func = sorted[i];
01029          EDOC_Fine("--------------------------------------------");
01030          EDOC_Fine("Calculating exceptions for function: " 
01031             << func->GetKeyName());
01032          //func->Print(std::cerr);
01033 
01034          // Process the functions callgraph to generate a list of
01035          // propogating exceptions.
01036          bool circular = GenerateExceptions(progress, *func);
01037 
01038          // If this function is in a circular callgraph that has
01039          // not yet been processed, then handle the circular callgraph
01040          // case.
01041          if (circular)
01042          {
01043             HandleCircularCallgraph(progress, *func);
01044          }
01045          
01046          // Now we have a complete list of exceptions, post process them
01047          // filtering out ones that dont match the functions exception 
01048          // spec and emitting warnings as necessary.
01049          PostProcessExceptions(*func);
01050          
01051          if (func->on_processed)
01052          {
01053             func->on_processed(*func, func->on_processed_data);
01054          }
01055       }
01056 
01057       
01058       #ifdef EDOC_ENABLE_VALIDATION
01059       std::cerr << "Checking data..." << std::endl;
01060       Validate();
01061       #endif // EDOC_ENABLE_VALIDATION
01062       return;
01063    }
01064    
01065    //===========================================================================
01066    bool Dictionary::GenerateExceptions(
01067       FunctionProgressIFace* progress, Function& function)
01068    {
01069       // Dont calculate propagating exceptions for a function that has already 
01070       // had it done.
01071       if (function.calculated_propogating_exceptions)
01072       {
01073          return false;
01074       }
01075       
01076       // Notify the user of progress.
01077       if (progress)
01078       {
01079          progress->Progress(&function);
01080       }
01081       
01082       EDOC_Finer("Entering: CalculatePropogatingExceptions");
01083       std::list<PropogatingException> poss_curr_catch_types;
01084 
01085       // @@@Brendon Maybe should not use UNKNOWN location but create a new 
01086       // location called NONE. I.e. this function is not being called but 
01087       // is being used to initiate the trace. So there is NO call location.
01088       FunctionLoc fl(*this, &function, *UNKNOWN_LOCATION);
01089 
01090       // This should be the only place a function loc has a true value for 
01091       // is_top_level
01092       fl.is_top_level = true;
01093       
01094       ProcessFunction(function, 
01095          fl,
01096          poss_curr_catch_types);
01097       fl.is_top_level = false;
01098 
01099       // mark this function as having had its exception list calculated.
01100       function.calculated_propogating_exceptions = true;
01101       
01102       return function.circular;
01103    }
01104    //===========================================================================
01105    void Dictionary::HandleCircularCallgraph(
01106       FunctionProgressIFace* progress, Function& function)
01107    {
01108       #warning "@@@Brendon emit a warning for circular callgraph possibly causing extra exceptions."
01109       EDOC_ASSERT(function.circular, "");
01110       
01111       // First we make sure that the other functions in the circular
01112       // callraph have been partially calculated.
01113       EDOC_FOREACH(std::set<Function*>, ft, *function.circular)
01114       {
01115          GenerateExceptions(progress, *(*ft));
01116       }
01117 
01118       // We then find the union of the propogating exceptions for all
01119       // the functions in the circle (not including the subst 
01120       // exceptions). 
01121       PropExcepPList all_exceps;
01122       EDOC_FOREACH(std::set<Function*>, ft, *function.circular)
01123       {
01124          EDOC_FOREACH(PropExcepList, jt, (*ft)->propogating_exceptions)
01125          {
01126             // If it isnt a subst exception, then add it to the list.
01127             if (jt->exception->type.value != SUBSTITUTION_EXCEPTION_TYPE)
01128             {
01129                PushBackUnique(all_exceps, &(*jt));
01130             }
01131          }
01132       }
01133 
01134       // Then for each subst exception we substitute the unioned list
01135       EDOC_FOREACH(std::set<Function*>, ft, *function.circular)
01136       {
01137          // Now perform the substitutions, creating propagating exception
01138          // instances from the list of Exception instances and the Propagating
01139          // exception instance used for the subst exception.
01140          std::list<PropogatingException> add;
01141 
01142          // Dont use foreach because we want to allow erasures.
01143          for(PropExcepList::iterator it = (*ft)->propogating_exceptions.begin();
01144             it != (*ft)->propogating_exceptions.end(); 
01145             /* no it++ */)
01146          {
01147             // For convenience.
01148             PropogatingException& p(*it);
01149 
01150             // Skip non-substitution exceptions. I.e. We dont do anything 
01151             // with them.
01152             if (p.exception->type.value != SUBSTITUTION_EXCEPTION_TYPE)
01153             {
01154                ++it;
01155                continue;
01156             }
01157 
01158             // Skip the ORIGINATING substitution exception.
01159             // We only substitute for propagating subst exceptions.
01160             // This is because the originating exception "...." that we add
01161             // to the function is not a real exception, we add it to
01162             // determine 
01163             // where exceptions MAY propagate through other functions in the 
01164             // recursive case. The orginal one is added for the sole purpose
01165             // of generating the propagating ones. The propagating ones tell
01166             // us where posible exceptions might come from. 
01167             if (p.orig_subst)
01168             {
01169                // Erase the subst exception.
01170                it = (*ft)->propogating_exceptions.erase(it);
01171 
01172                // Skip it++
01173                continue;
01174             }
01175 
01176             // Create from this subst prop excep a new prop excep for each
01177             // Exception* instance in its functions list.
01178             EDOC_FOREACH(PropExcepPList, jt, all_exceps)
01179             {
01180                PropogatingException p2(p);
01181                p2.exception = (*jt)->exception;
01182                
01183                // The possible and visible flags must be merged from both
01184                // the original prop excep and the propogating subst excep.
01185                
01186                // Since the subst prop excep is a "fake" then the merging rules
01187                // are a bit different here.
01188                // In particular, if eithre the original pexcep is "possible" or
01189                // the subst excep is "possible" then the result is possible.
01190                // Usually this would be an AND not an OR operation.
01191 
01192                // Likewise if the original is invisible OR the subst is
01193                // invisible then the result is invisible.
01194                p2.possible = (*jt)->possible | p.possible;
01195                p2.visible = (*jt)->visible & p.visible;
01196                
01197                add.push_back(p2);
01198             }
01199 
01200             // Erase the subst exception.
01201             it = (*ft)->propogating_exceptions.erase(it);
01202 
01203             // Skip it++
01204          }
01205 
01206          // Add unique exceptions defined in add
01207          AddExceptions((*ft)->propogating_exceptions, add);
01208       }
01209    }
01210    //===========================================================================
01211    void Dictionary::PostProcessExceptions(Function& function)
01212    {
01213       // Lets emit any necessary warnings and filter out exceptions
01214       // not permitted by the functions exception specifiers.
01215       // Debugging.
01216       EDOC_FOREACH(PropExcepList, it, function.propogating_exceptions)
01217       {
01218          EDOC_Debug("EMITS EXCEPTION: " 
01219             << it->exception->type.value->GetDeclaredName());
01220       }
01221 
01222       // Now we look at all propogating exceptions for this function and move
01223       // from propogating_list to filtered list any that do not match the 
01224       // functions throw spec. These will cause program aborts, but will not
01225       // propogate elsewhere.
01226       if (function.has_exception_spec)
01227       {
01228          // Dont use foreach because we want to allow erasures.
01229          for(PropExcepList::iterator it = 
01230                function.propogating_exceptions.begin();
01231             it != function.propogating_exceptions.end(); 
01232             /* no it++ */)
01233          {
01234             bool found = false;
01235             for (size_t j = 0; j < function.exception_spec.size(); j++)
01236             {
01237                if (it->exception->type.value->
01238                      IsCaughtBy(*function.exception_spec[j]))
01239                {
01240                   found = true;
01241                   break;
01242                }
01243             }
01244 
01245             // If it is not allowed by the specifier list, then remove it from
01246             // the propogating exceptions list and add it to the filtered list.
01247             if (!found)
01248             {
01249                function.filtered_exceptions.push_back(*it);
01250                it = function.propogating_exceptions.erase(it);
01251 
01252                // Skip it++
01253                continue;
01254             }
01255 
01256             it++;
01257          }
01258       }
01259    }
01260    //===========================================================================
01261    void Dictionary::ProcessFunction(
01262       Function& top,
01263       FunctionLoc& function,
01264       std::list<PropogatingException>& poss_curr_catch_types)
01265    {
01266       // Check to see if this function has already been processed.
01267       if (function.value->calculated_propogating_exceptions)
01268       {
01269          EDOC_Fine("Function has already been processed: " 
01270             << function.value->GetKeyName());
01271          return;
01272       }
01273 
01274       // If we are now starting to process a function that is part of 
01275       // a circular callgraph for the top function, then we will not
01276       // descend into it, rather we will just add a 
01277       // "recursive substitute exception" to the list and later we will
01278       // find all these functions and union their exception list and
01279       // re-calculate
01280       if (!function.is_top_level && top.circular &&
01281           top.circular->count(function.value))
01282       {
01283          // Handle the recursive function call case by adding a "...." 
01284          // substitute exception that represents the set of currently unknown
01285          // exception types that can be thrown by this function. 
01286          // Note: we only want to add it if it does not already exist.
01287          bool found = false;
01288          EDOC_FOREACH_CONST(std::list<PropogatingException>, it, 
01289             function.value->propogating_exceptions)
01290          {
01291             if (it->exception->type.value == SUBSTITUTION_EXCEPTION_TYPE)
01292             {
01293                found = true;
01294                break;
01295             }
01296          }
01297          
01298          if (!found)
01299          {
01300             // Then we will add the special substitution exception to the list
01301             // so that it looks like it originates from this function.
01302             FunctionLoc fl(*this, function.value, *UNKNOWN_LOCATION);
01303             
01304             // @@@Brendon Do i also make the propagating exception a possible
01305             // exception?
01306             PropogatingException p(*this, 
01307                &function.value->GetSubstException(), fl);
01308             
01309             // Mark the orig_subst flag to indicate
01310             // that it is the ORIGINAL substitution exception. The originating
01311             // one is never substituted, only propagating varients of it.
01312             // This is because if a propagating varient does not occur at the
01313             // top level then the subst exception has been completely filtered 
01314             // out.
01315             p.orig_subst = true;
01316             function.value->propogating_exceptions.push_back(p);
01317          }
01318          
01319          EDOC_Debug("The special recursion case has occured for a function: "
01320             << function.value->GetDeclaredName() << ":" 
01321             << (const void*)function.value);
01322          EDOC_Fine("Function is already in the processing stack not "
01323             "processing its exception list: " 
01324             << function.value->GetKeyName() << std::endl
01325             << "functions address: " << (void*)function.value);
01326          return;
01327       }
01328 
01329       EDOC_ASSERT(&top == function.value && function.is_top_level, "If the functions are calculated in the correct order and the circular callgraphs handled correctly, we should never encounter the case where a function is being called that has not been processed previously unless it is the top function.");
01330 
01331       EDOC_Finer("Entering: CalculatePropogatingExceptions for function: " 
01332          << function.value->GetDeclaredName());
01333 
01334       // Clear the current exceptions list as it may be a partial one.
01335       Erase(function.value->propogating_exceptions);
01336       Erase(function.value->filtered_exceptions);
01337 
01338       // If the function has no implementation and it is not a pure virtual with
01339       // children then dont process it as it will not have any exceptions.
01340       if (!function.value->processed_implementations &&
01341          !function.value->derived_virtuals.size())
01342       {
01343          EDOC_Fine("Function has no implementation returning without "
01344             "processing: " << function.value->GetKeyName());
01345          return;
01346       }
01347 
01348       // Calculate a list of all exceptions that emit from this functions main
01349       // code block.
01350       EDOC_Fine("Processing function: " << function.value->GetKeyName());
01351       ProcessCodeBlock(
01352          top,
01353          function.value->implementation, 
01354          function, 
01355          poss_curr_catch_types, 
01356          function.value->propogating_exceptions);
01357 
01358       return;
01359    }
01360    //===========================================================================
01361    void Dictionary::ProcessCodeBlock(
01362       Function& top,
01363       CodeBlock& block,
01364       FunctionLoc& function,
01365       std::list<PropogatingException>& poss_curr_catch_types,
01366       std::list<PropogatingException>& exceptions)
01367    {
01368       EDOC_Finer("Entering: ProcessCodeBlock");
01369       // Add originating exceptions to the list.
01370       // If the exception is ... then add all poss_curr_catch_types to the list
01371       // as well.
01372       EDOC_FOREACH(ExcepList, it, block.originating_exceptions)
01373       {
01374          EDOC_Fine("Function: " << function.value->GetKeyName() 
01375             << " has originating exception: " 
01376             << it->type.value->GetKeyName());
01377          AddOException(*this, exceptions, *it, poss_curr_catch_types);
01378       }
01379 
01380       std::list<FunctionLoc> fns = block.AllFunctionCalls();
01381       // For each function this block calls, obtain a list of its exceptions
01382       EDOC_FOREACH(FuncLocList, it, fns)
01383       {
01384          // If calling set_unexpected then emit a warning to the user indicating that we cant correctly handle this at the moment.
01385          if (it->value->GetKeyName() == "_ZSt14set_unexpectedPFvvE")
01386          {
01387             EDOC_NOTIFICATION(WSET_UNEXPECTED, "Function: " 
01388                << function.value->GetDeclaredName()
01389                << " is calling std::set_unexpected()",
01390                function.value, function.loc.file, function.loc.line, 
01391                NULL, 0, NULL, NULL, NULL, NULL);
01392          }
01393          
01394          // Make sure that we have the list of exceptions that can propogate 
01395          // from the function (Because of the processing order the only 
01396          // functions that should need processing from this point are ones 
01397          // in a circular callgraph).
01398          EDOC_Finer("Calcing exceptions for function : " 
01399             << it->value->GetDeclaredName() << " address: " << (void*)&(*it));
01400          ProcessFunction(top,
01401             (*it),
01402             poss_curr_catch_types);
01403 
01404          // @@@Brendon regarding virtual functions : It is all about the origin
01405          // of the exception. We dont want the parent funciton to be the origin
01406          // of all exceptions but have child as originator of its own
01407          // exceptions.
01408          // We will ignore the origin issue for now and assume all originate
01409          // from the parent function. This is MUCH simpler.
01410 
01411 
01412          // A functions derived virtuals have been added to the function as a
01413          // list of possible calls
01414          EDOC_Finer("Called function: " << (*it).value->GetDeclaredName() 
01415             << ", has exception count: " 
01416             << (*it).value->propogating_exceptions.size());
01417          
01418          // Add that functions exceptions to our list.
01419          EDOC_FOREACH(PropExcepList, kt, (*it).value->propogating_exceptions)
01420          {
01421             EDOC_Finer("Adding exception from function: " 
01422                << (*it).value->GetDeclaredName() << " to function: " 
01423                << function.value->GetDeclaredName());
01424             AddPException(*this, exceptions, *kt, *it, poss_curr_catch_types);
01425          }
01426       }
01427 
01428       // Process all try blocks.
01429       EDOC_FOREACH(TryBlockList, it, block.try_blocks)
01430       {
01431          EDOC_Fine("Number of exceptions before: " << exceptions.size());
01432          ProcessTryBlock(
01433             top,
01434             (*it),
01435             function,
01436             poss_curr_catch_types,
01437             exceptions);
01438 
01439          EDOC_Fine("Number of exceptions after: " << exceptions.size());
01440       }
01441 
01442       return;
01443    }
01444 
01445    //===========================================================================
01446    void Dictionary::ProcessTryBlock(
01447       Function& top,
01448       TryBlock& block,
01449       FunctionLoc& function,
01450       std::list<PropogatingException>& poss_curr_catch_types,
01451       std::list<PropogatingException>& exceptions)
01452    {
01453       EDOC_Finer("Entering: ProcessTryBlock");
01454       // Get the exceptions generated by the try block
01455       std::list<PropogatingException> try_exceptions;
01456       ProcessCodeBlock(top, *block.try_block, function, poss_curr_catch_types,
01457          try_exceptions);
01458 
01459       // Check for the MUST_NOT_THROW_EXPR case where a try block has NO catch
01460       // blocks we use this to mark that the try block MUST NOT THROW ANY
01461       // EXCEPTIONS if so it will cause a call to terminate()
01462       if (try_exceptions.size() && !block.catch_blocks.size())
01463       {
01464          EDOC_FOREACH(PropExcepList, it, try_exceptions)
01465          {
01466             EDOC_NOTIFICATION(ENOT_THROW, "Exception type: " 
01467                << it->exception->type.value->GetDeclaredName()
01468                << " propogates past a MUST_NOT_THROW_EXPR code block"
01469                " in function: " << function.value->GetDeclaredName(),
01470                function.value, function.loc.file, function.loc.line, 
01471                NULL, 0, NULL, &(*it), NULL, NULL);
01472          }
01473          return;
01474       }
01475 
01476       // For each catch block using the exceptions from the try block get a list
01477       // of matches to create a poss_curr_catch_types list.
01478       // Note: Order is important here.
01479       for (size_t i = 0; i < block.catch_blocks.size(); i++)
01480       {
01481          // Firstly lets get a list of all the e types that can be thrown by the
01482          // try block which can also be caught by the current catch block.
01483          TypeLoc catch_type = block.catch_blocks[i].catch_type;
01484 
01485          std::list<PropogatingException> types_caught;
01486 
01487          // Dont use foreach because we want to allow erasures.
01488          for(PropExcepList::iterator jt = try_exceptions.begin();
01489             jt != try_exceptions.end(); 
01490             /* no jt++ */)
01491          {
01492             // If exception is "...." and catch is "..." then treat
01493             // the exception as normal.
01494             if (jt->exception->
01495                type.value->IsCaughtBy(*catch_type.value))
01496             {
01497                EDOC_Fine("Caught exception: " 
01498                   << jt->exception->
01499                      type.value->GetDeclaredName());
01500                types_caught.push_back(*jt);
01501 
01502                // Erase it from the try_exceptions list.
01503                jt = try_exceptions.erase(jt);
01504                
01505                // Skip jt++
01506                continue;
01507             }
01508             else if (jt->exception->type.value == SUBSTITUTION_EXCEPTION_TYPE)
01509             {
01510                // If the exception is a subst exception "...." and it was not 
01511                // caught by the above handler (I.e. Handler was not of type ...)
01512                // Then we will "catch" it with this handler but not sink it.
01513                // I.e. we will process it as though it was caught but will 
01514                // assume that it will continue to propagate further on.
01515                
01516                // Push the exception on the back but do not erase it i.e. do not 
01517                // push its index onto the indexes list.
01518                types_caught.push_back(*jt);
01519             }
01520             
01521             jt++;
01522          }
01523 
01524          // If this catch block is usless in that it can not catch any
01525          // exceptions thrown in the try block, then warn the user. Also do not
01526          // process its code block.
01527          if (types_caught.size() == 0)
01528          {
01529             // Only warn if this is the top level funciton in the process stack.
01530             if (function.is_top_level)
01531             {
01532                EDOC_NOTIFICATION(WUNUSED_CATCH, 
01533                   "Catch block with type: " 
01534                   << catch_type.value->GetDeclaredName()
01535                   //<< " in function: " << function.value->GetDeclaredName()
01536                   << ", at location: " << catch_type.loc.GetNormalisedName()
01537                   << " is unable to catch any exceptions thrown from"
01538                   << " try block.",
01539                   function.value, catch_type.loc.file, catch_type.loc.line,
01540                   NULL, 0, catch_type.value, NULL, NULL, NULL);
01541             }
01542             
01543             // Dont make any use of the catch block so its exception
01544             // data/callgraphs are ignored since they will never occur.
01545          }
01546          else
01547          {
01548             // Now we process this catch block with the types_caught as
01549             // poss_curr_catch_types and append the exceptions that can leave it
01550             // to blocks_exceptions
01551 
01552             // Note: This replaces the poss_curr_catch_types not append to it as
01553             // there can only be 1 active exception at any time. So for example:
01554             //
01555             // try
01556             // {
01557             //    throw 3;
01558             // }
01559             // catch(int i)
01560             // {
01561             //    try
01562             //    {
01563             //       throw 2.0f;
01564             //    }
01565             //    catch(float f)
01566             //    {
01567             //       throw;
01568             //    }
01569             // }
01570             //
01571             // The rethrow is NOT able to rethrow the integer 3 but will rethrow
01572             // the float 2.0. This is why we do not append, but replace upon
01573             // entering the catch block.
01574             std::list<PropogatingException> catches_exceptions;
01575             ProcessCodeBlock(
01576                top,
01577                *block.catch_blocks[i].catch_code,
01578                function,
01579                types_caught,
01580                catches_exceptions);
01581 
01582             AddExceptions(exceptions, catches_exceptions);
01583          }
01584 
01585       }
01586 
01587 
01588       // Add whats left in the try_exceptions list to the blocks_exceptions
01589       AddExceptions(exceptions, try_exceptions);
01590 
01591       return;
01592    }
01593    //===========================================================================
01594    //@@@Brendon Possibly use special C++ type conversion functions.
01595    #define EDOC_REPLACE(DataType, Data, From, To, Count) \
01596       if ((void*)Data == From) {Data = (DataType*)To; Count++;}
01597    //===========================================================================
01598    size_t Dictionary::ReplaceReferences(PStack& stack, void* remove, 
01599       void* replace)
01600    {
01601       size_t count = 0;
01602       if (!stack.Push(this))
01603       {
01604          return count;
01605       }
01606 
01607       // @@@Brendon Update to use the managed object Validate instead of
01608       // accessing its private members directly.
01609       std::vector<ManagedObject*> objs = GetManagedObjectsVector();
01610       for (size_t i = 0; i < objs.size(); i++)
01611       {
01612          EDOC_FOREACH_CONST(StrIDObjPMap, it, objs[i]->items)
01613          {
01614             count += it->second->ReplaceReferences(stack, remove, replace);
01615          }
01616       }
01617       
01618       EDOC_REPLACE(File, UNKNOWN_FILE, remove, replace, count);
01619       
01620       return count;
01621    }
01622    //===========================================================================
01623    TranslationUnit* Dictionary::GetIndexedTranslationUnit(int32_t index)
01624    {
01625       if (index == -1)
01626       {
01627          return TranslationUnit::GetUnknown();
01628       }
01629       return translation_units[index];
01630    }
01631    //===========================================================================
01632    int32_t Dictionary::GetTranslationUnitIndex(TranslationUnit* tu)
01633    {
01634       for (size_t i = 0; i < translation_units.size(); i++)
01635       {
01636          //if(translation_units[i]->GetID() == tu->GetID())
01637          if(translation_units[i] == tu)
01638          {
01639             return i;
01640          }
01641       }
01642       
01643       if (tu == TranslationUnit::GetUnknown())
01644       {
01645          return -1;
01646       }
01647 
01648       EDOC_ASSERT(false, "Requested index of a translation unit that is not a part of this dictionary.");
01649       return 0;
01650    }
01651    //===========================================================================
01652 
01653 }
01654 

Generated on Tue Jan 20 18:26:07 2009 for EDoc-0.2.1 by  doxygen 1.5.1