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