//@copyright_begin // ================================================================ // Copyright Notice // Copyright (C) 1998-2004 by Joe Linoff // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Comments and suggestions are always welcome. // Please report bugs to http://ccdoc.sourceforge.net/ccdoc // ================================================================ //@copyright_end #include "log.h" #include "phase2.h" // ================================================================ // This variable allows the header version // to be queried at runtime. // ================================================================ namespace { char ccdoc_rcsid[] = "$Id: phase2.cc,v 1.9 2004/09/30 04:16:07 jlinoff Exp $"; } // ================================================================ // Local functions. // ================================================================ namespace { // ================================================================ // Process a match. // ================================================================ bool phase2_process_match(ccdoc::database& db, ccdoc::statement::base* match, ccdoc::statement::base* stmt) { if( match->get_type() == ccdoc::statement::base::STMT_METHOD || match->get_type() == ccdoc::statement::base::STMT_METHOD_CONSTRUCTOR || match->get_type() == ccdoc::statement::base::STMT_METHOD_DESTRUCTOR || match->get_type() == ccdoc::statement::base::STMT_METHOD_OPERATOR ) { ccdoc::statement::base* comm0 = match->get_comment(); ccdoc::statement::base* comm1 = stmt->get_comment(); if( comm0 == 0 ) { // Don't override the original comment if it // exists. if( comm1 ) { ccdoc::statement::comment comm(comm1); if( comm.get_suffix() ) { comm1->insert_after(match); } else { comm1->insert_before(match); } match->set_comment(comm1); comm1->set_comment(match); } } else if( comm1 ) { // Comments were specified for the original and // for the reference. Use the original comment. delete comm1; stmt->set_comment(0); } // Issue 0068 db.erase_from_path_map(stmt); delete stmt; return true; } return false; } // ================================================================ // Get the function argument list. // ================================================================ void phase2_get_arg_list(ccdoc::statement::base* stmt, string& args) { const vector& vec = stmt->get_tokens(); vector::const_iterator itr = vec.begin(); vector::const_iterator lp_itr = itr; int depth = 0; for(;itr!=vec.end();++itr) { string token = *itr; if( token == "(" ) { if( !depth ) lp_itr = itr; depth++; } else if( token == ")" ) { depth--; } } args = ""; for(;lp_itr!=vec.end();++lp_itr) { if( args.size() ) args += " "; args += *lp_itr; } } // ================================================ // Look for spurious function definitions that result from // the following code: // class A { // public: // A(); // ~A(); // }; // A::A() {} // A::~A() {} // ================================================ void phase2_clean_spurious_fct_refs(ccdoc::database& m_db, ccdoc::switches& m_sw) { vector stmts; m_db.load(stmts,ccdoc::statement::base::STMT_FUNCTION); m_db.load(stmts,ccdoc::statement::base::STMT_FUNCTION_OPERATOR); vector::iterator itr = stmts.begin(); for(;itr!=stmts.end();++itr) { ccdoc::statement::base* stmt = *itr; // Issue 0117: // The name scoping was not done properly in some cases. string id; stmt->get_hier_id_no_pkgs(id); // ================================================ // Quick check to determine whether it is possible // that this is a scoped id. // ================================================ bool found_sep = false; const char* p = id.c_str(); for(;*p;p++) { if( ':' == *p ) { ++p; if( ':' == *p ) { found_sep = true; break; } --p; } } if( !found_sep ) continue; // Look for matching classes. vector matching_stmts; m_db.get_stmt_no_pkgs(id,matching_stmts); if( matching_stmts.size() == 1 ) { // Remember that we are looking for the hier entry. // If only one was found, that is good, we can // do the substitution here. // delete this statement from the database. // Make sure that we capture the comment. phase2_process_match(m_db,matching_stmts[0],stmt); } else if( matching_stmts.size() > 1 ) { // There are multiple matching statements. // Find an exact match in the argument list. string args0; string args1; phase2_get_arg_list(stmt,args0); vector::iterator mitr = matching_stmts.begin(); for(;mitr!=matching_stmts.end();++mitr) { ccdoc::statement::base* match = *mitr; phase2_get_arg_list(match,args1); if( args0 == args1 ) { // We have a match, convert it. if( phase2_process_match(m_db,match,stmt) ) break; } } } } } } // ================================================================ // Phase2 // ================================================================ bool ccdoc::phase2::run(switches& sw,database& db) { database& m_db = db; switches& m_sw = sw; if(m_sw.verbose()) { s_log << "phase 2: begins\n"; } m_db.load_path_map(); // Issue 0039 phase2_clean_spurious_fct_refs(m_db,m_sw); if(m_sw.verbose()) { s_log << "phase 2: ends\n"; } return true; }