ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
    CompilerInstance *CI,
    IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
    : Recorder(llvm::make_unique<FileRecorder>()), Compiler(*CI),
      InMemoryFs(new llvm::vfs::InMemoryFileSystem),
      Sources(Compiler.getSourceManager()),
      // Forward the new diagnostics to the original DiagnosticConsumer.
      Diags(new DiagnosticIDs, new DiagnosticOptions,
            new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
      LangOpts(Compiler.getLangOpts()) {
  // Add a FileSystem containing the extra files needed in place of modular
  // headers.
  OverlayFS->pushOverlay(InMemoryFs);

  Diags.setSourceManager(&Sources);

  LangOpts.Modules = false;

  auto HSO = std::make_shared<HeaderSearchOptions>();
  *HSO = Compiler.getHeaderSearchOpts();

  HeaderInfo = llvm::make_unique<HeaderSearch>(HSO, Sources, Diags, LangOpts,
                                               &Compiler.getTarget());

  auto PO = std::make_shared<PreprocessorOptions>();
  *PO = Compiler.getPreprocessorOpts();

  PP = llvm::make_unique<clang::Preprocessor>(PO, Diags, LangOpts, Sources,
                                              *HeaderInfo, ModuleLoader,
                                              /*IILookup=*/nullptr,
                                              /*OwnsHeaderSearch=*/false);
  PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
  InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
                         Compiler.getFrontendOpts());
  ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
                           Compiler.getTarget().getTriple());
}
int main(int argc, const char **argv, char * const *envp)
{
    // Path
    void *MainAddr = (void*) (intptr_t) GetExecutablePath;
    llvm::sys::Path Path = GetExecutablePath(argv[0]);

    // DiagnosticOptions
    DiagnosticOptions diagnosticOptions;

    // DiagnosticClient
    TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::outs(), diagnosticOptions);

    // Diagnostic
    llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    Diagnostic diagnostic(DiagID, DiagClient);


    //DiagnosticOptions DiagOpts;
    //llvm::IntrusiveRefCntPtr<Diagnostic> diagnostic = CompilerInstance::createDiagnostics(DiagOpts, argc, argv);

    // LangOptions
    LangOptions langOptions;
    langOptions.CPlusPlus = 1;
    langOptions.CPlusPlus0x = 1;
    langOptions.Microsoft = 1;
    langOptions.Bool = 1;
    langOptions.Exceptions = 1;
    langOptions.CXXExceptions = 1;
    langOptions.EmitAllDecls = 1;

    // FileManager
    FileSystemOptions fileSystemOptions;
    FileManager fileManager(fileSystemOptions);

    // SourceManager
    SourceManager sourceManager(diagnostic, fileManager);

    // HeadderSearch
    HeaderSearch headerSearch(fileManager);

    // TargetOptions
    TargetOptions targetOptions;
    targetOptions.Triple = llvm::sys::getHostTriple();

    // TargetInfo
    TargetInfo *pTargetInfo =
        TargetInfo::CreateTargetInfo(
            diagnostic,
            targetOptions);

    // HeaderSearchOptions
    HeaderSearchOptions headerSearchOptions;
    ApplyHeaderSearchOptions(
        headerSearch,
        headerSearchOptions,
        langOptions,
        pTargetInfo->getTriple());

    // Preprocessor
    Preprocessor preprocessor(
        diagnostic,
        langOptions,
        *pTargetInfo,
        sourceManager,
        headerSearch);

    // PreprocessorOptions
    PreprocessorOptions preprocessorOptions;
    preprocessorOptions.DetailedRecord = true;
    preprocessor.createPreprocessingRecord();

    // FrontendOptions
    FrontendOptions frontendOptions;


    // InitializePreprocessor
    InitializePreprocessor(
        preprocessor,
        preprocessorOptions,
        headerSearchOptions,
        frontendOptions);

    //preprocessor.SetCommentRetentionState(true, true);

    // Tutorial
    const FileEntry *pFile = fileManager.getFile(
                                 "test.cpp",
                                 true);
    sourceManager.createMainFileID(pFile);


    /*preprocessor.EnterMainSourceFile();
    Token Tok;
    do {
    	preprocessor.Lex(Tok);  // read one token
    	//if (context.diags.hasErrorOccurred())  // stop lexing/pp on error
    	//	break;
    	preprocessor.DumpToken(Tok);  // outputs to cerr
    	std::cerr << std::endl;
    } while (Tok.isNot(tok::eof));*/


    const TargetInfo &targetInfo = *pTargetInfo;

    IdentifierTable identifierTable(langOptions);
    SelectorTable selectorTable;

    Builtin::Context builtinContext(targetInfo);
    ASTContext astContext(
        langOptions,
        sourceManager,
        targetInfo,
        identifierTable,
        selectorTable,
        builtinContext,
        0 /* size_reserve*/);
    // ASTConsumer astConsumer;
    MyASTConsumer astConsumer;
    astConsumer.sourceManager = &sourceManager;
    astConsumer.html = new ClangDocHTML;
    astConsumer.html->astConsumer = &astConsumer;
    preprocessor.addPPCallbacks(astConsumer.html);
    preprocessor.AddCommentHandler(astConsumer.html);

    Sema sema(
        preprocessor,
        astContext,
        astConsumer);
    sema.Initialize();

    //MySemanticAnalisys mySema( preprocessor, astContext, astConsumer);

    //Parser parser( preprocessor, sema);
    //parser.ParseTranslationUnit();
    astConsumer.preprocessor = &sema.PP;
    ParseAST(preprocessor, &astConsumer, astContext);
    return 0;
}