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!
Können Sie eine Dokumentation verlinken, in der die Kategorien erläutert werden? Ich kann es nicht finden .... –
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. –
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. –