Add the ability to have formally deprecated functions.

Functions which are deprecated will print out a message and show up in a small dialog on-screen, when they're first called. Deprecation output is disabled in fused mode by default, and can be modified with love.setDeprecationOutput(enable).

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2017-08-27 13:46:31 -03:00
parent 324ef8f690
commit de28c6e6a8
16 changed files with 542 additions and 10 deletions
+8
View File
@@ -21,6 +21,7 @@
// LOVE
#include "Module.h"
#include "Exception.h"
#include "deprecation.h"
// std
#include <map>
@@ -61,6 +62,11 @@ namespace love
love::Type Module::type("Module", &Object::type);
Module *Module::instances[] = {};
Module::Module()
{
initDeprecation();
}
Module::~Module()
{
ModuleRegistry &registry = registryInstance();
@@ -83,6 +89,8 @@ Module::~Module()
}
freeEmptyRegistry();
deinitDeprecation();
}
void Module::registerInstance(Module *instance)
+1
View File
@@ -59,6 +59,7 @@ public:
M_MAX_ENUM
};
Module();
virtual ~Module();
/**
+157
View File
@@ -0,0 +1,157 @@
/**
* Copyright (c) 2006-2017 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "common/config.h"
#include "deprecation.h"
#include "thread/threads.h"
#include <atomic>
#include <map>
namespace love
{
static std::map<std::string, DeprecationInfo> deprecated;
static std::vector<const DeprecationInfo *> deprecatedList;
static std::atomic<int> initCount;
static thread::Mutex *mutex = nullptr;
static bool outputEnabled = false;
void initDeprecation()
{
if (initCount.fetch_add(1) == 0)
mutex = thread::newMutex();
}
void deinitDeprecation()
{
if (initCount.fetch_sub(1) == 1)
{
deprecatedList.clear();
deprecated.clear();
delete mutex;
mutex = nullptr;
}
}
static void printDeprecationNotice(const DeprecationInfo &info)
{
std::string notice = getDeprecationNotice(info, true);
printf("LOVE - Warning: %s\n", notice.c_str());
}
void setDeprecationOutputEnabled(bool enable)
{
if (enable == outputEnabled)
return;
outputEnabled = enable;
if (enable)
{
GetDeprecated deprecated;
for (const DeprecationInfo *info : deprecated.all)
{
if (info->uses == 1)
printDeprecationNotice(*info);
}
}
}
std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere)
{
std::string notice;
if (usewhere)
notice += info.where;
notice += "Using deprecated function " + info.name;
if (info.type == DEPRECATED_REPLACEMENT && !info.replacement.empty())
notice += " (replaced by " + info.replacement + ")";
else if (info.type == DEPRECATED_RENAMED && !info.replacement.empty())
notice += " (renamed to " + info.replacement + ")";
return notice;
}
GetDeprecated::GetDeprecated()
: all(deprecatedList)
{
if (mutex != nullptr)
mutex->lock();
}
GetDeprecated::~GetDeprecated()
{
if (mutex != nullptr)
mutex->unlock();
}
MarkDeprecated::MarkDeprecated(const char *name)
: MarkDeprecated(name, DEPRECATED_NO_REPLACEMENT, nullptr)
{
}
MarkDeprecated::MarkDeprecated(const char *name, DeprecationType type, const char *replacement)
: info(nullptr)
{
if (mutex != nullptr)
mutex->lock();
auto it = deprecated.find(name);
if (it != deprecated.end())
{
it->second.uses++;
info = &it->second;
}
else
{
DeprecationInfo newinfo = {};
newinfo.type = type;
newinfo.uses = 1;
newinfo.name = name;
if (replacement != nullptr)
newinfo.replacement = replacement;
auto inserted = deprecated.insert(std::make_pair(newinfo.name, newinfo));
info = &inserted.first->second;
deprecatedList.push_back(info);
}
}
MarkDeprecated::~MarkDeprecated()
{
if (outputEnabled && info != nullptr && info->uses == 1)
printDeprecationNotice(*info);
if (mutex != nullptr)
mutex->unlock();
}
} // love
+72
View File
@@ -0,0 +1,72 @@
/**
* Copyright (c) 2006-2017 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#pragma once
#include "int.h"
#include <string>
#include <vector>
namespace love
{
enum DeprecationType
{
DEPRECATED_NO_REPLACEMENT,
DEPRECATED_REPLACEMENT,
DEPRECATED_RENAMED,
};
struct DeprecationInfo
{
DeprecationType type;
int64 uses;
std::string name;
std::string replacement;
std::string where;
};
void initDeprecation();
void deinitDeprecation();
void setDeprecationOutputEnabled(bool enable);
bool isDeprecationOutputEnabled();
std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere);
struct GetDeprecated
{
GetDeprecated();
~GetDeprecated();
const std::vector<const DeprecationInfo *> &all;
};
struct MarkDeprecated
{
MarkDeprecated(const char *name);
MarkDeprecated(const char *name, DeprecationType type, const char *replacement);
~MarkDeprecated();
DeprecationInfo *info;
};
} // love
+19
View File
@@ -786,6 +786,25 @@ lua_State *luax_getpinnedthread(lua_State *L)
return thread;
}
void luax_markdeprecated(lua_State *L, const char *name)
{
luax_markdeprecated(L, name, DEPRECATED_NO_REPLACEMENT, nullptr);
}
void luax_markdeprecated(lua_State *L, const char *name, DeprecationType type, const char *replacement)
{
MarkDeprecated deprecated(name, type, replacement);
if (deprecated.info != nullptr && deprecated.info->uses == 1)
{
luaL_where(L, 1);
const char *where = lua_tostring(L, -1);
if (where != nullptr)
deprecated.info->where = where;
lua_pop(L, 1);
}
}
extern "C" int luax_typerror(lua_State *L, int narg, const char *tname)
{
int argtype = lua_type(L, narg);
+8
View File
@@ -23,6 +23,7 @@
// LOVE
#include "types.h"
#include "deprecation.h"
// Lua
extern "C" {
@@ -447,6 +448,13 @@ lua_State *luax_insistpinnedthread(lua_State *L);
**/
lua_State *luax_getpinnedthread(lua_State *L);
/**
* Mark a function as deprecated. Should only be called inside wrapper function
* code.
**/
void luax_markdeprecated(lua_State *L, const char *name);
void luax_markdeprecated(lua_State *L, const char *name, DeprecationType type, const char *replacement);
extern "C" { // Also called from luasocket
int luax_typerror(lua_State *L, int narg, const char *tname);
}