#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;
}
int BodyPos(const Vector<CppPos> &pos)
{
for(int i = 0; i < pos.GetCount(); i++)
if(pos[i].impl)
return pos[i].line;
return 0;
}
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, Vector<String>(), base, "file", THISBACK(StoreError));
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(
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(
Vector<int>() << tk_if << tk_case << tk_for << tk_while << tk_catch);
static Vector<int> cc2_symbols(
Vector<int>() << t_and << t_or << '?');
FunctionEntry &entry = functions.Add();
entry.pos = BodyPos(functionStat.cppItem.pos);
entry.name = InsertNestingToSignature(functionStat.cppItem.natural,
functionStat.nesting);
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;
}
syntax highlighted by Code2HTML, v. 0.9.1