有没有办法一次修复所有MATLAB mlint消息?

有没有办法一次修复所有MATLAB mlint消息?,matlab,mlint,Matlab,Mlint,我继承了一些代码,作者不喜欢分号。是否可以一次性修复所有mlint消息(至少是具有自动修复功能的所有消息),而不必单击每个消息并按ALT+ENTER键?注意:此答案使用新版本MATLAB中不再推荐的功能。较新的函数是首选的,下面的代码仍然可以工作,只需将对MLINT的调用替换为对这个较新函数的调用 一般来说,我不知道如何根据消息自动修复代码。但是,在您的特定情况下,有一种自动方法可以将分号添加到引发警告的行中 首先,让我们从这个示例脚本junk.m开始: a = 1 b = 2; c = 'a

我继承了一些代码,作者不喜欢分号。是否可以一次性修复所有mlint消息(至少是具有自动修复功能的所有消息),而不必单击每个消息并按ALT+ENTER键?

注意:此答案使用新版本MATLAB中不再推荐的功能。较新的函数是首选的,下面的代码仍然可以工作,只需将对MLINT的调用替换为对这个较新函数的调用


一般来说,我不知道如何根据消息自动修复代码。但是,在您的特定情况下,有一种自动方法可以将分号添加到引发警告的行中

首先,让我们从这个示例脚本
junk.m
开始:

a = 1
b = 2;
c = 'a'
d = [1 2 3]
e = 'hello';
第一行、第三行和第四行将给出警告消息“用分号终止语句以抑制输出(在脚本中)。”。使用的函数形式,我们可以在文件中找到出现此警告的行。然后,我们可以读取文件中的所有代码行,在出现警告的代码行末尾添加分号,然后将代码行写回文件。下面是执行此操作的代码:

%# Find the lines where a given mlint warning occurs:

fileName = 'junk.m';
mlintID = 'NOPTS';                       %# The ID of the warning
mlintData = mlint(fileName,'-id');       %# Run mlint on the file
index = strcmp({mlintData.id},mlintID);  %# Find occurrences of the warnings...
lineNumbers = [mlintData(index).line];   %#   ... and their line numbers

%# Read the lines of code from the file:

fid = fopen(fileName,'rt');
linesOfCode = textscan(fid,'%s','Delimiter',char(10));  %# Read each line
fclose(fid);

%# Modify the lines of code:

linesOfCode = linesOfCode{1};  %# Remove the outer cell array encapsulation
linesOfCode(lineNumbers) = strcat(linesOfCode(lineNumbers),';');  %# Add ';'

%# Write the lines of code back to the file:

fid = fopen(fileName,'wt');
fprintf(fid,'%s\n',linesOfCode{1:end-1});  %# Write all but the last line
fprintf(fid,'%s',linesOfCode{end});        %# Write the last line
fclose(fid);

现在文件
junk.m
的每一行末尾都应该有分号。如果您愿意,可以将上述代码放入函数中,这样您就可以轻松地在继承代码的每个文件上运行它。

我知道这是一篇老文章,但我最近才需要它,并对原始代码进行了一些改进,因此,如果其他人需要它,就在这里。它查找函数中缺少的“;”而不仅仅是在常规脚本中,在代码中保留空白,并只写入发生更改的文件

function [] = add_semicolon(fileName)
%# Find the lines where a given mlint warning occurs:

mlintIDinScript = 'NOPTS';                       %# The ID of the warning
mlintIDinFunction = 'NOPRT';
mlintData = mlint(fileName,'-id');       %# Run mlint on the file
index = strcmp({mlintData.id},mlintIDinScript) | strcmp({mlintData.id},mlintIDinFunction);  %# Find occurrences of the warnings...
lineNumbers = [mlintData(index).line];   %#   ... and their line numbers

if isempty(lineNumbers)
    return;
end;
%# Read the lines of code from the file:

fid = fopen(fileName,'rt');
%linesOfCode = textscan(fid,'%s', 'Whitespace', '\n\r');  %# Read each line
lineNo = 0;
tline = fgetl(fid);
while ischar(tline)
    lineNo = lineNo + 1;
    linesOfCode{lineNo} = tline;
    tline = fgetl(fid);
end
fclose(fid);
%# Modify the lines of code:

%linesOfCode = linesOfCode{1};  %# Remove the outer cell array encapsulation
linesOfCode(lineNumbers) = strcat(linesOfCode(lineNumbers),';');  %# Add ';'

%# Write the lines of code back to the file:

fim = fopen(fileName,'wt');
fprintf(fim,'%s\n',linesOfCode{1:end-1});  %# Write all but the last line
fprintf(fim,'%s',linesOfCode{end});        %# Write the last line
fclose(fim);

