1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef TOOLS_GN_HEADER_CHECKER_H_
6#define TOOLS_GN_HEADER_CHECKER_H_
7
8#include <map>
9#include <set>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/ref_counted.h"
15#include "base/run_loop.h"
16#include "base/strings/string_piece.h"
17#include "base/synchronization/lock.h"
18#include "tools/gn/err.h"
19
20class BuildSettings;
21class InputFile;
22class Label;
23class LocationRange;
24class SourceFile;
25class Target;
26
27namespace base {
28class MessageLoop;
29}
30
31class HeaderChecker : public base::RefCountedThreadSafe<HeaderChecker> {
32 public:
33  // Represents a dependency chain.
34  struct ChainLink {
35    ChainLink() : target(NULL), is_public(false) {}
36    ChainLink(const Target* t, bool p) : target(t), is_public(p) {}
37
38    const Target* target;
39
40    // True when the dependency on this target is public.
41    bool is_public;
42
43    // Used for testing.
44    bool operator==(const ChainLink& other) const {
45      return target == other.target && is_public == other.is_public;
46    }
47  };
48  typedef std::vector<ChainLink> Chain;
49
50  HeaderChecker(const BuildSettings* build_settings,
51                const std::vector<const Target*>& targets);
52
53  // Runs the check. The targets in to_check will be checked. If this list is
54  // empty, all targets will be checked.
55  //
56  // This assumes that the current thread already has a message loop. On
57  // error, fills the given vector with the errors and returns false. Returns
58  // true on success.
59  //
60  // force_check, if true, will override targets opting out of header checking
61  // with "check_includes = false" and will check them anyway.
62  bool Run(const std::vector<const Target*>& to_check,
63           bool force_check,
64           std::vector<Err>* errors);
65
66 private:
67  friend class base::RefCountedThreadSafe<HeaderChecker>;
68  FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, IsDependencyOf);
69  FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, CheckInclude);
70  FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, PublicFirst);
71  FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, CheckIncludeAllowCircular);
72  ~HeaderChecker();
73
74  struct TargetInfo {
75    TargetInfo() : target(NULL), is_public(false), is_generated(false) {}
76    TargetInfo(const Target* t, bool is_pub, bool is_gen)
77        : target(t),
78          is_public(is_pub),
79          is_generated(is_gen) {
80    }
81
82    const Target* target;
83
84    // True if the file is public in the given target.
85    bool is_public;
86
87    // True if this file is generated and won't actually exist on disk.
88    bool is_generated;
89  };
90
91  typedef std::vector<TargetInfo> TargetVector;
92  typedef std::map<SourceFile, TargetVector> FileMap;
93
94  // Backend for Run() that takes the list of files to check. The errors_ list
95  // will be populate on failure.
96  void RunCheckOverFiles(const FileMap& flies, bool force_check);
97
98  void DoWork(const Target* target, const SourceFile& file);
99
100  // Adds the sources and public files from the given target to the given map.
101  static void AddTargetToFileMap(const Target* target, FileMap* dest);
102
103  // Returns true if the given file is in the output directory.
104  bool IsFileInOuputDir(const SourceFile& file) const;
105
106  // Resolves the contents of an include to a SourceFile.
107  SourceFile SourceFileForInclude(const base::StringPiece& input) const;
108
109  // from_target is the target the file was defined from. It will be used in
110  // error messages.
111  bool CheckFile(const Target* from_target,
112                 const SourceFile& file,
113                 Err* err) const;
114
115  // Checks that the given file in the given target can include the given
116  // include file. If disallowed, returns false and sets the error. The
117  // range indicates the location of the include in the file for error
118  // reporting.
119  bool CheckInclude(const Target* from_target,
120                    const InputFile& source_file,
121                    const SourceFile& include_file,
122                    const LocationRange& range,
123                    Err* err) const;
124
125  // Returns true if the given search_for target is a dependency of
126  // search_from.
127  //
128  // If found, the vector given in "chain" will be filled with the reverse
129  // dependency chain from the dest target (chain[0] = search_for) to the src
130  // target (chain[chain.size() - 1] = search_from).
131  //
132  // Chains with permitted dependencies will be considered first. If a
133  // permitted match is found, *is_permitted will be set to true. A chain with
134  // indirect, non-public dependencies will only be considered if there are no
135  // public or direct chains. In this case, *is_permitted will be false.
136  //
137  // A permitted dependency is a sequence of public dependencies. The first
138  // one may be private, since a direct dependency always allows headers to be
139  // included.
140  bool IsDependencyOf(const Target* search_for,
141                      const Target* search_from,
142                      Chain* chain,
143                      bool* is_permitted) const;
144
145  // For internal use by the previous override of IsDependencyOf.  If
146  // require_public is true, only public dependency chains are searched.
147  bool IsDependencyOf(const Target* search_for,
148                      const Target* search_from,
149                      bool require_permitted,
150                      Chain* chain) const;
151
152  // Non-locked variables ------------------------------------------------------
153  //
154  // These are initialized during construction (which happens on one thread)
155  // and are not modified after, so any thread can read these without locking.
156
157  base::MessageLoop* main_loop_;
158  base::RunLoop main_thread_runner_;
159
160  const BuildSettings* build_settings_;
161
162  // Maps source files to targets it appears in (usually just one target).
163  FileMap file_map_;
164
165  // Locked variables ----------------------------------------------------------
166  //
167  // These are mutable during runtime and require locking.
168
169  base::Lock lock_;
170
171  std::vector<Err> errors_;
172
173  DISALLOW_COPY_AND_ASSIGN(HeaderChecker);
174};
175
176#endif  // TOOLS_GN_HEADER_CHECKER_H_
177