Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(980)

Side by Side Diff: tools/gn/visibility.cc

Issue 500423003: Enhance GN diagnostic tools (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: use patterns for gn check Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/visibility.h ('k') | tools/gn/visibility_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/gn/visibility.h" 5 #include "tools/gn/visibility.h"
6 6
7 #include "base/strings/string_piece.h" 7 #include "base/strings/string_piece.h"
8 #include "base/strings/string_util.h" 8 #include "base/strings/string_util.h"
9 #include "tools/gn/err.h" 9 #include "tools/gn/err.h"
10 #include "tools/gn/filesystem_utils.h" 10 #include "tools/gn/filesystem_utils.h"
11 #include "tools/gn/item.h" 11 #include "tools/gn/item.h"
12 #include "tools/gn/label.h" 12 #include "tools/gn/label.h"
13 #include "tools/gn/scope.h" 13 #include "tools/gn/scope.h"
14 #include "tools/gn/value.h" 14 #include "tools/gn/value.h"
15 #include "tools/gn/variables.h" 15 #include "tools/gn/variables.h"
16 16
17 Visibility::VisPattern::VisPattern() : type_(MATCH) {
18 }
19
20 Visibility::VisPattern::VisPattern(Type type,
21 const SourceDir& dir,
22 const base::StringPiece& name)
23 : type_(type),
24 dir_(dir) {
25 name.CopyToString(&name_);
26 }
27
28 Visibility::VisPattern::~VisPattern() {
29 }
30
31 bool Visibility::VisPattern::Matches(const Label& label) const {
32 switch (type_) {
33 case MATCH:
34 return label.name() == name_ && label.dir() == dir_;
35 case DIRECTORY:
36 // The directories must match exactly for private visibility.
37 return label.dir() == dir_;
38 case RECURSIVE_DIRECTORY:
39 // Our directory must be a prefix of the input label for recursive
40 // private visibility.
41 return label.dir().value().compare(0, dir_.value().size(), dir_.value())
42 == 0;
43 default:
44 NOTREACHED();
45 return false;
46 }
47 }
48
49 Visibility::Visibility() { 17 Visibility::Visibility() {
50 } 18 }
51 19
52 Visibility::~Visibility() { 20 Visibility::~Visibility() {
53 } 21 }
54 22
55 bool Visibility::Set(const SourceDir& current_dir, 23 bool Visibility::Set(const SourceDir& current_dir,
56 const Value& value, 24 const Value& value,
57 Err* err) { 25 Err* err) {
58 patterns_.clear(); 26 patterns_.clear();
59 27
60 // Allow a single string to be passed in to make the common case (just one 28 // Allow a single string to be passed in to make the common case (just one
61 // pattern) easier to specify. 29 // pattern) easier to specify.
62 if (value.type() == Value::STRING) { 30 if (value.type() == Value::STRING) {
63 patterns_.push_back(GetPattern(current_dir, value, err)); 31 patterns_.push_back(LabelPattern::GetPattern(current_dir, value, err));
64 return !err->has_error(); 32 return !err->has_error();
65 } 33 }
66 34
67 // If it's not a string, it should be a list of strings. 35 // If it's not a string, it should be a list of strings.
68 if (!value.VerifyTypeIs(Value::LIST, err)) 36 if (!value.VerifyTypeIs(Value::LIST, err))
69 return false; 37 return false;
70 38
71 const std::vector<Value>& list = value.list_value(); 39 const std::vector<Value>& list = value.list_value();
72 for (size_t i = 0; i < list.size(); i++) { 40 for (size_t i = 0; i < list.size(); i++) {
73 patterns_.push_back(GetPattern(current_dir, list[i], err)); 41 patterns_.push_back(LabelPattern::GetPattern(current_dir, list[i], err));
74 if (err->has_error()) 42 if (err->has_error())
75 return false; 43 return false;
76 } 44 }
77 return true; 45 return true;
78 } 46 }
79 47
80 void Visibility::SetPublic() { 48 void Visibility::SetPublic() {
81 patterns_.clear(); 49 patterns_.clear();
82 patterns_.push_back( 50 patterns_.push_back(
83 VisPattern(VisPattern::RECURSIVE_DIRECTORY, SourceDir(), std::string())); 51 LabelPattern(LabelPattern::RECURSIVE_DIRECTORY, SourceDir(),
52 std::string(), Label()));
84 } 53 }
85 54
86 void Visibility::SetPrivate(const SourceDir& current_dir) { 55 void Visibility::SetPrivate(const SourceDir& current_dir) {
87 patterns_.clear(); 56 patterns_.clear();
88 patterns_.push_back( 57 patterns_.push_back(
89 VisPattern(VisPattern::DIRECTORY, current_dir, std::string())); 58 LabelPattern(LabelPattern::DIRECTORY, current_dir, std::string(),
59 Label()));
90 } 60 }
91 61
92 bool Visibility::CanSeeMe(const Label& label) const { 62 bool Visibility::CanSeeMe(const Label& label) const {
93 for (size_t i = 0; i < patterns_.size(); i++) { 63 for (size_t i = 0; i < patterns_.size(); i++) {
94 if (patterns_[i].Matches(label)) 64 if (patterns_[i].Matches(label))
95 return true; 65 return true;
96 } 66 }
97 return false; 67 return false;
98 } 68 }
99 69
100 std::string Visibility::Describe(int indent, bool include_brackets) const { 70 std::string Visibility::Describe(int indent, bool include_brackets) const {
101 std::string outer_indent_string(indent, ' '); 71 std::string outer_indent_string(indent, ' ');
102 72
103 if (patterns_.empty()) 73 if (patterns_.empty())
104 return outer_indent_string + "[] (no visibility)\n"; 74 return outer_indent_string + "[] (no visibility)\n";
105 75
106 std::string result; 76 std::string result;
107 77
108 std::string inner_indent_string = outer_indent_string; 78 std::string inner_indent_string = outer_indent_string;
109 if (include_brackets) { 79 if (include_brackets) {
110 result += outer_indent_string + "[\n"; 80 result += outer_indent_string + "[\n";
111 // Indent the insides more if brackets are requested. 81 // Indent the insides more if brackets are requested.
112 inner_indent_string += " "; 82 inner_indent_string += " ";
113 } 83 }
114 84
115 for (size_t i = 0; i < patterns_.size(); i++) { 85 for (size_t i = 0; i < patterns_.size(); i++)
116 switch (patterns_[i].type()) { 86 result += inner_indent_string + patterns_[i].Describe() + "\n";
117 case VisPattern::MATCH:
118 result += inner_indent_string +
119 DirectoryWithNoLastSlash(patterns_[i].dir()) + ":" +
120 patterns_[i].name() + "\n";
121 break;
122 case VisPattern::DIRECTORY:
123 result += inner_indent_string +
124 DirectoryWithNoLastSlash(patterns_[i].dir()) + ":*\n";
125 break;
126 case VisPattern::RECURSIVE_DIRECTORY:
127 result += inner_indent_string + patterns_[i].dir().value() + "*\n";
128 break;
129 }
130 }
131 87
132 if (include_brackets) 88 if (include_brackets)
133 result += outer_indent_string + "]\n"; 89 result += outer_indent_string + "]\n";
134 return result; 90 return result;
135 } 91 }
136 92
137 // static 93 // static
138 Visibility::VisPattern Visibility::GetPattern(const SourceDir& current_dir,
139 const Value& value,
140 Err* err) {
141 if (!value.VerifyTypeIs(Value::STRING, err))
142 return VisPattern();
143
144 const std::string& str = value.string_value();
145 if (str.empty()) {
146 *err = Err(value, "Visibility pattern must not be empty.");
147 return VisPattern();
148 }
149
150 // If there's no wildcard, this is specifying an exact label, use the
151 // label resolution code to get all the implicit name stuff.
152 size_t star = str.find('*');
153 if (star == std::string::npos) {
154 Label label = Label::Resolve(current_dir, Label(), value, err);
155 if (err->has_error())
156 return VisPattern();
157
158 // There should be no toolchain specified.
159 if (!label.toolchain_dir().is_null() || !label.toolchain_name().empty()) {
160 *err = Err(value, "Visibility label specified a toolchain.",
161 "Visibility names and patterns don't use toolchains, erase the\n"
162 "stuff in the ().");
163 return VisPattern();
164 }
165
166 return VisPattern(VisPattern::MATCH, label.dir(), label.name());
167 }
168
169 // Wildcard case, need to split apart the label to see what it specifies.
170 base::StringPiece path;
171 base::StringPiece name;
172 size_t colon = str.find(':');
173 if (colon == std::string::npos) {
174 path = base::StringPiece(str);
175 } else {
176 path = base::StringPiece(&str[0], colon);
177 name = base::StringPiece(&str[colon + 1], str.size() - colon - 1);
178 }
179
180 // The path can have these forms:
181 // 1. <empty> (use current dir)
182 // 2. <non wildcard stuff> (send through directory resolution)
183 // 3. <non wildcard stuff>* (send stuff through dir resolution, note star)
184 // 4. * (matches anything)
185 SourceDir dir;
186 bool has_path_star = false;
187 if (path.empty()) {
188 // Looks like ":foo".
189 dir = current_dir;
190 } else if (path[path.size() - 1] == '*') {
191 // Case 3 or 4 above.
192 has_path_star = true;
193
194 // Adjust path to contain everything but the star.
195 path = path.substr(0, path.size() - 1);
196
197 if (!path.empty() && path[path.size() - 1] != '/') {
198 // The input was "foo*" which is invalid.
199 *err = Err(value, "'*' must match full directories in visibility.",
200 "You did \"foo*\" but visibility doesn't do general pattern\n"
201 "matching. Instead, you have to add a slash: \"foo/*\".");
202 return VisPattern();
203 }
204 }
205
206 // Resolve the part of the path that's not the wildcard.
207 if (!path.empty()) {
208 // The non-wildcard stuff better not have a wildcard.
209 if (path.find('*') != base::StringPiece::npos) {
210 *err = Err(value, "Visibility patterns only support wildcard suffixes.",
211 "The visibility pattern contained a '*' that wasn't at tne end.");
212 return VisPattern();
213 }
214
215 // Resolve the non-wildcard stuff.
216 dir = current_dir.ResolveRelativeDir(path);
217 if (dir.is_null()) {
218 *err = Err(value, "Visibility pattern didn't resolve to a dir.",
219 "The directory name \"" + path.as_string() + "\" didn't\n"
220 "resolve to a directory.");
221 return VisPattern();
222 }
223 }
224
225 // Resolve the name. At this point, we're doing wildcard matches so the
226 // name should either be empty ("foo/*") or a wildcard ("foo:*");
227 if (colon != std::string::npos && name != "*") {
228 *err = Err(value, "Invalid visibility pattern.",
229 "You seem to be using the wildcard more generally that is supported.\n"
230 "Did you mean \"foo:*\" to match everything in the current file, or\n"
231 "\"./*\" to recursively match everything in the currend subtree.");
232 return VisPattern();
233 }
234
235 VisPattern::Type type;
236 if (has_path_star) {
237 // We know there's a wildcard, so if the name is empty it looks like
238 // "foo/*".
239 type = VisPattern::RECURSIVE_DIRECTORY;
240 } else {
241 // Everything else should be of the form "foo:*".
242 type = VisPattern::DIRECTORY;
243 }
244
245 // When we're doing wildcard matching, the name is always empty.
246 return VisPattern(type, dir, base::StringPiece());
247 }
248
249 // static
250 bool Visibility::CheckItemVisibility(const Item* from, 94 bool Visibility::CheckItemVisibility(const Item* from,
251 const Item* to, 95 const Item* to,
252 Err* err) { 96 Err* err) {
253 if (!to->visibility().CanSeeMe(from->label())) { 97 if (!to->visibility().CanSeeMe(from->label())) {
254 std::string to_label = to->label().GetUserVisibleName(false); 98 std::string to_label = to->label().GetUserVisibleName(false);
255 *err = Err(from->defined_from(), "Dependency not allowed.", 99 *err = Err(from->defined_from(), "Dependency not allowed.",
256 "The item " + from->label().GetUserVisibleName(false) + "\n" 100 "The item " + from->label().GetUserVisibleName(false) + "\n"
257 "can not depend on " + to_label + "\n" 101 "can not depend on " + to_label + "\n"
258 "because it is not in " + to_label + "'s visibility list: " + 102 "because it is not in " + to_label + "'s visibility list: " +
259 to->visibility().Describe(0, true)); 103 to->visibility().Describe(0, true));
260 return false; 104 return false;
261 } 105 }
262 return true; 106 return true;
263 } 107 }
264 108
265 // static 109 // static
266 bool Visibility::FillItemVisibility(Item* item, Scope* scope, Err* err) { 110 bool Visibility::FillItemVisibility(Item* item, Scope* scope, Err* err) {
267 const Value* vis_value = scope->GetValue(variables::kVisibility, true); 111 const Value* vis_value = scope->GetValue(variables::kVisibility, true);
268 if (vis_value) 112 if (vis_value)
269 item->visibility().Set(scope->GetSourceDir(), *vis_value, err); 113 item->visibility().Set(scope->GetSourceDir(), *vis_value, err);
270 else // Default to public. 114 else // Default to public.
271 item->visibility().SetPublic(); 115 item->visibility().SetPublic();
272 return !err->has_error(); 116 return !err->has_error();
273 } 117 }
OLDNEW
« no previous file with comments | « tools/gn/visibility.h ('k') | tools/gn/visibility_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698