[c++] analyseren code: leeftijd van functie bepalen met CVS

Pagina: 1
Acties:

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
Ik ben voor mijn afstudeerproject aan het bekijken of van een groot programma (paar miljoen regels code) alles wordt getest, wat kan met code coverage. Vervolgens kan een analyse worden losgelaten op de code zelf, om te bekijken welke stukken als eerste nieuw getest moeten worden. Een van de dingen is de leeftijd: als een functie al lang niet gewijzigd is, zal daar waarschijnlijk geen storende fout inzitten.

Tot zover de inleiding. Wat ik dus wil doen is met een CVS annotate-achtige functie de leeftijd van een functie bepalen (functie lijkt me een mooi detailniveau). Per regel is geen probleem: in elke HTML-CVS interface zit dat wel. Verbouw zo'n open-source projectje naar XML-output, en je hebt bruikbare info. Echte probleem zit hem in het bepalen van begin en eind van de functie, en de functienaam.

Ik ben al bezig geweest met het verbouwen van CTAGS, tot dusver zonder suc6. De c-code zit voor mij te lastig in elkaar om in 2 dagen volledig te begrijpen (duh), wat wel nodig is. Dit pakket kan niet eens de volledige functieomschrijving te pakken krijgen, als ik dat ga aanpassen kan ik net zogoed zelf iets nieuws beginnen.
cccc is een open-source projectje, wat op zich over die informatie zou moeten beschikken: Lines Of Code per functie etc. Ik ben net begonnen me in die source te verdiepen, wat makkelijker lijkt (netjes gestructureerd C++).

Weten jullie nog meer van dergelijke open-source tools? Of misschien een kant-en-klaar pakket dat de leeftijd per functie kan bepalen?

Ik wilde trouwens starten met de laatste wijziging per functie, verfijning is natuurlijk pas stap 2.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Het parsen van C++ is berucht moeilijk. Om maar eens wat domme dingen te noemen: de naam van een functie kan meer dan een regel zijn, het return type is niet triviaal te bepalen (mogelijk afwezig zoals bij ctors en conversie operatoren), templates maken het ook niet makkelijker en macros zijn de echte killers.
Verder, al heb je "de naam", dan heb je nog geen unieke identificatie van een functie vanwege
overloading. Kortom, misschien ben je wat optimistisch.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
Tja, er zijn diverse tools die het wel kunnen: analyseren per functienaam voor coverage, metrics, etc. cccc is er zoeen. Ik hoef ook maar 99% nauwkeurigheid te hebben, als er een keer een functie is die niet herkend wordt is dat niet zo supererg op 10 mln regels code.
Als je macro's buiten beschouwing laat, heb je het volgende als moeilijkste functie om te herkennen:
code:
1
2
3
4
5
6
7
8
9
10
11
return-type classname::classname /*commentaar*/
                  ( //parameters
                   int param_1, //doet iets
                   /*param 2// doet even niets */
                   param3
                  ) : 
                      member(param1)
{
  //en hier de standaard zooi, 
  //die je met regels tellen ook eruit moet filteren
}

Dat is toch wel te doen? Filter de commentaartekens eruit, zoek het haakje, enz. Alleen zijn al die parsers zo verdraaid moeilijk in elkaar gezet, dat ik het vermoeden heb dat het zo zijn nut heeft :).

Er moet toch een tooltje zijn die mij het regelnummer van de openings-accolade en de sluitings-accolade kan geven? Of de regel waarop het return-type staat ofzo...
Ik ga morgen dus weer lekker verder prutsen met cccc, wat lastig is, maar wel te doen. Probleem is dat ze van een andere parser-taal gebruik maken, die helaas niet al te simpel te doorgronden is. Vooral door het gebrek aan specificaties van die versie... :(

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Nou nee. Wat voor moeilijke constructies denk je in return-type tegen te komen?

vb class X f( int ) { }
is legitiem. class is redundant in deze context (oude C vorm).

Daarnaast heb je templates, en specialisaties:
template< typename T> typename T::X f( int ) { }

Het haakje zoeken kan ook lastig zijn:
int(*)(int a) f( int(*b)(int c) ) { return b; }
of
int (X::*) X::operator( ) ( ) { return &X::a; }

Succes.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
Oh ja.... *slik*. Toch maar cccc gebruiken, denk ik zo :). Kan ook een compiler slopen, maar dat is helemaal niet te doen. Dat soort lastige dingen heeft in C altijd een erg stijle leercurve. Mijn kennis van C is natuurlijk ook helemaal toppie, daar ligt het niet aan O-).

Maar zijn er geen tools die regelnummers per functie kunnen geven? Of leeftijd naar functie kunnen bepalen? Lijkt mij niet iets dat nou zo vergezocht is, of ben ik gek?

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Oh, C gaat wel. Dat is in vergelijking simpel. C++ is de killer. Maar kun je niet beter een echte compiler gebruiken, en de output daarvan gebruiken? In VC2003 , met "DUMPBIN /LINENUMBERS e: list.obj" krijg ik mooie output:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Microsoft (R) COFF/PE Dumper Version 7.10.3077
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file e:list.obj

