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
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 static bool LessThanCallComplexity(const Function* left,
00072 const Function* right)
00073 {
00074
00075 if (left->total_calls != right->total_calls)
00076 {
00077 return left->total_calls < right->total_calls;
00078 }
00079
00080
00081
00082
00083
00084
00085 if (left->circular == right->circular)
00086 {
00087 return false;
00088 }
00089
00090
00091
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
00102
00103
00104
00105 if (left->circular->size() != right->circular->size())
00106 {
00107 return left->circular->size() < right->circular->size();
00108 }
00109
00110
00111
00112
00113
00114 return (uintptr_t)left->circular < (uintptr_t)right->circular;
00115 }
00116
00117
00118
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
00127
00128 EDOC_FOREACH(PropExcepList, it, poss_curr_catch_types)
00129 {
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 bool possible = fcall.possible | it->possible;
00140
00141
00142
00143
00144
00145 bool visible = exception.visible & it->visible;
00146
00147
00148
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
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
00170
00171
00172 if (it->possible)
00173 {
00174 pe->possible = possible;
00175 }
00176
00177
00178
00179 if (!it->visible)
00180 {
00181 pe->visible = visible;
00182 }
00183 }
00184
00185
00186
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
00195
00196
00197
00198
00199
00200
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
00209
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
00218
00219
00220
00221
00222
00223 PropogatingException pe(dict, exception.exception, fcall);
00224
00225
00226
00227 pe.possible = fcall.possible | exception.possible;
00228
00229
00230 pe.visible = exception.visible;
00231
00232
00233
00234
00235
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
00244
00245
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
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
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
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
00297
00298 static bool AddExceptions(
00299 std::list<PropogatingException>& exceptions,
00300 std::list<PropogatingException>& add)
00301 {
00302 size_t added = 0;
00303
00304
00305
00306
00307
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
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
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
00377 SUBSTITUTION_EXCEPTION_TYPE = NULL;
00378
00379 delete UNKNOWN_LOCATION;
00380 UNKNOWN_LOCATION = NULL;
00381
00382
00383 UNKNOWN_FILE = NULL;
00384 }
00385
00386 void Dictionary::GeneratePredefined()
00387 {
00388 if (!UNKNOWN_FILE)
00389 {
00390
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
00420
00421 type->loc = *UNKNOWN_LOCATION;
00422 type->referenced_in_files.push_back(
00423 const_cast<File*>(UNKNOWN_FILE));
00424
00425
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
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
00487 EDOC_Fine("Finished reading file.");
00488 more_records = false;
00489 break;
00490 }
00491
00492
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
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
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
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
00535
00536
00537
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
00556
00557
00558
00559
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
00575
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
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
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
00636
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
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
00667
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
00675
00676
00677
00678
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
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
00716
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
00731
00732 UpdateFunctionAddressLists();
00733
00734
00735
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
00751
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
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
00776
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
00798
00799
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
00844
00845
00846
00847
00848
00849
00850
00851
00852 if (processed.count(f))
00853 {
00854
00855
00856
00857
00858 if (curr_stack.size() && *curr_stack.begin() == f)
00859 {
00860
00861
00862
00863
00864
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
00872
00873
00874 if (!circular)
00875 {
00876 circular = (*jt)->circular;
00877 }
00878
00879
00880
00881 else if ((*jt)->circular && circular != (*jt)->circular)
00882 {
00883
00884 to_merge.insert((*jt)->circular);
00885
00886
00887
00888 (*jt)->circular = NULL;
00889 }
00890 }
00891 }
00892
00893
00894
00895
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
00907 delete *jt;
00908 }
00909 Erase(to_merge);
00910
00911
00912 if (!circular)
00913 {
00914 circular = new std::set<Function*>();
00915 }
00916
00917
00918 EDOC_FOREACH(std::vector<Function*>, it, curr_stack)
00919 {
00920 circular->insert(*it);
00921 }
00922
00923
00924
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
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
00939 processed.insert(f);
00940 curr_stack.push_back(f);
00941
00942
00943 int ret = CalculateTotalFunctionCalls(processed, curr_stack, f->implementation) + 1;
00944
00945
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
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
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
00983
00984
00985
00986
00987
00988
00989
00990
00991
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
01025
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
01033
01034
01035
01036 bool circular = GenerateExceptions(progress, *func);
01037
01038
01039
01040
01041 if (circular)
01042 {
01043 HandleCircularCallgraph(progress, *func);
01044 }
01045
01046
01047
01048
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
01070
01071 if (function.calculated_propogating_exceptions)
01072 {
01073 return false;
01074 }
01075
01076
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
01086
01087
01088 FunctionLoc fl(*this, &function, *UNKNOWN_LOCATION);
01089
01090
01091
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
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
01112
01113 EDOC_FOREACH(std::set<Function*>, ft, *function.circular)
01114 {
01115 GenerateExceptions(progress, *(*ft));
01116 }
01117
01118
01119
01120
01121 PropExcepPList all_exceps;
01122 EDOC_FOREACH(std::set<Function*>, ft, *function.circular)
01123 {
01124 EDOC_FOREACH(PropExcepList, jt, (*ft)->propogating_exceptions)
01125 {
01126
01127 if (jt->exception->type.value != SUBSTITUTION_EXCEPTION_TYPE)
01128 {
01129 PushBackUnique(all_exceps, &(*jt));
01130 }
01131 }
01132 }
01133
01134
01135 EDOC_FOREACH(std::set<Function*>, ft, *function.circular)
01136 {
01137
01138
01139
01140 std::list<PropogatingException> add;
01141
01142
01143 for(PropExcepList::iterator it = (*ft)->propogating_exceptions.begin();
01144 it != (*ft)->propogating_exceptions.end();
01145 )
01146 {
01147
01148 PropogatingException& p(*it);
01149
01150
01151
01152 if (p.exception->type.value != SUBSTITUTION_EXCEPTION_TYPE)
01153 {
01154 ++it;
01155 continue;
01156 }
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167 if (p.orig_subst)
01168 {
01169
01170 it = (*ft)->propogating_exceptions.erase(it);
01171
01172
01173 continue;
01174 }
01175
01176
01177
01178 EDOC_FOREACH(PropExcepPList, jt, all_exceps)
01179 {
01180 PropogatingException p2(p);
01181 p2.exception = (*jt)->exception;
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194 p2.possible = (*jt)->possible | p.possible;
01195 p2.visible = (*jt)->visible & p.visible;
01196
01197 add.push_back(p2);
01198 }
01199
01200
01201 it = (*ft)->propogating_exceptions.erase(it);
01202
01203
01204 }
01205
01206
01207 AddExceptions((*ft)->propogating_exceptions, add);
01208 }
01209 }
01210
01211 void Dictionary::PostProcessExceptions(Function& function)
01212 {
01213
01214
01215
01216 EDOC_FOREACH(PropExcepList, it, function.propogating_exceptions)
01217 {
01218 EDOC_Debug("EMITS EXCEPTION: "
01219 << it->exception->type.value->GetDeclaredName());
01220 }
01221
01222
01223
01224
01225
01226 if (function.has_exception_spec)
01227 {
01228
01229 for(PropExcepList::iterator it =
01230 function.propogating_exceptions.begin();
01231 it != function.propogating_exceptions.end();
01232 )
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
01246
01247 if (!found)
01248 {
01249 function.filtered_exceptions.push_back(*it);
01250 it = function.propogating_exceptions.erase(it);
01251
01252
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
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
01275
01276
01277
01278
01279
01280 if (!function.is_top_level && top.circular &&
01281 top.circular->count(function.value))
01282 {
01283
01284
01285
01286
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
01301
01302 FunctionLoc fl(*this, function.value, *UNKNOWN_LOCATION);
01303
01304
01305
01306 PropogatingException p(*this,
01307 &function.value->GetSubstException(), fl);
01308
01309
01310
01311
01312
01313
01314
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
01335 Erase(function.value->propogating_exceptions);
01336 Erase(function.value->filtered_exceptions);
01337
01338
01339
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
01349
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
01370
01371
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
01382 EDOC_FOREACH(FuncLocList, it, fns)
01383 {
01384
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
01395
01396
01397
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
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414 EDOC_Finer("Called function: " << (*it).value->GetDeclaredName()
01415 << ", has exception count: "
01416 << (*it).value->propogating_exceptions.size());
01417
01418
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
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
01455 std::list<PropogatingException> try_exceptions;
01456 ProcessCodeBlock(top, *block.try_block, function, poss_curr_catch_types,
01457 try_exceptions);
01458
01459
01460
01461
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
01477
01478
01479 for (size_t i = 0; i < block.catch_blocks.size(); i++)
01480 {
01481
01482
01483 TypeLoc catch_type = block.catch_blocks[i].catch_type;
01484
01485 std::list<PropogatingException> types_caught;
01486
01487
01488 for(PropExcepList::iterator jt = try_exceptions.begin();
01489 jt != try_exceptions.end();
01490 )
01491 {
01492
01493
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
01503 jt = try_exceptions.erase(jt);
01504
01505
01506 continue;
01507 }
01508 else if (jt->exception->type.value == SUBSTITUTION_EXCEPTION_TYPE)
01509 {
01510
01511
01512
01513
01514
01515
01516
01517
01518 types_caught.push_back(*jt);
01519 }
01520
01521 jt++;
01522 }
01523
01524
01525
01526
01527 if (types_caught.size() == 0)
01528 {
01529
01530 if (function.is_top_level)
01531 {
01532 EDOC_NOTIFICATION(WUNUSED_CATCH,
01533 "Catch block with type: "
01534 << catch_type.value->GetDeclaredName()
01535
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
01544
01545 }
01546 else
01547 {
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
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
01589 AddExceptions(exceptions, try_exceptions);
01590
01591 return;
01592 }
01593
01594
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
01608
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
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