diff libinterp/corefcn/load-path.cc @ 28026:262cdfc6faf9

allow reloading of handles to private functions (bug #57439) To allow a handle to a private function to reload the function it references after the function has been cleared and/or when the directory where the function was defined is no longer in the load path, store the directory in the symbol scope for the function, not just in the function itself. Also use the canonical directory name as the key for the private_function map in the load path. * fcn-info.cc (fcn_info::fcn_info_rep::load_private_function): Use canonical directory name as key in private_functions map. (fcn_info::fcn_info_rep::xfind): Get function file and directory names directly from the search scope. (fcn_info::fcn_info_rep::x_builtin_find): Likewise. * load-path.h, load-path.cc (load_path::M_FILE, load_path::OCT_FILE, load_path::MEX_FILE): Now public. (find_private_fcn_file): New static function. (load_path::package_info::remove): Use canonical directory name as key for private function map. (load_path::package_info::add_to_private_fcn_map): Likewise. (load_path::package_info::add_to_method_map): Likewise. (load_path::package_info::remove_private_fcn_map): Likewise. (load_path::package_info::find_private_fcn): Likewise. If function is not found in map, search filesystem. * symscope.h, symscope.cc (symbol_scope_rep::m_fcn_file_name, symbol_scope_rep::m_dir_name): New data members. (symbol_scope::dup): Copy them. (symbol_scope::cache_fcn_file_name, symbol_scope::cache_dir_name, symbol_scope::fcn_file_name, symbol_scope::dir_name, symbol_scope_rep::cache_fcn_file_name, symbol_scope_rep::cache_dir_name, symbol_scope_rep::fcn_file_name, symbol_scope_rep::dir_name): New functions. * oct-parse.yy (base_parser::make_script): Also cache file and directory names in script scope. (base_parser::finish_function): Also cache file and directory names in function scope. * pt-fcn-handle.cc (tree_anon_fcn_handle::evaluate): Also cache file and directory names in new scope associated with the anonymous function object.
author John W. Eaton <jwe@octave.org>
date Thu, 30 Jan 2020 15:12:52 -0500
parents b018f553fd85
children e760fef2829c
line wrap: on
line diff
--- a/libinterp/corefcn/load-path.cc	Wed Jan 29 08:20:55 2020 -0800
+++ b/libinterp/corefcn/load-path.cc	Thu Jan 30 15:12:52 2020 -0500
@@ -185,6 +185,46 @@
     return retval;
   }
 
+  static std::string find_private_fcn_file (const std::string& dir,
+                                            const std::string& fcn,
+                                            int type)
+  {
+    std::string nm
+      = sys::file_ops::concat (sys::file_ops::concat (dir, "private"), fcn);
+
+    if (type & load_path::OCT_FILE)
+      {
+        std::string fnm = nm + ".oct";
+
+        sys::file_stat fs (fnm);
+
+        if (fs.exists () && fs.is_reg ())
+          return fnm;
+      }
+
+    if (type & load_path::MEX_FILE)
+      {
+        std::string fnm = nm + ".mex";
+
+        sys::file_stat fs (fnm);
+
+        if (fs.exists () && fs.is_reg ())
+          return fnm;
+      }
+
+    if (type & load_path::M_FILE)
+      {
+        std::string fnm = nm + ".m";
+
+        sys::file_stat fs (fnm);
+
+        if (fs.exists () && fs.is_reg ())
+          return fnm;
+      }
+
+    return "";
+  }
+
   // True if a path is contained in a path list separated by path_sep_char
 
   static bool
@@ -1525,7 +1565,7 @@
 
     remove_fcn_map (dir, fcn_files);
 
-    remove_private_fcn_map (dir);
+    remove_private_fcn_map (sys::canonicalize_file_name (dir));
 
     remove_method_map (dir);
   }
@@ -1656,25 +1696,28 @@
     std::string retval;
 
     //  update ();
-
-    const_private_fcn_map_iterator q = private_fcn_map.find (dir);
+    std::string canon_dir = sys::canonicalize_file_name (dir);
+
+    const_private_fcn_map_iterator q = private_fcn_map.find (canon_dir);
 
     if (q != private_fcn_map.end ())
       {
-        const dir_info::fcn_file_map_type& m = q->second;
-
-        dir_info::const_fcn_file_map_iterator p = m.find (fcn);
-
-        if (p != m.end ())
+        const dir_info::fcn_file_map_type& fcn_file_map = q->second;
+
+        dir_info::const_fcn_file_map_iterator p = fcn_file_map.find (fcn);
+
+        if (p != fcn_file_map.end ())
           {
             std::string fname
-              = sys::file_ops::concat (sys::file_ops::concat (dir, "private"), fcn);
+              = sys::file_ops::concat (sys::file_ops::concat (canon_dir, "private"), fcn);
 
             if (check_file_type (fname, type, p->second, fcn,
                                  "load_path::find_private_fcn"))
               retval = fname;
           }
       }
+    else
+      retval = find_private_fcn_file (canon_dir, fcn, type);
 
     return retval;
   }
@@ -1892,7 +1935,8 @@
     dir_info::fcn_file_map_type private_file_map = di.private_file_map;
 
     if (! private_file_map.empty ())
-      private_fcn_map[di.dir_name] = private_file_map;
+      private_fcn_map[sys::canonicalize_file_name (di.dir_name)]
+        = private_file_map;
   }
 
   void
@@ -1955,7 +1999,8 @@
         dir_info::fcn_file_map_type private_file_map = ci.private_file_map;
 
         if (! private_file_map.empty ())
-          private_fcn_map[full_dir_name] = private_file_map;
+          private_fcn_map[sys::canonicalize_file_name (full_dir_name)]
+            = private_file_map;
       }
   }
 
@@ -2094,7 +2139,7 @@
   void
   load_path::package_info::remove_private_fcn_map (const std::string& dir)
   {
-    auto p = private_fcn_map.find (dir);
+    auto p = private_fcn_map.find (sys::canonicalize_file_name (dir));
 
     if (p != private_fcn_map.end ())
       private_fcn_map.erase (p);