| Index: tools/gn/header_checker.cc
|
| diff --git a/tools/gn/header_checker.cc b/tools/gn/header_checker.cc
|
| index 4cdfc64ed6c647548fca3003ed63cd8363ab16b5..210bc5d37fe2f055f632d76efd7ae13c2376bde5 100644
|
| --- a/tools/gn/header_checker.cc
|
| +++ b/tools/gn/header_checker.cc
|
| @@ -67,72 +67,31 @@ LocationRange CreatePersistentRange(const InputFile& input_file,
|
| range.end().char_offset()));
|
| }
|
|
|
| -// Returns true if the given config could affect how the compiler runs (rather
|
| -// than being empty or just affecting linker flags).
|
| -bool ConfigHasCompilerSettings(const Config* config) {
|
| - const ConfigValues& values = config->config_values();
|
| - return
|
| - !values.cflags().empty() ||
|
| - !values.cflags_c().empty() ||
|
| - !values.cflags_cc().empty() ||
|
| - !values.cflags_objc().empty() ||
|
| - !values.cflags_objcc().empty() ||
|
| - !values.defines().empty() ||
|
| - !values.include_dirs().empty();
|
| -}
|
| -
|
| -// Returns true if the given target has any direct dependent configs with
|
| -// compiler settings in it.
|
| -bool HasDirectDependentCompilerSettings(const Target* target) {
|
| - const UniqueVector<LabelConfigPair>& direct =
|
| - target->direct_dependent_configs();
|
| - for (size_t i = 0; i < direct.size(); i++) {
|
| - if (ConfigHasCompilerSettings(direct[i].ptr))
|
| - return true;
|
| +// Given a reverse dependency chain where the target chain[0]'s includes are
|
| +// being used by chain[end] and not all deps are public, returns the string
|
| +// describing the error.
|
| +std::string GetDependencyChainPublicError(
|
| + const std::vector<const Target*>& chain) {
|
| + std::string ret = "The target " +
|
| + chain[chain.size() - 1]->label().GetUserVisibleName(false) + "\n" +
|
| + "is including a file in " + chain[0]->label().GetUserVisibleName(false) +
|
| + "\n";
|
| + if (chain.size() > 2) {
|
| + // Indirect dependency chain, print the chain.
|
| + ret += "\nIt's usually best to depend directly on the desination target.\n"
|
| + "In some cases, the detination target is considered a subcomponent\n"
|
| + "of an intermediate target. In this case, the intermediate target\n"
|
| + "should depend publicly on the destination to forward the ability\n"
|
| + "to include headers. Dependency chain (there may be others):\n";
|
| +
|
| + for (int i = static_cast<int>(chain.size()) - 1; i >= 0; i--) {
|
| + ret.append(" " + chain[i]->label().GetUserVisibleName(false));
|
| + if (i != 0)
|
| + ret.append(" ->");
|
| + ret.append("\n");
|
| + }
|
| }
|
| - return false;
|
| -}
|
| -
|
| -// Given a reverse dependency chain where the target chain[0]'s dependent
|
| -// configs don't apply to chain[end], returns the string describing the error.
|
| -// The problematic index is the target where the dependent configs were lost.
|
| -std::string GetDependentConfigChainError(
|
| - const std::vector<const Target*>& chain,
|
| - size_t problematic_index) {
|
| - // Erroneous dependent config chains are always at least three long, since
|
| - // dependent configs would apply if it was length two.
|
| - DCHECK(chain.size() >= 3);
|
| -
|
| - std::string from_label =
|
| - chain[chain.size() - 1]->label().GetUserVisibleName(false);
|
| - std::string to_label =
|
| - chain[0]->label().GetUserVisibleName(false);
|
| - std::string problematic_label =
|
| - chain[problematic_index]->label().GetUserVisibleName(false);
|
| - std::string problematic_upstream_label =
|
| - chain[problematic_index - 1]->label().GetUserVisibleName(false);
|
| -
|
| - return
|
| - "You have the dependency tree: SOURCE -> MID -> DEST\n"
|
| - "Where a file from:\n"
|
| - " SOURCE = " + from_label + "\n"
|
| - "is including a header from:\n"
|
| - " DEST = " + to_label + "\n"
|
| - "\n"
|
| - "DEST has direct_dependent_configs, and they don't apply to SOURCE "
|
| - "because\nSOURCE is more than one hop away. This means that DEST's "
|
| - "headers might not\nreceive the expected compiler flags.\n"
|
| - "\n"
|
| - "To fix this, make SOURCE depend directly on DEST.\n"
|
| - "\n"
|
| - "Alternatively, if the target:\n"
|
| - " MID = " + problematic_label + "\n"
|
| - "exposes DEST as part of its public API, you can declare this by "
|
| - "adding:\n"
|
| - " forward_dependent_configs_from = [\n"
|
| - " \"" + problematic_upstream_label + "\"\n"
|
| - " ]\n"
|
| - "to MID. This will apply DEST's direct dependent configs to SOURCE.\n";
|
| + return ret;
|
| }
|
|
|
| } // namespace
|
| @@ -340,7 +299,6 @@ bool HeaderChecker::CheckInclude(const Target* from_target,
|
|
|
| const TargetVector& targets = found->second;
|
| std::vector<const Target*> chain; // Prevent reallocating in the loop.
|
| - bool direct_dependent_configs_apply = false;
|
|
|
| // For all targets containing this file, we require that at least one be
|
| // a dependency of the current target, and all targets that are dependencies
|
| @@ -353,32 +311,12 @@ bool HeaderChecker::CheckInclude(const Target* from_target,
|
| if (to_target == from_target)
|
| return true;
|
|
|
| - bool has_direct_dependent_compiler_settings =
|
| - HasDirectDependentCompilerSettings(to_target);
|
| - if (IsDependencyOf(to_target,
|
| - from_target,
|
| - has_direct_dependent_compiler_settings,
|
| - &chain,
|
| - &direct_dependent_configs_apply)) {
|
| + bool is_public_dep_chain = false;
|
| + if (IsDependencyOf(to_target, from_target, &chain, &is_public_dep_chain)) {
|
| DCHECK(chain.size() >= 2);
|
| DCHECK(chain[0] == to_target);
|
| DCHECK(chain[chain.size() - 1] == from_target);
|
|
|
| - // The include is in a target that's a proper dependency. Verify that
|
| - // the including target has visibility.
|
| - if (!to_target->visibility().CanSeeMe(from_target->label())) {
|
| - std::string msg = "The included file is in " +
|
| - to_target->label().GetUserVisibleName(false) +
|
| - "\nwhich is not visible from " +
|
| - from_target->label().GetUserVisibleName(false) +
|
| - "\n(see \"gn help visibility\").";
|
| -
|
| - // Danger: must call CreatePersistentRange to put in Err.
|
| - *err = Err(CreatePersistentRange(source_file, range),
|
| - "Including a header from non-visible target.", msg);
|
| - return false;
|
| - }
|
| -
|
| // The file must be public in the target.
|
| if (!targets[i].is_public) {
|
| // Danger: must call CreatePersistentRange to put in Err.
|
| @@ -389,14 +327,11 @@ bool HeaderChecker::CheckInclude(const Target* from_target,
|
| return false;
|
| }
|
|
|
| - // If the to_target has direct_dependent_configs, they must apply to the
|
| - // from_target.
|
| - if (has_direct_dependent_compiler_settings &&
|
| - !direct_dependent_configs_apply) {
|
| - size_t problematic_index = GetDependentConfigChainProblemIndex(chain);
|
| + // The dependency chain must be public.
|
| + if (!is_public_dep_chain) {
|
| *err = Err(CreatePersistentRange(source_file, range),
|
| "Can't include this header from here.",
|
| - GetDependentConfigChainError(chain, problematic_index));
|
| + GetDependencyChainPublicError(chain));
|
| return false;
|
| }
|
|
|
| @@ -429,10 +364,10 @@ bool HeaderChecker::CheckInclude(const Target* from_target,
|
| // One thing we didn't check for is targets that expose their dependents
|
| // headers in their own public headers.
|
| //
|
| - // Say we have A -> B -> C. If C has direct_dependent_configs, everybody
|
| - // getting headers from C should get the configs also or things could be
|
| - // out-of-sync. Above, we check for A including C's headers directly, but A
|
| - // could also include a header from B that in turn includes a header from C.
|
| + // Say we have A -> B -> C. If C has public_configs, everybody getting headers
|
| + // from C should get the configs also or things could be out-of-sync. Above,
|
| + // we check for A including C's headers directly, but A could also include a
|
| + // header from B that in turn includes a header from C.
|
| //
|
| // There are two ways to solve this:
|
| // - If a public header in B includes C, force B to forward C's direct
|
| @@ -450,33 +385,33 @@ bool HeaderChecker::CheckInclude(const Target* from_target,
|
|
|
| bool HeaderChecker::IsDependencyOf(const Target* search_for,
|
| const Target* search_from,
|
| - bool prefer_direct_dependent_configs,
|
| std::vector<const Target*>* chain,
|
| - bool* direct_dependent_configs_apply) const {
|
| - if (search_for == search_from)
|
| + bool* is_public) const {
|
| + if (search_for == search_from) {
|
| + // A target is always visible from itself.
|
| + *is_public = true;
|
| return false;
|
| + }
|
|
|
| - // Find the shortest chain that forwards dependent configs, if one exists.
|
| - if (prefer_direct_dependent_configs &&
|
| - IsDependencyOf(search_for, search_from, true, chain)) {
|
| - if (direct_dependent_configs_apply)
|
| - *direct_dependent_configs_apply = true;
|
| + // Find the shortest public dependency chain.
|
| + if (IsDependencyOf(search_for, search_from, true, chain)) {
|
| + *is_public = true;
|
| return true;
|
| }
|
|
|
| // If not, try to find any dependency chain at all.
|
| if (IsDependencyOf(search_for, search_from, false, chain)) {
|
| - if (direct_dependent_configs_apply)
|
| - *direct_dependent_configs_apply = false;
|
| + *is_public = false;
|
| return true;
|
| }
|
|
|
| + *is_public = false;
|
| return false;
|
| }
|
|
|
| bool HeaderChecker::IsDependencyOf(const Target* search_for,
|
| const Target* search_from,
|
| - bool requires_dependent_configs,
|
| + bool require_public,
|
| std::vector<const Target*>* chain) const {
|
| // This method conducts a breadth-first search through the dependency graph
|
| // to find a shortest chain from search_from to search_for.
|
| @@ -511,52 +446,24 @@ bool HeaderChecker::IsDependencyOf(const Target* search_for,
|
| return true;
|
| }
|
|
|
| - // If the callee requires direct-dependent configs be forwarded, then
|
| - // only targets for which they will be forwarded should be explored.
|
| - // Groups implicitly forward direct-dependent configs of all of their deps.
|
| - bool uses_all_deps = !requires_dependent_configs || target == search_from ||
|
| - target->output_type() == Target::GROUP;
|
| -
|
| - const LabelTargetVector& deps =
|
| - uses_all_deps ? target->deps()
|
| - : target->forward_dependent_configs().vector();
|
| - for (size_t i = 0; i < deps.size(); i++) {
|
| - bool seeing_for_first_time =
|
| - breadcrumbs.insert(std::make_pair(deps[i].ptr, target)).second;
|
| - if (seeing_for_first_time)
|
| - work_queue.push(deps[i].ptr);
|
| + // Always consider public dependencies as possibilities.
|
| + const LabelTargetVector& public_deps = target->public_deps();
|
| + for (size_t i = 0; i < public_deps.size(); i++) {
|
| + if (breadcrumbs.insert(std::make_pair(public_deps[i].ptr, target)).second)
|
| + work_queue.push(public_deps[i].ptr);
|
| }
|
| - }
|
| -
|
| - return false;
|
| -}
|
|
|
| -// static
|
| -size_t HeaderChecker::GetDependentConfigChainProblemIndex(
|
| - const std::vector<const Target*>& chain) {
|
| - // Direct dependent configs go up the chain one level with the following
|
| - // exceptions:
|
| - // - Skip over groups
|
| - // - Skip anything that explicitly forwards it
|
| -
|
| - // Chains of length less than three have no problems.
|
| - // These should have been filtered out earlier.
|
| - DCHECK(chain.size() >= 3);
|
| -
|
| - for (size_t i = 1; i < chain.size() - 1; i++) {
|
| - if (chain[i]->output_type() == Target::GROUP)
|
| - continue; // This one is OK, skip to next one.
|
| -
|
| - // The forward list on this target should have contained in it the target
|
| - // at the next lower level.
|
| - const UniqueVector<LabelTargetPair>& forwarded =
|
| - chain[i]->forward_dependent_configs();
|
| - if (std::find_if(forwarded.begin(), forwarded.end(),
|
| - LabelPtrPtrEquals<Target>(chain[i - 1])) ==
|
| - forwarded.end())
|
| - return i;
|
| + if (!require_public) {
|
| + // Consider all dependencies since all target paths are allowed, so add
|
| + // in private ones.
|
| + const LabelTargetVector& private_deps = target->private_deps();
|
| + for (size_t i = 0; i < private_deps.size(); i++) {
|
| + if (breadcrumbs.insert(std::make_pair(private_deps[i].ptr, target))
|
| + .second)
|
| + work_queue.push(private_deps[i].ptr);
|
| + }
|
| + }
|
| }
|
|
|
| - CHECK(false) << "Unable to diagnose dependent config chain problem.";
|
| - return 0;
|
| + return false;
|
| }
|
|
|