我在MATLAB中使用checkcode函数给我一个提供的文件名中的所有错误消息的结构,以及它们的McCabe复杂性和与该错误相关的ID.即;
info = checkcode(fileName, '-cyc','-id');
Run Code Online (Sandbox Code Playgroud)
在MATLAB的首选项中,列出了所有可能的错误,并将它们分为几类.如"美学与可读性","语法错误","气馁函数用法"等.
有没有办法使用从上面的代码行获得的错误ID访问这些类别?
我在这个问题上抛出了不同的想法,并最终能够提出一个最优雅的解决方案来解决这个问题.
这种解决方案的关键组件是未记录的-allmsg
标志的checkcode
(或mlint
).如果提供此参数,mlint
则会打印完整的ID 列表,严重性代码和说明.更重要的是,类别也会打印在此列表中,所有mlint
ID都列在各自的mlint
类别下面.
现在我们不能简单地只用标志调用checkcode
(或mlint
)因为那太容易了.相反,它需要一个实际的文件来尝试解析并检查错误.您可以传递任何有效的m文件,但我选择传递内置文件,因为实际文件本身只包含帮助信息(因为它的实际实现可能是C++),因此能够非常快速地解析它而没有任何警告.-allmsg
sum.m
mlint
checkcode('sum.m', '-allmsg');
Run Code Online (Sandbox Code Playgroud)
打印到命令窗口的输出的摘录是:
INTER ========== Internal Message Fragments ==========
MSHHH 7 this is used for %#ok and should never be seen!
BAIL 7 done with run due to error
INTRN ========== Serious Internal Errors and Assertions ==========
NOLHS 3 Left side of an assignment is empty.
TMMSG 3 More than 50,000 Code Analyzer messages were generated, leading to some being deleted.
MXASET 4 Expression is too complex for code analysis to complete.
LIN2L 3 A source file line is too long for Code Analyzer.
QUIT 4 Earlier syntax errors confused Code Analyzer (or a possible Code Analyzer bug).
FILER ========== File Errors ==========
NOSPC 4 File <FILE> is too large or complex to analyze.
MBIG 4 File <FILE> is too big for Code Analyzer to handle.
NOFIL 4 File <FILE> cannot be opened for reading.
MDOTM 4 Filename <FILE> must be a valid MATLAB code file.
BDFIL 4 Filename <FILE> is not formed from a valid MATLAB identifier.
RDERR 4 Unable to read file <FILE>.
MCDIR 2 Class name <name> and @directory name do not agree: <FILE>.
MCFIL 2 Class name <name> and file name do not agree: <file>.
CFERR 1 Cannot open or read the Code Analyzer settings from file <FILE>. Using default settings instead.
...
MCLL 1 MCC does not allow C++ files to be read directly using LOADLIBRARY.
MCWBF 1 MCC requires that the first argument of WEBFIGURE not come from FIGURE(n).
MCWFL 1 MCC requires that the first argument of WEBFIGURE not come from FIGURE(n) (line <line #>).
NITS ========== Aesthetics and Readability ==========
DSPS 1 DISP(SPRINTF(...)) can usually be replaced by FPRINTF(...).
SEPEX 0 For better readability, use newline, semicolon, or comma before this statement.
NBRAK 0 Use of brackets [] is unnecessary. Use parentheses to group, if needed.
...
Run Code Online (Sandbox Code Playgroud)
第一列显然是mlint
ID,第二列实际上是严重性编号(0 =主要是无害的,1 =警告,2 =错误,4-7 =更严重的内部问题),第三列是显示的消息.
如您所见,所有类别也都有标识符但没有严重性,其消息格式为===== Category Name =====
.
所以现在我们可以解析这些信息并创建一些数据结构,使我们可以轻松查找给定mlint
ID 的严重性和类别.
尽管如此,它并不总是那么容易.不幸的是,checkcode
(或mlint
)只是将这些信息打印到命令窗口,而不是将它分配给我们的任何输出变量.因此,必须使用evalc
(颤抖)捕获输出并将其存储为字符串.然后,我们可以轻松解析此字符串,以获取与每个mlint
ID 关联的类别和严重性.
我已将我之前讨论过的所有部分放在一个小函数中,该函数将生成一个结构,其中所有字段都是mlint
ID.在每个字段中,您将收到以下信息:
warnings = mlintCatalog();
warnings.DWVRD
id: 'DWVRD'
severity: 2
message: 'WAVREAD has been removed. Use AUDIOREAD instead.'
category: 'Discouraged Function Usage'
category_id: 17
Run Code Online (Sandbox Code Playgroud)
如果你有兴趣,这里的功能很小.
function [warnings, categories] = mlintCatalog()
% Get a list of all categories, mlint IDs, and severity rankings
output = evalc('checkcode sum.m -allmsg');
% Break each line into it's components
lines = regexp(output, '\n', 'split').';
pattern = '^\s*(?<id>[^\s]*)\s*(?<severity>\d*)\s*(?<message>.*?\s*$)';
warnings = regexp(lines, pattern, 'names');
warnings = cat(1, warnings{:});
% Determine which ones are category names
isCategory = cellfun(@isempty, {warnings.severity});
categories = warnings(isCategory);
% Fix up the category names
pattern = '(^\s*=*\s*|\s*=*\s*$)';
messages = {categories.message};
categoryNames = cellfun(@(x)regexprep(x, pattern, ''), messages, 'uni', 0);
[categories.message] = categoryNames{:};
% Now pair each mlint ID with it's category
comp = bsxfun(@gt, 1:numel(warnings), find(isCategory).');
[category_id, ~] = find(diff(comp, [], 1) == -1);
category_id(end+1:numel(warnings)) = numel(categories);
% Assign a category field to each mlint ID
[warnings.category] = categoryNames{category_id};
category_id = num2cell(category_id);
[warnings.category_id] = category_id{:};
% Remove the categories from the warnings list
warnings = warnings(~isCategory);
% Convert warning severity to a number
severity = num2cell(str2double({warnings.severity}));
[warnings.severity] = severity{:};
% Save just the categories
categories = rmfield(categories, 'severity');
% Convert array of structs to a struct where the MLINT ID is the field
warnings = orderfields(cell2struct(num2cell(warnings), {warnings.id}));
end
Run Code Online (Sandbox Code Playgroud)
这是一种完全没有文档但相当强大的方法来获取与给定mlint
ID 相关联的类别和严重性.此功能存在于2010年,甚至可能在此之前,因此它应该适用于您必须处理的任何版本的MATLAB.这种方法也比仅仅注意给定mlint
ID所属的类别更灵活,因为随着新函数的添加和旧函数的弃用,类别(和严重性)将在不同版本之间发生变化.
感谢您提出这个具有挑战性的问题,我希望这个答案提供一些帮助和见解!