Есть ли способ исправить все сообщения mlint MATLAB одновременно? - PullRequest
11 голосов
/ 14 июля 2010

Я унаследовал некоторый код, в котором автор испытывал отвращение к точкам с запятой.Можно ли исправить все сообщения mlint за один раз (по крайней мере, все с автоматическим исправлением), вместо того, чтобы нажимать каждое из них и нажимать ALT + ENTER?

Ответы [ 3 ]

8 голосов
/ 14 июля 2010

ПРИМЕЧАНИЕ: В этом ответе используется функция 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 должен иметь точку с запятой в конце каждой строки. При желании вы можете поместить приведенный выше код в функцию, чтобы вы могли легко запускать его для каждого файла вашего унаследованного кода.

7 голосов
/ 22 августа 2013

Чтобы решить эту проблему в общем виде для всех доступных действий автофикса, мы должны прибегнуть к ужасно недокументированным java-методам. Реализация mlint (и теперь checkcode) использует mlintmex (встроенный; не мексфайл, как следует из названия), который просто возвращает вывод text из linter. Автофиксы не выставляются; четные номера строк и столбцов выводятся в виде простого текста. Кажется, что он совпадает с выводом двоичного файла mlint при установке Matlab ($(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

РЕДАКТИРОВАТЬ: AHA! Вы можете получить двоичный файл mlint для возврата исправлений с флагом -fix ... и это также относится к встроенному 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):   <~>

При назначении конструкции также раскрывается назначение нового поля fix, которое @ High Performance Mark отмечает в своем комментарии к @ gnovice '* ответ ; Похоже, что это 1, когда доступно исправление, 2, когда сообщение - FIX MESSAGE выше, и 4, когда сообщение - CHANGE MESSAGE.

Вот быстрая и грязная функция Matlab, которая возвращает «фиксированную» строку с указанием пути к m-файлу. Нет проверки ошибок и т. Д., И он не сохраняет файл обратно, так как я не обещаю, что он будет работать. Вы также можете использовать matlab.desktop.editor открытый (!) API для получения активного документа (getActive) и использовать метод получения и установки в свойстве Text, чтобы изменить документ на месте, не сохраняя его.

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
6 голосов
/ 08 марта 2012

Я знаю, что это старый пост, но я только недавно нуждался в этом и немного улучшил исходный код, так что если кому-то еще это нужно, вот оно. Похоже, отсутствует ";" в функциях, а не только в обычных сценариях, поддерживает пробелы в коде и записывает только файлы, в которых что-то изменилось.

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...