OLD | NEW |
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 } |
OLD | NEW |