Cxx AstVisitor re-visits previously or simultaneously indexed files because the "visible" content may have changed due to other preprocessor defines etc.
827 lines
23 KiB
C++
827 lines
23 KiB
C++
#include "data/parser/cxx/CxxAstVisitor.h"
|
|
|
|
#include <clang/AST/ASTContext.h>
|
|
#include <clang/Lex/Preprocessor.h>
|
|
|
|
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
|
|
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
|
|
|
#include "data/parser/cxx/CanonicalFilePathCache.h"
|
|
#include "data/parser/cxx/CxxAstVisitorComponent.h"
|
|
#include "data/parser/cxx/CxxAstVisitorComponentContext.h"
|
|
#include "data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h"
|
|
#include "data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h"
|
|
#include "data/parser/cxx/CxxAstVisitorComponentImplicitCode.h"
|
|
#include "data/parser/cxx/CxxAstVisitorComponentIndexer.h"
|
|
#include "data/parser/cxx/utilityClang.h"
|
|
#include "data/parser/ParserClient.h"
|
|
#include "data/parser/ParseLocation.h"
|
|
#include "utility/file/FileRegister.h"
|
|
|
|
#include "utility/utilityString.h"
|
|
|
|
CxxAstVisitor::CxxAstVisitor(
|
|
clang::ASTContext* astContext,
|
|
clang::Preprocessor* preprocessor,
|
|
std::shared_ptr<ParserClient> client,
|
|
std::shared_ptr<FileRegister> fileRegister,
|
|
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache
|
|
)
|
|
: m_astContext(astContext)
|
|
, m_preprocessor(preprocessor)
|
|
, m_client(client)
|
|
, m_fileRegister(fileRegister)
|
|
, m_canonicalFilePathCache(canonicalFilePathCache)
|
|
{
|
|
m_declNameCache = std::make_shared<DeclNameCache>([&](const clang::NamedDecl* decl) -> NameHierarchy
|
|
{
|
|
if (decl)
|
|
{
|
|
CxxDeclNameResolver resolver(m_canonicalFilePathCache);
|
|
if (std::shared_ptr<CxxDeclName> declName = resolver.getName(decl))
|
|
{
|
|
return declName->toNameHierarchy();
|
|
}
|
|
}
|
|
return NameHierarchy(L"global", NAME_DELIMITER_UNKNOWN);
|
|
}
|
|
);
|
|
m_typeNameCache = std::make_shared<TypeNameCache>([&](const clang::Type* type) -> NameHierarchy
|
|
{
|
|
if (type)
|
|
{
|
|
CxxTypeNameResolver resolver(m_canonicalFilePathCache);
|
|
if (std::shared_ptr<CxxTypeName> typeName = resolver.getName(type))
|
|
{
|
|
return typeName->toNameHierarchy();
|
|
}
|
|
}
|
|
return NameHierarchy(L"global", NAME_DELIMITER_UNKNOWN);
|
|
}
|
|
);
|
|
|
|
m_contextComponent = std::make_shared<CxxAstVisitorComponentContext>(this);
|
|
m_components.push_back(m_contextComponent);
|
|
m_typeRefKindComponent = std::make_shared<CxxAstVisitorComponentTypeRefKind>(this);
|
|
m_components.push_back(m_typeRefKindComponent);
|
|
m_declRefKindComponent = std::make_shared<CxxAstVisitorComponentDeclRefKind>(this);
|
|
m_components.push_back(m_declRefKindComponent);
|
|
m_implicitCodeComponent = std::make_shared<CxxAstVisitorComponentImplicitCode>(this);
|
|
m_components.push_back(m_implicitCodeComponent);
|
|
m_indexerComponent = std::make_shared<CxxAstVisitorComponentIndexer>(this, astContext, client, fileRegister);
|
|
m_components.push_back(m_indexerComponent);
|
|
}
|
|
|
|
CxxAstVisitor::~CxxAstVisitor()
|
|
{
|
|
}
|
|
|
|
template <>
|
|
std::shared_ptr<CxxAstVisitorComponentContext> CxxAstVisitor::getComponent()
|
|
{
|
|
return m_contextComponent;
|
|
}
|
|
|
|
template <>
|
|
std::shared_ptr<CxxAstVisitorComponentTypeRefKind> CxxAstVisitor::getComponent()
|
|
{
|
|
return m_typeRefKindComponent;
|
|
}
|
|
|
|
template <>
|
|
std::shared_ptr<CxxAstVisitorComponentDeclRefKind> CxxAstVisitor::getComponent()
|
|
{
|
|
return m_declRefKindComponent;
|
|
}
|
|
|
|
template <>
|
|
std::shared_ptr<CxxAstVisitorComponentIndexer> CxxAstVisitor::getComponent()
|
|
{
|
|
return m_indexerComponent;
|
|
}
|
|
|
|
std::shared_ptr<DeclNameCache> CxxAstVisitor::getDeclNameCache()
|
|
{
|
|
return m_declNameCache;
|
|
}
|
|
|
|
std::shared_ptr<TypeNameCache> CxxAstVisitor::getTypeNameCache()
|
|
{
|
|
return m_typeNameCache;
|
|
}
|
|
|
|
std::shared_ptr<CanonicalFilePathCache> CxxAstVisitor::getCanonicalFilePathCache()
|
|
{
|
|
return m_canonicalFilePathCache;
|
|
}
|
|
|
|
void CxxAstVisitor::indexDecl(clang::Decl* d)
|
|
{
|
|
this->TraverseDecl(d);
|
|
}
|
|
|
|
bool CxxAstVisitor::shouldVisitTemplateInstantiations() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool CxxAstVisitor::shouldVisitImplicitCode() const
|
|
{
|
|
return m_implicitCodeComponent->shouldVisitImplicitCode();
|
|
}
|
|
|
|
bool CxxAstVisitor::checkIgnoresTypeLoc(const clang::TypeLoc& tl) const
|
|
{
|
|
if ((!tl.getAs<clang::TagTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::TypedefTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::TemplateTypeParmTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::TemplateSpecializationTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::InjectedClassNameTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::DependentNameTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::DependentTemplateSpecializationTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::BuiltinTypeLoc>().isNull()) ||
|
|
(!tl.getAs<clang::AutoTypeLoc>().isNull()))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#define DEF_TRAVERSE_CUSTOM_TYPE_PTR(__NAME_TYPE__, __PARAM_TYPE__, CODE_BEFORE, CODE_AFTER) \
|
|
bool CxxAstVisitor::Traverse##__NAME_TYPE__(clang::__PARAM_TYPE__* v) \
|
|
{ \
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++) \
|
|
{ \
|
|
(*it)->beginTraverse##__NAME_TYPE__(v); \
|
|
} \
|
|
bool ret = true; \
|
|
{ CODE_BEFORE; } \
|
|
Base::Traverse##__NAME_TYPE__(v); \
|
|
{ CODE_AFTER; } \
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++) \
|
|
{ \
|
|
(*it)->endTraverse##__NAME_TYPE__(v); \
|
|
} \
|
|
return ret; \
|
|
}
|
|
|
|
#define DEF_TRAVERSE_CUSTOM_TYPE(__NAME_TYPE__, __PARAM_TYPE__, CODE_BEFORE, CODE_AFTER) \
|
|
bool CxxAstVisitor::Traverse##__NAME_TYPE__(clang::__PARAM_TYPE__ v) \
|
|
{ \
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++) \
|
|
{ \
|
|
(*it)->beginTraverse##__NAME_TYPE__(v); \
|
|
} \
|
|
bool ret = true; \
|
|
{ CODE_BEFORE; } \
|
|
Base::Traverse##__NAME_TYPE__(v); \
|
|
{ CODE_AFTER; } \
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++) \
|
|
{ \
|
|
(*it)->endTraverse##__NAME_TYPE__(v); \
|
|
} \
|
|
return ret; \
|
|
}
|
|
|
|
#define DEF_TRAVERSE_TYPE_PTR(__TYPE__, CODE_BEFORE, CODE_AFTER) \
|
|
DEF_TRAVERSE_CUSTOM_TYPE_PTR(__TYPE__, __TYPE__, CODE_BEFORE, CODE_AFTER)
|
|
|
|
#define DEF_TRAVERSE_TYPE(__TYPE__, CODE_BEFORE, CODE_AFTER) \
|
|
DEF_TRAVERSE_CUSTOM_TYPE(__TYPE__, __TYPE__, CODE_BEFORE, CODE_AFTER)
|
|
|
|
bool CxxAstVisitor::TraverseDecl(clang::Decl* decl)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseDecl(decl);
|
|
}
|
|
bool ret = m_interruptCounter.getCount() == 0;
|
|
|
|
bool traverse = true;
|
|
if (decl)
|
|
{
|
|
clang::SourceLocation loc = m_astContext->getSourceManager().getExpansionLoc(decl->getLocation());
|
|
|
|
if (loc.isInvalid())
|
|
{
|
|
loc = decl->getLocation();
|
|
}
|
|
|
|
if (loc.isValid())
|
|
{
|
|
traverse = isLocatedInProjectFile(loc);
|
|
}
|
|
}
|
|
|
|
if (traverse)
|
|
{
|
|
Base::TraverseDecl(decl);
|
|
}
|
|
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseDecl(decl);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// same as Base::TraverseQualifiedTypeLoc(..) but we need to make sure to call this.TraverseTypeLoc(..)
|
|
bool CxxAstVisitor::TraverseQualifiedTypeLoc(clang::QualifiedTypeLoc tl)
|
|
{
|
|
return TraverseTypeLoc(tl.getUnqualifiedLoc());
|
|
}
|
|
|
|
DEF_TRAVERSE_TYPE(TypeLoc, {}, {})
|
|
|
|
DEF_TRAVERSE_CUSTOM_TYPE(Type, QualType, {}, {})
|
|
|
|
DEF_TRAVERSE_TYPE_PTR(Stmt, {}, {})
|
|
|
|
// same as Base::TraverseCXXRecordDecl(..) but we need to integrate the setter for the context info.
|
|
// additionally: skip implicit CXXRecordDecls (this does not skip template specializations).
|
|
bool CxxAstVisitor::TraverseCXXRecordDecl(clang::CXXRecordDecl *d)
|
|
{
|
|
if (utility::isImplicit(d) && d->getMemberSpecializationInfo() == nullptr)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
WalkUpFromCXXRecordDecl(d);
|
|
|
|
TraverseNestedNameSpecifierLoc(d->getQualifierLoc());
|
|
|
|
if (d->isCompleteDefinition())
|
|
{
|
|
for (const auto& base : d->bases())
|
|
{
|
|
if (!traverseCXXBaseSpecifier(base))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
traverseDeclContextHelper(clang::dyn_cast<clang::DeclContext>(d));
|
|
return true;
|
|
}
|
|
|
|
bool CxxAstVisitor::traverseCXXBaseSpecifier(const clang::CXXBaseSpecifier& d)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseCXXBaseSpecifier();
|
|
}
|
|
bool ret = TraverseTypeLoc(d.getTypeSourceInfo()->getTypeLoc());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseCXXBaseSpecifier();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// same as Base::TraverseTemplateTypeParmDecl(..) but we need to integrate the setter for the context info.
|
|
bool CxxAstVisitor::TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d)
|
|
{
|
|
WalkUpFromTemplateTypeParmDecl(d);
|
|
|
|
if (d->hasDefaultArgument() && !d->defaultArgumentWasInherited())
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseTemplateDefaultArgumentLoc();
|
|
}
|
|
TraverseTypeLoc(d->getDefaultArgumentInfo()->getTypeLoc());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseTemplateDefaultArgumentLoc();
|
|
}
|
|
}
|
|
|
|
traverseDeclContextHelper(clang::dyn_cast<clang::DeclContext>(d));
|
|
return true;
|
|
}
|
|
|
|
// same as Base::TraverseTemplateTemplateParmDecl(..) but we need to integrate the setter for the context info.
|
|
bool CxxAstVisitor::TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d)
|
|
{
|
|
WalkUpFromTemplateTemplateParmDecl(d);
|
|
|
|
TraverseDecl(d->getTemplatedDecl());
|
|
|
|
if (d->hasDefaultArgument() && !d->defaultArgumentWasInherited())
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseTemplateDefaultArgumentLoc();
|
|
}
|
|
TraverseTemplateArgumentLoc(d->getDefaultArgument());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseTemplateDefaultArgumentLoc();
|
|
}
|
|
}
|
|
|
|
clang::TemplateParameterList* TPL = d->getTemplateParameters();
|
|
if (TPL)
|
|
{
|
|
for (clang::TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); I != E; ++I)
|
|
{
|
|
TraverseDecl(*I);
|
|
}
|
|
}
|
|
|
|
traverseDeclContextHelper(clang::dyn_cast<clang::DeclContext>(d));
|
|
return true;
|
|
}
|
|
|
|
bool CxxAstVisitor::VisitTranslationUnitDecl(clang::TranslationUnitDecl *d)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc loc)
|
|
{
|
|
bool ret = true;
|
|
if (loc)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseNestedNameSpecifierLoc(loc);
|
|
}
|
|
|
|
//todo: call method of base class...
|
|
if (clang::NestedNameSpecifierLoc prefix = loc.getPrefix())
|
|
{
|
|
ret = TraverseNestedNameSpecifierLoc(prefix);
|
|
}
|
|
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseNestedNameSpecifierLoc(loc);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseConstructorInitializer(clang::CXXCtorInitializer* init)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseConstructorInitializer(init);
|
|
}
|
|
|
|
if (!VisitConstructorInitializer(init))
|
|
{
|
|
return false;
|
|
}
|
|
bool ret = Base::TraverseConstructorInitializer(init);
|
|
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseConstructorInitializer(init);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseCallExpr(clang::CallExpr* s)
|
|
{
|
|
return TraverseCallCommon(s);
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseCXXMemberCallExpr(clang::CXXMemberCallExpr* s)
|
|
{
|
|
return TraverseCallCommon(s);
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseCXXOperatorCallExpr(clang::CXXOperatorCallExpr* s)
|
|
{
|
|
return TraverseCallCommon(s);
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseCXXConstructExpr(clang::CXXConstructExpr* s)
|
|
{
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseCallCommonCallee();
|
|
}
|
|
WalkUpFromCXXConstructExpr(s);
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->endTraverseCallCommonCallee();
|
|
}
|
|
}
|
|
for (unsigned int i = 0; i < s->getNumArgs(); ++i)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseCallCommonArgument();
|
|
}
|
|
TraverseStmt(s->getArg(i));
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseCallCommonArgument();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
DEF_TRAVERSE_TYPE_PTR(CXXTemporaryObjectExpr, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(LambdaExpr, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(FunctionDecl, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(ClassTemplateSpecializationDecl, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(ClassTemplatePartialSpecializationDecl, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(DeclRefExpr, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(CXXForRangeStmt, {}, {})
|
|
DEF_TRAVERSE_TYPE(TemplateSpecializationTypeLoc, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(UnresolvedLookupExpr, {}, {})
|
|
DEF_TRAVERSE_TYPE_PTR(UnresolvedMemberExpr, {}, {})
|
|
|
|
bool CxxAstVisitor::TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseTemplateArgumentLoc(loc);
|
|
}
|
|
|
|
bool ret = Base::TraverseTemplateArgumentLoc(loc);
|
|
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseTemplateArgumentLoc(loc);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture, clang::Expr *Init)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseLambdaCapture(lambdaExpr, capture);
|
|
}
|
|
|
|
bool ret = true;
|
|
|
|
if (lambdaExpr->isInitCapture(capture))
|
|
{
|
|
ret = TraverseDecl(capture->getCapturedVar());
|
|
}
|
|
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseLambdaCapture(lambdaExpr, capture);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseBinComma(clang::BinaryOperator* s)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseBinCommaLhs();
|
|
}
|
|
TraverseStmt(s->getLHS());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseBinCommaLhs();
|
|
}
|
|
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseBinCommaRhs();
|
|
}
|
|
TraverseStmt(s->getRHS());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseBinCommaRhs();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseDeclarationNameInfo(clang::DeclarationNameInfo NameInfo)
|
|
{
|
|
// we don't visit any children here
|
|
return true;
|
|
}
|
|
|
|
void CxxAstVisitor::traverseDeclContextHelper(clang::DeclContext* d)
|
|
{
|
|
if (!d)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (auto* child : d->decls()) {
|
|
// BlockDecls and CapturedDecls are traversed through BlockExprs and
|
|
// CapturedStmts respectively.
|
|
if (!llvm::isa<clang::BlockDecl>(child) && !llvm::isa<clang::CapturedDecl>(child))
|
|
{
|
|
TraverseDecl(child);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseCallCommon(clang::CallExpr* s)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseCallCommonCallee();
|
|
}
|
|
TraverseStmt(s->getCallee());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseCallCommonCallee();
|
|
}
|
|
|
|
for (unsigned int i = 0; i < s->getNumArgs(); ++i)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseCallCommonArgument();
|
|
}
|
|
TraverseStmt(s->getArg(i));
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseCallCommonArgument();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CxxAstVisitor::TraverseAssignCommon(clang::BinaryOperator* s)
|
|
{
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseAssignCommonLhs();
|
|
}
|
|
TraverseStmt(s->getLHS());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseAssignCommonLhs();
|
|
}
|
|
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++)
|
|
{
|
|
(*it)->beginTraverseAssignCommonRhs();
|
|
}
|
|
TraverseStmt(s->getRHS());
|
|
for (auto it = m_components.rbegin(); it != m_components.rend(); it++)
|
|
{
|
|
(*it)->endTraverseAssignCommonRhs();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#undef DEF_TRAVERSE_CUSTOM_TYPE_PTR
|
|
#undef DEF_TRAVERSE_CUSTOM_TYPE
|
|
#undef DEF_TRAVERSE_TYPE_PTR
|
|
#undef DEF_TRAVERSE_TYPE
|
|
|
|
#define DEF_VISIT_CUSTOM_TYPE_PTR(__NAME_TYPE__, __PARAM_TYPE__) \
|
|
bool CxxAstVisitor::Visit##__NAME_TYPE__(clang::__PARAM_TYPE__* v) \
|
|
{ \
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++) \
|
|
{ \
|
|
(*it)->visit##__NAME_TYPE__(v); \
|
|
} \
|
|
return true; \
|
|
}
|
|
|
|
#define DEF_VISIT_CUSTOM_TYPE(__NAME_TYPE__, __PARAM_TYPE__) \
|
|
bool CxxAstVisitor::Visit##__NAME_TYPE__(clang::__PARAM_TYPE__ v) \
|
|
{ \
|
|
for (auto it = m_components.begin(); it != m_components.end(); it++) \
|
|
{ \
|
|
(*it)->visit##__NAME_TYPE__(v); \
|
|
} \
|
|
return true; \
|
|
}
|
|
|
|
#define DEF_VISIT_TYPE_PTR(__TYPE__) \
|
|
DEF_VISIT_CUSTOM_TYPE_PTR(__TYPE__, __TYPE__)
|
|
|
|
#define DEF_VISIT_TYPE(__TYPE__) \
|
|
DEF_VISIT_CUSTOM_TYPE(__TYPE__, __TYPE__)
|
|
|
|
DEF_VISIT_TYPE_PTR(CastExpr)
|
|
DEF_VISIT_CUSTOM_TYPE_PTR(UnaryAddrOf, UnaryOperator)
|
|
DEF_VISIT_CUSTOM_TYPE_PTR(UnaryDeref, UnaryOperator)
|
|
DEF_VISIT_TYPE_PTR(DeclStmt)
|
|
DEF_VISIT_TYPE_PTR(ReturnStmt)
|
|
DEF_VISIT_TYPE_PTR(InitListExpr)
|
|
DEF_VISIT_TYPE_PTR(TagDecl)
|
|
DEF_VISIT_TYPE_PTR(ClassTemplateSpecializationDecl)
|
|
DEF_VISIT_TYPE_PTR(FunctionDecl)
|
|
DEF_VISIT_TYPE_PTR(CXXMethodDecl)
|
|
DEF_VISIT_TYPE_PTR(VarDecl)
|
|
DEF_VISIT_TYPE_PTR(VarTemplateSpecializationDecl)
|
|
DEF_VISIT_TYPE_PTR(FieldDecl)
|
|
DEF_VISIT_TYPE_PTR(TypedefDecl)
|
|
DEF_VISIT_TYPE_PTR(TypeAliasDecl)
|
|
DEF_VISIT_TYPE_PTR(NamespaceDecl)
|
|
DEF_VISIT_TYPE_PTR(NamespaceAliasDecl)
|
|
DEF_VISIT_TYPE_PTR(EnumConstantDecl)
|
|
DEF_VISIT_TYPE_PTR(UsingDirectiveDecl)
|
|
DEF_VISIT_TYPE_PTR(UsingDecl)
|
|
DEF_VISIT_TYPE_PTR(NonTypeTemplateParmDecl)
|
|
DEF_VISIT_TYPE_PTR(TemplateTypeParmDecl)
|
|
DEF_VISIT_TYPE_PTR(TemplateTemplateParmDecl)
|
|
DEF_VISIT_TYPE(TypeLoc)
|
|
DEF_VISIT_TYPE_PTR(DeclRefExpr)
|
|
DEF_VISIT_TYPE_PTR(MemberExpr)
|
|
DEF_VISIT_TYPE_PTR(CXXDependentScopeMemberExpr)
|
|
DEF_VISIT_TYPE_PTR(CXXConstructExpr)
|
|
DEF_VISIT_TYPE_PTR(LambdaExpr)
|
|
DEF_VISIT_CUSTOM_TYPE_PTR(ConstructorInitializer, CXXCtorInitializer)
|
|
|
|
#undef DEF_VISIT_CUSTOM_TYPE_PTR
|
|
#undef DEF_VISIT_CUSTOM_TYPE
|
|
#undef DEF_VISIT_TYPE_PTR
|
|
#undef DEF_VISIT_TYPE
|
|
|
|
ParseLocation CxxAstVisitor::getParseLocationOfTagDeclBody(clang::TagDecl* decl) const
|
|
{
|
|
if (decl->isThisDeclarationADefinition())
|
|
{
|
|
clang::SourceRange range;
|
|
if (clang::CXXRecordDecl* cxxDecl = clang::dyn_cast_or_null<clang::CXXRecordDecl>(decl))
|
|
{
|
|
clang::ClassTemplateDecl* templateDecl = cxxDecl->getDescribedClassTemplate();
|
|
if (templateDecl)
|
|
{
|
|
range = templateDecl->getSourceRange();
|
|
}
|
|
}
|
|
if (range.isInvalid())
|
|
{
|
|
range = decl->getDefinition()->getSourceRange();
|
|
}
|
|
return getParseLocation(range);
|
|
}
|
|
return ParseLocation();
|
|
}
|
|
|
|
ParseLocation CxxAstVisitor::getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const
|
|
{
|
|
if (decl->hasBody() && decl->isThisDeclarationADefinition())
|
|
{
|
|
clang::SourceRange range;
|
|
clang::FunctionTemplateDecl* templateDecl = decl->getDescribedFunctionTemplate();
|
|
if (templateDecl)
|
|
{
|
|
range = templateDecl->getSourceRange();
|
|
}
|
|
else
|
|
{
|
|
range = decl->getSourceRange();
|
|
}
|
|
return getParseLocation(range);
|
|
}
|
|
return ParseLocation();
|
|
}
|
|
|
|
ParseLocation CxxAstVisitor::getParseLocation(const clang::SourceLocation& sourceLocation) const
|
|
{
|
|
ParseLocation parseLocation;
|
|
if (sourceLocation.isValid())
|
|
{
|
|
const clang::SourceManager& sourceManager = m_astContext->getSourceManager();
|
|
|
|
clang::SourceLocation loc = sourceLocation;
|
|
if (sourceManager.isMacroBodyExpansion(sourceLocation))
|
|
{
|
|
loc = sourceManager.getExpansionLoc(sourceLocation);
|
|
if (loc.isInvalid())
|
|
{
|
|
loc = sourceLocation;
|
|
}
|
|
}
|
|
|
|
const clang::SourceLocation startLoc = sourceManager.getSpellingLoc(loc);
|
|
const clang::FileID fileId = sourceManager.getFileID(startLoc);
|
|
|
|
// find the location file
|
|
if (!fileId.isInvalid())
|
|
{
|
|
const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId);
|
|
if (fileEntry != nullptr && fileEntry->isValid())
|
|
{
|
|
parseLocation.filePath = m_canonicalFilePathCache->getCanonicalFilePath(fileEntry);
|
|
}
|
|
}
|
|
|
|
// find the start location
|
|
{
|
|
const unsigned int offset = sourceManager.getFileOffset(startLoc);
|
|
parseLocation.startLineNumber = sourceManager.getLineNumber(fileId, offset);
|
|
parseLocation.startColumnNumber = sourceManager.getColumnNumber(fileId, offset);
|
|
}
|
|
|
|
// General case -- find the end of the token starting at loc.
|
|
{
|
|
const clang::SourceLocation endSloc = m_preprocessor->getLocForEndOfToken(startLoc);
|
|
const unsigned int offset = sourceManager.getFileOffset(endSloc);
|
|
parseLocation.endLineNumber = sourceManager.getLineNumber(fileId, offset);
|
|
parseLocation.endColumnNumber = sourceManager.getColumnNumber(fileId, offset) - 1;
|
|
}
|
|
}
|
|
|
|
return parseLocation;
|
|
}
|
|
|
|
ParseLocation CxxAstVisitor::getParseLocation(const clang::SourceRange& sourceRange) const
|
|
{
|
|
ParseLocation parseLocation;
|
|
if (sourceRange.isValid())
|
|
{
|
|
const clang::SourceManager& sourceManager = m_astContext->getSourceManager();
|
|
|
|
clang::SourceRange range = sourceRange;
|
|
clang::SourceLocation endLoc = m_preprocessor->getLocForEndOfToken(range.getEnd());
|
|
|
|
if ((
|
|
sourceManager.isMacroArgExpansion(range.getBegin()) ||
|
|
sourceManager.isMacroBodyExpansion(range.getBegin())
|
|
) &&
|
|
(
|
|
sourceManager.isMacroArgExpansion(range.getEnd()) ||
|
|
sourceManager.isMacroBodyExpansion(range.getEnd())
|
|
))
|
|
{
|
|
range = sourceManager.getExpansionRange(sourceRange);
|
|
if (range.isValid())
|
|
{
|
|
endLoc = m_preprocessor->getLocForEndOfToken(range.getBegin());
|
|
}
|
|
else
|
|
{
|
|
range = sourceRange;
|
|
}
|
|
}
|
|
|
|
const clang::SourceLocation beginLoc = range.getBegin();
|
|
|
|
const clang::PresumedLoc presumedBegin = sourceManager.getPresumedLoc(beginLoc, false);
|
|
const clang::PresumedLoc presumedEnd = sourceManager.getPresumedLoc(endLoc.isValid() ? endLoc : range.getEnd(), false);
|
|
|
|
FilePath filePath;
|
|
{
|
|
const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(sourceManager.getFileID(beginLoc));
|
|
if (fileEntry != nullptr && fileEntry->isValid())
|
|
{
|
|
filePath = m_canonicalFilePathCache->getCanonicalFilePath(fileEntry);
|
|
}
|
|
else
|
|
{
|
|
filePath = m_canonicalFilePathCache->getCanonicalFilePath(utility::decodeFromUtf8(presumedBegin.getFilename()));
|
|
}
|
|
}
|
|
|
|
parseLocation = ParseLocation(
|
|
filePath,
|
|
presumedBegin.getLine(),
|
|
presumedBegin.getColumn(),
|
|
presumedEnd.getLine(),
|
|
presumedEnd.getColumn() - (endLoc.isValid() ? 1 : 0)
|
|
);
|
|
}
|
|
return parseLocation;
|
|
}
|
|
|
|
bool CxxAstVisitor::isLocatedInProjectFile(clang::SourceLocation loc)
|
|
{
|
|
const clang::SourceManager& sourceManager = m_astContext->getSourceManager();
|
|
|
|
clang::FileID fileId;
|
|
if (loc.isValid())
|
|
{
|
|
if (sourceManager.isWrittenInMainFile(loc))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
fileId = sourceManager.getFileID(loc);
|
|
}
|
|
|
|
if (fileId.isValid())
|
|
{
|
|
auto it = m_inProjectFileMap.find(fileId);
|
|
if (it != m_inProjectFileMap.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId);
|
|
if (fileEntry != nullptr && fileEntry->isValid())
|
|
{
|
|
FilePath filePath = getCanonicalFilePathCache()->getCanonicalFilePath(fileEntry);
|
|
const bool ret = m_fileRegister->hasFilePath(filePath);
|
|
m_inProjectFileMap[fileId] = ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|