LCOV - code coverage report
Current view: top level - gcc/analyzer - program-point.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 88.2 % 93 82
Test Date: 2026-02-28 14:20:25 Functions: 85.7 % 14 12
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Classes for representing locations within the program.
       2              :    Copyright (C) 2019-2026 Free Software Foundation, Inc.
       3              :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it
       8              : under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but
      13              : WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              : General Public License for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #include "analyzer/common.h"
      22              : 
      23              : #include "diagnostics/event-id.h"
      24              : #include "gcc-rich-location.h"
      25              : #include "gimple-pretty-print.h"
      26              : #include "sbitmap.h"
      27              : #include "selftest.h"
      28              : #include "shortest-paths.h"
      29              : 
      30              : #include "analyzer/analyzer-logging.h"
      31              : #include "analyzer/call-string.h"
      32              : #include "analyzer/supergraph.h"
      33              : #include "analyzer/program-point.h"
      34              : #include "analyzer/store.h"
      35              : #include "analyzer/region-model.h"
      36              : #include "analyzer/sm.h"
      37              : #include "analyzer/program-state.h"
      38              : #include "analyzer/pending-diagnostic.h"
      39              : #include "analyzer/diagnostic-manager.h"
      40              : #include "analyzer/exploded-graph.h"
      41              : #include "analyzer/analysis-plan.h"
      42              : #include "analyzer/inlining-iterator.h"
      43              : 
      44              : #if ENABLE_ANALYZER
      45              : 
      46              : namespace ana {
      47              : 
      48              : /* A subclass of diagnostics::context for use by
      49              :    program_point::print_source_line.  */
      50              : 
      51              : class debug_diagnostic_context : public diagnostics::context
      52              : {
      53              : public:
      54          639 :   debug_diagnostic_context ()
      55          639 :   {
      56          639 :     diagnostic_initialize (this, 0);
      57          639 :     auto &source_printing_opts = get_source_printing_options ();
      58          639 :     source_printing_opts.show_line_numbers_p = true;
      59          639 :     source_printing_opts.enabled = true;
      60          639 :   }
      61          639 :   ~debug_diagnostic_context ()
      62              :   {
      63         1278 :     diagnostic_finish (this);
      64          639 :   }
      65              : };
      66              : 
      67              : /* class program_point.  */
      68              : 
      69              : /* Print the source line (if any) for this program_point to PP.  */
      70              : 
      71              : void
      72          639 : program_point::print_source_line (pretty_printer *pp) const
      73              : {
      74         1278 :   if (!useful_location_p (get_location ()))
      75            0 :     return;
      76          639 :   debug_diagnostic_context tmp_dc;
      77         1278 :   gcc_rich_location richloc (get_location ());
      78          639 :   diagnostics::source_print_policy source_policy (tmp_dc);
      79          639 :   gcc_assert (pp);
      80          639 :   source_policy.print (*pp, richloc, diagnostics::kind::error, nullptr);
      81          639 :   pp_string (pp, pp_formatted_text (tmp_dc.get_reference_printer ()));
      82         1278 : }
      83              : 
      84              : /* Print this program_point to PP.  */
      85              : 
      86              : void
      87         3577 : program_point::print (pretty_printer *pp, const format &f) const
      88              : {
      89         3577 :   pp_string (pp, "callstring: ");
      90         3577 :   m_call_string->print (pp);
      91         3577 :   f.spacer (pp);
      92              : 
      93         3577 :   if (m_snode)
      94              :     {
      95         3542 :       pp_printf (pp, "sn: %i", m_snode->m_id);
      96         3542 :       if (f.m_newlines)
      97              :         {
      98          639 :           pp_newline (pp);
      99          639 :           print_source_line (pp);
     100              :         }
     101              :     }
     102              :   else
     103           35 :     pp_string (pp, "origin");
     104         3577 : }
     105              : 
     106              : /* Dump this point to stderr.  */
     107              : 
     108              : DEBUG_FUNCTION void
     109            0 : program_point::dump () const
     110              : {
     111            0 :   tree_dump_pretty_printer pp (stderr);
     112            0 :   print (&pp, format (true));
     113            0 : }
     114              : 
     115              : /* Return a new json::object of the form
     116              :    {"snode_idx" : int (optional), the index of the supernode,
     117              :     "call_string": object for the call_string}.  */
     118              : 
     119              : std::unique_ptr<json::object>
     120            0 : program_point::to_json () const
     121              : {
     122            0 :   auto point_obj = std::make_unique<json::object> ();
     123              : 
     124            0 :   if (get_supernode ())
     125            0 :     point_obj->set_integer ("snode_idx", get_supernode ()->m_id);
     126            0 :   point_obj->set ("call_string", m_call_string->to_json ());
     127              : 
     128            0 :   return point_obj;
     129              : }
     130              : 
     131              : /* Pop the topmost call from the current callstack.  */
     132              : void
     133         1593 : program_point::pop_from_call_stack ()
     134              : {
     135         1593 :   m_call_string = m_call_string->get_parent ();
     136         1593 :   gcc_assert (m_call_string);
     137         1593 : }
     138              : 
     139              : /* Generate a hash value for this program_point.  */
     140              : 
     141              : hashval_t
     142      4654147 : program_point::hash () const
     143              : {
     144      4654147 :   inchash::hash hstate;
     145      4654147 :   hstate.add_ptr (m_snode);
     146      4654147 :   hstate.add_ptr (m_call_string);
     147      4654147 :   return hstate.end ();
     148              : }
     149              : 
     150              : /* Get the function * at DEPTH within the call stack.  */
     151              : 
     152              : function *
     153      1152259 : program_point::get_function_at_depth (unsigned depth) const
     154              : {
     155      1724010 :   gcc_assert (depth <= m_call_string->length ());
     156      1152259 :   if (depth == m_call_string->length ())
     157       780184 :     return m_snode->get_function ();
     158              :   else
     159       372075 :     return get_call_string ()[depth].get_caller_function ();
     160              : }
     161              : 
     162              : /* Assert that this object is sane.  */
     163              : 
     164              : void
     165       786934 : program_point::validate () const
     166              : {
     167              :   /* Skip this in a release build.  */
     168              : #if !CHECKING_P
     169              :   return;
     170              : #endif
     171              : 
     172       786934 :   m_call_string->validate ();
     173              :   /* The "callee" of the final entry in the callstring should be the
     174              :      function of the m_function_point.  */
     175       786934 :   if (m_call_string->length () > 0)
     176       399352 :     gcc_assert
     177              :       ((*m_call_string)[m_call_string->length () - 1].get_callee_function ()
     178              :        == get_function ());
     179       786934 : }
     180              : 
     181              : /* class program_point.  */
     182              : 
     183              : program_point
     184         3429 : program_point::origin (const region_model_manager &mgr)
     185              : {
     186         3429 :   return program_point (nullptr,
     187         3429 :                         mgr.get_empty_call_string ());
     188              : }
     189              : 
     190              : program_point
     191        10071 : program_point::from_function_entry (const region_model_manager &mgr,
     192              :                                     const supergraph &sg,
     193              :                                     const function &fun)
     194              : {
     195        10071 :   return program_point (sg.get_node_for_function_entry (fun),
     196        10071 :                         mgr.get_empty_call_string ());
     197              : }
     198              : 
     199              : /* Return true iff POINT_A and POINT_B share the same function and
     200              :    call_string, both directly, and when attempting to undo inlining
     201              :    information.  */
     202              : 
     203              : bool
     204          110 : program_point::effectively_intraprocedural_p (const program_point &point_a,
     205              :                                               const program_point &point_b)
     206              : {
     207              :   /* First, compare without considering inlining info.  */
     208          220 :   if (point_a.get_function ()
     209          110 :       != point_b.get_function ())
     210              :     return false;
     211          110 :   if (&point_a.get_call_string ()
     212          110 :       != &point_b.get_call_string ())
     213              :     return false;
     214              : 
     215              :   /* Consider inlining info; they must have originally come from
     216              :      the same function and have been inlined in the same way.  */
     217          110 :   location_t loc_a = point_a.get_location ();
     218          110 :   location_t loc_b = point_b.get_location ();
     219          110 :   inlining_iterator iter_a (loc_a);
     220          110 :   inlining_iterator iter_b (loc_b);
     221          314 :   while (!(iter_a.done_p () || iter_b.done_p ()))
     222              :     {
     223          110 :       if (iter_a.done_p () || iter_b.done_p ())
     224              :         return false;
     225              : 
     226          110 :       if (iter_a.get_fndecl () != iter_b.get_fndecl ())
     227              :         return false;
     228          108 :       if (iter_a.get_callsite () != iter_b.get_callsite ())
     229              :         return false;
     230          108 :       if (iter_a.get_block () != iter_b.get_block ())
     231              :         return false;
     232              : 
     233           94 :       iter_a.next ();
     234           94 :       iter_b.next ();
     235              :     }
     236              : 
     237              :   return true;
     238              : }
     239              : 
     240              : #if CHECKING_P
     241              : 
     242              : namespace selftest {
     243              : 
     244              : /* Verify that program_point::operator== works as expected.  */
     245              : 
     246              : static void
     247            4 : test_program_point_equality ()
     248              : {
     249            4 :   region_model_manager mgr;
     250              : 
     251            4 :   const supernode *snode = nullptr;
     252              : 
     253            4 :   const call_string &cs = mgr.get_empty_call_string ();
     254              : 
     255            4 :   program_point a = program_point (snode, cs);
     256            4 :   program_point b = program_point (snode, cs);
     257            4 :   ASSERT_EQ (a, b);
     258              :   // TODO: verify with non-empty callstrings, with different snodes
     259            4 : }
     260              : 
     261              : /* Run all of the selftests within this file.  */
     262              : 
     263              : void
     264            4 : analyzer_program_point_cc_tests ()
     265              : {
     266            4 :   test_program_point_equality ();
     267            4 : }
     268              : 
     269              : } // namespace selftest
     270              : 
     271              : #endif /* CHECKING_P */
     272              : 
     273              : } // namespace ana
     274              : 
     275              : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.