Files
Sourcetrail/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp
T
mlangkabel ca3e2f48ee logic: removed C/C++ "unparsed" check from indexer
Cxx AstVisitor re-visits previously or simultaneously indexed files because the "visible" content may have changed due to other preprocessor defines etc.
2018-04-24 13:25:06 +02:00

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;
}