2010-07-14 10 views
11

Heredé algún código donde el autor tenía una aversión a los puntos y comas. ¿Es posible corregir todos los mensajes de mlint de una vez (al menos todos los que tienen una corrección automática), en lugar de tener que hacer clic en cada uno y presionar ALT + ENTRAR?¿Hay alguna forma de corregir todos los mensajes mlint de MATLAB a la vez?

+3

Tenga en cuenta que agradezco las respuestas existentes, pero espero encontrar una solución más aplicable en general. –

+0

Reemplazaron mlint con código de comprobación recientemente. Puede usarlo también. – NKN

Respuesta

8

NOTA: esta pregunta utiliza la función MLINT, que ya no se recomienda en las últimas versiones de MATLAB. Se prefiere la función más reciente CHECKCODE, y el código siguiente funcionará simplemente reemplazando la llamada a MLINT con una llamada a esta función más nueva.


no sé de una manera en general código para corregir automáticamente basado en MLINT mensajes. Sin embargo, en su caso específico existe una forma automatizada para que usted agregue punto y coma a las líneas que lanzan una advertencia MLINT.

En primer lugar, vamos a empezar con este script de ejemplo junk.m:

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

primera, tercera, y cuarta línea le dará el mensaje MLINT advertencia "declaración Terminar con punto y coma para suprimir la salida (dentro de un script). ". Usando la forma funcional de MLINT, podemos encontrar las líneas en el archivo donde ocurre esta advertencia. Luego, podemos leer todas las líneas de código del archivo, agregar un punto y coma al final de las líneas donde ocurre la advertencia y escribir las líneas de código en el archivo. Aquí está el código para hacerlo:

%# 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); 

Y ahora el archivo junk.m debe tener un punto y coma al final de cada línea. Si lo desea, puede poner el código anterior en una función para que pueda ejecutarlo fácilmente en cada archivo de su código heredado.

+1

Si reemplaza '-struct' con '-id' en su llamada a mlint, la estructura que se devuelve contiene un campo adicional llamado 'id', que es una identificación corta para el mensaje mlint. Eso podría ser más fácil de comparar que el texto completo del mensaje. La estructura también contiene un campo llamado 'arreglar' que es 0 para todas las advertencias en mi archivo de prueba y no he descubierto para qué es aún: no está documentado. –

+0

@High Performance Mark: el campo '' fix'' debe ser una característica más nueva, ya que no aparece en MATLAB R2009a. – gnovice

+0

sí, estoy ejecutando 2010a aquí. –

6

Sé que esta es una publicación anterior, pero solo necesitaba esto recientemente y mejoré un poco el código original, así que si alguien más lo necesita aquí, lo es. Busca desaparecidos ";" en las funciones, no solo en las secuencias de comandos normales, mantiene el espacio en blanco en el código y escribe solo los archivos que tienen algo cambiado.

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

Gracias, y bienvenidos a SO. Incluso las viejas preguntas valen la pena agregar. –

7

Con el fin de resolver este problema de una manera general para todas las acciones de reparación automática disponibles, hay que recurrir a métodos Java terriblemente indocumentados. La implementación de mlint (y ahora checkcode) usa mlintmex (un built-in; no es un archivo mex como el nombre lo sugiere), que simplemente devuelve el texto de la salida del linter. No hay autoexplicaciones expuestas; incluso los números de línea y columna se emiten como texto sin formato. Parece ser lo mismo que el resultado del binario mlint dentro de la instalación de Matlab ($(matlabroot)/bin/$(arch)/mlint)

Por lo tanto, debemos recurrir a la implementación java utilizada por el editor. Cuidado: aquí sigue un código terriblemente indocumentado para 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! Puede obtener el binario mlint para devolver las correcciones con el indicador -fix ... ¡y esto también se aplica al built-in checkcode!Aún sin documentar (por lo que yo sé), pero probablemente mucho más robusto que el anterior:

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

Al asignar a una estructura, esto también revela el propósito del nuevo campo fix que @High Performance Mark notas en su comentario sobre @gnovice 's answer; parece ser 1 cuando hay una solución disponible, 2 cuando el mensaje es FIX MESSAGE anterior, y 4 cuando el mensaje es CHANGE MESSAGE.

Aquí está una función Matlab rápida y sucia que devuelve una cadena 'fija' dada la ruta a un archivo-m. Sin errores, etc., y no guarda el archivo, ya que no prometo que funcionará. También puede usar la API pública matlab.desktop.editor (!) Para obtener el documento activo (getActive) y usar el captador y el colocador en la propiedad Text para modificar el documento en su lugar sin guardarlo.

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

¡Increíble, el primero parece ser exactamente lo que estaba buscando! No tendremos la oportunidad de probarlo antes de que expire la recompensa, pero a menos que alguien pueda superar esto, viene en tu dirección. –

+2

Agregué el appraoch de Java a un acceso directo, encontré un bonito icono de herramienta y funciona sin problemas hasta el momento. Gran solución – Oleg

+0

@OlegKomarov: cuidado, dos cambios en la misma línea pueden confundirse. Invertí el orden de iteración, que parece corregir la mayoría de los casos. Más robusto, sin embargo, sería ejecutar iterativamente mlint y corregir un mensaje a la vez. –

Cuestiones relacionadas