data: basic template parsing

* Implemented basic parsing and storage of template parameter types, template classes and template functions
* Added template specialization edge.
* Implemented handling of partial specializations. Needs some more tweaking.
* Added a lot of test code for template stuff (still needs some cases to be tested)
* Removed the isTemplateParameterType from DataType, since it shouldn't be needed
* Function qualTypeToDataType uses clang PrintingPolicy to fetch the desired format.
* Merged a lot of code for getting the correct names and name hierarchies of definitions
* Removed TokenComponentDataType
* Merged both of the Storage::addTypeEdge(...) functions
* Added "-fno-delayed-template-parsing" flag to parser for parsing test code.
This commit is contained in:
malte_langkabel
2014-11-24 16:50:31 +01:00
parent 7b17f5b3ad
commit 63407c2c81
24 changed files with 792 additions and 239 deletions
+17
View File
@@ -28,6 +28,11 @@ public:
ABSTRACTION_NONE
};
enum RecordType {
RECORD_STRUCT,
RECORD_CLASS
};
static std::string addAccessPrefix(const std::string& str, AccessType access);
static std::string addAbstractionPrefix(const std::string& str, AbstractionType abstraction);
static std::string addStaticPrefix(const std::string& str, bool isStatic);
@@ -84,6 +89,18 @@ public:
virtual Id onGlobalVariableUsageParsed(
const ParseLocation& location, const ParseFunction& user, const std::vector<std::string>& usedNameHierarchy) = 0;
virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function) = 0;
virtual Id onTemplateRecordParameterTypeParsed(
const ParseLocation& location, const std::string& templateParameterTypeName,
const std::vector<std::string>& templateRecordNameHierarchy) = 0;
virtual Id onTemplateRecordSpecializationParsed(
const ParseLocation& location, const std::vector<std::string>& specializedRecordNameHierarchy,
const RecordType specializedRecordType, const std::vector<std::string>& templateRecordNameHierarchy) = 0;
virtual Id onTemplateFunctionParameterTypeParsed(
const ParseLocation& location, const std::string& templateParameterTypeName,
const ParseFunction function) = 0;
virtual Id onTemplateFunctionSpecializationParsed(
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction) = 0;
};
#endif // PARSER_CLIENT_H
+121 -19
View File
@@ -9,6 +9,7 @@
#include "data/parser/ParseTypeUsage.h"
#include "data/parser/ParseVariable.h"
#include "data/type/DataType.h"
#include "utility/logging/logging.h"
#include "utility/utilityString.h"
ASTVisitor::ASTVisitor(clang::ASTContext* context, ParserClient* client)
@@ -32,7 +33,7 @@ bool ASTVisitor::VisitTypedefDecl(clang::TypedefDecl* declaration)
{
m_client->onTypedefParsed(
getParseLocationForNamedDecl(declaration),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
utility::getDeclNameHierarchy(declaration),
getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getUnderlyingType()),
convertAccessType(declaration->getAccess())
);
@@ -49,19 +50,19 @@ bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration)
{
m_client->onClassParsed(
getParseLocationForNamedDecl(declaration),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
utility::getDeclNameHierarchy(declaration),
convertAccessType(declaration->getAccess()),
getParseLocationOfRecordBody(declaration)
);
if (declaration->hasDefinition() && declaration->getNumBases())
{
for (const auto& it : declaration->bases())
for (const clang::CXXBaseSpecifier& it : declaration->bases())
{
m_client->onInheritanceParsed(
getParseLocation(it.getSourceRange()),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
utility::splitToVector(getTypeName(it.getType()), "::"),
utility::getDeclNameHierarchy(declaration),
utility::qualTypeToDataType(it.getType()).getTypeNameHierarchy(),
convertAccessType(it.getAccessSpecifier())
);
}
@@ -71,10 +72,11 @@ bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration)
{
m_client->onStructParsed(
getParseLocationForNamedDecl(declaration),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
utility::getDeclNameHierarchy(declaration),
convertAccessType(declaration->getAccess()),
getParseLocationOfRecordBody(declaration)
);
// TODO: what about struct inheritance?
}
}
@@ -181,7 +183,7 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration)
getParseLocationOfFunctionBody(declaration)
);
if (declaration->hasBody() && declaration->isThisDeclarationADefinition())
if (declaration->hasBody() && declaration->getBody() != NULL && declaration->isThisDeclarationADefinition())
{
ASTBodyVisitor bodyVisitor(this, declaration);
bodyVisitor.Visit(declaration->getBody());
@@ -206,7 +208,7 @@ bool ASTVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration)
m_client->onFieldUsageParsed(
getParseLocationForNamedDecl(init->getMember(), init->getMemberLocation()),
getParseFunction(declaration),
utility::splitToVector(init->getMember()->getQualifiedNameAsString(), "::")
utility::getDeclNameHierarchy(init->getMember())
);
}
else if (init->isBaseInitializer())
@@ -222,7 +224,6 @@ bool ASTVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration)
}
}
}
return true;
}
@@ -232,11 +233,10 @@ bool ASTVisitor::VisitNamespaceDecl(clang::NamespaceDecl* declaration)
{
m_client->onNamespaceParsed(
declaration->isAnonymousNamespace() ? ParseLocation() : getParseLocationForNamedDecl(declaration),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
utility::getDeclNameHierarchy(declaration),
getParseLocation(declaration->getSourceRange())
);
}
return true;
}
@@ -246,12 +246,11 @@ bool ASTVisitor::VisitEnumDecl(clang::EnumDecl* declaration)
{
m_client->onEnumParsed(
getParseLocationForNamedDecl(declaration),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
utility::getDeclNameHierarchy(declaration),
convertAccessType(declaration->getAccess()),
getParseLocation(declaration->getSourceRange())
);
}
return true;
}
@@ -261,13 +260,110 @@ bool ASTVisitor::VisitEnumConstantDecl(clang::EnumConstantDecl* declaration)
{
m_client->onEnumFieldParsed(
getParseLocation(declaration->getSourceRange()),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::")
utility::getDeclNameHierarchy(declaration)
);
}
return true;
}
bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration)
{
std::vector<std::string> templateRecordNameHierarchy = utility::getDeclNameHierarchy(declaration);
clang::TemplateParameterList* parameterList = declaration->getTemplateParameters();
for (int i = 0; i < parameterList->size(); i++)
{
clang::NamedDecl* namedDecl = parameterList->getParam(i);
if (hasValidLocation(namedDecl))
{
std::string templateParameterTypeName = namedDecl->getNameAsString();
m_client->onTemplateRecordParameterTypeParsed(
getParseLocationForNamedDecl(namedDecl),
templateParameterTypeName,
templateRecordNameHierarchy
);
}
}
for (clang::ClassTemplateDecl::spec_iterator it = declaration->specializations().begin(); // template argument as parameter does not work
it != declaration->specializations().end(); it++
)
{
ParserClient::RecordType specializedRecordType = it->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS;
std::vector<std::string> specializedRecordNameHierarchy = utility::getDeclNameHierarchy(*(it));
m_client->onTemplateRecordSpecializationParsed(
getParseLocationForNamedDecl(*it), specializedRecordNameHierarchy, specializedRecordType, templateRecordNameHierarchy
);
}
return true;
}
bool ASTVisitor::VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* declaration)
{
//std::vector<std::string> templateRecordNameHierarchy = utility::splitToVector(
// declaration->getQualifiedNameAsString(), "::"
//);
//clang::ClassTemplateDecl* baseTemplateDecl = declaration->getSpecializedTemplate();
//std::string specializedParameterNamePart = "<";
//const clang::TemplateArgumentList& templateArgumentList = declaration->getTemplateArgs();
//for (int i = 0; i < templateArgumentList.size(); i++)
//{
// DataType datatype = utility::qualTypeToDataType(templateArgumentList.get(i).getAsType());
// if (datatype.isTemplateParameterType())
// {
// specializedParameterNamePart += baseTemplateDecl->getTemplateParameters()->getParam(i)->getNameAsString();
// }
// else
// {
// specializedParameterNamePart += datatype.getFullTypeName();
// }
// specializedParameterNamePart += (i < templateArgumentList.size() - 1) ? ", " : "";
//}
//specializedParameterNamePart += ">";
//int foo = 0;
return true;
}
bool ASTVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declaration)
{
const ParseFunction templateFunction = getParseFunction(declaration->getTemplatedDecl());
for (clang::FunctionTemplateDecl::spec_iterator it = declaration->specializations().begin(); it != declaration->specializations().end(); it++)
{
ParseLocation specializedFunctionLocation = getParseLocationForNamedDecl(*(it));
ParseFunction specializedFunction = getParseFunction(*(it));
m_client->onTemplateFunctionSpecializationParsed(
specializedFunctionLocation,
specializedFunction,
templateFunction);
m_client->onFunctionParsed(specializedFunctionLocation, specializedFunction, getParseLocationOfFunctionBody(*(it)));
}
clang::TemplateParameterList* parameterList = declaration->getTemplateParameters();
for (int i = 0; i < parameterList->size(); i++)
{
clang::NamedDecl* namedDecl = parameterList->getParam(i);
if (hasValidLocation(namedDecl))
{
std::string templateParameterTypeName = namedDecl->getNameAsString();
m_client->onTemplateFunctionParameterTypeParsed(
getParseLocationForNamedDecl(namedDecl),
templateParameterTypeName,
templateFunction
);
}
}
return true;
}
void ASTVisitor::VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallExpr* expr)
{
// if (clang::FunctionDecl *CalleeDecl = CE->getDirectCallee())
@@ -340,7 +436,7 @@ void ASTVisitor::VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::Mem
m_client->onFieldUsageParsed(
parseLocation,
getParseFunction(decl),
utility::splitToVector(expr->getMemberDecl()->getQualifiedNameAsString(), "::")
utility::getDeclNameHierarchy(expr->getMemberDecl())
);
}
@@ -354,7 +450,7 @@ void ASTVisitor::VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::De
m_client->onGlobalVariableUsageParsed(
parseLocation,
getParseFunction(decl),
utility::splitToVector(expr->getDecl()->getQualifiedNameAsString(), "::")
utility::getDeclNameHierarchy(expr->getDecl())
);
}
@@ -504,16 +600,21 @@ std::vector<ParseTypeUsage> ASTVisitor::getParameters(clang::FunctionDecl* decla
ParseVariable ASTVisitor::getParseVariable(clang::DeclaratorDecl* declaration) const
{
bool isStatic = false;
bool isStatic;
std::vector<std::string> hameHierarchy = utility::getDeclNameHierarchy(declaration);
if (clang::isa<clang::VarDecl>(declaration))
{
clang::VarDecl* varDecl = clang::dyn_cast<clang::VarDecl>(declaration);
isStatic = varDecl->isStaticDataMember() || varDecl->getStorageClass() == clang::SC_Static;
}
else if (clang::isa<clang::FieldDecl>(declaration))
{
isStatic = false; // fieldDecls cannot be static. If they are, they are treated as VarDecls
}
return ParseVariable(
getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getType()),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
hameHierarchy,
isStatic
);
}
@@ -522,6 +623,7 @@ ParseFunction ASTVisitor::getParseFunction(clang::FunctionDecl* declaration) con
{
bool isStatic = false;
bool isConst = false;
if (clang::isa<clang::CXXMethodDecl>(declaration))
{
clang::CXXMethodDecl* methodDecl = clang::dyn_cast<clang::CXXMethodDecl>(declaration);
@@ -535,7 +637,7 @@ ParseFunction ASTVisitor::getParseFunction(clang::FunctionDecl* declaration) con
return ParseFunction(
getParseTypeUsageOfReturnType(declaration),
utility::splitToVector(declaration->getQualifiedNameAsString(), "::"),
utility::getDeclNameHierarchy(declaration),
getParameters(declaration),
isStatic,
isConst
+9 -5
View File
@@ -16,11 +16,11 @@ public:
virtual ~ASTVisitor();
// Left for debugging purposes. Uncomment to see a colored ast-dump of the parsed file.
// virtual bool VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl)
// {
// decl->dump();
// return true;
// }
//virtual bool VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl)
//{
// decl->dump();
// return true;
//}
// RecursiveASTVisitor implementation
virtual bool VisitStmt(const clang::Stmt* statement); // avoid visiting
@@ -36,6 +36,10 @@ public:
virtual bool VisitEnumDecl(clang::EnumDecl* declaration); // enums
virtual bool VisitEnumConstantDecl(clang::EnumConstantDecl* declaration); // enum fields
virtual bool VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration);
virtual bool VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* declaration);
virtual bool VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declaration);
// ASTBodyVisitorClient implementation
virtual void VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallExpr* expr); // calls
virtual void VisitCallExprInDeclBody(clang::VarDecl* decl, clang::CallExpr* expr); // calls in initialization of global variables
+7 -1
View File
@@ -26,6 +26,10 @@ void CxxParser::parseFiles(
// verbose
// args.push_back("-v");
// The option -fno-delayed-template-parsing signals that templates that there should
// be AST elements for unused template functions as well.
args.push_back("-fno-delayed-template-parsing");
// The option -c signals that no executable is built.
args.push_back("-c");
@@ -72,5 +76,7 @@ void CxxParser::parseFiles(
void CxxParser::parseFile(std::shared_ptr<TextAccess> textAccess)
{
ASTActionFactory actionFactory(m_client);
clang::tooling::runToolOnCode(actionFactory.create(), textAccess->getText());
std::vector<std::string> args;
args.push_back("-fno-delayed-template-parsing");
clang::tooling::runToolOnCodeWithArgs(actionFactory.create(), textAccess->getText(), args);
}
+115 -14
View File
@@ -1,5 +1,9 @@
#include "data/parser/cxx/utilityCxx.h"
#include <clang/AST/PrettyPrinter.h>
#include <clang/AST/DeclTemplate.h>
#include <clang/AST/ASTContext.h>
#include "data/type/DataType.h"
#include "data/type/modifier/DataTypeModifierArray.h"
#include "data/type/modifier/DataTypeModifierPointer.h"
@@ -7,12 +11,13 @@
#include "data/type/DataTypeModifierStack.h"
#include "data/type/DataTypeQualifierList.h"
#include "utility/utilityString.h"
#include "utility/logging/logging.h"
namespace utility
{
DataType qualTypeToDataType(clang::QualType qualType)
{
std::string typeName;
std::vector<std::string> typeNameHerarchy;
DataTypeQualifierList qualifierList;
DataTypeModifierStack modifierStack;
@@ -21,7 +26,7 @@ namespace utility
const clang::Type* type = qualType.getTypePtr();
if (type->getAs<clang::TypedefType>())
{
typeName = utility::substrAfter(qualType.getAsString(), ' ');
typeNameHerarchy.push_back(utility::substrAfter(qualType.getAsString(), ' '));
break;
}
else if (type->isPointerType())
@@ -54,17 +59,35 @@ namespace utility
qualType = type->getPointeeType();
}
else if (type->isStructureOrClassType() || type->isEnumeralType())
{
// we are working on the string here to not lose the namespace information stored in the name.
typeName = utility::substrAfter(qualType.getAsString(), ' ');
// typeName = qualType.getBaseTypeIdentifier()->getName(); // this one does not keep namespace information.
break;
}
else
{
typeName = qualType.getUnqualifiedType().getAsString();
const clang::Type* type = qualType.getUnqualifiedType().getTypePtr();
if (clang::isa<clang::TagType>(type))
{
typeNameHerarchy = getDeclNameHierarchy(clang::dyn_cast<clang::TagType>(type)->getDecl());
}
else
{
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
std::string typeName = qualType.getUnqualifiedType().getAsString(pp);
if (type->isTemplateTypeParmType())
{
clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast<clang::TemplateTypeParmType>(qualType.getUnqualifiedType())->getDecl();
if (templateTypeParmDecl)
{
typeNameHerarchy = getContextNameHierarchy(templateTypeParmDecl->getDeclContext());
typeNameHerarchy.back() += "::" + typeName;
}
}
else
{
typeNameHerarchy.push_back(typeName);
}
}
break;
}
}
@@ -73,12 +96,90 @@ namespace utility
{
qualifierList.addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
}
return DataType(typeNameHerarchy, qualifierList, modifierStack);
}
if (typeName == "_Bool")
std::vector<std::string> getDeclNameHierarchy(clang::Decl* declaration)
{
std::string declName = "";
if (clang::isa<clang::NamedDecl>(declaration))
{
typeName = "bool";
declName = getDeclName(clang::dyn_cast<clang::NamedDecl>(declaration));
}
else
{
LOG_ERROR("unhandled declaration type");
}
std::vector<std::string> contextNameHierarchy = getContextNameHierarchy(declaration->getDeclContext());
contextNameHierarchy.push_back(declName);
return contextNameHierarchy;
}
std::vector<std::string> getContextNameHierarchy(clang::DeclContext* declContext)
{
std::vector<std::string> contextNameHierarchy;
clang::DeclContext* parentContext = declContext->getParent();
if (parentContext)
{
contextNameHierarchy = getContextNameHierarchy(parentContext);
}
return DataType(typeName, qualifierList, modifierStack);
if (clang::isa<clang::NamedDecl>(declContext))
{
std::string declName = getDeclName(clang::dyn_cast<clang::NamedDecl>(declContext));
if (declName != "")
{
contextNameHierarchy.push_back(declName);
}
}
return contextNameHierarchy;
}
std::string getDeclName(clang::NamedDecl* declaration)
{
std::string declName = declaration->getNameAsString();
if (clang::isa<clang::CXXRecordDecl>(declaration))
{
clang::ClassTemplateDecl* templateClassDeclaration = clang::dyn_cast<clang::CXXRecordDecl>(declaration)->getDescribedClassTemplate();
if (templateClassDeclaration)
{
declName = getDeclName(templateClassDeclaration);
}
else if (clang::isa<clang::ClassTemplateSpecializationDecl>(declaration))
{
std::string specializedParameterNamePart = "<";
const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(declaration)->getTemplateArgs();
for (int i = 0; i < templateArgumentList.size(); i++)
{
DataType datatype = utility::qualTypeToDataType(templateArgumentList.get(i).getAsType());
specializedParameterNamePart += datatype.getFullTypeName();
specializedParameterNamePart += (i < templateArgumentList.size() - 1) ? ", " : "";
}
specializedParameterNamePart += ">";
declName += specializedParameterNamePart;
}
}
else if (clang::isa<clang::TemplateDecl>(declaration))
{
std::string templateParameterNamePart = "<";
clang::TemplateParameterList* parameterList = clang::dyn_cast<clang::TemplateDecl>(declaration)->getTemplateParameters();
for (int i = 0; i < parameterList->size(); i++)
{
clang::NamedDecl* namedDecl = parameterList->getParam(i);
templateParameterNamePart += namedDecl->getNameAsString();
templateParameterNamePart += (i < parameterList->size() - 1) ? ", " : "";
}
templateParameterNamePart += ">";
declName += templateParameterNamePart;
}
else if (clang::isa<clang::NamespaceDecl>(declaration) && clang::dyn_cast<clang::NamespaceDecl>(declaration)->isAnonymousNamespace())
{
declName = "(anonymous namespace)";
}
return declName;
}
}
+7
View File
@@ -2,14 +2,21 @@
#define UTILITY_CLANG_H
#include <memory>
#include <string>
#include <vector>
#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
class DataType;
namespace utility
{
DataType qualTypeToDataType(clang::QualType qualType);
std::vector<std::string> getDeclNameHierarchy(clang::Decl* declaration);
std::vector<std::string> getContextNameHierarchy(clang::DeclContext* declaration);
std::string getDeclName(clang::NamedDecl* declaration);
}
#endif // UTILITY_CLANG_H