1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/Frontend/ASTUnit.h" |
14 | #include "CIndexer.h" |
15 | #include "CLog.h" |
16 | #include "CXLoadedDiagnostic.h" |
17 | #include "CXSourceLocation.h" |
18 | #include "CXString.h" |
19 | #include "CXTranslationUnit.h" |
20 | #include "llvm/Support/Compiler.h" |
21 | #include "llvm/Support/Format.h" |
22 | |
23 | using namespace clang; |
24 | using namespace clang::cxindex; |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | static bool isASTUnitSourceLocation(const CXSourceLocation &L) { |
31 | |
32 | |
33 | return ((uintptr_t)L.ptr_data[0] & 0x1) == 0; |
34 | } |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | CXSourceLocation clang_getNullLocation() { |
41 | CXSourceLocation Result = { { nullptr, nullptr }, 0 }; |
42 | return Result; |
43 | } |
44 | |
45 | unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { |
46 | return (loc1.ptr_data[0] == loc2.ptr_data[0] && |
47 | loc1.ptr_data[1] == loc2.ptr_data[1] && |
48 | loc1.int_data == loc2.int_data); |
49 | } |
50 | |
51 | CXSourceRange clang_getNullRange() { |
52 | CXSourceRange Result = { { nullptr, nullptr }, 0, 0 }; |
53 | return Result; |
54 | } |
55 | |
56 | CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { |
57 | if (!isASTUnitSourceLocation(begin)) { |
58 | if (isASTUnitSourceLocation(end)) |
59 | return clang_getNullRange(); |
60 | CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 }; |
61 | return Result; |
62 | } |
63 | |
64 | if (begin.ptr_data[0] != end.ptr_data[0] || |
65 | begin.ptr_data[1] != end.ptr_data[1]) |
66 | return clang_getNullRange(); |
67 | |
68 | CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] }, |
69 | begin.int_data, end.int_data }; |
70 | |
71 | return Result; |
72 | } |
73 | |
74 | unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) { |
75 | return range1.ptr_data[0] == range2.ptr_data[0] |
76 | && range1.ptr_data[1] == range2.ptr_data[1] |
77 | && range1.begin_int_data == range2.begin_int_data |
78 | && range1.end_int_data == range2.end_int_data; |
79 | } |
80 | |
81 | int clang_Range_isNull(CXSourceRange range) { |
82 | return clang_equalRanges(range, clang_getNullRange()); |
83 | } |
84 | |
85 | |
86 | CXSourceLocation clang_getRangeStart(CXSourceRange range) { |
87 | |
88 | if ((uintptr_t)range.ptr_data[0] & 0x1) { |
89 | CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 }; |
90 | return Result; |
91 | } |
92 | |
93 | CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, |
94 | range.begin_int_data }; |
95 | return Result; |
96 | } |
97 | |
98 | CXSourceLocation clang_getRangeEnd(CXSourceRange range) { |
99 | |
100 | if ((uintptr_t)range.ptr_data[0] & 0x1) { |
101 | CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 }; |
102 | return Result; |
103 | } |
104 | |
105 | CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, |
106 | range.end_int_data }; |
107 | return Result; |
108 | } |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | CXSourceLocation clang_getLocation(CXTranslationUnit TU, |
115 | CXFile file, |
116 | unsigned line, |
117 | unsigned column) { |
118 | if (cxtu::isNotUsableTU(TU)) { |
119 | LOG_BAD_TU(TU); |
120 | return clang_getNullLocation(); |
121 | } |
122 | if (!file) |
123 | return clang_getNullLocation(); |
124 | if (line == 0 || column == 0) |
125 | return clang_getNullLocation(); |
126 | |
127 | LogRef Log = Logger::make(__func__); |
128 | ASTUnit *CXXUnit = cxtu::getASTUnit(TU); |
129 | ASTUnit::ConcurrencyCheck Check(*CXXUnit); |
130 | const FileEntry *File = static_cast<const FileEntry *>(file); |
131 | SourceLocation SLoc = CXXUnit->getLocation(File, line, column); |
132 | if (SLoc.isInvalid()) { |
133 | if (Log) |
134 | *Log << llvm::format("(\"%s\", %d, %d) = invalid", |
135 | File->getName().str().c_str(), line, column); |
136 | return clang_getNullLocation(); |
137 | } |
138 | |
139 | CXSourceLocation CXLoc = |
140 | cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); |
141 | if (Log) |
142 | *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(), |
143 | line, column) |
144 | << CXLoc; |
145 | |
146 | return CXLoc; |
147 | } |
148 | |
149 | CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU, |
150 | CXFile file, |
151 | unsigned offset) { |
152 | if (cxtu::isNotUsableTU(TU)) { |
153 | LOG_BAD_TU(TU); |
154 | return clang_getNullLocation(); |
155 | } |
156 | if (!file) |
157 | return clang_getNullLocation(); |
158 | |
159 | ASTUnit *CXXUnit = cxtu::getASTUnit(TU); |
160 | |
161 | SourceLocation SLoc |
162 | = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset); |
163 | |
164 | if (SLoc.isInvalid()) |
165 | return clang_getNullLocation(); |
166 | |
167 | return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); |
168 | } |
169 | |
170 | |
171 | |
172 | |
173 | |
174 | |
175 | static void createNullLocation(CXFile *file, unsigned *line, |
176 | unsigned *column, unsigned *offset) { |
177 | if (file) |
178 | *file = nullptr; |
179 | if (line) |
180 | *line = 0; |
181 | if (column) |
182 | *column = 0; |
183 | if (offset) |
184 | *offset = 0; |
185 | } |
186 | |
187 | static void createNullLocation(CXString *filename, unsigned *line, |
188 | unsigned *column, unsigned *offset = nullptr) { |
189 | if (filename) |
190 | *filename = cxstring::createEmpty(); |
191 | if (line) |
192 | *line = 0; |
193 | if (column) |
194 | *column = 0; |
195 | if (offset) |
196 | *offset = 0; |
197 | } |
198 | |
199 | int (CXSourceLocation location) { |
200 | const SourceLocation Loc = |
201 | SourceLocation::getFromRawEncoding(location.int_data); |
202 | if (Loc.isInvalid()) |
203 | return 0; |
204 | |
205 | const SourceManager &SM = |
206 | *static_cast<const SourceManager*>(location.ptr_data[0]); |
207 | return SM.isInSystemHeader(Loc); |
208 | } |
209 | |
210 | int clang_Location_isFromMainFile(CXSourceLocation location) { |
211 | const SourceLocation Loc = |
212 | SourceLocation::getFromRawEncoding(location.int_data); |
213 | if (Loc.isInvalid()) |
214 | return 0; |
215 | |
216 | const SourceManager &SM = |
217 | *static_cast<const SourceManager*>(location.ptr_data[0]); |
218 | return SM.isWrittenInMainFile(Loc); |
219 | } |
220 | |
221 | void clang_getExpansionLocation(CXSourceLocation location, |
222 | CXFile *file, |
223 | unsigned *line, |
224 | unsigned *column, |
225 | unsigned *offset) { |
226 | if (!isASTUnitSourceLocation(location)) { |
227 | CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset); |
228 | return; |
229 | } |
230 | |
231 | SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); |
232 | |
233 | if (!location.ptr_data[0] || Loc.isInvalid()) { |
234 | createNullLocation(file, line, column, offset); |
235 | return; |
236 | } |
237 | |
238 | const SourceManager &SM = |
239 | *static_cast<const SourceManager*>(location.ptr_data[0]); |
240 | SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); |
241 | |
242 | |
243 | |
244 | FileID fileID = SM.getFileID(ExpansionLoc); |
245 | bool Invalid = false; |
246 | const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); |
247 | if (Invalid || !sloc.isFile()) { |
248 | createNullLocation(file, line, column, offset); |
249 | return; |
250 | } |
251 | |
252 | if (file) |
253 | *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc)); |
254 | if (line) |
255 | *line = SM.getExpansionLineNumber(ExpansionLoc); |
256 | if (column) |
257 | *column = SM.getExpansionColumnNumber(ExpansionLoc); |
258 | if (offset) |
259 | *offset = SM.getDecomposedLoc(ExpansionLoc).second; |
260 | } |
261 | |
262 | void clang_getPresumedLocation(CXSourceLocation location, |
263 | CXString *filename, |
264 | unsigned *line, |
265 | unsigned *column) { |
266 | if (!isASTUnitSourceLocation(location)) { |
267 | |
268 | |
269 | createNullLocation(filename, line, column); |
270 | return; |
271 | } |
272 | |
273 | SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); |
274 | |
275 | if (!location.ptr_data[0] || Loc.isInvalid()) { |
276 | createNullLocation(filename, line, column); |
277 | return; |
278 | } |
279 | |
280 | const SourceManager &SM = |
281 | *static_cast<const SourceManager *>(location.ptr_data[0]); |
282 | PresumedLoc PreLoc = SM.getPresumedLoc(Loc); |
283 | if (PreLoc.isInvalid()) { |
284 | createNullLocation(filename, line, column); |
285 | return; |
286 | } |
287 | |
288 | if (filename) *filename = cxstring::createRef(PreLoc.getFilename()); |
289 | if (line) *line = PreLoc.getLine(); |
290 | if (column) *column = PreLoc.getColumn(); |
291 | } |
292 | |
293 | void clang_getInstantiationLocation(CXSourceLocation location, |
294 | CXFile *file, |
295 | unsigned *line, |
296 | unsigned *column, |
297 | unsigned *offset) { |
298 | |
299 | clang_getExpansionLocation(location, file, line, column, offset); |
300 | } |
301 | |
302 | void clang_getSpellingLocation(CXSourceLocation location, |
303 | CXFile *file, |
304 | unsigned *line, |
305 | unsigned *column, |
306 | unsigned *offset) { |
307 | if (!isASTUnitSourceLocation(location)) { |
308 | CXLoadedDiagnostic::decodeLocation(location, file, line, |
309 | column, offset); |
310 | return; |
311 | } |
312 | |
313 | SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); |
314 | |
315 | if (!location.ptr_data[0] || Loc.isInvalid()) |
316 | return createNullLocation(file, line, column, offset); |
317 | |
318 | const SourceManager &SM = |
319 | *static_cast<const SourceManager*>(location.ptr_data[0]); |
320 | |
321 | SourceLocation SpellLoc = SM.getFileLoc(Loc); |
322 | std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc); |
323 | FileID FID = LocInfo.first; |
324 | unsigned FileOffset = LocInfo.second; |
325 | |
326 | if (FID.isInvalid()) |
327 | return createNullLocation(file, line, column, offset); |
328 | |
329 | if (file) |
330 | *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID)); |
331 | if (line) |
332 | *line = SM.getLineNumber(FID, FileOffset); |
333 | if (column) |
334 | *column = SM.getColumnNumber(FID, FileOffset); |
335 | if (offset) |
336 | *offset = FileOffset; |
337 | } |
338 | |
339 | void clang_getFileLocation(CXSourceLocation location, |
340 | CXFile *file, |
341 | unsigned *line, |
342 | unsigned *column, |
343 | unsigned *offset) { |
344 | if (!isASTUnitSourceLocation(location)) { |
345 | CXLoadedDiagnostic::decodeLocation(location, file, line, |
346 | column, offset); |
347 | return; |
348 | } |
349 | |
350 | SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); |
351 | |
352 | if (!location.ptr_data[0] || Loc.isInvalid()) |
353 | return createNullLocation(file, line, column, offset); |
354 | |
355 | const SourceManager &SM = |
356 | *static_cast<const SourceManager*>(location.ptr_data[0]); |
357 | SourceLocation FileLoc = SM.getFileLoc(Loc); |
358 | std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc); |
359 | FileID FID = LocInfo.first; |
360 | unsigned FileOffset = LocInfo.second; |
361 | |
362 | if (FID.isInvalid()) |
363 | return createNullLocation(file, line, column, offset); |
364 | |
365 | if (file) |
366 | *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID)); |
367 | if (line) |
368 | *line = SM.getLineNumber(FID, FileOffset); |
369 | if (column) |
370 | *column = SM.getColumnNumber(FID, FileOffset); |
371 | if (offset) |
372 | *offset = FileOffset; |
373 | } |
374 | |