Skip to content

Commit

Permalink
Cpp metrics plugin (#638)
Browse files Browse the repository at this point in the history
Co-authored-by: Máté Cserép <[email protected]>
  • Loading branch information
intjftw and mcserep authored Nov 8, 2023
1 parent c8bdffb commit 9c4a016
Show file tree
Hide file tree
Showing 15 changed files with 478 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5.1)
cmake_minimum_required(VERSION 3.16.3)
project(CodeCompass)

# Common config variables and settings
Expand Down
5 changes: 5 additions & 0 deletions Functions.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Generate ODB files from sources
# @return ODB_CXX_SOURCES - odb cxx source files
function(generate_odb_files _src)
set(DEPENDENCY_PLUGIN_INCLUDE_DIRS ${ARGN})
list(TRANSFORM DEPENDENCY_PLUGIN_INCLUDE_DIRS PREPEND "-I${CMAKE_SOURCE_DIR}/plugins/")
list(TRANSFORM DEPENDENCY_PLUGIN_INCLUDE_DIRS APPEND "/model/include")

foreach(_file ${_src})
get_filename_component(_dir ${_file} DIRECTORY)
get_filename_component(_name ${_file} NAME)
Expand All @@ -25,6 +29,7 @@ function(generate_odb_files _src)
-I ${CMAKE_SOURCE_DIR}/model/include
-I ${CMAKE_SOURCE_DIR}/util/include
-I ${ODB_INCLUDE_DIRS}
${DEPENDENCY_PLUGIN_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/${_file}
COMMAND
mv ${CMAKE_CURRENT_BINARY_DIR}/include/model/${_cxx}
Expand Down
12 changes: 12 additions & 0 deletions plugins/cpp/model/include/model/cppfunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ struct CppFunctionParamCount
std::size_t count;
};

#pragma db view \
object(CppFunction) object(CppVariable = Parameters : CppFunction::parameters) \
query((?) + "GROUP BY" + cc::model::CppEntity::astNodeId)
struct CppFunctionParamCountWithId
{
#pragma db column("CppEntity.astNodeId")
CppAstNodeId id;

#pragma db column("count(" + Parameters::id + ")")
std::size_t count;
};

#pragma db view \
object(CppFunction) object(CppVariable = Locals : CppFunction::locals)
struct CppFunctionLocalCount
Expand Down
15 changes: 15 additions & 0 deletions plugins/cpp_metrics/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# The C++ metrics plugin depends on the C++ plugin's components to be built.

if ("${cpp_PLUGIN_DIR}" STREQUAL "")
# Use SEND_ERROR here so a build file is not generated at the end.
# CodeCompass might use a lot of plugins and produce a lengthy build, so
# a warning at configure time would easily be missed by the users.
message(SEND_ERROR
"C++ Metrics plugin found without C++ plugin in the plugins directory.")
endif()

add_subdirectory(model)
add_subdirectory(parser)
add_subdirectory(service)

#install_webplugin(webgui)
16 changes: 16 additions & 0 deletions plugins/cpp_metrics/model/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
include_directories(
include
${cpp_PLUGIN_DIR}/model/include)

message(WARNING "${cpp_PLUGIN_DIR}/model/include")

set(ODB_SOURCES
include/model/cppastnodemetrics.h
include/model/cppfilemetrics.h)

generate_odb_files("${ODB_SOURCES}" "cpp")

add_odb_library(cppmetricsmodel ${ODB_CXX_SOURCES})
target_link_libraries(cppmetricsmodel cppmodel)

install_sql()
35 changes: 35 additions & 0 deletions plugins/cpp_metrics/model/include/model/cppastnodemetrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef CC_MODEL_CPPASTNODEMETRICS_H
#define CC_MODEL_CPPASTNODEMETRICS_H

#include <model/cppastnode.h>

namespace cc
{
namespace model
{

#pragma db object
struct CppAstNodeMetrics
{
enum Type
{
PARAMETER_COUNT
};

#pragma db id auto
std::uint64_t id;

#pragma db not_null
CppAstNodeId astNodeId;

#pragma db not_null
Type type;

#pragma db not_null
unsigned value;
};

} //model
} //cc

#endif //CC_MODEL_CPPASTNODEMETRICS_H
35 changes: 35 additions & 0 deletions plugins/cpp_metrics/model/include/model/cppfilemetrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef CC_MODEL_CPPFILEMETRICS_H
#define CC_MODEL_CPPFILEMETRICS_H

#include <model/file.h>

namespace cc
{
namespace model
{

#pragma db object
struct CppFileMetrics
{
enum Type
{
PLACEHOLDER
};

#pragma db id auto
std::uint64_t id;

#pragma db not_null
FileId file;

#pragma db not_null
Type type;

#pragma db not_null
unsigned value;
};

} //model
} //cc

#endif //CC_MODEL_CPPFILEMETRICS_H
21 changes: 21 additions & 0 deletions plugins/cpp_metrics/parser/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
include_directories(
include
${PROJECT_SOURCE_DIR}/model/include
${PROJECT_SOURCE_DIR}/util/include
${PROJECT_SOURCE_DIR}/parser/include
${PROJECT_SOURCE_DIR}/plugins/cpp/model/include
${PROJECT_BINARY_DIR}/plugins/cpp/model/include
${PLUGIN_DIR}/model/include)

add_library(cxxmetricsparser SHARED
src/cppmetricsparser.cpp)

target_link_libraries(cxxmetricsparser
cppmetricsmodel
model
util
${Boost_LIBRARIES})

install(TARGETS cxxmetricsparser
LIBRARY DESTINATION ${INSTALL_LIB_DIR}
DESTINATION ${INSTALL_PARSER_DIR})
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef CC_PARSER_CPPMETRICSPARSER_H
#define CC_PARSER_CPPMETRICSPARSER_H

