• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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