Skip to content

Commit

Permalink
Initial naive metrics extractor implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
dbukki committed Mar 28, 2024
1 parent e77d2cd commit 036d719
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 0 deletions.
75 changes: 75 additions & 0 deletions plugins/cpp/parser/src/clangastvisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#include "symbolhelper.h"
#include "nestedscope.h"

#include <iostream>

namespace cc
{
namespace parser
Expand Down Expand Up @@ -868,6 +870,9 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor<ClangASTVisitor>

//--- CppFunction ---//

if (!fn_->isThisDeclarationADefinition())
return true;

model::CppFunctionPtr cppFunction = _functionStack.top();

clang::QualType qualType = fn_->getReturnType();
Expand All @@ -882,6 +887,73 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor<ClangASTVisitor>
cppFunction->bumpiness = 0;
cppFunction->statementCount = 0;

unsigned int count = fn_->getNumTemplateParameterLists();
for (unsigned int t = 0; t < count; ++t)
{
if (clang::TemplateParameterList* pTPars = fn_->getTemplateParameterList(t))
{
cppFunction->qualifiedName += '<';
for (unsigned int p = 0; p < pTPars->size(); ++p)
{
const clang::NamedDecl* par = pTPars->getParam(p);
if (p > 0)
cppFunction->qualifiedName += ',';
cppFunction->qualifiedName += par->getQualifiedNameAsString();
}
cppFunction->qualifiedName += '>';
}
}

/*if (const clang::TemplateArgumentList* pTArgs = fn_->getTemplateSpecializationArgs())
{
cppFunction->qualifiedName += '<';
for (unsigned int t = 0; t < pTArgs->size(); ++t)
{
const clang::TemplateArgument& arg = pTArgs->get(t);
if (t > 0)
cppFunction->qualifiedName += ',';
cppFunction->qualifiedName += arg.getParamTypeForDecl().getAsString();
}
cppFunction->qualifiedName += '>';
}*/

const auto itPB = fn_->param_begin();
const auto itPE = fn_->param_end();
cppFunction->qualifiedName += '(';
for (auto it = itPB; it != itPE; ++it)
{
if (it != itPB)
cppFunction->qualifiedName += ',';
cppFunction->qualifiedName += (*it)->getType().getAsString();
}
cppFunction->qualifiedName += ')';

if (clang::CXXMethodDecl* md_ = llvm::dyn_cast<clang::CXXMethodDecl>(fn_))
{
clang::Qualifiers qs = md_->getMethodQualifiers();
if (qs.hasConst())
cppFunction->qualifiedName += " const";
if (qs.hasVolatile())
cppFunction->qualifiedName += " volatile";
if (qs.hasRestrict())
cppFunction->qualifiedName += " restrict";

clang::RefQualifierKind rqs = md_->getRefQualifier();
switch (rqs)
{
case clang::RefQualifierKind::RQ_None:
break;
case clang::RefQualifierKind::RQ_LValue:
cppFunction->qualifiedName += "&";
break;
case clang::RefQualifierKind::RQ_RValue:
cppFunction->qualifiedName += "&&";
break;
}
}

//std::cout << cppFunction->qualifiedName << std::endl;

//--- Tags ---//

if (_isImplicit)
Expand Down Expand Up @@ -1066,6 +1138,9 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor<ClangASTVisitor>

//--- CppVariable ---//

if (!vd_->isThisDeclarationADefinition())
return true;

model::CppVariablePtr variable = std::make_shared<model::CppVariable>();
_variables.push_back(variable);

Expand Down
34 changes: 34 additions & 0 deletions plugins/cpp_metrics/model/include/model/cppastnodemetrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,40 @@ struct CppRecordMetricsView
double value;
};

#pragma db view \
object(CppAstNodeMetrics) \
object(CppAstNode : CppAstNodeMetrics::astNodeId == CppAstNode::id) \
object(File : CppAstNode::location.file) \
object(CppEntity : CppAstNode::id == CppEntity::astNodeId)
struct CppMetricsLocationView
{
//#pragma db column(CppEntity::name)
//std::string name;
#pragma db column(CppEntity::qualifiedName)
std::string qualifiedName;

typedef cc::model::CppAstNodeMetrics::Type Type;

#pragma db column(CppAstNodeMetrics::type)
Type type;
#pragma db column(CppAstNodeMetrics::value)
double value;

typedef cc::model::Position::PosType PosType;

#pragma db column(CppAstNode::location.range.start.line)
PosType startLine;
#pragma db column(CppAstNode::location.range.start.column)
PosType startColumn;
#pragma db column(CppAstNode::location.range.end.line)
PosType endLine;
#pragma db column(CppAstNode::location.range.end.column)
PosType endColumn;

#pragma db column(File::path)
std::string filePath;
};

} //model
} //cc

Expand Down
131 changes: 131 additions & 0 deletions plugins/cpp_metrics/parser/src/cppmetricsparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
#include <model/cppastnode-odb.hxx>

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

