* Implemented functions for parsing usages of fields and global variables in ASTBodyVisitor and ASTVisitor. * Storage adds TokenLocatons and Edges for usages. * Added tests for parsing usage of fields and global variables. fortune cookie message = Fame, riches and love are yours for the taking.
432 lines
11 KiB
C++
432 lines
11 KiB
C++
#include "data/parser/cxx/ASTVisitor.h"
|
|
|
|
#include "data/parser/cxx/ASTBodyVisitor.h"
|
|
#include "data/parser/cxx/utilityCxx.h"
|
|
#include "data/parser/ParseLocation.h"
|
|
#include "data/parser/ParseTypeUsage.h"
|
|
#include "data/parser/ParseVariable.h"
|
|
#include "data/type/DataType.h"
|
|
|
|
ASTVisitor::ASTVisitor(clang::ASTContext* context, std::shared_ptr<ParserClient> client)
|
|
: m_context(context)
|
|
, m_client(client)
|
|
{
|
|
}
|
|
|
|
ASTVisitor::~ASTVisitor()
|
|
{
|
|
}
|
|
|
|
bool ASTVisitor::VisitStmt(const clang::Stmt* statement)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitTypedefDecl(const clang::TypedefDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
m_client->onTypedefParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString(),
|
|
utility::qualTypeToDataType(declaration->getUnderlyingType()),
|
|
convertAccessType(declaration->getAccess())
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
if (declaration->isClass())
|
|
{
|
|
m_client->onClassParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString(),
|
|
convertAccessType(declaration->getAccess())
|
|
);
|
|
|
|
if (declaration->hasDefinition() && declaration->getNumBases())
|
|
{
|
|
for (const auto& it : declaration->bases())
|
|
{
|
|
m_client->onInheritanceParsed(
|
|
getParseLocation(it.getSourceRange()),
|
|
declaration->getQualifiedNameAsString(),
|
|
getTypeName(it.getType()),
|
|
convertAccessType(it.getAccessSpecifier())
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else if (declaration->isStruct())
|
|
{
|
|
m_client->onStructParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString(),
|
|
convertAccessType(declaration->getAccess())
|
|
);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitVarDecl(clang::VarDecl* declaration)
|
|
{
|
|
// Abort on local variables and parameters.
|
|
if (declaration->isFunctionOrMethodVarDecl() || clang::isa<clang::ParmVarDecl>(declaration))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
clang::AccessSpecifier access = declaration->getAccess();
|
|
|
|
if (access == clang::AS_none)
|
|
{
|
|
m_client->onGlobalVariableParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
getParseVariable(declaration)
|
|
);
|
|
|
|
if (declaration->getInit())
|
|
{
|
|
ASTBodyVisitor bodyVisitor(this, declaration);
|
|
bodyVisitor.Visit(declaration->getInit());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_client->onFieldParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
getParseVariable(declaration),
|
|
convertAccessType(declaration->getAccess())
|
|
);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitFieldDecl(clang::FieldDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
m_client->onFieldParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
getParseVariable(declaration),
|
|
convertAccessType(declaration->getAccess())
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitFunctionDecl(clang::FunctionDecl* declaration)
|
|
{
|
|
// Abort for CXXMethodDecls to avoid duplicate call.
|
|
if (clang::isa<clang::CXXMethodDecl>(declaration))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
m_client->onFunctionParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString(),
|
|
getParseTypeUsageOfReturnType(declaration),
|
|
getParameters(declaration)
|
|
);
|
|
|
|
if (declaration->hasBody() && declaration->isThisDeclarationADefinition())
|
|
{
|
|
ASTBodyVisitor bodyVisitor(this, declaration);
|
|
bodyVisitor.Visit(declaration->getBody());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
ParserClient::AbstractionType abstraction = ParserClient::ABSTRACTION_NONE;
|
|
if (declaration->isPure())
|
|
{
|
|
abstraction = ParserClient::ABSTRACTION_PURE_VIRTUAL;
|
|
}
|
|
else if (declaration->isVirtual())
|
|
{
|
|
abstraction = ParserClient::ABSTRACTION_VIRTUAL;
|
|
}
|
|
|
|
m_client->onMethodParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString(),
|
|
getParseTypeUsageOfReturnType(declaration),
|
|
getParameters(declaration),
|
|
convertAccessType(declaration->getAccess()),
|
|
abstraction,
|
|
declaration->isConst(),
|
|
declaration->isStatic()
|
|
);
|
|
|
|
if (declaration->hasBody() && declaration->isThisDeclarationADefinition())
|
|
{
|
|
ASTBodyVisitor bodyVisitor(this, declaration);
|
|
bodyVisitor.Visit(declaration->getBody());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
for (clang::CXXConstructorDecl::init_const_iterator it = declaration->init_begin(); it != declaration->init_end(); it++)
|
|
{
|
|
if ((*it)->getInit())
|
|
{
|
|
ASTBodyVisitor bodyVisitor(this, declaration);
|
|
bodyVisitor.Visit((*it)->getInit());
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitNamespaceDecl(clang::NamespaceDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
m_client->onNamespaceParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString()
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitEnumDecl(clang::EnumDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
m_client->onEnumParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString(),
|
|
convertAccessType(declaration->getAccess())
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ASTVisitor::VisitEnumConstantDecl(clang::EnumConstantDecl* declaration)
|
|
{
|
|
if (hasValidLocation(declaration))
|
|
{
|
|
m_client->onEnumFieldParsed(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
declaration->getQualifiedNameAsString()
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ASTVisitor::VisitCallExprInDeclBody(clang::NamedDecl* decl, clang::CallExpr* expr)
|
|
{
|
|
// if (clang::FunctionDecl *CalleeDecl = CE->getDirectCallee())
|
|
// {
|
|
// return CalleeDecl;
|
|
// }
|
|
|
|
// clang::Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();
|
|
// if (clang::BlockExpr *Block = clang::dyn_cast<clang::BlockExpr>(CEE))
|
|
// {
|
|
// NumBlockCallEdges++;
|
|
// return Block->getBlockDecl();
|
|
// }
|
|
|
|
// return nullptr;
|
|
|
|
m_client->onCallParsed(
|
|
getParseLocation(expr->getSourceRange()),
|
|
decl->getQualifiedNameAsString(),
|
|
expr->getDirectCallee()->getQualifiedNameAsString()
|
|
);
|
|
}
|
|
|
|
void ASTVisitor::VisitCXXConstructExprInDeclBody(clang::NamedDecl* decl, clang::CXXConstructExpr* expr)
|
|
{
|
|
m_client->onCallParsed(
|
|
getParseLocation(expr->getSourceRange()),
|
|
decl->getQualifiedNameAsString(),
|
|
expr->getConstructor()->getQualifiedNameAsString()
|
|
);
|
|
}
|
|
|
|
void ASTVisitor::VisitFieldUsageExprInDeclBody(clang::NamedDecl* decl, clang::MemberExpr* expr)
|
|
{
|
|
const clang::SourceManager& sourceManager = m_context->getSourceManager();
|
|
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(expr->getSourceRange().getBegin());
|
|
const clang::PresumedLoc& presumedEnd = sourceManager.getPresumedLoc(expr->getSourceRange().getEnd());
|
|
const std::string exprName = expr->getMemberNameInfo().getAsString();
|
|
|
|
ParseLocation parseLocation(
|
|
presumedBegin.getFilename(),
|
|
presumedBegin.getLine(),
|
|
presumedBegin.getColumn(),
|
|
presumedEnd.getLine(),
|
|
presumedEnd.getColumn() + exprName.size() - 1
|
|
);
|
|
|
|
m_client->onFieldUsageParsed(
|
|
parseLocation,
|
|
decl->getQualifiedNameAsString(),
|
|
expr->getMemberDecl()->getQualifiedNameAsString()
|
|
);
|
|
}
|
|
|
|
void ASTVisitor::VisitGlobalVariableUsageExprInDeclBody(clang::NamedDecl* decl, clang::DeclRefExpr* expr)
|
|
{
|
|
const clang::SourceManager& sourceManager = m_context->getSourceManager();
|
|
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(expr->getSourceRange().getBegin());
|
|
const clang::PresumedLoc& presumedEnd = sourceManager.getPresumedLoc(expr->getSourceRange().getEnd());
|
|
const std::string exprName = expr->getNameInfo().getAsString();
|
|
|
|
ParseLocation parseLocation(
|
|
presumedBegin.getFilename(),
|
|
presumedBegin.getLine(),
|
|
presumedBegin.getColumn(),
|
|
presumedEnd.getLine(),
|
|
presumedEnd.getColumn() + exprName.size() - 1
|
|
);
|
|
|
|
m_client->onGlobalVariableUsageParsed(
|
|
parseLocation,
|
|
decl->getQualifiedNameAsString(),
|
|
expr->getDecl()->getQualifiedNameAsString()
|
|
);
|
|
}
|
|
|
|
bool ASTVisitor::hasValidLocation(const clang::Decl* declaration) const
|
|
{
|
|
const clang::SourceLocation& location = declaration->getLocStart();
|
|
return location.isValid() && m_context->getSourceManager().isWrittenInMainFile(location);
|
|
}
|
|
|
|
ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange) const
|
|
{
|
|
if (sourceRange.isInvalid())
|
|
{
|
|
return ParseLocation("", 0, 0, 0, 0);
|
|
}
|
|
|
|
const clang::SourceManager& sourceManager = m_context->getSourceManager();
|
|
|
|
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(sourceRange.getBegin());
|
|
const clang::PresumedLoc& presumedEnd = sourceManager.getPresumedLoc(sourceRange.getEnd());
|
|
|
|
return ParseLocation(
|
|
presumedBegin.getFilename(),
|
|
presumedBegin.getLine(),
|
|
presumedBegin.getColumn(),
|
|
presumedEnd.getLine(),
|
|
presumedEnd.getColumn()
|
|
);
|
|
}
|
|
|
|
ParseTypeUsage ASTVisitor::getParseTypeUsage(clang::ValueDecl* declaration) const
|
|
{
|
|
return ParseTypeUsage(
|
|
getParseLocation(declaration->getSourceRange()),
|
|
utility::qualTypeToDataType(declaration->getType())
|
|
);
|
|
}
|
|
|
|
ParseVariable ASTVisitor::getParseVariable(clang::ValueDecl* declaration) const
|
|
{
|
|
bool isStatic = false;
|
|
if (clang::isa<clang::VarDecl>(declaration))
|
|
{
|
|
clang::VarDecl* varDecl = static_cast<clang::VarDecl*>(declaration);
|
|
isStatic = varDecl->isStaticDataMember() || varDecl->getStorageClass() == clang::SC_Static;
|
|
}
|
|
|
|
return ParseVariable(
|
|
utility::qualTypeToDataType(declaration->getType()),
|
|
declaration->getQualifiedNameAsString(),
|
|
isStatic
|
|
);
|
|
}
|
|
|
|
ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(clang::FunctionDecl* declaration) const
|
|
{
|
|
// TODO: use FunctionDecl::getReturnTypeSourceRange() in newer clang version
|
|
clang::SourceRange range;
|
|
const clang::TypeSourceInfo *TSI = declaration->getTypeSourceInfo();
|
|
if (TSI)
|
|
{
|
|
clang::FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs<clang::FunctionTypeLoc>();
|
|
if (FTL)
|
|
{
|
|
// Skip self-referential return types.
|
|
range = clang::SourceRange(
|
|
FTL.getReturnLoc().getLocStart(),
|
|
declaration->getNameInfo().getLocStart().getLocWithOffset(-2)
|
|
);
|
|
}
|
|
}
|
|
|
|
return ParseTypeUsage(
|
|
getParseLocation(range),
|
|
utility::qualTypeToDataType(declaration->getReturnType())
|
|
);
|
|
}
|
|
|
|
std::vector<ParseTypeUsage> ASTVisitor::getParameters(clang::FunctionDecl* declaration) const
|
|
{
|
|
std::vector<ParseTypeUsage> parameters;
|
|
|
|
for (unsigned i = 0; i < declaration->getNumParams(); i++)
|
|
{
|
|
parameters.push_back(getParseTypeUsage(declaration->getParamDecl(i)));
|
|
}
|
|
|
|
return parameters;
|
|
}
|
|
|
|
std::string ASTVisitor::getTypeName(const clang::QualType& qualType) const
|
|
{
|
|
DataType dataType = utility::qualTypeToDataType(qualType);
|
|
return dataType.getRawTypeName();
|
|
}
|
|
|
|
ParserClient::AccessType ASTVisitor::convertAccessType(clang::AccessSpecifier access) const
|
|
{
|
|
switch (access)
|
|
{
|
|
case clang::AS_public:
|
|
return ParserClient::ACCESS_PUBLIC;
|
|
case clang::AS_protected:
|
|
return ParserClient::ACCESS_PROTECTED;
|
|
case clang::AS_private:
|
|
return ParserClient::ACCESS_PRIVATE;
|
|
case clang::AS_none:
|
|
return ParserClient::ACCESS_NONE;
|
|
}
|
|
}
|