// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gn/target_generator.h"

#include <stddef.h>

#include <memory>
#include <utility>

#include "gn/action_target_generator.h"
#include "gn/binary_target_generator.h"
#include "gn/build_settings.h"
#include "gn/bundle_data_target_generator.h"
#include "gn/config.h"
#include "gn/copy_target_generator.h"
#include "gn/create_bundle_target_generator.h"
#include "gn/err.h"
#include "gn/filesystem_utils.h"
#include "gn/functions.h"
#include "gn/generated_file_target_generator.h"
#include "gn/group_target_generator.h"
#include "gn/metadata.h"
#include "gn/parse_tree.h"
#include "gn/scheduler.h"
#include "gn/scope.h"
#include "gn/token.h"
#include "gn/value.h"
#include "gn/value_extractors.h"
#include "gn/variables.h"

TargetGenerator::TargetGenerator(Target* target,
                                 Scope* scope,
                                 const FunctionCallNode* function_call,
                                 Err* err)
    : target_(target),
      scope_(scope),
      function_call_(function_call),
      err_(err) {}

TargetGenerator::~TargetGenerator() = default;

void TargetGenerator::Run() {
  // All target types use these.
  if (!FillDependentConfigs())
    return;

  if (!FillData())
    return;

  if (!FillDependencies())
    return;

  if (!FillMetadata())
    return;

  if (!FillTestonly())
    return;

  if (!FillAssertNoDeps())
    return;

  if (!Visibility::FillItemVisibility(target_, scope_, err_))
    return;

  if (!FillWriteRuntimeDeps())
    return;

  // Do type-specific generation.
  DoRun();
}

// static
void TargetGenerator::GenerateTarget(Scope* scope,
                                     const FunctionCallNode* function_call,
                                     const std::vector<Value>& args,
                                     const std::string& output_type,
                                     Err* err) {
  // Name is the argument to the function.
  if (args.size() != 1u || args[0].type() != Value::STRING) {
    *err = Err(function_call, "Target generator requires one string argument.",
               "Otherwise I'm not sure what to call this target.");
    return;
  }

  // The location of the target is the directory name with no slash at the end.
  // FIXME(brettw) validate name.
  const Label& toolchain_label = ToolchainLabelForScope(scope);
  Label label(scope->GetSourceDir(), args[0].string_value(),
              toolchain_label.dir(), toolchain_label.name());

  if (g_scheduler->verbose_logging())
    g_scheduler->Log("Defining target", label.GetUserVisibleName(true));

  std::unique_ptr<Target> target = std::make_unique<Target>(
      scope->settings(), label, scope->build_dependency_files());
  target->set_defined_from(function_call);

  // Create and call out to the proper generator.
  if (output_type == functions::kBundleData) {
    BundleDataTargetGenerator generator(target.get(), scope, function_call,
                                        err);
    generator.Run();
  } else if (output_type == functions::kCreateBundle) {
    CreateBundleTargetGenerator generator(target.get(), scope, function_call,
                                          err);
    generator.Run();
  } else if (output_type == functions::kCopy) {
    CopyTargetGenerator generator(target.get(), scope, function_call, err);
    generator.Run();
  } else if (output_type == functions::kAction) {
    ActionTargetGenerator generator(target.get(), scope, function_call,
                                    Target::ACTION, err);
    generator.Run();
  } else if (output_type == functions::kActionForEach) {
    ActionTargetGenerator generator(target.get(), scope, function_call,
                                    Target::ACTION_FOREACH, err);
    generator.Run();
  } else if (output_type == functions::kExecutable) {
    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                    Target::EXECUTABLE, err);
    generator.Run();
  } else if (output_type == functions::kGroup) {
    GroupTargetGenerator generator(target.get(), scope, function_call, err);
    generator.Run();
  } else if (output_type == functions::kLoadableModule) {
    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                    Target::LOADABLE_MODULE, err);
    generator.Run();
  } else if (output_type == functions::kSharedLibrary) {
    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                    Target::SHARED_LIBRARY, err);
    generator.Run();
  } else if (output_type == functions::kSourceSet) {
    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                    Target::SOURCE_SET, err);
    generator.Run();
  } else if (output_type == functions::kStaticLibrary) {
    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                    Target::STATIC_LIBRARY, err);
    generator.Run();
  } else if (output_type == functions::kGeneratedFile) {
    GeneratedFileTargetGenerator generator(target.get(), scope, function_call,
                                           Target::GENERATED_FILE, err);
    generator.Run();
  } else if (output_type == functions::kRustLibrary) {
    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                    Target::RUST_LIBRARY, err);
    generator.Run();
  } else if (output_type == functions::kRustProcMacro) {
    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                    Target::RUST_PROC_MACRO, err);
    generator.Run();
  } else {
    *err = Err(function_call, "Not a known target type",
               "I am very confused by the target type \"" + output_type + "\"");
  }

  if (err->has_error())
    return;

  // Save this target for the file.
  Scope::ItemVector* collector = scope->GetItemCollector();
  if (!collector) {
    *err = Err(function_call, "Can't define a target in this context.");
    return;
  }
  collector->push_back(std::move(target));
}

