/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file LICENSE.rst or https://cmake.org/licensing for details.  */
/* clang-format off */
#include "cmGeneratorTarget.h"
/* clang-format on */

#include <algorithm>
#include <array>
#include <initializer_list>
#include <map>
#include <ostream>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include <cm/memory>
#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>

#include "cmFileSetMetadata.h"
#include "cmGenExContext.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorFileSet.h"
#include "cmGlobalGenerator.h"
#include "cmList.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetLinkLibraryType.h"
#include "cmTargetTypes.h"
#include "cmValue.h"

bool cmGeneratorTarget::AddHeaderSetVerification()
{
  for (bool const isInterface : { false, true }) {
    if (!this->GetPropertyAsBool(isInterface ? "VERIFY_INTERFACE_HEADER_SETS"
                                             : "VERIFY_PRIVATE_HEADER_SETS")) {
      continue;
    }

    if (this->GetType() != cm::TargetType::STATIC_LIBRARY &&
        this->GetType() != cm::TargetType::SHARED_LIBRARY &&
        (this->GetType() != cm::TargetType::MODULE_LIBRARY || isInterface) &&
        this->GetType() != cm::TargetType::UNKNOWN_LIBRARY &&
        this->GetType() != cm::TargetType::OBJECT_LIBRARY &&
        this->GetType() != cm::TargetType::INTERFACE_LIBRARY &&
        this->GetType() != cm::TargetType::EXECUTABLE) {
      continue;
    }

    char const* headerSetsProperty = isInterface
      ? "INTERFACE_HEADER_SETS_TO_VERIFY"
      : "PRIVATE_HEADER_SETS_TO_VERIFY";

    auto verifyValue = this->GetProperty(headerSetsProperty);
    bool const all = verifyValue.IsEmpty();
    std::set<std::string> verifySet;
    if (!all) {
      cmList verifyList{ verifyValue };
      verifySet.insert(verifyList.begin(), verifyList.end());
    }

    cmTarget* verifyTarget = nullptr;
    std::string const verifyTargetName =
      cmStrCat(this->GetName(),
               isInterface ? "_verify_interface_header_sets"
                           : "_verify_private_header_sets");

    char const* allVerifyTargetName = isInterface
      ? "all_verify_interface_header_sets"
      : "all_verify_private_header_sets";
    cmTarget* allVerifyTarget =
      this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse(
        allVerifyTargetName, { cm::TargetDomain::NATIVE });

    auto fileSetEntries = isInterface
      ? this->GetInterfaceFileSets(cm::FileSetMetadata::HEADERS)
      : this->GetFileSets(cm::FileSetMetadata::HEADERS);

    std::set<cmGeneratorFileSet const*> fileSets;
    for (auto const& fileSet : fileSetEntries) {
      if (all || verifySet.count(fileSet->GetName())) {
        verifySet.erase(fileSet->GetName());
        if (fileSet->GetProperty("SKIP_LINTING").IsOn()) {
          continue;
        }
        fileSets.insert(fileSet);
      }
    }

    if (isInterface) {
      cmPolicies::PolicyStatus const cmp0209 = this->GetPolicyStatusCMP0209();
      if (cmp0209 != cmPolicies::NEW &&
          this->GetType() == cm::TargetType::EXECUTABLE &&
          !this->GetPropertyAsBool("ENABLE_EXPORTS")) {
        if (cmp0209 == cmPolicies::WARN && !fileSets.empty()) {
          this->Makefile->IssuePolicyWarning(
            cmPolicies::CMP0209, {},
            cmStrCat("Executable target \""_s, this->GetName(),
                     "\" has interface header file sets, but it does not "
                     "enable exports. Those headers would be verified under "
                     "CMP0209 NEW behavior.\n"_s));
        }
        continue;
      }
    }

    if (!verifySet.empty()) {
      this->Makefile->IssueMessage(
        MessageType::FATAL_ERROR,
        cmStrCat("Property ", headerSetsProperty, " of target \"",
                 this->GetName(),
                 "\" contained the following header sets that are nonexistent "
                 "or not ",
                 isInterface ? "INTERFACE" : "PRIVATE", ":\n  ",
                 cmJoin(verifySet, "\n  ")));
      return false;
    }

    cm::optional<cm::optional<std::string>> defaultLanguage;

    // First, collect all verification stubs before creating the target,
    // so we know whether to create an OBJECT library or not.
    std::vector<std::string> stubSources;
    for (auto const* fileSet : fileSets) {
      auto const& dirCges = fileSet->CompileDirectoryEntries();
      auto const& fileCges = fileSet->CompileFileEntries();

      static auto const contextSensitive =
        [](std::unique_ptr<cmCompiledGeneratorExpression> const& cge) {
          return cge->GetHadContextSensitiveCondition();
        };
      bool dirCgesContextSensitive = false;
      bool fileCgesContextSensitive = false;

      std::vector<std::string> dirs;
      std::map<std::string, std::vector<std::string>> filesPerDir;
      bool first = true;
      for (auto const& config : this->Makefile->GetGeneratorConfigs(
             cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) {
        cm::GenEx::Context context(this->LocalGenerator, config);
        if (first || dirCgesContextSensitive) {
          dirs = fileSet->EvaluateDirectoryEntries(dirCges, context, this);
          dirCgesContextSensitive =
            std::any_of(dirCges.begin(), dirCges.end(), contextSensitive);
        }
        if (first || fileCgesContextSensitive) {
          filesPerDir.clear();
          for (auto const& fileCge : fileCges) {
            fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, context,
                                       this);
            if (fileCge->GetHadContextSensitiveCondition()) {
              fileCgesContextSensitive = true;
            }
          }
        }

        for (auto const& files : filesPerDir) {
          for (auto const& file : files.second) {
            cm::optional<std::string> filenameOpt =
              this->GenerateHeaderSetVerificationFile(
                *this->Makefile->GetOrCreateSource(file), files.first,
                verifyTargetName, defaultLanguage);
            if (!filenameOpt) {
              continue;
            }
            std::string filename = *filenameOpt;

            if (fileCgesContextSensitive) {
              filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, '>');
            }
            stubSources.emplace_back(std::move(filename));
          }
        }

        if (!dirCgesContextSensitive && !fileCgesContextSensitive) {
          break;
        }
        first = false;
      }
    }

    if (stubSources.empty()) {
      // No headers to verify. Create a utility target so the target
      // name always exists (e.g. for build system dependencies) without
      // needing a placeholder source. This avoids warnings from tools
      // like Xcode's libtool about empty static libraries.
      verifyTarget =
        this->Makefile->AddNewUtilityTarget(verifyTargetName, true);
    } else {
      // Create an OBJECT library to compile the verification stubs.
      {
        cmMakefile::PolicyPushPop polScope(this->Makefile);
        this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW);
        verifyTarget = this->Makefile->AddLibrary(
          verifyTargetName, cm::TargetType::OBJECT_LIBRARY, {}, true);
      }

      if (isInterface) {
        // Link to the original target so that we pick up its
        // interface compile options just like a consumer would.
        // This also ensures any generated headers in the original
        // target will be created.
        verifyTarget->AddLinkLibrary(
          *this->Makefile, this->GetName(),
          cmTargetLinkLibraryType::GENERAL_LibraryType);
      } else {
        // For private file sets, we need to simulate compiling the
        // same way as the original target. That includes linking to
        // the same things so we pick up the same transitive
        // properties. For the <LANG>_... properties, we don't care if
        // we set them for languages this target won't eventually use.
        // Copy language-standard properties for all supported
        // languages. We don't care if we set properties for languages
        // this target won't eventually use.
        static std::array<std::string, 19> const propertiesToCopy{ {
          "COMPILE_DEFINITIONS",    "COMPILE_FEATURES",
          "COMPILE_FLAGS",          "COMPILE_OPTIONS",
          "DEFINE_SYMBOL",          "INCLUDE_DIRECTORIES",
          "LINK_LIBRARIES",         "C_STANDARD",
          "C_STANDARD_REQUIRED",    "C_EXTENSIONS",
          "CXX_STANDARD",           "CXX_STANDARD_REQUIRED",
          "CXX_EXTENSIONS",         "OBJC_STANDARD",
          "OBJC_STANDARD_REQUIRED", "OBJC_EXTENSIONS",
          "OBJCXX_STANDARD",        "OBJCXX_STANDARD_REQUIRED",
          "OBJCXX_EXTENSIONS",
        } };
        for (std::string const& prop : propertiesToCopy) {
          cmValue propValue = this->Target->GetProperty(prop);
          if (propValue.IsSet()) {
            verifyTarget->SetProperty(prop, propValue);
          }
        }
        // The original target might have generated headers. Since
        // we only link to the original target for compilation,
        // there's nothing to force such generation to happen yet.
        // Our verify target must depend on the original target to
        // ensure such generated files will be created.
        verifyTarget->AddUtility(this->GetName(), false, this->Makefile);
        verifyTarget->AddCodegenDependency(this->GetName());
      }

      verifyTarget->SetProperty("AUTOMOC", "OFF");
      verifyTarget->SetProperty("AUTORCC", "OFF");
      verifyTarget->SetProperty("AUTOUIC", "OFF");
      verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
      verifyTarget->SetProperty("UNITY_BUILD", "OFF");
      verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF");

      if (isInterface) {
        verifyTarget->FinalizeTargetConfiguration(
          this->Makefile->GetCompileDefinitionsEntries());
      } else {
        // Private verification only needs to add the directory scope
        // definitions here
        for (auto const& def :
             this->Makefile->GetCompileDefinitionsEntries()) {
          verifyTarget->InsertCompileDefinition(def);
        }
      }

      for (auto const& source : stubSources) {
        verifyTarget->AddSource(source);
      }
    }
    if (!allVerifyTarget) {
      allVerifyTarget =
        this->GlobalGenerator->GetMakefiles().front()->AddNewUtilityTarget(
          allVerifyTargetName, true);
    }
    allVerifyTarget->AddUtility(verifyTargetName, false);

    this->LocalGenerator->AddGeneratorTarget(
      cm::make_unique<cmGeneratorTarget>(verifyTarget, this->LocalGenerator));
  }
  return true;
}

