2016-03-09 2 views
5

Ich verwende die Prüfcode Funktion in MATLAB, um mir eine Struktur aller Fehlermeldungen in einem angegebenen Dateinamen zusammen mit ihrer McCabe Komplexität und ID mit diesem Fehler verbunden. d.Finden Sie die Kategorie von MATLAB mlint Warnung ID

info = checkcode(fileName, '-cyc','-id'); 

In MATLAB-Einstellungen gibt es eine Liste aller möglichen Fehler, und sie sind in Kategorien unterteilt. Wie "Ästhetik und Lesbarkeit", "Syntaxfehler", "Entmutigte Funktionsverwendung" etc.

Gibt es eine Möglichkeit, diese Kategorien mit der Fehler-ID aus der obigen Codezeile zuzugreifen?

+0

Können Sie eine Dokumentation verlinken, in der die Kategorien erläutert werden? Ich kann es nicht finden .... –

+0

Klicken Sie auf der Startseite auf Einstellungen im Bereich "Umgebung" und wählen Sie dann "Code Analyzer" auf der linken Seite. Alle Kategorien sind dort drin. –

+1

Zur Klarstellung, meine Absicht ist es, eine Fehler-ID wie 'DWVRD' (die dem Fehler "Wavread wird in zukünftigen Releases entfernt werden, verwenden Sie stattdessen audioread") in eine Funktion einzugeben, die die Kategorie dieses Fehlercodes zurückgibt ist unter und alle anderen damit verbundenen Eigenschaften aufgeführt. –

Antwort

7

Ich warf für diese Frage verschiedene Ideen in meinen Kopf und konnte schließlich eine meist elegante Lösung für den Umgang damit finden.

Die Lösung

Die kritische Komponente dieser Lösung ist die undocumented -allmsg Flagge of checkcode (or mlint). Wenn Sie dieses Argument angeben, wird eine vollständige Liste der mlint IDs, Schweregradcodes und Beschreibungen gedruckt. Noch wichtiger ist, dass die Kategorien und in dieser Liste gedruckt werden und alle mlint IDs unter ihrer jeweiligen mlint Kategorie aufgeführt sind.

Die Hinrichtung

Jetzt können wir rufen nicht einfach checkcode (oder mlint) mit nur die -allmsg Flagge, denn das wäre zu einfach. Stattdessen wird eine tatsächliche Datei benötigt, um zu analysieren und nach Fehlern zu suchen. Sie können eine gültige m-Datei übergeben, aber ich habe beschlossen, die integrierte sum.m zu übergeben, da die eigentliche Datei selbst nur Hilfe Informationen enthält (wie es echte Implementierung ist wahrscheinlich C++) und mlint ist daher in der Lage, sehr zu analysieren schnell ohne Warnungen.

checkcode('sum.m', '-allmsg'); 

ein Auszug der in das Befehlsfenster gedruckten Ausgabe ist:

