Skip to content

Commit 9c4a016

Browse files
intjftwmcserep
andauthored
Cpp metrics plugin (#638)
Co-authored-by: Máté Cserép <mcserep@gmail.com>
1 parent c8bdffb commit 9c4a016

File tree

15 files changed

+478
-1
lines changed

15 files changed

+478
-1
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.5.1)
1+
cmake_minimum_required(VERSION 3.16.3)
22
project(CodeCompass)
33

44
# Common config variables and settings

Functions.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Generate ODB files from sources
22
# @return ODB_CXX_SOURCES - odb cxx source files
33
function(generate_odb_files _src)
4+
set(DEPENDENCY_PLUGIN_INCLUDE_DIRS ${ARGN})
5+
list(TRANSFORM DEPENDENCY_PLUGIN_INCLUDE_DIRS PREPEND "-I${CMAKE_SOURCE_DIR}/plugins/")
6+
list(TRANSFORM DEPENDENCY_PLUGIN_INCLUDE_DIRS APPEND "/model/include")
7+
48
foreach(_file ${_src})
59
get_filename_component(_dir ${_file} DIRECTORY)
610
get_filename_component(_name ${_file} NAME)
@@ -25,6 +29,7 @@ function(generate_odb_files _src)
2529
-I ${CMAKE_SOURCE_DIR}/model/include
2630
-I ${CMAKE_SOURCE_DIR}/util/include
2731
-I ${ODB_INCLUDE_DIRS}
32+
${DEPENDENCY_PLUGIN_INCLUDE_DIRS}
2833
${CMAKE_CURRENT_SOURCE_DIR}/${_file}
2934
COMMAND
3035
mv ${CMAKE_CURRENT_BINARY_DIR}/include/model/${_cxx}

plugins/cpp/model/include/model/cppfunction.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ struct CppFunctionParamCount
3939
std::size_t count;
4040
};
4141

42+
#pragma db view \
43+
object(CppFunction) object(CppVariable = Parameters : CppFunction::parameters) \
44+
query((?) + "GROUP BY" + cc::model::CppEntity::astNodeId)
45+
struct CppFunctionParamCountWithId
46+
{
47+
#pragma db column("CppEntity.astNodeId")
48+
CppAstNodeId id;
49+
50+
#pragma db column("count(" + Parameters::id + ")")
51+
std::size_t count;
52+
};
53+
4254
#pragma db view \
4355
object(CppFunction) object(CppVariable = Locals : CppFunction::locals)
4456
struct CppFunctionLocalCount

