00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #include "EDoc/Type.h"
00022 #include "EDoc/PersistenceIFace.h"
00023 #include "EDoc/Dictionary.h"
00024 #include "EDoc/Function.h"
00025 #include "EDoc/exceptions.h"
00026 #include "EDoc/Logger.h"
00027 #include "EDoc/utils.h"
00028 #include "EDoc/PStack.h"
00029 #include "EDoc/StackRef.h"
00030
00031 #include "EDoc/persistence_data.h"
00032 #include "IndexedDictionary.h"
00033
00034 #include <iostream>
00035
00036
00037
00038
00039 #define EDOC_MERGE_ERROR(Message) \
00040 EDOC_Error(Message); \
00041 EDOC_THROW_EXCEPTION(MergeException, "Failed merging type.", Message);
00042
00043
00044 namespace EDoc
00045 {
00046
00047 uint8_t Type::GetRecordType() const
00048 {
00049 return VALUE_RECORD_TYPE_TYPE;
00050 }
00051
00052 Type::Type(Dictionary& dict_in, std::string key_name_in) :
00053 StringIdentifiedObject(dict_in, key_name_in),
00054 external_linkage(true),
00055 translation_unit(NULL),
00056 throw_type(NULL),
00057 root_type(NULL),
00058 loc(&dict_in),
00059 visible(true)
00060 {
00061 }
00062
00063 Type::Type(Dictionary& dict_in, int32_t index_in) :
00064 StringIdentifiedObject(dict_in, index_in),
00065 external_linkage(true),
00066 translation_unit(NULL),
00067 throw_type(NULL),
00068 root_type(NULL),
00069 loc(&dict_in),
00070 visible(true)
00071 {
00072 }
00073
00074 Type& Type::operator=(const Type& right)
00075 {
00076
00077 if (this == &right)
00078 {
00079 EDOC_Finer("Not assigning as the instances are the same.");
00080 return *this;
00081 }
00082
00083 name = right.name;
00084 loc = right.loc;
00085 external_linkage = right.external_linkage;
00086 throw_type = dict.types.AlwaysGet(*right.throw_type);
00087 root_type = dict.types.AlwaysGet(*right.root_type);
00088
00089 if (!external_linkage)
00090 {
00091
00092 translation_unit = right.translation_unit;
00093 }
00094
00095
00096 Erase(identical);
00097 for (size_t i = 0; i < right.identical.size(); i++)
00098 {
00099 identical.push_back(dict.types.AlwaysGet(
00100 *right.identical[i]));
00101 }
00102
00103
00104 Erase(catchable);
00105 for (size_t i = 0; i < right.catchable.size(); i++)
00106 {
00107 catchable.push_back(dict.types.AlwaysGet(
00108 *right.catchable[i]));
00109 }
00110
00111 Erase(referenced_in_files);
00112 EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00113 {
00114 referenced_in_files.push_back(
00115 dict.files.AlwaysGet(*(*it)));
00116 }
00117
00118 populated = right.populated;
00119 visible = right.visible;
00120 return *this;
00121 }
00122
00123 void Type::Read(PersistenceIFace& file, IndexedDictionary& idict)
00124 {
00125 name = file.ReadString(KEY_CANONICAL_NAME);
00126 external_linkage = file.ReadBoolean(KEY_EXTERNAL_LINKAGE);
00127 if (!external_linkage)
00128 {
00129 translation_unit = idict.dict->GetIndexedTranslationUnit(
00130 file.ReadUInt32(KEY_TRANSLATION_UNIT));
00131 }
00132
00133 throw_type = idict.types.AlwaysGet(file.ReadUInt32(KEY_THROW_TYPE));
00134 root_type = idict.types.AlwaysGet(file.ReadUInt32(KEY_ROOT_TYPE));
00135
00136 loc.Read(file, idict);
00137
00138 size_t size = file.ReadUInt32(KEY_IDENTICAL_TYPE_LS);
00139 for (size_t i = 0; i < size; i++)
00140 {
00141 identical.push_back(
00142 idict.types.AlwaysGet(file.ReadUInt32(KEY_IDENTICAL_TYPE_LI)));
00143 }
00144
00145 size = file.ReadUInt32(KEY_CATCHABLE_TYPE_LS);
00146 for (size_t i = 0; i < size; i++)
00147 {
00148 catchable.push_back(
00149 idict.types.AlwaysGet(file.ReadUInt32(KEY_CATCHABLE_TYPE_LI)));
00150 }
00151
00152 size = file.ReadUInt32(KEY_REFERENCE_FILES_LS);
00153 for (size_t i = 0; i < size; i++)
00154 {
00155 referenced_in_files.push_back(
00156 idict.files.AlwaysGet(file.ReadUInt32(KEY_REFERENCE_FILE)));
00157 }
00158
00159 populated = true;
00160 SetKeyName(GetNameInternal());
00161 }
00162
00163 std::ostream& Type::Print(std::ostream& out, std::string prefix) const
00164 {
00165 out << prefix << "Name: " << name << std::endl;
00166
00167 out << prefix << "Throw Type: "
00168 << (throw_type ? throw_type->GetNormalisedName() : "(NULL)")
00169 << std::endl;
00170
00171 out << prefix << "Root Type: "
00172 << (root_type ? root_type->GetNormalisedName() : "(NULL)")
00173 << std::endl;
00174
00175 loc.Print(out, prefix) << std::endl;
00176
00177 for (size_t i = 0; i < identical.size(); i++)
00178 {
00179 out << prefix << "Identical to: " << identical[i]->GetNormalisedName() << std::endl;
00180 }
00181
00182 for (size_t i = 0; i < catchable.size(); i++)
00183 {
00184 out << prefix << "Catchable by: " << catchable[i]->GetNormalisedName() << std::endl;
00185 }
00186
00187 return out;
00188 }
00189
00190
00191 bool Type::operator==(const Type& right) const
00192 {
00193 if ((name != right.name) ||
00194 (external_linkage != right.external_linkage) ||
00195 (identical.size() != right.identical.size()) ||
00196 (catchable.size() != right.catchable.size()) ||
00197 (throw_type != right.throw_type) ||
00198 (root_type != right.root_type) ||
00199 (loc != right.loc))
00200 {
00201 return false;
00202 }
00203
00204 if (!external_linkage)
00205 {
00206 if (translation_unit->GetID() !=
00207 right.translation_unit->GetID())
00208 {
00209 return false;
00210 }
00211 }
00212
00213 for (size_t i = 0; i < identical.size(); i++)
00214 {
00215 if (identical[i] != right.identical[i])
00216 {
00217 return false;
00218 }
00219 }
00220
00221 for (size_t i = 0; i < catchable.size(); i++)
00222 {
00223 if (catchable[i] != right.catchable[i])
00224 {
00225 return false;
00226 }
00227 }
00228
00229 return true;
00230 }
00231
00232 void Type::Merge(const StringIdentifiedObject& right_in)
00233 {
00234 const Type& right(dynamic_cast<const Type&>(right_in));
00235
00236 if (!populated)
00237 {
00238 *this = right;
00239 return;
00240 }
00241
00242 if (external_linkage != right.external_linkage)
00243 {
00244 EDOC_MERGE_ERROR("");
00245 }
00246
00247 if (!external_linkage)
00248 {
00249 if (translation_unit->GetID() !=
00250 right.translation_unit->GetID())
00251 {
00252 EDOC_Error("Our translation unit name: "
00253 << translation_unit->GetName()
00254 << "\nRight translation unit name: "
00255 << right.translation_unit->GetName());
00256 EDOC_MERGE_ERROR("Unable to merge two types with internal "
00257 "linkage but of different translation units.");
00258 }
00259 }
00260
00261
00262 if (!name.size())
00263 {
00264 EDOC_Finer("Assigning name: " << right.name);
00265 name = right.name;
00266 }
00267 else if (right.name.size() && (name != right.name))
00268 {
00269 EDOC_MERGE_ERROR("Unable to merge two types with different names. "
00270 "Left: " << name << ", right: " << right.name);
00271
00272 }
00273 else
00274 {
00275 EDOC_Finer("Otherwise we have a name and it is equal to the right "
00276 "name or right has no name.");
00277 }
00278
00279
00280 if (loc && right.loc && (loc != right.loc))
00281 {
00282 EDOC_MERGE_ERROR("Unable to merge two types declared in "
00283 "different files.");
00284 }
00285 else if (!loc)
00286 {
00287 EDOC_Finer("Merging locations.");
00288 loc.Merge(right.loc);
00289 }
00290
00291
00292
00293 if (!throw_type && !right.throw_type)
00294 {
00295 EDOC_MERGE_ERROR("Unable to merge two incomplete types.");
00296 }
00297 else if (!throw_type)
00298 {
00299 throw_type = dict.types.AlwaysGet(*right.throw_type);
00300 }
00301 else if (!right.throw_type)
00302 {
00303
00304 EDOC_ASSERT(throw_type, "");
00305 }
00306 else if (throw_type->GetNormalisedName() != right.throw_type->GetNormalisedName())
00307 {
00308 std::ostringstream ls;
00309 ls << "Referenced in files: ";
00310 EDOC_FOREACH(FilePList, it, referenced_in_files)
00311 {
00312 if (it != referenced_in_files.begin())
00313 {
00314 ls << ", ";
00315 }
00316 ls << (*it)->GetName();
00317 }
00318 ls << std::endl;
00319 Print(ls);
00320
00321 std::ostringstream rs;
00322 rs << "Referenced in files: ";
00323 EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00324 {
00325 if (it != right.referenced_in_files.begin())
00326 {
00327 rs << ", ";
00328 }
00329 rs << (*it)->GetName();
00330 }
00331 rs << std::endl;
00332 right.Print(rs);
00333
00334 EDOC_Error("Type: " << GetKeyName() << " is found in two files but has differing throw types. They are"
00335 << "\nLeft: " << throw_type->GetNormalisedName()
00336 << "\nRight: " << right.throw_type->GetNormalisedName()
00337 << "\n\nLeft: " << ls.str()
00338 << "\n\nRight: " << rs.str());
00339 EDOC_MERGE_ERROR("Cant merge types with differing throw types.");
00340 }
00341 else
00342 {
00343 EDOC_Finer("Eithre throw types are the same of both NULL. right: "
00344 << (right.throw_type ? right.throw_type->GetNormalisedName():"(NULL)"));
00345 }
00346
00347
00348 if (!root_type && !right.root_type)
00349 {
00350 EDOC_MERGE_ERROR("Unable to merge two incomplete types.");
00351 }
00352 else if (!root_type)
00353 {
00354 root_type = dict.types.AlwaysGet(*right.root_type);
00355 }
00356 else if (!root_type)
00357 {
00358
00359 EDOC_ASSERT(root_type, "");
00360 }
00361 else if (root_type->GetNormalisedName() != right.root_type->GetNormalisedName())
00362 {
00363 EDOC_MERGE_ERROR("Cant merge types with differing root_type types.");
00364 }
00365
00366
00367
00368 for (size_t i = 0; i < right.identical.size(); i++)
00369 {
00370
00371 Type* t = dict.types.AlwaysGet(*right.identical[i]);
00372 for (size_t j = 0; j < identical.size() && t; j++)
00373 {
00374 if (t == identical[j])
00375 {
00376 t = NULL;
00377 }
00378 }
00379
00380 if (t)
00381 {
00382 identical.push_back(t);
00383 }
00384 }
00385
00386
00387 for (size_t i = 0; i < right.catchable.size(); i++)
00388 {
00389
00390 Type* t = dict.types.AlwaysGet(*right.catchable[i]);
00391 for (size_t j = 0; j < catchable.size() && t; j++)
00392 {
00393 if (t == catchable[j])
00394 {
00395 t = NULL;
00396 }
00397 }
00398
00399 if (t)
00400 {
00401 catchable.push_back(t);
00402 }
00403 }
00404
00405
00406 EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00407 {
00408 PushBackUnique(referenced_in_files,
00409 dict.files.AlwaysGet(*(*it)));
00410 }
00411
00412
00413 populated = true;
00414 }
00415
00416
00417 bool Type::IsCaughtBy(const Type& right) const
00418 {
00419
00420
00421 if (&right == this)
00422 {
00423 return true;
00424 }
00425
00426 if (right.name == "...")
00427 {
00428 return true;
00429 }
00430
00431 if (!throw_type || !right.throw_type)
00432 {
00433 EDOC_THROW_EXCEPTION(BugException, "@@@Brendon", "");
00434 }
00435
00436 if (right.throw_type == throw_type)
00437 {
00438 return true;
00439 }
00440
00441
00442
00443
00444
00445 for (size_t i = 0; i < throw_type->catchable.size(); i++)
00446 {
00447 if (throw_type->catchable[i] == right.throw_type)
00448 {
00449 return true;
00450 }
00451 }
00452
00453
00454 return false;
00455 }
00456
00457
00458 void Type::Write(PersistenceIFace& file) const
00459 {
00460 file.WriteString(KEY_CANONICAL_NAME, name);
00461 file.WriteBoolean(KEY_EXTERNAL_LINKAGE, external_linkage);
00462 if (!external_linkage)
00463 {
00464 file.WriteUInt32Debug(KEY_TRANSLATION_UNIT,
00465 dict.GetTranslationUnitIndex(translation_unit),
00466 translation_unit->GetName());
00467 }
00468
00469
00470 file.WriteUInt32Debug(KEY_THROW_TYPE, throw_type->GetIndex(),
00471 throw_type->name);
00472 file.WriteUInt32Debug(KEY_ROOT_TYPE, root_type->GetIndex(), root_type->name);
00473
00474 loc.Write(file);
00475
00476 file.WriteUInt32(KEY_IDENTICAL_TYPE_LS, identical.size());
00477 for (size_t i = 0; i < identical.size(); i++)
00478 {
00479 file.WriteUInt32Debug(KEY_IDENTICAL_TYPE_LI, identical[i]->GetIndex(),
00480 identical[i]->name);
00481 }
00482
00483 file.WriteUInt32(KEY_CATCHABLE_TYPE_LS, catchable.size());
00484 for (size_t i = 0; i < catchable.size(); i++)
00485 {
00486 file.WriteUInt32Debug(KEY_CATCHABLE_TYPE_LI, catchable[i]->GetIndex(),
00487 catchable[i]->name);
00488 }
00489
00490 file.WriteUInt32(KEY_REFERENCE_FILES_LS, referenced_in_files.size());
00491 EDOC_FOREACH_CONST(FilePList, it, referenced_in_files)
00492 {
00493 file.WriteUInt32Debug(KEY_REFERENCE_FILE, (*it)->GetIndex(),
00494 (*it)->GetKeyName());
00495 }
00496 }
00497
00498 bool Type::IsEquivilant(const Type& right) const
00499 {
00500 if (this == &right)
00501 {
00502 return true;
00503 }
00504
00505
00506
00507 if (GetKeyName() == right.GetKeyName())
00508 {
00509 return true;
00510 }
00511
00512
00513
00514 if (root_type->external_linkage &&
00515 right.root_type->external_linkage)
00516 {
00517
00518
00519 return false;
00520 }
00521 else
00522 {
00523 return true;
00524 }
00525 }
00526
00527
00528 #define EDOC_REPLACE(DataType, Data, From, To, Count) \
00529 if ((void*)Data == From) {Data = (DataType*)To; Count++;}
00530
00531 size_t Type::ReplaceReferences(PStack& stack, void* remove,
00532 void* replace)
00533 {
00534 size_t count = 0;
00535 if (!stack.Push(this))
00536 {
00537 return count;
00538 }
00539
00540
00541
00542
00543
00544
00545
00546
00547 EDOC_REPLACE(Type, throw_type, remove, replace, count);
00548 EDOC_REPLACE(Type, root_type, remove, replace, count);
00549
00550 for (size_t i = 0; i < identical.size(); i++)
00551 {
00552 EDOC_REPLACE(Type, identical[i], remove, replace, count);
00553 }
00554
00555 for (size_t i = 0; i < catchable.size(); i++)
00556 {
00557 EDOC_REPLACE(Type, catchable[i], remove, replace, count);
00558 }
00559
00560 count += loc.ReplaceReferences(stack, remove, replace);
00561
00562 EDOC_FOREACH(FilePList, it, referenced_in_files)
00563 {
00564 EDOC_REPLACE(File, (*it), remove, replace, count);
00565 }
00566
00567 return count;
00568 }
00569
00570 void Type::Validate(PStack& stack, const Dictionary& dict_in) const
00571 {
00572
00573
00574
00575 StackRef ref(stack, this);
00576 if (!ref)
00577 {
00578 return;
00579 }
00580
00581 EDOC_ASSERT(&dict == &dict_in,
00582 "Current dict: " << &dict
00583 << "\nRequired dict: " << &dict_in
00584 << "\nKey: " << key_name
00585 << "\nIndex: " << index);
00586 EDOC_ASSERT(populated, "");
00587 EDOC_ASSERT(dict_in.types.Get(GetKeyName()) == this,
00588 "Our address: " << (const void*)this
00589 << ", dicts address: " << (const void*)dict_in.types.Get(GetKeyName())
00590 << " type: " << *this
00591 << " types scoped name: " << GetKeyName());
00592
00593 if (!external_linkage)
00594 {
00595 EDOC_ASSERT(translation_unit, *this);
00596
00597 }
00598 else
00599 {
00600 EDOC_ASSERT(!translation_unit, *this);
00601 }
00602
00603 EDOC_ASSERT(throw_type, *this);
00604 throw_type->Validate(stack, dict_in);
00605
00606 EDOC_ASSERT(root_type, *this);
00607 root_type->Validate(stack, dict_in);
00608
00609 for (size_t i = 0; i < identical.size(); i++)
00610 {
00611 EDOC_ASSERT(identical[i], *this);
00612 identical[i]->Validate(stack, dict_in);
00613 }
00614
00615 for (size_t i = 0; i < catchable.size(); i++)
00616 {
00617 EDOC_ASSERT(catchable[i], *this);
00618 catchable[i]->Validate(stack, dict_in);
00619 }
00620
00621 loc.Validate(stack, dict_in);
00622
00623
00624 EDOC_FOREACH_CONST(FilePList, it, referenced_in_files)
00625 {
00626 (*it)->Validate(stack, dict_in);
00627 }
00628 }
00629
00630 std::string Type::GetNameInternal() const
00631 {
00632
00633
00634
00635 std::ostringstream stream;
00636 if (!external_linkage)
00637 {
00638 stream << translation_unit->GetID() << ":"
00639 << translation_unit->GetName() << ":"
00640 << loc.line << ":"
00641 << name;
00642 return stream.str();
00643 }
00644 else
00645 {
00646 return name;
00647 }
00648 }
00649
00650
00651 }