2010-07-14 4 views
11

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

+3

Обратите внимание, что я ценю существующие ответы, но надеюсь найти более общеприменимое решение. –

+0

Недавно они заменили mlint чек-кодом. Вы можете использовать его также. – NKN

ответ

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 должен иметь точку с запятой в конце каждой строки. Если вы хотите, вы можете поместить вышеуказанный код в функцию, чтобы вы могли легко запустить его в каждом файле вашего унаследованного кода.

+1

Если вы замените '-struct' на '-id' в своем вызове mlint, возвращаемая структура содержит дополнительное поле с именем 'id', которое является коротким идентификатором для сообщения mlint. Это может быть проще сопоставить с полным текстом сообщения. Структура также содержит поле под названием «fix», которое равно 0 для всех предупреждений в моем тестовом файле, и я еще не понял, что это такое - он не документирован. –

+0

@ Знак высокой производительности: поле '' fix'' должно быть более новым, поскольку оно не отображается в MATLAB R2009a. – gnovice

+0

да, я бегу 2010a здесь. –

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); 
+1

Спасибо, и добро пожаловать в СО. Даже старые вопросы стоит добавить. –

7

Для того, чтобы решить эту проблему в общем виде для всех доступных действий AUTOFIX, мы должны прибегать к ужасно недокументированным методам Java. Реализация mlint (и теперь checkcode) использует mlintmex (встроенный, а не файл mexfile, как следует из названия), который просто возвращает текст , выводимый из 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 

EDIT: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 отмечает в своем комментарии @gnoviceanswer; он кажется равным 1 при наличии исправления 2, когда сообщение является FIX MESSAGE выше, и 4, когда сообщение является CHANGE MESSAGE.

Вот быстрая и грязная функция Matlab, которая возвращает строку «fixed», заданную для пути к m-файлу. Нет проверки ошибок и т. Д., И он не сохраняет файл обратно, поскольку я не обещаю, что он сработает. Вы также можете использовать общедоступный (!) API matlab.desktop.editor, чтобы получить активный документ (getActive), и использовать свойство getter и setter в свойстве 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 
+0

Удивительный, первый, похоже, именно то, что я искал! У вас не будет возможности проверить его до того, как истечет срок действия, но если кто-то не сможет это сделать, он подходит вам. –

+2

Я добавил оценку Java в ярлык, нашел приятный значок инструмента, и он работает гладко до сих пор. Отличное решение. – Oleg

+0

@OlegKomarov: Остерегайтесь, два изменения на одной линии могут повредить друг другу. Я изменил порядок итераций, который, по-видимому, фиксирует большинство случаев. Более надежным было бы итеративное выполнение mlint и исправление одного сообщения за раз. –

Смежные вопросы