File Type: COFF OBJECT

LINENUMBERS #4

 Symbol index:       19 Base line number:    13
 Symbol name = ??E@YAAAW4ListIterator@@AAW40@@Z (enum ListIterator & __cdecl operator++(enum ListIterator &))
 0000001E(   14)  00000032(   15)

LINENUMBERS #8

 Symbol index:       30 Base line number:    18
 Symbol name = ??D@YAAAHW4ListIterator@@@Z (int & __cdecl operator*(enum ListIterator))
 0000001E(   19)  00000028(   20)

LINENUMBERS #A

 Symbol index:       3D Base line number:    27
 Symbol name = ??0List@@QAE@XZ (public: __thiscall List::List(void))
 00000023(   29)

LINENUMBERS #C

 Symbol index:       4A Base line number:    32
 Symbol name = ??1List@@QAE@XZ (public: __thiscall List::~List(void))
 00000023(   34)

  Summary
<knip>

Dan mag je zelf uitzoeken welke linenumbers je precies wil, en hoe je met functienamen
wil omgaan (d'r zitten nog geen templates in dit stukje).

edit:

De originele code was overigens (eerste codesnippet in VC2003 die ik snel kon vinden, die niet belast was met copyrights)

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// List.cpp: implementation of the List class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "List.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ListIterator& operator++(ListIterator& rhs)
{
    return rhs=List::linkage[rhs];
}

int& operator*(ListIterator rhs)
{
    return List::objects[(int)rhs];
}


int List::objects[li_end];
ListIterator List::linkage[li_end];

List::List()
{

}

List::~List()
{

}

[ Voor 31% gewijzigd door MSalters op 01-03-2005 14:04 . Reden: originele code ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
Te laat, cccc heb ik nu (in 8 uur tijd) verbouwd om ook de eindregel te geven. Het geeft direct de metrics die ik in de volgende ronde nodig heb. Uiteraard is dumpbin wel een mogelijkheid als we besluiten alleen Windows te gebruiken, of als we besluiten om CCCC niet te gebruiken voor metrics.
En misschien, als ik dumpbin roep, gaat er bij iemand hier op GoT of op de afdeling een lampje branden voor een Linux/Unix tooltje :)

edit:
natuurlijk is dat met 1 minuut google ook te vinden: http://aqualinux.chez.tiscali.fr/commun/gcc_vc.htm -> objdump

[ Voor 14% gewijzigd door MBV op 01-03-2005 15:48 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
En? Werkt het met de voorbeelden van een paar posts terug? Nog wat testcases nodig?
Overigens is het unix equivalent nm, voorzover ik weet.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
objdump zou het equivalent moeten zijn, niet uitgeprobeerd. Er zijn vast nog wel een paar handige tools voor.

De voorbeelden die jij noemde zijn wel erg extreem, als dit binnen de code styles van jouw bedrijf valt wil ik daar niet werken:P.
edit:
daarmee doel ik voornamelijk op het 'zoek het haakje'-voorbeeld, aangezien code-styles meestal opgezet zijn dat ze het makkelijker maken om in de code 'in te werken'
offtopic:
wat doet dat eerste 'zoek het haakje'-voorbeeld eigenlijk? meegegeven functie teruggeven?
Ik zal het eens voeren aan cccc, met alle vertrouwen dat het gaat werken :)

[ Voor 25% gewijzigd door MBV op 02-03-2005 13:36 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Eerste functie is inderdaad een functie die een function pointer als argument heeft en dezelfde retourneert. Function pointers als argument en return value zijn gangbaar in FSM implementaties. Ik mag hopen dat jullie FSMs gebruiken, dus dit soort functies zijn niet extreem.
operator( ) is ook gebruikelijk als je de STL gebruikt.

Ik twijfelde een beetje, omdat cccc ANTLR gebruikt. Ik weet dat die 'issues' heeft met sommige C++ constructs. Dat hoeft niet erg te zijn - jij hoeft geen variabelen en types uit elkaar te houden, of casts en functiecalls (twee beruchte parse probelemen in C++).

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
Ik denk dat jij een ander referentiekader hebt. Ik ben über-junior (afstudeerstage), en jij hebt kennelijk wat meer ervaring. Ik zag eerst echt niet wat die functie deed, pas toen ik er 3 keer naar had gekeken viel het me op wat er gebeurde.
FSM had ik nog nooit eerder van gehoord (maar ik begrijp het principe natuurlijk wel, State Transition Diagrams krijg je in het eerste jaar TI op de TH Rijswijk). Ziet eruit als iets dat het beste toepasbaar is in de embedded-richting, maar daar kan ik me in vergissen.

Functiecalls, variabelen en types hoef ik hier idd niet uit elkaar te houden om de functiedefinitie te herkennen. Dat kan wel belangrijk zijn bij het bepalen van de andere metrics, maar daar wordt er ook niet veel gebruik van gemaakt.

En, mede-GOT-ers, nog andere suggesties? Ben benieuwd naar een andere mening dan de (kennelijk goed onderbouwde) mening van MSalters :)

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
Ik heb nog eens even gekeken wat er gebeurt als je templates gebruikt met dumpbin. Op zich geen probleem, hij spuugt alleen 2x die templatefunctie uit (logisch, aangeroepen met int en double, wat zich moet vertalen in 2x een functie). Ik heb daarbij maar direct STL gebruikt, en daar gaat het gigantisch fout: ik krijg 100 extra dingen van stl, waar ik totaal geen onderscheid kan maken in wat 'van mij' is, en wat van de STL.

Ik gebruik dus het volgende stukje code als testcode:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
 * this is just a tiny example to show the possibilities
 * of dumpbin
 */

#include <iostream>

using namespace std;

template <class T>
T return_square(T x)
{
  return x*x;
}

/**
 * this function prints the return value of return_square
 * to stdout
 */

void print_to_screen()
{
  int number;
  number = return_square(5);
  double number2;
  number2 = return_square(2.236068);
  cout <<"return_square(5) returned " << number << endl;
  cout << "return_square(2.246068) returned " <<number2 <<endl;
}

int main()
{
  print_to_screen();
}

/**
 * that's all
 */


Dat dit niet tot regel 334 komt, kan ik ook wel verzinnen. Gekker vind ik de declaraties die op rgl 14 zouden staan... :X

Met CCCC worden de volgende cijfers gegeven:
main() = rgl 31-39
print_to_screen() = rgl 21-31
return_square(T) = 11-21

'k denk dus dat ik mijn modificatie ga uitbreiden met een -1 ergens :) en dan vind ik hem prima...

[edit]
'k heb nog even geprobeerd jouw testcases te compileren, maar mijn compiler vond ze toch wel iets te extreem. De intel compiler roept (bij int(*)(int a)f ( int(*b)(int c)) ) een error: expected an identifier (en wijst naar het eerste haakje sluiten). Ook microsoft compiler zegt er iets over: syntax error: ')'. Ik heb geprobeerd dit te omzeilen met een typedef voor een functiepointer, maar dan zegt hij: error: function returning function is not allowed
Ook bij de member-functie-pointer teruggeven geeft hij een error. Eigenlijk wel vreemd dat dat niet kan, vooral aangezien er volgens jouw vaak gebruik van wordt gemaakt :?

