Beispiel #1
0
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;
}
Beispiel #2
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #9
0
/// \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);
}
Beispiel #10
0
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());
}
Beispiel #11
0
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);


}
Beispiel #12
0
/// \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());
}
Beispiel #13
0
// 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));
}
Beispiel #15
0
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);
}
Beispiel #19
0
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);
    }
  }
}
Beispiel #20
0
/// \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();
}