#include <util/filesystem.h>
#include <util/logutil.h>
#include <util/filesystem.h>
#include <util/odbtransaction.h>

#include <memory>
#include <iostream>
#include <fstream>

namespace cc
{
Expand Down Expand Up @@ -270,12 +273,140 @@ void CppMetricsParser::lackOfCohesion()
});
}

class AstNodeLoc
{
public:
typedef model::Position::PosType Pos;

private:
std::string _file;
model::Range _range;
std::size_t _hash;

public:
const std::string& file() const { return _file; }
const model::Range& range() const { return _range; }

public:
struct Hash
{ std::size_t operator()(const AstNodeLoc& node) const { return node._hash; } };

public:
AstNodeLoc(const std::string& file_, Pos sLn_, Pos sCol_, Pos eLn_, Pos eCol_) :
_file(file_),
_range(model::Position(sLn_, sCol_), model::Position(eLn_, eCol_)),
_hash(0)
{
std::hash<std::string> hStr;
std::hash<Pos> hPos;

_hash ^= hStr(_file);
_hash ^= hPos(_range.start.line);
_hash ^= hPos(_range.start.column);
_hash ^= hPos(_range.end.line);
_hash ^= hPos(_range.end.column);
}

public:
bool operator==(const AstNodeLoc& other) const
{
return _range == other._range && _file == other._file;
}
};

bool CppMetricsParser::parse()
{
functionParameters();
functionMcCabe();
functionBumpyRoad();
lackOfCohesion();

std::string sName;
std::cout << "\nExtraction name: ";
std::getline(std::cin, sName);
boost::trim(sName);
if (!sName.empty())
{
boost::filesystem::path pRootDir = "/home/dani/Artifacts/Extract/";
pRootDir /= sName;
boost::filesystem::path pCodeDir = pRootDir / "Code/";
boost::filesystem::create_directories(pCodeDir);
std::cout << "Extracting to: " << pRootDir.c_str() << std::endl;

util::OdbTransaction {_ctx.db} ([&, this]
{
typedef model::CppAstNodeMetrics::Type Type;
std::unordered_map<Type, std::unique_ptr<std::ofstream>> umReg;
umReg.emplace(Type::PARAMETER_COUNT,
std::make_unique<std::ofstream>((pRootDir / "ParamCount.ccr").c_str()));
umReg.emplace(Type::MCCABE,
std::make_unique<std::ofstream>((pRootDir / "McCabe.ccr").c_str()));
umReg.emplace(Type::BUMPY_ROAD,
std::make_unique<std::ofstream>((pRootDir / "BumpyRoad.ccr").c_str()));
umReg.emplace(Type::LACK_OF_COHESION,
std::make_unique<std::ofstream>((pRootDir / "LackOfCoh.ccr").c_str()));
umReg.emplace(Type::LACK_OF_COHESION_HS,
std::make_unique<std::ofstream>((pRootDir / "LackOfCohHS.ccr").c_str()));

std::unordered_map<AstNodeLoc, std::size_t, AstNodeLoc::Hash> umCode;

constexpr auto npos = model::Position::npos;
for (const model::CppMetricsLocationView& view
: _ctx.db->query<model::CppMetricsLocationView>())
{
if ((view.startLine != npos && view.startColumn != npos && view.endLine != npos && view.endColumn != npos)
&& (view.startLine < view.endLine || (view.startLine == view.endLine && view.startColumn < view.endColumn)))
{
AstNodeLoc loc(view.filePath,
view.startLine, view.startColumn,
view.endLine, view.endColumn);

auto resCode = umCode.insert(std::make_pair(loc, umCode.size()));
if (resCode.second)
{
std::ostringstream sDstPath;
sDstPath << pCodeDir.c_str() << resCode.first->second << ".ccx";

std::ifstream isSrc(loc.file());
std::ofstream osDst(sDstPath.str());

AstNodeLoc::Pos ln = 1;
AstNodeLoc::Pos col = 1;
bool extract = false;
int ch;
while ((ch = isSrc.get()) >= 0)
{
if (ln == loc.range().start.line && col == loc.range().start.column)
extract = true;
if (ln == loc.range().end.line && col == loc.range().end.column)
{ extract = false; break; }

if (extract)
osDst.put(ch);

if (ch == '\n')
++ln, col = 1;
else ++col;
}

if (extract)
{
std::cerr << loc.file()
<< '\t' << loc.range().start.line << ':' << loc.range().start.column
<< '-' << loc.range().end.line << ':' << loc.range().end.column
<< std::endl;
std::cerr << "ln = " << ln << ", col = " << col << std::endl;
assert(false);
}
}

std::ostream& osReg = *umReg[view.type];
osReg << view.qualifiedName << '\t' << view.value << '\t' << resCode.first->second << '\n';
}
}
});
}
else std::cout << "No extraction took place." << std::endl;
return true;
}

Expand Down

0 comments on commit 036d719

Please sign in to comment.