const BuildSettings* TargetGenerator::GetBuildSettings() const {
  return scope_->settings()->build_settings();
}

bool TargetGenerator::FillSources() {
  const Value* value = scope_->GetValue(variables::kSources, true);
  if (!value)
    return true;

  Target::FileList dest_sources;
  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
                                  scope_->GetSourceDir(), &dest_sources, err_))
    return false;
  target_->sources() = std::move(dest_sources);
  return true;
}

bool TargetGenerator::FillPublic() {
  const Value* value = scope_->GetValue(variables::kPublic, true);
  if (!value)
    return true;

  // If the public headers are defined, don't default to public.
  target_->set_all_headers_public(false);

  Target::FileList dest_public;
  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
                                  scope_->GetSourceDir(), &dest_public, err_))
    return false;
  target_->public_headers() = std::move(dest_public);
  return true;
}

bool TargetGenerator::FillConfigs() {
  return FillGenericConfigs(variables::kConfigs, &target_->configs());
}

bool TargetGenerator::FillDependentConfigs() {
  if (!FillGenericConfigs(variables::kAllDependentConfigs,
                          &target_->all_dependent_configs()))
    return false;

  if (!FillGenericConfigs(variables::kPublicConfigs,
                          &target_->public_configs()))
    return false;

  return true;
}

bool TargetGenerator::FillData() {
  const Value* value = scope_->GetValue(variables::kData, true);
  if (!value)
    return true;
  if (!value->VerifyTypeIs(Value::LIST, err_))
    return false;

  const std::vector<Value>& input_list = value->list_value();
  std::vector<std::string>& output_list = target_->data();
  output_list.reserve(input_list.size());

  const SourceDir& dir = scope_->GetSourceDir();
  const std::string& root_path =
      scope_->settings()->build_settings()->root_path_utf8();

  for (size_t i = 0; i < input_list.size(); i++) {
    const Value& input = input_list[i];
    if (!input.VerifyTypeIs(Value::STRING, err_))
      return false;
    const std::string input_str = input.string_value();

    // Treat each input as either a file or a directory, depending on the
    // last character.
    bool as_dir = !input_str.empty() && input_str[input_str.size() - 1] == '/';

    std::string resolved =
        dir.ResolveRelativeAs(!as_dir, input, err_, root_path, &input_str);
    if (err_->has_error())
      return false;

    output_list.push_back(resolved);
  }
  return true;
}

bool TargetGenerator::FillDependencies() {
  if (!FillGenericDeps(variables::kDeps, &target_->private_deps()))
    return false;
  if (!FillGenericDeps(variables::kPublicDeps, &target_->public_deps()))
    return false;
  if (!FillGenericDeps(variables::kDataDeps, &target_->data_deps()))
    return false;

  // "data_deps" was previously named "datadeps". For backwards-compat, read
  // the old one if no "data_deps" were specified.
  if (!scope_->GetValue(variables::kDataDeps, false)) {
    if (!FillGenericDeps("datadeps", &target_->data_deps()))
      return false;
  }

  return true;
}

bool TargetGenerator::FillMetadata() {
  // Need to get a mutable value to mark all values in the scope as used. This
  // cannot be done on a const Scope.
  Value* value = scope_->GetMutableValue(variables::kMetadata,
                                         Scope::SEARCH_CURRENT, true);

  if (!value)
    return true;

  if (!value->VerifyTypeIs(Value::SCOPE, err_))
    return false;

  Scope* scope_value = value->scope_value();

  scope_value->GetCurrentScopeValues(&target_->metadata().contents());
  scope_value->MarkAllUsed();

  // Metadata values should always hold lists of Values, such that they can be
  // collected and concatenated. Any additional specific type verification is
  // done at walk time.
  for (const auto& iter : target_->metadata().contents()) {
    if (!iter.second.VerifyTypeIs(Value::LIST, err_))
      return false;
  }

  target_->metadata().set_source_dir(scope_->GetSourceDir());
  target_->metadata().set_origin(value->origin());
  return true;
}

