From 49509d2f746b7a8d50e685cfd0e0b391676b9466 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sun, 1 Jul 2018 12:31:49 +0200 Subject: Log deprecated Lua function calls (#7491) --- src/script/lua_api/l_base.cpp | 79 +++++++++++++++++++++++++++++++++++++++++ src/script/lua_api/l_base.h | 8 +++++ src/script/lua_api/l_noise.cpp | 6 ++-- src/script/lua_api/l_noise.h | 4 +-- src/script/lua_api/l_object.cpp | 3 +- src/script/lua_api/l_object.h | 3 +- 6 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp index b401db05a..784b197e1 100644 --- a/src/script/lua_api/l_base.cpp +++ b/src/script/lua_api/l_base.cpp @@ -21,7 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_internal.h" #include "cpp_api/s_base.h" #include "content/mods.h" +#include "profiler.h" #include "server.h" +#include #include ScriptApiBase *ModApiBase::getScriptApiBase(lua_State *L) @@ -85,3 +87,80 @@ bool ModApiBase::registerFunction(lua_State *L, const char *name, return true; } + +std::unordered_map ModApiBase::m_deprecated_wrappers; +bool ModApiBase::m_error_deprecated_calls = false; + +int ModApiBase::l_deprecated_function(lua_State *L) +{ + thread_local std::vector deprecated_logged; + + u64 start_time = porting::getTimeUs(); + lua_Debug ar; + + // Get function name for lookup + FATAL_ERROR_IF(!lua_getstack(L, 0, &ar), "lua_getstack() failed"); + FATAL_ERROR_IF(!lua_getinfo(L, "n", &ar), "lua_getinfo() failed"); + + // Combine name with line and script backtrace + FATAL_ERROR_IF(!lua_getstack(L, 1, &ar), "lua_getstack() failed"); + FATAL_ERROR_IF(!lua_getinfo(L, "Sl", &ar), "lua_getinfo() failed"); + + // Get parent class to get the wrappers map + luaL_checktype(L, 1, LUA_TUSERDATA); + void *ud = lua_touserdata(L, 1); + ModApiBase *o = *(ModApiBase**)ud; + + // New function and new function name + auto it = o->m_deprecated_wrappers.find(ar.name); + + // Get backtrace and hash it to reduce the warning flood + std::string backtrace = ar.short_src; + backtrace.append(":").append(std::to_string(ar.currentline)); + u64 hash = murmur_hash_64_ua(backtrace.data(), backtrace.length(), 0xBADBABE); + + if (std::find(deprecated_logged.begin(), deprecated_logged.end(), hash) + == deprecated_logged.end()) { + + deprecated_logged.emplace_back(hash); + warningstream << "Call to deprecated function '" << ar.name << "', please use '" + << it->second.name << "' at " << backtrace << std::endl; + + if (m_error_deprecated_calls) + script_error(L, LUA_ERRRUN, NULL, NULL); + } + + u64 end_time = porting::getTimeUs(); + g_profiler->avg("l_deprecated_function", end_time - start_time); + + return it->second.func(L); +} + +void ModApiBase::markAliasDeprecated(luaL_Reg *reg) +{ + std::string value = g_settings->get("deprecated_lua_api_handling"); + m_error_deprecated_calls = value == "error"; + + if (!m_error_deprecated_calls && value != "log") + return; + + const char *last_name = nullptr; + lua_CFunction last_func = nullptr; + + // ! Null termination ! + while (reg->func) { + if (last_func == reg->func) { + // Duplicate found + std::pair entry( + reg->name, + { .name = last_name, .func = reg->func } + ); + m_deprecated_wrappers.emplace(entry); + reg->func = l_deprecated_function; + } + + last_func = reg->func; + last_name = reg->name; + ++reg; + } +} diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h index 12c1a86cc..b46b5b567 100644 --- a/src/script/lua_api/l_base.h +++ b/src/script/lua_api/l_base.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_internal.h" #include "common/helper.h" #include "gamedef.h" +#include extern "C" { #include @@ -70,4 +71,11 @@ public: const char* name, lua_CFunction func, int top); + + static int l_deprecated_function(lua_State *L); + static void markAliasDeprecated(luaL_Reg *reg); +private: + // = { , } + static std::unordered_map m_deprecated_wrappers; + static bool m_error_deprecated_calls; }; diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index d382ca3bd..ac3ddd479 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -122,6 +122,7 @@ void LuaPerlinNoise::Register(lua_State *L) lua_pop(L, 1); + markAliasDeprecated(methods); luaL_openlib(L, 0, methods, 0); lua_pop(L, 1); @@ -130,7 +131,7 @@ void LuaPerlinNoise::Register(lua_State *L) const char LuaPerlinNoise::className[] = "PerlinNoise"; -const luaL_Reg LuaPerlinNoise::methods[] = { +luaL_Reg LuaPerlinNoise::methods[] = { luamethod_aliased(LuaPerlinNoise, get_2d, get2d), luamethod_aliased(LuaPerlinNoise, get_3d, get3d), {0,0} @@ -380,6 +381,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L) lua_pop(L, 1); + markAliasDeprecated(methods); luaL_openlib(L, 0, methods, 0); lua_pop(L, 1); @@ -388,7 +390,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L) const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap"; -const luaL_Reg LuaPerlinNoiseMap::methods[] = { +luaL_Reg LuaPerlinNoiseMap::methods[] = { luamethod_aliased(LuaPerlinNoiseMap, get_2d_map, get2dMap), luamethod_aliased(LuaPerlinNoiseMap, get_2d_map_flat, get2dMap_flat), luamethod_aliased(LuaPerlinNoiseMap, calc_2d_map, calc2dMap), diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h index 13e668507..9f50dfd3f 100644 --- a/src/script/lua_api/l_noise.h +++ b/src/script/lua_api/l_noise.h @@ -31,7 +31,7 @@ class LuaPerlinNoise : public ModApiBase private: NoiseParams np; static const char className[]; - static const luaL_Reg methods[]; + static luaL_Reg methods[]; // Exported functions @@ -63,7 +63,7 @@ class LuaPerlinNoiseMap : public ModApiBase Noise *noise; bool m_is3d; static const char className[]; - static const luaL_Reg methods[]; + static luaL_Reg methods[]; // Exported functions diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index b6f37d51b..1ea7d7ff2 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1815,6 +1815,7 @@ void ObjectRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable + markAliasDeprecated(methods); luaL_openlib(L, 0, methods, 0); // fill methodtable lua_pop(L, 1); // drop methodtable @@ -1823,7 +1824,7 @@ void ObjectRef::Register(lua_State *L) } const char ObjectRef::className[] = "ObjectRef"; -const luaL_Reg ObjectRef::methods[] = { +luaL_Reg ObjectRef::methods[] = { // ServerActiveObject luamethod(ObjectRef, remove), luamethod_aliased(ObjectRef, get_pos, getpos), diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 76b8bc4a4..6876ea512 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -50,9 +50,8 @@ public: static ServerActiveObject* getobject(ObjectRef *ref); private: ServerActiveObject *m_object = nullptr; - static const char className[]; - static const luaL_Reg methods[]; + static luaL_Reg methods[]; static LuaEntitySAO* getluaobject(ObjectRef *ref); -- cgit v1.2.3