1// Copyright (c) 2013 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/value_extractors.h"
6
7#include "tools/gn/build_settings.h"
8#include "tools/gn/err.h"
9#include "tools/gn/label.h"
10#include "tools/gn/source_dir.h"
11#include "tools/gn/source_file.h"
12#include "tools/gn/target.h"
13#include "tools/gn/value.h"
14
15namespace {
16
17// Sets the error and returns false on failure.
18template<typename T, class Converter>
19bool ListValueExtractor(const Value& value,
20                        std::vector<T>* dest,
21                        Err* err,
22                        const Converter& converter) {
23  if (!value.VerifyTypeIs(Value::LIST, err))
24    return false;
25  const std::vector<Value>& input_list = value.list_value();
26  dest->resize(input_list.size());
27  for (size_t i = 0; i < input_list.size(); i++) {
28    if (!converter(input_list[i], &(*dest)[i], err))
29      return false;
30  }
31  return true;
32}
33
34// Like the above version but extracts to a UniqueVector and sets the error if
35// there are duplicates.
36template<typename T, class Converter>
37bool ListValueUniqueExtractor(const Value& value,
38                              UniqueVector<T>* dest,
39                              Err* err,
40                              const Converter& converter) {
41  if (!value.VerifyTypeIs(Value::LIST, err))
42    return false;
43  const std::vector<Value>& input_list = value.list_value();
44
45  for (size_t i = 0; i < input_list.size(); i++) {
46    T new_one;
47    if (!converter(input_list[i], &new_one, err))
48      return false;
49    if (!dest->push_back(new_one)) {
50      // Already in the list, throw error.
51      *err = Err(input_list[i], "Duplicate item in list");
52      size_t previous_index = dest->IndexOf(new_one);
53      err->AppendSubErr(Err(input_list[previous_index],
54                            "This was the previous definition."));
55      return false;
56    }
57  }
58  return true;
59}
60
61// This extractor rejects files with system-absolute file paths. If we need
62// that in the future, we'll have to add some flag to control this.
63struct RelativeFileConverter {
64  RelativeFileConverter(const BuildSettings* build_settings_in,
65                        const SourceDir& current_dir_in)
66      : build_settings(build_settings_in),
67        current_dir(current_dir_in) {
68  }
69  bool operator()(const Value& v, SourceFile* out, Err* err) const {
70    if (!v.VerifyTypeIs(Value::STRING, err))
71      return false;
72    *out = current_dir.ResolveRelativeFile(v.string_value(),
73                                           build_settings->root_path_utf8());
74    if (out->is_system_absolute()) {
75      *err = Err(v, "System-absolute file path.",
76          "You can't list a system-absolute file path here. Please include "
77          "only files in\nthe source tree. Maybe you meant to begin with two "
78          "slashes to indicate an\nabsolute path in the source tree?");
79      return false;
80    }
81    return true;
82  }
83  const BuildSettings* build_settings;
84  const SourceDir& current_dir;
85};
86
87struct RelativeDirConverter {
88  RelativeDirConverter(const BuildSettings* build_settings_in,
89                       const SourceDir& current_dir_in)
90      : build_settings(build_settings_in),
91        current_dir(current_dir_in) {
92  }
93  bool operator()(const Value& v, SourceDir* out, Err* err) const {
94    if (!v.VerifyTypeIs(Value::STRING, err))
95      return false;
96    *out = current_dir.ResolveRelativeDir(v.string_value(),
97                                          build_settings->root_path_utf8());
98    return true;
99  }
100  const BuildSettings* build_settings;
101  const SourceDir& current_dir;
102};
103
104// Fills in a label.
105template<typename T> struct LabelResolver {
106  LabelResolver(const SourceDir& current_dir_in,
107                const Label& current_toolchain_in)
108      : current_dir(current_dir_in),
109        current_toolchain(current_toolchain_in) {}
110  bool operator()(const Value& v, Label* out, Err* err) const {
111    if (!v.VerifyTypeIs(Value::STRING, err))
112      return false;
113    *out = Label::Resolve(current_dir, current_toolchain, v, err);
114    return !err->has_error();
115  }
116  const SourceDir& current_dir;
117  const Label& current_toolchain;
118};
119
120// Fills the label part of a LabelPtrPair, leaving the pointer null.
121template<typename T> struct LabelPtrResolver {
122  LabelPtrResolver(const SourceDir& current_dir_in,
123                   const Label& current_toolchain_in)
124      : current_dir(current_dir_in),
125        current_toolchain(current_toolchain_in) {}
126  bool operator()(const Value& v, LabelPtrPair<T>* out, Err* err) const {
127    if (!v.VerifyTypeIs(Value::STRING, err))
128      return false;
129    out->label = Label::Resolve(current_dir, current_toolchain, v, err);
130    out->origin = v.origin();
131    return !err->has_error();
132  }
133  const SourceDir& current_dir;
134  const Label& current_toolchain;
135};
136
137}  // namespace
138
139bool ExtractListOfStringValues(const Value& value,
140                               std::vector<std::string>* dest,
141                               Err* err) {
142  if (!value.VerifyTypeIs(Value::LIST, err))
143    return false;
144  const std::vector<Value>& input_list = value.list_value();
145  dest->reserve(input_list.size());
146  for (size_t i = 0; i < input_list.size(); i++) {
147    if (!input_list[i].VerifyTypeIs(Value::STRING, err))
148      return false;
149    dest->push_back(input_list[i].string_value());
150  }
151  return true;
152}
153
154bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
155                                const Value& value,
156                                const SourceDir& current_dir,
157                                std::vector<SourceFile>* files,
158                                Err* err) {
159  return ListValueExtractor(value, files, err,
160                            RelativeFileConverter(build_settings, current_dir));
161}
162
163bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
164                               const Value& value,
165                               const SourceDir& current_dir,
166                               std::vector<SourceDir>* dest,
167                               Err* err) {
168  return ListValueExtractor(value, dest, err,
169                            RelativeDirConverter(build_settings, current_dir));
170}
171
172bool ExtractListOfLabels(const Value& value,
173                         const SourceDir& current_dir,
174                         const Label& current_toolchain,
175                         LabelTargetVector* dest,
176                         Err* err) {
177  return ListValueExtractor(value, dest, err,
178                            LabelPtrResolver<Target>(current_dir,
179                                                     current_toolchain));
180}
181
182bool ExtractListOfUniqueLabels(const Value& value,
183                               const SourceDir& current_dir,
184                               const Label& current_toolchain,
185                               UniqueVector<Label>* dest,
186                               Err* err) {
187  return ListValueUniqueExtractor(value, dest, err,
188                                  LabelResolver<Config>(current_dir,
189                                                        current_toolchain));
190}
191
192bool ExtractListOfUniqueLabels(const Value& value,
193                               const SourceDir& current_dir,
194                               const Label& current_toolchain,
195                               UniqueVector<LabelConfigPair>* dest,
196                               Err* err) {
197  return ListValueUniqueExtractor(value, dest, err,
198                                  LabelPtrResolver<Config>(current_dir,
199                                                           current_toolchain));
200}
201
202bool ExtractListOfUniqueLabels(const Value& value,
203                               const SourceDir& current_dir,
204                               const Label& current_toolchain,
205                               UniqueVector<LabelTargetPair>* dest,
206                               Err* err) {
207  return ListValueUniqueExtractor(value, dest, err,
208                                  LabelPtrResolver<Target>(current_dir,
209                                                           current_toolchain));
210}
211
212bool ExtractRelativeFile(const BuildSettings* build_settings,
213                         const Value& value,
214                         const SourceDir& current_dir,
215                         SourceFile* file,
216                         Err* err) {
217  RelativeFileConverter converter(build_settings, current_dir);
218  return converter(value, file, err);
219}
220