bool TargetGenerator::FillTestonly() {
  const Value* value = scope_->GetValue(variables::kTestonly, true);
  if (value) {
    if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
      return false;
    target_->set_testonly(value->boolean_value());
  }
  return true;
}

bool TargetGenerator::FillAssertNoDeps() {
  const Value* value = scope_->GetValue(variables::kAssertNoDeps, true);
  if (value) {
    return ExtractListOfLabelPatterns(*value, scope_->GetSourceDir(),
                                      &target_->assert_no_deps(), err_);
  }
  return true;
}

bool TargetGenerator::FillOutputs(bool allow_substitutions) {
  const Value* value = scope_->GetValue(variables::kOutputs, true);
  if (!value)
    return true;

  SubstitutionList& outputs = target_->action_values().outputs();
  if (!outputs.Parse(*value, err_))
    return false;

  if (!allow_substitutions) {
    // Verify no substitutions were actually used.
    if (!outputs.required_types().empty()) {
      *err_ =
          Err(*value, "Source expansions not allowed here.",
              "The outputs of this target used source {{expansions}} but this "
              "target type\ndoesn't support them. Just express the outputs "
              "literally.");
      return false;
    }
  }

  // Check the substitutions used are valid for this purpose.
  if (!EnsureValidSubstitutions(outputs.required_types(),
                                &IsValidSourceSubstitution, value->origin(),
                                err_))
    return false;

  // Validate that outputs are in the output dir.
  CHECK(outputs.list().size() == value->list_value().size());
  for (size_t i = 0; i < outputs.list().size(); i++) {
    if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i],
                                         value->list_value()[i]))
      return false;
  }
  return true;
}

bool TargetGenerator::FillCheckIncludes() {
  const Value* value = scope_->GetValue(variables::kCheckIncludes, true);
  if (!value)
    return true;
  if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
    return false;
  target_->set_check_includes(value->boolean_value());
  return true;
}

bool TargetGenerator::FillOutputExtension() {
  const Value* value = scope_->GetValue(variables::kOutputExtension, true);
  if (!value)
    return true;
  if (!value->VerifyTypeIs(Value::STRING, err_))
    return false;
  target_->set_output_extension(value->string_value());
  return true;
}

bool TargetGenerator::EnsureSubstitutionIsInOutputDir(
    const SubstitutionPattern& pattern,
    const Value& original_value) {
  if (pattern.ranges().empty()) {
    // Pattern is empty, error out (this prevents weirdness below).
    *err_ = Err(original_value, "This has an empty value in it.");
    return false;
  }

  if (pattern.ranges()[0].type == &SubstitutionLiteral) {
    // If the first thing is a literal, it must start with the output dir.
    if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
                                   pattern.ranges()[0].literal,
                                   original_value.origin(), err_))
      return false;
  } else {
    // Otherwise, the first subrange must be a pattern that expands to
    // something in the output directory.
    if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) {
      *err_ =
          Err(original_value, "File is not inside output directory.",
              "The given file should be in the output directory. Normally you\n"
              "would specify\n\"$target_out_dir/foo\" or "
              "\"{{source_gen_dir}}/foo\".");
      return false;
    }
  }

  return true;
}

bool TargetGenerator::FillGenericConfigs(const char* var_name,
                                         UniqueVector<LabelConfigPair>* dest) {
  const Value* value = scope_->GetValue(var_name, true);
  if (value) {
    ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(),
                              ToolchainLabelForScope(scope_), dest, err_);
  }
  return !err_->has_error();
}

bool TargetGenerator::FillGenericDeps(const char* var_name,
                                      LabelTargetVector* dest) {
  const Value* value = scope_->GetValue(var_name, true);
  if (value) {
    ExtractListOfLabels(*value, scope_->GetSourceDir(),
                        ToolchainLabelForScope(scope_), dest, err_);
  }
  return !err_->has_error();
}

bool TargetGenerator::FillWriteRuntimeDeps() {
  const Value* value = scope_->GetValue(variables::kWriteRuntimeDeps, true);
  if (!value)
    return true;

  // Compute the file name and make sure it's in the output dir.
  SourceFile source_file = scope_->GetSourceDir().ResolveRelativeFile(
      *value, err_, GetBuildSettings()->root_path_utf8());
  if (err_->has_error())
    return false;
  if (!EnsureStringIsInOutputDir(GetBuildSettings()->build_dir(),
                                 source_file.value(), value->origin(), err_))
    return false;
  OutputFile output_file(GetBuildSettings(), source_file);
  target_->set_write_runtime_deps_output(output_file);

  return true;
}