#include <parser/abstractparser.h>
#include <parser/parsercontext.h>

#include <model/cppastnodemetrics.h>
#include <model/cppastnodemetrics-odb.hxx>

#include <model/cppfunction.h>
#include <model/cppfunction-odb.hxx>

#include <util/parserutil.h>
#include <util/threadpool.h>

namespace cc
{
namespace parser
{

class CppMetricsParser : public AbstractParser
{
public:
CppMetricsParser(ParserContext& ctx_);
virtual ~CppMetricsParser();
virtual bool cleanupDatabase() override;
virtual bool parse() override;

private:
void functionParameters();

std::unordered_set<model::FileId> _fileIdCache;
std::unordered_map<model::CppAstNodeId, model::FileId> _astNodeIdCache;
std::unique_ptr<util::JobQueueThreadPool<std::string>> _pool;
};

} // parser
} // cc

#endif // CC_PARSER_CPPMETRICSPARSER_H
151 changes: 151 additions & 0 deletions plugins/cpp_metrics/parser/src/cppmetricsparser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#include <cppmetricsparser/cppmetricsparser.h>

#include <model/cppastnodemetrics.h>
#include <model/cppastnodemetrics-odb.hxx>
#include <model/cppfilemetrics.h>
#include <model/cppfilemetrics-odb.hxx>

#include <model/cppastnode.h>
#include <model/cppastnode-odb.hxx>

#include <boost/filesystem.hpp>

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

#include <memory>

namespace cc
{
namespace parser
{

CppMetricsParser::CppMetricsParser(ParserContext& ctx_): AbstractParser(ctx_)
{
util::OdbTransaction {_ctx.db} ([&, this] {
for (const model::CppFileMetrics& fm
: _ctx.db->query<model::CppFileMetrics>())
{
_fileIdCache.insert(fm.file);
}

for (const model::CppAstNodeMetrics& anm
: _ctx.db->query<model::CppAstNodeMetrics>())
{
auto node = _ctx.db->query_one<model::CppAstNode>(
odb::query<model::CppAstNode>::id == anm.astNodeId);
_astNodeIdCache.insert({anm.astNodeId, node->location.file->id});
}
});
}

bool CppMetricsParser::cleanupDatabase()
{
if (!_fileIdCache.empty())
{
try
{
util::OdbTransaction {_ctx.db} ([this] {
for (const model::File& file
: _ctx.db->query<model::File>(
odb::query<model::File>::id.in_range(_fileIdCache.begin(), _fileIdCache.end())))
{
auto it = _ctx.fileStatus.find(file.path);
if (it != _ctx.fileStatus.end() &&
(it->second == cc::parser::IncrementalStatus::DELETED ||
it->second == cc::parser::IncrementalStatus::MODIFIED ||
it->second == cc::parser::IncrementalStatus::ACTION_CHANGED))
{
LOG(info) << "[cxxmetricsparser] Database cleanup: " << file.path;

_ctx.db->erase_query<model::CppFileMetrics>(odb::query<model::CppFileMetrics>::file == file.id);
_fileIdCache.erase(file.id);
}
}

for (const auto& pair : _astNodeIdCache)
{
auto file = _ctx.db->query_one<model::File>(
odb::query<model::File>::id == pair.second);

auto it = _ctx.fileStatus.find(file->path);
if (it != _ctx.fileStatus.end() &&
(it->second == cc::parser::IncrementalStatus::DELETED ||
it->second == cc::parser::IncrementalStatus::MODIFIED ||
it->second == cc::parser::IncrementalStatus::ACTION_CHANGED))
{
LOG(info) << "[cxxmetricsparser] Database cleanup: " << file->path;

_ctx.db->erase_query<model::CppAstNodeMetrics>(odb::query<model::CppAstNodeMetrics>::astNodeId == pair.first);
_astNodeIdCache.erase(pair.first);
}
}
});
}
catch (odb::database_exception&)
{
LOG(fatal) << "Transaction failed in cxxmetrics parser!";
return false;
}
}
return true;
}

void CppMetricsParser::functionParameters()
{
util::OdbTransaction {_ctx.db} ([&, this]
{
for (const model::CppFunctionParamCountWithId& paramCount
: _ctx.db->query<model::CppFunctionParamCountWithId>())
{
model::CppAstNodeMetrics funcParams;
funcParams.astNodeId = paramCount.id;
funcParams.type = model::CppAstNodeMetrics::Type::PARAMETER_COUNT;
funcParams.value = paramCount.count;
_ctx.db->persist(funcParams);
}
});
}

bool CppMetricsParser::parse()
{
// Function parameter number metric.
functionParameters();

return true;
}

CppMetricsParser::~CppMetricsParser()
{
}

/* These two methods are used by the plugin manager to allow dynamic loading
of CodeCompass Parser plugins. Clang (>= version 6.0) gives a warning that
these C-linkage specified methods return types that are not proper from a
C code.
These codes are NOT to be called from any C code. The C linkage is used to
turn off the name mangling so that the dynamic loader can easily find the
symbol table needed to set the plugin up.
*/
// When writing a plugin, please do NOT copy this notice to your code.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
extern "C"
{
boost::program_options::options_description getOptions()
{
boost::program_options::options_description description("C++ Metrics Plugin");

return description;
}

std::shared_ptr<CppMetricsParser> make(ParserContext& ctx_)
{
return std::make_shared<CppMetricsParser>(ctx_);
}
}
#pragma clang diagnostic pop

} // parser
} // cc
Loading

0 comments on commit 9c4a016

Please sign in to comment.