diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31febbe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +clang-extract.* +*.o diff --git a/Makefile b/Makefile index 60c729d..58d86be 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,43 @@ -CONFIG := Release CONFIG := Debug -LLVM_DIR ?= /PATH/TO/LLVM/ +LLVM_DIR ?= $(shell llvm-config --obj-root) EXENAME := ./clang-extract.$(CONFIG) -CXXFLAGS := -I$(LLVM_DIR)/include -I$(LLVM_DIR)/tools/clang/include \ - -DNDEBUG -D_GNU_SOURCE -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS \ + +CXXFLAGS += -std=c++11 -stdlib=libc++ -I$(LLVM_DIR)/include -I$(LLVM_DIR)/tools/clang/include \ + -nostdinc++ -I$(LLVM_DIR)/include/c++/v1 \ + -D_GNU_SOURCE -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS \ -pedantic -fomit-frame-pointer -fno-exceptions -fno-rtti -fPIC -fno-strict-aliasing \ -W -Wall -Woverloaded-virtual -Wcast-qual -Wno-long-long -Wno-unused-parameter -Wwrite-strings \ -Wno-variadic-macros -Wno-reorder -Wno-trigraphs -Wno-unknown-pragmas -Wno-unused -LDFLAGS := -L$(LLVM_DIR)/$(CONFIG)/lib +LDFLAGS += -L$(LLVM_DIR)/lib LIBS := -lclangFrontend -lclangSerialization -lclangParse -lclangSema -lclangAnalysis -lclangAST \ - -lclangLex -lclangBasic -lLLVMMC -lLLVMCore -lLLVMSupport -lpthread -ldl -lm + -lclangLex -lclangBasic -lclangEdit \ + -lLLVMLTO -lLLVMObjCARCOpts -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMBitWriter -lLLVMCppBackendCodeGen \ + -lLLVMCppBackendInfo -lLLVMTableGen -lLLVMDebugInfo -lLLVMOption -lLLVMX86Disassembler -lLLVMX86AsmParser \ + -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMX86Desc -lLLVMX86Info \ + -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMJIT -lLLVMIRReader -lLLVMBitReader -lLLVMAsmParser \ + -lLLVMMCDisassembler -lLLVMInstrumentation -lLLVMInterpreter -lLLVMCodeGen -lLLVMScalarOpts \ + -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMMCJIT -lLLVMTarget \ + -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport -lcurses \ + -lclangLex -lclangBasic -lLLVMMC -lLLVMCore -lLLVMSupport -lclangDriver -lpthread -ldl -lm -lz -ifeq ($(CONFIG),"Debug") - CXXFLAGS += -DDEBUG -g +ifeq ($(CONFIG),Debug) + CXXFLAGS += -D_DEBUG -DDEBUG -UNDEBUG -g3 -O0 endif -ifeq ($(CONFIG),"Release") - CXXFLAGS += -O3 +ifeq ($(CONFIG),Release) + CXXFLAGS += -DNDEBUG -g3 -O3 endif -SRCS := extract.cpp main.cpp +SRCS := extract.cpp main.cpp $(EXENAME) : $(SRCS) extract.h Makefile $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(SRCS) $(LIBS) test : test1.h #$(EXENAME) $(EXENAME) -I . test1.h -o test.out + +.PHONY: clean +clean : + rm -fr $(EXENAME) + diff --git a/extract.cpp b/extract.cpp index 4926691..d0ef316 100644 --- a/extract.cpp +++ b/extract.cpp @@ -46,7 +46,7 @@ static FileID s_getFileId(const SourceLocation& loc, SourceManager& sm) assert(loc.isFileID() && "not a file location"); FileID ret = sm.getFileID(loc); assert(!ret.isInvalid() && "invalid file id for declaration"); - + return ret; } @@ -83,7 +83,7 @@ static void s_printAnnotations(llvm::raw_ostream& os, const Decl* decl, int decl { const AttrVec& attrVec = decl->getAttrs(); for( specific_attr_iterator iterator = specific_attr_begin(attrVec), end_iterator = specific_attr_end(attrVec); - iterator != end_iterator; + iterator != end_iterator; ++iterator ) { os << "Annotation( refid=" << declId << ", text=\"\"\""; @@ -165,7 +165,7 @@ void Havok::ExtractASTConsumer::declareImplicitMethods(Decl* declIn) { CXXRecordDecl* recordDecl = dyn_cast(declIn); assert(recordDecl && "The declaration should be a record declaration."); - + if(!recordDecl->isCompleteDefinition()) return; @@ -183,7 +183,7 @@ void Havok::ExtractASTConsumer::declareImplicitMethods(Decl* declIn) // This includes top-level classes, namespaces, typedefs, constants, enums, functions // in every included header file. Contained elements are children of a top-level element. // Every element that is parsed is in here somewhere -void Havok::ExtractASTConsumer::HandleTopLevelDecl(DeclGroupRef declGroupIn) +bool Havok::ExtractASTConsumer::HandleTopLevelDecl(DeclGroupRef declGroupIn) { // If there are multiple declarations with the same semantic type in the same scope they are // returned as a group. [ e.g. class A { ... } B; ] Usually each group only contains one declaration. @@ -192,6 +192,8 @@ void Havok::ExtractASTConsumer::HandleTopLevelDecl(DeclGroupRef declGroupIn) declareImplicitMethods(*iter); m_decls.push_back(*iter); } + + return true; } void Havok::ExtractASTConsumer::dumpAllDeclarations() @@ -422,7 +424,7 @@ int Havok::ExtractASTConsumer::dumpDecl_i(const Decl* declIn) // only dumping information for non-template functions of non-template records or // non-template functions of template records (but not non-template functions // of template record specializations or instantiations). - if( methodDecl == methodDecl->getFirstDeclaration() && + if( methodDecl == methodDecl->getFirstDecl() && tk == FunctionDecl::TK_NonTemplate && // non template function ( templateRecord != NULL || // function from a template class declaration !isa(parentRecord) ) ) // not a template instantiation or specialization @@ -512,7 +514,7 @@ int Havok::ExtractASTConsumer::dumpDecl_i(const Decl* declIn) } } else if( const EnumConstantDecl* enumConstantDecl = dyn_cast(declIn) ) - { + { // the enum has already been dumped int enumId = getTypeId_i( enumConstantDecl->getType().getTypePtr() ); m_os << "EnumConstant( enumId=" << enumId; @@ -557,7 +559,7 @@ int Havok::ExtractASTConsumer::dumpType_i(QualType qualTypeIn, int scopeId) const Type *const typeIn = qualTypeIn.getTypePtr(); int id = dumpNonQualifiedType_i(typeIn, scopeId); - if (qualTypeIn.getQualifiers() & Qualifiers::Const) + if (qualTypeIn.isConstQualified()) { int retId = findConstTypeId_i(id); if (retId == -1) @@ -599,7 +601,7 @@ int Havok::ExtractASTConsumer::dumpSimpleType_i(QualType qualTypeIn, int scopeId const Type *const typeIn = qualTypeIn.getTypePtr(); int id = dumpNonQualifiedSimpleType_i(typeIn, scopeId); - if (qualTypeIn.getQualifiers() & Qualifiers::Const) + if (qualTypeIn.isConstQualified()) { int retId = findConstTypeId_i(id); if (retId == -1) @@ -618,13 +620,13 @@ int Havok::ExtractASTConsumer::dumpNonQualifiedSimpleType_i(const Type* typeIn, // clean the type from any sugar used to specify it in source code (elaborated types) typeIn = s_getTrueType(typeIn); - + { const TemplateSpecializationType* templateSpecializationType = typeIn->getAs(); if( templateSpecializationType && (typeIn->getAs() == NULL) ) // not a typedef to a template specialization type { - // this type is dumped in case of an explicit instantiation when this function + // this type is dumped in case of an explicit instantiation when this function // is called from dumpTemplateClassSpecialization_i(), or in case of an // implicit instantiation when this function is called in a generic way to // dump a needed type. @@ -632,17 +634,17 @@ int Havok::ExtractASTConsumer::dumpNonQualifiedSimpleType_i(const Type* typeIn, return dumpTemplateInstantiationType_i(templateSpecializationType); } } - + // seen this type before? int retId = findTypeId_i(typeIn); if(retId != -1) { return retId; } - + if( const TypedefType* bt = typeIn->getAs() ) { - // sometimes TypedefTypes can also be casted to InjectedClassNameTypes, + // sometimes TypedefTypes can also be casted to InjectedClassNameTypes, // for this reason we need to handle this first. int tid = dumpType_i(bt->getDecl()->getUnderlyingType()); retId = m_uid.alloc(); @@ -709,12 +711,12 @@ int Havok::ExtractASTConsumer::dumpNonQualifiedSimpleType_i(const Type* typeIn, } else if( const FunctionProtoType* bt = typeIn->getAs() ) { - int resType = dumpType_i(bt->getResultType()); - const int numArgs = bt->getNumArgs(); + int resType = dumpType_i(bt->getReturnType()); + const int numArgs = bt->getNumParams(); std::vector paramTypes; for(int i = 0; i < numArgs; ++i) { - paramTypes.push_back(dumpType_i(bt->getArgType(i))); + paramTypes.push_back(dumpType_i(bt->getParamType(i))); } retId = m_uid.alloc(); m_os << "FunctionProtoType( id=" << retId << ", rettypeid=" << resType << ", paramtypeids=["; @@ -736,7 +738,7 @@ int Havok::ExtractASTConsumer::dumpNonQualifiedSimpleType_i(const Type* typeIn, // int eid = _dumpType( bt->getElementType().getTypePtr() ); // retId = m_uid.alloc(); // m_os << "ArrayType id='" << retId << "' elemId='" << eid << "' count='" << bt->getSizeExpr() ->getType().getTypePtr() << "'\n"; - } + } else if( const DependentNameType* bt = typeIn->getAs() ) { retId = m_uid.alloc(); @@ -790,7 +792,7 @@ int Havok::ExtractASTConsumer::dumpTemplateInstantiationType_i( TemplateName templateName = templateSpecializationType->getTemplateName(); TemplateDecl* templateDecl = templateName.getAsTemplateDecl(); assert(templateDecl && "could not retrieve template declaration"); - + ClassTemplateDecl* classTemplateDecl = dyn_cast(templateDecl); const Decl* scopeDiscoveryDecl = NULL; const ClassTemplateSpecializationDecl* classTemplateInstantiationDecl = NULL; @@ -812,7 +814,7 @@ int Havok::ExtractASTConsumer::dumpTemplateInstantiationType_i( break; } } - assert((classTemplateInstantiationDecl || templateSpecializationType->isDependentType()) && + assert((classTemplateInstantiationDecl || templateSpecializationType->isDependentType()) && "could not retrieve template specialization declaration for instantiation"); // classTemplateInstantiationDecl will be NULL only if the template instance is dependent from a template parameter if(classTemplateInstantiationDecl != NULL) @@ -826,7 +828,7 @@ int Havok::ExtractASTConsumer::dumpTemplateInstantiationType_i( } else { - const TemplateTemplateParmDecl* templateTemplateParmDecl = + const TemplateTemplateParmDecl* templateTemplateParmDecl = dyn_cast(templateDecl); assert(templateTemplateParmDecl && "template declaration is not a class template or template parameter"); scopeDiscoveryDecl = templateTemplateParmDecl->getCanonicalDecl(); @@ -838,12 +840,12 @@ int Havok::ExtractASTConsumer::dumpTemplateInstantiationType_i( int scopeid = dumpScope_i(scopeDiscoveryDecl); retId = m_uid.alloc(); - m_os << "TemplateRecordInstantiationType( id=" << retId << ", templateid=" + m_os << "TemplateRecordInstantiationType( id=" << retId << ", templateid=" << templateId; if(classTemplateInstantiationDecl != NULL) { s_printRecordFlags(m_os, classTemplateInstantiationDecl); - } + } else { s_printDefaultRecordFlags(m_os); @@ -880,7 +882,7 @@ int Havok::ExtractASTConsumer::dumpTemplateInstantiationType_i( } int Havok::ExtractASTConsumer::dumpTemplateSpecializationType_i( - const ClassTemplateSpecializationDecl* classTemplateSpecializationDecl, + const ClassTemplateSpecializationDecl* classTemplateSpecializationDecl, int scopeId ) { const TemplateArgumentList& argList = classTemplateSpecializationDecl->getTemplateArgs(); @@ -909,12 +911,12 @@ int Havok::ExtractASTConsumer::dumpTemplateSpecializationType_i( int templateId = getTypeId_i(m_context->getRecordType(templatedDecl).getTypePtr()); retId = m_uid.alloc(); - m_os << "TemplateRecordSpecialization( id=" << retId << ", templateid=" + m_os << "TemplateRecordSpecialization( id=" << retId << ", templateid=" << templateId; s_printRecordFlags(m_os, classTemplateSpecializationDecl); m_os << ", scopeid=" << scopeId << " )\n"; - if(const ClassTemplatePartialSpecializationDecl* classTemplatePartialSpecializationDecl = + if(const ClassTemplatePartialSpecializationDecl* classTemplatePartialSpecializationDecl = dyn_cast(classTemplateSpecializationDecl)) { // 2: dump the parameters @@ -932,14 +934,14 @@ int Havok::ExtractASTConsumer::dumpTemplateSpecializationType_i( // list we might refer to the types dumped in the parameter list (T1 in the above example). This cannot happen in // case of explicit instantiation of course. // The type returned by LLVM for T1 in the argument list is not the same we dumped in the previous step, - // that type must be present in the map for everything to work properly, and that's why we do a special operation + // that type must be present in the map for everything to work properly, and that's why we do a special operation // adding (or replacing) all those types with the id obtained by looking up the Parameter list type. addOrReplaceSpecializationTypeParameterTypes_i(classTemplatePartialSpecializationDecl->getTemplateParameters()); } // 4: dump the argument list - dumpTemplateArgumentList_i(templateSpecializationType->getArgs(), - templateSpecializationType->getNumArgs(), + dumpTemplateArgumentList_i(templateSpecializationType->getArgs(), + templateSpecializationType->getNumArgs(), retId); m_knownTypes[recordType] = retId; @@ -1003,7 +1005,7 @@ void Havok::ExtractASTConsumer::dumpSpecifiersRecursive_i(const NestedNameSpecif { if( dyn_cast(specifierType) ) dumpNonQualifiedSimpleType_i(specifierType); - } + } } void Havok::ExtractASTConsumer::dumpTypeSpecifiers_i( const Type* type ) @@ -1088,10 +1090,10 @@ void Havok::ExtractASTConsumer::dumpTemplateClass_i(const ClassTemplateDecl* cla m_knownTypes[injectedClassnameType] = templateId; // 1: dump template parameter list - const TemplateParameterList* paramList = - classTemplateDef != NULL ? - classTemplateDef->getTemplateParameters() : - classTemplateDecl->getTemplateParameters(); + const TemplateParameterList* paramList = + classTemplateDef != NULL ? + classTemplateDef->getTemplateParameters() : + classTemplateDecl->getTemplateParameters(); dumpTemplateParameterList_i(paramList, templateId); } @@ -1108,7 +1110,7 @@ void Havok::ExtractASTConsumer::dumpTemplateClass_i(const ClassTemplateDecl* cla // We dump type T1 (type template parameter) when dumping the Parameter list above, but when dumping the parent // type we might refer to the types dumped in the parameter list (T1 in the above example). // The type returned by LLVM for T1 in the argument list is not the same we dumped in the previous step, - // that type must be present in the map for everything to work properly, and that's why we do a special operation + // that type must be present in the map for everything to work properly, and that's why we do a special operation // adding (or replacing) all those types with the id obtained by looking up the Parameter list type. addOrReplaceSpecializationTypeParameterTypes_i(classTemplateDecl->getTemplateParameters()); @@ -1134,14 +1136,14 @@ void Havok::ExtractASTConsumer::dumpTemplateClassSpecialization_i(const ClassTem classTemplateSpecializationDef = dyn_cast(classTemplateSpecializationDefRecord); int scopeId = dumpScope_i(classTemplateSpecializationDefRecord != NULL ? classTemplateSpecializationDefRecord : classTemplateSpecializationDecl); - + // 1: dump the TemplateSpecializationRecord entry // dump template specializations using specific function int templateId = dumpTemplateSpecializationType_i(classTemplateSpecializationDef != NULL ? classTemplateSpecializationDef : classTemplateSpecializationDecl, scopeId); if(classTemplateSpecializationDecl->isThisDeclarationADefinition()) { - if(const ClassTemplatePartialSpecializationDecl* classTemplatePartialSpecializationDecl = + if(const ClassTemplatePartialSpecializationDecl* classTemplatePartialSpecializationDecl = dyn_cast(classTemplateSpecializationDecl)) { // 2: add special entries in the type map for types referred by template parameters, consider the following template class declaration: @@ -1155,7 +1157,7 @@ void Havok::ExtractASTConsumer::dumpTemplateClassSpecialization_i(const ClassTem // We dump type T1 (type template parameter) when dumping the Parameter list above, but when dumping the parent // type we might refer to the types dumped in the parameter list (T1 in the above example). // The type returned by LLVM for T1 in the argument list is not the same we dumped in the previous step, - // that type must be present in the map for everything to work properly, and that's why we do a special operation + // that type must be present in the map for everything to work properly, and that's why we do a special operation // adding (or replacing) all those types with the id obtained by looking up the Parameter list type. addOrReplaceSpecializationTypeParameterTypes_i(classTemplatePartialSpecializationDecl->getTemplateParameters()); } @@ -1165,7 +1167,7 @@ void Havok::ExtractASTConsumer::dumpTemplateClassSpecialization_i(const ClassTem } } else if(kind == TSK_ExplicitInstantiationDefinition) - { + { const TemplateArgumentList& argList = classTemplateSpecializationDecl->getTemplateArgs(); const QualType canonType = m_context->getRecordType(classTemplateSpecializationDecl); TemplateName tempName(classTemplateSpecializationDecl->getSpecializedTemplate()); @@ -1199,8 +1201,8 @@ void Havok::ExtractASTConsumer::dumpTemplateParameterList_i(const TemplateParame else if ( const TemplateTypeParmDecl* templateTypeParmDecl = dyn_cast(paramDecl) ) { int typeId = dumpType_i(m_context->getTemplateTypeParmType( - templateTypeParmDecl->getDepth(), - templateTypeParmDecl->getIndex(), + templateTypeParmDecl->getDepth(), + templateTypeParmDecl->getIndex(), templateTypeParmDecl->isParameterPack(), const_cast(templateTypeParmDecl))); m_os << "TemplateTypeParamType( templateid=" << templateId << ", id=" << typeId; @@ -1238,10 +1240,10 @@ void Havok::ExtractASTConsumer::dumpTemplateArgumentList_i(const TemplateArgumen { if(argv[i].getKind() == TemplateArgument::Type) { - QualType qualType = argv[i].getAsType(); + QualType qualType = argv[i].getAsType(); int typeId = dumpType_i(qualType); m_os << "TemplateSpecializationTypeArg( recordid=" << templateId << ", typeid=" << typeId << " )\n"; - } + } else if(argv[i].getKind() == TemplateArgument::Template) { TemplateName templateName = argv[i].getAsTemplate(); @@ -1256,7 +1258,7 @@ void Havok::ExtractASTConsumer::dumpTemplateArgumentList_i(const TemplateArgumen } else { - const TemplateTemplateParmDecl* templateTemplateParmDecl = + const TemplateTemplateParmDecl* templateTemplateParmDecl = dyn_cast(templateDecl); assert(templateTemplateParmDecl && "template declaration is not a class template or template parameter"); KnownTemplateTemplateParamMap::const_iterator it = m_knowTemplateTemplateParams.find(templateTemplateParmDecl->getCanonicalDecl()); @@ -1328,16 +1330,16 @@ void Havok::ExtractASTConsumer::addOrReplaceSpecializationTypeParameterTypes_i(c if ( const TemplateTypeParmDecl* templateTypeParmDecl = dyn_cast(paramDecl)) { int typeId = getTypeId_i(m_context->getTemplateTypeParmType( - templateTypeParmDecl->getDepth(), - templateTypeParmDecl->getIndex(), + templateTypeParmDecl->getDepth(), + templateTypeParmDecl->getIndex(), templateTypeParmDecl->isParameterPack(), const_cast(templateTypeParmDecl)).getTypePtr()); const Type* newType = m_context->getTemplateTypeParmType( - templateTypeParmDecl->getDepth(), - templateTypeParmDecl->getIndex(), + templateTypeParmDecl->getDepth(), + templateTypeParmDecl->getIndex(), templateTypeParmDecl->isParameterPack()).getTypePtr(); m_knownTypes[newType] = typeId; - } + } } } diff --git a/extract.h b/extract.h index 7be7daa..9043be3 100644 --- a/extract.h +++ b/extract.h @@ -10,7 +10,7 @@ #include "clang/Frontend/CompilerInstance.h" #pragma warning(pop) -namespace Havok +namespace Havok { using namespace clang; @@ -24,7 +24,7 @@ namespace Havok virtual void Initialize(ASTContext& context); virtual void InitializeSema(Sema& sema); // Base callback coming from LLVM (used to accumulate all declarations) - virtual void HandleTopLevelDecl(DeclGroupRef DG); + virtual bool HandleTopLevelDecl(DeclGroupRef DG) override; enum DumpBits { @@ -67,7 +67,7 @@ namespace Havok int getNamespaceId_i(const NamespaceDecl* namespaceDecl); // More utility functions void addOrReplaceSpecializationTypeParameterTypes_i(const TemplateParameterList* paramList); - + // Some types of dump entry are routed through this class to unify default handling. class DumpEntry { @@ -101,7 +101,7 @@ namespace Havok protected: // Output a comma, if necessary. void checkOutputComma(); - + protected: EntryType m_entryType; /// Used to put commas in the correct position. @@ -114,7 +114,7 @@ namespace Havok DumpEntry& operator=(DumpEntry& other); }; - + // List of declarations, declarations are collected and then dumped in a second phase std::list m_decls; @@ -154,7 +154,7 @@ namespace Havok int m_uidNext; }; UidAllocator m_uid; - + // Dumping configuration bits DumpBits m_dumpBits; @@ -162,9 +162,9 @@ namespace Havok Sema* m_sema; private: - + ExtractASTConsumer& operator=(ExtractASTConsumer& other); - }; + }; } #endif //RAW_DUMP_H diff --git a/main.cpp b/main.cpp index fb23824..fe21f97 100644 --- a/main.cpp +++ b/main.cpp @@ -2,21 +2,22 @@ // and conditions defined in file 'LICENSE.txt', which is part of this source code package. #pragma warning(push,0) - #include - #include - #include - #include - - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include #pragma warning(pop) #include @@ -26,100 +27,93 @@ #include static inline bool s_fileNameMatch(const char* path, const char* pattern) { - static char path_s[MAX_PATH]; // static storage - strcpy(path_s, path); - PathStripPath(path_s); - return (PathMatchSpec(path_s, pattern) == TRUE); + static char path_s[MAX_PATH]; // static storage + strcpy(path_s, path); + PathStripPath(path_s); + return (PathMatchSpec(path_s, pattern) == TRUE); } #undef GetCurrentDirectory // remove annoying define from windows header #else #include +#if defined(__APPLE__) +#include +#endif static inline bool s_fileNameMatch(const char* path, const char* pattern) { - const char* base = basename( const_cast(path) ); - return (fnmatch(pattern, base, 0) == 0); + const char* base = basename( const_cast(path) ); + return (fnmatch(pattern, base, 0) == 0); } #endif namespace Havok { - // Module loader - class ModuleLoader : public clang::ModuleLoader - { - public: - - virtual ModuleKey loadModule(SourceLocation, IdentifierInfo&, SourceLocation) - { - assert(0); - return 0; - } - }; - // Preprocessor callbacks used to exclude specific included files (with #include) - // When the preprocessor processes a file, it will generate callbacks to this object - // on various events, when an inclusion directive is detected we will simply look - // it up in our set of excluded inclusion, and if something matches we will basically - // override that with an empty buffer. - class FilenamePatternExcluder : public clang::PPCallbacks - { - public: - - FilenamePatternExcluder(clang::Preprocessor& preprocessor, clang::SourceManager& sourceManager) - : PPCallbacks(), m_preprocessor(preprocessor), m_sourceManager(sourceManager) - {} - - ~FilenamePatternExcluder() - {} - - void addExcludedPattern(const std::string& str) - { - m_excludedPatterns.push_back(str); - } - - virtual void InclusionDirective( - SourceLocation, - const Token&, - StringRef fileName, - bool, - const FileEntry* file, - SourceLocation, - StringRef, - StringRef ) - { - m_preprocessor.SetSuppressIncludeNotFoundError(false); - for(unsigned int i = 0; i < m_excludedPatterns.size(); ++i) - { - if(s_fileNameMatch(fileName.str().c_str(), m_excludedPatterns[i].c_str())) - { - if(file) - { - // file was found - m_sourceManager.overrideFileContents(file, llvm::MemoryBuffer::getNewMemBuffer(0), false); - } - else - { - // file was not found (but as it matches one of the excluded patterns we ignore it anyway) - m_preprocessor.SetSuppressIncludeNotFoundError(true); - } - break; - } - } - } - - protected: - - // Included file patterns that will be skipped, these string should contain - // OS-style wildcards to exclude sets of files based on their name. - std::vector m_excludedPatterns; - - // Source manager used to exclude all the specified inclusions. - clang::SourceManager& m_sourceManager; - - // Preprocessor used during parsing of the source - clang::Preprocessor& m_preprocessor; - - private: - FilenamePatternExcluder& operator=(const FilenamePatternExcluder& other); - }; + // Preprocessor callbacks used to exclude specific included files (with #include) + // When the preprocessor processes a file, it will generate callbacks to this object + // on various events, when an inclusion directive is detected we will simply look + // it up in our set of excluded inclusion, and if something matches we will basically + // override that with an empty buffer. + class FilenamePatternExcluder : public clang::PPCallbacks + { + public: + + FilenamePatternExcluder(clang::Preprocessor& preprocessor, clang::SourceManager& sourceManager) + : PPCallbacks(), m_sourceManager(sourceManager), m_preprocessor(preprocessor) + {} + + ~FilenamePatternExcluder() + {} + + void addExcludedPattern(const std::string& str) + { + m_excludedPatterns.push_back(str); + } + + virtual void InclusionDirective( + SourceLocation, + const Token&, + StringRef fileName, + bool, + CharSourceRange, + const FileEntry* file, + StringRef, + StringRef, + const Module*) + { + m_preprocessor.SetSuppressIncludeNotFoundError(false); + for(unsigned int i = 0; i < m_excludedPatterns.size(); ++i) + { + if(s_fileNameMatch(fileName.str().c_str(), m_excludedPatterns[i].c_str())) + { + if(file) + { + // file was found + m_sourceManager.overrideFileContents(file, llvm::MemoryBuffer::getNewMemBuffer(0), false); + } + else + { + // file was not found (but as it matches one of the excluded patterns we ignore it anyway) + m_preprocessor.SetSuppressIncludeNotFoundError(true); + } + break; + } + } + } + + protected: + + // Included file patterns that will be skipped, these string should contain + // OS-style wildcards to exclude sets of files based on their name. + std::vector m_excludedPatterns; + + // Source manager used to exclude all the specified inclusions. + clang::SourceManager& m_sourceManager; + + // Preprocessor used during parsing of the source + clang::Preprocessor& m_preprocessor; + + private: + FilenamePatternExcluder& operator=(const FilenamePatternExcluder& other); + }; } static llvm::cl::list o_cppDefines(llvm::cl::ZeroOrMore, "D", llvm::cl::desc("Predefined preprocessor constants"), llvm::cl::value_desc("value") ); // Predefined constants @@ -134,169 +128,183 @@ static llvm::cl::opt o_outputFilename(llvm::cl::Required, "o", llvm int main(int argc, char **argv) { - int exitStatus; - - //_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_EVERY_1024_DF | _CRTDBG_LEAK_CHECK_DF ); - llvm::cl::ParseCommandLineOptions(argc, argv, "Help Text Here", true); - llvm::MemoryBuffer* emptyMemoryBuffer = llvm::MemoryBuffer::getNewMemBuffer(0, "emptyMemoryBuffer"); - { - clang::TextDiagnosticPrinter diagnosticConsumer(llvm::errs(), clang::DiagnosticOptions(), false); - llvm::IntrusiveRefCntPtr diagnosticIDs(new clang::DiagnosticIDs()); - clang::DiagnosticsEngine diagnostics(diagnosticIDs, &diagnosticConsumer, false); - // ignored warnings - diagnostics.setDiagnosticMapping(clang::diag::warn_undefined_internal, clang::diag::MAP_IGNORE, clang::SourceLocation()); //-Wno-undefined-internal - - clang::TargetOptions targetOptions; - targetOptions.Triple = llvm::sys::getHostTriple(); - llvm::IntrusiveRefCntPtr targetInfo( clang::TargetInfo::CreateTargetInfo(diagnostics, targetOptions ) ); - clang::FileSystemOptions filesystemOptions; - clang::FileManager fileManager(filesystemOptions); - clang::SourceManager sourceManager(diagnostics, fileManager); - clang::HeaderSearch headerSearch(fileManager); - Havok::ModuleLoader moduleLoader; - clang::LangOptions langOptions; - langOptions.CPlusPlus = 1; - langOptions.CPlusPlus0x = 0; - langOptions.Bool = 1; - langOptions.ConstStrings = 1; - langOptions.AssumeSaneOperatorNew = 1; - langOptions.ImplicitInt = 0; - langOptions.ElideConstructors = 0; - - clang::Preprocessor preprocessor(diagnostics, langOptions, targetInfo.getPtr(), sourceManager, headerSearch, moduleLoader); - - Havok::FilenamePatternExcluder* filenamePatternExcluder = new Havok::FilenamePatternExcluder(preprocessor, sourceManager); - preprocessor.addPPCallbacks(filenamePatternExcluder); // the preprocessor is now owner of the FilenamePatternExcluder - clang::PreprocessorOptions preprocessorOptions; - clang::HeaderSearchOptions headerSearchOptions; - clang::FrontendOptions frontendOptions; - - std::string errorInfo; - llvm::raw_fd_ostream outstream(o_outputFilename.c_str(), errorInfo); - { - // Gather input files into a memory - std::string mainFileText; - llvm::raw_string_ostream stream(mainFileText); - - // Print the LLVMClangParser working directory - { - llvm::sys::Path cwd = llvm::sys::Path::GetCurrentDirectory(); - outstream << "InvocationWorkingDirectory( path='" << cwd.c_str() << "' )\n"; - } - - // -D - for( llvm::cl::list::iterator iter = o_cppDefines.begin(), end = o_cppDefines.end(); iter != end; ++iter ) - { - std::string::size_type index = iter->find_first_of('='); - std::string macro, value; - if(index != std::string::npos) - { - macro = iter->substr(0, index); - value = iter->substr(index+1, std::string::npos); - } - else - { - macro = (*iter); - } - - stream << "#define " << macro << ' ' << value << '\n'; - outstream << "InvocationDefine( name='" << macro << "', value='" << value << "' )\n"; - } - - // -I - for( std::vector::iterator iter = o_includePath.begin(), end = o_includePath.end(); iter != end; ++iter ) - { - headerSearchOptions.AddPath(*iter, clang::frontend::Angled, true, false, false); - outstream << "InvocationIncludePath( path='" << *iter << "' )\n"; - } - - // -exclude - { - // Do not free buffers associated with the compiler invocation - preprocessorOptions.RetainRemappedFileBuffers = true; - for( std::vector::iterator iter = o_excludeFilenames.begin(), end = o_excludeFilenames.end(); iter != end; ++iter ) - { - preprocessorOptions.addRemappedFile(iter->c_str(), emptyMemoryBuffer); - } - } - - // -exclude-pattern - { - for( std::vector::iterator iter = o_excludeFilenamePatterns.begin(), end = o_excludeFilenamePatterns.end(); iter != end; ++iter ) - { - filenamePatternExcluder->addExcludedPattern(*iter); - } - } - - // -A - for( llvm::cl::list::iterator iter = o_passAttributes.begin(), end = o_passAttributes.end(); iter != end; ++iter ) - { - std::string::size_type index = iter->find_first_of('='); - std::string macro, value; - if(index != std::string::npos) - { - macro = iter->substr(0, index); - value = iter->substr(index+1, std::string::npos); - } - else - { - macro = (*iter); - } - - outstream << "InvocationAttribute( name='" << macro << "', value='" << value << "' )\n"; - } - - for( std::vector::iterator iter = o_forceInclude.begin(), end = o_forceInclude.end(); iter != end; ++iter ) - { - stream << "#include<" << iter->c_str() << ">\n"; - outstream << "InvocationForceInclude( path='" << iter->c_str() << "' )\n"; - } - for( std::vector::iterator iter = o_inputFilenames.begin(), end = o_inputFilenames.end(); iter != end; ++iter ) - { - stream << "#include<" << iter->c_str() << ">\n"; - outstream << "InvocationInput( path='" << iter->c_str() << "' )\n"; - } - stream.flush(); - - llvm::MemoryBuffer* mainBuf = llvm::MemoryBuffer::getMemBufferCopy( llvm::StringRef(mainFileText.c_str(), mainFileText.size()), "masterInputFile" ); - sourceManager.createMainFileIDForMemBuffer(mainBuf); - } - std::string resourceDir = o_resourceDir; - if(!resourceDir.empty()) - { - resourceDir += "/include"; - headerSearchOptions.AddPath(resourceDir, clang::frontend::System, false, false, true); - } - - clang::InitializePreprocessor( preprocessor, clang::PreprocessorOptions(), headerSearchOptions, frontendOptions); - - Havok::ExtractASTConsumer consumer(outstream); - clang::IdentifierTable identifierTable(langOptions); - clang::SelectorTable selectorTable; - clang::Builtin::Context builtinContext; - clang::ASTContext astcontext( langOptions, sourceManager, targetInfo.getPtr(), identifierTable, selectorTable, builtinContext, 0); - - #ifdef _DEBUG - outstream.SetUnbuffered(); - #endif - diagnostics.getClient()->BeginSourceFile(langOptions); - clang::ParseAST(preprocessor, &consumer, astcontext); - diagnostics.getClient()->EndSourceFile(); - exitStatus = diagnostics.hasErrorOccurred() ? 1 : 0; - if(exitStatus == 0) - { - // AST parsing succeeded, proceed with declaration dumping - consumer.dumpAllDeclarations(); - } - else - { - outstream << "## The diagnostic engine returned an error during code parsing.\n"; - } - - outstream.flush(); - } - delete emptyMemoryBuffer; - llvm::llvm_shutdown(); - - return exitStatus; + int exitStatus; + + //_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_EVERY_1024_DF | _CRTDBG_LEAK_CHECK_DF ); + llvm::cl::ParseCommandLineOptions(argc, argv, "Help Text Here"); + llvm::MemoryBuffer* emptyMemoryBuffer = llvm::MemoryBuffer::getNewMemBuffer(0, "emptyMemoryBuffer"); + { + llvm::IntrusiveRefCntPtr DO(new clang::DiagnosticOptions()); + clang::TextDiagnosticPrinter diagnosticConsumer(llvm::errs(), DO.get(), false); + llvm::IntrusiveRefCntPtr diagnosticIDs(new clang::DiagnosticIDs()); + llvm::IntrusiveRefCntPtr diagnosticsEngine(new clang::DiagnosticsEngine(diagnosticIDs, DO.get(), &diagnosticConsumer, false)); + // ignored warnings + //diagnosticsEngine.setDiagnosticMapping(clang::diag::warn_undefined_internal, clang::diag::MAP_IGNORE, clang::SourceLocation()); //-Wno-undefined-internal + + std::shared_ptr targetOptions(new clang::TargetOptions()); + targetOptions->Triple = llvm::sys::getDefaultTargetTriple(); + llvm::IntrusiveRefCntPtr targetInfo(clang::TargetInfo::CreateTargetInfo(*diagnosticsEngine, targetOptions )); + clang::FileSystemOptions filesystemOptions; + clang::FileManager fileManager(filesystemOptions); + clang::SourceManager sourceManager(*diagnosticsEngine, fileManager); + + llvm::IntrusiveRefCntPtr HSOpts(new clang::HeaderSearchOptions()); + //Havok::ModuleLoader moduleLoader; apparently not needed anymore + // as we're going to use clang::CompilerInstance moduleLoader directly + + clang::CompilerInstance moduleLoader; + clang::LangOptions langOptions; + langOptions.CPlusPlus = 1; + langOptions.CPlusPlus11 = 0; + langOptions.Bool = 1; + langOptions.ConstStrings = 1; + langOptions.AssumeSaneOperatorNew = 1; + langOptions.ImplicitInt = 0; + langOptions.ElideConstructors = 0; + + clang::HeaderSearch headerSearch(HSOpts, sourceManager, *diagnosticsEngine, langOptions, targetInfo.get()); + + llvm::IntrusiveRefCntPtr PPOpts (new clang::PreprocessorOptions()); + llvm::IntrusiveRefCntPtr preprocessor (new clang::Preprocessor(PPOpts, *diagnosticsEngine, langOptions, sourceManager, headerSearch, moduleLoader)); + + preprocessor->Initialize(*targetInfo); + + diagnosticConsumer.BeginSourceFile (langOptions, preprocessor.get()); + + Havok::FilenamePatternExcluder* filenamePatternExcluder = new Havok::FilenamePatternExcluder(*preprocessor.get(), sourceManager); + preprocessor->addPPCallbacks(filenamePatternExcluder); // the preprocessor is now owner of the FilenamePatternExcluder + clang::HeaderSearchOptions headerSearchOptions; + clang::FrontendOptions frontendOptions; + + std::string errorInfo; + llvm::raw_fd_ostream outstream(o_outputFilename.c_str(), errorInfo, llvm::sys::fs::OpenFlags::F_None); + { + // Gather input files into a memory + std::string mainFileText; + llvm::raw_string_ostream stream(mainFileText); + + // Print the LLVMClangParser working directory + { + llvm::SmallString<128> cwd; + llvm::sys::fs::current_path (cwd); + outstream << "InvocationWorkingDirectory( path='" << cwd.c_str() << "' )\n"; + } + + // -D + for( llvm::cl::list::iterator iter = o_cppDefines.begin(), end = o_cppDefines.end(); iter != end; ++iter ) + { + std::string::size_type index = iter->find_first_of('='); + std::string macro, value; + if(index != std::string::npos) + { + macro = iter->substr(0, index); + value = iter->substr(index+1, std::string::npos); + } + else + { + macro = (*iter); + } + + stream << "#define " << macro << ' ' << value << '\n'; + outstream << "InvocationDefine( name='" << macro << "', value='" << value << "' )\n"; + } + + // -I + for( std::vector::iterator iter = o_includePath.begin(), end = o_includePath.end(); iter != end; ++iter ) + { + headerSearchOptions.AddPath(*iter, clang::frontend::Angled, true, false); + outstream << "InvocationIncludePath( path='" << *iter << "' )\n"; + } + + // -exclude + { + // Do not free buffers associated with the compiler invocation + PPOpts->RetainRemappedFileBuffers = true; + for( std::vector::iterator iter = o_excludeFilenames.begin(), end = o_excludeFilenames.end(); iter != end; ++iter ) + { + PPOpts->addRemappedFile(iter->c_str(), emptyMemoryBuffer); + } + } + + // -exclude-pattern + { + for( std::vector::iterator iter = o_excludeFilenamePatterns.begin(), end = o_excludeFilenamePatterns.end(); iter != end; ++iter ) + { + filenamePatternExcluder->addExcludedPattern(*iter); + } + } + + // -A + for( llvm::cl::list::iterator iter = o_passAttributes.begin(), end = o_passAttributes.end(); iter != end; ++iter ) + { + std::string::size_type index = iter->find_first_of('='); + std::string macro, value; + if(index != std::string::npos) + { + macro = iter->substr(0, index); + value = iter->substr(index+1, std::string::npos); + } + else + { + macro = (*iter); + } + + outstream << "InvocationAttribute( name='" << macro << "', value='" << value << "' )\n"; + } + + for( std::vector::iterator iter = o_forceInclude.begin(), end = o_forceInclude.end(); iter != end; ++iter ) + { + stream << "#include<" << iter->c_str() << ">\n"; + outstream << "InvocationForceInclude( path='" << iter->c_str() << "' )\n"; + } + for( std::vector::iterator iter = o_inputFilenames.begin(), end = o_inputFilenames.end(); iter != end; ++iter ) + { + stream << "#include <" << iter->c_str() << ">\n"; + outstream << "InvocationInput( path='" << iter->c_str() << "' )\n"; + } + stream.flush(); + + llvm::MemoryBuffer* mainBuf = llvm::MemoryBuffer::getMemBufferCopy( llvm::StringRef(mainFileText.c_str(), mainFileText.size()), "masterInputFile" ); + sourceManager.setMainFileID(sourceManager.createFileID(mainBuf)); + } + std::string resourceDir = o_resourceDir; + if(!resourceDir.empty()) + { + resourceDir += "/include"; + headerSearchOptions.AddPath(resourceDir, clang::frontend::System, false, false); + } + + clang::InitializePreprocessor( *preprocessor.get(), *PPOpts, frontendOptions); + + Havok::ExtractASTConsumer consumer(outstream); + clang::IdentifierTable identifierTable(langOptions); + clang::SelectorTable selectorTable; + clang::Builtin::Context builtinContext; + + llvm::IntrusiveRefCntPtr astcontext(new clang::ASTContext(langOptions, sourceManager, identifierTable, selectorTable, builtinContext)); + + astcontext->InitBuiltinTypes(*targetInfo.get()); + + #ifdef _DEBUG + outstream.SetUnbuffered(); + #endif + clang::ParseAST(*preprocessor.get(), &consumer, *astcontext.get()); + diagnosticConsumer.EndSourceFile(); + exitStatus = diagnosticsEngine->hasErrorOccurred() ? 1 : 0; + if(exitStatus == 0) + { + // AST parsing succeeded, proceed with declaration dumping + consumer.dumpAllDeclarations(); + } + else + { + outstream << "## The diagnostic engine returned an error during code parsing.\n"; + } + + outstream.flush(); + } + delete emptyMemoryBuffer; + llvm::llvm_shutdown(); + + return exitStatus; }