1
0

Merge pull request #3391 from cuberite/ApiCheckTypes

APIDump: Check param and return types.
This commit is contained in:
Mattes D 2016-10-04 12:36:47 +02:00 committed by GitHub
commit 0b08911286
4 changed files with 204 additions and 59 deletions

View File

@ -3706,7 +3706,12 @@ end
},
Clear =
{
Returns = "self",
Returns =
{
{
Type = "self",
},
},
Notes = "Removes all parts from this object",
},
constructor =
@ -6080,8 +6085,16 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
},
Notes = "Returns true if the potion with the given damage is drinkable",
},
},
},
}, -- Functions
ConstantGroups =
{
eType =
{
Include = { "eff.*" },
},
}, -- ConstantGroups
}, -- cEntityEffect
cFile =
{
Desc = [[
@ -10248,7 +10261,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "MobType",
Type = "Globals#MobType",
Type = "Globals#eMonsterType",
},
},
Returns =
@ -11075,7 +11088,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "GameMode",
Type = "Globals#GameMode",
Type = "Globals#eGameMode",
},
},
Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead.",
@ -11175,7 +11188,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "GameMode",
Type = "Globals#GameMode",
Type = "Globals#eGameMode",
},
},
Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically.",
@ -11763,7 +11776,7 @@ a_Player:OpenWindow(Window);
},
{
Name = "World",
Type = "cWorld*",
Type = "cWorld",
IsOptional = true,
},
},
@ -11896,7 +11909,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "NewGameMode",
Type = "Globals#GameMode",
Type = "Globals#eGameMode",
},
},
Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit.",
@ -14242,8 +14255,17 @@ end
{
Notes = "A workbench (crafting table) window",
},
},
},
}, -- Constants
ConstantGroups =
{
WindowType =
{
Include = { "wt.*" },
}
}, -- ConstantGroups
}, -- cWindow
cWorld =
{
Desc = [[
@ -15865,10 +15887,10 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i
Returns =
{
{
Type = "cScoreBoard",
Type = "cScoreboard",
},
},
Notes = "Returns the {{cScoreBoard|ScoreBoard}} object used by this world. ",
Notes = "Returns the {{cScoreboard|Scoreboard}} object used by this world. ",
},
GetSeed =
{
@ -18235,7 +18257,7 @@ World:ForEachEntity(
{
{
Name = "BiomeType",
Type = "Globals#BiomeTypes",
Type = "Globals#EMCSBiome",
},
},
Notes = "Converts a string representation to a {{Globals#BiomeTypes|BiomeType}} enumerated value. Returns biInvalidBiome if the input is not a recognized biome.",
@ -18253,7 +18275,7 @@ World:ForEachEntity(
{
{
Name = "DamageType",
Type = "Globals#DamageType",
Type = "Globals#eDamageType",
},
},
Notes = "Converts a string representation to a {{Globals#DamageType|DamageType}} enumerated value. Returns -1 if the inupt is not a recognized damage type.",
@ -18271,10 +18293,10 @@ World:ForEachEntity(
{
{
Name = "Dimension",
Type = "Globals#WorldDimension",
Type = "Globals#eDimension",
},
},
Notes = "Converts a string representation to a {{Globals#WorldDimension|Dimension}} enumerated value. Returns dimNotSet if the input is not a recognized dimension.",
Notes = "Converts a string representation to a {{Globals#eDimension|eDimension}} enumerated value. Returns dimNotSet if the input is not a recognized dimension.",
},
StringToItem =
{
@ -18310,10 +18332,10 @@ World:ForEachEntity(
{
{
Name = "MobType",
Type = "Globals#MobType",
Type = "eMonsterType",
},
},
Notes = "(<b>DEPRECATED!</b>) Please use cMonster:StringToMobType(). Converts a string representation to a {{Globals#MobType|MobType}} enumerated value",
Notes = "(<b>DEPRECATED!</b>) Please use cMonster:StringToMobType(). Converts a string representation to an {{Globals#eMonsterType|eMonsterType}} enumerated value",
},
StripColorCodes =
{
@ -18688,6 +18710,14 @@ World:ForEachEntity(
on the message's type.
]],
},
eMobHeadType =
{
Include = "SKULL_TYPE_.*",
},
eMobHeadRotation =
{
Include = "SKULL_ROTATION_.*",
},
eMonsterType =
{
Include =

View File

@ -1254,7 +1254,7 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
{
{
Name = "MobType",
Type = "Globals#MobType",
Type = "eMonsterType",
},
},
Notes = "Returns the entity type that will be spawn by this mob spawner.",
@ -1306,7 +1306,7 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
{
{
Name = "MobType",
Type = "Globals#MobType",
Type = "eMonsterType",
},
},
Notes = "Sets the type of the mob that will be spawned by this mob spawner.",

View File

@ -96,8 +96,8 @@ return
Params =
{
{
Name = "HTTPRequest",
Type = "Request",
Name = "Request",
Type = "HTTPRequest",
},
},
Returns =

View File

@ -1816,43 +1816,12 @@ end
local function HandleWebAdminDump(a_Request)
if (a_Request.PostParams["Dump"] ~= nil) then
DumpApi()
end
return
[[
<p>Pressing the button will generate the API dump on the server. Note that this can take some time.</p>
<form method="POST"><input type="submit" name="Dump" value="Dump the API"/></form>
]]
end
local function HandleCmdApi(a_Split)
DumpApi()
return true
end
local function HandleCmdApiShow(a_Split, a_EntireCmd)
os.execute("API" .. cFile:GetPathSeparator() .. "index.html")
return true, "Launching the browser to show the API docs..."
end
local function HandleCmdApiCheck(a_Split, a_EntireCmd)
--- Checks the currently undocumented symbols against an "official" undocumented symbol list
-- Returns an array-table of strings representing the newly-undocumented symbol names
local function CheckNewUndocumentedSymbols()
-- Download the official API stats on undocumented stuff:
-- (We need a blocking downloader, which is impossible with the current cNetwork API)
assert(os.execute("wget -O official_undocumented.lua http://apidocs.cuberite.org/_undocumented.lua"))
assert(os.execute("wget -q -O official_undocumented.lua http://apidocs.cuberite.org/_undocumented.lua"))
local OfficialStats = cFile:ReadWholeFile("official_undocumented.lua")
if (OfficialStats == "") then
return true, "Cannot load official stats"
@ -1916,7 +1885,7 @@ local function HandleCmdApiCheck(a_Split, a_EntireCmd)
-- Bail out if no items found:
if not(res[1]) then
return true, "No new undocumented functions"
return
end
-- Save any found items to a file:
@ -1925,7 +1894,153 @@ local function HandleCmdApiCheck(a_Split, a_EntireCmd)
f:write("\n")
f:close()
return true, "Newly undocumented items: " .. #res .. "\n" .. table.concat(res, "\n")
return res
end
--- Checks the API description for unknown types listed in Params or Returns
-- Returns an array-table of { Location = "cClass:function(), param #1", Type = "UnknownType" }
-- Returns nil if no unknown types are found
local function CheckBadTypes()
-- Load the API and preprocess known types:
local api = PrepareApi()
local knownTypes =
{
string = true,
number = true,
boolean = true,
any = true,
self = true,
table = true,
["function"] = true,
["..."] = true,
["SQLite DB object"] = true,
["<unknown>"] = true, -- Allow "<unknown>" types, for now, until the API is properly documented
}
for _, clsDesc in ipairs(api) do
knownTypes[clsDesc.Name] = true -- The class is a known type
for grpName, _ in pairs(clsDesc.ConstantGroups or {}) do -- All class' enums are known types (with namespacing)
knownTypes[clsDesc.Name .. "#" .. grpName] = true
end
if (clsDesc.Name == "Globals") then
for grpName, _ in pairs(clsDesc.ConstantGroups or {}) do -- All Globals' enums are known types without namespacing, too
knownTypes[grpName] = true
end
end
end -- for cls - classes
-- Check types:
local res = {}
for _, clsDesc in ipairs(api) do
for _, fnDesc in ipairs(clsDesc.Functions or {}) do
local fnName = fnDesc.Name
local fn = fnDesc[1] and fnDesc or { fnDesc } -- Unify the format, fn is an array of function signatures
for idxS, signature in ipairs(fn) do
for idxP, param in ipairs(signature.Params or {}) do
if not(knownTypes[param.Type]) then
table.insert(res, {
Location = string.format("%s:%s(), signature #%d, param #%d", clsDesc.Name, fnName, idxS, idxP),
Type = param.Type,
})
end
end -- for param
if (type(signature.Returns) == "table") then
for idxR, ret in ipairs(signature.Returns) do
if not(knownTypes[ret.Type]) then
table.insert(res, {
Location = string.format("%s:%s(), signature #%d, return #%d", clsDesc.Name, fnName, idxS, idxR),
Type = ret.Type,
})
end
end -- for ret
elseif not(signature.Returns) then
else
table.insert(res, {
Location = string.format("%s:%s(), signature #%d, return string", clsDesc.Name, fnName, idxS),
Type = tostring(signature.Returns),
})
end
end -- for signature
end -- for fn - functions
end -- for cls - classes
-- If no problems found, bail out:
if not(res[1]) then
return
end
-- Write the problems into a file:
local f = io.open("UnknownTypes.lua", "w")
f:write("return\n{\n")
for _, item in ipairs(res) do
f:write("\t{ ", string.format("{ Location = %q, Type = %q", item.Location, item.Type), "},\n")
end
f:write("}\n")
f:close()
return res
end
local function HandleWebAdminDump(a_Request)
if (a_Request.PostParams["Dump"] ~= nil) then
DumpApi()
end
return
[[
<p>Pressing the button will generate the API dump on the server. Note that this can take some time.</p>
<form method="POST"><input type="submit" name="Dump" value="Dump the API"/></form>
]]
end
local function HandleCmdApi(a_Split)
DumpApi()
return true
end
local function HandleCmdApiShow(a_Split, a_EntireCmd)
os.execute("API" .. cFile:GetPathSeparator() .. "index.html")
return true, "Launching the browser to show the API docs..."
end
local function HandleCmdApiCheck(a_Split, a_EntireCmd)
-- Check the Params and Returns types:
LOG("Checking API for bad types...")
local badTypes = CheckBadTypes()
if (badTypes) then
-- Serialize into descriptions:
local descs = {}
for idx, t in ipairs(badTypes) do
descs[idx] = string.format("Location %q, type %q", t.Location, t.Type)
end
return true, "Found bad types:\n" .. table.concat(descs, "\n")
end
-- Check for new symbols that are not documented:
LOG("Checking API for newly undocumented symbols...")
local newUndocumented = CheckNewUndocumentedSymbols()
if (newUndocumented) then
return true, "Found new undocumented symbols:\n" .. table.concat(newUndocumented, "\n")
end
return true, "API check completed successfully"
end