build: merge Coati app and Trial to single executable
* removed trial target * updated deploy scripts to exclude trial * cleanup CMakeLists * removed Eigen dependencies * split parser lib into lib_cxx and lib_java * added ProjectFactory and ProjectFactoryModules * removed old installer projects * updated wix installer * updated readme for wix setup * updated to use obfuscated exe * added qt.conf * added indexing dialog images * added jars * added coatidb files of sample projects * added source code of javaparser sample * removed auto-refresh image * intermediate files of windows installer are created in build folder * preselected desktop shortcut * build bat is executed from deploy_windows script
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
#include "data/parser/cxx/ASTAction.h"
|
||||
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
|
||||
#include "data/parser/cxx/CommentHandler.h"
|
||||
#include "data/parser/cxx/PreprocessorCallbacks.h"
|
||||
|
||||
ASTAction::ASTAction(ParserClient* client, FileRegister* fileRegister)
|
||||
: m_client(client)
|
||||
, m_fileRegister(fileRegister)
|
||||
, m_commentHandler(client, fileRegister)
|
||||
{
|
||||
}
|
||||
|
||||
ASTAction::~ASTAction()
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer> ASTAction::CreateASTConsumer(clang::CompilerInstance& compiler, llvm::StringRef inFile)
|
||||
{
|
||||
return std::unique_ptr<clang::ASTConsumer>(new ASTConsumer(&compiler.getASTContext(), &compiler.getPreprocessor(), m_client, m_fileRegister));
|
||||
}
|
||||
|
||||
bool ASTAction::BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::StringRef filePath)
|
||||
{
|
||||
clang::Preprocessor& preprocessor = compiler.getPreprocessor();
|
||||
preprocessor.addPPCallbacks(
|
||||
llvm::make_unique<PreprocessorCallbacks>(compiler.getSourceManager(), m_client, m_fileRegister));
|
||||
preprocessor.addCommentHandler(&m_commentHandler);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef AST_ACTION_H
|
||||
#define AST_ACTION_H
|
||||
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
|
||||
#include "data/parser/cxx/ASTConsumer.h"
|
||||
#include "data/parser/cxx/CommentHandler.h"
|
||||
#include "utility/file/FileRegister.h"
|
||||
|
||||
class ASTAction : public clang::ASTFrontendAction
|
||||
{
|
||||
public:
|
||||
explicit ASTAction(ParserClient* client, FileRegister* fileRegister);
|
||||
virtual ~ASTAction();
|
||||
|
||||
protected:
|
||||
virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler, llvm::StringRef inFile);
|
||||
|
||||
virtual bool BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::StringRef filePath);
|
||||
|
||||
private:
|
||||
ParserClient* m_client;
|
||||
FileRegister* m_fileRegister;
|
||||
CommentHandler m_commentHandler;
|
||||
|
||||
};
|
||||
|
||||
#endif // AST_ACTION_H
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "data/parser/cxx/ASTActionFactory.h"
|
||||
|
||||
ASTActionFactory::ASTActionFactory(ParserClient* client, FileRegister* fileRegister)
|
||||
: m_client(client)
|
||||
, m_fileRegister(fileRegister)
|
||||
{
|
||||
}
|
||||
|
||||
ASTActionFactory::~ASTActionFactory()
|
||||
{
|
||||
}
|
||||
|
||||
clang::FrontendAction* ASTActionFactory::create()
|
||||
{
|
||||
return new ASTAction(m_client, m_fileRegister);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef AST_ACTION_FACTORY
|
||||
#define AST_ACTION_FACTORY
|
||||
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
#include "data/parser/cxx/ASTAction.h"
|
||||
#include "utility/file/FileRegister.h"
|
||||
|
||||
class ASTActionFactory : public clang::tooling::FrontendActionFactory
|
||||
{
|
||||
public:
|
||||
explicit ASTActionFactory(ParserClient* client, FileRegister* fileRegister);
|
||||
virtual ~ASTActionFactory();
|
||||
|
||||
virtual clang::FrontendAction* create();
|
||||
|
||||
private:
|
||||
ParserClient* m_client;
|
||||
FileRegister* m_fileRegister;
|
||||
};
|
||||
|
||||
#endif // AST_ACTION_FACTORY
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "data/parser/cxx/ASTConsumer.h"
|
||||
|
||||
#include "data/parser/ParserClient.h"
|
||||
|
||||
ASTConsumer::ASTConsumer(clang::ASTContext* context, clang::Preprocessor* preprocessor, ParserClient* client, FileRegister* fileRegister)
|
||||
: m_visitor(context, preprocessor, client, fileRegister)
|
||||
{
|
||||
}
|
||||
|
||||
ASTConsumer::~ASTConsumer()
|
||||
{
|
||||
}
|
||||
|
||||
void ASTConsumer::HandleTranslationUnit(clang::ASTContext& context)
|
||||
{
|
||||
m_visitor.indexDecl(context.getTranslationUnitDecl());
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef AST_CONSUMER_H
|
||||
#define AST_CONSUMER_H
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
|
||||
#include "utility/file/FileRegister.h"
|
||||
|
||||
#include "data/parser/cxx/ASTVisitor.h"
|
||||
|
||||
class ASTConsumer
|
||||
: public clang::ASTConsumer
|
||||
{
|
||||
public:
|
||||
explicit ASTConsumer(clang::ASTContext* context, clang::Preprocessor* preprocessor, ParserClient* client, FileRegister* fileRegister);
|
||||
virtual ~ASTConsumer();
|
||||
|
||||
virtual void HandleTranslationUnit(clang::ASTContext& context);
|
||||
|
||||
private:
|
||||
ASTVisitor m_visitor;
|
||||
};
|
||||
|
||||
#endif // AST_CONSUMER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,248 @@
|
||||
#ifndef AST_VISITOR_H
|
||||
#define AST_VISITOR_H
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Basic/SourceLocation.h>
|
||||
#include <clang/Basic/SourceManager.h>
|
||||
|
||||
#include "data/parser/ParserClient.h"
|
||||
#include "data/parser/SymbolKind.h"
|
||||
#include "utility/file/FileRegister.h"
|
||||
#include "utility/messaging/MessageInterruptTasksCounter.h"
|
||||
#include "utility/Cache.h"
|
||||
|
||||
class ASTVisitor
|
||||
: clang::RecursiveASTVisitor<ASTVisitor>
|
||||
{
|
||||
public:
|
||||
typedef Cache<const clang::NamedDecl*, NameHierarchy> DeclNameCache;
|
||||
typedef Cache<const clang::Type*, NameHierarchy> TypeNameCache;
|
||||
|
||||
class ContextNameGenerator
|
||||
{
|
||||
public:
|
||||
virtual ~ContextNameGenerator() {}
|
||||
virtual NameHierarchy getName() const = 0;
|
||||
};
|
||||
|
||||
class ContextDeclNameGenerator: public ContextNameGenerator
|
||||
{
|
||||
public:
|
||||
ContextDeclNameGenerator(const clang::NamedDecl* decl, std::shared_ptr<DeclNameCache> nameCache)
|
||||
: m_decl(decl)
|
||||
, m_nameCache(nameCache)
|
||||
{}
|
||||
|
||||
virtual ~ContextDeclNameGenerator() {}
|
||||
|
||||
virtual NameHierarchy getName() const
|
||||
{
|
||||
return m_nameCache->getValue(m_decl);
|
||||
}
|
||||
|
||||
private:
|
||||
const clang::NamedDecl* m_decl;
|
||||
std::shared_ptr<DeclNameCache> m_nameCache;
|
||||
};
|
||||
|
||||
class ContextTypeNameGenerator: public ContextNameGenerator
|
||||
{
|
||||
public:
|
||||
ContextTypeNameGenerator(const clang::Type* type, std::shared_ptr<TypeNameCache> nameCache)
|
||||
: m_type(type)
|
||||
, m_nameCache(nameCache)
|
||||
{}
|
||||
|
||||
virtual ~ContextTypeNameGenerator() {}
|
||||
|
||||
virtual NameHierarchy getName() const
|
||||
{
|
||||
return m_nameCache->getValue(m_type);
|
||||
}
|
||||
|
||||
private:
|
||||
const clang::Type* m_type;
|
||||
std::shared_ptr<TypeNameCache> m_nameCache;
|
||||
};
|
||||
|
||||
ASTVisitor(clang::ASTContext* context, clang::Preprocessor* preprocessor, ParserClient* client, FileRegister* fileRegister);
|
||||
virtual ~ASTVisitor();
|
||||
|
||||
// Left for debugging purposes. Uncomment to see a colored ast-dump of the parsed file.
|
||||
virtual bool VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl);
|
||||
|
||||
|
||||
void indexDecl(clang::Decl *d) { TraverseDecl(d); }
|
||||
|
||||
private:
|
||||
typedef clang::RecursiveASTVisitor<ASTVisitor> base;
|
||||
friend class clang::RecursiveASTVisitor<ASTVisitor>;
|
||||
|
||||
// XXX: The CF_Read flag is useful mostly for lvalues -- for rvalues, we
|
||||
// don't set the CF_Read flag, but the rvalue is assumed to be read anyway.
|
||||
|
||||
enum ContextFlags {
|
||||
CF_Called = 0x1, // the value is read only to be called
|
||||
CF_Read = 0x2, // the value is read for any other use
|
||||
CF_AddressTaken = 0x4, // the gl-value's address escapes
|
||||
CF_Assigned = 0x8, // the gl-value is assigned to
|
||||
CF_Modified = 0x10 // the gl-value is updated (i.e. compound assignment)
|
||||
};
|
||||
|
||||
enum RefType : int {
|
||||
RT_AddressTaken,
|
||||
RT_Assigned,
|
||||
RT_BaseClass,
|
||||
RT_Called,
|
||||
RT_Declaration,
|
||||
RT_DefinedTest,
|
||||
RT_Definition,
|
||||
RT_Expansion,
|
||||
RT_Included,
|
||||
RT_Initialized,
|
||||
RT_Modified,
|
||||
RT_NamespaceAlias,
|
||||
RT_Other,
|
||||
RT_Qualifier,
|
||||
RT_Read,
|
||||
RT_Reference,
|
||||
RT_TemplateArgument,
|
||||
RT_TemplateDefaultArgument,
|
||||
RT_TemplateSpecialization,
|
||||
RT_Undefinition,
|
||||
RT_Using,
|
||||
RT_UsingDirective,
|
||||
RT_Max
|
||||
};
|
||||
|
||||
typedef unsigned int Context;
|
||||
|
||||
clang::ASTContext* m_context;
|
||||
clang::Preprocessor* m_preprocessor;
|
||||
ParserClient* m_client;
|
||||
FileRegister* m_fileRegister;
|
||||
|
||||
Context m_thisContext;
|
||||
Context m_childContext;
|
||||
RefType m_typeContext;
|
||||
|
||||
// Misc routines
|
||||
bool shouldVisitTemplateInstantiations() const { return true; }
|
||||
bool shouldVisitImplicitCode() const { return true; }
|
||||
|
||||
// Dispatcher routines
|
||||
bool TraverseStmt(clang::Stmt *stmt);
|
||||
bool TraverseType(clang::QualType t);
|
||||
bool TraverseTypeLoc(clang::TypeLoc tl);
|
||||
bool TraverseDecl(clang::Decl *d);
|
||||
bool TraverseLambdaExpr(clang::LambdaExpr* e);
|
||||
bool TraverseFunctionDecl(clang::FunctionDecl* d);
|
||||
bool TraverseTypedefDecl(clang::TypedefDecl *d);
|
||||
bool TraverseTypeAliasDecl(clang::TypeAliasDecl *d);
|
||||
bool TraverseFieldDecl(clang::FieldDecl *d);
|
||||
bool TraverseVarDecl(clang::VarDecl *d);
|
||||
bool TraverseClassTemplateDecl(clang::ClassTemplateDecl* d);
|
||||
bool TraverseFunctionTemplateDecl(clang::FunctionTemplateDecl* d);
|
||||
bool TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d);
|
||||
bool TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d);
|
||||
bool TraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d);
|
||||
bool TraverseDeclRefExpr(clang::DeclRefExpr* e);
|
||||
bool TraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc);
|
||||
bool TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e);
|
||||
bool TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc);
|
||||
|
||||
// Expression context propagation
|
||||
bool TraverseCallExpr(clang::CallExpr *e) { return TraverseCallCommon(e); }
|
||||
bool TraverseCXXMemberCallExpr(clang::CXXMemberCallExpr *e) { return TraverseCallCommon(e); }
|
||||
bool TraverseCXXOperatorCallExpr(clang::CXXOperatorCallExpr *e) { return TraverseCallCommon(e); }
|
||||
bool TraverseBinComma(clang::BinaryOperator *s);
|
||||
bool TraverseBinAssign(clang::BinaryOperator *e) { return TraverseAssignCommon(e, CF_Assigned); }
|
||||
#define OPERATOR(NAME) bool TraverseBin##NAME##Assign(clang::CompoundAssignOperator *e) { return TraverseAssignCommon(e, CF_Modified); }
|
||||
OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub)
|
||||
OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor)
|
||||
#undef OPERATOR
|
||||
bool VisitParenExpr(clang::ParenExpr *e) { m_childContext = m_thisContext; return true; }
|
||||
bool VisitCastExpr(clang::CastExpr *e);
|
||||
bool VisitUnaryAddrOf(clang::UnaryOperator *e);
|
||||
bool VisitUnaryDeref(clang::UnaryOperator *e);
|
||||
bool VisitDeclStmt(clang::DeclStmt *s);
|
||||
bool VisitReturnStmt(clang::ReturnStmt *s);
|
||||
bool VisitVarDecl(clang::VarDecl *d);
|
||||
bool VisitInitListExpr(clang::InitListExpr *e);
|
||||
bool TraverseConstructorInitializer(clang::CXXCtorInitializer *init);
|
||||
bool TraverseCallCommon(clang::CallExpr *call);
|
||||
bool TraverseAssignCommon(clang::BinaryOperator *e, ContextFlags lhsFlag);
|
||||
|
||||
// Expression reference recording
|
||||
bool VisitLambdaExpr(clang::LambdaExpr* e);
|
||||
bool VisitMemberExpr(clang::MemberExpr *e);
|
||||
bool VisitDeclRefExpr(clang::DeclRefExpr *e);
|
||||
bool VisitCXXConstructExpr(clang::CXXConstructExpr *e);
|
||||
void RecordDeclRefExpr(clang::NamedDecl *d, clang::SourceLocation loc, clang::Expr *e, Context context);
|
||||
|
||||
// NestedNameSpecifier handling
|
||||
bool TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc qualifier);
|
||||
|
||||
// Declaration and TypeLoc handling
|
||||
void traverseDeclContextHelper(clang::DeclContext *d);
|
||||
bool TraverseCXXRecordDecl(clang::CXXRecordDecl *d);
|
||||
bool TraverseNamespaceAliasDecl(clang::NamespaceAliasDecl *d);
|
||||
bool TraverseClassTemplateSpecializationDecl(
|
||||
clang::ClassTemplateSpecializationDecl *d);
|
||||
void templateParameterListsHelper(clang::DeclaratorDecl *d);
|
||||
bool VisitDecl(clang::Decl *d);
|
||||
bool VisitTypeLoc(clang::TypeLoc tl);
|
||||
|
||||
// Reference recording
|
||||
ParseLocation getDeclRefRange(
|
||||
clang::NamedDecl *decl,
|
||||
clang::SourceLocation loc);
|
||||
|
||||
void RecordTypeRef(
|
||||
const clang::Type* type,
|
||||
clang::SourceLocation beginLoc,
|
||||
RefType refType,
|
||||
SymbolKind symbolType = SYMBOL_KIND_MAX);
|
||||
|
||||
void RecordDeclRef(
|
||||
clang::NamedDecl *d,
|
||||
clang::SourceLocation beginLoc,
|
||||
RefType refType,
|
||||
SymbolKind symbolType = SYMBOL_KIND_MAX);
|
||||
|
||||
bool isImplicit(clang::Decl* d) const;
|
||||
|
||||
bool isLocatedInUnparsedProjectFile(clang::SourceLocation loc);
|
||||
bool isLocatedInProjectFile(clang::SourceLocation loc);
|
||||
|
||||
AccessKind convertAccessType(clang::AccessSpecifier access) const;
|
||||
ParserClient::AbstractionType getAbstractionType(const clang::CXXMethodDecl* methodDecl) const;
|
||||
ParseLocation getParseLocationOfRecordBody(clang::RecordDecl* decl) const;
|
||||
ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const;
|
||||
ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const;
|
||||
|
||||
NameHierarchy getContextName() const;
|
||||
|
||||
struct FileIdHash {
|
||||
size_t operator()(clang::FileID fileID) const {
|
||||
return fileID.getHashValue();
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<const clang::FileID, bool, FileIdHash> m_inUnparsedProjectFileMap;
|
||||
std::unordered_map<const clang::FileID, bool, FileIdHash> m_inProjectFileMap;
|
||||
|
||||
std::shared_ptr<ContextNameGenerator> m_contextNameGenerator;
|
||||
std::shared_ptr<ContextNameGenerator> m_childContextNameGenerator; // TODO: rename templateArgumentContextNameGenerator
|
||||
|
||||
std::shared_ptr<DeclNameCache> m_declNameCache;
|
||||
std::shared_ptr<TypeNameCache> m_typeNameCache;
|
||||
|
||||
AccessKind m_contextAccess;
|
||||
MessageInterruptTasksCounter m_interruptCounter;
|
||||
};
|
||||
|
||||
#endif // AST_VISITOR_H
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "data/parser/cxx/CommentHandler.h"
|
||||
|
||||
#include "data/parser/ParseLocation.h"
|
||||
#include "data/parser/ParserClient.h"
|
||||
#include "utility/file/FileRegister.h"
|
||||
|
||||
CommentHandler::CommentHandler(ParserClient* client, FileRegister* fileRegister)
|
||||
: m_client(client)
|
||||
, m_fileRegister(fileRegister)
|
||||
{
|
||||
}
|
||||
|
||||
CommentHandler::~CommentHandler()
|
||||
{
|
||||
}
|
||||
|
||||
bool CommentHandler::HandleComment(clang::Preprocessor& preprocessor, clang::SourceRange sourceRange)
|
||||
{
|
||||
clang::SourceManager& sourceManager = preprocessor.getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(sourceRange.getBegin(), false);
|
||||
const clang::PresumedLoc& presumedEnd = sourceManager.getPresumedLoc(sourceRange.getEnd(), false);
|
||||
|
||||
FilePath filePath = FilePath(presumedBegin.getFilename());
|
||||
if (m_fileRegister->hasFilePath(filePath) && !m_fileRegister->fileIsParsed(filePath))
|
||||
{
|
||||
m_client->onCommentParsed(ParseLocation(
|
||||
presumedBegin.getFilename(),
|
||||
presumedBegin.getLine(),
|
||||
presumedBegin.getColumn(),
|
||||
presumedEnd.getLine(),
|
||||
presumedEnd.getColumn()
|
||||
));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef COMMENT_HANDLER_H
|
||||
#define COMMENT_HANDLER_H
|
||||
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
|
||||
class FileRegister;
|
||||
class ParserClient;
|
||||
|
||||
class CommentHandler
|
||||
: public clang::CommentHandler
|
||||
{
|
||||
public:
|
||||
CommentHandler(ParserClient* client, FileRegister* fileRegister);
|
||||
virtual ~CommentHandler();
|
||||
|
||||
virtual bool HandleComment(clang::Preprocessor& preprocessor, clang::SourceRange sourceRange);
|
||||
|
||||
private:
|
||||
ParserClient* m_client;
|
||||
FileRegister* m_fileRegister;
|
||||
};
|
||||
|
||||
#endif // COMMENT_HANDLER_H
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "data/parser/cxx/CxxCompilationDatabaseSingle.h"
|
||||
|
||||
CxxCompilationDatabaseSingle::CxxCompilationDatabaseSingle(const clang::tooling::CompileCommand& command)
|
||||
: m_command(command)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<clang::tooling::CompileCommand> CxxCompilationDatabaseSingle::getCompileCommands(
|
||||
llvm::StringRef FilePath
|
||||
) const {
|
||||
return getAllCompileCommands();
|
||||
}
|
||||
|
||||
std::vector<std::string> CxxCompilationDatabaseSingle::getAllFiles() const
|
||||
{
|
||||
return std::vector<std::string>(1, m_command.Filename);
|
||||
}
|
||||
|
||||
std::vector<clang::tooling::CompileCommand> CxxCompilationDatabaseSingle::getAllCompileCommands() const
|
||||
{
|
||||
return std::vector<clang::tooling::CompileCommand>(1, m_command);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef CXX_COMPILATION_DATABASE_SINGLE_H
|
||||
#define CXX_COMPILATION_DATABASE_SINGLE_H
|
||||
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
|
||||
class CxxCompilationDatabaseSingle
|
||||
: public clang::tooling::CompilationDatabase
|
||||
{
|
||||
public:
|
||||
CxxCompilationDatabaseSingle(const clang::tooling::CompileCommand& command);
|
||||
|
||||
virtual std::vector<clang::tooling::CompileCommand> getCompileCommands(llvm::StringRef FilePath) const override;
|
||||
virtual std::vector<std::string> getAllFiles() const override;
|
||||
virtual std::vector<clang::tooling::CompileCommand> getAllCompileCommands() const override;
|
||||
|
||||
private:
|
||||
clang::tooling::CompileCommand m_command;
|
||||
};
|
||||
|
||||
#endif // CXX_COMPILATION_DATABASE_SINGLE_H
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "data/parser/cxx/CxxDiagnosticConsumer.h"
|
||||
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
#include "data/parser/ParseLocation.h"
|
||||
#include "data/parser/ParserClient.h"
|
||||
#include "utility/file/FileRegister.h"
|
||||
|
||||
CxxDiagnosticConsumer::CxxDiagnosticConsumer(
|
||||
clang::raw_ostream &os,
|
||||
clang::DiagnosticOptions *diags,
|
||||
ParserClient* client,
|
||||
FileRegister* fileRegister,
|
||||
bool useLogging
|
||||
)
|
||||
: clang::TextDiagnosticPrinter(os, diags)
|
||||
, m_client(client)
|
||||
, m_register(fileRegister)
|
||||
, m_isParsingFile(false)
|
||||
, m_useLogging(useLogging)
|
||||
{
|
||||
}
|
||||
|
||||
void CxxDiagnosticConsumer::BeginSourceFile(const clang::LangOptions& langOptions, const clang::Preprocessor* preProcessor)
|
||||
{
|
||||
if (m_useLogging)
|
||||
{
|
||||
clang::TextDiagnosticPrinter::BeginSourceFile(langOptions, preProcessor);
|
||||
}
|
||||
|
||||
m_isParsingFile = true;
|
||||
}
|
||||
|
||||
void CxxDiagnosticConsumer::EndSourceFile()
|
||||
{
|
||||
if (m_useLogging)
|
||||
{
|
||||
clang::TextDiagnosticPrinter::EndSourceFile();
|
||||
}
|
||||
|
||||
m_isParsingFile = false;
|
||||
}
|
||||
|
||||
void CxxDiagnosticConsumer::HandleDiagnostic(clang::DiagnosticsEngine::Level level, const clang::Diagnostic& info)
|
||||
{
|
||||
if (m_useLogging)
|
||||
{
|
||||
clang::TextDiagnosticPrinter::HandleDiagnostic(level, info);
|
||||
}
|
||||
|
||||
if (!m_isParsingFile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (level >= clang::DiagnosticsEngine::Error)
|
||||
{
|
||||
llvm::SmallString<100> messageStr;
|
||||
info.FormatDiagnostic(messageStr);
|
||||
std::string message = messageStr.str();
|
||||
|
||||
if (message == "MS-style inline assembly is not available: Unable to find target for this triple (no targets are registered)")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string filePath;
|
||||
uint line = 0;
|
||||
uint column = 0;
|
||||
|
||||
if (info.getLocation().isValid() && info.hasSourceManager())
|
||||
{
|
||||
const clang::SourceManager& sourceManager = info.getSourceManager();
|
||||
clang::PresumedLoc presumedLocation = sourceManager.getPresumedLoc(info.getLocation());
|
||||
|
||||
filePath = clang::tooling::getAbsolutePath(presumedLocation.getFilename());
|
||||
line = presumedLocation.getLine();
|
||||
column = presumedLocation.getColumn();
|
||||
}
|
||||
|
||||
m_client->onError(
|
||||
ParseLocation(filePath, line, column),
|
||||
message,
|
||||
level == clang::DiagnosticsEngine::Fatal,
|
||||
m_register->hasFilePath(filePath)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef CXX_DIAGNOSTIC_CONSUMER
|
||||
#define CXX_DIAGNOSTIC_CONSUMER
|
||||
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
|
||||
class FileRegister;
|
||||
class ParserClient;
|
||||
|
||||
class CxxDiagnosticConsumer
|
||||
: public clang::TextDiagnosticPrinter
|
||||
{
|
||||
public:
|
||||
CxxDiagnosticConsumer(
|
||||
clang::raw_ostream &os,
|
||||
clang::DiagnosticOptions *diags,
|
||||
ParserClient* client,
|
||||
FileRegister* fileRegister,
|
||||
bool useLogging = true
|
||||
);
|
||||
|
||||
void BeginSourceFile(const clang::LangOptions& langOptions, const clang::Preprocessor* preProcessor);
|
||||
void EndSourceFile();
|
||||
|
||||
void HandleDiagnostic(clang::DiagnosticsEngine::Level level, const clang::Diagnostic& info);
|
||||
|
||||
private:
|
||||
ParserClient* m_client;
|
||||
FileRegister* m_register;
|
||||
|
||||
bool m_isParsingFile;
|
||||
bool m_useLogging;
|
||||
};
|
||||
|
||||
#endif // CXX_DIAGNOSTIC_CONSUMER
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "data/parser/cxx/CxxParser.h"
|
||||
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
#include "utility/file/FileRegister.h"
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/text/TextAccess.h"
|
||||
#include "utility/tracing.h"
|
||||
|
||||
#include "data/parser/cxx/ASTActionFactory.h"
|
||||
#include "data/parser/cxx/CxxCompilationDatabaseSingle.h"
|
||||
#include "data/parser/cxx/CxxDiagnosticConsumer.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
static std::vector<std::string> getSyntaxOnlyToolArgs(const std::vector<std::string> &ExtraArgs, llvm::StringRef FileName)
|
||||
{
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back("clang-tool");
|
||||
Args.push_back("-fsyntax-only");
|
||||
Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
|
||||
Args.push_back(FileName.str());
|
||||
return Args;
|
||||
}
|
||||
|
||||
// custom implementation of clang::runToolOnCodeWithArgs which also sets our custon DiagnosticConsumer
|
||||
static bool runToolOnCodeWithArgs(
|
||||
clang::DiagnosticConsumer* DiagConsumer,
|
||||
clang::FrontendAction *ToolAction,
|
||||
const llvm::Twine &Code,
|
||||
const std::vector<std::string> &Args,
|
||||
const llvm::Twine &FileName = "input.cc",
|
||||
const clang::tooling::FileContentMappings &VirtualMappedFiles = clang::tooling::FileContentMappings()
|
||||
)
|
||||
{
|
||||
llvm::SmallString<16> FileNameStorage;
|
||||
llvm::StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
|
||||
llvm::IntrusiveRefCntPtr<clang::FileManager> Files(new clang::FileManager(clang::FileSystemOptions()));
|
||||
clang::tooling::ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction, Files.get());
|
||||
|
||||
llvm::SmallString<1024> CodeStorage;
|
||||
Invocation.mapVirtualFile(FileNameRef, Code.toNullTerminatedStringRef(CodeStorage));
|
||||
|
||||
for (auto &FilenameWithContent : VirtualMappedFiles)
|
||||
{
|
||||
Invocation.mapVirtualFile(FilenameWithContent.first, FilenameWithContent.second);
|
||||
}
|
||||
|
||||
Invocation.setDiagnosticConsumer(DiagConsumer);
|
||||
|
||||
return Invocation.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CxxParser::CxxParser(ParserClient* client, std::shared_ptr<FileRegister> fileRegister)
|
||||
: Parser(client)
|
||||
, m_fileRegister(fileRegister)
|
||||
{
|
||||
}
|
||||
|
||||
CxxParser::~CxxParser()
|
||||
{
|
||||
}
|
||||
|
||||
void CxxParser::parseFiles(const std::vector<FilePath>& filePaths, const Arguments& arguments)
|
||||
{
|
||||
m_fileRegister->setFilePaths(filePaths);
|
||||
setupParsing(arguments);
|
||||
|
||||
std::vector<std::string> sourcePaths;
|
||||
for (const FilePath& path : m_fileRegister->getUnparsedSourceFilePaths()) // filter headers
|
||||
{
|
||||
sourcePaths.push_back(path.absolute().str());
|
||||
}
|
||||
|
||||
runTool(sourcePaths);
|
||||
}
|
||||
|
||||
void CxxParser::parseFile(const FilePath& filePath, std::shared_ptr<TextAccess> textAccess, const Arguments& arguments)
|
||||
{
|
||||
m_fileRegister->setFilePaths(std::vector<FilePath>(1, filePath));
|
||||
setupParsing(arguments);
|
||||
|
||||
std::vector<std::string> args = getCommandlineArguments(arguments);
|
||||
std::shared_ptr<CxxDiagnosticConsumer> diagnostics = getDiagnostics(arguments);
|
||||
|
||||
ASTActionFactory actionFactory(m_client, m_fileRegister.get());
|
||||
runToolOnCodeWithArgs(diagnostics.get(), actionFactory.create(), textAccess->getText(), args);
|
||||
}
|
||||
|
||||
std::vector<std::string> CxxParser::getCommandlineArgumentsEssential(const Arguments& arguments) const
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
|
||||
// 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 -fexceptions signals that clang should watch out for exception-related code during indexing.
|
||||
args.push_back("-fexceptions");
|
||||
|
||||
// The option -c signals that no executable is built.
|
||||
args.push_back("-c");
|
||||
|
||||
// The option -w disables all warnings.
|
||||
args.push_back("-w");
|
||||
|
||||
args.insert(args.begin(), arguments.compilerFlags.begin(), arguments.compilerFlags.end());
|
||||
|
||||
for (const FilePath& path : arguments.headerSearchPaths)
|
||||
{
|
||||
args.push_back("-I" + path.str());
|
||||
}
|
||||
|
||||
for (const FilePath& path : arguments.systemHeaderSearchPaths)
|
||||
{
|
||||
args.push_back("-isystem");
|
||||
args.push_back(path.str());
|
||||
}
|
||||
|
||||
for (const FilePath& path : arguments.frameworkSearchPaths)
|
||||
{
|
||||
args.push_back("-iframework");
|
||||
args.push_back(path.str());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
std::vector<std::string> CxxParser::getCommandlineArguments(const Arguments& arguments) const
|
||||
{
|
||||
std::vector<std::string> args = getCommandlineArgumentsEssential(arguments);
|
||||
|
||||
// Set language standard
|
||||
std::string standard = "-std=" + arguments.languageStandard;
|
||||
args.push_back(standard);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> CxxParser::getCompilationDatabase(
|
||||
const Arguments& arguments
|
||||
) const {
|
||||
// Commandline flags passed to the programm. Everything after '--' will be interpreted by the ClangTool.
|
||||
std::vector<std::string> args = getCommandlineArguments(arguments);
|
||||
args.insert(args.begin(), "app");
|
||||
args.insert(args.begin() + 1, "--");
|
||||
|
||||
int argc = args.size();
|
||||
const char** argv = new const char*[argc];
|
||||
for (size_t i = 0; i < args.size(); i++)
|
||||
{
|
||||
argv[i] = args[i].c_str();
|
||||
}
|
||||
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> compilationDatabase(
|
||||
clang::tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv)
|
||||
);
|
||||
|
||||
delete[] argv;
|
||||
|
||||
if (!compilationDatabase)
|
||||
{
|
||||
LOG_ERROR("Failed to load compilation database");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return compilationDatabase;
|
||||
}
|
||||
|
||||
std::shared_ptr<CxxDiagnosticConsumer> CxxParser::getDiagnostics(const Arguments& arguments) const
|
||||
{
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> options = new clang::DiagnosticOptions();
|
||||
return std::make_shared<CxxDiagnosticConsumer>(
|
||||
llvm::errs(), &*options, m_client, m_fileRegister.get(), arguments.logErrors);
|
||||
}
|
||||
|
||||
void CxxParser::setupParsing(const Arguments& arguments)
|
||||
{
|
||||
m_compilationDatabase = getCompilationDatabase(arguments);
|
||||
m_diagnostics = getDiagnostics(arguments);
|
||||
}
|
||||
|
||||
void CxxParser::setupParsingCDB(const Arguments& arguments)
|
||||
{
|
||||
m_diagnostics = getDiagnostics(arguments);
|
||||
}
|
||||
|
||||
void CxxParser::runTool(const std::vector<std::string>& files)
|
||||
{
|
||||
TRACE();
|
||||
|
||||
clang::tooling::ClangTool tool(*m_compilationDatabase, files);
|
||||
tool.setDiagnosticConsumer(m_diagnostics.get());
|
||||
|
||||
ASTActionFactory actionFactory(m_client, m_fileRegister.get());
|
||||
tool.run(&actionFactory);
|
||||
}
|
||||
|
||||
void CxxParser::runTool(clang::tooling::CompileCommand command, const Arguments& arguments)
|
||||
{
|
||||
TRACE();
|
||||
|
||||
std::vector<std::string> args = getCommandlineArgumentsEssential(arguments);
|
||||
command.CommandLine.insert(command.CommandLine.end(), args.begin(), args.end());
|
||||
|
||||
CxxCompilationDatabaseSingle compilationDatabase(command);
|
||||
clang::tooling::ClangTool tool(compilationDatabase, std::vector<std::string>(1, command.Filename));
|
||||
tool.setDiagnosticConsumer(m_diagnostics.get());
|
||||
|
||||
ASTActionFactory actionFactory(m_client, m_fileRegister.get());
|
||||
tool.run(&actionFactory);
|
||||
}
|
||||
|
||||
FileRegister* CxxParser::getFileRegister()
|
||||
{
|
||||
return m_fileRegister.get();
|
||||
}
|
||||
|
||||
ParserClient* CxxParser::getParserClient()
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef CXX_PARSER_H
|
||||
#define CXX_PARSER_H
|
||||
|
||||
#include "data/parser/cxx/CxxCompilationDatabaseSingle.h"
|
||||
#include "data/parser/Parser.h"
|
||||
|
||||
class CxxDiagnosticConsumer;
|
||||
class FileRegister;
|
||||
class FileRegister;
|
||||
class TaskParseCxx;
|
||||
|
||||
class CxxParser: public Parser
|
||||
{
|
||||
public:
|
||||
CxxParser(ParserClient* client, std::shared_ptr<FileRegister> fileRegister);
|
||||
~CxxParser();
|
||||
|
||||
// ParserClient implementation
|
||||
virtual void parseFiles(const std::vector<FilePath>& filePaths, const Arguments& arguments);
|
||||
virtual void parseFile(const FilePath& filePath, std::shared_ptr<TextAccess> textAccess, const Arguments& arguments);
|
||||
|
||||
private:
|
||||
std::vector<std::string> getCommandlineArgumentsEssential(const Arguments& arguments) const;
|
||||
std::vector<std::string> getCommandlineArguments(const Arguments& arguments) const;
|
||||
std::shared_ptr<clang::tooling::FixedCompilationDatabase> getCompilationDatabase(const Arguments& arguments) const;
|
||||
|
||||
std::shared_ptr<CxxDiagnosticConsumer> getDiagnostics(const Arguments& arguments) const;
|
||||
|
||||
// Accessed by TaskParseCxx
|
||||
void setupParsing(const Arguments& arguments);
|
||||
void setupParsingCDB(const Arguments& arguments);
|
||||
|
||||
void runTool(const std::vector<std::string>& files);
|
||||
void runTool(clang::tooling::CompileCommand command, const Arguments& arguments);
|
||||
|
||||
FileRegister* getFileRegister();
|
||||
ParserClient* getParserClient();
|
||||
|
||||
friend class TaskParseCxx;
|
||||
|
||||
std::shared_ptr<FileRegister> m_fileRegister;
|
||||
|
||||
std::shared_ptr<clang::tooling::CompilationDatabase> m_compilationDatabase;
|
||||
std::shared_ptr<CxxDiagnosticConsumer> m_diagnostics;
|
||||
};
|
||||
|
||||
#endif // CXX_PARSER_H
|
||||
@@ -0,0 +1,171 @@
|
||||
#include "data/parser/cxx/PreprocessorCallbacks.h"
|
||||
|
||||
#include "clang/Driver/Util.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Lex/MacroArgs.h"
|
||||
|
||||
#include "utility/file/FileRegister.h"
|
||||
|
||||
#include "data/parser/ParserClient.h"
|
||||
#include "data/parser/ParseLocation.h"
|
||||
|
||||
PreprocessorCallbacks::PreprocessorCallbacks(
|
||||
clang::SourceManager& sourceManager, ParserClient* client, FileRegister* fileRegister
|
||||
)
|
||||
: m_sourceManager(sourceManager)
|
||||
, m_client(client)
|
||||
, m_fileRegister(fileRegister)
|
||||
{
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::FileChanged(
|
||||
clang::SourceLocation location, FileChangeReason reason, clang::SrcMgr::CharacteristicKind, clang::FileID prevID)
|
||||
{
|
||||
FilePath filePath;
|
||||
|
||||
const clang::FileEntry *fileEntry = m_sourceManager.getFileEntryForID(m_sourceManager.getFileID(location));
|
||||
if (fileEntry)
|
||||
{
|
||||
filePath = FilePath(fileEntry->getName()).canonical();
|
||||
}
|
||||
|
||||
if (!filePath.empty() && m_fileRegister->hasFilePath(filePath) && !m_fileRegister->fileIsParsed(filePath))
|
||||
{
|
||||
m_currentPath = filePath;
|
||||
|
||||
if (reason == EnterFile && !m_fileRegister->includeFileIsParsed(filePath))
|
||||
{
|
||||
m_client->onFileParsed(m_fileRegister->getFileInfo(filePath));
|
||||
m_fileRegister->markIncludeFileParsing(filePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentPath = FilePath();
|
||||
}
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::InclusionDirective(
|
||||
clang::SourceLocation hashLocation, const clang::Token& includeToken, llvm::StringRef fileName, bool isAngled,
|
||||
clang::CharSourceRange fileNameRange, const clang::FileEntry* fileEntry, llvm::StringRef searchPath,
|
||||
llvm::StringRef relativePath, const clang::Module* imported
|
||||
){
|
||||
if (!m_currentPath.empty() && fileEntry)
|
||||
{
|
||||
FilePath includedFilePath = FilePath(fileEntry->getName()).canonical();
|
||||
if (m_fileRegister->hasFilePath(includedFilePath))
|
||||
{
|
||||
m_client->onFileIncludeParsed(
|
||||
getParseLocation(fileNameRange.getAsRange()),
|
||||
m_fileRegister->getFileInfo(m_currentPath),
|
||||
m_fileRegister->getFileInfo(includedFilePath)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::MacroDefined(const clang::Token& macroNameToken, const clang::MacroDirective* macroDirective)
|
||||
{
|
||||
if (!m_currentPath.empty())
|
||||
{
|
||||
// ignore builtin macros
|
||||
if (m_sourceManager.getSpellingLoc(macroNameToken.getLocation()).printToString(m_sourceManager)[0] == '<')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NameHierarchy nameHierarchy;
|
||||
nameHierarchy.push(std::make_shared<NameElement>(macroNameToken.getIdentifierInfo()->getName().str()));
|
||||
|
||||
m_client->onMacroDefineParsed(
|
||||
getParseLocation(macroNameToken), nameHierarchy, getParseLocation(macroDirective->getMacroInfo()));
|
||||
}
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::MacroUndefined(
|
||||
const clang::Token& macroNameToken, const clang::MacroDefinition& macroDefinition)
|
||||
{
|
||||
onMacroUsage(macroNameToken);
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::Defined(
|
||||
const clang::Token& macroNameToken, const clang::MacroDefinition& macroDefinition, clang::SourceRange range)
|
||||
{
|
||||
onMacroUsage(macroNameToken);
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::Ifdef(clang::SourceLocation location, const clang::Token& macroNameToken,
|
||||
const clang::MacroDefinition& macroDefinition)
|
||||
{
|
||||
onMacroUsage(macroNameToken);
|
||||
}
|
||||
void PreprocessorCallbacks::Ifndef(clang::SourceLocation location, const clang::Token& macroNameToken,
|
||||
const clang::MacroDefinition& macroDefinition)
|
||||
{
|
||||
onMacroUsage(macroNameToken);
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::MacroExpands(
|
||||
const clang::Token& macroNameToken, const clang::MacroDefinition& macroDirective,
|
||||
clang::SourceRange range, const clang::MacroArgs* args
|
||||
){
|
||||
onMacroUsage(macroNameToken);
|
||||
}
|
||||
|
||||
void PreprocessorCallbacks::onMacroUsage(const clang::Token& macroNameToken)
|
||||
{
|
||||
if (!m_currentPath.empty())
|
||||
{
|
||||
NameHierarchy nameHierarchy;
|
||||
nameHierarchy.push(std::make_shared<NameElement>(macroNameToken.getIdentifierInfo()->getName().str()));
|
||||
|
||||
m_client->onMacroExpandParsed(getParseLocation(macroNameToken), nameHierarchy);
|
||||
}
|
||||
}
|
||||
|
||||
ParseLocation PreprocessorCallbacks::getParseLocation(const clang::Token& macroNameTok) const
|
||||
{
|
||||
const clang::SourceLocation& location = m_sourceManager.getSpellingLoc(macroNameTok.getLocation());
|
||||
const clang::SourceLocation& endLocation = m_sourceManager.getSpellingLoc(macroNameTok.getEndLoc());
|
||||
|
||||
return ParseLocation(
|
||||
m_sourceManager.getFilename(location),
|
||||
m_sourceManager.getSpellingLineNumber(location),
|
||||
m_sourceManager.getSpellingColumnNumber(location),
|
||||
m_sourceManager.getSpellingLineNumber(endLocation),
|
||||
m_sourceManager.getSpellingColumnNumber(endLocation) - 1
|
||||
);
|
||||
}
|
||||
|
||||
ParseLocation PreprocessorCallbacks::getParseLocation(const clang::MacroInfo* macroInfo) const
|
||||
{
|
||||
clang::SourceLocation location = macroInfo->getDefinitionLoc();
|
||||
clang::SourceLocation endLocation = macroInfo->getDefinitionEndLoc();
|
||||
|
||||
return ParseLocation(
|
||||
m_sourceManager.getFilename(location),
|
||||
m_sourceManager.getSpellingLineNumber(location),
|
||||
m_sourceManager.getSpellingColumnNumber(location),
|
||||
m_sourceManager.getSpellingLineNumber(endLocation),
|
||||
m_sourceManager.getSpellingColumnNumber(endLocation) - 1
|
||||
);
|
||||
}
|
||||
|
||||
ParseLocation PreprocessorCallbacks::getParseLocation(const clang::SourceRange& sourceRange) const
|
||||
{
|
||||
if (sourceRange.isInvalid())
|
||||
{
|
||||
return ParseLocation();
|
||||
}
|
||||
|
||||
const clang::PresumedLoc& presumedBegin = m_sourceManager.getPresumedLoc(sourceRange.getBegin(), false);
|
||||
const clang::PresumedLoc& presumedEnd = m_sourceManager.getPresumedLoc(sourceRange.getEnd(), false);
|
||||
|
||||
return ParseLocation(
|
||||
presumedBegin.getFilename(),
|
||||
presumedBegin.getLine(),
|
||||
presumedBegin.getColumn(),
|
||||
presumedEnd.getLine(),
|
||||
presumedEnd.getColumn() - 1
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef PREPROCESSOR_CALLBACKS_H
|
||||
#define PREPROCESSOR_CALLBACKS_H
|
||||
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
|
||||
#include "utility/file/FilePath.h"
|
||||
|
||||
class FileRegister;
|
||||
class ParserClient;
|
||||
|
||||
struct ParseLocation;
|
||||
|
||||
class PreprocessorCallbacks
|
||||
: public clang::PPCallbacks
|
||||
{
|
||||
public:
|
||||
explicit PreprocessorCallbacks(clang::SourceManager& sourceManager, ParserClient* client, FileRegister* fileRegister);
|
||||
|
||||
virtual void FileChanged(
|
||||
clang::SourceLocation location, FileChangeReason reason, clang::SrcMgr::CharacteristicKind, clang::FileID);
|
||||
|
||||
virtual void InclusionDirective(
|
||||
clang::SourceLocation hashLocation, const clang::Token& includeToken, llvm::StringRef fileName, bool isAngled,
|
||||
clang::CharSourceRange fileNameRange, const clang::FileEntry* fileEntry, llvm::StringRef searchPath,
|
||||
llvm::StringRef relativePath, const clang::Module* imported);
|
||||
|
||||
virtual void MacroDefined(const clang::Token& macroNameToken, const clang::MacroDirective* macroDirective);
|
||||
virtual void MacroUndefined(const clang::Token& macroNameToken, const clang::MacroDefinition& macroDefinition);
|
||||
|
||||
virtual void Defined(
|
||||
const clang::Token& macroNameToken, const clang::MacroDefinition& macroDefinition, clang::SourceRange range);
|
||||
virtual void Ifdef(clang::SourceLocation location, const clang::Token& macroNameToken,
|
||||
const clang::MacroDefinition& macroDefinition);
|
||||
virtual void Ifndef(clang::SourceLocation location, const clang::Token& macroNameToken,
|
||||
const clang::MacroDefinition& macroDefinition);
|
||||
|
||||
virtual void MacroExpands(
|
||||
const clang::Token& macroNameToken, const clang::MacroDefinition& macroDirective,
|
||||
clang::SourceRange range, const clang::MacroArgs* args
|
||||
);
|
||||
|
||||
private:
|
||||
void onMacroUsage(const clang::Token& macroNameToken);
|
||||
|
||||
ParseLocation getParseLocation(const clang::Token& macroNameToc) const;
|
||||
ParseLocation getParseLocation(const clang::MacroInfo* macroNameToc) const;
|
||||
ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const;
|
||||
|
||||
const clang::SourceManager& m_sourceManager;
|
||||
ParserClient* m_client;
|
||||
FileRegister* m_fileRegister;
|
||||
|
||||
FilePath m_currentPath;
|
||||
};
|
||||
|
||||
#endif // PREPROCESSOR_CALLBACKS_H
|
||||
@@ -0,0 +1,138 @@
|
||||
#include "data/parser/cxx/TaskParseCxx.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "clang/Tooling/JSONCompilationDatabase.h"
|
||||
|
||||
#include "component/view/DialogView.h"
|
||||
#include "data/parser/cxx/CxxParser.h"
|
||||
#include "data/StorageProvider.h"
|
||||
#include "utility/file/FileRegister.h"
|
||||
#include "utility/scheduling/Blackboard.h"
|
||||
#include "utility/utility.h"
|
||||
|
||||
std::vector<FilePath> TaskParseCxx::getSourceFilesFromCDB(const FilePath& compilationDatabasePath)
|
||||
{
|
||||
std::string error;
|
||||
std::shared_ptr<clang::tooling::JSONCompilationDatabase> cdb = std::shared_ptr<clang::tooling::JSONCompilationDatabase>
|
||||
(clang::tooling::JSONCompilationDatabase::loadFromFile(compilationDatabasePath.str(), error));
|
||||
|
||||
std::vector<FilePath> filePaths;
|
||||
if (cdb)
|
||||
{
|
||||
std::vector<std::string> files = cdb->getAllFiles();
|
||||
for (const std::string& file : files)
|
||||
{
|
||||
filePaths.push_back(FilePath(file));
|
||||
}
|
||||
}
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
TaskParseCxx::TaskParseCxx(
|
||||
std::shared_ptr<StorageProvider> storageProvider,
|
||||
std::shared_ptr<FileRegister> fileRegister,
|
||||
const Parser::Arguments& arguments,
|
||||
DialogView* dialogView
|
||||
)
|
||||
: m_storageProvider(storageProvider)
|
||||
, m_arguments(arguments)
|
||||
, m_dialogView(dialogView)
|
||||
, m_isCDB(false)
|
||||
, m_interrupted(false)
|
||||
{
|
||||
if (arguments.compilationDatabasePath.exists())
|
||||
{
|
||||
m_isCDB = true;
|
||||
}
|
||||
m_parserClient = std::make_shared<ParserClientImpl>(); // todo: create one parserclient per file
|
||||
m_parser = std::make_shared<CxxParser>(m_parserClient.get(), fileRegister);
|
||||
}
|
||||
|
||||
void TaskParseCxx::doEnter(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
int indexerCount = 0;
|
||||
if (blackboard->get("indexer_count", indexerCount))
|
||||
{
|
||||
indexerCount++;
|
||||
blackboard->set("indexer_count", indexerCount);
|
||||
}
|
||||
|
||||
if (m_isCDB)
|
||||
{
|
||||
std::string error;
|
||||
m_cdb = std::shared_ptr<clang::tooling::JSONCompilationDatabase>
|
||||
(clang::tooling::JSONCompilationDatabase::loadFromFile(m_arguments.compilationDatabasePath.str(), error));
|
||||
|
||||
m_parser->setupParsingCDB(m_arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_parser->setupParsing(m_arguments);
|
||||
}
|
||||
}
|
||||
|
||||
Task::TaskState TaskParseCxx::doUpdate(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
FileRegister* fileRegister = m_parser->getFileRegister();
|
||||
|
||||
FilePath sourcePath = fileRegister->consumeSourceFile();
|
||||
|
||||
if (sourcePath.empty())
|
||||
{
|
||||
return STATE_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dialogView->updateIndexingDialog(
|
||||
fileRegister->getParsedSourceFilesCount(), fileRegister->getSourceFilesCount(), sourcePath.str()
|
||||
);
|
||||
|
||||
std::shared_ptr<IntermediateStorage> storage = m_storageProvider->popIndexerTarget();
|
||||
m_parserClient->setStorage(storage);
|
||||
m_parserClient->startParsingFile();
|
||||
|
||||
if (m_isCDB)
|
||||
{
|
||||
std::vector<clang::tooling::CompileCommand> commands = m_cdb->getCompileCommands(sourcePath.str());
|
||||
if (commands.size() > 0)
|
||||
{
|
||||
m_parser->runTool(commands[0], m_arguments);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_parser->runTool(std::vector<std::string>(1, sourcePath.str()));
|
||||
}
|
||||
|
||||
m_parserClient->finishParsingFile();
|
||||
m_parserClient->resetStorage();
|
||||
|
||||
if (!m_interrupted)
|
||||
{
|
||||
fileRegister->markThreadFilesParsed();
|
||||
m_storageProvider->pushIndexerTarget(storage);
|
||||
}
|
||||
}
|
||||
|
||||
return (m_interrupted ? STATE_FAILURE : STATE_SUCCESS);
|
||||
}
|
||||
|
||||
void TaskParseCxx::doExit(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
int indexerCount = 0;
|
||||
if (blackboard->get("indexer_count", indexerCount))
|
||||
{
|
||||
indexerCount--;
|
||||
blackboard->set("indexer_count", indexerCount);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskParseCxx::doReset(std::shared_ptr<Blackboard> blackboard)
|
||||
{
|
||||
}
|
||||
|
||||
void TaskParseCxx::handleMessage(MessageInterruptTasks* message)
|
||||
{
|
||||
m_interrupted = true;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef TASK_PARSE_CXX_H
|
||||
#define TASK_PARSE_CXX_H
|
||||
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
|
||||
#include "data/parser/Parser.h"
|
||||
#include "data/parser/ParserClientImpl.h"
|
||||
#include "utility/scheduling/Task.h"
|
||||
#include "utility/TimePoint.h"
|
||||
#include "utility/messaging/type/MessageInterruptTasks.h"
|
||||
#include "utility/messaging/MessageListener.h"
|
||||
|
||||
class CxxParser;
|
||||
class DialogView;
|
||||
class FileRegister;
|
||||
class StorageProvider;
|
||||
|
||||
namespace clang
|
||||
{
|
||||
namespace tooling
|
||||
{
|
||||
class JSONCompilationDatabase;
|
||||
}
|
||||
}
|
||||
|
||||
class TaskParseCxx
|
||||
: public Task
|
||||
, public MessageListener<MessageInterruptTasks>
|
||||
{
|
||||
public:
|
||||
static std::vector<FilePath> getSourceFilesFromCDB(const FilePath& compilationDatabasePath);
|
||||
|
||||
TaskParseCxx(
|
||||
std::shared_ptr<StorageProvider> storageProvider,
|
||||
std::shared_ptr<FileRegister> fileRegister,
|
||||
const Parser::Arguments& arguments,
|
||||
DialogView* dialogView
|
||||
);
|
||||
|
||||
private:
|
||||
virtual void doEnter(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual TaskState doUpdate(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doExit(std::shared_ptr<Blackboard> blackboard);
|
||||
virtual void doReset(std::shared_ptr<Blackboard> blackboard);
|
||||
|
||||
virtual void handleMessage(MessageInterruptTasks* message);
|
||||
|
||||
std::shared_ptr<StorageProvider> m_storageProvider;
|
||||
|
||||
const Parser::Arguments m_arguments;
|
||||
DialogView* m_dialogView;
|
||||
|
||||
std::shared_ptr<CxxParser> m_parser;
|
||||
std::shared_ptr<ParserClientImpl> m_parserClient;
|
||||
|
||||
bool m_isCDB;
|
||||
std::shared_ptr<clang::tooling::JSONCompilationDatabase> m_cdb;
|
||||
|
||||
bool m_interrupted;
|
||||
};
|
||||
|
||||
#endif // TASK_PARSE_CXX_H
|
||||
@@ -0,0 +1,384 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
|
||||
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
#include <clang/AST/ASTContext.h>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "utility/file/FilePath.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
CxxDeclNameResolver::CxxDeclNameResolver(const clang::Decl* declaration)
|
||||
: CxxNameResolver(std::vector<const clang::Decl*>())
|
||||
{
|
||||
const clang::Decl* prev = declaration;
|
||||
while (prev)
|
||||
{
|
||||
m_declaration = prev;
|
||||
prev = prev->getPreviousDecl();
|
||||
}
|
||||
}
|
||||
|
||||
CxxDeclNameResolver::CxxDeclNameResolver(const clang::Decl* declaration, std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: CxxNameResolver(ignoredContextDecls)
|
||||
{
|
||||
const clang::Decl* prev = declaration;
|
||||
while (prev)
|
||||
{
|
||||
m_declaration = prev;
|
||||
prev = prev->getPreviousDecl();
|
||||
}
|
||||
}
|
||||
|
||||
CxxDeclNameResolver::~CxxDeclNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy()
|
||||
{
|
||||
NameHierarchy contextNameHierarchy;
|
||||
if (m_declaration)
|
||||
{
|
||||
std::shared_ptr<NameElement> declName;
|
||||
|
||||
if (clang::isa<clang::NamedDecl>(m_declaration))
|
||||
{
|
||||
declName = getDeclName(clang::dyn_cast<const clang::NamedDecl>(m_declaration));
|
||||
}
|
||||
else
|
||||
{
|
||||
// LOG_ERROR("unhandled declaration type: " + std::string(m_declaration->getDeclKindName()));
|
||||
}
|
||||
|
||||
contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext());
|
||||
|
||||
if (declName)
|
||||
{
|
||||
contextNameHierarchy.push(declName);
|
||||
}
|
||||
}
|
||||
return contextNameHierarchy;
|
||||
}
|
||||
|
||||
NameHierarchy CxxDeclNameResolver::getContextNameHierarchy(const clang::DeclContext* declContext)
|
||||
{
|
||||
NameHierarchy contextNameHierarchy;
|
||||
|
||||
if (declContext && !ignoresContext(declContext))
|
||||
{
|
||||
const clang::DeclContext* parentContext = declContext->getParent();
|
||||
if (parentContext)
|
||||
{
|
||||
contextNameHierarchy = getContextNameHierarchy(parentContext);
|
||||
}
|
||||
|
||||
if (const clang::NamedDecl* contextNamedDecl = clang::dyn_cast_or_null<clang::NamedDecl>(declContext))
|
||||
{
|
||||
std::shared_ptr<NameElement> declName = getDeclName(contextNamedDecl);
|
||||
if (declName)
|
||||
{
|
||||
contextNameHierarchy.push(declName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return contextNameHierarchy;
|
||||
}
|
||||
|
||||
std::shared_ptr<NameElement> CxxDeclNameResolver::getDeclName()
|
||||
{
|
||||
const clang::NamedDecl* declaration = clang::dyn_cast<clang::NamedDecl>(m_declaration);
|
||||
std::string declNameString = declaration->getNameAsString();
|
||||
if (const clang::TypeAliasDecl* typeAliasDecl = clang::dyn_cast_or_null<clang::TypeAliasDecl>(declaration))
|
||||
{
|
||||
clang::TypeAliasTemplateDecl* templatedDeclaration = typeAliasDecl->getDescribedAliasTemplate();
|
||||
if (templatedDeclaration)
|
||||
{
|
||||
return getDeclName(templatedDeclaration);
|
||||
}
|
||||
}
|
||||
if (const clang::CXXRecordDecl* recordDecl = clang::dyn_cast_or_null<clang::CXXRecordDecl>(declaration))
|
||||
{
|
||||
clang::ClassTemplateDecl* templateClassDeclaration = recordDecl->getDescribedClassTemplate();
|
||||
if (templateClassDeclaration)
|
||||
{
|
||||
return getDeclName(templateClassDeclaration);
|
||||
}
|
||||
else if (clang::isa<clang::ClassTemplatePartialSpecializationDecl>(declaration))
|
||||
{
|
||||
const clang::ClassTemplatePartialSpecializationDecl* partialSpecializationDecl =
|
||||
clang::dyn_cast<clang::ClassTemplatePartialSpecializationDecl>(declaration);
|
||||
|
||||
clang::TemplateParameterList* parameterList = partialSpecializationDecl->getTemplateParameters();
|
||||
unsigned int currentParameterIndex = 0;
|
||||
|
||||
std::string specializedParameterNamePart = "<";
|
||||
int templateArgumentCount = partialSpecializationDecl->getTemplateArgs().size();
|
||||
const clang::TemplateArgumentList& templateArgumentList = partialSpecializationDecl->getTemplateArgs();
|
||||
for (int i = 0; i < templateArgumentCount; i++)
|
||||
{
|
||||
const clang::TemplateArgument& templateArgument = templateArgumentList.get(i);
|
||||
if (templateArgument.isDependent()) // IMPORTANT_TODO: fix case when arg depends on template parameter of outer template class, or depends on first template parameter.
|
||||
{
|
||||
if(currentParameterIndex < parameterList->size())
|
||||
{
|
||||
specializedParameterNamePart += getTemplateParameterString(parameterList->getParam(currentParameterIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
//this if fixes the crash, but not the problem TODO
|
||||
// const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
// LOG_ERROR("Template getParam out of Range " + declaration->getLocation().printToString(sourceManager));
|
||||
}
|
||||
currentParameterIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
specializedParameterNamePart += getTemplateArgumentName(templateArgument);
|
||||
}
|
||||
specializedParameterNamePart += (i < templateArgumentCount - 1) ? ", " : "";
|
||||
}
|
||||
specializedParameterNamePart += ">";
|
||||
return std::make_shared<NameElement>(declNameString + specializedParameterNamePart);
|
||||
}
|
||||
else if (clang::isa<clang::ClassTemplateSpecializationDecl>(declaration))
|
||||
{
|
||||
std::string templateArgumentNamePart = "<";
|
||||
const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(declaration)->getTemplateArgs();
|
||||
for (size_t i = 0; i < templateArgumentList.size(); i++)
|
||||
{
|
||||
templateArgumentNamePart += getTemplateArgumentName(templateArgumentList.get(i));
|
||||
templateArgumentNamePart += (i < templateArgumentList.size() - 1) ? ", " : "";
|
||||
}
|
||||
templateArgumentNamePart += ">";
|
||||
return std::make_shared<NameElement>(declNameString + templateArgumentNamePart);
|
||||
}
|
||||
else if (recordDecl->isLambda())
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(recordDecl->getLocStart());
|
||||
std::string lambdaName = "lambda at " + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn());
|
||||
return std::make_shared<NameElement>(lambdaName, NameElement::Signature("void", "()"));
|
||||
}
|
||||
else if (declNameString.size() == 0)
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
const std::string recordType = (recordDecl->isStruct() ? "struct" : "class");
|
||||
return std::make_shared<NameElement>("anonymous " + recordType + " (" + FilePath(presumedBegin.getFilename()).fileName() + ")");
|
||||
}
|
||||
}
|
||||
else if (clang::isa<clang::FunctionDecl>(declaration))
|
||||
{
|
||||
if (const clang::CXXMethodDecl* methodDecl = clang::dyn_cast_or_null<clang::CXXMethodDecl>(declaration))
|
||||
{
|
||||
if (methodDecl->getParent()->isLambda())
|
||||
{
|
||||
// return empty pointer since lambdas will be handled at the level of the parent class... not optimal.
|
||||
return std::shared_ptr<NameElement>();
|
||||
}
|
||||
}
|
||||
|
||||
std::string functionName;
|
||||
|
||||
const clang::FunctionDecl* functionDecl = clang::dyn_cast<clang::FunctionDecl>(declaration);
|
||||
if (clang::FunctionTemplateDecl* templateFunctionDeclaration = functionDecl->getDescribedFunctionTemplate())
|
||||
{
|
||||
functionName = getDeclName(templateFunctionDeclaration)->getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
functionName = declNameString;
|
||||
if (functionDecl->isFunctionTemplateSpecialization())
|
||||
{
|
||||
std::string templateArgumentNamePart = "<";
|
||||
const clang::TemplateArgumentList* templateArgumentList = functionDecl->getTemplateSpecializationArgs();
|
||||
for (size_t i = 0; i < templateArgumentList->size(); i++)
|
||||
{
|
||||
const clang::TemplateArgument& templateArgument = templateArgumentList->get(i);
|
||||
templateArgumentNamePart += getTemplateArgumentName(templateArgument);
|
||||
templateArgumentNamePart += (i < templateArgumentList->size() - 1) ? ", " : "";
|
||||
}
|
||||
templateArgumentNamePart += ">";
|
||||
functionName += templateArgumentNamePart;
|
||||
}
|
||||
}
|
||||
|
||||
bool isStatic = false;
|
||||
bool isConst = false;
|
||||
|
||||
if (clang::isa<clang::CXXMethodDecl>(declaration))
|
||||
{
|
||||
const clang::CXXMethodDecl* methodDecl = clang::dyn_cast<const clang::CXXMethodDecl>(declaration);
|
||||
isStatic = methodDecl->isStatic();
|
||||
isConst = methodDecl->isConst();
|
||||
}
|
||||
else
|
||||
{
|
||||
isStatic = functionDecl->getStorageClass() == clang::SC_Static;
|
||||
}
|
||||
|
||||
CxxTypeNameResolver typenNameResolver(getIgnoredContextDecls());
|
||||
typenNameResolver.ignoreContextDecl(functionDecl);
|
||||
std::string returnTypeString = typenNameResolver.qualTypeToDataType(functionDecl->getReturnType())->getFullTypeName();
|
||||
|
||||
std::string parameterString = "(";
|
||||
for (unsigned int i = 0; i < functionDecl->param_size(); i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
parameterString += ", ";
|
||||
}
|
||||
parameterString += typenNameResolver.qualTypeToDataType(functionDecl->parameters()[i]->getType())->getFullTypeName();
|
||||
}
|
||||
parameterString += ")";
|
||||
|
||||
return std::make_shared<NameElement>(
|
||||
functionName,
|
||||
NameElement::Signature((isStatic ? "static " : "") + returnTypeString, parameterString + (isConst ? " const" : "")));
|
||||
}
|
||||
else if (clang::isa<clang::TemplateDecl>(declaration)) // also triggers on TemplateTemplateParmDecl
|
||||
{
|
||||
std::string templateParameterNamePart = "<";
|
||||
clang::TemplateParameterList* parameterList = clang::dyn_cast<clang::TemplateDecl>(declaration)->getTemplateParameters();
|
||||
for (size_t i = 0; i < parameterList->size(); i++)
|
||||
{
|
||||
templateParameterNamePart += getTemplateParameterString(parameterList->getParam(i));
|
||||
templateParameterNamePart += (i < parameterList->size() - 1) ? ", " : "";
|
||||
}
|
||||
templateParameterNamePart += ">";
|
||||
return std::make_shared<NameElement>(declNameString + templateParameterNamePart);
|
||||
}
|
||||
else if (clang::isa<clang::NamespaceDecl>(declaration) && clang::dyn_cast<clang::NamespaceDecl>(declaration)->isAnonymousNamespace())
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
return std::make_shared<NameElement>("anonymous namespace (" + FilePath(presumedBegin.getFilename()).fileName() + ")");
|
||||
}
|
||||
else if (clang::isa<clang::EnumDecl>(declaration) && declNameString.size() == 0)
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
return std::make_shared<NameElement>("anonymous enum (" + FilePath(presumedBegin.getFilename()).fileName() + ")");
|
||||
}
|
||||
else if (
|
||||
(
|
||||
clang::isa<clang::TemplateTypeParmDecl>(declaration) ||
|
||||
clang::isa<clang::NonTypeTemplateParmDecl>(declaration) ||
|
||||
clang::isa<clang::TemplateTemplateParmDecl>(declaration)
|
||||
) && declNameString.size() == 0)
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
return std::make_shared<NameElement>("anonymous template parameter (" + FilePath(presumedBegin.getFilename()).fileName() + ")");
|
||||
}
|
||||
else if (clang::isa<clang::ParmVarDecl>(declaration) && declNameString.size() == 0)
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
return std::make_shared<NameElement>("anonymous parameter (" + FilePath(presumedBegin.getFilename()).fileName() + ")");
|
||||
}
|
||||
|
||||
if (declNameString.size() > 0)
|
||||
{
|
||||
return std::make_shared<NameElement>(declNameString);
|
||||
}
|
||||
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
// LOG_ERROR("could not resolve name of decl at: " + declaration->getLocation().printToString(sourceManager));
|
||||
return std::make_shared<NameElement>("anonymous symbol (" + FilePath(presumedBegin.getFilename()).fileName() + ")");
|
||||
}
|
||||
|
||||
std::shared_ptr<NameElement> CxxDeclNameResolver::getDeclName(const clang::NamedDecl* declaration)
|
||||
{
|
||||
CxxDeclNameResolver resolver(declaration);
|
||||
return resolver.getDeclName();
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getTemplateParameterString(const clang::NamedDecl* parameter)
|
||||
{
|
||||
std::string templateParameterTypeString = "";
|
||||
|
||||
clang::Decl::Kind templateParameterKind = parameter->getKind();
|
||||
switch (templateParameterKind)
|
||||
{
|
||||
case clang::Decl::NonTypeTemplateParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::NonTypeTemplateParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTypeParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTypeParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTemplateParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTemplateParmDecl>(parameter));
|
||||
break;
|
||||
default:
|
||||
// LOG_ERROR("Unhandled kind of template parameter.");
|
||||
break;
|
||||
}
|
||||
|
||||
std::string parameterName = parameter->getName();
|
||||
if (!parameterName.empty())
|
||||
{
|
||||
templateParameterTypeString += " " + parameterName;
|
||||
}
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter)
|
||||
{
|
||||
CxxTypeNameResolver typeNameResolver(getIgnoredContextDecls());
|
||||
|
||||
if (clang::isa<clang::TemplateDecl>(m_declaration))
|
||||
{
|
||||
typeNameResolver.ignoreContextDecl(clang::dyn_cast<clang::TemplateDecl>(m_declaration)->getTemplatedDecl());
|
||||
}
|
||||
else // works for partial template specializations
|
||||
{
|
||||
typeNameResolver.ignoreContextDecl(m_declaration);
|
||||
}
|
||||
|
||||
std::string typeString = typeNameResolver.qualTypeToDataType(parameter->getType())->getFullTypeName();
|
||||
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
typeString += "...";
|
||||
}
|
||||
|
||||
return typeString;
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter)
|
||||
{
|
||||
std::string typeString = (parameter->wasDeclaredWithTypename() ? "typename" : "class");
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
typeString += "...";
|
||||
}
|
||||
return typeString;
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter)
|
||||
{
|
||||
std::string templateParameterTypeString = "template<";
|
||||
clang::TemplateParameterList* parameterList = parameter->getTemplateParameters();
|
||||
for (size_t i = 0; i < parameterList->size(); i++)
|
||||
{
|
||||
templateParameterTypeString += getTemplateParameterString(parameterList->getParam(i));
|
||||
templateParameterTypeString += (i < parameterList->size() - 1) ? ", " : "";
|
||||
}
|
||||
templateParameterTypeString += ">";
|
||||
templateParameterTypeString += " typename"; // TODO: what if template template parameter is defined with class keyword?
|
||||
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
templateParameterTypeString += "...";
|
||||
}
|
||||
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
|
||||
{
|
||||
CxxTemplateArgumentNameResolver resolver(getIgnoredContextDecls());
|
||||
return resolver.getTemplateArgumentName(argument);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef CXX_DECL_NAME_RESOLVER_H
|
||||
#define CXX_DECL_NAME_RESOLVER_H
|
||||
|
||||
#include "data/name/NameHierarchy.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
|
||||
class CxxDeclNameResolver: public CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxDeclNameResolver(const clang::Decl* declaration);
|
||||
CxxDeclNameResolver(const clang::Decl* declaration, std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
virtual ~CxxDeclNameResolver();
|
||||
|
||||
NameHierarchy getDeclNameHierarchy();
|
||||
std::shared_ptr<NameElement> getDeclName();
|
||||
|
||||
private:
|
||||
NameHierarchy getContextNameHierarchy(const clang::DeclContext* declaration);
|
||||
std::shared_ptr<NameElement> getDeclName(const clang::NamedDecl* declaration);
|
||||
std::string getTemplateParameterString(const clang::NamedDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter);
|
||||
std::string getTemplateArgumentName(const clang::TemplateArgument& argument);
|
||||
|
||||
const clang::Decl* m_declaration;
|
||||
};
|
||||
|
||||
#endif // CXX_DECL_NAME_RESOLVER_H
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
|
||||
CxxNameResolver::CxxNameResolver(std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: m_ignoredContextDecls(ignoredContextDecls)
|
||||
{
|
||||
}
|
||||
|
||||
CxxNameResolver::~CxxNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
void CxxNameResolver::ignoreContextDecl(const clang::Decl* decl)
|
||||
{
|
||||
m_ignoredContextDecls.push_back(decl);
|
||||
}
|
||||
|
||||
bool CxxNameResolver::ignoresContext(const clang::DeclContext* declContext)
|
||||
{
|
||||
const clang::Decl* decl = clang::dyn_cast<clang::Decl>(declContext);
|
||||
for (size_t i = 0; i < m_ignoredContextDecls.size(); i++)
|
||||
{
|
||||
if (decl == m_ignoredContextDecls[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const clang::Decl*> CxxNameResolver::getIgnoredContextDecls() const
|
||||
{
|
||||
return m_ignoredContextDecls;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef CXX_NAME_RESOLVER_H
|
||||
#define CXX_NAME_RESOLVER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
|
||||
class CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxNameResolver(std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
virtual ~CxxNameResolver();
|
||||
|
||||
void ignoreContextDecl(const clang::Decl* decl);
|
||||
bool ignoresContext(const clang::DeclContext* declContext);
|
||||
|
||||
protected:
|
||||
std::vector<const clang::Decl*> getIgnoredContextDecls() const;
|
||||
|
||||
private:
|
||||
std::vector<const clang::Decl*> m_ignoredContextDecls;
|
||||
};
|
||||
|
||||
#endif // CXX_NAME_RESOLVER_H
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
|
||||
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "data/type/NamedDataType.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
CxxTemplateArgumentNameResolver::CxxTemplateArgumentNameResolver()
|
||||
: CxxNameResolver(std::vector<const clang::Decl*>())
|
||||
{
|
||||
}
|
||||
|
||||
CxxTemplateArgumentNameResolver::CxxTemplateArgumentNameResolver(std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: CxxNameResolver(ignoredContextDecls)
|
||||
{
|
||||
}
|
||||
|
||||
CxxTemplateArgumentNameResolver::~CxxTemplateArgumentNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::string CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
|
||||
{
|
||||
// This doesn't work correctly if the template argument is dependent.
|
||||
// If that's required: build name from depth and index of template arg.
|
||||
const clang::TemplateArgument::ArgKind kind = argument.getKind();
|
||||
switch (kind)
|
||||
{
|
||||
case clang::TemplateArgument::Type:
|
||||
{
|
||||
CxxTypeNameResolver typeNameResolver(getIgnoredContextDecls());
|
||||
return typeNameResolver.qualTypeToDataType(argument.getAsType())->getFullTypeName();
|
||||
}
|
||||
case clang::TemplateArgument::Integral:
|
||||
case clang::TemplateArgument::Null:
|
||||
case clang::TemplateArgument::Declaration:
|
||||
case clang::TemplateArgument::NullPtr:
|
||||
case clang::TemplateArgument::Template:
|
||||
case clang::TemplateArgument::TemplateExpansion: // handled correctly? template template parameter...
|
||||
case clang::TemplateArgument::Expression:
|
||||
{
|
||||
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 buf;
|
||||
llvm::raw_string_ostream os(buf);
|
||||
argument.print(pp, os);
|
||||
const std::string typeName = os.str();
|
||||
|
||||
return typeName;
|
||||
}
|
||||
case clang::TemplateArgument::Pack:
|
||||
{
|
||||
std::string typeName = "<";
|
||||
argument.getPackAsArray();
|
||||
llvm::ArrayRef<clang::TemplateArgument> pack = argument.getPackAsArray();
|
||||
for (size_t i = 0; i < pack.size(); i++)
|
||||
{
|
||||
typeName += getTemplateArgumentName(pack[i]);
|
||||
if (i < pack.size() - 1)
|
||||
{
|
||||
typeName += ", ";
|
||||
}
|
||||
}
|
||||
typeName += ">";
|
||||
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H
|
||||
#define CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
|
||||
class DataType;
|
||||
|
||||
class CxxTemplateArgumentNameResolver: public CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxTemplateArgumentNameResolver();
|
||||
CxxTemplateArgumentNameResolver(std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
virtual ~CxxTemplateArgumentNameResolver();
|
||||
|
||||
std::string getTemplateArgumentName(const clang::TemplateArgument& argument);
|
||||
};
|
||||
|
||||
#endif // CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H
|
||||
@@ -0,0 +1,270 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
#include <clang/AST/ASTContext.h>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
|
||||
#include "data/type/DataType.h"
|
||||
#include "data/type/NamedDataType.h"
|
||||
#include "data/type/ArrayModifiedDataType.h"
|
||||
#include "data/type/PointerModifiedDataType.h"
|
||||
#include "data/type/ReferenceModifiedDataType.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
CxxTypeNameResolver::CxxTypeNameResolver()
|
||||
: CxxNameResolver(std::vector<const clang::Decl*>())
|
||||
{
|
||||
}
|
||||
|
||||
CxxTypeNameResolver::CxxTypeNameResolver(std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: CxxNameResolver(ignoredContextDecls)
|
||||
{
|
||||
}
|
||||
|
||||
CxxTypeNameResolver::~CxxTypeNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<DataType> CxxTypeNameResolver::qualTypeToDataType(clang::QualType qualType)
|
||||
{
|
||||
std::shared_ptr<DataType> dataType = typeToDataType(qualType.getTypePtr());
|
||||
if (qualType.isConstQualified())
|
||||
{
|
||||
dataType->addQualifier(DataType::QUALIFIER_CONST);
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
std::shared_ptr<DataType> CxxTypeNameResolver::typeToDataType(const clang::Type* type)
|
||||
{
|
||||
std::shared_ptr<DataType> dataType;
|
||||
|
||||
switch (type->getTypeClass())
|
||||
{
|
||||
case clang::Type::Paren:
|
||||
{
|
||||
dataType = qualTypeToDataType(type->getAs<clang::ParenType>()->getInnerType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Typedef:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(type->getAs<clang::TypedefType>()->getDecl(), getIgnoredContextDecls());
|
||||
dataType = std::make_shared<NamedDataType>(declNameResolver.getDeclNameHierarchy());
|
||||
break;
|
||||
}
|
||||
case clang::Type::MemberPointer:
|
||||
{
|
||||
// test this case!
|
||||
}
|
||||
case clang::Type::Pointer:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(type->getPointeeType());
|
||||
dataType = std::make_shared<PointerModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::ConstantArray:
|
||||
case clang::Type::DependentSizedArray:
|
||||
case clang::Type::IncompleteArray:
|
||||
case clang::Type::VariableArray:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(clang::dyn_cast<clang::ArrayType>(type)->getElementType());
|
||||
dataType = std::make_shared<ArrayModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::LValueReference:
|
||||
case clang::Type::RValueReference:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(type->getPointeeType());
|
||||
dataType = std::make_shared<ReferenceModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::Elaborated:
|
||||
{
|
||||
dataType = qualTypeToDataType(clang::dyn_cast<clang::ElaboratedType>(type)->getNamedType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Enum:
|
||||
case clang::Type::Record:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(type->getAs<clang::TagType>()->getDecl(), getIgnoredContextDecls());
|
||||
dataType = std::make_shared<NamedDataType>(declNameResolver.getDeclNameHierarchy());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Builtin:
|
||||
{
|
||||
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 = type->getAs<clang::BuiltinType>()->getName(pp);
|
||||
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::TemplateSpecialization:
|
||||
{
|
||||
NameHierarchy typeNameHerarchy;
|
||||
|
||||
const clang::TagType* tagType = type->getAs<clang::TagType>(); // remove this case when NameHierarchy is split into namepart and parameter part
|
||||
if (tagType)
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(tagType->getDecl(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
else // specialization of a template template parameter (no concrete class) important, may help: has no underlying decl!
|
||||
{
|
||||
const clang::TemplateSpecializationType* templateSpecializationType = type->getAs<clang::TemplateSpecializationType>();
|
||||
CxxDeclNameResolver declNameResolver(templateSpecializationType->getTemplateName().getAsTemplateDecl(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
|
||||
if (typeNameHerarchy.size() > 0)
|
||||
{
|
||||
std::string templateArgumentNamePart = "<";
|
||||
CxxTemplateArgumentNameResolver resolver(getIgnoredContextDecls());
|
||||
for (size_t i = 0; i < templateSpecializationType->getNumArgs(); i++)
|
||||
{
|
||||
templateArgumentNamePart += resolver.getTemplateArgumentName(templateSpecializationType->getArg(i));
|
||||
if (i + 1 < templateSpecializationType->getNumArgs())
|
||||
templateArgumentNamePart += ", ";
|
||||
}
|
||||
templateArgumentNamePart += ">";
|
||||
|
||||
std::string declName = typeNameHerarchy.back()->getName();
|
||||
declName = declName.substr(0, declName.rfind("<")); // remove template parameters
|
||||
declName += templateArgumentNamePart; // add template arguments
|
||||
typeNameHerarchy.pop();
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(declName)); // templateSpecialization has no signature.
|
||||
}
|
||||
}
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::TemplateTypeParm:
|
||||
{
|
||||
clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast<clang::TemplateTypeParmType>(type)->getDecl();
|
||||
|
||||
CxxDeclNameResolver declNameResolver(templateTypeParmDecl, getIgnoredContextDecls());
|
||||
NameHierarchy typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::SubstTemplateTypeParm:
|
||||
{
|
||||
dataType = qualTypeToDataType(type->getAs<clang::SubstTemplateTypeParmType>()->getReplacementType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::DependentName:
|
||||
{
|
||||
const clang::DependentNameType* dependentNameType = clang::dyn_cast<clang::DependentNameType>(type);
|
||||
|
||||
NameHierarchy typeNameHerarchy = getNameHierarchy(dependentNameType->getQualifier());
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(dependentNameType->getIdentifier()->getName().str()));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::PackExpansion:
|
||||
{
|
||||
const clang::PackExpansionType* packExpansionType = clang::dyn_cast<clang::PackExpansionType>(type);
|
||||
dataType = qualTypeToDataType(packExpansionType->getPattern());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Auto:
|
||||
{
|
||||
clang::QualType deducedType = clang::dyn_cast<clang::AutoType>(type)->getDeducedType();
|
||||
if (!deducedType.isNull())
|
||||
{
|
||||
dataType = qualTypeToDataType(deducedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>("auto"));
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case clang::Type::Decltype:
|
||||
{
|
||||
const clang::DecltypeType* decltypeType = clang::dyn_cast<clang::DecltypeType>(type);
|
||||
dataType = qualTypeToDataType(decltypeType->getUnderlyingType());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::string typeClassName = type->getTypeClassName();
|
||||
LOG_INFO(std::string("Unhandled kind of type encountered: ") + typeClassName);
|
||||
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"
|
||||
|
||||
clang::SmallString<64> Buf;
|
||||
llvm::raw_svector_ostream StrOS(Buf);
|
||||
clang::QualType::print(type, clang::Qualifiers(), StrOS, pp, clang::Twine());
|
||||
std::string typeName = StrOS.str();
|
||||
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
NameHierarchy CxxTypeNameResolver::getTypeNameHierarchy(const clang::Type* type)
|
||||
{
|
||||
return typeToDataType(type)->getTypeNameHierarchy();
|
||||
}
|
||||
|
||||
NameHierarchy CxxTypeNameResolver::getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier)
|
||||
{
|
||||
clang::NestedNameSpecifier::SpecifierKind nnsKind = nestedNameSpecifier->getKind();
|
||||
NameHierarchy typeNameHerarchy;
|
||||
switch (nnsKind)
|
||||
{
|
||||
case clang::NestedNameSpecifier::Identifier:
|
||||
{
|
||||
const clang::NestedNameSpecifier* prefix = nestedNameSpecifier->getPrefix();
|
||||
if (prefix)
|
||||
{
|
||||
typeNameHerarchy = getNameHierarchy(prefix);
|
||||
}
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(nestedNameSpecifier->getAsIdentifier()->getName()));
|
||||
}
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Namespace:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsNamespace(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
break;
|
||||
case clang::NestedNameSpecifier::NamespaceAlias:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsNamespaceAlias(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
break;
|
||||
case clang::NestedNameSpecifier::TypeSpec:
|
||||
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
typeNameHerarchy = typeToDataType(nestedNameSpecifier->getAsType())->getTypeNameHierarchy();
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Global:
|
||||
// no context name hierarchy needed.
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Super:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(nestedNameSpecifier->getAsRecordDecl(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return typeNameHerarchy;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef CXX_TYPE_NAME_RESOLVER_H
|
||||
#define CXX_TYPE_NAME_RESOLVER_H
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
#include "data/type/DataType.h"
|
||||
|
||||
class CxxTypeNameResolver: public CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxTypeNameResolver();
|
||||
CxxTypeNameResolver(std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
virtual ~CxxTypeNameResolver();
|
||||
|
||||
std::shared_ptr<DataType> qualTypeToDataType(clang::QualType qualType);
|
||||
NameHierarchy getTypeNameHierarchy(const clang::Type* type);
|
||||
|
||||
private:
|
||||
std::shared_ptr<DataType> typeToDataType(const clang::Type* type);
|
||||
NameHierarchy getNameHierarchy(const clang::NestedNameSpecifier* nestedNameSpecifier);
|
||||
};
|
||||
|
||||
#endif // CXX_TYPE_NAME_RESOLVER_H
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "data/parser/cxx/utilityCxx.h"
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "data/type/NamedDataType.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
namespace utility
|
||||
{
|
||||
std::shared_ptr<DataType> qualTypeToDataType(clang::QualType qualType)
|
||||
{
|
||||
CxxTypeNameResolver resolver;
|
||||
return resolver.qualTypeToDataType(qualType);
|
||||
}
|
||||
|
||||
NameHierarchy getDeclNameHierarchy(const clang::Decl* declaration)
|
||||
{
|
||||
CxxDeclNameResolver resolver(declaration);
|
||||
return resolver.getDeclNameHierarchy();
|
||||
}
|
||||
|
||||
NameHierarchy getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration)
|
||||
{
|
||||
NameHierarchy specializationParentNameHierarchy;
|
||||
llvm::PointerUnion<clang::ClassTemplateDecl*, clang::ClassTemplatePartialSpecializationDecl*> pu = declaration->getSpecializedTemplateOrPartial();
|
||||
if (pu.is<clang::ClassTemplateDecl*>())
|
||||
{
|
||||
clang::ClassTemplateDecl* specializedFromDecl = pu.get<clang::ClassTemplateDecl*>();
|
||||
specializationParentNameHierarchy = utility::getDeclNameHierarchy(specializedFromDecl);
|
||||
}
|
||||
else if (pu.is<clang::ClassTemplatePartialSpecializationDecl*>())
|
||||
{
|
||||
clang::ClassTemplatePartialSpecializationDecl* specializedFromDecl = pu.get<clang::ClassTemplatePartialSpecializationDecl*>();
|
||||
specializationParentNameHierarchy = utility::getDeclNameHierarchy(specializedFromDecl);
|
||||
}
|
||||
return specializationParentNameHierarchy;
|
||||
}
|
||||
|
||||
std::shared_ptr<DataType> templateArgumentToDataType(const clang::TemplateArgument& argument) // remove this! this is stupid! agurment is not always a datatype.
|
||||
{
|
||||
const clang::TemplateArgument::ArgKind kind = argument.getKind();
|
||||
switch (kind)
|
||||
{
|
||||
case clang::TemplateArgument::Type:
|
||||
return utility::qualTypeToDataType(argument.getAsType());
|
||||
case clang::TemplateArgument::Integral:
|
||||
return utility::qualTypeToDataType(argument.getIntegralType());
|
||||
case clang::TemplateArgument::Null:
|
||||
LOG_ERROR("Type of template argument not handled: Null");
|
||||
break;
|
||||
case clang::TemplateArgument::Declaration:
|
||||
return utility::qualTypeToDataType(argument.getAsDecl()->getType());
|
||||
case clang::TemplateArgument::NullPtr:
|
||||
return utility::qualTypeToDataType(argument.getNullPtrType());
|
||||
break;
|
||||
case clang::TemplateArgument::Template:
|
||||
{
|
||||
clang::TemplateName templateName = argument.getAsTemplate();
|
||||
switch (templateName.getKind())
|
||||
{
|
||||
case clang::TemplateName::Template:
|
||||
return std::make_shared<NamedDataType>(getDeclNameHierarchy(templateName.getAsTemplateDecl()));
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Type of template argument not handled: Template");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case clang::TemplateArgument::TemplateExpansion:
|
||||
LOG_ERROR("Type of template argument not handled: TemplateExpansion");
|
||||
break;
|
||||
case clang::TemplateArgument::Expression:
|
||||
return utility::qualTypeToDataType(argument.getAsExpr()->getType());
|
||||
case clang::TemplateArgument::Pack:
|
||||
{
|
||||
std::string typeName = "<";
|
||||
argument.getPackAsArray();
|
||||
llvm::ArrayRef<clang::TemplateArgument> pack = argument.getPackAsArray();
|
||||
for (size_t i = 0; i < pack.size(); i++)
|
||||
{
|
||||
typeName += templateArgumentToDataType(pack[i])->getFullTypeName();
|
||||
if (i < pack.size() - 1)
|
||||
{
|
||||
typeName += ", ";
|
||||
}
|
||||
}
|
||||
typeName += ">";
|
||||
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
return std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return std::make_shared<NamedDataType>(NameHierarchy());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef UTILITY_CLANG_H
|
||||
#define UTILITY_CLANG_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
|
||||
class DataType;
|
||||
class NameHierarchy;
|
||||
|
||||
namespace utility
|
||||
{
|
||||
std::shared_ptr<DataType> qualTypeToDataType(clang::QualType qualType);
|
||||
|
||||
NameHierarchy getDeclNameHierarchy(const clang::Decl* declaration);
|
||||
std::shared_ptr<DataType> templateArgumentToDataType(const clang::TemplateArgument& argument);
|
||||
NameHierarchy getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration);
|
||||
}
|
||||
|
||||
#endif // UTILITY_CLANG_H
|
||||
Reference in New Issue
Block a user