diff --git a/plugins/cpp/model/include/model/cpprecord.h b/plugins/cpp/model/include/model/cpprecord.h index a6765894a..4bf0d1a93 100644 --- a/plugins/cpp/model/include/model/cpprecord.h +++ b/plugins/cpp/model/include/model/cpprecord.h @@ -49,8 +49,21 @@ typedef std::shared_ptr CppMemberTypePtr; #pragma db object struct CppRecord : CppEntity { + enum Context { + TOP_LEVEL, + NAMESPACE, + RECORD, + FUNCTION, + OTHER + }; + bool isAbstract = false; bool isPOD = false; + bool isLambda = false; + + // Context defines where the CppRecord is located in (e.g. in a namespace). + // Context = RECORD means it is nested within another record. + Context context = Context::OTHER; std::string toString() const { @@ -72,6 +85,18 @@ struct CppRecord : CppEntity return ret; } + + std::string getContextString() const + { + switch (context) + { + case Context::TOP_LEVEL: return "Top Level"; + case Context::NAMESPACE: return "Namespace"; + case Context::RECORD: return "Record"; + case Context::FUNCTION: return "Function"; + case Context::OTHER: return "Other"; + } + } }; typedef std::shared_ptr CppRecordPtr; diff --git a/plugins/cpp/parser/src/clangastvisitor.h b/plugins/cpp/parser/src/clangastvisitor.h index 10683fd65..9849f785b 100644 --- a/plugins/cpp/parser/src/clangastvisitor.h +++ b/plugins/cpp/parser/src/clangastvisitor.h @@ -614,6 +614,20 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor cppRecord->entityHash = astNode->entityHash; cppRecord->name = rd_->getNameAsString(); cppRecord->qualifiedName = rd_->getQualifiedNameAsString(); + cppRecord->isLambda = rd_->isLambda(); + + const clang::DeclContext* parentDecl = rd_->getParent(); + if (parentDecl) { + if (parentDecl->isTranslationUnit()) { + cppRecord->context = model::CppRecord::Context::TOP_LEVEL; + } else if (parentDecl->isNamespace()) { + cppRecord->context = model::CppRecord::Context::NAMESPACE; + } else if (parentDecl->isRecord()) { + cppRecord->context = model::CppRecord::Context::RECORD; + } else if (parentDecl->isFunctionOrMethod()) { + cppRecord->context = model::CppRecord::Context::FUNCTION; + } + } if (const clang::CXXRecordDecl* crd = llvm::dyn_cast(rd_)) diff --git a/plugins/cpp/service/src/cppservice.cpp b/plugins/cpp/service/src/cppservice.cpp index 516043a74..a64387fb9 100644 --- a/plugins/cpp/service/src/cppservice.cpp +++ b/plugins/cpp/service/src/cppservice.cpp @@ -333,9 +333,12 @@ void CppServiceHandler::getProperties( return_["Abstract type"] = "true"; if (type.isPOD) return_["POD type"] = "true"; + if(type.isLambda) + return_["Lambda"] = "true"; return_["Name"] = type.name; return_["Qualified name"] = type.qualifiedName; + return_["Context"] = type.getContextString(); } else LOG(warning) diff --git a/plugins/cpp/test/src/cpppropertiesservicetest.cpp b/plugins/cpp/test/src/cpppropertiesservicetest.cpp index bf8240ee8..44a03f7ef 100644 --- a/plugins/cpp/test/src/cpppropertiesservicetest.cpp +++ b/plugins/cpp/test/src/cpppropertiesservicetest.cpp @@ -86,6 +86,7 @@ TEST_F(CppPropertiesServiceTest, ClassPropertiesTest) std::map expected = { {"Name", "SimpleClass"}, + {"Context", "Namespace"}, {"Qualified name", "cc::test::SimpleClass"} }; @@ -96,6 +97,7 @@ TEST_F(CppPropertiesServiceTest, ClassPropertiesTest) std::map expected = { {"Name", "NestedClass"}, + {"Context", "Namespace"}, {"Qualified name", "cc::test::NestedClass"}, {"POD type", "true"} }; @@ -107,6 +109,7 @@ TEST_F(CppPropertiesServiceTest, ClassPropertiesTest) std::map expected = { {"Name", "InnerClass"}, + {"Context", "Record"}, {"Qualified name", "cc::test::NestedClass::InnerClass"}, {"POD type", "true"} }; @@ -121,6 +124,7 @@ TEST_F(CppPropertiesServiceTest, InheritancePropertiesTest) std::map expected = { {"Name", "BaseClass1"}, + {"Context", "Namespace"}, {"Qualified name", "cc::test::BaseClass1"}, {"Abstract type", "true"} }; @@ -132,6 +136,7 @@ TEST_F(CppPropertiesServiceTest, InheritancePropertiesTest) std::map expected = { {"Name", "DerivedClass"}, + {"Context", "Namespace"}, {"Qualified name", "cc::test::DerivedClass"} }; diff --git a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h index 9fabefd1c..9601e9b1d 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -7,6 +7,9 @@ #include #include +#include +#include + #include #include @@ -88,6 +91,8 @@ class CppMetricsParser : public AbstractParser void relationalCohesionModuleLevel(); // Returns module path query based on parser configuration. odb::query getModulePathsQuery(); + // Returns cohesion record query based on parser configuration. + odb::query getCohesionRecordQuery(); /// @brief Constructs an ODB query that you can use to filter only /// the database records of the given parameter type whose path diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index cfe2db646..83be2f050 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -264,13 +264,28 @@ void CppMetricsParser::typeMcCabe() }); } +odb::query CppMetricsParser::getCohesionRecordQuery() +{ + odb::query query = getFilterPathsQuery(); + + if (_ctx.options.count("cppmetrics-ignore-lambdas")) { + query = query && odb::query::CppRecord::isLambda == false; + } + + if (_ctx.options.count("cppmetrics-ignore-nested-classes")) { + query = query && odb::query::CppRecord::context != model::CppRecord::Context::RECORD; + } + + return query; +} + void CppMetricsParser::lackOfCohesion() { // Calculate the cohesion metric for all types on parallel threads. parallelCalcMetric( "Lack of cohesion", _threadCount * lackOfCohesionPartitionMultiplier, // number of jobs; adjust for granularity - getFilterPathsQuery(), + getCohesionRecordQuery(), [&, this](const MetricsTasks& tasks) { util::OdbTransaction {_ctx.db} ([&, this] @@ -376,7 +391,7 @@ void CppMetricsParser::efferentTypeLevel() parallelCalcMetric( "Efferent coupling of types", _threadCount * efferentCouplingTypesPartitionMultiplier,// number of jobs; adjust for granularity - getFilterPathsQuery(), + getCohesionRecordQuery(), [&, this](const MetricsTasks& tasks) { util::OdbTransaction{_ctx.db}([&, this] @@ -456,7 +471,7 @@ void CppMetricsParser::afferentTypeLevel() parallelCalcMetric( "Afferent coupling of types", _threadCount * afferentCouplingTypesPartitionMultiplier,// number of jobs; adjust for granularity - getFilterPathsQuery(), + getCohesionRecordQuery(), [&, this](const MetricsTasks& tasks) { util::OdbTransaction{_ctx.db}([&, this] @@ -697,6 +712,12 @@ extern "C" { boost::program_options::options_description description("C++ Metrics Plugin"); + description.add_options() + ("cppmetrics-ignore-lambdas", + "Skip Efferent/Afferent Coupling, Lack of Cohesion C++ metrics calculations for lambdas.") + ("cppmetrics-ignore-nested-classes", + "Skip Efferent/Afferent Coupling, Lack of Cohesion C++ metrics calculations for nested classes."); + return description; }