src: split CxxAstVisitor into component based indexing system

* also: added logging for sqlite exceptions
This commit is contained in:
malte_langkabel
2016-12-09 17:00:26 +01:00
parent 809d27ecac
commit 26902acbbb
18 changed files with 2170 additions and 1121 deletions
File diff suppressed because it is too large Load Diff
+52 -57
View File
@@ -1,16 +1,11 @@
#ifndef CXX_AST_VISITOR_H
#define CXX_AST_VISITOR_H
#include <unordered_map>
#include <vector>
#include <memory>
#include "clang/AST/ASTContext.h"
#include <clang/AST/RecursiveASTVisitor.h>
#include "data/parser/cxx/CxxContext.h"
#include "data/parser/AccessKind.h"
#include "data/parser/ReferenceKind.h"
#include "data/parser/SymbolKind.h"
#include "utility/messaging/MessageInterruptTasksCounter.h"
#include "utility/Cache.h"
@@ -18,6 +13,12 @@ class ParserClient;
struct ParseLocation;
class FileRegister;
class CxxAstVisitorComponent;
class CxxAstVisitorComponentContext;
class CxxAstVisitorComponentDeclRefKind;
class CxxAstVisitorComponentTypeRefKind;
class CxxAstVisitorComponentIndexer;
// methods are called in this order:
// TraverseDecl()
// `- TraverseFunctionDecl()
@@ -29,29 +30,18 @@ class FileRegister;
// | `- VisitFunctionDecl()
// `- TraverseChildNodes()
class ScopedContextKindSetter
{
public:
ScopedContextKindSetter(const ReferenceKind refKind, std::vector<ReferenceKind>* stack)
: m_stack(stack)
{
m_stack->push_back(refKind);
}
~ScopedContextKindSetter()
{
m_stack->pop_back();
}
private:
std::vector<ReferenceKind>* m_stack;
};
class CxxAstVisitor: public clang::RecursiveASTVisitor<CxxAstVisitor>
{
public:
CxxAstVisitor(clang::ASTContext* astContext, clang::Preprocessor* preprocessor, ParserClient* client, FileRegister* fileRegister);
virtual ~CxxAstVisitor();
template <typename T>
std::shared_ptr<T> getComponent();
std::shared_ptr<DeclNameCache> getDeclNameCache();
std::shared_ptr<TypeNameCache> getTypeNameCache();
// Indexing entry point
void indexDecl(clang::Decl *d);
@@ -59,6 +49,8 @@ public:
virtual bool shouldVisitTemplateInstantiations() const;
virtual bool shouldVisitImplicitCode() const;
bool checkIgnoresTypeLoc(const clang::TypeLoc& tl) const;
// Traversal methods. These specify how to traverse the AST and record context info.
virtual bool TraverseDecl(clang::Decl *d);
virtual bool TraverseQualifiedTypeLoc(clang::QualifiedTypeLoc tl);
@@ -66,7 +58,8 @@ public:
virtual bool TraverseType(clang::QualType t);
virtual bool TraverseStmt(clang::Stmt *stmt);
virtual bool TraverseCXXRecordDecl(clang::CXXRecordDecl *d);
virtual bool TraverseCXXRecordDecl(clang::CXXRecordDecl* d);
bool traverseCXXBaseSpecifier(const clang::CXXBaseSpecifier& d);
virtual bool TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d);
virtual bool TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d);
virtual bool TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc loc);
@@ -85,10 +78,27 @@ public:
virtual bool TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* s);
virtual bool TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
virtual bool TraverseLambdaCapture(clang::LambdaExpr* lambdaExpr, const clang::LambdaCapture* capture);
virtual bool TraverseBinComma(clang::BinaryOperator* s);
#define OPERATOR(NAME) virtual bool TraverseBin##NAME##Assign(clang::CompoundAssignOperator *s) { return TraverseAssignCommon(s); }
OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub)
OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor)
#undef OPERATOR
void traverseDeclContextHelper(clang::DeclContext* d);
bool TraverseCallCommon(clang::CallExpr* s);
bool TraverseAssignCommon(clang::BinaryOperator* s);
// Visitor methods. These actually record stuff and store it in the database.
virtual bool VisitCastExpr(clang::CastExpr* s);
virtual bool VisitUnaryAddrOf(clang::UnaryOperator* s);
virtual bool VisitUnaryDeref(clang::UnaryOperator* s);
virtual bool VisitDeclStmt(clang::DeclStmt* s);
virtual bool VisitReturnStmt(clang::ReturnStmt* s);
virtual bool VisitInitListExpr(clang::InitListExpr* s);
virtual bool VisitTagDecl(clang::TagDecl* d);
virtual bool VisitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d);
virtual bool VisitFunctionDecl(clang::FunctionDecl* d);
@@ -114,39 +124,13 @@ public:
virtual bool VisitLambdaExpr(clang::LambdaExpr* s);
virtual bool VisitConstructorInitializer(clang::CXXCtorInitializer* init);
protected:
// General helpers
bool isImplicit(const clang::Decl* d) const;
bool shouldVisitDecl(const clang::Decl* decl);
bool shouldVisitReference(const clang::SourceLocation& referenceLocation, const clang::Decl* contextDecl);
bool isLocatedInUnparsedProjectFile(clang::SourceLocation loc);
bool isLocatedInProjectFile(clang::SourceLocation loc);
ParseLocation getParseLocationOfTagDeclBody(clang::TagDecl* decl) const;
ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const;
ParseLocation getParseLocation(const clang::SourceLocation& loc) const;
ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const;
AccessKind convertAccessSpecifier(clang::AccessSpecifier access) const;
SymbolKind convertTagKind(clang::TagTypeKind tagKind);
private:
ReferenceKind consumeDeclRefContextKind();
SymbolKind getSymbolKind(clang::VarDecl* d);
typedef clang::RecursiveASTVisitor<CxxAstVisitor> base;
const clang::NamedDecl* getTopmostContextDecl() const;
NameHierarchy getContextName(const size_t skip = 0) const;
NameHierarchy getContextName(const NameHierarchy& fallback, const size_t skip = 0) const;
bool checkIgnoresTypeLoc(const clang::TypeLoc& tl);
struct FileIdHash
{
size_t operator()(clang::FileID fileID) const
{
return fileID.getHashValue();
}
};
typedef clang::RecursiveASTVisitor<CxxAstVisitor> Base;
clang::ASTContext* m_astContext;
clang::Preprocessor* m_preprocessor;
@@ -155,15 +139,26 @@ private:
MessageInterruptTasksCounter m_interruptCounter;
ReferenceKind m_typeRefContext;
ReferenceKind m_declRefContext;
std::vector<std::shared_ptr<CxxContext>> m_contextStack;
std::shared_ptr<CxxContext> m_templateArgumentContext;
std::vector<std::shared_ptr<CxxAstVisitorComponent>> m_components;
std::shared_ptr<CxxAstVisitorComponentContext> m_contextComponent;
std::shared_ptr<CxxAstVisitorComponentDeclRefKind> m_declRefKindComponent;
std::shared_ptr<CxxAstVisitorComponentTypeRefKind> m_typeRefKindComponent;
std::shared_ptr<CxxAstVisitorComponentIndexer> m_indexerComponent;
std::shared_ptr<DeclNameCache> m_declNameCache;
std::shared_ptr<TypeNameCache> m_typeNameCache;
std::unordered_map<const clang::FileID, bool, FileIdHash> m_inUnparsedProjectFileMap;
std::unordered_map<const clang::FileID, bool, FileIdHash> m_inProjectFileMap;
};
template <>
std::shared_ptr<CxxAstVisitorComponentContext> CxxAstVisitor::getComponent();
template <>
std::shared_ptr<CxxAstVisitorComponentTypeRefKind> CxxAstVisitor::getComponent();
template <>
std::shared_ptr<CxxAstVisitorComponentDeclRefKind> CxxAstVisitor::getComponent();
template <>
std::shared_ptr<CxxAstVisitorComponentIndexer> CxxAstVisitor::getComponent();
#endif // CXX_AST_VISITOR_H
@@ -0,0 +1,20 @@
#include "data/parser/cxx/CxxAstVisitorComponent.h"
CxxAstVisitorComponent::CxxAstVisitorComponent(CxxAstVisitor* astVisitor)
: m_astVisitor(astVisitor)
{
}
CxxAstVisitorComponent::~CxxAstVisitorComponent()
{
}
CxxAstVisitor* CxxAstVisitorComponent::getAstVisitor()
{
return m_astVisitor;
}
const CxxAstVisitor* CxxAstVisitorComponent::getAstVisitor() const
{
return m_astVisitor;
}
@@ -0,0 +1,130 @@
#ifndef CXX_AST_VISITOR_COMPONENT_H
#define CXX_AST_VISITOR_COMPONENT_H
#include "data/parser/cxx/CxxAstVisitor.h"
// CxxAstVisitorComponent: This is the base class for all ast visitor components.
// Each component can override it's begin-/endTraverse and visit methods in order to provide some functionality. The CxxAstVisitor
// executes all of these methods of registered components while traversing the AST.
class CxxAstVisitorComponent
{
public:
CxxAstVisitorComponent(CxxAstVisitor* astVisitor);
virtual ~CxxAstVisitorComponent();
#define DEF_TRAVERSE_CUSTOM_TYPE_PTR(__NAME_TYPE__, __PARAM_TYPE__) \
virtual void beginTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ *v) {} \
virtual void endTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ *v) {}
#define DEF_TRAVERSE_CUSTOM_TYPE(__NAME_TYPE__, __PARAM_TYPE__) \
virtual void beginTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ v) {} \
virtual void endTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ v) {}
#define DEF_TRAVERSE_TYPE_PTR(__TYPE__) \
DEF_TRAVERSE_CUSTOM_TYPE_PTR(__TYPE__, __TYPE__)
#define DEF_TRAVERSE_TYPE(__TYPE__) \
DEF_TRAVERSE_CUSTOM_TYPE(__TYPE__, __TYPE__)
DEF_TRAVERSE_TYPE_PTR(Decl)
DEF_TRAVERSE_TYPE_PTR(Stmt)
DEF_TRAVERSE_CUSTOM_TYPE(Type, QualType)
DEF_TRAVERSE_TYPE(TypeLoc)
DEF_TRAVERSE_TYPE_PTR(FunctionDecl)
DEF_TRAVERSE_TYPE_PTR(ClassTemplateSpecializationDecl)
DEF_TRAVERSE_TYPE_PTR(ClassTemplatePartialSpecializationDecl)
DEF_TRAVERSE_TYPE(TemplateSpecializationTypeLoc)
DEF_TRAVERSE_TYPE_PTR(LambdaExpr)
DEF_TRAVERSE_TYPE_PTR(DeclRefExpr)
DEF_TRAVERSE_TYPE_PTR(UnresolvedLookupExpr)
virtual void beginTraverseCallCommonCallee() {}
virtual void endTraverseCallCommonCallee() {}
virtual void beginTraverseCallCommonArgument() {}
virtual void endTraverseCallCommonArgument() {}
virtual void beginTraverseBinCommaLhs() {}
virtual void endTraverseBinCommaLhs() {}
virtual void beginTraverseBinCommaRhs() {}
virtual void endTraverseBinCommaRhs() {}
virtual void beginTraverseAssignCommonLhs() {}
virtual void endTraverseAssignCommonLhs() {}
virtual void beginTraverseAssignCommonRhs() {}
virtual void endTraverseAssignCommonRhs() {}
virtual void beginTraverseCXXBaseSpecifier() {}
virtual void endTraverseCXXBaseSpecifier() {}
virtual void beginTraverseTemplateDefaultArgumentLoc() {}
virtual void endTraverseTemplateDefaultArgumentLoc() {}
DEF_TRAVERSE_CUSTOM_TYPE_PTR(ConstructorInitializer, CXXCtorInitializer)
DEF_TRAVERSE_TYPE_PTR(CXXTemporaryObjectExpr)
virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) {}
virtual void endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) {}
virtual void beginTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture) {}
virtual void endTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture) {}
virtual void visitTagDecl(clang::TagDecl* d) {}
virtual void visitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d) {}
virtual void visitVarDecl(clang::VarDecl* d) {}
virtual void visitFieldDecl(clang::FieldDecl* d) {}
virtual void visitFunctionDecl(clang::FunctionDecl* d) {}
virtual void visitCXXMethodDecl(clang::CXXMethodDecl* d) {}
virtual void visitEnumConstantDecl(clang::EnumConstantDecl* d) {}
virtual void visitNamespaceDecl(clang::NamespaceDecl* d) {}
virtual void visitNamespaceAliasDecl(clang::NamespaceAliasDecl* d) {}
virtual void visitTypedefDecl(clang::TypedefDecl* d) {}
virtual void visitTypeAliasDecl(clang::TypeAliasDecl* d) {}
virtual void visitUsingDirectiveDecl(clang::UsingDirectiveDecl* d) {}
virtual void visitUsingDecl(clang::UsingDecl* d) {}
virtual void visitNonTypeTemplateParmDecl(clang::NonTypeTemplateParmDecl* d) {}
virtual void visitTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d) {}
virtual void visitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d) {}
virtual void visitTypeLoc(clang::TypeLoc tl) {}
virtual void visitCastExpr(clang::CastExpr* s) {}
virtual void visitUnaryAddrOf(clang::UnaryOperator* s) {}
virtual void visitUnaryDeref(clang::UnaryOperator* s) {}
virtual void visitDeclStmt(clang::DeclStmt* s) {}
virtual void visitReturnStmt(clang::ReturnStmt* s) {}
virtual void visitInitListExpr(clang::InitListExpr* s) {}
virtual void visitDeclRefExpr(clang::DeclRefExpr* s) {}
virtual void visitMemberExpr(clang::MemberExpr* s) {}
virtual void visitCXXConstructExpr(clang::CXXConstructExpr* s) {}
virtual void visitLambdaExpr(clang::LambdaExpr* s) {}
virtual void visitConstructorInitializer(clang::CXXCtorInitializer* init) {}
#undef DEF_TRAVERSE_CUSTOM_TYPE_PTR
#undef DEF_TRAVERSE_CUSTOM_TYPE
#undef DEF_TRAVERSE_TYPE_PTR
#undef DEF_TRAVERSE_TYPE
protected:
CxxAstVisitor* getAstVisitor();
const CxxAstVisitor* getAstVisitor() const;
private:
CxxAstVisitor* m_astVisitor;
};
#endif // CXX_AST_VISITOR_COMPONENT_H
@@ -0,0 +1,200 @@
#include "data/parser/cxx/CxxAstVisitorComponentContext.h"
#include "utility/ScopedFunctor.h"
CxxAstVisitorComponentContext::CxxAstVisitorComponentContext(CxxAstVisitor* astVisitor)
: CxxAstVisitorComponent(astVisitor)
{
}
CxxAstVisitorComponentContext::~CxxAstVisitorComponentContext()
{
}
const clang::NamedDecl* CxxAstVisitorComponentContext::getTopmostContextDecl() const
{
for (std::vector<std::shared_ptr<CxxContext>>::const_reverse_iterator it = m_contextStack.rbegin(); it != m_contextStack.rend(); it ++)
{
if (*it)
{
const clang::NamedDecl* decl = (*it)->getDecl();
if (decl)
{
return decl;
}
}
}
return nullptr;
}
NameHierarchy CxxAstVisitorComponentContext::getContextName(const size_t skip)
{
size_t skipped = 0;
for (auto it = m_contextStack.rbegin(); it != m_contextStack.rend(); it++)
{
if (*it)
{
if (skipped >= skip)
{
return (*it)->getName();
}
else
{
skipped++;
}
}
}
return getAstVisitor()->getDeclNameCache()->getValue(nullptr);
}
NameHierarchy CxxAstVisitorComponentContext::getContextName(const NameHierarchy& fallback, const size_t skip)
{
size_t skipped = 0;
for (auto it = m_contextStack.rbegin(); it != m_contextStack.rend(); it++)
{
if (*it)
{
if (skipped >= skip)
{
return (*it)->getName();
}
else
{
skipped++;
}
}
}
return fallback;
}
void CxxAstVisitorComponentContext::beginTraverseDecl(clang::Decl* d)
{
std::shared_ptr<CxxContextDecl> context;
if (d &&
clang::isa<clang::NamedDecl>(d) &&
!clang::isa<clang::ParmVarDecl>(d) && // no parameter
!(clang::isa<clang::VarDecl>(d) && d->getParentFunctionOrMethod() != NULL) && // no local variable
!clang::isa<clang::UsingDirectiveDecl>(d) && // no using directive decl
!clang::isa<clang::UsingDecl>(d) && // no using decl
!clang::isa<clang::NamespaceDecl>(d) // no namespace
){
clang::NamedDecl* nd = clang::dyn_cast<clang::NamedDecl>(d);
context = std::make_shared<CxxContextDecl>(nd, getAstVisitor()->getDeclNameCache());
}
m_contextStack.push_back(context);
}
void CxxAstVisitorComponentContext::endTraverseDecl(clang::Decl* d)
{
m_contextStack.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseTypeLoc(clang::TypeLoc tl)
{
std::shared_ptr<CxxContextType> context;
if (!getAstVisitor()->checkIgnoresTypeLoc(tl))
{
context = std::make_shared<CxxContextType>(tl.getTypePtr(), getAstVisitor()->getTypeNameCache());
}
m_contextStack.push_back(context);
}
void CxxAstVisitorComponentContext::endTraverseTypeLoc(clang::TypeLoc tl)
{
m_contextStack.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseLambdaExpr(clang::LambdaExpr* s)
{
clang::CXXMethodDecl* methodDecl = s->getCallOperator();
m_contextStack.push_back(std::make_shared<CxxContextDecl>(methodDecl, getAstVisitor()->getDeclNameCache()));
}
void CxxAstVisitorComponentContext::endTraverseLambdaExpr(clang::LambdaExpr* s)
{
m_contextStack.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseFunctionDecl(clang::FunctionDecl* d)
{
m_templateArgumentContext.push_back(std::make_shared<CxxContextDecl>(d, getAstVisitor()->getDeclNameCache()));
}
void CxxAstVisitorComponentContext::endTraverseFunctionDecl(clang::FunctionDecl* d)
{
m_templateArgumentContext.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d)
{
m_templateArgumentContext.push_back(std::make_shared<CxxContextDecl>(d, getAstVisitor()->getDeclNameCache()));
}
void CxxAstVisitorComponentContext::endTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d)
{
m_templateArgumentContext.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d)
{
m_templateArgumentContext.push_back(std::make_shared<CxxContextDecl>(d, getAstVisitor()->getDeclNameCache()));
}
void CxxAstVisitorComponentContext::endTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d)
{
m_templateArgumentContext.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseDeclRefExpr(clang::DeclRefExpr* s)
{
m_templateArgumentContext.push_back(std::make_shared<CxxContextDecl>(s->getDecl(), getAstVisitor()->getDeclNameCache()));
}
void CxxAstVisitorComponentContext::endTraverseDeclRefExpr(clang::DeclRefExpr* s)
{
m_templateArgumentContext.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc)
{
m_templateArgumentContext.push_back(std::make_shared<CxxContextType>(loc.getTypePtr(), getAstVisitor()->getTypeNameCache()));
}
void CxxAstVisitorComponentContext::endTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc)
{
m_templateArgumentContext.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e) // TODO: do this for unresolved and dependent stuff
{
std::shared_ptr<CxxContext> clear;
m_templateArgumentContext.push_back(clear);
}
void CxxAstVisitorComponentContext::endTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e)
{
m_templateArgumentContext.pop_back();
}
void CxxAstVisitorComponentContext::beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc)
{
std::shared_ptr<CxxContext> context;
if (!m_templateArgumentContext.empty())
{
context = m_templateArgumentContext.back();
}
m_contextStack.push_back(context);
}
void CxxAstVisitorComponentContext::endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc)
{
m_contextStack.pop_back();
}
@@ -0,0 +1,55 @@
#ifndef CXX_AST_VISITOR_COMPONENT_CONTEXT_H
#define CXX_AST_VISITOR_COMPONENT_CONTEXT_H
#include "data/parser/cxx/CxxAstVisitorComponent.h"
#include "data/parser/cxx/CxxContext.h"
// This CxxAstVisitorComponent is responsible for recording and providing the decl/type that acts as the context of the currently traversed/visited node.
// Example: void foo() { bar(); }
// For this snippet the declaration of "foo" serves as the context of the call to "bar"
class CxxAstVisitorComponentContext: public CxxAstVisitorComponent
{
public:
CxxAstVisitorComponentContext(CxxAstVisitor* astVisitor);
virtual ~CxxAstVisitorComponentContext();
const clang::NamedDecl* getTopmostContextDecl() const;
NameHierarchy getContextName(const size_t skip = 0);
NameHierarchy getContextName(const NameHierarchy& fallback, const size_t skip = 0);
virtual void beginTraverseDecl(clang::Decl* d);
virtual void endTraverseDecl(clang::Decl* d);
virtual void beginTraverseTypeLoc(clang::TypeLoc tl);
virtual void endTraverseTypeLoc(clang::TypeLoc tl);
virtual void beginTraverseLambdaExpr(clang::LambdaExpr* s);
virtual void endTraverseLambdaExpr(clang::LambdaExpr* s);
virtual void beginTraverseFunctionDecl(clang::FunctionDecl* d);
virtual void endTraverseFunctionDecl(clang::FunctionDecl* d);
virtual void beginTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d);
virtual void endTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d);
virtual void beginTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d);
virtual void endTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d);
virtual void beginTraverseDeclRefExpr(clang::DeclRefExpr* s);
virtual void endTraverseDeclRefExpr(clang::DeclRefExpr* s);
virtual void beginTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc);
virtual void endTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc);
virtual void beginTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e);
virtual void endTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e);
virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
virtual void endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
private:
std::vector<std::shared_ptr<CxxContext>> m_contextStack;
std::vector<std::shared_ptr<CxxContext>> m_templateArgumentContext;
};
#endif // CXX_AST_VISITOR_COMPONENT_CONTEXT_H
@@ -0,0 +1,178 @@
#include "data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h"
CxxAstVisitorComponentDeclRefKind::CxxAstVisitorComponentDeclRefKind(CxxAstVisitor* astVisitor)
: CxxAstVisitorComponent(astVisitor)
, m_thisRefKind(REFERENCE_USAGE)
, m_childRefKind(REFERENCE_USAGE)
{
}
CxxAstVisitorComponentDeclRefKind::~CxxAstVisitorComponentDeclRefKind()
{
}
ReferenceKind CxxAstVisitorComponentDeclRefKind::getReferenceKind() const
{
return m_thisRefKind;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseDecl(clang::Decl* d)
{
saveAll();
m_thisRefKind = REFERENCE_USAGE;
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::endTraverseDecl(clang::Decl* d)
{
restoreAll();
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseStmt(clang::Stmt* s)
{
saveAll();
if (s == nullptr)
{
return;
}
m_thisRefKind = m_childRefKind;
if (!clang::isa<clang::Expr>(s))
{
m_thisRefKind = REFERENCE_USAGE;
}
m_childRefKind = m_thisRefKind;
}
void CxxAstVisitorComponentDeclRefKind::endTraverseStmt(clang::Stmt* s)
{
restoreAll();
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseType(clang::QualType t)
{
saveAll();
m_thisRefKind = REFERENCE_USAGE;
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::endTraverseType(clang::QualType t)
{
restoreAll();
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseTypeLoc(clang::TypeLoc tl)
{
saveAll();
m_thisRefKind = REFERENCE_USAGE;
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::endTraverseTypeLoc(clang::TypeLoc tl)
{
restoreAll();
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseCallCommonCallee()
{
m_thisRefKind = REFERENCE_CALL;
m_childRefKind = REFERENCE_CALL;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseCallCommonArgument()
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseBinCommaLhs()
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseBinCommaRhs()
{
m_childRefKind = m_thisRefKind;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseAssignCommonLhs()
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseAssignCommonRhs()
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseConstructorInitializer(clang::CXXCtorInitializer* init)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::beginTraverseCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* s)
{
m_thisRefKind = REFERENCE_CALL;
m_childRefKind = REFERENCE_CALL;
}
void CxxAstVisitorComponentDeclRefKind::visitVarDecl(clang::VarDecl* d)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::visitCastExpr(clang::CastExpr* s)
{
switch (s->getCastKind())
{
case clang::CK_ArrayToPointerDecay:
case clang::CK_ToVoid:
case clang::CK_LValueToRValue:
m_childRefKind = REFERENCE_USAGE;
}
}
void CxxAstVisitorComponentDeclRefKind::visitUnaryAddrOf(clang::UnaryOperator* s)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::visitUnaryDeref(clang::UnaryOperator* s)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::visitDeclStmt(clang::DeclStmt* s)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::visitReturnStmt(clang::ReturnStmt* s)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::visitInitListExpr(clang::InitListExpr* s)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::visitMemberExpr(clang::MemberExpr* s)
{
m_childRefKind = REFERENCE_USAGE;
}
void CxxAstVisitorComponentDeclRefKind::saveAll()
{
m_oldThisRefKinds.push_back(m_thisRefKind);
m_oldChildRefKinds.push_back(m_childRefKind);
}
void CxxAstVisitorComponentDeclRefKind::restoreAll()
{
m_thisRefKind = m_oldThisRefKinds.back();
m_oldThisRefKinds.pop_back();
m_childRefKind = m_oldChildRefKinds.back();
m_oldChildRefKinds.pop_back();
}
@@ -0,0 +1,77 @@
#ifndef CXX_AST_VISITOR_COMPONENT_DECL_REF_KIND_H
#define CXX_AST_VISITOR_COMPONENT_DECL_REF_KIND_H
#include <vector>
#include "data/parser/cxx/CxxAstVisitor.h"
#include "data/parser/cxx/CxxAstVisitorComponent.h"
#include "data/parser/ReferenceKind.h"
// This CxxAstVisitorComponent is responsible for recording and providing the context based ReferenceKind for each reference to a declaration encountered while traversing the AST.
// Example: void foo() { bar(); }
// For this snippet the reference to "bar" is used in the context of a call.
class CxxAstVisitorComponentDeclRefKind: public CxxAstVisitorComponent
{
public:
CxxAstVisitorComponentDeclRefKind(CxxAstVisitor* astVisitor);
virtual ~CxxAstVisitorComponentDeclRefKind();
ReferenceKind getReferenceKind() const;
virtual void beginTraverseDecl(clang::Decl* d);
virtual void endTraverseDecl(clang::Decl* d);
virtual void beginTraverseStmt(clang::Stmt* s);
virtual void endTraverseStmt(clang::Stmt* s);
virtual void beginTraverseType(clang::QualType t);
virtual void endTraverseType(clang::QualType t);
virtual void beginTraverseTypeLoc(clang::TypeLoc tl);
virtual void endTraverseTypeLoc(clang::TypeLoc tl);
virtual void beginTraverseCallCommonCallee();
virtual void beginTraverseCallCommonArgument();
virtual void beginTraverseBinCommaLhs();
virtual void beginTraverseBinCommaRhs();
virtual void beginTraverseAssignCommonLhs();
virtual void beginTraverseAssignCommonRhs();
virtual void beginTraverseConstructorInitializer(clang::CXXCtorInitializer* init);
virtual void beginTraverseCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* s);
virtual void visitVarDecl(clang::VarDecl* d);
virtual void visitCastExpr(clang::CastExpr* s);
virtual void visitUnaryAddrOf(clang::UnaryOperator* s);
virtual void visitUnaryDeref(clang::UnaryOperator* s);
virtual void visitDeclStmt(clang::DeclStmt* s);
virtual void visitReturnStmt(clang::ReturnStmt* s);
virtual void visitInitListExpr(clang::InitListExpr* s);
virtual void visitMemberExpr(clang::MemberExpr* s);
private:
void saveAll();
void restoreAll();
ReferenceKind m_thisRefKind;
ReferenceKind m_childRefKind;
std::vector<ReferenceKind> m_oldThisRefKinds;
std::vector<ReferenceKind> m_oldChildRefKinds;
};
#endif // CXX_AST_VISITOR_COMPONENT_DECL_REF_KIND_H
@@ -0,0 +1,682 @@
#include "data/parser/cxx/CxxAstVisitorComponentIndexer.h"
#include <clang/AST/ASTContext.h>
#include <clang/Basic/SourceLocation.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Lex/Preprocessor.h>
#include "data/parser/cxx/CxxAstVisitorComponentContext.h"
#include "data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h"
#include "data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h"
#include "data/parser/cxx/utilityCxxAstVisitor.h"
#include "data/parser/ParseLocation.h"
#include "data/parser/ParserClient.h"
#include "utility/file/FileRegister.h"
CxxAstVisitorComponentIndexer::CxxAstVisitorComponentIndexer(CxxAstVisitor* astVisitor, clang::ASTContext* astContext, ParserClient* client, FileRegister* fileRegister)
: CxxAstVisitorComponent(astVisitor)
, m_astContext(astContext)
, m_client(client)
, m_fileRegister(fileRegister)
{
}
CxxAstVisitorComponentIndexer::~CxxAstVisitorComponentIndexer()
{
}
void CxxAstVisitorComponentIndexer::beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc)
{
if (
(loc.getArgument().getKind() == clang::TemplateArgument::Template) &&
(shouldVisitReference(loc.getLocation(), getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getTopmostContextDecl()))
){
// TODO: maybe move this to VisitTemplateName
m_client->recordReference(
getAstVisitor()->getComponent<CxxAstVisitorComponentTypeRefKind>()->getReferenceKind(),
getAstVisitor()->getDeclNameCache()->getValue(loc.getArgument().getAsTemplate().getAsTemplateDecl()),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(),
getParseLocation(loc.getLocation())
);
}
}
void CxxAstVisitorComponentIndexer::beginTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture)
{
if ((!lambdaExpr->isInitCapture(capture)) && (capture->capturesVariable()))
{
clang::VarDecl* d = capture->getCapturedVar();
SymbolKind symbolKind = getSymbolKind(d);
if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER)
{
if (!d->getNameAsString().empty()) // don't record anonymous parameters
{
ParseLocation declLocation = getParseLocation(d->getLocation());
std::string name =
declLocation.filePath.fileName() + "<" +
std::to_string(declLocation.startLineNumber) + ":" +
std::to_string(declLocation.startColumnNumber) + ">";
m_client->onLocalSymbolParsed(name, getParseLocation(capture->getLocation()));
}
}
}
}
void CxxAstVisitorComponentIndexer::visitTagDecl(clang::TagDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
utility::convertTagKind(d->getTagKind()),
getParseLocation(d->getLocation()),
getParseLocationOfTagDeclBody(d),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d)
{
if (shouldVisitDecl(d))
{
clang::NamedDecl* specializedFromDecl;
// todo: use context and childcontext!!
llvm::PointerUnion<clang::ClassTemplateDecl*, clang::ClassTemplatePartialSpecializationDecl*> pu = d->getSpecializedTemplateOrPartial();
if (pu.is<clang::ClassTemplateDecl*>())
{
specializedFromDecl = pu.get<clang::ClassTemplateDecl*>();
}
else if (pu.is<clang::ClassTemplatePartialSpecializationDecl*>())
{
specializedFromDecl = pu.get<clang::ClassTemplatePartialSpecializationDecl*>();
}
m_client->recordReference(
REFERENCE_TEMPLATE_SPECIALIZATION_OF, // TODO: call this REFERENCE_TEMPLATE_SPECIALIZATION and reverse the following arguments
getAstVisitor()->getDeclNameCache()->getValue(specializedFromDecl),
getAstVisitor()->getDeclNameCache()->getValue(d),
getParseLocation(d->getLocation())
);
}
}
void CxxAstVisitorComponentIndexer::visitVarDecl(clang::VarDecl* d)
{
if (shouldVisitDecl(d))
{
SymbolKind symbolKind = getSymbolKind(d);
if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER)
{
if (!d->getNameAsString().empty()) // don't record anonymous parameters
{
ParseLocation declLocation = getParseLocation(d->getLocation());
std::string name =
declLocation.filePath.fileName() + "<" +
std::to_string(declLocation.startLineNumber) + ":" +
std::to_string(declLocation.startColumnNumber) + ">";
m_client->onLocalSymbolParsed(name, getParseLocation(d->getLocation()));
}
}
else
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
symbolKind,
getParseLocation(d->getLocation()),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
}
}
}
void CxxAstVisitorComponentIndexer::visitFieldDecl(clang::FieldDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_FIELD,
getParseLocation(d->getLocation()),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitFunctionDecl(clang::FunctionDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
clang::isa<clang::CXXMethodDecl>(d) ? SYMBOL_METHOD : SYMBOL_FUNCTION,
getParseLocation(d->getLocation()),
getParseLocationOfFunctionBody(d),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
if (d->isFunctionTemplateSpecialization())
{
m_client->recordReference(
REFERENCE_TEMPLATE_SPECIALIZATION_OF, // TODO: call this REFERENCE_TEMPLATE_SPECIALIZATION and reverse the following arguments
getAstVisitor()->getDeclNameCache()->getValue(d->getPrimaryTemplate()->getTemplatedDecl()), // todo: use context and childcontext!!
getAstVisitor()->getDeclNameCache()->getValue(d),
getParseLocation(d->getLocation())
);
}
}
}
void CxxAstVisitorComponentIndexer::visitCXXMethodDecl(clang::CXXMethodDecl* d)
{
// Decl has been recorded in VisitFunctionDecl
if (shouldVisitDecl(d))
{
for (clang::CXXMethodDecl::method_iterator it = d->begin_overridden_methods(); // TODO: iterate in traversal and use RT_Overridden or so..
it != d->end_overridden_methods(); it++)
{
m_client->recordReference(
REFERENCE_OVERRIDE,
getAstVisitor()->getDeclNameCache()->getValue(*it),
getAstVisitor()->getDeclNameCache()->getValue(d),
getParseLocation(d->getLocation())
);
}
clang::MemberSpecializationInfo* memberSpecializationInfo = d->getMemberSpecializationInfo();
if (memberSpecializationInfo)
{
clang::NamedDecl* specializedNamedDecl = memberSpecializationInfo->getInstantiatedFrom();
if (clang::isa<clang::FunctionDecl>(specializedNamedDecl))
{
m_client->recordReference(
REFERENCE_TEMPLATE_MEMBER_SPECIALIZATION_OF,
getAstVisitor()->getDeclNameCache()->getValue(specializedNamedDecl),
getAstVisitor()->getDeclNameCache()->getValue(d),
getParseLocation(d->getLocation())
);
}
}
}
}
void CxxAstVisitorComponentIndexer::visitEnumConstantDecl(clang::EnumConstantDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_ENUM_CONSTANT,
getParseLocation(d->getLocation()),
ACCESS_NONE,
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitNamespaceDecl(clang::NamespaceDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_NAMESPACE,
d->isAnonymousNamespace() ? ParseLocation() : getParseLocation(d->getLocation()),
getParseLocation(d->getSourceRange()),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitNamespaceAliasDecl(clang::NamespaceAliasDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_NAMESPACE,
getParseLocation(d->getLocation()),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
m_client->recordReference(
REFERENCE_USAGE,
getAstVisitor()->getDeclNameCache()->getValue(d->getAliasedNamespace()),
getAstVisitor()->getDeclNameCache()->getValue(d),
getParseLocation(d->getTargetNameLoc())
);
}
}
void CxxAstVisitorComponentIndexer::visitTypedefDecl(clang::TypedefDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_TYPEDEF,
getParseLocation(d->getLocation()),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitTypeAliasDecl(clang::TypeAliasDecl* d)
{
if (shouldVisitDecl(d))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_TYPEDEF,
getParseLocation(d->getLocation()),
utility::convertAccessSpecifier(d->getAccess()),
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitUsingDirectiveDecl(clang::UsingDirectiveDecl* d)
{
if (shouldVisitDecl(d))
{
ParseLocation loc = getParseLocation(d->getLocation());
m_client->recordReference(
REFERENCE_USAGE,
getAstVisitor()->getDeclNameCache()->getValue(d->getNominatedNamespaceAsWritten()),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(NameHierarchy(loc.filePath.fileName())),
loc
);
}
}
void CxxAstVisitorComponentIndexer::visitUsingDecl(clang::UsingDecl* d)
{
if (shouldVisitDecl(d))
{
ParseLocation loc = getParseLocation(d->getLocation());
m_client->recordReference(
REFERENCE_USAGE,
getAstVisitor()->getDeclNameCache()->getValue(d),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(NameHierarchy(loc.filePath.fileName())),
loc
);
}
}
void CxxAstVisitorComponentIndexer::visitNonTypeTemplateParmDecl(clang::NonTypeTemplateParmDecl* d)
{
if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters.
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_TEMPLATE_PARAMETER,
getParseLocation(d->getLocation()),
ACCESS_TEMPLATE_PARAMETER,
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d)
{
if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters.
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_TEMPLATE_PARAMETER,
getParseLocation(d->getLocation()),
ACCESS_TEMPLATE_PARAMETER,
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d)
{
if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters.
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(d),
SYMBOL_TEMPLATE_PARAMETER,
getParseLocation(d->getLocation()),
ACCESS_TEMPLATE_PARAMETER,
utility::isImplicit(d)
);
}
}
void CxxAstVisitorComponentIndexer::visitTypeLoc(clang::TypeLoc tl)
{
if ((shouldVisitReference(tl.getBeginLoc(), getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getTopmostContextDecl())) &&
(!getAstVisitor()->checkIgnoresTypeLoc(tl)))
{
clang::SourceLocation loc;
if (!tl.getAs<clang::DependentNameTypeLoc>().isNull())
{
const clang::DependentNameTypeLoc& dntl = tl.castAs<clang::DependentNameTypeLoc>();
loc = dntl.getNameLoc();
}
else
{
loc = tl.getBeginLoc();
}
m_client->recordReference(
getAstVisitor()->getComponent<CxxAstVisitorComponentTypeRefKind>()->getReferenceKind(),
getAstVisitor()->getTypeNameCache()->getValue(tl.getTypePtr()),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(1), // we skip the last element because it refers to this typeloc.
getParseLocation(loc)
);
}
}
void CxxAstVisitorComponentIndexer::visitDeclRefExpr(clang::DeclRefExpr* s)
{
clang::ValueDecl* decl = s->getDecl();
if (shouldVisitReference(s->getLocation(), getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getTopmostContextDecl()))
{
if ((clang::isa<clang::ParmVarDecl>(decl)) ||
(clang::isa<clang::VarDecl>(decl) && decl->getParentFunctionOrMethod() != NULL)
) {
ParseLocation declLocation = getParseLocation(decl->getLocation());
std::string name = declLocation.filePath.fileName() + "<" +
std::to_string(declLocation.startLineNumber) + ":" +
std::to_string(declLocation.startColumnNumber) + ">";
m_client->onLocalSymbolParsed(name, getParseLocation(s->getLocation()));
}
else
{
m_client->recordReference(
consumeDeclRefContextKind(),
getAstVisitor()->getDeclNameCache()->getValue(s->getDecl()),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(),
getParseLocation(s->getLocation())
);
}
}
}
void CxxAstVisitorComponentIndexer::visitMemberExpr(clang::MemberExpr* s)
{
if (shouldVisitReference(s->getMemberLoc(), getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getTopmostContextDecl()))
{
m_client->recordReference(
consumeDeclRefContextKind(),
getAstVisitor()->getDeclNameCache()->getValue(s->getMemberDecl()),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(),
getParseLocation(s->getMemberLoc())
);
}
}
void CxxAstVisitorComponentIndexer::visitCXXConstructExpr(clang::CXXConstructExpr* s)
{
if (shouldVisitReference(s->getLocation(), getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getTopmostContextDecl()))
{
//if (e->getParenOrBraceRange().isValid()) {
// // XXX: This code is a kludge. Recording calls to constructors is
// // troublesome because there isn't an obvious location to associate the
// // call with. Consider:
// // A::A() : field(1, 2, 3) {}
// // new A<B>(1, 2, 3)
// // struct A { A(B); }; A f() { B b; return b; }
// // Implicit calls to conversion operator methods pose a similar
// // problem.
// //
// // Recording constructor calls is very useful, though, so, as a
// // temporary measure, when there are constructor arguments surrounded
// // by parentheses, associate the call with the right parenthesis.
// //
// // Perhaps the right fix is to associate the call with the line itself
// // or with a larger span which may have other references nested within
// // it. The fix may have implications for the navigator GUI.
// RecordDeclRefExpr(
// e->getConstructor(),
// e->getParenOrBraceRange().getEnd(),
// e,
// CF_Called);
//}
clang::SourceLocation loc;
clang::SourceLocation braceBeginLoc = s->getParenOrBraceRange().getBegin();
clang::SourceLocation nameBeginLoc = s->getSourceRange().getBegin();
if (braceBeginLoc.isValid())
{
if (braceBeginLoc == nameBeginLoc)
{
loc = nameBeginLoc;
}
else
{
loc = braceBeginLoc.getLocWithOffset(-1);
}
}
else
{
loc = s->getSourceRange().getEnd();
}
loc = clang::Lexer::GetBeginningOfToken(loc, m_astContext->getSourceManager(), m_astContext->getLangOpts());
m_client->recordReference(
consumeDeclRefContextKind(),
getAstVisitor()->getDeclNameCache()->getValue(s->getConstructor()),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(),
getParseLocation(loc)
);
}
}
void CxxAstVisitorComponentIndexer::visitLambdaExpr(clang::LambdaExpr* s)
{
clang::CXXMethodDecl* methodDecl = s->getCallOperator();
if (shouldVisitDecl(methodDecl))
{
m_client->recordSymbol(
getAstVisitor()->getDeclNameCache()->getValue(methodDecl),
SYMBOL_FUNCTION,
getParseLocation(s->getLocStart()),
getParseLocationOfFunctionBody(methodDecl),
ACCESS_NONE, // TODO: introduce AccessLambda
utility::isImplicit(methodDecl)
);
}
}
void CxxAstVisitorComponentIndexer::visitConstructorInitializer(clang::CXXCtorInitializer* init)
{
if (shouldVisitReference(init->getMemberLocation(), getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getTopmostContextDecl()))
{
// record the field usage here because it is not a DeclRefExpr
if (clang::FieldDecl* memberDecl = init->getMember())
{
m_client->recordReference(
REFERENCE_USAGE,
getAstVisitor()->getDeclNameCache()->getValue(memberDecl),
getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContextName(),
getParseLocation(init->getMemberLocation())
);
}
}
}
ParseLocation CxxAstVisitorComponentIndexer::getParseLocationOfTagDeclBody(clang::TagDecl* decl) const
{
return getAstVisitor()->getParseLocationOfTagDeclBody(decl);
}
ParseLocation CxxAstVisitorComponentIndexer::getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const
{
return getAstVisitor()->getParseLocationOfFunctionBody(decl);
}
ParseLocation CxxAstVisitorComponentIndexer::getParseLocation(const clang::SourceLocation& loc) const
{
return getAstVisitor()->getParseLocation(loc);
}
ParseLocation CxxAstVisitorComponentIndexer::getParseLocation(const clang::SourceRange& sourceRange) const
{
return getAstVisitor()->getParseLocation(sourceRange);
}
ReferenceKind CxxAstVisitorComponentIndexer::consumeDeclRefContextKind()
{
ReferenceKind refKind = REFERENCE_UNDEFINED;
std::shared_ptr<CxxAstVisitorComponentTypeRefKind> typeRefKindComponent = getAstVisitor()->getComponent<CxxAstVisitorComponentTypeRefKind>();
if (typeRefKindComponent->getReferenceKind() == REFERENCE_TYPE_USAGE)
{
refKind = getAstVisitor()->getComponent<CxxAstVisitorComponentDeclRefKind>()->getReferenceKind();
}
else
{
refKind = typeRefKindComponent->getReferenceKind();
}
return refKind;
}
SymbolKind CxxAstVisitorComponentIndexer::getSymbolKind(clang::VarDecl* d)
{
SymbolKind symbolKind = SYMBOL_KIND_MAX;
if (llvm::isa<clang::ParmVarDecl>(d))
{
symbolKind = SYMBOL_PARAMETER;
}
else if (d->getParentFunctionOrMethod() == NULL)
{
if (d->getAccess() == clang::AS_none)
{
symbolKind = SYMBOL_GLOBAL_VARIABLE;
}
else
{
symbolKind = SYMBOL_FIELD;
}
}
else
{
symbolKind = SYMBOL_LOCAL_VARIABLE;
}
return symbolKind;
}
bool CxxAstVisitorComponentIndexer::shouldVisitDecl(const clang::Decl* decl)
{
if (decl)
{
clang::SourceLocation loc = decl->getLocation();
bool declIsImplicit = utility::isImplicit(decl);
if ((declIsImplicit && isLocatedInProjectFile(loc)) ||
(!declIsImplicit && isLocatedInUnparsedProjectFile(loc)))
{
return true;
}
}
return false;
}
bool CxxAstVisitorComponentIndexer::shouldVisitReference(const clang::SourceLocation& referenceLocation, const clang::Decl* contextDecl)
{
bool declIsImplicit = true; // default value is "true" to make sure that everything that should be visited gets visited.
if (contextDecl)
{
declIsImplicit = utility::isImplicit(contextDecl);
}
if ((declIsImplicit && isLocatedInProjectFile(referenceLocation)) ||
(!declIsImplicit && isLocatedInUnparsedProjectFile(referenceLocation)))
{
return true;
}
return false;
}
bool CxxAstVisitorComponentIndexer::isLocatedInUnparsedProjectFile(clang::SourceLocation loc)
{
clang::SourceManager& sourceManager = m_astContext->getSourceManager();
clang::SourceLocation spellingLoc = sourceManager.getSpellingLoc(loc);
clang::FileID fileId;
if (spellingLoc.isValid())
{
fileId = sourceManager.getFileID(spellingLoc);
}
if (fileId.isValid())
{
auto it = m_inUnparsedProjectFileMap.find(fileId);
if (it != m_inUnparsedProjectFileMap.end())
{
return it->second;
}
bool ret = false;
if (sourceManager.isWrittenInMainFile(spellingLoc))
{
ret = true;
}
else
{
const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId);
if (fileEntry != NULL)
{
std::string fileName = fileEntry->getName();
FilePath filePath = FilePath(fileName).canonical();
if (m_fileRegister->hasIncludeFile(filePath))
{
ret = !(m_fileRegister->includeFileIsParsed(filePath));
}
}
}
m_inUnparsedProjectFileMap[fileId] = ret;
return ret;
}
return false;
}
bool CxxAstVisitorComponentIndexer::isLocatedInProjectFile(clang::SourceLocation loc)
{
clang::SourceManager& sourceManager = m_astContext->getSourceManager();
clang::SourceLocation spellingLoc = sourceManager.getSpellingLoc(loc);
clang::FileID fileId;
if (spellingLoc.isValid())
{
fileId = sourceManager.getFileID(spellingLoc);
}
if (!fileId.isInvalid())
{
auto it = m_inProjectFileMap.find(fileId);
if (it != m_inProjectFileMap.end())
{
return it->second;
}
const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId);
if (fileEntry != NULL)
{
std::string fileName = fileEntry->getName();
FilePath filePath = FilePath(fileName).canonical();
bool ret = m_fileRegister->hasFilePath(filePath.str());
m_inProjectFileMap[fileId] = ret;
return ret;
}
}
return false;
}
@@ -0,0 +1,77 @@
#ifndef CXX_AST_VISITOR_COMPONENT_INDEXER_H
#define CXX_AST_VISITOR_COMPONENT_INDEXER_H
#include <unordered_map>
#include "data/parser/cxx/CxxAstVisitor.h"
#include "data/parser/cxx/CxxAstVisitorComponent.h"
#include "data/parser/ReferenceKind.h"
#include "data/parser/SymbolKind.h"
// This CxxAstVisitorComponent is responsible for recording all symbols and relations throughout the visited AST.
class CxxAstVisitorComponentIndexer: public CxxAstVisitorComponent
{
public:
CxxAstVisitorComponentIndexer(CxxAstVisitor* astVisitor, clang::ASTContext* astContext, ParserClient* client, FileRegister* fileRegister);
virtual ~CxxAstVisitorComponentIndexer();
virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
virtual void beginTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture);
virtual void visitTagDecl(clang::TagDecl* d);
virtual void visitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d);
virtual void visitVarDecl(clang::VarDecl* d);
virtual void visitFieldDecl(clang::FieldDecl* d);
virtual void visitFunctionDecl(clang::FunctionDecl* d);
virtual void visitCXXMethodDecl(clang::CXXMethodDecl* d);
virtual void visitEnumConstantDecl(clang::EnumConstantDecl* d);
virtual void visitNamespaceDecl(clang::NamespaceDecl* d);
virtual void visitNamespaceAliasDecl(clang::NamespaceAliasDecl* d);
virtual void visitTypedefDecl(clang::TypedefDecl* d);
virtual void visitTypeAliasDecl(clang::TypeAliasDecl* d);
virtual void visitUsingDirectiveDecl(clang::UsingDirectiveDecl* d);
virtual void visitUsingDecl(clang::UsingDecl* d);
virtual void visitNonTypeTemplateParmDecl(clang::NonTypeTemplateParmDecl* d);
virtual void visitTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d);
virtual void visitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d);
virtual void visitTypeLoc(clang::TypeLoc tl);
virtual void visitDeclRefExpr(clang::DeclRefExpr* s);
virtual void visitMemberExpr(clang::MemberExpr* s);
virtual void visitCXXConstructExpr(clang::CXXConstructExpr* s);
virtual void visitLambdaExpr(clang::LambdaExpr* s);
virtual void visitConstructorInitializer(clang::CXXCtorInitializer* init);
private:
struct FileIdHash
{
size_t operator()(clang::FileID fileID) const
{
return fileID.getHashValue();
}
};
ParseLocation getParseLocationOfTagDeclBody(clang::TagDecl* decl) const;
ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const;
ParseLocation getParseLocation(const clang::SourceLocation& loc) const;
ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const;
ReferenceKind consumeDeclRefContextKind();
SymbolKind getSymbolKind(clang::VarDecl* d);
bool shouldVisitDecl(const clang::Decl* decl);
bool shouldVisitReference(const clang::SourceLocation& referenceLocation, const clang::Decl* contextDecl);
bool isLocatedInUnparsedProjectFile(clang::SourceLocation loc);
bool isLocatedInProjectFile(clang::SourceLocation loc);
clang::ASTContext* m_astContext;
ParserClient* m_client;
FileRegister* m_fileRegister;
std::unordered_map<const clang::FileID, bool, FileIdHash> m_inUnparsedProjectFileMap;
std::unordered_map<const clang::FileID, bool, FileIdHash> m_inProjectFileMap;
};
#endif // CXX_AST_VISITOR_COMPONENT_INDEXER_H
@@ -0,0 +1,59 @@
#include "data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h"
CxxAstVisitorComponentTypeRefKind::CxxAstVisitorComponentTypeRefKind(CxxAstVisitor* astVisitor)
: CxxAstVisitorComponent(astVisitor)
{
}
CxxAstVisitorComponentTypeRefKind::~CxxAstVisitorComponentTypeRefKind()
{
}
ReferenceKind CxxAstVisitorComponentTypeRefKind::getReferenceKind() const
{
for (auto it = m_refKindStack.rbegin(); it != m_refKindStack.rend(); it++)
{
if ((*it) != REFERENCE_UNDEFINED)
{
return (*it);
}
}
return REFERENCE_TYPE_USAGE;
}
void CxxAstVisitorComponentTypeRefKind::beginTraverseCXXBaseSpecifier()
{
m_refKindStack.push_back(REFERENCE_INHERITANCE);
}
void CxxAstVisitorComponentTypeRefKind::endTraverseCXXBaseSpecifier()
{
m_refKindStack.pop_back();
}
void CxxAstVisitorComponentTypeRefKind::beginTraverseTemplateDefaultArgumentLoc()
{
m_refKindStack.push_back(REFERENCE_TEMPLATE_DEFAULT_ARGUMENT);
}
void CxxAstVisitorComponentTypeRefKind::endTraverseTemplateDefaultArgumentLoc()
{
m_refKindStack.pop_back();
}
void CxxAstVisitorComponentTypeRefKind::beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc)
{
if (getReferenceKind() != REFERENCE_TEMPLATE_DEFAULT_ARGUMENT)
{
m_refKindStack.push_back(REFERENCE_TEMPLATE_ARGUMENT);
}
else
{
m_refKindStack.push_back(REFERENCE_UNDEFINED);
}
}
void CxxAstVisitorComponentTypeRefKind::endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc)
{
m_refKindStack.pop_back();
}
@@ -0,0 +1,35 @@
#ifndef CXX_AST_VISITOR_COMPONENT_TYPE_REF_KIND_H
#define CXX_AST_VISITOR_COMPONENT_TYPE_REF_KIND_H
#include <vector>
#include "data/parser/cxx/CxxAstVisitor.h"
#include "data/parser/cxx/CxxAstVisitorComponent.h"
#include "data/parser/ReferenceKind.h"
// This CxxAstVisitorComponent is responsible for recording and providing the context based ReferenceKind for each reference to a type encountered while traversing the AST.
// Example: class Foo: public Bar {};
// For this snippet the type "Bar" is used in the context of an inheritence.
class CxxAstVisitorComponentTypeRefKind: public CxxAstVisitorComponent
{
public:
CxxAstVisitorComponentTypeRefKind(CxxAstVisitor* astVisitor);
virtual ~CxxAstVisitorComponentTypeRefKind();
ReferenceKind getReferenceKind() const;
virtual void beginTraverseCXXBaseSpecifier();
virtual void endTraverseCXXBaseSpecifier();
virtual void beginTraverseTemplateDefaultArgumentLoc();
virtual void endTraverseTemplateDefaultArgumentLoc();
virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
virtual void endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
private:
std::vector<ReferenceKind> m_refKindStack;
};
#endif // CXX_AST_VISITOR_COMPONENT_TYPE_REF_KIND_H
@@ -0,0 +1,73 @@
#include "data/parser/cxx/utilityCxxAstVisitor.h"
#include <clang/AST/DeclCXX.h>
#include <clang/AST/DeclTemplate.h>
bool utility::isImplicit(const clang::Decl* d)
{
if (!d)
{
return false;
}
if (d->isImplicit())
{
if (const clang::RecordDecl* rd = clang::dyn_cast_or_null<clang::RecordDecl>(d))
{
if (rd->isLambda())
{
return isImplicit(clang::dyn_cast_or_null<clang::Decl>(d->getDeclContext()));
}
}
return true;
}
else if (const clang::ClassTemplateSpecializationDecl* ctsd = clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(d))
{
if (!ctsd->isExplicitSpecialization())
{
return true;
}
}
else if (const clang::FunctionDecl* fd = clang::dyn_cast_or_null<clang::FunctionDecl>(d))
{
if (fd->isTemplateInstantiation() && fd->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization) // or undefined??
{
return true;
}
}
return isImplicit(clang::dyn_cast_or_null<clang::Decl>(d->getDeclContext()));
}
AccessKind utility::convertAccessSpecifier(clang::AccessSpecifier access)
{
switch (access)
{
case clang::AS_public:
return ACCESS_PUBLIC;
case clang::AS_protected:
return ACCESS_PROTECTED;
case clang::AS_private:
return ACCESS_PRIVATE;
case clang::AS_none:
return ACCESS_NONE;
}
}
SymbolKind utility::convertTagKind(clang::TagTypeKind tagKind)
{
switch (tagKind)
{
case clang::TTK_Struct:
return SYMBOL_STRUCT;
case clang::TTK_Union:
return SYMBOL_UNION;
case clang::TTK_Class:
return SYMBOL_CLASS;
case clang::TTK_Enum:
return SYMBOL_ENUM;
case clang::TTK_Interface:
return SYMBOL_KIND_MAX;
}
}
@@ -0,0 +1,16 @@
#ifndef UTILITY_CXX_AST_VISITOR_H
#define UTILITY_CXX_AST_VISITOR_H
#include <clang/AST/Decl.h>
#include "data/parser/AccessKind.h"
#include "data/parser/SymbolKind.h"
namespace utility
{
bool isImplicit(const clang::Decl* d);
AccessKind convertAccessSpecifier(clang::AccessSpecifier access);
SymbolKind convertTagKind(clang::TagTypeKind tagKind);
}
#endif // UTILITY_CXX_AST_VISITOR_H