-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathiwyu_path_util.cc
223 lines (183 loc) · 6.48 KB
/
iwyu_path_util.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//===--- iwyu_path_util.cc - file-path utilities for include-what-you-use -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "iwyu_path_util.h"
#include <stddef.h>
#include <string.h> // for strlen
#include <system_error>
#include "iwyu_stl_util.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
namespace include_what_you_use {
namespace {
vector<HeaderSearchPath>* header_search_paths;
// Please keep this in sync with _SOURCE_EXTENSIONS in fix_includes.py.
const char* source_extensions[] = {
".c",
".C",
".cc",
".CC",
".cxx",
".CXX",
".cpp",
".CPP"
".c++",
".C++",
".cp"
};
} // namespace
void SetHeaderSearchPaths(const vector<HeaderSearchPath>& search_paths) {
if (header_search_paths != NULL) {
delete header_search_paths;
}
header_search_paths = new vector<HeaderSearchPath>(search_paths);
}
const vector<HeaderSearchPath>& HeaderSearchPaths() {
if (header_search_paths == NULL) {
header_search_paths = new vector<HeaderSearchPath>();
}
return *header_search_paths;
}
bool IsHeaderFile(string path) {
if (EndsWith(path, "\"") || EndsWith(path, ">"))
path = path.substr(0, path.length() - 1);
// Some headers don't have an extension (e.g. <string>), or have an
// unusual one (the compiler doesn't care), so it's safer to
// enumerate non-header extensions instead.
for (size_t i = 0; i < llvm::array_lengthof(source_extensions); ++i) {
if (EndsWith(path, source_extensions[i]))
return false;
}
return true;
}
string Basename(const string& path) {
string::size_type last_slash = path.rfind('/');
if (last_slash != string::npos) {
return path.substr(last_slash + 1);
}
return path;
}
string CanonicalizeFilePath(const string& path) {
string result = path;
#ifdef _WIN32
// canonicalise directory separators (forward slashes considered canonical)
for (size_t i = 0; i < result.size(); ++i) {
if (result[i] == '\\')
result[i] = '/';
}
#endif
// We may also want to collapse ../ here.
return result;
}
string GetCanonicalName(string file_path) {
// Get rid of any <> and "" in case file_path is really an #include line.
StripLeft(&file_path, "\"") || StripLeft(&file_path, "<");
StripRight(&file_path, "\"") || StripRight(&file_path, ">");
file_path = CanonicalizeFilePath(file_path);
bool stripped_ext = StripRight(&file_path, ".h")
|| StripRight(&file_path, ".hpp")
|| StripRight(&file_path, ".hxx")
|| StripRight(&file_path, ".hh")
|| StripRight(&file_path, ".inl");
if (!stripped_ext) {
for (size_t i = 0; i < llvm::array_lengthof(source_extensions); ++i) {
if (StripRight(&file_path, source_extensions[i]))
break;
}
}
StripRight(&file_path, "_unittest")
|| StripRight(&file_path, "_regtest")
|| StripRight(&file_path, "_test")
|| StripLeft(&file_path, "test_headercompile_");
StripRight(&file_path, "-inl");
// .h files in /public/ match .cc files in /internal/
const string::size_type internal_pos = file_path.find("/internal/");
if (internal_pos != string::npos)
file_path = (file_path.substr(0, internal_pos) + "/public/" +
file_path.substr(internal_pos + strlen("/internal/")));
// .h files in /include/ match .cc files in /src/
const string::size_type include_pos = file_path.find("/include/");
if (include_pos != string::npos)
file_path = (file_path.substr(0, include_pos) + "/src/" +
file_path.substr(include_pos + strlen("/include/")));
return file_path;
}
string NormalizeFilePath(const string& path) {
string result = CanonicalizeFilePath(path);
while (StripLeft(&result, "./")) {
}
return result;
}
bool IsAbsolutePath(const string& path) {
return llvm::sys::path::is_absolute(path);
}
string MakeAbsolutePath(const string& path) {
llvm::SmallString<128> absolute_path(path.c_str());
std::error_code error = llvm::sys::fs::make_absolute(absolute_path);
CHECK_(!error);
return absolute_path.str();
}
string MakeAbsolutePath(const string& base_path, const string& relative_path) {
llvm::SmallString<128> absolute_path(base_path.c_str());
llvm::sys::path::append(absolute_path, relative_path);
return absolute_path.str();
}
string GetParentPath(const string& path) {
llvm::StringRef parent = llvm::sys::path::parent_path(path);
return parent.str();
}
// Converts a file-path, such as /usr/include/stdio.h, to a
// quoted include, such as <stdio.h>.
string ConvertToQuotedInclude(const string& filepath) {
// First, get rid of leading ./'s and the like.
string path = NormalizeFilePath(filepath);
// Case 1: Uses an explicit entry on the search path (-I) list.
const vector<HeaderSearchPath>& search_paths = HeaderSearchPaths();
// HeaderSearchPaths is sorted to be longest-first, so this
// loop will prefer the longest prefix: /usr/include/c++/4.4/foo
// will be mapped to <foo>, not <c++/4.4/foo>.
for (Each<HeaderSearchPath> it(&search_paths); !it.AtEnd(); ++it) {
if (StripLeft(&path, it->path)) {
StripLeft(&path, "/");
if (it->path_type == HeaderSearchPath::kSystemPath)
return "<" + path + ">";
else
return "\"" + path + "\"";
}
}
// Case 2: Uses the implicit "-I." entry on the search path. Always local.
return "\"" + path + "\"";
}
bool IsQuotedInclude(const string& s) {
if (s.size() < 2)
return false;
return ((StartsWith(s, "<") && EndsWith(s, ">")) ||
(StartsWith(s, "\"") && EndsWith(s, "\"")));
}
// Returns whether this is a system (as opposed to user) include file,
// based on where it lives.
bool IsSystemIncludeFile(const string& filepath) {
return ConvertToQuotedInclude(filepath)[0] == '<';
}
// Returns true if the given file is third-party. Google-authored
// code living in third_party/ is not considered third-party.
bool IsThirdPartyFile(string quoted_path) {
if (!StripLeft("ed_path, "\"third_party/"))
return false;
// These are Google-authored libraries living in third_party/
// because of old licensing constraints.
if (StartsWith(quoted_path, "car/") ||
StartsWith(quoted_path, "gtest/") ||
StartsWith(quoted_path, "gmock/"))
return false;
return true;
}
} // namespace include_what_you_use