[ Voor 26% gewijzigd door MBV op 04-03-2005 15:04 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Ach, ik had niet heel erg scherp opgelet of de code door een compiler gehaald, maar even wat dingen uit de losse pols geschud. Met een typedef krijg ik het zonder meer werkend, maar de exacte syntax is dus
C++:
1
2
3
4
int (*f(int a))(float b) {
    int x = a;
    return 0;
}

( maar goed dat ik het opzocht, VC2005 blijkt hier een bug te hebben
edit:
in IntelliSense
)

Maar ik heb een nog leukere gevonden:

C++:
1
2
3
struct X { 
  X ( ) { }
}* f( ) { return 0; }

Meteen het returntype definieren in de functiedefinitie >:) Dan kun je dus echt veel rotzooi kwijt.

STL types zijn makkelijk te filteren: die beginnen met std:: of __ of _[A-Z].

[ Voor 3% gewijzigd door MSalters op 07-03-2005 17:36 ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 10-05 18:20
Als je het returntype definieert in je functiedefinitie, hoe wil je dan ooit gebruik maken van die geretourneerde waarde? sssst! niks over recursieve functies zeggen, heb je toch nooit iets aan :P
Maar het is je gelukt, cccc geeft een warning dat hij regel 48-52 negeert. Maar aangezien een van de andere programmeurs hier er ook niks in zag, ga ik er maar vanuit dat het niet vaak voorkomt :). Ook de constructie met die struct vind ik vaag genoeg om te negeren.

Je hebt gelijk, std-zooi is __ of std::. Daarnaast maken we daar ook nog eens weinig gebruik van (Qt voor GUI). Toch lijkt het me niet verstandig: bij dumpbin krijg je tenminste de linenumbers eruit, de GNU-alternatieven (objdump en nm) geven heel onduidelijke info. En dumpbin is niet echt crossplatform... :)

[ Voor 3% gewijzigd door MBV op 07-03-2005 11:22 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Ach, is een deel van m'n werk, dit soort randgevallen. Het voordeel van dit soort dingen goedkrijgen zit 'm meer in de geruststelling die het geeft voor de normalere gevallen.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1