cm::optional<std::string> cmGeneratorTarget::GenerateHeaderSetVerificationFile(
  cmSourceFile& source, std::string const& dir,
  std::string const& verifyTargetName,
  cm::optional<cm::optional<std::string>>& defaultLanguage) const
{
  if (source.GetPropertyAsBool("SKIP_LINTING")) {
    return cm::nullopt;
  }

  cm::optional<std::string> language =
    this->ResolveHeaderLanguage(source, defaultLanguage);
  if (!language) {
    return cm::nullopt;
  }

  std::string headerFilename = dir;
  if (!headerFilename.empty()) {
    headerFilename += '/';
  }
  headerFilename += source.GetLocation().GetName();

  return this->GenerateStubForLanguage(*language, headerFilename,
                                       verifyTargetName, source);
}

cm::optional<std::string> cmGeneratorTarget::ResolveHeaderLanguage(
  cmSourceFile& source,
  cm::optional<cm::optional<std::string>>& defaultLanguage) const
{
  static std::array<cm::string_view, 4> const supportedLangs{ {
    "C",
    "CXX",
    "OBJC",
    "OBJCXX",
  } };
  auto isSupported = [](cm::string_view lang) -> bool {
    return std::find(supportedLangs.begin(), supportedLangs.end(), lang) !=
      supportedLangs.end();
  };

  // If the source has an explicit language, validate and return it.
  std::string language = source.GetOrDetermineLanguage();
  if (!language.empty()) {
    if (!isSupported(language)) {
      return cm::nullopt;
    }
    return cm::optional<std::string>(std::move(language));
  }

  /*
    Compute and cache the default language for unlanguaged headers.
    The lattice join is run once per file set, not once per header.
    Lattice:   OBJCXX
              /      \
            CXX      OBJC
              \      /
                 C
  */
  if (!defaultLanguage) {
    std::set<std::string> langs;
    for (AllConfigSource const& tgtSource : this->GetAllConfigSources()) {
      std::string const& lang = tgtSource.Source->GetOrDetermineLanguage();
      if (isSupported(lang)) {
        langs.insert(lang);
      }
    }
    if (langs.empty()) {
      std::vector<std::string> languagesVector;
      this->GlobalGenerator->GetEnabledLanguages(languagesVector);
      for (std::string const& lang : languagesVector) {
        if (isSupported(lang)) {
          langs.insert(lang);
        }
      }
    }

    cm::optional<std::string> resolved;
    if (langs.count("OBJCXX") || (langs.count("CXX") && langs.count("OBJC"))) {
      resolved = "OBJCXX"; // promote
    } else if (langs.count("CXX")) {
      resolved = "CXX";
    } else if (langs.count("OBJC")) {
      resolved = "OBJC";
    } else if (langs.count("C")) {
      resolved = "C";
    }
    defaultLanguage = resolved;
  }

  return *defaultLanguage;
}

