mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
.examples
git-svn-id: svn://ultimatepp.org/upp/trunk@14619 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
02376c48d3
commit
b65edcd720
7 changed files with 0 additions and 344 deletions
|
|
@ -1,119 +0,0 @@
|
|||
#include <CppBase/CppBase.h>
|
||||
#include "Analyse.h"
|
||||
|
||||
|
||||
bool ContainsAt(const String &source, const String &pattern, int pos = 0)
|
||||
{
|
||||
return pos >= 0
|
||||
&& pos + pattern.GetLength() <= source.GetLength()
|
||||
&& 0 == memcmp(source.Begin() + pos, pattern.Begin(), pattern.GetLength());
|
||||
}
|
||||
|
||||
bool StartsWith(const String &source, const String &pattern)
|
||||
{
|
||||
return ContainsAt(source, pattern, 0);
|
||||
}
|
||||
|
||||
bool EndsWith(const String &source, const String &pattern)
|
||||
{
|
||||
return ContainsAt(source, pattern, source.GetLength() - pattern.GetLength());
|
||||
}
|
||||
|
||||
String InsertNestingToSignature(String natural, String nesting)
|
||||
{
|
||||
if(StartsWith(nesting, "::"))
|
||||
nesting.Remove(0, 2);
|
||||
if(nesting.GetCount() && !EndsWith(nesting, "::"))
|
||||
nesting << "::";
|
||||
|
||||
int pos = natural.Find('('); // find the first opening parenthesis
|
||||
pos--;
|
||||
while(pos >= 0 && !iscid(natural[pos])) // skip over non-id chars before paren.
|
||||
pos--;
|
||||
if(pos < 0) return "";
|
||||
while(pos >= 0 && iscid(natural[pos])) // skip over last id before paren
|
||||
pos--;
|
||||
natural.Insert(pos+1, nesting);
|
||||
return natural;
|
||||
}
|
||||
|
||||
CodeMetric::CodeMetric(const String &fileContent) :
|
||||
orphanLines(0), blankLines(0), commentLines(0)
|
||||
{
|
||||
StringStream stream(fileContent);
|
||||
CppBase base;
|
||||
Parser parser;
|
||||
parser.whenFnEnd = THISBACK(StoreMetric);
|
||||
|
||||
parser.Do(stream, base, 0, 0,
|
||||
"file", CNULL,
|
||||
Vector<String>(),
|
||||
Vector<String>(),
|
||||
Index<String>());
|
||||
|
||||
const SrcFile &srcFile = parser.getPreprocessedFile();
|
||||
|
||||
commentLines = srcFile.commentLinesRemoved;
|
||||
blankLines = srcFile.blankLinesRemoved;
|
||||
orphanLines = parser.symbolsOutsideFunctions.GetStat(';');
|
||||
totalLLOC = orphanLines;
|
||||
sumCC1 = sumCC2 = sumDepth = 0;
|
||||
|
||||
for(int i = 0; i < functions.GetCount(); i++) {
|
||||
totalLLOC += functions[i].logicalLinesOfCode;
|
||||
sumCC1 += functions[i].cyclomaticComplexity1;
|
||||
sumCC2 += functions[i].cyclomaticComplexity2;
|
||||
sumDepth += functions[i].scopeDepth;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String CodeMetric::ToString() const
|
||||
{
|
||||
String s;
|
||||
s << "LLOC: " << totalLLOC
|
||||
<< ", Blank: " << blankLines
|
||||
<< ", Comments: " << commentLines;
|
||||
if(errors != "")
|
||||
s << "\nErrors:\n" << errors;
|
||||
return s;
|
||||
}
|
||||
|
||||
void CodeMetric::StoreError(int line, const String &msg)
|
||||
{
|
||||
errors << "line " << line << ": " << msg << "\n";
|
||||
}
|
||||
|
||||
int CodeMetric::LogicalLinesOfCode(const LexSymbolStat &symbolStat)
|
||||
{
|
||||
static Vector<int> oneLiners(pick(
|
||||
Vector<int>() << tk_if << tk_else << tk_switch << tk_case
|
||||
<< tk_for << tk_do << tk_while << tk_try << tk_catch
|
||||
<< tk_struct << tk_class << tk_namespace
|
||||
<< tk_public << tk_private << tk_protected
|
||||
<< ';'));
|
||||
return symbolStat.SumStat( oneLiners );
|
||||
}
|
||||
|
||||
void CodeMetric::StoreMetric(const Parser::FunctionStat & functionStat)
|
||||
{
|
||||
static Vector<int> cc1_symbols(pick(
|
||||
Vector<int>() << tk_if << tk_case << tk_for << tk_while << tk_catch));
|
||||
|
||||
static Vector<int> cc2_symbols(pick(
|
||||
Vector<int>() << t_and << t_or << '?'));
|
||||
|
||||
if(!functionStat.cppItem.impl)
|
||||
return;
|
||||
|
||||
FunctionEntry &entry = functions.Add();
|
||||
|
||||
entry.pos = functionStat.cppItem.line;
|
||||
entry.name = InsertNestingToSignature(functionStat.cppItem.natural,
|
||||
functionStat.scope);
|
||||
int cc1 = 1 + functionStat.symbolStat.SumStat( cc1_symbols );
|
||||
entry.cyclomaticComplexity1 = cc1;
|
||||
entry.cyclomaticComplexity2 = cc1 + functionStat.symbolStat.SumStat( cc2_symbols );
|
||||
entry.logicalLinesOfCode = 2 + LogicalLinesOfCode(functionStat.symbolStat);
|
||||
entry.scopeDepth = functionStat.maxScopeDepth;
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef _CppAnalyse_Analyze_h_
|
||||
#define _CppAnalyse_Analyze_h_
|
||||
|
||||
#include <CppBase/CppBase.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
struct CodeMetric
|
||||
{
|
||||
public:
|
||||
struct FunctionEntry : public Moveable<FunctionEntry>
|
||||
{
|
||||
String name;
|
||||
int pos;
|
||||
int cyclomaticComplexity1;
|
||||
int cyclomaticComplexity2;
|
||||
int logicalLinesOfCode;
|
||||
int scopeDepth;
|
||||
};
|
||||
|
||||
int orphanLines, blankLines, commentLines;
|
||||
int totalLLOC, sumCC1, sumCC2, sumDepth;
|
||||
Vector<FunctionEntry> functions;
|
||||
String errors;
|
||||
|
||||
explicit CodeMetric(const String &fileContent);
|
||||
String ToString() const;
|
||||
|
||||
private:
|
||||
typedef CodeMetric CLASSNAME;
|
||||
void StoreError(int line, const String &msg);
|
||||
void StoreMetric(const Parser::FunctionStat & functionStat);
|
||||
int LogicalLinesOfCode(const LexSymbolStat &symbolStat);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef _CppAnalyse_AnalyseGui_h
|
||||
#define _CppAnalyse_AnalyseGui_h
|
||||
|
||||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
class WarningDisplay : public Display
|
||||
{
|
||||
int limit;
|
||||
Color warningColor;
|
||||
public:
|
||||
WarningDisplay(int limit, Color warningColor = Color(255, 128, 128));
|
||||
void PaintBackground(Draw& w, const Rect& r, const Value& q,
|
||||
Color ink, Color paper, dword style) const;
|
||||
};
|
||||
|
||||
class AnalyseGui : public TopWindow
|
||||
{
|
||||
public:
|
||||
typedef AnalyseGui CLASSNAME;
|
||||
MenuBar menu;
|
||||
Splitter splitter;
|
||||
LineEdit source;
|
||||
ArrayCtrl chart;
|
||||
LineEdit textMetric;
|
||||
WarningDisplay ccDisplay, llocDisplay, depthDisplay;
|
||||
|
||||
AnalyseGui();
|
||||
void MainMenu(Bar& menu);
|
||||
void Open();
|
||||
void UpdateMetric();
|
||||
void GotoFunction();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
PREMULTIPLIED
|
||||
IMAGE_ID(GaugeIcon)
|
||||
|
||||
IMAGE_BEGIN_DATA
|
||||
IMAGE_DATA(120,156,141,146,209,13,192,32,8,5,25,193,145,157,193,175,142,227,102,88,154,210,0,62,176,24,19,19,184,83,74,169)
|
||||
IMAGE_DATA(81,163,83,112,136,35,16,56,57,218,253,199,99,57,61,71,95,230,120,19,220,123,119,140,13,201,33,199,87,171,123,140)
|
||||
IMAGE_DATA(216,62,207,57,159,26,228,112,119,37,14,201,139,195,214,110,172,132,112,197,59,80,111,219,184,140,3,140,18,242,113,78)
|
||||
IMAGE_DATA(234,136,124,50,83,214,117,221,43,13,240,46,55,247,202,145,176,136,151,5,26,78,249,205,1,190,25,21,44,114,160,251)
|
||||
IMAGE_DATA(43,214,253,199,69,84,108,229,201,234,22,126,2,44,165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
IMAGE_END_DATA(160, 1)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
description "Investigating C++ cyclometric complexity\377";
|
||||
|
||||
uses
|
||||
CtrlLib,
|
||||
CppBase;
|
||||
|
||||
file
|
||||
AnalyseGui.h,
|
||||
Analyse.h,
|
||||
AnalyseGui.iml,
|
||||
Analyse.cpp,
|
||||
main.cpp;
|
||||
|
||||
mainconfig
|
||||
"" = "GUI";
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6 B |
|
|
@ -1,127 +0,0 @@
|
|||
#include "AnalyseGui.h"
|
||||
#include "Analyse.h"
|
||||
|
||||
#define IMAGECLASS Images
|
||||
#define IMAGEFILE <CodeMetric/AnalyseGui.iml>
|
||||
#include <Draw/iml.h>
|
||||
|
||||
String defaultCode =
|
||||
"/*"
|
||||
" This tool measures certain source code metrics.\n"
|
||||
" You can type, paste, or load the code you would like measure into this text area.\n"
|
||||
" Metrics provided are:\n"
|
||||
" - Cyclomatic complexity 1: counts the decision points per method, thus estimating the\n"
|
||||
" number of testcases needed for each method.\n"
|
||||
" - Cyclomatic complexity 2: CC1 extended with the implicit decisions created by the\n"
|
||||
" && || and ?: operators. Evaluation:\n"
|
||||
" CC2 1-10 simple, low risk method\n"
|
||||
" CC2 10-20 moderate complexity & risk method\n"
|
||||
" CC2 21-50 high complexity & risk method\n"
|
||||
" CC2 >50 too complex, untestable method, should be refactored\n"
|
||||
" - Depth: measures deepest scope embedding level per method. This estimates the human\n"
|
||||
" memory needed to keep in mind the current context. Any methods with depth > 5 is\n"
|
||||
" considered too complex, and candidate for refactoring\n"
|
||||
" - Logical Lines Of Code: estimates the amount of source code per method in a way\n"
|
||||
" which is mostly independent from code formatting style. Methods longer than 80 LLOC are\n"
|
||||
" too long, and should be refactored.\n"
|
||||
"*/\n"
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" return 0;\n"
|
||||
"}\n";
|
||||
|
||||
String defaultTitle = "CodeMetric GUI";
|
||||
|
||||
|
||||
WarningDisplay::WarningDisplay(int limit, Color warningColor) :
|
||||
limit(limit), warningColor(warningColor)
|
||||
{
|
||||
}
|
||||
|
||||
void WarningDisplay::PaintBackground(Draw& w, const Rect& r, const Value& q,
|
||||
Color ink, Color paper, dword style) const
|
||||
{
|
||||
int v = (int)q;
|
||||
if(v >= limit)
|
||||
paper = warningColor;
|
||||
Display::PaintBackground(w, r, q, ink, paper, style);
|
||||
}
|
||||
|
||||
void AnalyseGui::MainMenu(Bar &bar)
|
||||
{
|
||||
bar.Add("Load file", THISBACK(Open));
|
||||
}
|
||||
|
||||
void AnalyseGui::Open()
|
||||
{
|
||||
FileSelector fsel;
|
||||
fsel.ExecuteOpen("Select file");
|
||||
String fileName = fsel.Get();
|
||||
if(fileName == "")
|
||||
return;
|
||||
source <<= LoadFile(fileName);
|
||||
UpdateMetric();
|
||||
Title(defaultTitle + " [" + fileName + "]");
|
||||
}
|
||||
|
||||
void AnalyseGui::UpdateMetric()
|
||||
{
|
||||
String s = ~source;
|
||||
CodeMetric metric(s);
|
||||
chart.Clear();
|
||||
for(int i = 0; i < metric.functions.GetCount(); i++)
|
||||
{
|
||||
CodeMetric::FunctionEntry & entry =
|
||||
metric.functions[i];
|
||||
chart.Add(entry.name,
|
||||
entry.pos,
|
||||
entry.cyclomaticComplexity1,
|
||||
entry.cyclomaticComplexity2,
|
||||
entry.logicalLinesOfCode,
|
||||
entry.scopeDepth);
|
||||
}
|
||||
|
||||
textMetric.SetData(metric.ToString());
|
||||
}
|
||||
|
||||
void AnalyseGui::GotoFunction()
|
||||
{
|
||||
int cursor = chart.GetCursor();
|
||||
if(cursor >= 0 && cursor < chart.GetCount())
|
||||
{
|
||||
int pos = (int)chart.Get(cursor, 1);
|
||||
source.SetCursor( source.GetPos(pos) );
|
||||
source.CenterCursor();
|
||||
}
|
||||
}
|
||||
|
||||
AnalyseGui::AnalyseGui() :
|
||||
ccDisplay(50), llocDisplay(80), depthDisplay(5)
|
||||
{
|
||||
Title(defaultTitle);
|
||||
Icon(Images::GaugeIcon);
|
||||
AddFrame(menu);
|
||||
menu.Set( THISBACK(MainMenu) );
|
||||
source <<= THISBACK(UpdateMetric);
|
||||
source <<= defaultCode;
|
||||
textMetric.SetEditable(false);
|
||||
chart.AddColumn("Function", 80);
|
||||
chart.AddColumn("Pos", 15);
|
||||
chart.AddColumn("CC1", 15).SetDisplay(ccDisplay);
|
||||
chart.AddColumn("CC2", 15).SetDisplay(ccDisplay);
|
||||
chart.AddColumn("LLOC", 15).SetDisplay(llocDisplay);
|
||||
chart.AddColumn("Depth", 15).SetDisplay(depthDisplay);
|
||||
chart.WhenLeftDouble = THISBACK(GotoFunction);
|
||||
UpdateMetric();
|
||||
splitter.Vert() << source << chart << textMetric;
|
||||
splitter.SetPos(9000, 1);
|
||||
splitter.SetPos(6500, 0);
|
||||
Add(splitter.SizePos());
|
||||
Sizeable().Zoomable();
|
||||
}
|
||||
|
||||
|
||||
GUI_APP_MAIN
|
||||
{
|
||||
AnalyseGui().Run();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue