2015-08-20 13 views
5

Obecnie pracuję nad dość dużym projektem. Aby podnieść jakość naszego kodu, zdecydowaliśmy się na egzekwowanie wartości zwracanych (Kody błędów) dla każdej funkcji. GCC obsługuje ostrzeżenie dotyczące zwracanej wartości funkcji, jednak definicja funkcji musi być poprzedzona następującą flagą.Znajdowanie i modyfikowanie definicji funkcji (C++) za pomocą skryptu bash

static __attribute__((warn_unused_result)) ErrorCode test() { /* code goes here */ } 

Chcę zaimplementować bashscript który analizuje cały kod źródłowy i wysyła ostrzeżenie w przypadku

__attribute__((warn_unused_result)) 

brakuje. Należy pamiętać, że wszystkie funkcje wymagające tego rodzaju modyfikacji zwracają typ o nazwie ErrorCode. Czy myślisz, że jest to możliwe za pośrednictwem skryptu bash?

+0

Polecam, aby rozważyć pisanie to jako plugin dzyń. Napisałem wtyczkę, która analizuje użycie symbolu i ostrzega o tym, że bezużyteczne zawiera około 350 linii kodu, więc nie jest to szczególnie trudne. –

Odpowiedz

3

W prosty sposób mogę sobie wyobrazić, za pośrednictwem ctags. Utwórz plik znacznika na całym kodzie źródłowym, a następnie przeanalizuj plik znaczników. Jednak nie jestem pewien co do formatu pliku znaczników. Wariant, którego tu używam (Exuberant Ctags 5.8) wydaje się umieszczać "f" w czwartej kolumnie, jeśli znacznik reprezentuje funkcję. Tak więc w tym przypadku użyłbym awk do filtrowania wszystkich znaczników reprezentujących funkcje, a następnie grep, aby wyrzucić wszystkie wiersze bez __attribute__((warn_unused_result)).

Tak, w skrócie, najpierw zrobić

$ ctags **/*.c 

To tworzy plik o nazwie „znaczniki” w bieżącym katalogu. Polecenie może być również ctags-exuberant, w zależności od Twojego wariantu. **/*.c to wzór globalny, który może działać w twojej powłoce - jeśli nie, musisz dostarczyć swoje pliki źródłowe w inny sposób (spójrz na opcje ctags).

Następnie filtrować Funktions:

$ cat tags | awk -F '\t' '$4 == "f" {print $0}' | grep -v "__attribute__((warn_unused_result))" 
+0

Spojrzałem na to i wygląda na całkiem obiecujące. Jednak z tego co wiem, metoda nie dba o rodzaj wartości zwracanej przez funkcję. Jednak chcę tylko traktować funkcje z wartością zwracaną ErrorCode –

+0

Ah, przepraszam, ominąłem to w twoim pytaniu. Więc będziesz musiał zagrać trochę za pomocą wyrażeń regularnych. Pierwsza próba może wyglądać następująco: 'cat tags | awk -F '\ t' '4 $ == "f" {wydrukuj 3 $}' | grep '. * ErrorCode. * (' '. Zauważ, że pozwoliłem' awk' tylko wydrukować kolumnę '$ 3', która zawiera wzorzec dla funkcji w mojej wersji' ctags'. Jednak nie jestem do końca pewien czy to działa w szczególnych przypadkach, np. gdy typ zwracany znajduje się w innej linii niż nazwa funkcji, powinieneś zagrać z nim i kontrolować wyniki –

+1

Działa bezbłędnie! Kciuki w górę i wielkie dzięki. –

1

Nie, nie jest to możliwe w ogólnym przypadku. Gramatyka C++ jest najbardziej złożonym ze wszystkich języków, jakie znam, a C++ nie jest parsowalny poprzez wyrażenia regularne w ogólnym przypadku. Możesz odnieść sukces, jeśli ograniczysz się do bardzo wąskiego zestawu zastosowań, ale nie jestem pewien, jak to możliwe w twoim przypadku. Nie sądzę, że wysiłek jest wart wysiłku, ponieważ czasami ignorowanie wyniku działania jest OK.

+0

To nie jest tak skomplikowane, to dość surowy język. – 123

+1

Coś może być bardzo surowe i bardzo złożone w tym samym czasie. Tak jak powiedziałem wcześniej, regexp parsowanie ogólnego kodu C++ nie jest możliwe. – SergeyA

+0

Parsowanie pliku utworzonego za pomocą ctags zostało wykonane dla mnie. Zajmuje się także obszarami nazw, funkcjami inline, szablonami ... –

5

Być może możesz użyć sed z wyrażeń regularnych. Następujące pracował dla mnie na kilka plików testowych próbowałem:

sed -r "s/ErrorCode\s+\w+\s*(.*)\s*\{/__attribute__((warn_unused_result)) \0/g" test.cpp 

Jeśli nie jesteś zaznajomiony z regex, wzór zasadniczo przekłada się na:

errorCode jakieś odstępy, niektóre znaki alfanumeryczne (nazwa funkcji), może jakiś biały spacja, otwarty nawias, cokolwiek (argumenty), bliski nawias, może jakiś biały, otwarty nawias klamrowy.

Jeśli ten wzór zostanie znaleziony, zostanie poprzedzony prefiksem __attribute__((warn_unused_result)). Zauważ, że działa to tylko wtedy, gdy wstawiasz nawias klamrowy zawsze w tym samym wierszu, co argumenty, i nie masz linii podziału w deklaracjach funkcji.

+0

Och, cóż, nie używasz szablonów, prawda? Zdaję sobie sprawę, że to trochę naiwne ... – Jonas

+0

Dzięki! Chyba mógłbym to wykorzystać. Może jednak spowodować wiele błędów. Z tego co otrzymam, to automatycznie zastąpi wskazane zdarzenia. To trochę zbyt ostre jak na mój gust. Czy są jakieś opcje, które powodują, że polecenie zwraca tylko wiersz i plik, w którym może nastąpić wymiana, tak, że nadal mogę zdecydować, czy to zrobić, czy nie? –

+0

Można "grep -E" ErrorCode \ s + \ w + \ s * (. *) \ S * \ {"', aby wydrukować wszystkie wiersze pasujące do wyrażenia regularnego. – Jonas

Powiązane problemy