2016-03-09 14 views
5

Korzystam z funkcji w MATLAB, aby dać mi strukturę wszystkich komunikatów o błędach w podanej nazwie pliku wraz z ich złożonością McCabe i identyfikatorem związanym z tym błędem. to znaczy;Znajdź kategorię MATLAB mlint ostrzeżenie ID

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

W preferencjach MATLAB znajduje się lista wszystkich możliwych błędów, które są podzielone na kategorie. Takich jak "Estetyka i czytelność", "Błędy składni", "Zniechęcona funkcja użycia" itp.

Czy istnieje sposób dostępu do tych kategorii przy użyciu identyfikatora błędu uzyskanego z powyższego wiersza kodu?

+0

Czy możesz połączyć dokumentację, w której wyjaśnione są te kategorie? Nie mogę go znaleźć .... –

+0

Jedna z kart domowych, kliknij preferencje w sekcji środowiska, a następnie wybierz "Analizator kodów" po lewej stronie. Wszystkie kategorie są tam. –

+1

Dla wyjaśnienia, moim zamiarem jest wprowadzenie identyfikatora błędu, takiego jak "DWVRD" (który odpowiada błędowi "wavread zostanie usunięty w przyszłej wersji, użyj zamiast tego audioread") do jakiejś funkcji, która zwróci kategorię tego kodu błędu jest wymieniony pod i wszelkie inne właściwości z nim związane. –

Odpowiedz

7

Rzuciłem o różne pomysły w mojej głowie na to pytanie i nareszcie mogłem wymyślić najbardziej eleganckie rozwiązanie, jak sobie z tym poradzić.

Rozwiązanie

Krytycznym elementem tego rozwiązania jest undocumented -allmsg flaga of checkcode (or mlint). Jeśli podasz ten argument, drukowana jest pełna lista identyfikatorów mlint ID, kodów istotności i opisów. Co ważniejsze, na tej liście drukowane są również kategorie oraz, a wszystkie identyfikatory mlint są wymienione poniżej ich kategorii mlint.

Egzekucja

Teraz nie możemy po prostu zadzwonić checkcode (lub mlint) z tylko flaga -allmsg bo to byłoby zbyt proste. Zamiast tego wymaga rzeczywistego pliku, aby spróbować przeanalizować i sprawdzić błędy. Możesz może przekazać dowolny prawidłowy plik m, ale zdecydowałem się przekazać wbudowany sum.m, ponieważ sam plik zawiera tylko informacje pomocy (ponieważ jest to prawdziwa implementacja jest prawdopodobnie C++), a zatem mlint jest w stanie bardzo łatwo je przeanalizować. szybko bez ostrzeżeń.

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

Fragment wyjścia drukowanej okna polecenia:

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. 
    ... 

Pierwsza kolumna jest wyraźnie mlint ID, w drugiej kolumnie w rzeczywistości liczbą poziom (0 = głównie nieszkodliwe, 1 = ostrzeżenie, 2 = błąd, 4-7 = poważniejsze problemy wewnętrzne), a trzecia kolumna to komunikat, który jest wyświetlany.

Jak widać, wszystkie kategorie również mają identyfikator, ale nie mają istotności, a ich format wiadomości to ===== Category Name =====.

Teraz możemy po prostu przeanalizować te informacje i stworzyć strukturę danych, która pozwoli nam łatwo sprawdzić istotność i kategorię dla danego identyfikatora mlint.

Znowu jednak nie zawsze jest tak łatwo. Niestety, checkcode (lub mlint) po prostu wypisuje tę informację do okna poleceń i nie przypisuje jej do żadnej z naszych zmiennych wyjściowych. Z tego powodu konieczne jest użycie evalc (shudder), aby przechwycić dane wyjściowe i zapisać je jako ciąg znaków. Następnie możemy łatwo przeanalizować ten ciąg, aby uzyskać kategorię i nasilenie związane z każdym identyfikatorem mlint.

Przykład Parser

I umieścić wszystkie części I omówiono wcześniej razem w małej funkcji, która generuje struct gdzie wszystkie pola są mlint ID. Wewnątrz każdego pola otrzymasz następujące informacje:

warnings = mlintCatalog(); 
warnings.DWVRD 

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

A tu jest mała funkcja, jeśli jesteś zainteresowany.

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 

Streszczenie

Jest to zupełnie bez dokumentów, ale dość wytrzymała sposobem się kategorię i nasilenia związanego z danym mlint ID. Ta funkcjonalność istniała w 2010 roku, a może nawet wcześniej, dlatego powinna działać z każdą wersją MATLAB, z którą masz do czynienia. Takie podejście jest również o wiele bardziej elastyczne niż po prostu zanotowanie, jakie kategorie ma dany identyfikator mlint, ponieważ kategoria (i poziom ważności) zmieni się z wersji na wersję, gdy nowe funkcje zostaną dodane, a stare funkcje zostaną uznane za przestarzałe.

Dziękuję za zadanie tego trudnego pytania i mam nadzieję, że ta odpowiedź zapewni niewielką pomoc i wgląd!

+0

To wydaje się o wiele lepszym rozwiązaniem niż użycie pliku Excela, który stworzyłem do ich przechowywania. Na pewno zaktualizuję moje metody. Dziękuję Ci. –

+0

+1 Miałem podobną propozycję dla wtyczki do edytora tekstu [Atom] (https://atom.io/): https://github.com/ajdm/linter-matlab/issues/2#issuecomment- 182097020 – Amro

0

Tylko do zamknięcia tego wydania. Udało mi się wyodrębnić dane z kilku różnych miejsc i złożyć je razem. Mam teraz arkusz kalkulacyjny Excela wszystkich ostrzeżeń i błędów matlaba z kolumnami odpowiadającymi ich kodom ID, kategorii i ciężkości (np. Jeśli jest to ostrzeżenie lub błąd). Mogę teraz odczytać ten plik, wyszukać kody identyfikacyjne, które otrzymuję dzięki funkcji "sprawdź kod" i wyciągnąć wszelkie wymagane informacje. To może teraz zostać użyte do stworzenia narzędzi analitycznych, aby spojrzeć na jakość pisemnych skryptów/klas itp.

Jeśli ktokolwiek chciałby kopię tego pliku, to napisz do mnie wiadomość, a ja z przyjemnością go dostarczę.

Darren.

Powiązane problemy