为了以一种通用的方式解决所有可用的自动修复操作的这个问题,我们必须求助于可怕的未记录的java方法。
mlint
(现在是
checkcode
)的实现使用
mlintmex
(一个内置文件;而不是顾名思义的mexfile),它只返回linter输出的文本。没有暴露自动修复;偶数行号和列号以纯文本形式发出。它似乎与Matlab安装中的mlint二进制文件的输出相同(
$(matlabroot)/bin/$(arch)/mlint

因此,我们必须回到编辑器本身使用的java实现。注意:下面是R2013a的未记录代码

%// Get the java component for the active matlab editor
ed = matlab.desktop.editor.getActive().JavaEditor.getTextComponent();
%// Get the java representation of all mlint messages
msgs = com.mathworks.widgets.text.mcode.MLint.getMessages(ed.getText(),ed.getFilename())

%// Loop through all messages and apply the autofix, if it exits 
%// Iterate backwards to try to prevent changing the location of subsequent
%// fixes... but two nearby fixes could still mess each other up.
for i = msgs.size-1:-1:0
  if msgs.get(i).hasAutoFix()
    com.mathworks.widgets.text.mcode.analyzer.CodeAnalyzerUtils.applyAutoFixes(ed,msgs.get(i).getAutoFixChanges);
  end
end

编辑:啊哈!您可以让mlint二进制文件返回带有
-fix
标志的修复程序。。。这也适用于内置的检查代码!仍然没有文档记录(据我所知),但可能比上述内容更可靠:

>> checkcode(matlab.desktop.editor.getActiveFilename(),'-fix')
L 2 (C 3): Terminate statement with semicolon to suppress output (in functions).  (CAN FIX)
----FIX MESSAGE  <Add a semicolon.>
----CHANGE MESSAGE L 2 (C 13);  L 2 (C 12):   <;>
L 30 (C 52-53): Input argument 'in' might be unused. If this is OK, consider replacing it by ~.  (CAN FIX)
----FIX MESSAGE  <Replace name by ~.>
----CHANGE MESSAGE L 30 (C 52);  L 30 (C 53):   <~>

如果在对mlint的调用中用“-id”替换“-struct”,则返回的结构包含一个名为“id”的附加字段,该字段是mlint消息的短id。这可能比消息的全文更容易匹配。该结构还包含一个名为“fix”的字段,对于我的测试文件中的所有警告,该字段为0,但我还没有弄清楚它的用途——它没有文档记录。@High Performance Mark:
“fix”
字段必须是一个较新的功能,因为它在MATLAB R2009a中没有出现。@HighPerformanceMark,我发现了如何使
fix
字段起作用:将
-fix
标志传递给mlint/checkcode!有关详细信息,请参阅。谢谢,欢迎访问SO。即使是老问题也值得补充。请注意,我很欣赏现有的答案,但希望找到一个更普遍适用的解决方案。他们最近用checkcode取代了mlint。你也可以用它。太棒了,第一个似乎正是我想要的!在赏金到期之前没有机会测试它,但除非有人能超越它,否则它会朝你的方向发展。我在快捷方式中添加了Java appraoch,找到了一个不错的工具图标,目前为止它运行顺利。很好的解决办法。@OlegKomarov:小心,同一条线上的两个变化可能会把对方搞得一团糟。我颠倒了迭代顺序,这似乎解决了大多数情况。不过,更健壮的方法是迭代运行mlint,一次修复一条消息,我只是想知道这是否可以导出到其他IDE。我喜欢在vim中编辑,可能有一种方法可以做到这一点。不幸的是,我不是一个
vimscript
编辑器,如果有人改进matlab-mlint集成脚本,使其具有类似的功能,那就太好了。如果没有人这样做,我可能有一天会尝试,这个主题将非常有帮助。@Werner:是的,你可以调用Mathworks提供的mlint二进制文件,自己解析输出。不过,更有趣的是,尝试直接链接到动态库
libmwmlint.{dll,因此,dylib}
。快速浏览一下这些符号,我不禁想知道它是否可能(
MLINT::MLINT_文件(char const*)
MLINT::MLINT_文本(char const*,char const*,unsigned int)
,以及最有趣/令人畏惧的:
MLINT::set_output_fun(void(*)(char const*,void*),void*)
)。
function str = applyAutoFixes(filepath)

msgs = checkcode(filepath,'-fix');

fid = fopen(filepath,'rt');
iiLine = 1;
lines = cell(0);
line = fgets(fid);
while ischar(line)
    lines{iiLine} = line;
    iiLine = iiLine+1;
    line = fgets(fid);
end
fclose(fid);

pos = [0 cumsum(cellfun('length',lines))];
str = [lines{:}];

fixes = msgs([msgs.fix] == 4);
%// Iterate backwards to try to prevent changing the indexing of 'str'
%// Note that two changes could still conflict with eachother. You could check
%// for this, or iteratively run mlint and fix one problem at a time.
for fix = fliplr(fixes(:)')
    %'// fix.column is a 2x2 - not sure what the second column is used for
    change_start = pos(fix.line(1)) + fix.column(1,1);
    change_end   = pos(fix.line(2)) + fix.column(2,1);

    if change_start >= change_end
        %// Seems to be an insertion
        str = [str(1:change_start) fix.message str(change_start+1:end)];
    else
        %// Seems to be a replacement
        str = [str(1:change_start-1) fix.message str(change_end+1:end)];
    end
end