diff --git a/plugins/cpp/model/include/model/cppastnode.h b/plugins/cpp/model/include/model/cppastnode.h index 21e3dd7dd..67f93507b 100644 --- a/plugins/cpp/model/include/model/cppastnode.h +++ b/plugins/cpp/model/include/model/cppastnode.h @@ -58,6 +58,7 @@ struct CppAstNode LocalTypeLoc, TypedefTypeLoc, InheritanceTypeLoc, + UsingLoc, Other = 1000 }; @@ -133,6 +134,7 @@ inline std::string astTypeToString(CppAstNode::AstType type_) case CppAstNode::AstType::LocalTypeLoc: return "LocalTypeLoc"; case CppAstNode::AstType::TypedefTypeLoc: return "TypedefTypeLoc"; case CppAstNode::AstType::InheritanceTypeLoc: return "InheritanceTypeLoc"; + case CppAstNode::AstType::UsingLoc: return "UsingLoc"; case CppAstNode::AstType::Other: return "Other"; } diff --git a/plugins/cpp/parser/src/clangastvisitor.h b/plugins/cpp/parser/src/clangastvisitor.h index 5d50c4858..f50af517c 100644 --- a/plugins/cpp/parser/src/clangastvisitor.h +++ b/plugins/cpp/parser/src/clangastvisitor.h @@ -998,6 +998,60 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor return true; } + + bool VisitUsingDecl(clang::UsingDecl* ud_) + { + //--- CppAstNode ---// + + for (const clang::UsingShadowDecl* nd : ud_->shadows()) { + model::CppAstNodePtr astNode = std::make_shared(); + + astNode->astValue = getSourceText( + _clangSrcMgr, + ud_->getBeginLoc(), + ud_->getLocation(), + true); + astNode->location = getFileLoc(ud_->getBeginLoc(), ud_->getEndLoc()); + astNode->entityHash = util::fnvHash(getUSR(nd->getTargetDecl())); + + astNode->symbolType = model::CppAstNode::SymbolType::Other; + astNode->astType = model::CppAstNode::AstType::UsingLoc; + + astNode->id = model::createIdentifier(*astNode); + + if (insertToCache(nd, astNode)) + _astNodes.push_back(astNode); + } + + return true; + } + + bool VisitUsingDirectiveDecl(clang::UsingDirectiveDecl* udd_) + { + //--- CppAstNode ---// + + model::CppAstNodePtr astNode = std::make_shared(); + + const clang::NamespaceDecl* nd = udd_->getNominatedNamespace(); + + astNode->astValue = getSourceText( + _clangSrcMgr, + udd_->getBeginLoc(), + udd_->getLocation(), + true); + astNode->location = getFileLoc(udd_->getBeginLoc(), udd_->getEndLoc()); + astNode->entityHash = util::fnvHash(getUSR(nd)); + astNode->symbolType = model::CppAstNode::SymbolType::Namespace; + astNode->astType = model::CppAstNode::AstType::Usage; + + astNode->id = model::createIdentifier(*astNode); + + if (insertToCache(udd_, astNode)) + _astNodes.push_back(astNode); + + return true; + } + bool VisitCXXConstructExpr(clang::CXXConstructExpr* ce_) { model::CppAstNodePtr astNode = std::make_shared(); @@ -1298,7 +1352,7 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor clang::SourceLocation realStart = start_; clang::SourceLocation realEnd = end_; - + if (_clangSrcMgr.isMacroBodyExpansion(start_)) realStart = _clangSrcMgr.getExpansionLoc(start_); if (_clangSrcMgr.isMacroArgExpansion(start_)) diff --git a/plugins/cpp/test/sources/parser/CMakeLists.txt b/plugins/cpp/test/sources/parser/CMakeLists.txt index 9c76a5ae1..d1a7f125a 100644 --- a/plugins/cpp/test/sources/parser/CMakeLists.txt +++ b/plugins/cpp/test/sources/parser/CMakeLists.txt @@ -9,5 +9,6 @@ add_library(CppTestProject STATIC cxxrecord.cpp enum.cpp function.cpp + using.cpp variable.cpp namespace.cpp) diff --git a/plugins/cpp/test/sources/parser/using.cpp b/plugins/cpp/test/sources/parser/using.cpp new file mode 100644 index 000000000..435cf15a6 --- /dev/null +++ b/plugins/cpp/test/sources/parser/using.cpp @@ -0,0 +1,33 @@ +namespace Nested +{ +namespace MyNamespace +{ +class C +{ +}; + +void g(C) { } + +void g(double) { } + +constexpr C VAR1{}; + +template +constexpr T VAR2 = T{}; +} +} + +using namespace Nested; +void g() {} +using MyNamespace::g; + +void using_fun() +{ + using MyNamespace::C; + using MyNamespace::VAR1; + using MyNamespace::VAR2; + + g(); + g(VAR1); + g(VAR2); +} \ No newline at end of file diff --git a/plugins/cpp/test/src/cppparsertest.cpp b/plugins/cpp/test/src/cppparsertest.cpp index 4358af277..f90e21d2f 100644 --- a/plugins/cpp/test/src/cppparsertest.cpp +++ b/plugins/cpp/test/src/cppparsertest.cpp @@ -83,6 +83,10 @@ TEST_F(CppParserTest, FilesAreInDatabase) file = _db->query_value(QFile::filename == "namespace.cpp"); EXPECT_EQ(file.type, "CPP"); EXPECT_EQ(file.parseStatus, model::File::PSFullyParsed); + + file = _db->query_value(QFile::filename == "using.cpp"); + EXPECT_EQ(file.type, "CPP"); + EXPECT_EQ(file.parseStatus, model::File::PSFullyParsed); }); } @@ -546,7 +550,7 @@ TEST_F(CppParserTest, Fields) { _transaction([&, this] { model::CppVariable fieldFunction = _db->query_value( - QCppFunction::name == "fieldFunction"); + QCppVariable::name == "fieldFunction"); RCppAstNode astNodes = _db->query( QCppAstNode::entityHash == fieldFunction.entityHash); @@ -686,11 +690,11 @@ TEST_F(CppParserTest, Namespace) model::CppNamespace myNamespace1 = _db->query_value( QCppNamespace::name == "MyNamespace1"); model::CppAstNode astNode = _db->query_value( - QCppAstNode::entityHash == myNamespace1.entityHash); + QCppAstNode::entityHash == myNamespace1.entityHash && + QCppAstNode::astType == model::CppAstNode::AstType::Definition); EXPECT_EQ(astNode.symbolType, model::CppAstNode::SymbolType::Namespace); EXPECT_EQ(astNode.location.range.start.line, 1); - EXPECT_EQ(astNode.astType, model::CppAstNode::AstType::Definition); model::CppNamespace myNamespace2 = _db->query_value( QCppNamespace::name == "MyNamespace2"); @@ -702,3 +706,66 @@ TEST_F(CppParserTest, Namespace) EXPECT_EQ(astNode.astType, model::CppAstNode::AstType::Definition); }); } + +TEST_F(CppParserTest, Using) +{ + _transaction([&, this] { + model::CppNamespace nested = _db->query_value( + QCppNamespace::name == "Nested"); + + model::CppAstNode astNode = _db->query_value( + QCppAstNode::entityHash == nested.entityHash && + QCppAstNode::astType == model::CppAstNode::AstType::Usage); + + EXPECT_EQ(astNode.symbolType, model::CppAstNode::SymbolType::Namespace); + EXPECT_EQ(astNode.location.range.start.line, 20); + + + model::CppRecord cClass = _db->query_value( + QCppRecord::qualifiedName == "Nested::MyNamespace::C"); + + astNode = _db->query_value( + QCppAstNode::entityHash == cClass.entityHash && + QCppAstNode::astType == model::CppAstNode::AstType::UsingLoc); + + EXPECT_EQ(astNode.symbolType, model::CppAstNode::SymbolType::Other); + EXPECT_EQ(astNode.location.range.start.line, 26); + + + model::CppVariable var1 = _db->query_value( + QCppVariable::name == "VAR1"); + + astNode = _db->query_value( + QCppAstNode::entityHash == var1.entityHash && + QCppAstNode::astType == model::CppAstNode::AstType::UsingLoc); + + EXPECT_EQ(astNode.symbolType, model::CppAstNode::SymbolType::Other); + EXPECT_EQ(astNode.location.range.start.line, 27); + + astNode = _db->query_value( + QCppAstNode::entityHash == var1.entityHash && + QCppAstNode::astType == model::CppAstNode::AstType::Read); + + EXPECT_EQ(astNode.symbolType, model::CppAstNode::SymbolType::Variable); + EXPECT_EQ(astNode.location.range.start.line, 31); + + RCppFunction functions_with_g = _db->query( + QCppFunction::qualifiedName == "Nested::MyNamespace::g"); + + for (const model::CppFunction& func : functions_with_g) { + astNode = _db->query_value( + QCppAstNode::entityHash == func.entityHash && + QCppAstNode::astType == model::CppAstNode::AstType::UsingLoc); + + EXPECT_EQ(astNode.symbolType, model::CppAstNode::SymbolType::Other); + EXPECT_EQ(astNode.location.range.start.line, 22); + + + astNode = _db->query_value( + QCppAstNode::entityHash == func.entityHash && + QCppAstNode::astType == model::CppAstNode::AstType::Usage); + + EXPECT_EQ(astNode.symbolType, model::CppAstNode::SymbolType::Function); + } + }); +} \ No newline at end of file