// 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 "tools/gn/target_generator.h"

#include <stddef.h>

#include <memory>
#include <utility>

#include "tools/gn/action_target_generator.h"
#include "tools/gn/binary_target_generator.h"
#include "tools/gn/build_settings.h"
#include "tools/gn/bundle_data_target_generator.h"
#include "tools/gn/config.h"
#include "tools/gn/copy_target_generator.h"
#include "tools/gn/create_bundle_target_generator.h"
#include "tools/gn/err.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/functions.h"
#include "tools/gn/generated_file_target_generator.h"
#include "tools/gn/group_target_generator.h"
#include "tools/gn/metadata.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/scheduler.h"
#include "tools/gn/scope.h"
#include "tools/gn/token.h"
#include "tools/gn/value.h"
#include "tools/gn/value_extractors.h"
#include "tools/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 {
    *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().swap(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().swap(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::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;
}
