查找MATLAB mlint警告ID的类别

p4rjhz4m  于 2023-10-23  发布在  Matlab
关注(0)|答案(2)|浏览(131)

我使用MATLAB中的 checkcode 函数,在提供的文件名中提供所有错误消息的结构,沿着与该错误相关的McCabe复杂性和ID。即,

info = checkcode(fileName, '-cyc','-id');

在MATLAB的首选项中,有一个所有可能错误的列表,并将它们分为几类。如“美学与可读性”、“避免错误”、“不鼓励的函数用法”等。
有没有一种方法可以使用从上面的代码行获得的错误ID来访问这些类别?

41zrol4v

41zrol4v1#

对于这个问题,我在脑海中反复思考了不同的想法,最后终于想出了一个最优雅的解决方案。

解决方案

此解决方案的关键组件是未文档化的-allmsg标志of checkcode (or mlint )。如果提供此参数,则会打印mlint ID、严重性代码和说明的完整列表。更重要的是,类别 * 也 * 打印在此列表中,所有mlint ID都列在各自的mlint类别下。

执行

现在我们不能简单地调用checkcode(或mlint),only-allmsg标志,因为这太容易了。相反,它需要一个实际的文件来尝试解析和检查错误。您可以 * 传递任何有效的m文件,但我选择传递内置的sum.m,因为实际文件本身只包含帮助信息(因为它的真实的实现可能是C++),因此mlint能够 * 非常 * 快速地解析它,没有警告。

checkcode('sum.m', '-allmsg');

打印到命令窗口的输出摘录如下:

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.
   ...

第一列显然是mlint ID,第二列实际上是严重性编号(0 =基本无害,1 =警告,2 =错误,4-7 =更严重的内部问题),第三列是显示的消息。
正如您所看到的,所有类别 * 也 * 有一个标识符,但没有严重性,它们的消息格式是===== Category Name =====
因此,现在我们可以解析这些信息并创建一些数据结构,使我们能够轻松地查找给定mlint ID的严重性和类别。
不过,再一次,这并不总是那么容易。不幸的是,checkcode(或mlint)只是将此信息输出到命令窗口,而没有将其分配给任何输出变量。因此,需要使用evalc(* shrimp *)来捕获输出并将其存储为字符串。然后,我们可以轻松地解析这个字符串,以获得与每个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

如果你感兴趣的话,这里有一个小函数。

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

摘要

这是一种完全没有文档记载但相当健壮的获取与给定mlint ID关联的类别和严重性的方法。这个功能在2010年就已经存在了,甚至可能在那之前,所以它应该可以与你必须处理的任何版本的MATLAB一起工作。这种方法也比简单地指出给定的mlint ID属于什么类别要灵活得多,因为随着新功能的添加和旧功能的弃用,类别(和严重性)会随着版本的不同而变化。
感谢您提出这个具有挑战性的问题,我希望这个答案能提供一些帮助和见解!

piv4azn7

piv4azn72#

把这期结束了。我从几个不同的地方提取了数据并把它们拼在一起。我现在有一个Excel电子表格,其中包含所有matlab的警告和错误,以及相应的ID代码,类别和严重性(即,如果是警告或错误)。我现在可以读取这个文件,查找ID代码,我从使用'检查代码'功能,并提请任何所需的信息。这现在可以用来创建分析工具,以查看编写的脚本/类等的质量。
如果有人想要这个文件的副本,然后给我留言,我会很乐意提供它。
达伦

相关问题