Repository: carbon-language/carbon-lang
File: toolchain/check/cpp/generate_ast.cpp (C++)

Code before:
  explicit GenerateASTAction(Context& context) : context_(&context) {}

 protected:
  auto CreateASTConsumer(clang::CompilerInstance& /*clang_instance*/,
                         llvm::StringRef /*file*/)
      -> std::unique_ptr<clang::ASTConsumer> override {
    return std::make_unique<BufferingConsumer>(*context_->sem_ir().cpp_file());
  }

  auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/)
      -> bool override {
    // TODO: Consider creating an `ExternalSemaSource` here and attaching it to
    // the compilation.
    // TODO: `clang.getPreprocessor().enableIncrementalProcessing();` to avoid
    // the TU scope getting torn down before we're done parsing macros.
    return true;
  }

  auto ExecuteAction() -> void override {
    clang::CompilerInstance& clang_instance = getCompilerInstance();
    clang_instance.createSema(getTranslationUnitKind(),
                              /*CompletionConsumer=*/nullptr);

    // Parse the imports and inline C++ fragments. This is notionally very
    // similar to `ParseAST`, but doesn't parse C++20 modules and stops just
    // before reaching the end of the translation unit.

    context_->cpp_context()->set_parser(std::make_unique<clang::Parser>(
        clang_instance.getPreprocessor(), clang_instance.getSema(),
        /*SkipFunctionBodies=*/false));
    auto& parser = context_->cpp_context()->parser();

    clang_instance.getPreprocessor().EnterMainSourceFile();
    if (auto* source = clang_instance.getASTContext().getExternalSource()) {
      source->StartTranslationUnit(&clang_instance.getASTConsumer());
    }

    parser.Initialize();
    clang_instance.getSema().ActOnStartOfTranslationUnit();

    // Don't allow C++20 module declarations in inline Cpp code fragments.
    auto module_import_state = clang::Sema::ModuleImportState::NotACXX20Module;

    // Parse top-level declarations until we see EOF. Do not parse EOF, as that
    // will cause the parser to end the translation unit prematurely.
    while (parser.getCurToken().isNot(clang::tok::eof)) {
      clang::Parser::DeclGroupPtrTy decl_group;
      bool eof = parser.ParseTopLevelDecl(decl_group, module_import_state);
      CARBON_CHECK(!eof);
      if (decl_group && !clang_instance.getASTConsumer().HandleTopLevelDecl(
                            decl_group.get())) {

Review comment (refactor):
Perhaps move this to be a function comment? I'm not sure if it's just understood what `ExecuteAction` is expected to do.

Code after:
  explicit GenerateASTAction(Context& context) : context_(&context) {}

 protected:
  auto CreateASTConsumer(clang::CompilerInstance& /*clang_instance*/,
                         llvm::StringRef /*file*/)
      -> std::unique_ptr<clang::ASTConsumer> override {
    return std::make_unique<BufferingConsumer>(*context_->sem_ir().cpp_file());
  }

  auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/)
      -> bool override {
    // TODO: Consider creating an `ExternalSemaSource` here and attaching it to
    // the compilation.
    // TODO: `clang.getPreprocessor().enableIncrementalProcessing();` to avoid
    // the TU scope getting torn down before we're done parsing macros.
    return true;
  }

  // Parse the imports and inline C++ fragments. This is notionally very similar
  // to `clang::ParseAST`, which `ASTFrontendAction::ExecuteAction` calls, but
  // this version doesn't parse C++20 modules and stops just before reaching the
  // end of the translation unit.
  auto ExecuteAction() -> void override {
    clang::CompilerInstance& clang_instance = getCompilerInstance();
    clang_instance.createSema(getTranslationUnitKind(),
                              /*CompletionConsumer=*/nullptr);

    context_->cpp_context()->set_parser(std::make_unique<clang::Parser>(
        clang_instance.getPreprocessor(), clang_instance.getSema(),
        /*SkipFunctionBodies=*/false));
    auto& parser = context_->cpp_context()->parser();

    clang_instance.getPreprocessor().EnterMainSourceFile();
    if (auto* source = clang_instance.getASTContext().getExternalSource()) {
      source->StartTranslationUnit(&clang_instance.getASTConsumer());
    }

    parser.Initialize();
    clang_instance.getSema().ActOnStartOfTranslationUnit();

    // Don't allow C++20 module declarations in inline Cpp code fragments.
    auto module_import_state = clang::Sema::ModuleImportState::NotACXX20Module;

    // Parse top-level declarations until we see EOF. Do not parse EOF, as that
    // will cause the parser to end the translation unit prematurely.
    while (parser.getCurToken().isNot(clang::tok::eof)) {
      clang::Parser::DeclGroupPtrTy decl_group;
      bool eof = parser.ParseTopLevelDecl(decl_group, module_import_state);
      CARBON_CHECK(!eof);
      if (decl_group && !clang_instance.getASTConsumer().HandleTopLevelDecl(
                            decl_group.get())) {