plugins/cpp_metrics/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# The C++ metrics plugin depends on the C++ plugin's components to be built.
2+
3+
if ("${cpp_PLUGIN_DIR}" STREQUAL "")
4+
# Use SEND_ERROR here so a build file is not generated at the end.
5+
# CodeCompass might use a lot of plugins and produce a lengthy build, so
6+
# a warning at configure time would easily be missed by the users.
7+
message(SEND_ERROR
8+
"C++ Metrics plugin found without C++ plugin in the plugins directory.")
9+
endif()
10+
11+
add_subdirectory(model)
12+
add_subdirectory(parser)
13+
add_subdirectory(service)
14+
15+
#install_webplugin(webgui)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
include_directories(
2+
include
3+
${cpp_PLUGIN_DIR}/model/include)
4+
5+
message(WARNING "${cpp_PLUGIN_DIR}/model/include")
6+
7+
set(ODB_SOURCES
8+
include/model/cppastnodemetrics.h
9+
include/model/cppfilemetrics.h)
10+
11+
generate_odb_files("${ODB_SOURCES}" "cpp")
12+
13+
add_odb_library(cppmetricsmodel ${ODB_CXX_SOURCES})
14+
target_link_libraries(cppmetricsmodel cppmodel)
15+
16+
install_sql()
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef CC_MODEL_CPPASTNODEMETRICS_H
2+
#define CC_MODEL_CPPASTNODEMETRICS_H
3+
4+
#include <model/cppastnode.h>
5+
6+
namespace cc
7+
{
8+
namespace model
9+
{
10+
11+
#pragma db object
12+
struct CppAstNodeMetrics
13+
{
14+
enum Type
15+
{
16+
PARAMETER_COUNT
17+
};
18+
19+
#pragma db id auto
20+
std::uint64_t id;
21+
22+
#pragma db not_null
23+
CppAstNodeId astNodeId;
24+
25+
#pragma db not_null
26+
Type type;
27+
28+
#pragma db not_null
29+
unsigned value;
30+
};
31+
32+
} //model
33+
} //cc
34+
35+
#endif //CC_MODEL_CPPASTNODEMETRICS_H
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef CC_MODEL_CPPFILEMETRICS_H
2+
#define CC_MODEL_CPPFILEMETRICS_H
3+
4+
#include <model/file.h>
5+
6+
namespace cc
7+
{
8+
namespace model
9+
{
10+
11+
#pragma db object
12+
struct CppFileMetrics
13+
{
14+
enum Type
15+
{
16+
PLACEHOLDER
17+
};
18+
19+
#pragma db id auto
20+
std::uint64_t id;
21+
22+
#pragma db not_null
23+
FileId file;
24+
25+
#pragma db not_null
26+
Type type;
27+
28+
#pragma db not_null
29+
unsigned value;
30+
};
31+
32+
} //model
33+
} //cc
34+
35+
#endif //CC_MODEL_CPPFILEMETRICS_H
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
include_directories(
2+
include
3+
${PROJECT_SOURCE_DIR}/model/include
4+
${PROJECT_SOURCE_DIR}/util/include
5+
${PROJECT_SOURCE_DIR}/parser/include
6+
${PROJECT_SOURCE_DIR}/plugins/cpp/model/include
7+
${PROJECT_BINARY_DIR}/plugins/cpp/model/include
8+
${PLUGIN_DIR}/model/include)
9+
10+
add_library(cxxmetricsparser SHARED
11+
src/cppmetricsparser.cpp)
12+
13+
target_link_libraries(cxxmetricsparser
14+
cppmetricsmodel
15+
model
16+
util
17+
${Boost_LIBRARIES})
18+
19+
install(TARGETS cxxmetricsparser
20+
LIBRARY DESTINATION ${INSTALL_LIB_DIR}
21+
DESTINATION ${INSTALL_PARSER_DIR})
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef CC_PARSER_CPPMETRICSPARSER_H
2+
#define CC_PARSER_CPPMETRICSPARSER_H
3+
4+
#include <parser/abstractparser.h>
5+
#include <parser/parsercontext.h>
6+
7+
#include <model/cppastnodemetrics.h>
8+
#include <model/cppastnodemetrics-odb.hxx>
9+
10+
#include <model/cppfunction.h>
11+
#include <model/cppfunction-odb.hxx>
12+
13+
#include <util/parserutil.h>
14+
#include <util/threadpool.h>
15+
16+
namespace cc
17+
{
18+
namespace parser
19+
{
20+
21+
class CppMetricsParser : public AbstractParser
22+
{
23+
public:
24+
CppMetricsParser(ParserContext& ctx_);
25+
virtual ~CppMetricsParser();
26+
virtual bool cleanupDatabase() override;
27+
virtual bool parse() override;
28+
29+
private:
30+
void functionParameters();
31+
32+
std::unordered_set<model::FileId> _fileIdCache;
33+
std::unordered_map<model::CppAstNodeId, model::FileId> _astNodeIdCache;
34+
std::unique_ptr<util::JobQueueThreadPool<std::string>> _pool;
35+
};
36+
37+
} // parser
38+
} // cc
39+
40+
#endif // CC_PARSER_CPPMETRICSPARSER_H
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include <cppmetricsparser/cppmetricsparser.h>
2+
3+
#include <model/cppastnodemetrics.h>
4+
#include <model/cppastnodemetrics-odb.hxx>
5+
#include <model/cppfilemetrics.h>
6+
#include <model/cppfilemetrics-odb.hxx>
7+
8+
#include <model/cppastnode.h>
9+
#include <model/cppastnode-odb.hxx>
10+
11+
#include <boost/filesystem.hpp>
12+
13+
#include <util/logutil.h>
14+
#include <util/odbtransaction.h>
15+
16+
#include <memory>
17+
18+
namespace cc
19+
{
20+
namespace parser
21+
{
22+
23+
CppMetricsParser::CppMetricsParser(ParserContext& ctx_): AbstractParser(ctx_)
24+
{
25+
util::OdbTransaction {_ctx.db} ([&, this] {
26+
for (const model::CppFileMetrics& fm
27+
: _ctx.db->query<model::CppFileMetrics>())
28+
{
29+
_fileIdCache.insert(fm.file);
30+
}
31+
32+
for (const model::CppAstNodeMetrics& anm
33+
: _ctx.db->query<model::CppAstNodeMetrics>())
34+
{
35+
auto node = _ctx.db->query_one<model::CppAstNode>(
36+
odb::query<model::CppAstNode>::id == anm.astNodeId);
37+
_astNodeIdCache.insert({anm.astNodeId, node->location.file->id});
38+
}
39+
});
40+
}
41+
42+
bool CppMetricsParser::cleanupDatabase()
43+
{
44+
if (!_fileIdCache.empty())
45+
{
46+
try
47+
{
48+
util::OdbTransaction {_ctx.db} ([this] {
49+
for (const model::File& file
50+
: _ctx.db->query<model::File>(
51+
odb::query<model::File>::id.in_range(_fileIdCache.begin(), _fileIdCache.end())))
52+
{
53+
auto it = _ctx.fileStatus.find(file.path);
54+
if (it != _ctx.fileStatus.end() &&
55+
(it->second == cc::parser::IncrementalStatus::DELETED ||
56+
it->second == cc::parser::IncrementalStatus::MODIFIED ||
57+
it->second == cc::parser::IncrementalStatus::ACTION_CHANGED))
58+
{
59+
LOG(info) << "[cxxmetricsparser] Database cleanup: " << file.path;
60+
61+
_ctx.db->erase_query<model::CppFileMetrics>(odb::query<model::CppFileMetrics>::file == file.id);
62+
_fileIdCache.erase(file.id);
63+
}
64+
}
65+
66+
for (const auto& pair : _astNodeIdCache)
67+
{
68+
auto file = _ctx.db->query_one<model::File>(
69+
odb::query<model::File>::id == pair.second);
70+
71+
auto it = _ctx.fileStatus.find(file->path);
72+
if (it != _ctx.fileStatus.end() &&
73+
(it->second == cc::parser::IncrementalStatus::DELETED ||
74+
it->second == cc::parser::IncrementalStatus::MODIFIED ||
75+
it->second == cc::parser::IncrementalStatus::ACTION_CHANGED))
76+
{
77+
LOG(info) << "[cxxmetricsparser] Database cleanup: " << file->path;
78+
79+
_ctx.db->erase_query<model::CppAstNodeMetrics>(odb::query<model::CppAstNodeMetrics>::astNodeId == pair.first);
80+
_astNodeIdCache.erase(pair.first);
81+
}
82+
}
83+
});
84+
}
85+
catch (odb::database_exception&)
86+
{
87+
LOG(fatal) << "Transaction failed in cxxmetrics parser!";
88+
return false;
89+
}
90+
}
91+
return true;
92+
}
93+
94+
void CppMetricsParser::functionParameters()
95+
{
96+
util::OdbTransaction {_ctx.db} ([&, this]
97+
{
98+
for (const model::CppFunctionParamCountWithId& paramCount
99+
: _ctx.db->query<model::CppFunctionParamCountWithId>())
100+
{
101+
model::CppAstNodeMetrics funcParams;
102+
funcParams.astNodeId = paramCount.id;
103+
funcParams.type = model::CppAstNodeMetrics::Type::PARAMETER_COUNT;
104+
funcParams.value = paramCount.count;
105+
_ctx.db->persist(funcParams);
106+
}
107+
});
108+
}
109+
110+
bool CppMetricsParser::parse()
111+
{
112+
// Function parameter number metric.
113+
functionParameters();
114+
115+
return true;
116+
}
117+
118+
CppMetricsParser::~CppMetricsParser()
119+
{
120+
}
121+
122+
/* These two methods are used by the plugin manager to allow dynamic loading
123+
of CodeCompass Parser plugins. Clang (>= version 6.0) gives a warning that
124+
these C-linkage specified methods return types that are not proper from a
125+
C code.
126+
127+
These codes are NOT to be called from any C code. The C linkage is used to
128+
turn off the name mangling so that the dynamic loader can easily find the
129+
symbol table needed to set the plugin up.
130+
*/
131+
// When writing a plugin, please do NOT copy this notice to your code.
132+
#pragma clang diagnostic push
133+
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
134+
extern "C"
135+
{
136+
boost::program_options::options_description getOptions()
137+
{
138+
boost::program_options::options_description description("C++ Metrics Plugin");
139+
140+
return description;
141+
}
142+
143+
std::shared_ptr<CppMetricsParser> make(ParserContext& ctx_)
144+
{
145+
return std::make_shared<CppMetricsParser>(ctx_);
146+
}
147+
}
148+
#pragma clang diagnostic pop
149+
150+
} // parser
151+
} // cc

0 commit comments

Comments
 (0)