int main() { llvm::raw_stdout_ostream ost; //DiagnosticOptions dops; TextDiagnosticPrinter tdp(ost);//, dops); Diagnostic diag(&tdp); LangOptions lang; //lang.GNUMode = 1; SourceManager sm; FileManager fm; HeaderSearch headers(fm); InitHeaderSearch init(headers); init.AddDefaultSystemIncludePaths(lang); init.Realize(); TargetInfo *ti = TargetInfo::CreateTargetInfo(LLVM_HOSTTRIPLE); Preprocessor pp(diag, lang, *ti, sm, headers); PreprocessorInitOptions ppio; InitializePreprocessor(pp, ppio); const FileEntry *file = fm.getFile("foo.c"); sm.createMainFileID(file, SourceLocation()); pp.EnterMainSourceFile(); IdentifierTable tab(lang); MyAction action(pp); Parser p(pp, action); p.ParseTranslationUnit(); return 0; }
static FileID createInMemoryFile(StringRef FileName, MemoryBuffer *Source, SourceManager &Sources, FileManager &Files, vfs::InMemoryFileSystem *MemFS) { MemFS->addFileNoOwn(FileName, 0, Source); return Sources.createFileID(Files.getFile(FileName), SourceLocation(), SrcMgr::C_User); }
static bool ReadSourceLocation(FileManager &FM, SourceManager &SM, const char *&Memory, const char *MemoryEnd, SourceLocation &Location) { // Read the filename. unsigned FileNameLen = 0; if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) || Memory + FileNameLen > MemoryEnd) return true; llvm::StringRef FileName(Memory, FileNameLen); Memory += FileNameLen; // Read the line, column. unsigned Line = 0, Column = 0; if (ReadUnsigned(Memory, MemoryEnd, Line) || ReadUnsigned(Memory, MemoryEnd, Column)) return true; if (FileName.empty()) { Location = SourceLocation(); return false; } const FileEntry *File = FM.getFile(FileName); if (!File) return true; // Make sure that this file has an entry in the source manager. if (!SM.hasFileInfo(File)) SM.createFileID(File, SourceLocation(), SrcMgr::C_User); Location = SM.getLocation(File, Line, Column); return false; }
bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, Diagnostic &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { // Figure out where to get and map in the main file, unless it's already // been created (e.g., by a precompiled preamble). if (!SourceMgr.getMainFileID().isInvalid()) { // Do nothing: the main file has already been set. } else if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } SourceMgr.createMainFileID(File); } else { llvm::OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { // FIXME: Give ec.message() in this diag. Diags.Report(diag::err_fe_error_reading_stdin); return false; } const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), SB->getBufferSize(), 0); SourceMgr.createMainFileID(File); SourceMgr.overrideFileContents(File, SB.take()); } assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; }
bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, Diagnostic &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { // Figure out where to get and map in the main file. if (Opts.EmptyInputOnly) { const char *EmptyStr = ""; llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>"); SourceMgr.createMainFileIDForMemBuffer(SB); } else if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (File) SourceMgr.createMainFileID(File, SourceLocation()); if (SourceMgr.getMainFileID().isInvalid()) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } } else { llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); SourceMgr.createMainFileIDForMemBuffer(SB); if (SourceMgr.getMainFileID().isInvalid()) { Diags.Report(diag::err_fe_error_reading_stdin); return false; } } return true; }
bool CompilerInstance::InitializeSourceManager(StringRef InputFile, SrcMgr::CharacteristicKind Kind, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } SourceMgr.createMainFileID(File, Kind); } else { OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { // FIXME: Give ec.message() in this diag. Diags.Report(diag::err_fe_error_reading_stdin); return false; } const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), SB->getBufferSize(), 0); SourceMgr.createMainFileID(File, Kind); SourceMgr.overrideFileContents(File, SB.take()); } assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; }
// Initialize the remapping of files to alternative contents, e.g., // those specified through other files. static void InitializeFileRemapping(DiagnosticsEngine &Diags, SourceManager &SourceMgr, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { // Remap files in the source manager (with buffers). for (PreprocessorOptions::const_remapped_file_buffer_iterator Remap = InitOpts.remapped_file_buffer_begin(), RemapEnd = InitOpts.remapped_file_buffer_end(); Remap != RemapEnd; ++Remap) { // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, Remap->second->getBufferSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << Remap->first; if (!InitOpts.RetainRemappedFileBuffers) delete Remap->second; continue; } // Override the contents of the "from" file with the contents of // the "to" file. SourceMgr.overrideFileContents(FromFile, Remap->second, InitOpts.RetainRemappedFileBuffers); } // Remap files in the source manager (with other files). for (PreprocessorOptions::const_remapped_file_iterator Remap = InitOpts.remapped_file_begin(), RemapEnd = InitOpts.remapped_file_end(); Remap != RemapEnd; ++Remap) { // Find the file that we're mapping to. const FileEntry *ToFile = FileMgr.getFile(Remap->second); if (!ToFile) { Diags.Report(diag::err_fe_remap_missing_to_file) << Remap->first << Remap->second; continue; } // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << Remap->first; continue; } // Override the contents of the "from" file with the contents of // the "to" file. SourceMgr.overrideFileContents(FromFile, ToFile); } SourceMgr.setOverridenFilesKeepOriginalName( InitOpts.RemappedFilesKeepOriginalName); }
bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { SrcMgr::CharacteristicKind Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind); assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; } StringRef InputFile = Input.getFile(); // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } // The natural SourceManager infrastructure can't currently handle named // pipes, but we would at least like to accept them for the main // file. Detect them here, read them with the more generic MemoryBuffer // function, and simply override their contents as we do for STDIN. if (File->isNamedPipe()) { OwningPtr<llvm::MemoryBuffer> MB; if (llvm::error_code ec = llvm::MemoryBuffer::getFile(InputFile, MB)) { Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message(); return false; } // Create a new virtual file that will have the correct size. File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0); SourceMgr.overrideFileContents(File, MB.take()); } SourceMgr.createMainFileID(File, Kind); } else { OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { // FIXME: Give ec.message() in this diag. Diags.Report(diag::err_fe_error_reading_stdin); return false; } const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), SB->getBufferSize(), 0); SourceMgr.createMainFileID(File, Kind); SourceMgr.overrideFileContents(File, SB.take()); } assert(!SourceMgr.getMainFileID().isInvalid() && "Couldn't establish MainFileID!"); return true; }
/// \brief Collect the set of header includes needed to construct the given /// module and update the TopHeaders file set of the module. /// /// \param Module The module we're collecting includes from. /// /// \param Includes Will be augmented with the set of \#includes or \#imports /// needed to load all of the named headers. static void collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) { // Don't collect any headers for unavailable modules. if (!Module->isAvailable()) return; // Add includes for each of these headers. for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) { const FileEntry *Header = Module->NormalHeaders[I]; Module->addTopHeader(Header); addHeaderInclude(Header, Includes, LangOpts); } // Note that Module->PrivateHeaders will not be a TopHeader. if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { Module->addTopHeader(UmbrellaHeader); if (Module->Parent) { // Include the umbrella header for submodules. addHeaderInclude(UmbrellaHeader, Includes, LangOpts); } } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) { // Add all of the headers we find in this subdirectory. llvm::error_code EC; SmallString<128> DirNative; llvm::sys::path::native(UmbrellaDir->getName(), DirNative); for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative.str(), EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { // Check whether this entry has an extension typically associated with // headers. if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path())) .Cases(".h", ".H", ".hh", ".hpp", true) .Default(false)) continue; // If this header is marked 'unavailable' in this module, don't include // it. if (const FileEntry *Header = FileMgr.getFile(Dir->path())) { if (ModMap.isHeaderInUnavailableModule(Header)) continue; Module->addTopHeader(Header); } // Include this header umbrella header for submodules. addHeaderInclude(Dir->path(), Includes, LangOpts); } } // Recurse into submodules. for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), SubEnd = Module->submodule_end(); Sub != SubEnd; ++Sub) collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub, Includes); }
ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) { if (!TopHeaderNames.empty()) { for (std::vector<std::string>::iterator I = TopHeaderNames.begin(), E = TopHeaderNames.end(); I != E; ++I) { if (const FileEntry *FE = FileMgr.getFile(*I)) TopHeaders.insert(FE); } TopHeaderNames.clear(); } return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end()); }
void testClang() { return; //maks:teste std::string InFile = "E:/GAMEDEVELOPMENT/output/dots.c"; // Create a file manager object to provide access to and cache the filesystem. FileManager FileMgr; char *PredefineBuffer = ""; ASTConsumer *consumer = new ASTDumper(); // Create the diagnostic client for reporting errors or for // implementing -verify. DiagnosticClient* TextDiagClient = 0; TextDiagClient = new TextDiagnosticPrinter(); llvm::OwningPtr<DiagnosticClient> DiagClient(TextDiagClient); Diagnostic Diags(DiagClient.get()); LangOptions LangInfo; SourceManager SourceMgr; HeaderSearch HeaderInfo(FileMgr); TargetInfo *Target; std::string Triple = CreateTargetTriple(); //llvm::OwningPtr<TargetInfo> Target(TargetInfo::CreateTargetInfo(Triple)); Target = TargetInfo::CreateTargetInfo(Triple); // Set up the preprocessor with these options. Preprocessor PP(Diags, LangInfo, *Target, SourceMgr, HeaderInfo); PP.setPredefines(PredefineBuffer); const FileEntry *File = FileMgr.getFile(InFile); if (File) SourceMgr.createMainFileID(File, SourceLocation()); ParseAST(PP, consumer, false); }
/// \brief Helper static function to normalize a path for injection into /// a synthetic header. /*static*/ std::string HeaderSearch::NormalizeDashIncludePath(StringRef File, FileManager &FileMgr) { // Implicit include paths should be resolved relative to the current // working directory first, and then use the regular header search // mechanism. The proper way to handle this is to have the // predefines buffer located at the current working directory, but // it has no file entry. For now, workaround this by using an // absolute path if we find the file here, and otherwise letting // header search handle it. SmallString<128> Path(File); llvm::sys::fs::make_absolute(Path); bool exists; if (llvm::sys::fs::exists(Path.str(), exists) || !exists) Path = File; else if (exists) FileMgr.getFile(File); return Lexer::Stringify(Path.str()); }
// Initialize the remapping of files to alternative contents, e.g., // those specified through other files. static void InitializeFileRemapping(Diagnostic &Diags, SourceManager &SourceMgr, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { // Remap files in the source manager. for (PreprocessorOptions::remapped_file_iterator Remap = InitOpts.remapped_file_begin(), RemapEnd = InitOpts.remapped_file_end(); Remap != RemapEnd; ++Remap) { // Find the file that we're mapping to. const FileEntry *ToFile = FileMgr.getFile(Remap->second); if (!ToFile) { Diags.Report(diag::err_fe_remap_missing_to_file) << Remap->first << Remap->second; continue; } // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << Remap->first; continue; } // Load the contents of the file we're mapping to. std::string ErrorStr; const llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); if (!Buffer) { Diags.Report(diag::err_fe_error_opening) << Remap->second << ErrorStr; continue; } // Override the contents of the "from" file with the contents of // the "to" file. SourceMgr.overrideFileContents(FromFile, Buffer); } }
int main() { llvm::raw_fd_ostream out_stream(1, false); DiagnosticOptions diag_options; TextDiagnosticPrinter *diagClient = new TextDiagnosticPrinter(out_stream, diag_options); Diagnostic diags(diagClient); LangOptions opts; TargetOptions target_opts; target_opts.Triple = LLVM_HOSTTRIPLE; TargetInfo *target = TargetInfo::CreateTargetInfo(diags, target_opts); FileManager fm; SourceManager sm(diags); HeaderSearch headers(fm); Preprocessor pp(diags, opts, *target, sm, headers); PreprocessorOptions preprocessor_options; HeaderSearchOptions header_search_options; FrontendOptions frontend_options; InitializePreprocessor( pp, preprocessor_options, header_search_options, frontend_options); FileEntry const *file = fm.getFile("test.cpp"); FileID main_file = sm.createMainFileID(file); diagClient->BeginSourceFile(opts, &pp); pp.EnterMainSourceFile(); bool invalid = false; llvm::StringRef sr = sm.getBufferData(main_file, &invalid); (void) sr; Token tok; do { pp.Lex(tok); if (diags.hasErrorOccurred()) { break; } pp.DumpToken(tok); cerr << endl; } while (tok.isNot(tok::eof)); }
GlobalModuleIndex::ErrorCode GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) { llvm::SmallString<128> IndexPath; IndexPath += Path; llvm::sys::path::append(IndexPath, IndexFileName); // Coordinate building the global index file with other processes that might // try to do the same. llvm::LockFileManager Locked(IndexPath); switch (Locked) { case llvm::LockFileManager::LFS_Error: return EC_IOError; case llvm::LockFileManager::LFS_Owned: // We're responsible for building the index ourselves. Do so below. break; case llvm::LockFileManager::LFS_Shared: // Someone else is responsible for building the index. We don't care // when they finish, so we're done. return EC_Building; } // The module index builder. GlobalModuleIndexBuilder Builder(FileMgr); // Load each of the module files. std::error_code EC; for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd; D != DEnd && !EC; D.increment(EC)) { // If this isn't a module file, we don't care. if (llvm::sys::path::extension(D->path()) != ".pcm") { // ... unless it's a .pcm.lock file, which indicates that someone is // in the process of rebuilding a module. They'll rebuild the index // at the end of that translation unit, so we don't have to. if (llvm::sys::path::extension(D->path()) == ".pcm.lock") return EC_Building; continue; } // If we can't find the module file, skip it. const FileEntry *ModuleFile = FileMgr.getFile(D->path()); if (!ModuleFile) continue; // Load this module file. if (Builder.loadModuleFile(ModuleFile)) return EC_IOError; } // The output buffer, into which the global index will be written. SmallVector<char, 16> OutputBuffer; { llvm::BitstreamWriter OutputStream(OutputBuffer); Builder.writeIndex(OutputStream); } // Write the global index file to a temporary file. llvm::SmallString<128> IndexTmpPath; int TmpFD; if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD, IndexTmpPath)) return EC_IOError; // Open the temporary global index file for output. llvm::raw_fd_ostream Out(TmpFD, true); if (Out.has_error()) return EC_IOError; // Write the index. Out.write(OutputBuffer.data(), OutputBuffer.size()); Out.close(); if (Out.has_error()) return EC_IOError; // Remove the old index file. It isn't relevant any more. llvm::sys::fs::remove(IndexPath.str()); // Rename the newly-written index file to the proper name. if (llvm::sys::fs::rename(IndexTmpPath.str(), IndexPath.str())) { // Rename failed; just remove the llvm::sys::fs::remove(IndexTmpPath.str()); return EC_IOError; } // We're done. return EC_None; }
TEST_F(TestClang, testParseAstFunction) { using clang::ASTContext; using clang::FileEntry; using clang::FileManager; using clang::HeaderSearch; using clang::IdentifierTable; using clang::LangOptions; using clang::Preprocessor; using clang::SelectorTable; using clang::SourceManager; using clang::TargetInfo; using clang::TargetOptions; // Create objects needed to create a preprocessor. LangOptions langOptions; langOptions.CPlusPlus = 1; // We will parse a C++ file. TargetOptions targetOptions; targetOptions.Triple = "x86_64"; // x86, ppc, ... auto_ptr<TargetInfo> targetInfo( TargetInfo::CreateTargetInfo(*diagnostic, targetOptions)); EXPECT_DIAGNOSTIC_IS_CLEAN; ASSERT_TRUE(0 != targetInfo.get()); SourceManager sourceManager(*diagnostic); FileManager fileManager; HeaderSearch headerSearch(fileManager); // Create a preprocessor. Preprocessor preprocessor(*diagnostic, langOptions, *targetInfo, sourceManager, headerSearch); EXPECT_DIAGNOSTIC_IS_CLEAN; // Create an ASTContext. IdentifierTable identifierTable(langOptions); SelectorTable selectorTable; clang::Builtin::Context builtinContext(*targetInfo); const unsigned int NumReserved = 10; ASTContext astContext(langOptions, sourceManager, *targetInfo, identifierTable, selectorTable, builtinContext, NumReserved); // Find a source file and add the source file to the source manager. const FileEntry* file = fileManager.getFile("a.cpp"); ASSERT_TRUE(0 != file); sourceManager.createMainFileID(file); // Create the AST consumer. MyAstConsumer consumer; // Parse the tree. clang::ParseAST(preprocessor, &consumer, astContext); EXPECT_DIAGNOSTIC_IS_CLEAN; // Check AST stats. EXPECT_EQ(1, consumer._astinfo._classCount); EXPECT_EQ(2, consumer._astinfo._fieldCount); EXPECT_EQ(1, consumer._astinfo._methodCount); EXPECT_EQ(1, consumer._astinfo._constructorCount); }
/// \brief Collect the set of header includes needed to construct the given /// module and update the TopHeaders file set of the module. /// /// \param Module The module we're collecting includes from. /// /// \param Includes Will be augmented with the set of \#includes or \#imports /// needed to load all of the named headers. static std::error_code collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) { // Don't collect any headers for unavailable modules. if (!Module->isAvailable()) return std::error_code(); // Add includes for each of these headers. for (Module::Header &H : Module->Headers[Module::HK_Normal]) { Module->addTopHeader(H.Entry); // Use the path as specified in the module map file. We'll look for this // file relative to the module build directory (the directory containing // the module map file) so this will find the same file that we found // while parsing the module map. if (std::error_code Err = addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC)) return Err; } // Note that Module->PrivateHeaders will not be a TopHeader. if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { // FIXME: Track the name as written here. Module->addTopHeader(UmbrellaHeader); if (Module->Parent) { // Include the umbrella header for submodules. if (std::error_code Err = addHeaderInclude(UmbrellaHeader, Includes, LangOpts, Module->IsExternC)) return Err; } } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) { // Add all of the headers we find in this subdirectory. std::error_code EC; SmallString<128> DirNative; llvm::sys::path::native(UmbrellaDir->getName(), DirNative); for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { // Check whether this entry has an extension typically associated with // headers. if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path())) .Cases(".h", ".H", ".hh", ".hpp", true) .Default(false)) continue; const FileEntry *Header = FileMgr.getFile(Dir->path()); // FIXME: This shouldn't happen unless there is a file system race. Is // that worth diagnosing? if (!Header) continue; // If this header is marked 'unavailable' in this module, don't include // it. if (ModMap.isHeaderUnavailableInModule(Header, Module)) continue; // Include this header as part of the umbrella directory. // FIXME: Track the name as written through to here. Module->addTopHeader(Header); if (std::error_code Err = addHeaderInclude(Header, Includes, LangOpts, Module->IsExternC)) return Err; } if (EC) return EC; } // Recurse into submodules. for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), SubEnd = Module->submodule_end(); Sub != SubEnd; ++Sub) if (std::error_code Err = collectModuleHeaderIncludes( LangOpts, FileMgr, ModMap, *Sub, Includes)) return Err; return std::error_code(); }
TEST_F(TestClang, testParseAstManual) { using clang::ASTContext; using clang::ASTConsumer; using clang::FileEntry; using clang::FileManager; using clang::HeaderSearch; using clang::IdentifierTable; using clang::LangOptions; using clang::Parser; using clang::Preprocessor; using clang::SelectorTable; using clang::Sema; using clang::SourceManager; using clang::TargetInfo; using clang::TargetOptions; // Create C++ language options. LangOptions langOptions; langOptions.CPlusPlus = 1; // Create target options. // There is no default target, we need to set a target manually. TargetOptions targetOptions; targetOptions.Triple = "x86_64"; auto_ptr<TargetInfo> targetInfo(TargetInfo::CreateTargetInfo(*diagnostic, targetOptions)); EXPECT_TRUE(0 != targetInfo.get()); EXPECT_DIAGNOSTIC_IS_CLEAN; // Create a source manager. SourceManager sourceManager(*diagnostic); EXPECT_DIAGNOSTIC_IS_CLEAN; // Create a file manager. FileManager fileManager; // Create a header searcher. HeaderSearch headerSearch(fileManager); // Create a preprocessor. Preprocessor preprocessor(*diagnostic, langOptions, *targetInfo, sourceManager, headerSearch); EXPECT_DIAGNOSTIC_IS_CLEAN; // Create an ASTContext. IdentifierTable identifierTable(langOptions); SelectorTable selectorTable; clang::Builtin::Context builtinContext(*targetInfo); const unsigned int NumReserved = 10; ASTContext astContext(langOptions, sourceManager, *targetInfo, identifierTable, selectorTable, builtinContext, NumReserved); // Create an AST consumer. clang::ASTConsumer consumer; // Create a semantic analyzer and an AST builder. Sema sema(preprocessor, astContext, consumer); EXPECT_DIAGNOSTIC_IS_CLEAN; // Create a parser. Parser parser(preprocessor, sema); EXPECT_DIAGNOSTIC_IS_CLEAN; // Find a source file. const FileEntry* file = fileManager.getFile("a.cpp"); ASSERT_TRUE(0 != file); // Add the source file to the source manager. //sourceManager.createMainFileID(file); parser.getActions().getSourceManager().createMainFileID(file); preprocessor.EnterMainSourceFile(); EXPECT_DIAGNOSTIC_IS_CLEAN; // Parse the file with the parser. parser.ParseTranslationUnit(); EXPECT_DIAGNOSTIC_IS_CLEAN; // Handle the whole tree. AstInfo astinfo; MyDeclVisitor visitor(llvm::errs(), astinfo); visitor.Visit(astContext.getTranslationUnitDecl()); // Check AST stats. EXPECT_EQ(1, astinfo._classCount); EXPECT_EQ(2, astinfo._fieldCount); EXPECT_EQ(1, astinfo._methodCount); EXPECT_EQ(1, astinfo._constructorCount); }
GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr, llvm::MemoryBuffer *Buffer, llvm::BitstreamCursor Cursor) : Buffer(Buffer), IdentifierIndex(), NumIdentifierLookups(), NumIdentifierLookupHits() { typedef llvm::DenseMap<unsigned, LoadedModuleInfo> LoadedModulesMap; LoadedModulesMap LoadedModules; // Read the global index. unsigned LargestID = 0; bool InGlobalIndexBlock = false; bool Done = false; bool AnyOutOfDate = false; while (!Done) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: return; case llvm::BitstreamEntry::EndBlock: if (InGlobalIndexBlock) { InGlobalIndexBlock = false; Done = true; continue; } return; case llvm::BitstreamEntry::Record: // Entries in the global index block are handled below. if (InGlobalIndexBlock) break; return; case llvm::BitstreamEntry::SubBlock: if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) return; InGlobalIndexBlock = true; } else if (Cursor.SkipBlock()) { return; } continue; } SmallVector<uint64_t, 64> Record; StringRef Blob; switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) { case INDEX_METADATA: // Make sure that the version matches. if (Record.size() < 1 || Record[0] != CurrentVersion) return; break; case MODULE: { unsigned Idx = 0; unsigned ID = Record[Idx++]; if (ID > LargestID) LargestID = ID; off_t Size = Record[Idx++]; time_t ModTime = Record[Idx++]; // File name. unsigned NameLen = Record[Idx++]; llvm::SmallString<64> FileName(Record.begin() + Idx, Record.begin() + Idx + NameLen); Idx += NameLen; // Dependencies unsigned NumDeps = Record[Idx++]; llvm::SmallVector<unsigned, 2> Dependencies(Record.begin() + Idx, Record.begin() + Idx + NumDeps); // Find the file. If we can't find it, ignore it. const FileEntry *File = FileMgr.getFile(FileName); if (!File) { AnyOutOfDate = true; break; } // If the module file is newer than the index, ignore it. if (File->getSize() != Size || File->getModificationTime() != ModTime) { AnyOutOfDate = true; break; } // Record this module. The dependencies will be resolved later. LoadedModuleInfo &Info = LoadedModules[ID]; Info.File = File; Info.Dependencies.swap(Dependencies); break; } case IDENTIFIER_INDEX: // Wire up the identifier index. if (Record[0]) { IdentifierIndex = IdentifierIndexTable::Create( (const unsigned char *)Blob.data() + Record[0], (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); } break; } } // If there are any modules that have gone out-of-date, prune out any modules // that depend on them. if (AnyOutOfDate) { // First, build back links in the module dependency graph. SmallVector<unsigned, 4> Stack; for (LoadedModulesMap::iterator LM = LoadedModules.begin(), LMEnd = LoadedModules.end(); LM != LMEnd; ++LM) { unsigned ID = LM->first; // If this module is out-of-date, push it onto the stack. if (LM->second.File == 0) Stack.push_back(ID); for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { unsigned DepID = LM->second.Dependencies[I]; LoadedModulesMap::iterator Known = LoadedModules.find(DepID); if (Known == LoadedModules.end() || !Known->second.File) { // The dependency was out-of-date, so mark us as out of date. // This is just an optimization. if (LM->second.File) Stack.push_back(ID); LM->second.File = 0; continue; } // Record this reverse dependency. Known->second.ImportedBy.push_back(ID); } } // Second, walk the back links from out-of-date modules to those modules // that depend on them, making those modules out-of-date as well. while (!Stack.empty()) { unsigned ID = Stack.back(); Stack.pop_back(); LoadedModuleInfo &Info = LoadedModules[ID]; for (unsigned I = 0, N = Info.ImportedBy.size(); I != N; ++I) { unsigned FromID = Info.ImportedBy[I]; if (LoadedModules[FromID].File) { LoadedModules[FromID].File = 0; Stack.push_back(FromID); } } } } // Allocate the vector containing information about all of the modules. Modules.resize(LargestID + 1); for (LoadedModulesMap::iterator LM = LoadedModules.begin(), LMEnd = LoadedModules.end(); LM != LMEnd; ++LM) { if (!LM->second.File) continue; Modules[LM->first].File = LM->second.File; // Resolve dependencies. Drop any we can't resolve due to out-of-date // module files. for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { unsigned DepID = LM->second.Dependencies[I]; LoadedModulesMap::iterator Known = LoadedModules.find(DepID); if (Known == LoadedModules.end() || !Known->second.File) continue; Modules[LM->first].Dependencies.push_back(Known->second.File); } } }
/// \brief Collect the set of header includes needed to construct the given /// module and update the TopHeaders file set of the module. /// /// \param Module The module we're collecting includes from. /// /// \param Includes Will be augmented with the set of \#includes or \#imports /// needed to load all of the named headers. static std::error_code collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) { // Don't collect any headers for unavailable modules. if (!Module->isAvailable()) return std::error_code(); // Add includes for each of these headers. for (auto HK : {Module::HK_Normal, Module::HK_Private}) { for (Module::Header &H : Module->Headers[HK]) { Module->addTopHeader(H.Entry); // Use the path as specified in the module map file. We'll look for this // file relative to the module build directory (the directory containing // the module map file) so this will find the same file that we found // while parsing the module map. addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); } } // Note that Module->PrivateHeaders will not be a TopHeader. if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { Module->addTopHeader(UmbrellaHeader.Entry); if (Module->Parent) // Include the umbrella header for submodules. addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, Module->IsExternC); } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { // Add all of the headers we find in this subdirectory. std::error_code EC; SmallString<128> DirNative; llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; Dir != End && !EC; Dir.increment(EC)) { // Check whether this entry has an extension typically associated with // headers. if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName())) .Cases(".h", ".H", ".hh", ".hpp", true) .Default(false)) continue; const FileEntry *Header = FileMgr.getFile(Dir->getName()); // FIXME: This shouldn't happen unless there is a file system race. Is // that worth diagnosing? if (!Header) continue; // If this header is marked 'unavailable' in this module, don't include // it. if (ModMap.isHeaderUnavailableInModule(Header, Module)) continue; // Compute the relative path from the directory to this file. SmallVector<StringRef, 16> Components; auto PathIt = llvm::sys::path::rbegin(Dir->getName()); for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) Components.push_back(*PathIt); SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); for (auto It = Components.rbegin(), End = Components.rend(); It != End; ++It) llvm::sys::path::append(RelativeHeader, *It); // Include this header as part of the umbrella directory. Module->addTopHeader(Header); addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); } if (EC) return EC; } // Recurse into submodules. for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), SubEnd = Module->submodule_end(); Sub != SubEnd; ++Sub) if (std::error_code Err = collectModuleHeaderIncludes( LangOpts, FileMgr, ModMap, *Sub, Includes)) return Err; return std::error_code(); }