LCOV - code coverage report
Current view: top level - c++tools - resolver.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.3 % 119 111
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 14 14
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* C++ modules.  Experimental!  -*- c++ -*-
       2              :    Copyright (C) 2017-2026 Free Software Foundation, Inc.
       3              :    Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
       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 "config.h"
      22              : 
      23              : #include "resolver.h"
      24              : // C++
      25              : #include <algorithm>
      26              : #include <memory>
      27              : // C
      28              : #include <cstring>
      29              : // OS
      30              : #include <fcntl.h>
      31              : #include <unistd.h>
      32              : #if 0 // 1 for testing no mmap
      33              : #define MAPPED_READING 0
      34              : #else
      35              : #ifdef IN_GCC
      36              : #if HAVE_MMAP_FILE && _POSIX_MAPPED_FILES > 0
      37              : #define MAPPED_READING 1
      38              : #else
      39              : #define MAPPED_READING 0
      40              : #endif
      41              : #else
      42              : #ifdef HAVE_SYS_MMAN_H
      43              : #include <sys/mman.h>
      44              : #define MAPPED_READING 1
      45              : #else
      46              : #define MAPPED_READING 0
      47              : #endif
      48              : #endif
      49              : #endif
      50              : 
      51              : #include <sys/types.h>
      52              : #include <sys/stat.h>
      53              : 
      54              : #if !defined (IN_GCC) && !MAPPED_READING
      55              : #define xmalloc(X) malloc(X)
      56              : #endif
      57              : 
      58              : #if !HOST_HAS_O_CLOEXEC
      59              : #define O_CLOEXEC 0
      60              : #endif
      61              : 
      62              : #ifndef DIR_SEPARATOR
      63              : #define DIR_SEPARATOR '/'
      64              : #endif
      65              : 
      66         4700 : module_resolver::module_resolver (bool map, bool xlate)
      67         4700 :   : default_map (map), default_translate (xlate)
      68              : {
      69         4700 : }
      70              : 
      71         9038 : module_resolver::~module_resolver ()
      72              : {
      73         4519 :   if (fd_repo >= 0)
      74          675 :     close (fd_repo);
      75         9038 : }
      76              : 
      77              : bool
      78         4697 : module_resolver::set_repo (std::string &&r, bool force)
      79              : {
      80         4697 :   if (force || repo.empty ())
      81              :     {
      82         4697 :       repo = std::move (r);
      83         4697 :       force = true;
      84              :     }
      85         4697 :   return force;
      86              : }
      87              : 
      88              : bool
      89           27 : module_resolver::add_mapping (std::string &&module, std::string &&file,
      90              :                               bool force)
      91              : {
      92           27 :   auto res = map.emplace (std::move (module), std::move (file));
      93           27 :   if (res.second)
      94              :     force = true;
      95            0 :   else if (force)
      96            0 :     res.first->second = std::move (file);
      97              : 
      98           27 :   return force;
      99              : }
     100              : 
     101              : int
     102           24 : module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
     103              : {
     104           24 :   struct stat stat;
     105           24 :   if (fstat (fd, &stat) < 0)
     106            0 :     return -errno;
     107              : 
     108           24 :   if (!stat.st_size)
     109              :     return 0;
     110              : 
     111           24 :   void *buffer = nullptr;
     112              : #if MAPPED_READING
     113              :   // Just map the file, we're gonna read all of it, so no need for
     114              :   // line buffering
     115           24 :   buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
     116           24 :   if (buffer == MAP_FAILED)
     117            0 :     return -errno;
     118           24 :   struct Deleter {
     119           24 :     void operator()(void* p) const { munmap(p, size); }
     120              :     size_t size;
     121              :   };
     122           24 :   std::unique_ptr<void, Deleter> guard(buffer, Deleter{(size_t)stat.st_size});
     123              : #else
     124              :   buffer = xmalloc (stat.st_size);
     125              :   if (!buffer)
     126              :     return -errno;
     127              :   struct Deleter { void operator()(void* p) const { free(p); } };
     128              :   std::unique_ptr<void, Deleter> guard(buffer);
     129              :   if (read (fd, buffer, stat.st_size) != stat.st_size)
     130              :     return -errno;
     131              : #endif
     132              : 
     133           24 :   size_t prefix_len = prefix ? strlen (prefix) : 0;
     134           24 :   unsigned lineno = 0;
     135              : 
     136           75 :   for (char const *begin = reinterpret_cast <char const *> (buffer),
     137           24 :          *end = begin + stat.st_size, *eol;
     138           75 :        begin != end; begin = eol + 1)
     139              :     {
     140           54 :       lineno++;
     141           54 :       eol = std::find (begin, end, '\n');
     142           54 :       if (eol == end)
     143              :         // last line has no \n, ignore the line, you lose
     144              :         break;
     145              : 
     146           54 :       auto *pos = begin;
     147           54 :       bool pfx_search = prefix_len != 0;
     148              : 
     149              :     pfx_search:
     150           87 :       while (*pos == ' ' || *pos == '\t')
     151           15 :         pos++;
     152              : 
     153              :       auto *space = pos;
     154          411 :       while (*space != '\n' && *space != ' ' && *space != '\t')
     155          339 :         space++;
     156              : 
     157           72 :       if (pos == space)
     158              :         // at end of line, nothing here 
     159            3 :         continue;
     160              : 
     161           69 :       if (pfx_search)
     162              :         {
     163           18 :           if (size_t (space - pos) == prefix_len
     164           18 :               && std::equal (pos, space, prefix))
     165              :             pfx_search = false;
     166           18 :           pos = space;
     167           18 :           goto pfx_search;
     168              :         }
     169              : 
     170           99 :       std::string module (pos, space);
     171          177 :       while (*space == ' ' || *space == '\t')
     172           75 :         space++;
     173           99 :       std::string file (space, eol);
     174              : 
     175           51 :       if (module[0] == '$')
     176              :         {
     177           24 :           if (module == "$root")
     178           21 :             set_repo (std::move (file));
     179              :           else
     180            3 :             return lineno;
     181              :         }
     182              :       else
     183              :         {
     184           27 :           if (file.empty ())
     185            0 :             file = GetCMIName (module);
     186           27 :           add_mapping (std::move (module), std::move (file), force);
     187              :         }
     188              :     }
     189              : 
     190              :   return 0;
     191           24 : }
     192              : 
     193              : char const *
     194        24234 : module_resolver::GetCMISuffix ()
     195              : {
     196        24234 :   return "gcm";
     197              : }
     198              : 
     199              : module_resolver *
     200         4700 : module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
     201              :                                  std::string &a, std::string &i)
     202              : {
     203         4700 :   if (!version || version > Cody::Version)
     204            0 :     s->ErrorResponse ("version mismatch");
     205         4700 :   else if (a != "GCC")
     206              :     // Refuse anything but GCC
     207            0 :     ErrorResponse (s, std::string ("only GCC supported"));
     208         4700 :   else if (!ident.empty () && ident != i)
     209              :     // Failed ident check
     210            0 :     ErrorResponse (s, std::string ("bad ident"));
     211              :   else
     212              :     // Success!
     213         4700 :     s->ConnectResponse ("gcc");
     214              : 
     215         4700 :   return this;
     216              : }
     217              : 
     218              : int
     219         4700 : module_resolver::ModuleRepoRequest (Cody::Server *s)
     220              : {
     221         4700 :   s->PathnameResponse (repo);
     222         4700 :   return 0;
     223              : }
     224              : 
     225              : int
     226         5455 : module_resolver::cmi_response (Cody::Server *s, std::string &module)
     227              : {
     228         5455 :   auto iter = map.find (module);
     229         5455 :   if (iter == map.end ())
     230              :     {
     231         5431 :       std::string file = default_map ? GetCMIName (module) : std::string ();
     232         5431 :       auto res = map.emplace (module, file);
     233         5431 :       iter = res.first;
     234         5431 :     }
     235              : 
     236         5455 :   if (iter->second.empty ())
     237            3 :     s->ErrorResponse ("no such module");
     238              :   else
     239         5452 :     s->PathnameResponse (iter->second);
     240              : 
     241         5455 :   return 0;
     242              : }
     243              : 
     244              : int
     245         2813 : module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
     246              :                                       std::string &module)
     247              : {
     248         2813 :   return cmi_response (s, module);
     249              : }
     250              : 
     251              : int
     252         2642 : module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
     253              :                                       std::string &module)
     254              : {
     255         2642 :   return cmi_response (s, module);
     256              : }
     257              : 
     258              : int
     259        19086 : module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
     260              :                                           std::string &include)
     261              : {
     262        19086 :   auto iter = map.find (include);
     263        19086 :   if (iter == map.end () && default_translate)
     264              :     {
     265              :       // Not found, look for it
     266        18806 :       auto file = GetCMIName (include);
     267        18806 :       struct stat statbuf;
     268        18806 :       bool ok = true;
     269              : 
     270              : #if HAVE_FSTATAT
     271        18806 :       int fd_dir = AT_FDCWD;
     272        18806 :       if (!repo.empty ())
     273              :         {
     274        18806 :           if (fd_repo == -1)
     275              :             {
     276          702 :               fd_repo = open (repo.c_str (),
     277              :                               O_RDONLY | O_CLOEXEC | O_DIRECTORY);
     278          702 :               if (fd_repo < 0)
     279            5 :                 fd_repo = -2;
     280              :             }
     281        18806 :           fd_dir = fd_repo;
     282              :         }
     283              : 
     284        18806 :       if (!repo.empty () && fd_repo < 0)
     285              :         ok = false;
     286        18442 :       else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
     287        18442 :                || !S_ISREG (statbuf.st_mode))
     288              :         ok = false;
     289              : #else
     290              :       auto append = repo;
     291              :       append.push_back (DIR_SEPARATOR);
     292              :       append.append (file);
     293              :       if (stat (append.c_str (), &statbuf) < 0
     294              :           || !S_ISREG (statbuf.st_mode))
     295              :         ok = false;
     296              : #endif
     297              :       if (!ok)
     298              :         // Mark as not present
     299        18763 :         file.clear ();
     300        18806 :       auto res = map.emplace (include, file);
     301        18806 :       iter = res.first;
     302        18806 :     }
     303              : 
     304        19086 :   if (iter == map.end () || iter->second.empty ())
     305        19043 :     s->BoolResponse (false);
     306              :   else
     307           43 :     s->PathnameResponse (iter->second);
     308              : 
     309        19086 :   return 0;
     310              : }
     311              : 
     312              : /* This handles a client notification to the server that a CMI has been
     313              :    produced for a module.  For this simplified server, we just accept
     314              :    the transaction and respond with "OK".  */
     315              : 
     316              : int
     317         2612 : module_resolver::ModuleCompiledRequest (Cody::Server *s, Cody::Flags,
     318              :                                       std::string &)
     319              : {
     320         2612 :   s->OKResponse();
     321         2612 :   return 0;
     322              : }
        

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.