Module:ClangDiags
Jump to navigation
Jump to search
- Module:ClangDiags/DiagsData holds diagnostic data
- Module:ClangDiags/GroupsData holds group data
local p = {}
local clangVersion = '17.0.6'
local diagsData = require('Module:ClangDiags/DiagsData')
local groupsData = require('Module:ClangDiags/GroupsData')
local diagsLongDataIdx = require('Module:ClangDiags/DiagsLongDataIdx')
local function getLongDiagData(id)
for _, idx in ipairs(diagsLongDataIdx) do
if idx.start <= id and id <= idx['end'] then
--error("getLongDiagData " .. id .. ' Module:ClangDiags/DiagsLongData' .. idx.file)
local data = require('Module:ClangDiags/DiagsLongData' .. idx.file)
local diag = data[id]
for k, v in pairs(diagsData[id]) do
diag[k] = v
end
return diag
end
end
end
local function escapeSpecialChars(text)
local replacements = {
['%['] = "[",
['%]'] = "]",
['%%'] = "%",
['{'] = "{",
['}'] = "}",
['%|'] = "|",
}
-- Iterate over all replacements and perform the substitutions
for original, replacement in pairs(replacements) do
text = text:gsub(original, replacement)
end
return text
end
local function formatInlineCode(text)
return '<code>' .. escapeSpecialChars(text) .. '</code>'
end
local function formatGroupLink(g, defaultactive)
local eltext = 'element'
if (g.count ~= 1) then
eltext = eltext .. 's'
end
local flag = g.flag
if defaultactive then
flag = g.flagoff
end
return string.format('[[Clang:Flag/%s|%s]] (%d %s)', g.flag, flag, g.count, eltext)
end
local function getStyle(prefix)
local style = {};
style.prefix = "color: #007bfd; font-weight: bolder;"
style.message = "color: #007bfd; font-weight: bolder;"
if prefix == "error: " or prefix == "fatal error: " then
style.prefix = "color: #A00; font-weight: bolder;"
elseif prefix == "warning: " then
style.prefix = "color: #A0A; font-weight: bolder;"
elseif prefix == "note: " then
style.prefix = "color: #000; font-weight: bolder;"
style.message = "color: #007bfd;"
elseif prefix == "remark: " then
style.prefix = "color: #00A; font-weight: bolder;"
end
return style
end
-- Function to detect diagnostic type and format message
local function formatMessage(message)
local formattedMessage = message
local keywords = {"fatal error: ", "error: ", "warning: ", "note: ", "remark: "}
for _, type in ipairs(keywords) do
local startIdx, endIdx = string.find(message, type)
if endIdx then
local prefix = string.sub(message, 1, startIdx-1)
local mainText = string.sub(message, endIdx)
local style = getStyle(type)
formattedMessage = string.format("<span style=\"%s\">%s<span style=\"%s\">%s</span>%s</span>", style.message, prefix, style.prefix, type, escapeSpecialChars(mainText))
break
end
end
return formattedMessage
end
local function formatHierarchical(message, vert)
if type(message) == 'string' then
if message == "" then
return " \n"
else
return escapeSpecialChars(message) .. '\n'
end
end
wiki = ''
if vert then
wiki = wiki .. '\n{| border=0 style="margin: -3px;"\n'
for no, part in ipairs(message) do
if no ~= 1 then
wiki = wiki .. '|-\n'
wiki = wiki .. '| style="padding: 0 5px; border-top: 2px solid;" | ' .. formatHierarchical(part, false)
else
wiki = wiki .. '| style="padding: 0 5px;" | ' .. formatHierarchical(part, false)
end
end
wiki = wiki .. '|}\n'
else
wiki = wiki .. '\n{| border=0 style="margin: -3px;"\n'
for _, part in ipairs(message) do
wiki = wiki .. '| ' .. formatHierarchical(part, true)
end
wiki = wiki .. '|}\n'
end
return wiki
end
local function formatHierarchicalPrefix(prefix, message, prefix2)
local style = getStyle(prefix)
prefix = (prefix2 or "") .. string.format('<span style="%s">%s</span>', style.prefix, prefix)
if type(message) == 'string' then
message = prefix .. message
else
table.insert(message, 1, prefix)
message = formatHierarchical(message)
end
return string.format('<span style="%s">%s</span>', style.message, message)
end
local function formatHierarchicalPrefix2(val)
return formatHierarchicalPrefix('error: ', val)
end
local function formatMultiVersion(last, first)
local str
if first == nil and last == nil then
return ''
elseif first == nil and last ~= nil then
str = string.format('until %s', last)
elseif first ~= nil and last == nil then
str = string.format('since %s', first)
elseif first == last then
str = string.format('%s', first)
else
str = string.format('%s - %s', first, last)
end
return string.format(' <span style="color: green; font-size: 0.8em;">(%s)</span>', str)
end
local function formatMultiVersionValues(vervals, func)
if type(vervals) == 'string' then
return func(vervals)
end
wiki = ''
for no,verval in ipairs(vervals) do
if no ~= 1 then
wiki = wiki .. "<br>"
end
wiki = wiki .. func(verval[3]) .. formatMultiVersion(verval[1], verval[2])
end
return wiki
end
local function getLatestMultiVersionValue(vervals)
if type(vervals) == 'string' then
return vervals
else
return vervals[1][3]
end
end
function p.createTable(frame)
-- Start of the wiki table
local wikitable = '{| class="wikitable sortable"\n'
wikitable = wikitable .. '! Id || Type || Title \n'
local counter = 0 -- Initialize counter
for id, diag in pairs(diagsData) do
if counter >= 100 then -- Check if counter has reached 1000
break -- Stop the loop
end
wikitable = wikitable .. '|-\n'
wikitable = wikitable .. string.format('| [[Clang:Diag/%s|%s]] || %s || %s\n', id, id, diag.type, diag.title)
counter = counter + 1 -- Increment counter
end
-- End of the table
wikitable = wikitable .. '\n|}'
return wikitable
end
function p.createInfo(frame)
local id = frame.args.id
local diag = getLongDiagData(id)
local wiki = ''
local title = diag.prefix .. diag.title
local hierarchical = diag.hierarchical or diag.title
frame:preprocess(string.format('{{DISPLAYTITLE:Clang %s (%s)}}', title, id))
frame:preprocess(string.format('{{DEFAULTSORT:%s}}', diag.title))
wiki = wiki .. string.format('[[Category:Clang %ss]]\n', diag.type)
wiki = wiki .. string.format('[[Category:Clang %s Category]]\n', getLatestMultiVersionValue(diag.category_hist))
wiki = wiki .. '{| class="wikitable sortable"\n'
wiki = wiki .. '! Text\n'
wiki = wiki .. '| ' .. formatMultiVersionValues(diag.hierarchical_hist, formatHierarchicalPrefix2) .. '\n'
wiki = wiki .. '|-\n'
wiki = wiki .. '! Type\n'
wiki = wiki .. '| ' .. diag.type .. '\n'
wiki = wiki .. '|-\n'
wiki = wiki .. '! Category\n'
wiki = wiki .. '| ' .. formatMultiVersionValues(diag.category_hist, escapeSpecialChars) .. '\n'
wiki = wiki .. '|-\n'
wiki = wiki .. '! Internal Id\n'
wiki = wiki .. '| ' .. formatMultiVersionValues(diag.id_hist, escapeSpecialChars) .. '\n'
local defaultactive = diag.defaultactive == nil or diag.defaultactive
if diag.type == 'Warning' or diag.type == "Downgradable Error" then
wiki = wiki .. '|-\n'
wiki = wiki .. '! Active by Default\n'
if defaultactive then
wiki = wiki .. '| Yes\n'
else
wiki = wiki .. '| No\n'
end
end
if diag.groups ~= nil then
wiki = wiki .. '|-\n'
wiki = wiki .. '! Flags\n'
wiki = wiki .. '| '
for no, group in ipairs(diag.groups) do
local g = groupsData[group]
wiki = wiki .. formatGroupLink(g, defaultactive) .. '<br>'
end
wiki = wiki .. '\n'
end
wiki = wiki .. '|-\n'
wiki = wiki .. '! Internal Message\n'
-- wiki = wiki .. '| ' .. string.format('<code>%s</code>\n', escapeSpecialChars(diag.message))
wiki = wiki .. '| ' .. formatMultiVersionValues(diag.message_hist, formatInlineCode) .. '\n'
wiki = wiki .. '|-\n'
wiki = wiki .. '! Regular Expression\n'
wiki = wiki .. '| ' .. string.format('<code>%s</code>\n', escapeSpecialChars(diag.regex1 .. diag.regex2 .. diag.regex3))
if diag.commit ~= nil then
wiki = wiki .. '|-\n'
wiki = wiki .. '! First Commit\n'
wiki = wiki .. '| ' .. string.format('%s [https://github.com/llvm/llvm-project/commit/%s %s] %s\n', os.date("%Y-%m-%d", diag.commit[2]), diag.commit[1], diag.commit[1], escapeSpecialChars(diag.commit[3]))
end
wiki = wiki .. '|}\n'
wiki = wiki .. '\n'
wiki = wiki .. '== Description ==\n'
return wiki
end
function p.createInternalInfo(frame)
local id = frame.args.id
local diag = getLongDiagData(id)
local wiki = ''
wiki = wiki .. string.format('== Clang Internals (%s)==\n', clangVersion)
if diag.commit ~= nil then
wiki = wiki .. '=== Git Commit Message ===\n'
wiki = wiki .. string.format('<pre>%s</pre>\n', escapeSpecialChars(diag.commit[4]));
end
if diag.source ~= nil then
wiki = wiki .. '=== Used in Clang Sources ===\n'
wiki = wiki .. 'This section lists all occurrences of the diagnostic within the Clang\'s codebase. For each occurrence, an auto-extracted snipped from the source code is listed including key elements like control structures, functions, or classes. It should illustrate the conditions under which the diagnostic is activated.\n'
for _, source in ipairs(diag.source) do
local lineno = source[2] - 1
wiki = wiki .. string.format('==== [https://github.com/llvm/llvm-project/blob/llvmorg-%s/%s#L%d %s (line %d)] ====\n', clangVersion, source[1], lineno, source[1], lineno)
local highlight = string.format('<syntaxhighlight lang="cpp">\n%s\n</syntaxhighlight>\n', source[3])
wiki = wiki .. frame:preprocess(highlight);
end
end
if diag.tests2 ~= nil then
wiki = wiki .. '=== Triggered in Clang Tests ===\n'
wiki = wiki .. 'This section lists all internal Clang test cases that trigger the diagnostic.\n'
for file, tests in pairs(diag.tests2) do
wiki = wiki .. string.format('==== [https://github.com/llvm/llvm-project/blob/llvmorg-%s/%s %s] ====\n', clangVersion, file, file)
for _, test in ipairs(tests) do
wiki = wiki .. '* ' .. formatMessage(test) .. '\n\n'
end
end
end
return wiki
end
local function createGroupDiagList(diags, defaultactive2)
local wiki = '{| class=wikitable\n'
local count = 0
for _, diagid in ipairs(diags) do
local diag = diagsData[diagid]
local defaultactive = diag.defaultactive == nil or diag.defaultactive
local hierarchical = diag.hierarchical or diag.title
if defaultactive2 == defaultactive then
wiki = wiki .. '| ' .. string.format('[[Clang:Diag/%s|%s]]\n', diagid, diagid)
wiki = wiki .. '| ' .. formatHierarchicalPrefix(diag.prefix, hierarchical) .. '\n'
wiki = wiki .. '|-\n'
count = count + 1
end
end
wiki = wiki .. '|}\n'
if count == 0 then
wiki = 'None\n'
end
return wiki
end
function p.createGroupInfo(frame)
local id = frame.args.id
local group = groupsData[id]
frame:preprocess(string.format('{{DISPLAYTITLE:Clang Flag: %s / %s}}', group.flag, group.flagoff))
frame:preprocess(string.format('{{DEFAULTSORT:%s}}', id))
local wiki = ''
wiki = wiki .. string.format('[[Category:Clang Flags]]\n')
wiki = wiki .. '\n'
wiki = wiki .. '== Supergroups ==\n'
for _, g in ipairs(group.supergroups) do
wiki = wiki .. string.format('* %s\n', formatGroupLink(groupsData[g], false))
end
wiki = wiki .. '\n'
wiki = wiki .. '== Subroups ==\n'
for _, g in ipairs(group.subgroups) do
wiki = wiki .. string.format('* %s\n', formatGroupLink(groupsData[g], false))
end
wiki = wiki .. '\n'
wiki = wiki .. '== Warnings/Remarks ==\n'
wiki = wiki .. string.format('=== Default Active (Deactivate with %s) ===\n', group.flagoff)
wiki = wiki .. createGroupDiagList(group.diags, true)
wiki = wiki .. string.format('=== Default Inactive (Activate with %s) ===\n', group.flag)
wiki = wiki .. createGroupDiagList(group.diags, false)
return wiki
end
-- Function to output the number of diagnostics
function p.countDiags()
local count = 0
for _ in pairs(diagsData) do
count = count + 1
end
return count
end
return p