11

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

4

3 回答 3

8

注意:此答案使用函数MLINT,在较新版本的 MATLAB 中不再推荐使用该函数。较新的函数CHECKCODE是首选,下面的代码仍然可以通过简单地将 MLINT 调用替换为对这个较新函数的调用。


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

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

a = 1
b = 2;
c = 'a'
d = [1 2 3]
e = 'hello';

第一行、第三行和第四行将为您提供MLINT警告消息“用分号终止语句以禁止输出(在脚本内)。”。使用MLINT的函数形式,我们可以在文件中找到出现此警告的行。然后,我们可以从文件中读取所有代码行,在出现警告的行的末尾添加分号,然后将代码行写回文件。这是执行此操作的代码:

%# 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应该在每一行的末尾都有分号。如果你愿意,你可以把上面的代码放在一个函数中,这样你就可以很容易地在你继承代码的每个文件上运行它。

于 2010-07-14T17:37:40.273 回答
7

为了以通用方式为所有可用的自动修复操作解决这个问题,我们必须求助于可怕的未记录的 java 方法。mlint(and now )的实现checkcode使用mlintmex(a builtin;而不是顾名思义的 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标志的修复程序......这也适用于 builtin checkcode!仍然没有记录(据我所知),但可能比上述更强大:

>> 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):   <~>

在分配给结构时,这也揭示了@High Performance Mark在他对@gnovice答案fix的评论中指出的新字段的用途;当有可用的修复程序时,它似乎是 1,当消息是上述时,它似乎是 2,当消息是.FIX MESSAGECHANGE MESSAGE

这是一个快速而肮脏的 Matlab 函数,它在给定 m 文件路径的情况下返回一个“固定”字符串。没有错误检查等,它不会保存文件,因为我不保证它会起作用。您还可以使用matlab.desktop.editor公共 (!) API 来获取活动文档 ( getActive) 并使用Text属性上的 getter 和 setter 来修改文档而不保存它。

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
于 2013-08-22T18:25:40.113 回答
6

我知道这是一篇旧帖子,但我最近才需要它,并且对原始代码进行了一些改进,所以如果其他人需要它,它就在这里。它寻找丢失的“;” 在函数中,而不仅仅是在常规脚本中,维护代码中的空格并只写入发生更改的文件。

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);
于 2012-03-08T13:18:17.987 回答