INTER ========== Internal Message Fragments ========== 
    MSHHH 7 this is used for %#ok and should never be seen! 
    BAIL 7 done with run due to error 
    INTRN ========== Serious Internal Errors and Assertions ========== 
    NOLHS 3 Left side of an assignment is empty. 
    TMMSG 3 More than 50,000 Code Analyzer messages were generated, leading to some being deleted. 
    MXASET 4 Expression is too complex for code analysis to complete. 
    LIN2L 3 A source file line is too long for Code Analyzer. 
    QUIT 4 Earlier syntax errors confused Code Analyzer (or a possible Code Analyzer bug). 
    FILER ========== File Errors ========== 
    NOSPC 4 File <FILE> is too large or complex to analyze. 
    MBIG 4 File <FILE> is too big for Code Analyzer to handle. 
    NOFIL 4 File <FILE> cannot be opened for reading. 
    MDOTM 4 Filename <FILE> must be a valid MATLAB code file. 
    BDFIL 4 Filename <FILE> is not formed from a valid MATLAB identifier. 
    RDERR 4 Unable to read file <FILE>. 
    MCDIR 2 Class name <name> and @directory name do not agree: <FILE>. 
    MCFIL 2 Class name <name> and file name do not agree: <file>. 
    CFERR 1 Cannot open or read the Code Analyzer settings from file <FILE>. Using default settings instead. 
    ... 
    MCLL 1 MCC does not allow C++ files to be read directly using LOADLIBRARY. 
    MCWBF 1 MCC requires that the first argument of WEBFIGURE not come from FIGURE(n). 
    MCWFL 1 MCC requires that the first argument of WEBFIGURE not come from FIGURE(n) (line <line #>). 
    NITS ========== Aesthetics and Readability ========== 
    DSPS 1 DISP(SPRINTF(...)) can usually be replaced by FPRINTF(...). 
    SEPEX 0 For better readability, use newline, semicolon, or comma before this statement. 
    NBRAK 0 Use of brackets [] is unnecessary. Use parentheses to group, if needed. 
    ... 

Die erste Spalte ist eindeutig die mlint ID, die zweite Spalte ist tatsächlich eine Gewichtszahl (0 = meist harmlos, 1 = Warnung, 2 = Fehler, 4-7 = ernstere interne Probleme), und die dritte Spalte ist die Nachricht, die angezeigt wird.

Wie Sie sehen können, alle Kategorien auch eine Kennung haben, aber keine Schweregrade und ihr Nachrichtenformat ist ===== Category Name =====.

Jetzt können wir nur diese Informationen analysieren und eine Datenstruktur erstellen, die es uns ermöglicht, einfach den Schweregrad und die Kategorie für eine gegebene mlint ID nachzuschlagen.

Auch hier kann es nicht immer so einfach sein. Unglücklicherweise druckt checkcode (oder mlint) diese Information einfach in das Befehlsfenster und weist sie keiner unserer Ausgangsvariablen zu. Aus diesem Grund ist es erforderlich, evalc (shudder) zu verwenden, um die Ausgabe zu erfassen und als Zeichenfolge zu speichern. Wir können diese Zeichenfolge dann leicht analysieren, um die mit jeder mlint ID verbundene Kategorie und den Schweregrad zu ermitteln.

Ein Beispiel Parser

Ich habe alle Stücke habe ich in eine kleine Funktion zuvor zusammen diskutiert, die eine Struktur erzeugen, in der alle der Felder sind die mlint IDs. In jedem Feld erhalten Sie folgende Informationen:

warnings = mlintCatalog(); 
warnings.DWVRD 

      id: 'DWVRD' 
     severity: 2 
     message: 'WAVREAD has been removed. Use AUDIOREAD instead.' 
     category: 'Discouraged Function Usage' 
    category_id: 17 

Und hier ist die kleine Funktion, wenn Sie interessiert sind.

function [warnings, categories] = mlintCatalog() 
    % Get a list of all categories, mlint IDs, and severity rankings 
    output = evalc('checkcode sum.m -allmsg'); 

    % Break each line into it's components 
    lines = regexp(output, '\n', 'split').'; 
    pattern = '^\s*(?<id>[^\s]*)\s*(?<severity>\d*)\s*(?<message>.*?\s*$)'; 
    warnings = regexp(lines, pattern, 'names'); 
    warnings = cat(1, warnings{:}); 

    % Determine which ones are category names 
    isCategory = cellfun(@isempty, {warnings.severity}); 
    categories = warnings(isCategory); 

    % Fix up the category names 
    pattern = '(^\s*=*\s*|\s*=*\s*$)'; 
    messages = {categories.message}; 
    categoryNames = cellfun(@(x)regexprep(x, pattern, ''), messages, 'uni', 0); 
    [categories.message] = categoryNames{:}; 

    % Now pair each mlint ID with it's category 
    comp = bsxfun(@gt, 1:numel(warnings), find(isCategory).'); 
    [category_id, ~] = find(diff(comp, [], 1) == -1); 
    category_id(end+1:numel(warnings)) = numel(categories); 

    % Assign a category field to each mlint ID 
    [warnings.category] = categoryNames{category_id}; 

    category_id = num2cell(category_id); 
    [warnings.category_id] = category_id{:}; 

    % Remove the categories from the warnings list 
    warnings = warnings(~isCategory); 

    % Convert warning severity to a number 
    severity = num2cell(str2double({warnings.severity})); 
    [warnings.severity] = severity{:}; 

    % Save just the categories 
    categories = rmfield(categories, 'severity'); 

    % Convert array of structs to a struct where the MLINT ID is the field 
    warnings = orderfields(cell2struct(num2cell(warnings), {warnings.id})); 
end 

Zusammenfassung

Dies ist eine völlig undokumentiert, aber recht robust Art und Weise die Kategorie und Schweregrad mit einer bestimmten mlint ID zugeordnet bekommen. Diese Funktionalität existierte im Jahr 2010 und vielleicht sogar davor, also sollte es mit jeder Version von MATLAB funktionieren, mit der Sie umgehen müssen. Dieser Ansatz ist auch viel flexibler, als einfach zu notieren, in welchen Kategorien sich eine gegebene mlint ID befindet, da sich die Kategorie (und der Schweregrad) von Version zu Version ändert, wenn neue Funktionen hinzugefügt werden und alte Funktionen veraltet sind.

Vielen Dank, dass Sie diese herausfordernde Frage gestellt haben, und ich hoffe, dass diese Antwort ein wenig Hilfe und Einblicke liefert!

+0

Dies scheint eine viel bessere Lösung als die Verwendung der Excel-Datei, die ich erstellt habe, um sie zu speichern. Ich werde sicher meine Methoden damit aktualisieren. Vielen Dank. –

+0

+1 Ich hatte einen ähnlichen Vorschlag für ein Linter-Plugin für den [Atom] (https://atom.io/) Texteditor: https://github.com/ajdm/linter-matlab/issues/2#issuecomment- 182097020 – Amro

0

Nur um dieses Problem zu schließen. Ich habe es geschafft, die Daten von ein paar verschiedenen Orten zu extrahieren und sie zusammenzufügen. Ich habe jetzt eine Excel-Tabelle aller Matlab Warnungen und Fehler mit Spalten für ihre entsprechenden ID-Codes, Kategorie und Schweregrad (dh, wenn es eine Warnung oder Fehler ist). Ich kann jetzt diese Datei einlesen, ID-Codes nachsehen, die ich von der "Prüfcode" -Funktion bekomme, und alle benötigten Informationen herausziehen. Dies kann nun verwendet werden, um Analyse-Tools zu erstellen, um die Qualität von geschriebenen Skripten/Klassen usw. zu überprüfen.

Wenn jemand eine Kopie dieser Datei möchte, dann schreib mir eine Nachricht und ich werde es gerne zur Verfügung stellen.

Darren.

Verwandte Themen