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 <string.h>
6
7 #include "gn/source_file.h"
8
9 #include "base/logging.h"
10 #include "gn/filesystem_utils.h"
11 #include "gn/source_dir.h"
12 #include "util/build_config.h"
13
14 namespace {
15
AssertValueSourceFileString(const std::string & s)16 void AssertValueSourceFileString(const std::string& s) {
17 #if defined(OS_WIN)
18 DCHECK(s[0] == '/' ||
19 (s.size() > 2 && s[0] != '/' && s[1] == ':' && IsSlash(s[2])));
20 #else
21 DCHECK(s[0] == '/');
22 #endif
23 DCHECK(!EndsWithSlash(s)) << s;
24 }
25
EndsWithExtension(std::string_view str,std::string_view ext)26 bool EndsWithExtension(std::string_view str, std::string_view ext) {
27 return str.size() > ext.size() && str[str.size() - ext.size() - 1] == '.' &&
28 !::memcmp(str.data() + str.size() - ext.size(), ext.data(),
29 ext.size());
30 }
31
GetSourceFileType(const std::string & file)32 SourceFile::Type GetSourceFileType(const std::string& file) {
33 size_t size = file.size();
34 const char* str = file.data();
35
36 // First, single-char extensions.
37 if (size > 2 && str[size - 2] == '.') {
38 switch (str[size - 1]) {
39 case 'c':
40 return SourceFile::SOURCE_C; // .c
41 case 'h':
42 return SourceFile::SOURCE_H; // .h
43 case 'm':
44 return SourceFile::SOURCE_M; // .m
45 case 'o':
46 return SourceFile::SOURCE_O; // .o
47 case 'S':
48 case 's':
49 return SourceFile::SOURCE_S; // .S and .s
50 default:
51 return SourceFile::SOURCE_UNKNOWN;
52 }
53 }
54
55 // Second, two-char extensions
56 if (size > 3 && str[size - 3] == '.') {
57 #define TAG2(c1, c2) ((unsigned)(c1) | ((unsigned)(c2) << 8))
58 switch (TAG2(str[size - 2], str[size - 1])) {
59 case TAG2('c', 'c'):
60 return SourceFile::SOURCE_CPP; // .cc
61 case TAG2('g', 'o'):
62 return SourceFile::SOURCE_GO; // .go
63 case TAG2('h', 'h'):
64 return SourceFile::SOURCE_H; // .hh
65 case TAG2('m', 'm'):
66 return SourceFile::SOURCE_MM; // .mm
67 case TAG2('r', 'c'):
68 return SourceFile::SOURCE_RC; // .rc
69 case TAG2('r', 's'):
70 return SourceFile::SOURCE_RS; // .rs
71 default:
72 return SourceFile::SOURCE_UNKNOWN;
73 }
74 #undef TAG2
75 }
76
77 if (size > 4 && str[size - 4] == '.') {
78 #define TAG3(c1, c2, c3) \
79 ((unsigned)(c1) | ((unsigned)(c2) << 8) | ((unsigned)(c3) << 16))
80 switch (TAG3(str[size - 3], str[size - 2], str[size - 1])) {
81 case TAG3('c', 'p', 'p'):
82 case TAG3('c', 'x', 'x'):
83 case TAG3('c', '+', '+'):
84 return SourceFile::SOURCE_CPP;
85 case TAG3('h', 'p', 'p'):
86 case TAG3('h', 'x', 'x'):
87 case TAG3('i', 'n', 'c'):
88 case TAG3('i', 'p', 'p'):
89 case TAG3('i', 'n', 'l'):
90 return SourceFile::SOURCE_H;
91 case TAG3('a', 's', 'm'):
92 return SourceFile::SOURCE_S;
93 case TAG3('d', 'e', 'f'):
94 return SourceFile::SOURCE_DEF;
95 case TAG3('o', 'b', 'j'):
96 return SourceFile::SOURCE_O;
97 default:
98 return SourceFile::SOURCE_UNKNOWN;
99 }
100 #undef TAG3
101 }
102
103 // Other cases
104 if (EndsWithExtension(file, "swift"))
105 return SourceFile::SOURCE_SWIFT;
106
107 if (EndsWithExtension(file, "swiftmodule"))
108 return SourceFile::SOURCE_SWIFTMODULE;
109
110 if (EndsWithExtension(file, "modulemap"))
111 return SourceFile::SOURCE_MODULEMAP;
112
113 return SourceFile::SOURCE_UNKNOWN;
114 }
115
Normalized(std::string value)116 std::string Normalized(std::string value) {
117 DCHECK(!value.empty());
118 AssertValueSourceFileString(value);
119 NormalizePath(&value);
120 return value;
121 }
122
123 } // namespace
124
SourceFile(const std::string & value)125 SourceFile::SourceFile(const std::string& value)
126 : SourceFile(StringAtom(Normalized(value))) {}
127
SourceFile(std::string && value)128 SourceFile::SourceFile(std::string&& value)
129 : SourceFile(StringAtom(Normalized(std::move(value)))) {}
130
SourceFile(StringAtom value)131 SourceFile::SourceFile(StringAtom value) : value_(value) {}
132
GetType() const133 SourceFile::Type SourceFile::GetType() const {
134 return GetSourceFileType(value_.str());
135 }
136
IsDefType() const137 bool SourceFile::IsDefType() const {
138 std::string_view v = value_.str();
139 return EndsWithExtension(v, "def");
140 }
141
IsObjectType() const142 bool SourceFile::IsObjectType() const {
143 std::string_view v = value_.str();
144 return EndsWithExtension(v, "o") || EndsWithExtension(v, "obj");
145 }
146
IsModuleMapType() const147 bool SourceFile::IsModuleMapType() const {
148 std::string_view v = value_.str();
149 return EndsWithExtension(v, "modulemap");
150 }
151
IsSwiftType() const152 bool SourceFile::IsSwiftType() const {
153 std::string_view v = value_.str();
154 return EndsWithExtension(v, "swift");
155 }
156
IsSwiftModuleType() const157 bool SourceFile::IsSwiftModuleType() const {
158 std::string_view v = value_.str();
159 return EndsWithExtension(v, "swiftmodule");
160 }
161
GetName() const162 std::string SourceFile::GetName() const {
163 if (is_null())
164 return std::string();
165
166 const std::string& value = value_.str();
167 DCHECK(value.find('/') != std::string::npos);
168 size_t last_slash = value.rfind('/');
169 return std::string(&value[last_slash + 1], value.size() - last_slash - 1);
170 }
171
GetDir() const172 SourceDir SourceFile::GetDir() const {
173 if (is_null())
174 return SourceDir();
175
176 const std::string& value = value_.str();
177 DCHECK(value.find('/') != std::string::npos);
178 size_t last_slash = value.rfind('/');
179 return SourceDir(value.substr(0, last_slash + 1));
180 }
181
Resolve(const base::FilePath & source_root) const182 base::FilePath SourceFile::Resolve(const base::FilePath& source_root) const {
183 return ResolvePath(value_.str(), true, source_root);
184 }
185
SetValue(const std::string & value)186 void SourceFile::SetValue(const std::string& value) {
187 value_ = StringAtom(value);
188 }
189
SourceFileTypeSet()190 SourceFileTypeSet::SourceFileTypeSet() : empty_(true) {
191 memset(flags_, 0,
192 sizeof(bool) * static_cast<int>(SourceFile::SOURCE_NUMTYPES));
193 }
194
CSourceUsed() const195 bool SourceFileTypeSet::CSourceUsed() const {
196 return empty_ || Get(SourceFile::SOURCE_CPP) ||
197 Get(SourceFile::SOURCE_MODULEMAP) || Get(SourceFile::SOURCE_H) ||
198 Get(SourceFile::SOURCE_C) || Get(SourceFile::SOURCE_M) ||
199 Get(SourceFile::SOURCE_MM) || Get(SourceFile::SOURCE_RC) ||
200 Get(SourceFile::SOURCE_S) || Get(SourceFile::SOURCE_O) ||
201 Get(SourceFile::SOURCE_DEF);
202 }
203
RustSourceUsed() const204 bool SourceFileTypeSet::RustSourceUsed() const {
205 return Get(SourceFile::SOURCE_RS);
206 }
207
GoSourceUsed() const208 bool SourceFileTypeSet::GoSourceUsed() const {
209 return Get(SourceFile::SOURCE_GO);
210 }
211
SwiftSourceUsed() const212 bool SourceFileTypeSet::SwiftSourceUsed() const {
213 return Get(SourceFile::SOURCE_SWIFT);
214 }
215
MixedSourceUsed() const216 bool SourceFileTypeSet::MixedSourceUsed() const {
217 return (1 << static_cast<int>(CSourceUsed())
218 << static_cast<int>(RustSourceUsed())
219 << static_cast<int>(GoSourceUsed())
220 << static_cast<int>(SwiftSourceUsed())) > 2;
221 }
222