libs/EDoc/CodeBlock.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003    Copyright (C) 2007 by Brendon Costa
00004 
00005    This library is free software; you can redistribute it and/or modify 
00006    it under the terms of the "LGPL Like" License defined in the file COPYING 
00007    that should have been distributed along with this source.
00008 
00009    This library is distributed in the hope that it will be useful, 
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of 
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013    You should have received a copy of the "LGPL Like" License 
00014    along with this library; see the file COPYING. if not, it can be 
00015    obtained from the EDoc++ website: 
00016    http://edoc.sourceforge.net/license.html
00017 
00018 *******************************************************************************/
00019 #include "config.h"
00020 
00021 
00022 #include "EDoc/CodeBlock.h"
00023 #include "EDoc/TryBlock.h"
00024 #include "EDoc/utils.h"
00025 #include "EDoc/Function.h"
00026 #include "EDoc/Type.h"
00027 #include "EDoc/FunctionType.h"
00028 #include "EDoc/PStack.h"
00029 #include "EDoc/StackRef.h"
00030 #include "EDoc/Dictionary.h"
00031 
00032 #include "EDoc/PersistenceIFace.h"
00033 #include "IndexedDictionary.h"
00034 #include "EDoc/persistence_data.h"
00035 
00036 namespace EDoc
00037 {
00038    //===========================================================================
00039    CodeBlock::CodeBlock(Dictionary* dict_in) :
00040       DictionarySpecific(dict_in)
00041    {
00042    }
00043    //===========================================================================
00044    CodeBlock::CodeBlock(const CodeBlock& right) :
00045       DictionarySpecific(&right.dict)
00046    {
00047       *this = right;
00048    }
00049    //===========================================================================
00050    CodeBlock::CodeBlock(const CodeBlock& right, Dictionary& dict_in) :
00051       DictionarySpecific(&dict_in)
00052    {
00053       *this = right;
00054    }
00055    //===========================================================================
00056    CodeBlock& CodeBlock::operator=(const CodeBlock& right)
00057    {
00058       if (this == &right)
00059       {
00060          return *this;
00061       }
00062 
00063       Erase(function_calls);
00064       EDOC_FOREACH_CONST(FuncLocList, it, right.function_calls)
00065       {
00066          function_calls.push_back(FunctionLoc(*it, dict));
00067       }
00068 
00069       Erase(originating_exceptions);
00070       EDOC_FOREACH_CONST(ExcepList, it, right.originating_exceptions)
00071       {
00072          originating_exceptions.push_back(Exception(*it, dict));
00073       }
00074 
00075       Erase(function_pointer_calls);
00076       EDOC_FOREACH_CONST(FTypeLocList, it, right.function_pointer_calls)
00077       {
00078          function_pointer_calls.push_back(FunctionTypeLoc(*it, dict));
00079       }
00080 
00081       Erase(try_blocks);
00082       EDOC_FOREACH_CONST(TryBlockList, it, right.try_blocks)
00083       {
00084          try_blocks.push_back(TryBlock(*it, dict));
00085       }
00086 
00087       Erase(possible_function_calls);
00088       
00089       return *this;
00090    }
00091    //===========================================================================
00092    void CodeBlock::Read(PersistenceIFace& file, IndexedDictionary& idict)
00093    {
00094       size_t size = 0;
00095 
00096       size = file.ReadUInt32(KEY_FUNCTION_CALL_LS);
00097       Erase(function_calls);
00098       for (size_t i = 0; i < size; i++)
00099       {
00100          function_calls.push_back(FunctionLoc(&dict));
00101          function_calls.back().Read(file, idict);
00102       }
00103 
00104       size = file.ReadUInt32(KEY_ORIGINATING_EXCEPTIONS_LS);
00105       Erase(originating_exceptions);
00106       for (size_t i = 0; i < size; i++)
00107       {
00108          originating_exceptions.push_back(Exception(&dict));
00109          originating_exceptions.back().Read(file, idict);
00110       }
00111 
00112       size = file.ReadUInt32(KEY_FUNCP_CALLS_LS);
00113       Erase(function_pointer_calls);
00114       for (size_t i = 0; i < size; i++)
00115       {
00116          function_pointer_calls.push_back(FunctionTypeLoc(&dict));
00117          function_pointer_calls.back().Read(file, idict);
00118       }
00119 
00120       size = file.ReadUInt32(KEY_TRY_BLOCKS_LS);
00121       Erase(try_blocks);
00122       for (size_t i = 0; i < size; i++)
00123       {
00124          try_blocks.push_back(TryBlock(&dict));
00125          try_blocks.back().Read(file, idict);
00126       }
00127    }
00128    //===========================================================================
00129    void CodeBlock::Write(PersistenceIFace& file) const
00130    {
00131       file.WriteUInt32(KEY_FUNCTION_CALL_LS, function_calls.size());
00132       EDOC_FOREACH_CONST(FuncLocList, it, function_calls)
00133       {
00134          it->Write(file);
00135       }
00136 
00137       // Dont save originating exceptions that were generated automatically
00138       size_t size = 0;
00139       EDOC_FOREACH_CONST(ExcepList, it, originating_exceptions)
00140       {
00141          if (!it->auto_throw_spec)
00142          {
00143             size++;
00144          }
00145       }
00146       file.WriteUInt32(KEY_ORIGINATING_EXCEPTIONS_LS, size);
00147       EDOC_FOREACH_CONST(ExcepList, it, originating_exceptions)
00148       {
00149          if (!it->auto_throw_spec)
00150          {
00151             it->Write(file);
00152          }
00153       }
00154 
00155       file.WriteUInt32(KEY_FUNCP_CALLS_LS, function_pointer_calls.size());
00156       EDOC_FOREACH_CONST(FTypeLocList, it, function_pointer_calls)
00157       {
00158          it->Write(file);
00159       }
00160 
00161       file.WriteUInt32(KEY_TRY_BLOCKS_LS, try_blocks.size());
00162       EDOC_FOREACH_CONST(TryBlockList, it, try_blocks)
00163       {
00164          it->Write(file);
00165       }
00166    }
00167    //===========================================================================
00168    bool CodeBlock::Merge(const CodeBlock& right)
00169    {
00170       bool differed = false;
00171       
00172       #define EDOC_LIST_MERGE(VectorName, VectorType) \
00173       { \
00174          size_t i = 0; \
00175          for (std::list<VectorType>::const_iterator it = \
00176             right.VectorName.begin(); \
00177             it != right.VectorName.end(); \
00178             it++, i++) \
00179          { \
00180             EDOC_Finer("Searching in vector: right." << #VectorName \
00181                << ", size: " << right.VectorName.size() \
00182                << ", i: " << i); \
00183             bool found = false; \
00184             size_t j = 0; \
00185             for (std::list<VectorType>::const_iterator jt = \
00186                VectorName.begin(); \
00187                jt != VectorName.end(); \
00188                jt++, j++) \
00189             { \
00190                EDOC_Finer("Searching in vector: " << #VectorName \
00191                   << ", size: " << VectorName.size() \
00192                   << ", j: " << j); \
00193                if (*jt == *it) \
00194                { \
00195                   EDOC_Finer("Found in vector: " << #VectorName); \
00196                   found = true; \
00197                   break; \
00198                } \
00199             } \
00200              \
00201             if (!found) \
00202             { \
00203                differed = 1; \
00204                EDOC_Finer("Pushing empty onto back vector: " << #VectorName); \
00205                VectorName.push_back(VectorType(&dict)); \
00206                VectorName.back() = *it; \
00207             } \
00208          } \
00209       }
00210 
00211       EDOC_LIST_MERGE(function_calls, FunctionLoc)
00212       EDOC_LIST_MERGE(originating_exceptions, Exception)
00213       EDOC_LIST_MERGE(function_pointer_calls, FunctionTypeLoc)
00214       EDOC_LIST_MERGE(try_blocks, TryBlock)
00215       
00216       // Note: There is no need for merging at any deeper depths. This should
00217       // suffice for merging two different function implementations. It could be
00218       // made to generate less blocks by looking for try blocks with same catch
00219       // types and merging the impls etc, but it is not worth the effort and
00220       // will not change the functionality.
00221       return differed;
00222    }
00223    //===========================================================================
00224    bool CodeBlock::operator==(const CodeBlock& right) const
00225    {
00226       // Compare two code blocks (Possibly from different dictionaries)
00227       // for equality where the order of the data is unimportant but the
00228       // contents must be the same.
00229       #define EDOC_LIST_COMPARE(VectorName, VectorType) \
00230       if (VectorName.size() != right.VectorName.size()) \
00231       { \
00232          return false; \
00233       } \
00234       for (std::list<VectorType>::const_iterator it = VectorName.begin(); \
00235          it != VectorName.end(); it++) \
00236       { \
00237          bool found = false; \
00238          for (std::list<VectorType>::const_iterator jt = \
00239             right.VectorName.begin(); \
00240             jt != right.VectorName.end(); \
00241             jt++) \
00242          { \
00243             if (*it == *jt) \
00244             { \
00245                found = true; \
00246                break; \
00247             } \
00248          } \
00249          if (!found) \
00250          { \
00251             return false; \
00252          } \
00253       }
00254 
00255       EDOC_LIST_COMPARE(function_calls, FunctionLoc)
00256       EDOC_LIST_COMPARE(originating_exceptions, Exception)
00257       EDOC_LIST_COMPARE(function_pointer_calls, FunctionTypeLoc)
00258       EDOC_LIST_COMPARE(try_blocks, TryBlock)
00259       
00260       return true;
00261    }
00262    //===========================================================================
00263    std::list<FunctionLoc> CodeBlock::AllFunctionCalls()
00264    {
00265       std::list<FunctionLoc> ret(function_calls);
00266       Append(ret, possible_function_calls);
00267       return ret;
00268    }
00269    //===========================================================================
00270    void CodeBlock::AddPossCall(FunctionLoc func)
00271    {
00272       possible_function_calls.push_back(func);
00273       possible_function_calls.back().possible = true;
00274    }
00275    //===========================================================================
00276    std::list<CodeBlock*> CodeBlock::GetAllCodeBlocks()
00277    {
00278       std::list<CodeBlock*> ret;
00279       ret.push_back(this);
00280       
00281       EDOC_FOREACH(TryBlockList, it, try_blocks)
00282       {
00283          // Append the try blocks code segment.
00284          Append(ret, it->try_block->GetAllCodeBlocks());
00285          
00286          // Append the try blocks catchg segments code.
00287          EDOC_FOREACH(CatchBlockVec, jt, it->catch_blocks)
00288          {
00289             Append(ret, jt->catch_code->GetAllCodeBlocks());
00290          }
00291       }
00292       
00293       return ret;
00294    }
00295    //===========================================================================
00296    size_t CodeBlock::ReplaceReferences(PStack& stack, void* remove, 
00297       void* replace)
00298    {
00299       size_t count = 0;
00300       if (!stack.Push(this))
00301       {
00302          return count;
00303       }
00304 
00305       EDOC_FOREACH(FuncLocList, it, function_calls)
00306       {
00307          count += it->ReplaceReferences(stack, remove, replace);
00308       }
00309 
00310       EDOC_FOREACH(ExcepList, it, originating_exceptions)
00311       {
00312          count += it->ReplaceReferences(stack, remove, replace);
00313       }
00314 
00315       EDOC_FOREACH(FTypeLocList, it, function_pointer_calls)
00316       {
00317          count += it->ReplaceReferences(stack, remove, replace);
00318       }
00319 
00320       EDOC_FOREACH(TryBlockList, it, try_blocks)
00321       {
00322          count += it->ReplaceReferences(stack, remove, replace);
00323       }
00324 
00325       EDOC_FOREACH(FuncLocList, it, possible_function_calls)
00326       {
00327          count += it->ReplaceReferences(
00328             stack, remove, replace);
00329       }
00330 
00331       return count;
00332    }
00333    //===========================================================================
00334    std::ostream& CodeBlock::Print(std::ostream& out, std::string prefix) const
00335    {
00336       out << prefix << "{" << std::endl;
00337       
00338       EDOC_FOREACH_CONST(FuncLocList, it, function_calls)
00339       {
00340          out << prefix << INDENT_STR << "Call : " 
00341              << it->value->GetKeyName() << std::endl;
00342       }
00343 
00344       EDOC_FOREACH_CONST(FuncLocList, it, possible_function_calls)
00345       {
00346          out << prefix << INDENT_STR << "Poss Call : " 
00347              << it->value->GetKeyName() << std::endl;
00348       }
00349 
00350       EDOC_FOREACH_CONST(ExcepList, it, originating_exceptions)
00351       {
00352          out << prefix << INDENT_STR << "Throw : " 
00353              << it->type.value->GetKeyName() << std::endl;
00354       }
00355 
00356       EDOC_FOREACH_CONST(FTypeLocList, it, function_pointer_calls)
00357       {
00358          out << prefix << INDENT_STR << "FP Call : " 
00359              << it->value->GetKeyName() << std::endl;
00360       }
00361 
00362       EDOC_FOREACH_CONST(TryBlockList, it, try_blocks)
00363       {
00364          it->Print(out, prefix + INDENT_STR);
00365       }
00366 
00367       out << prefix << "}" << std::endl;
00368       return out;
00369    }
00370    //===========================================================================
00371    void CodeBlock::ExpandCallGraph(Function& function)
00372    {
00373       // Look at the function  pointer calls list and add any matches with
00374       // addresses taken to the possible_function_calls list
00375       EDOC_FOREACH(FTypeLocList, it, function_pointer_calls)
00376       {
00377          for (size_t j = 0; j < it->value->addressed_functions.size(); j++)
00378          {
00379             AddPossCall(FunctionLoc(dict, 
00380                it->value->addressed_functions[j], 
00381                it->loc));
00382          }
00383       }
00384 
00385       EDOC_FOREACH(TryBlockList, it, try_blocks)
00386       {
00387          it->ExpandCallGraph(function);
00388       }
00389    }
00390    //===========================================================================
00391    void CodeBlock::Validate(PStack& stack, const Dictionary& dict_in) const
00392    {
00393       StackRef ref(stack, this);
00394       if (!ref)
00395       {
00396          return;
00397       }
00398       
00399       EDOC_ASSERT(&dict == &dict_in, "");
00400       
00401       EDOC_FOREACH_CONST(FuncLocList, it, function_calls)
00402       {
00403          it->Validate(stack, dict_in);
00404       }
00405 
00406       EDOC_FOREACH_CONST(ExcepList, it, originating_exceptions)
00407       {
00408          it->Validate(stack, dict_in);
00409          EDOC_ASSERT(
00410             it->type.value->throw_type->external_linkage, 
00411             "Throw type of an originating exception should ALWAYS have "
00412             "external linkage."
00413             << "\nException type is: " 
00414             << it->type.value->GetKeyName()
00415             << "\nThrow type is: " 
00416             << it->type.value->throw_type->GetKeyName());
00417       }
00418 
00419       EDOC_FOREACH_CONST(FTypeLocList, it, function_pointer_calls)
00420       {
00421          it->Validate(stack, dict_in);
00422       }
00423 
00424       EDOC_FOREACH_CONST(TryBlockList, it, try_blocks)
00425       {
00426          it->Validate(stack, dict_in);
00427       }
00428 
00429       EDOC_FOREACH_CONST(FuncLocList, it, possible_function_calls)
00430       {
00431          it->Validate(stack, dict_in);
00432          EDOC_ASSERT(it->possible, "Possible function calls must always "
00433             "have the \"possible\" flag set to true in the "
00434             "FunctionLoc object.");
00435       }
00436    }
00437    //===========================================================================
00438    std::list<EDoc::Exception*> CodeBlock::GetOriginatingExceptions()
00439    {
00440       std::list<EDoc::Exception*> ret;
00441       for (std::list<Exception>::iterator it = 
00442          originating_exceptions.begin();
00443          it != originating_exceptions.end(); it++)
00444       {
00445          ret.push_back(&(*it));
00446       }
00447 
00448       return ret;
00449    }
00450    //===========================================================================
00451 }

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