Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / gn / visibility.cc
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 #include "tools/gn/visibility.h"
6
7 #include "base/strings/string_piece.h"
8 #include "base/strings/string_util.h"
9 #include "tools/gn/err.h"
10 #include "tools/gn/filesystem_utils.h"
11 #include "tools/gn/item.h"
12 #include "tools/gn/label.h"
13 #include "tools/gn/scope.h"
14 #include "tools/gn/value.h"
15 #include "tools/gn/variables.h"
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() {
50 }
51
52 Visibility::~Visibility() {
53 }
54
55 bool Visibility::Set(const SourceDir& current_dir,
56                      const Value& value,
57                      Err* err) {
58   patterns_.clear();
59
60   // Allow a single string to be passed in to make the common case (just one
61   // pattern) easier to specify.
62   if (value.type() == Value::STRING) {
63     patterns_.push_back(GetPattern(current_dir, value, err));
64     return !err->has_error();
65   }
66
67   // If it's not a string, it should be a list of strings.
68   if (!value.VerifyTypeIs(Value::LIST, err))
69     return false;
70
71   const std::vector<Value>& list = value.list_value();
72   for (size_t i = 0; i < list.size(); i++) {
73     patterns_.push_back(GetPattern(current_dir, list[i], err));
74     if (err->has_error())
75       return false;
76   }
77   return true;
78 }
79
80 void Visibility::SetPublic() {
81   patterns_.clear();
82   patterns_.push_back(
83       VisPattern(VisPattern::RECURSIVE_DIRECTORY, SourceDir(), std::string()));
84 }
85
86 void Visibility::SetPrivate(const SourceDir& current_dir) {
87   patterns_.clear();
88   patterns_.push_back(
89       VisPattern(VisPattern::DIRECTORY, current_dir, std::string()));
90 }
91
92 bool Visibility::CanSeeMe(const Label& label) const {
93   for (size_t i = 0; i < patterns_.size(); i++) {
94     if (patterns_[i].Matches(label))
95       return true;
96   }
97   return false;
98 }
99
100 std::string Visibility::Describe() const {
101   if (patterns_.empty())
102     return std::string("[] (no visibility)");
103   std::string result = "[\n";
104
105   for (size_t i = 0; i < patterns_.size(); i++) {
106     switch (patterns_[i].type()) {
107       case VisPattern::MATCH:
108         result += "  " + patterns_[i].dir().value() + ":" +
109             patterns_[i].name() + "\n";
110         break;
111       case VisPattern::DIRECTORY:
112         result += "  " + DirectoryWithNoLastSlash(patterns_[i].dir()) +
113             ":*\n";
114         break;
115       case VisPattern::RECURSIVE_DIRECTORY:
116         result += "  " + patterns_[i].dir().value() + "*\n";
117         break;
118     }
119   }
120
121   result += "]";
122   return result;
123 }
124
125 // static
126 Visibility::VisPattern Visibility::GetPattern(const SourceDir& current_dir,
127                                               const Value& value,
128                                               Err* err) {
129   if (!value.VerifyTypeIs(Value::STRING, err))
130     return VisPattern();
131
132   const std::string& str = value.string_value();
133   if (str.empty()) {
134     *err = Err(value, "Visibility pattern must not be empty.");
135     return VisPattern();
136   }
137
138   // If there's no wildcard, this is specifying an exact label, use the
139   // label resolution code to get all the implicit name stuff.
140   size_t star = str.find('*');
141   if (star == std::string::npos) {
142     Label label = Label::Resolve(current_dir, Label(), value, err);
143     if (err->has_error())
144       return VisPattern();
145
146     // There should be no toolchain specified.
147     if (!label.toolchain_dir().is_null() || !label.toolchain_name().empty()) {
148       *err = Err(value, "Visibility label specified a toolchain.",
149           "Visibility names and patterns don't use toolchains, erase the\n"
150           "stuff in the ().");
151       return VisPattern();
152     }
153
154     return VisPattern(VisPattern::MATCH, label.dir(), label.name());
155   }
156
157   // Wildcard case, need to split apart the label to see what it specifies.
158   base::StringPiece path;
159   base::StringPiece name;
160   size_t colon = str.find(':');
161   if (colon == std::string::npos) {
162     path = base::StringPiece(str);
163   } else {
164     path = base::StringPiece(&str[0], colon);
165     name = base::StringPiece(&str[colon + 1], str.size() - colon - 1);
166   }
167
168   // The path can have these forms:
169   //   1. <empty>  (use current dir)
170   //   2. <non wildcard stuff>  (send through directory resolution)
171   //   3. <non wildcard stuff>*  (send stuff through dir resolution, note star)
172   //   4. *  (matches anything)
173   SourceDir dir;
174   bool has_path_star = false;
175   if (path.empty()) {
176     // Looks like ":foo".
177     dir = current_dir;
178   } else if (path[path.size() - 1] == '*') {
179     // Case 3 or 4 above.
180     has_path_star = true;
181
182     // Adjust path to contain everything but the star.
183     path = path.substr(0, path.size() - 1);
184
185     if (!path.empty() && path[path.size() - 1] != '/') {
186       // The input was "foo*" which is invalid.
187       *err = Err(value, "'*' must match full directories in visibility.",
188           "You did \"foo*\" but visibility doesn't do general pattern\n"
189           "matching. Instead, you have to add a slash: \"foo/*\".");
190       return VisPattern();
191     }
192   }
193
194   // Resolve the part of the path that's not the wildcard.
195   if (!path.empty()) {
196     // The non-wildcard stuff better not have a wildcard.
197     if (path.find('*') != base::StringPiece::npos) {
198       *err = Err(value, "Visibility patterns only support wildcard suffixes.",
199           "The visibility pattern contained a '*' that wasn't at tne end.");
200       return VisPattern();
201     }
202
203     // Resolve the non-wildcard stuff.
204     dir = current_dir.ResolveRelativeDir(path);
205     if (dir.is_null()) {
206       *err = Err(value, "Visibility pattern didn't resolve to a dir.",
207           "The directory name \"" + path.as_string() + "\" didn't\n"
208           "resolve to a directory.");
209       return VisPattern();
210     }
211   }
212
213   // Resolve the name. At this point, we're doing wildcard matches so the
214   // name should either be empty ("foo/*") or a wildcard ("foo:*");
215   if (colon != std::string::npos && name != "*") {
216     *err = Err(value, "Invalid visibility pattern.",
217         "You seem to be using the wildcard more generally that is supported.\n"
218         "Did you mean \"foo:*\" to match everything in the current file, or\n"
219         "\"./*\" to recursively match everything in the currend subtree.");
220     return VisPattern();
221   }
222
223   VisPattern::Type type;
224   if (has_path_star) {
225     // We know there's a wildcard, so if the name is empty it looks like
226     // "foo/*".
227     type = VisPattern::RECURSIVE_DIRECTORY;
228   } else {
229     // Everything else should be of the form "foo:*".
230     type = VisPattern::DIRECTORY;
231   }
232
233   // When we're doing wildcard matching, the name is always empty.
234   return VisPattern(type, dir, base::StringPiece());
235 }
236
237 // static
238 bool Visibility::CheckItemVisibility(const Item* from,
239                                      const Item* to,
240                                      Err* err) {
241   if (!to->visibility().CanSeeMe(from->label())) {
242     std::string to_label = to->label().GetUserVisibleName(false);
243     *err = Err(from->defined_from(), "Dependency not allowed.",
244         "The item " + from->label().GetUserVisibleName(false) + "\n"
245         "can not depend on " + to_label + "\n"
246         "because it is not in " + to_label + "'s visibility list: " +
247         to->visibility().Describe());
248     return false;
249   }
250   return true;
251 }
252
253 // static
254 bool Visibility::FillItemVisibility(Item* item, Scope* scope, Err* err) {
255   const Value* vis_value = scope->GetValue(variables::kVisibility, true);
256   if (vis_value)
257     item->visibility().Set(scope->GetSourceDir(), *vis_value, err);
258   else  // Default to public.
259     item->visibility().SetPublic();
260   return !err->has_error();
261 }