libs/EDoc/Function.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 #include "EDoc/Function.h"
00022 #include "EDoc/Type.h"
00023 #include "EDoc/FunctionType.h"
00024 #include "EDoc/Dictionary.h"
00025 #include "EDoc/PersistenceIFace.h"
00026 #include "EDoc/exceptions.h"
00027 #include "EDoc/Logger.h"
00028 #include "EDoc/utils.h"
00029 #include "EDoc/PStack.h"
00030 #include "EDoc/StackRef.h"
00031 #include "EDoc/NotificationIFace.h"
00032 
00033 #include "EDoc/persistence_data.h"
00034 #include "IndexedDictionary.h"
00035 
00036 #include <sstream>
00037 
00038 #ifdef HAVE_STRING_H
00039    #include <string.h>
00040 #endif
00041 
00042 namespace EDoc
00043 {
00044    //===========================================================================
00045    uint8_t Function::GetRecordType() const
00046    {
00047       return VALUE_RECORD_TYPE_FUNCTION;
00048    }
00049    //===========================================================================
00050    Function::Function(Dictionary& dict_in, std::string key_name_in) :
00051       StringIdentifiedObject(dict_in, key_name_in),
00052       is_public(false),
00053       is_inline(false),
00054       is_implicit(false),
00055       has_exception_spec(false),
00056       function_pointer_type(NULL),
00057       loc(&dict_in),
00058       exceptions_enabled(true),
00059       processed_implementations(0),
00060       translation_unit(NULL),
00061       implementation(&dict),
00062       calculated_propogating_exceptions(false),
00063       visible(true),
00064       subst_exception(NULL),
00065       total_calls(-1),
00066       circular(NULL),
00067       on_processed(NULL),
00068       on_processed_data(NULL)
00069    {
00070    }
00071    //===========================================================================
00072    Function::Function(Dictionary& dict_in, int32_t index_in) :
00073       StringIdentifiedObject(dict_in, index_in),
00074       is_public(false),
00075       is_inline(false),
00076       is_implicit(false),
00077       has_exception_spec(false),
00078       function_pointer_type(NULL),
00079       loc(&dict_in),
00080       exceptions_enabled(true),
00081       processed_implementations(0),
00082       translation_unit(NULL),
00083       implementation(&dict),
00084       calculated_propogating_exceptions(false),
00085       visible(true),
00086       subst_exception(NULL),
00087       total_calls(-1),
00088       circular(NULL),
00089       on_processed(NULL),
00090       on_processed_data(NULL)
00091    {
00092    }
00093    //===========================================================================
00094    Function::~Function()
00095    {
00096       RemoveFromCircular();
00097       delete subst_exception;
00098       subst_exception = NULL;
00099    }
00100    //===========================================================================
00101    void Function::RemoveFromCircular()
00102    {
00103       if (circular)
00104       {
00105          // Remove this function from the circular set.
00106          std::set<Function*>::iterator it = circular->find(this);
00107          EDOC_ASSERT(it != circular->end(), "");
00108          circular->erase(it);
00109          
00110          // If we are the last in the set, then delete the set.
00111          if (circular->size() == 0)
00112          {
00113             delete circular;
00114          }
00115          circular = NULL;
00116       }
00117    }
00118    //===========================================================================
00119    Function& Function::operator=(const Function& right)
00120    {
00121       // @@@Brendon Do i need to assign the StringIdentifiedObject parts too?
00122       if (this == &right)
00123       {
00124          return *this;
00125       }
00126 
00127       EDOC_Finer("Assign-Merging primitives.");
00128       link_name = right.link_name;
00129       full_name = right.full_name;
00130       is_public = right.is_public;
00131       is_inline = right.is_inline;
00132       is_implicit = right.is_implicit;
00133       translation_unit = right.translation_unit;
00134 
00135       has_exception_spec = right.has_exception_spec;
00136       calculated_propogating_exceptions = 
00137          right.calculated_propogating_exceptions;
00138 
00139       Erase(propogating_exceptions);
00140 
00141       loc = right.loc;
00142 
00143       Erase(exception_spec);
00144       for (size_t i = 0; i < right.exception_spec.size(); i++)
00145       {
00146          exception_spec.push_back(
00147             dict.types.AlwaysGet(*right.exception_spec[i]));
00148       }
00149 
00150       Erase(address_taken);
00151       for (size_t i = 0; i < right.address_taken.size(); i++)
00152       {
00153          address_taken.push_back(Location(&dict));
00154          address_taken.back() = right.address_taken[i];
00155       }
00156 
00157       Erase(derived_virtuals);
00158       for (size_t i = 0; i < right.derived_virtuals.size(); i++)
00159       {
00160          derived_virtuals.push_back(
00161             dict.functions.AlwaysGet(
00162                *right.derived_virtuals[i]));
00163       }
00164 
00165       function_pointer_type = NULL;
00166       if (right.function_pointer_type)
00167       {
00168          function_pointer_type = dict.function_types.AlwaysGet(
00169             *right.function_pointer_type);
00170       }
00171 
00172       exceptions_enabled = right.exceptions_enabled;
00173 
00174       processed_implementations = right.processed_implementations;
00175 
00176       EDOC_Finer("Assign-Merging : Merging implementations.");
00177       EDOC_Finer("Right implementation is: " << right.implementation);
00178       implementation = right.implementation;
00179       EDOC_Finer("Our implementation is: " << implementation);
00180       
00181       populated = right.populated;
00182       
00183 
00184       Erase(referenced_in_files);
00185       EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00186       {
00187          referenced_in_files.push_back(
00188             dict.files.AlwaysGet(*(*it)));
00189       }
00190 
00191       visible = right.visible;
00192       return *this;
00193    }
00194    //===========================================================================
00195    void Function::Read(PersistenceIFace& file, IndexedDictionary& idict)
00196    {
00197       size_t size = 0;
00198 
00199       link_name = file.ReadString(KEY_LINK_NAME);
00200       full_name = file.ReadString(KEY_FULL_NAME);
00201       is_public = file.ReadBoolean(KEY_IS_PUBLIC);
00202       is_inline = file.ReadBoolean(KEY_IS_INLINE);
00203       is_implicit = file.ReadBoolean(KEY_IS_IMPLICIT);
00204       translation_unit = dict.GetIndexedTranslationUnit(
00205          file.ReadUInt32(KEY_TRANSLATION_UNIT));
00206       loc.Read(file, idict);
00207 
00208       has_exception_spec = file.ReadBoolean(KEY_HAS_EXCEPTION_SPEC);
00209       if (has_exception_spec)
00210       {
00211          size = file.ReadUInt32(KEY_EXCEPTION_SPEC_LS);
00212          for (size_t i = 0; i < size; i++)
00213          {
00214             exception_spec.push_back(
00215                idict.types.AlwaysGet(file.ReadUInt32(KEY_EXCEPTION_SPEC_LI)));
00216          }
00217       }
00218 
00219       size = file.ReadUInt32(KEY_DERIVED_VIRT_LS);
00220       for (size_t i = 0; i < size; i++)
00221       {
00222          derived_virtuals.push_back(
00223             idict.functions.AlwaysGet(
00224                file.ReadUInt32(KEY_DERIVED_VIRT_LI)));
00225       }
00226 
00227       size = file.ReadUInt32(KEY_ADDRESS_TAKEN_LS);
00228       for (size_t i = 0; i < size; i++)
00229       {
00230          Location l(&dict);
00231          l.Read(file, idict);
00232          address_taken.push_back(loc);
00233       }
00234       if (address_taken.size())
00235       {
00236          function_pointer_type = idict.function_types.AlwaysGet(
00237             file.ReadUInt32(KEY_FUNCTION_TYPE));
00238       }
00239 
00240 
00241       size = file.ReadUInt32(KEY_REFERENCE_FILES_LS);
00242       for (size_t i = 0; i < size; i++)
00243       {
00244          referenced_in_files.push_back(
00245             idict.files.AlwaysGet(file.ReadUInt32(KEY_REFERENCE_FILE)));
00246       }
00247 
00248       exceptions_enabled = file.ReadBoolean(KEY_EXCEPTIONS_ENABLED);
00249 
00250 
00251       processed_implementations = file.ReadUInt32(KEY_PROCESSED_IMPLEMENTATION);
00252       if (processed_implementations)
00253       {
00254          EDOC_Finer("Reading implementation.");
00255          implementation.Read(file, idict);
00256          EDOC_Finer("Done reading implementation.");
00257       }
00258 
00259       // Private functions have a key name that includes the name of the file
00260       // this implementation is in. I.e. they are static or part of an anon
00261       // namespace. 
00262       // This uses the compile unit name and not the name of the file it came
00263       // from because we need to ensure uniqueness within different translation
00264       // units even if the function was implemented as a static ina header file.
00265       populated = true;
00266       if (is_public && !is_inline)
00267       {
00268          SetKeyName(link_name);
00269       }
00270       else
00271       {
00272          // If this is a private file then it should only EVER be referenced in
00273          // a single file which is the single translation unit that it belongs
00274          // to. We ensure the uniqueness of the key name by appending the name
00275          // of the translation unit to which it belongs to the link name.
00276          if (referenced_in_files.size() != 1)
00277          {
00278             EDOC_THROW_EXCEPTION(FileIOException, 
00279                "All private functions should be referenced in exactly "
00280                "1 translation unit.", "");
00281          }
00282          
00283          std::ostringstream stream;
00284          stream << link_name << ":" << translation_unit->GetID() << ":" 
00285             << translation_unit->GetName();
00286          SetKeyName(stream.str());
00287       }
00288    }
00289    //===========================================================================
00290    void Function::Write(PersistenceIFace& file) const
00291    {
00292       file.WriteString(KEY_LINK_NAME, link_name);
00293       file.WriteString(KEY_FULL_NAME, full_name);
00294       file.WriteBoolean(KEY_IS_PUBLIC, is_public);
00295       file.WriteBoolean(KEY_IS_INLINE, is_inline);
00296       file.WriteBoolean(KEY_IS_IMPLICIT, is_implicit);
00297       file.WriteUInt32Debug(KEY_TRANSLATION_UNIT, 
00298          dict.GetTranslationUnitIndex(translation_unit),
00299          translation_unit->GetName());
00300       loc.Write(file);
00301 
00302       file.WriteBoolean(KEY_HAS_EXCEPTION_SPEC, has_exception_spec);
00303       if (has_exception_spec)
00304       {
00305          file.WriteUInt32(KEY_EXCEPTION_SPEC_LS, exception_spec.size());
00306          for (size_t i = 0; i < exception_spec.size(); i++)
00307          {
00308             file.WriteUInt32Debug(KEY_EXCEPTION_SPEC_LI, 
00309                exception_spec[i]->GetIndex(), 
00310                exception_spec[i]->GetDeclaredName());
00311          }
00312       }
00313 
00314       file.WriteUInt32(KEY_DERIVED_VIRT_LS,
00315          derived_virtuals.size());
00316       for (size_t i = 0; i < derived_virtuals.size(); i++)
00317       {
00318          file.WriteUInt32Debug(KEY_DERIVED_VIRT_LI, 
00319             derived_virtuals[i]->GetIndex(),
00320             derived_virtuals[i]->GetDeclaredName());
00321       }
00322 
00323 
00324       file.WriteUInt32(KEY_ADDRESS_TAKEN_LS, address_taken.size());
00325       for (size_t i = 0; i < address_taken.size(); i++)
00326       {
00327          address_taken[i].Write(file);
00328       }
00329       
00330       if (address_taken.size())
00331       {
00332          file.WriteUInt32Debug(KEY_FUNCTION_TYPE, 
00333             function_pointer_type->GetIndex(), 
00334             function_pointer_type->GetKeyName());
00335       }
00336 
00337       file.WriteUInt32(KEY_REFERENCE_FILES_LS, referenced_in_files.size());
00338       EDOC_FOREACH_CONST(FilePList, it, referenced_in_files)
00339       {
00340          file.WriteUInt32Debug(KEY_REFERENCE_FILE,
00341             (*it)->GetIndex(),
00342             (*it)->GetKeyName());
00343       }
00344 
00345       file.WriteBoolean(KEY_EXCEPTIONS_ENABLED, exceptions_enabled);
00346 
00347       file.WriteUInt32(KEY_PROCESSED_IMPLEMENTATION, processed_implementations);
00348       if (processed_implementations)
00349       {
00350          implementation.Write(file);
00351       }   
00352    }
00353    //===========================================================================
00354    std::ostream& Function::Print(std::ostream& out, std::string prefix) const
00355    {
00356       out << prefix << "Link Name: " << link_name << std::endl;
00357       out << prefix << "Declared Name: " << full_name << std::endl;
00358       if (is_public)
00359       {
00360          out << prefix << "Is Public: True" << std::endl;
00361       }
00362       else
00363       {
00364          out << prefix << "Is Public: False" << std::endl;
00365       }
00366 
00367       if (is_inline)
00368       {
00369          out << prefix << "Is Inline: True" << std::endl;
00370       }
00371       else
00372       {
00373          out << prefix << "Is Inline: False" << std::endl;
00374       }
00375 
00376       if (is_implicit)
00377       {
00378          out << prefix << "Is Implicit: True" << std::endl;
00379       }
00380       else
00381       {
00382          out << prefix << "Is Implicit: False" << std::endl;
00383       }
00384 
00385       if (has_exception_spec)
00386       {
00387          out << prefix << "Has Throw Spec: True" << std::endl;
00388          out << prefix << "Throw spec: " << GetSpecString() << std::endl;
00389       }
00390       else
00391       {
00392          out << prefix << "Has Throw Spec: False" << std::endl;
00393       }
00394 
00395       for (size_t i = 0; i < derived_virtuals.size(); i++)
00396       {
00397          out << prefix << "Virtual Call through: " 
00398             << derived_virtuals[i]->GetDeclaredName() << " "
00399             << derived_virtuals[i]->GetSpecString() << std::endl;
00400       }
00401 
00402       for (size_t i = 0; i < address_taken.size(); i++)
00403       {
00404          out << prefix << "Address taken at: ";
00405          address_taken[i].SingleLinePrint(out);
00406          out << std::endl;
00407       }
00408       if (address_taken.size())
00409       {
00410          out << prefix << "Function Pointer Type: " 
00411             << function_pointer_type->GetKeyName() << std::endl;
00412       }
00413 
00414       loc.Print(out, prefix) << std::endl;
00415 
00416       if (exceptions_enabled)
00417       {
00418          out << prefix << "Exceptions enabled: True" << std::endl;
00419       }
00420       else
00421       {
00422          out << prefix << "Exceptions enabled: False" << std::endl;
00423       }
00424 
00425       out << prefix << "Implementation processed: " 
00426          << processed_implementations << std::endl;
00427          
00428       out << prefix << GetDeclaredName() << GetSpecString() << std::endl;
00429       if (processed_implementations)
00430       {
00431          implementation.Print(out, prefix);
00432       }
00433 
00434       if (calculated_propogating_exceptions)
00435       {
00436          out << prefix << "Calculated Propogating Exceptions: True" << std::endl;
00437       }
00438       else
00439       {
00440          out << prefix << "Calculated Propogating Exceptions: False" << std::endl;
00441       }
00442       
00443       EDOC_FOREACH_CONST(PropExcepList, it, propogating_exceptions)
00444       {
00445          out << prefix << INDENT_STR << "P: " << it->exception->type.value->GetDeclaredName() << std::endl;
00446       }
00447       
00448       out << prefix << "total_calls: " << total_calls << std::endl;
00449       if (circular)
00450       {
00451          out << prefix << "Part of circular callgraph along with:" << std::endl;
00452          EDOC_FOREACH_CONST(std::set<Function*>, it, *circular)
00453          {
00454             out << prefix << INDENT_STR
00455                << (*it)->GetDeclaredName() << " "
00456                << (*it)->GetSpecString() << std::endl;
00457          }
00458       }
00459       else
00460       {
00461          out << prefix << "NOT part of circular callgraph (or not yet calculated)." << std::endl;
00462       }
00463       return out;
00464    }
00465 
00466    //===========================================================================
00467    /** \brief define a small macro that is called upon a merge error.
00468     */
00469    #define EDOC_MERGE_ERROR(Message) \
00470       EDOC_Error("Function Name: " << GetKeyName() \
00471          << "\nMessage: " << Message); \
00472       EDOC_THROW_EXCEPTION(MergeException, "Failed merging function.", Message);
00473       
00474    //===========================================================================
00475    void Function::Merge(const StringIdentifiedObject& right_in)
00476    {
00477       const Function& right(dynamic_cast<const Function&>(right_in));
00478       
00479       // If this object has not been populated yet, then we just assign data
00480       // instead of merging, but we need to make sure we do not assign from its
00481       // pointer but use dict to get references to appropiate objects.
00482       if (!populated)
00483       {
00484          EDOC_Finer("This function has not been populated so doing an "
00485             "assign merge from the right function.");
00486          *this = right;
00487          return;
00488       }
00489 
00490       EDOC_Finer("Doing complex merge of function.");
00491       if (GetKeyName() != right.GetKeyName())
00492       {
00493          EDOC_MERGE_ERROR("Unable to merge two types with different names. "
00494             "Left: " << GetKeyName() << ", right: " 
00495             << right.GetKeyName());
00496       
00497       }
00498 
00499       // Otherwise we have two completed functions and need to perform a complex
00500       // merge operation.
00501       
00502       
00503       if (link_name != right.link_name)
00504       {
00505          EDOC_MERGE_ERROR("Unable to merge two functions with different names. "
00506             "Left: " << link_name << ", right: " 
00507             << right.link_name);
00508       
00509       }
00510       
00511       if (is_public != right.is_public)
00512       {
00513          EDOC_MERGE_ERROR("Unable to merge two functions when one is public "
00514             "and the other is private to a translation unit.");
00515       }
00516 
00517       if (is_inline != right.is_inline)
00518       {
00519          EDOC_MERGE_ERROR("Unable to merge two functions when one is inlined "
00520             "and the other is not.");
00521       }
00522 
00523       if (processed_implementations && right.processed_implementations &&
00524          (exceptions_enabled != right.exceptions_enabled))
00525       {
00526          EDOC_MERGE_ERROR("Unable to merge two functions which have two "
00527             "implementations where one implementation has been processed "
00528             "with exceptions enabled and the other without. "
00529             << "Left Function: " << GetKeyName()
00530             << ", Right Function: " << right.GetKeyName()
00531             << ", Left Declared Name: " << GetDeclaredName()
00532             << ", Right Declared Name: " << right.GetDeclaredName()
00533             << ", Left Location: " << loc
00534             << ", Right Location: " << right.loc
00535             << ", Left Ref in Files: " << GetRefInFilesString()
00536             << ", Right Ref in Files: " << right.GetRefInFilesString());
00537       }
00538 
00539       if (function_pointer_type && right.function_pointer_type && 
00540             (function_pointer_type->GetKeyName() != 
00541              right.function_pointer_type->GetKeyName()))
00542       {
00543          EDOC_MERGE_ERROR("Cant merge two functions with different types."
00544             " left: " << function_pointer_type->GetKeyName() 
00545             << ", right: " << right.function_pointer_type->GetKeyName());
00546       }
00547 
00548       // We dont care too much about the declared name. It may differ for each
00549       // translation unit. So only merge it if we dont currently have one.
00550       if (!full_name.size())
00551       {
00552          full_name = right.full_name;
00553       }
00554 
00555       // Merge the exceptions_enabled flag.
00556       // Object with an implementation takes precedence. Otherwise we dont care
00557       // really what value it has.
00558       if (!processed_implementations && right.processed_implementations)
00559       {
00560          exceptions_enabled = right.exceptions_enabled;
00561       }
00562       
00563       // Warn if the exception specs differ, but the merge should inherit the
00564       // most restrictive exception spec of both.
00565       bool exception_specs_differ = false;
00566       if (has_exception_spec != right.has_exception_spec)
00567       {
00568          exception_specs_differ = true;
00569       }
00570 
00571 
00572       if (!exception_specs_differ && 
00573          (exception_spec.size() != right.exception_spec.size()))
00574       {
00575          exception_specs_differ = true;
00576       }
00577       for (size_t i = 0; !exception_specs_differ && (i < exception_spec.size());
00578          i++)
00579       {
00580          bool found = false;
00581          for (size_t j = 0; j < right.exception_spec.size(); j++)
00582          {
00583             if (right.exception_spec[j]->GetNormalisedName() == 
00584                exception_spec[i]->GetNormalisedName())
00585             {
00586                found = true;
00587                break;
00588             }
00589          }
00590 
00591          if (!found)
00592          {
00593             exception_specs_differ = true;
00594          }
00595       }
00596 
00597       // If the specs differ then set the merged to the most restrictive spec.
00598       if (exception_specs_differ)
00599       {
00600          EDOC_NOTIFICATION(WDIFF_THROW, 
00601                "Function: " << GetKeyName()
00602             << ", Declared Name: " << GetDeclaredName()
00603             << ", Left Spec:  " << GetSpecString()
00604             << ", Right Spec: " << right.GetSpecString(),
00605             this, loc.file, loc.line, right.loc.file, right.loc.line, 
00606             NULL, NULL, NULL, NULL);
00607          //EDOC_WARNING(WDIFF_THROW, 
00608          //      "Function: " << GetKeyName()
00609          //   << ", Declared Name: " << GetDeclaredName()
00610          //   << ", Left Spec:  " << GetSpecString()
00611          //   << ", Right Spec: " << right.GetSpecString());
00612          
00613          EDOC_Warning("Merging two functions with different exception specs."
00614             << "\nLeft Spec: " << GetSpecString()
00615             << "\nRight Spec: " << right.GetSpecString()
00616             << "\nFunction Name: " << GetKeyName());
00617 
00618          has_exception_spec = true;
00619          std::vector<Type*> merged_spec;
00620 
00621          // only add an exception if it is found in both specs.
00622          for (size_t i = 0; i < exception_spec.size(); i++)
00623          {
00624             bool found = false;
00625             for (size_t j = 0; j < right.exception_spec.size(); j++)
00626             {
00627                if (right.exception_spec[j]->GetNormalisedName() == 
00628                   exception_spec[i]->GetNormalisedName())
00629                {
00630                   found = true;
00631                   break;
00632                }
00633             }
00634 
00635             if (found)
00636             {
00637                merged_spec.push_back(exception_spec[i]);
00638             }
00639          }
00640          exception_spec = merged_spec;
00641 
00642          EDOC_Warning("Resulting merged spec is: " << GetSpecString());
00643       }
00644 
00645       // Merge implicit function param.
00646       // If one is implicit and the other is not then just make the result 
00647       // NON-Implicit
00648       if (!right.is_implicit)
00649       {
00650          // @@@Brendon Warning if they differ?
00651          is_implicit = false;
00652       }
00653       
00654       // Merge the virt fall through.
00655       for (size_t i = 0; i < right.derived_virtuals.size(); i++)
00656       {
00657          bool found = false;
00658          for (size_t j = 0; j < derived_virtuals.size(); j++)
00659          {
00660             if (right.derived_virtuals[i]->GetKeyName() == 
00661                derived_virtuals[j]->GetKeyName())
00662             {
00663                found = true;
00664                break;
00665             }
00666          }
00667 
00668          if (!found)
00669          {
00670             derived_virtuals.push_back(
00671                dict.functions.AlwaysGet(*right.derived_virtuals[i]));
00672          }
00673       }
00674 
00675       // Merge the address taken list.
00676       for (size_t i = 0; i < right.address_taken.size(); i++)
00677       {
00678          bool found = false;
00679          for (size_t j = 0; j < address_taken.size(); j++)
00680          {
00681             if (right.address_taken[i] == address_taken[j])
00682             {
00683                found = true;
00684                break;
00685             }
00686          }
00687 
00688          // If the address does not exist then add it.
00689          if (!found)
00690          {
00691             // Need to use assign merge so that the location object references
00692             // files in our dictionary not its one.
00693             address_taken.push_back(Location(&dict));
00694             address_taken.back() = right.address_taken[i];
00695          }
00696       }
00697 
00698       // If the address has been taken after the merge and we do not have a
00699       // function pointer type then get it from the right instance.
00700       if (address_taken.size() && !function_pointer_type)
00701       {
00702          function_pointer_type = dict.function_types.AlwaysGet(
00703             *right.function_pointer_type);
00704       }
00705 
00706       // Locations are not merged, as it is possible for the function to be
00707       // defined in two different places. However if we have no source
00708       // information, then use the loc for the other file.
00709       if (!loc)
00710       {
00711          loc = right.loc;
00712       }
00713 
00714       // In situations wheremore than one implementation exists the last
00715       // implementation is used by the linker. We will set the translation unit
00716       // to equal the last one encountered.
00717       if (right.processed_implementations)
00718       {
00719          translation_unit = right.translation_unit;
00720       }
00721       
00722       
00723       // merge impls. This will return true if the impls needed to be merged
00724       // or false if no merge was necessary as the impls are the same or
00725       // have previously been merged.
00726       if (implementation.Merge(right.implementation))
00727       {
00728          // If the impls needed to be merged and BOTH had an impl, then it
00729          // means that we had differing impls. In this situation we need to 
00730          // warn the user that there is more than 1 impl.
00731          if (processed_implementations && right.processed_implementations)
00732          {
00733             EDOC_Finer("Merging Left implementation: " << implementation);
00734             EDOC_Finer("Merging Right implementation: " 
00735                << right.implementation);
00736 
00737             // We will warn the user, but will generate the union of the 
00738             // two impls. This will give a more pessimistic callgraph
00739             // and exception impl.
00740             // @@@Brendon Add to the description the left and right locations
00741             // for file/line.
00742             EDOC_NOTIFICATION(WDIFF_IMPL, 
00743                "Function: " << GetKeyName()
00744                << ", Declared Name: " << GetDeclaredName(),
00745                this, loc.file, loc.line, right.loc.file, right.loc.line, 
00746                NULL, NULL, NULL, NULL);
00747             implementation.Merge(right.implementation);
00748             
00749             EDOC_Warning("Failed merging function: " << right.GetKeyName()
00750                << ", with function: " << GetKeyName() 
00751                << " as their implementations differ.");
00752             EDOC_Warning("Left implementation: " << implementation);
00753             EDOC_Warning("Right implementation: " << right.implementation);
00754             EDOC_Warning("Left referenced in files: " << GetRefInFilesString());
00755             EDOC_Warning("Right referenced in files: " 
00756                << right.GetRefInFilesString());
00757             EDOC_Warning("Left declared at location: " << loc);
00758             EDOC_Warning("Right declared at location: " << right.loc);
00759          }
00760          
00761          processed_implementations++;
00762       }
00763       else if (!processed_implementations && right.processed_implementations)
00764       {
00765          // This is for the situation where right has an implementation but it
00766          // has an empty impl.
00767          processed_implementations++;
00768       }
00769       
00770       // Merge the file references after the rest so that it is eaasier to
00771       // seperate out where a problem may ocur if the implementation 
00772       // merge fails.
00773       EDOC_FOREACH_CONST(FilePList, it, right.referenced_in_files)
00774       {
00775          PushBackUnique(referenced_in_files,
00776             dict.files.AlwaysGet(*(*it)));
00777       }
00778 
00779 
00780       populated = true;
00781    }
00782    //===========================================================================
00783    std::string Function::GetSpecString() const
00784    {
00785       std::ostringstream stream;
00786 
00787       if (has_exception_spec)
00788       {
00789          stream << "throws(";
00790          for (size_t i = 0; i < exception_spec.size(); i++)
00791          {
00792             if (i != 0)
00793             {
00794                stream << ", ";
00795             }
00796             if (exception_spec[i]->IsPopulated())
00797             {
00798                stream << exception_spec[i]->GetDeclaredName();
00799             }
00800             else
00801             {
00802                stream << "(UNPOPULATED: " << exception_spec[i]->GetKeyName()
00803                   <<")";
00804             }
00805          }
00806          stream << ")";
00807       }
00808 
00809       return stream.str();
00810    }
00811    //===========================================================================
00812    void Function::ExpandCallGraph()
00813    {
00814       if (processed_implementations)
00815       {
00816          implementation.ExpandCallGraph(*this);
00817       }
00818 
00819       for (size_t j = 0; j < derived_virtuals.size(); j++)
00820       {
00821          EDOC_Finer("Adding POSSIBLE call for function: " 
00822             << GetKeyName() 
00823             << " to child virtual function: " 
00824             << derived_virtuals[j]->GetKeyName());
00825          implementation.AddPossCall(FunctionLoc(dict, derived_virtuals[j],
00826             *dict.UNKNOWN_LOCATION));
00827       }
00828    }
00829    //===========================================================================
00830    std::list<const PropogatingException*> Function::GetVisiblePropExceptions() const
00831    {
00832       std::list<const PropogatingException*> ret;
00833       EDOC_FOREACH_CONST(PropExcepList, it, propogating_exceptions)
00834       {
00835          if (it->IsVisible())
00836          {
00837             ret.push_back(&(*it));
00838          }
00839          else
00840          {
00841             EDOC_Info("Exception is not visible: " 
00842                << it->exception->type.value->GetDeclaredName());
00843             if (!it->visible)
00844             {
00845                EDOC_Info("At prop level.");
00846             }
00847 
00848             if (!it->exception->visible)
00849             {
00850                EDOC_Info("At orig level.");
00851             }
00852 
00853             if (!it->exception->type.value->visible)
00854             {
00855                EDOC_Info("At type level.");
00856             }
00857          }
00858       }
00859       
00860       return ret;
00861    }
00862    //===========================================================================
00863    bool Function::IsMain() const
00864    {
00865       return link_name == "main";
00866    }
00867    //===========================================================================
00868    bool Function::IsStaticInitialiser() const
00869    {
00870       // @@@Brendon This can be made a LOT faster.
00871       const char* STATIC_BASE_NAME = 
00872          "_Z41__static_initialization_and_destruction_0ii";
00873       size_t static_base_name_len = strlen(STATIC_BASE_NAME);
00874    
00875       return !strncmp(link_name.c_str(), 
00876          STATIC_BASE_NAME, static_base_name_len);
00877    }
00878    //===========================================================================
00879    bool Function::IsDestructor() const
00880    {
00881       // If the name has a ~ in it then it is a destructor.
00882       return full_name.find('~') != std::string::npos;
00883    }
00884    //===========================================================================
00885    //@@@Brendon Possibly use special C++ type conversion functions.
00886    #define EDOC_REPLACE(DataType, Data, From, To, Count) \
00887       if ((void*)Data == From) {Data = (DataType*)To; Count++;}
00888    //===========================================================================
00889    size_t Function::ReplaceReferences(PStack& stack, void* remove, 
00890       void* replace)
00891    {
00892       size_t count = 0;
00893       if (!stack.Push(this))
00894       {
00895          return count;
00896       }
00897 
00898       for (size_t i = 0; i < exception_spec.size(); i++)
00899       {
00900          EDOC_REPLACE(Type, exception_spec[i], remove, replace, count);
00901       }
00902 
00903       for (size_t i = 0; i < derived_virtuals.size(); i++)
00904       {
00905          EDOC_REPLACE(Function, derived_virtuals[i], 
00906             remove, replace, count);
00907       }
00908 
00909       for (size_t i = 0; i < address_taken.size(); i++)
00910       {
00911          count += address_taken[i].ReplaceReferences(stack, remove, replace);
00912       }
00913 
00914       EDOC_REPLACE(FunctionType, function_pointer_type, remove, replace, count);
00915 
00916       count += loc.ReplaceReferences(stack, remove, replace);
00917 
00918       if (processed_implementations)
00919       {
00920          count += implementation.ReplaceReferences(stack, remove, replace);
00921       }
00922 
00923       EDOC_FOREACH(PropExcepList, it, propogating_exceptions)
00924       {
00925          count += it->ReplaceReferences(stack, remove, replace);
00926       }
00927 
00928       for (size_t i = 0; i < filtered_exceptions.size(); i++)
00929       {
00930          count += filtered_exceptions[i].ReplaceReferences(stack, 
00931             remove, replace);
00932       }
00933 
00934       EDOC_FOREACH(FilePList, it, referenced_in_files)
00935       {
00936          EDOC_REPLACE(File, (*it), remove, replace, count);
00937       }
00938 
00939       if (circular)
00940       {
00941          EDOC_FOREACH(std::set<Function*>, it, *circular)
00942          {
00943             EDOC_ASSERT((void*)(*it) != remove, 
00944                "Replacing a function pointer after it has been populated "
00945                "into a circular callgraph is not currently supported.");
00946          }
00947       }
00948 
00949       return count;
00950    }
00951    //===========================================================================
00952    void Function::Validate(PStack& stack, const Dictionary& dict_in) const
00953    {
00954       // @@@Brendon Validate that the keyname from StringIdentifiedObject is the
00955       // same as what we would calculate the keyname to be from our internal
00956       // data. Mismatches may occur from assignment operator.
00957 
00958       StackRef ref(stack, this);
00959       if (!ref)
00960       {
00961          return;
00962       }
00963       
00964       EDOC_ASSERT(&dict == &dict_in, 
00965          "Current dict: " << &dict 
00966          << "\nRequired dict: " << &dict_in
00967          << "\nKey: " << key_name
00968          << "\nIndex: " << index);
00969       EDOC_ASSERT(populated, GetKeyName() << ", address: " << (void*)this);
00970 
00971       EDOC_ASSERT(translation_unit, "");
00972 
00973       EDOC_ASSERT(GetKeyName().size(), GetKeyName() << ", address: " 
00974          << (void*)this);
00975       EDOC_ASSERT(dict_in.functions.Get(GetKeyName()) == this, GetKeyName() 
00976          << ", address: " << (void*)this);
00977       
00978       for (size_t i = 0; i < exception_spec.size(); i++)
00979       {
00980          exception_spec[i]->Validate(stack, dict_in);
00981       }
00982 
00983       for (size_t i = 0; i < derived_virtuals.size(); i++)
00984       {
00985          derived_virtuals[i]->Validate(stack, dict_in);
00986       }
00987 
00988       for (size_t i = 0; i < address_taken.size(); i++)
00989       {
00990          address_taken[i].Validate(stack, dict_in);
00991       }
00992 
00993       if (address_taken.size())
00994       {
00995          EDOC_ASSERT(function_pointer_type, "");
00996          function_pointer_type->Validate(stack, dict_in);
00997       }
00998       else
00999       {
01000          EDOC_ASSERT(!function_pointer_type, "");
01001       }
01002       
01003       loc.Validate(stack, dict_in);
01004 
01005       
01006       implementation.Validate(stack, dict_in);
01007 
01008       bool got_filename = false;
01009       std::string filename = "";
01010       EDOC_FOREACH_CONST(PropExcepList, it, propogating_exceptions)
01011       {
01012          it->Validate(stack, dict_in);
01013 
01014          // All propogating exceptions should propogate from the same file.
01015          if (!got_filename)
01016          {
01017             filename = it->func.loc.file->GetName();
01018             if (filename.size())
01019             {
01020                got_filename = true;
01021             }
01022          }
01023          else
01024          {
01025             EDOC_ASSERT(it->func.loc.file->GetName() == filename, GetKeyName() 
01026                << ", address: " << (void*)this);
01027          }
01028       }
01029 
01030       for (size_t i = 0; i < filtered_exceptions.size(); i++)
01031       {
01032          filtered_exceptions[i].Validate(stack, dict_in);
01033       }
01034 
01035       EDOC_FOREACH_CONST(FilePList, it, referenced_in_files)
01036       {
01037          (*it)->Validate(stack, dict_in);
01038       }
01039       
01040       // If this is a static function then we require that it have an
01041       // implementation. This is really just a check to ensure the
01042       // GCC mod is working.
01043       //
01044       // @@@Brendon This check is failing. In particular for is_inline unused 
01045       // template members
01046       // And for is_public for some implicitly generated thunk functions
01047       // I will remove this for the time being.
01048       //if (!is_public || is_inline)
01049       //{
01050       //   EDOC_ASSERT(processed_implementations, 
01051       //      "Static and inline functions must have implementations." 
01052       //      << " Function: " << GetKeyName() << ", address: " << (void*)this
01053       //      << ", Details: " << *this);
01054       //}
01055 
01056       if (circular)
01057       {
01058          EDOC_FOREACH_CONST(std::set<Function*>, it, *circular)
01059          {
01060             EDOC_ASSERT((*it)->circular == circular, "");
01061             (*it)->Validate(stack, dict_in);
01062          }
01063       }
01064    }
01065    //===========================================================================
01066    std::string Function::GetRefInFilesString() const
01067    {
01068       std::ostringstream stream;
01069       EDOC_FOREACH_CONST(FilePList, it, referenced_in_files)
01070       {
01071          stream << "File: " 
01072             << (*it)->GetKeyName() 
01073             << std::endl;
01074       }
01075       
01076       return stream.str();
01077    }
01078    //===========================================================================
01079    std::list<EDoc::PropogatingException*> Function::GetPropogatingExceptions()
01080    {
01081       std::list<EDoc::PropogatingException*> ret;
01082       EDOC_FOREACH(PropExcepList, it, propogating_exceptions)
01083       {
01084          ret.push_back(&(*it));
01085       }
01086 
01087       return ret;
01088    }
01089    //===========================================================================
01090    Exception& Function::GetSubstException()
01091    {
01092       if (!subst_exception)
01093       {
01094          subst_exception = new Exception(&dict);
01095          subst_exception->type.loc = *dict.UNKNOWN_LOCATION;
01096          subst_exception->type.value = const_cast<Type*>(dict.SUBSTITUTION_EXCEPTION_TYPE);
01097 
01098          // This should never be in documentation anyway.
01099          subst_exception->visible = true;
01100          
01101          // This should be set temporarily by the function being calculated
01102          // when this exception is used.
01103          subst_exception->function = this;
01104       }
01105       
01106       return *subst_exception;
01107    }
01108    //===========================================================================
01109 }
01110 

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