cm::optional<std::string> cmGeneratorTarget::GenerateStubForLanguage(
  std::string const& language, std::string const& headerFilename,
  std::string const& verifyTargetName, cmSourceFile& source) const
{
  static std::array<std::pair<cm::string_view, cm::string_view>, 4> const
    langToExt = { {
      { "C", ".c" },
      { "CXX", ".cxx" },
      { "OBJC", ".m" },
      { "OBJCXX", ".mm" },
    } };

  // NOLINTNEXTLINE(readability-qualified-auto)
  auto const it =
    std::find_if(langToExt.begin(), langToExt.end(),
                 [&](std::pair<cm::string_view, cm::string_view> const& p) {
                   return p.first == language;
                 });
  if (it == langToExt.end()) {
    return cm::nullopt;
  }

  std::string filename =
    cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
             verifyTargetName, '/', headerFilename, it->second);

  cmSourceFile* verificationSource =
    this->Makefile->GetOrCreateSource(filename);
  source.SetSpecialSourceType(
    cmSourceFile::SpecialSourceType::HeaderSetVerificationSource);
  verificationSource->SetProperty("LANGUAGE", language);

  cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(filename));

  cmGeneratedFileStream fout(filename);
  fout.SetCopyIfDifferent(true);
  // The IWYU "associated" pragma tells include-what-you-use to
  // consider the headerFile as part of the entire language
  // unit within include-what-you-use and as a result allows
  // one to get IWYU advice for headers.
  // Also suppress clang-tidy include checks in generated code.
  fout
    << "/* NOLINTNEXTLINE(misc-header-include-cycle,misc-include-cleaner) */\n"
    << "#include <" << headerFilename << "> /* IWYU pragma: associated */\n";
  fout.close();

  return cm::optional<std::string>(std::move(filename));
}
