blob: e75f6a757f467ed36543bae4d04ae33a1f229628 [file] [log] [blame]
Ted Kremenek4c4f08d2011-10-31 22:05:42 +00001//===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines routines for manipulating CXSourceLocations.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Frontend/ASTUnit.h"
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000015#include "CIndexer.h"
Chandler Carruth4b417452013-01-19 08:09:44 +000016#include "CLog.h"
Ted Kremenekd010ba42011-11-10 08:43:12 +000017#include "CXLoadedDiagnostic.h"
Chandler Carruthcc0694c2012-12-04 09:25:21 +000018#include "CXSourceLocation.h"
19#include "CXString.h"
20#include "CXTranslationUnit.h"
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +000021#include "llvm/Support/Compiler.h"
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +000022#include "llvm/Support/Format.h"
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000023
24using namespace clang;
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +000025using namespace clang::cxindex;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000026
27//===----------------------------------------------------------------------===//
Ted Kremenekce6a5712011-10-31 22:23:51 +000028// Internal predicates on CXSourceLocations.
29//===----------------------------------------------------------------------===//
30
31static 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 return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
35}
36
37//===----------------------------------------------------------------------===//
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000038// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
39//===----------------------------------------------------------------------===//
40
41extern "C" {
42
43CXSourceLocation clang_getNullLocation() {
Craig Topper69186e72014-06-08 08:38:04 +000044 CXSourceLocation Result = { { nullptr, nullptr }, 0 };
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000045 return Result;
46}
47
48unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
49 return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
50 loc1.ptr_data[1] == loc2.ptr_data[1] &&
51 loc1.int_data == loc2.int_data);
52}
53
54CXSourceRange clang_getNullRange() {
Craig Topper69186e72014-06-08 08:38:04 +000055 CXSourceRange Result = { { nullptr, nullptr }, 0, 0 };
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000056 return Result;
57}
58
59CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
Ted Kremenekd010ba42011-11-10 08:43:12 +000060 if (!isASTUnitSourceLocation(begin)) {
61 if (isASTUnitSourceLocation(end))
62 return clang_getNullRange();
63 CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
64 return Result;
65 }
66
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000067 if (begin.ptr_data[0] != end.ptr_data[0] ||
68 begin.ptr_data[1] != end.ptr_data[1])
69 return clang_getNullRange();
70
71 CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
72 begin.int_data, end.int_data };
73
74 return Result;
75}
76
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000077unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
78 return range1.ptr_data[0] == range2.ptr_data[0]
79 && range1.ptr_data[1] == range2.ptr_data[1]
80 && range1.begin_int_data == range2.begin_int_data
81 && range1.end_int_data == range2.end_int_data;
82}
83
84int clang_Range_isNull(CXSourceRange range) {
85 return clang_equalRanges(range, clang_getNullRange());
86}
87
88
89CXSourceLocation clang_getRangeStart(CXSourceRange range) {
Ted Kremenekd010ba42011-11-10 08:43:12 +000090 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
91 if ((uintptr_t)range.ptr_data[0] & 0x1) {
Craig Topper69186e72014-06-08 08:38:04 +000092 CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
Ted Kremenekd010ba42011-11-10 08:43:12 +000093 return Result;
94 }
95
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000096 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
97 range.begin_int_data };
98 return Result;
99}
100
101CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000102 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
103 if ((uintptr_t)range.ptr_data[0] & 0x1) {
Craig Topper69186e72014-06-08 08:38:04 +0000104 CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
Ted Kremenekd010ba42011-11-10 08:43:12 +0000105 return Result;
106 }
107
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000108 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
109 range.end_int_data };
110 return Result;
111}
112
113} // end extern "C"
114
115//===----------------------------------------------------------------------===//
116// Getting CXSourceLocations and CXSourceRanges from a translation unit.
117//===----------------------------------------------------------------------===//
118
119extern "C" {
120
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000121CXSourceLocation clang_getLocation(CXTranslationUnit TU,
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000122 CXFile file,
123 unsigned line,
124 unsigned column) {
Dmitri Gribenko852d6222014-02-11 15:02:48 +0000125 if (cxtu::isNotUsableTU(TU)) {
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000126 LOG_BAD_TU(TU);
127 return clang_getNullLocation();
128 }
129 if (!file)
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000130 return clang_getNullLocation();
Argyrios Kyrtzidis5fcef772013-09-12 01:10:36 +0000131 if (line == 0 || column == 0)
132 return clang_getNullLocation();
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000133
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +0000134 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000135 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000136 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
137 const FileEntry *File = static_cast<const FileEntry *>(file);
138 SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
139 if (SLoc.isInvalid()) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000140 if (Log)
141 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
Mehdi Amini004b9c72016-10-10 22:52:47 +0000142 File->getName().str().c_str(), line, column);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000143 return clang_getNullLocation();
144 }
145
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000146 CXSourceLocation CXLoc =
147 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
148 if (Log)
Mehdi Amini004b9c72016-10-10 22:52:47 +0000149 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
150 line, column)
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000151 << CXLoc;
Mehdi Amini004b9c72016-10-10 22:52:47 +0000152
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000153 return CXLoc;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000154}
155
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000156CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000157 CXFile file,
158 unsigned offset) {
Dmitri Gribenko852d6222014-02-11 15:02:48 +0000159 if (cxtu::isNotUsableTU(TU)) {
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000160 LOG_BAD_TU(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000161 return clang_getNullLocation();
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000162 }
163 if (!file)
164 return clang_getNullLocation();
165
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000166 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000167
168 SourceLocation SLoc
169 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
170
171 if (SLoc.isInvalid())
172 return clang_getNullLocation();
173
174 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
175}
176
177} // end extern "C"
178
179//===----------------------------------------------------------------------===//
180// Routines for expanding and manipulating CXSourceLocations, regardless
181// of their origin.
182//===----------------------------------------------------------------------===//
183
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000184static void createNullLocation(CXFile *file, unsigned *line,
185 unsigned *column, unsigned *offset) {
186 if (file)
Craig Topper69186e72014-06-08 08:38:04 +0000187 *file = nullptr;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000188 if (line)
189 *line = 0;
190 if (column)
191 *column = 0;
192 if (offset)
193 *offset = 0;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000194}
195
Ted Kremenekce6a5712011-10-31 22:23:51 +0000196static void createNullLocation(CXString *filename, unsigned *line,
Craig Topper69186e72014-06-08 08:38:04 +0000197 unsigned *column, unsigned *offset = nullptr) {
Ted Kremenekce6a5712011-10-31 22:23:51 +0000198 if (filename)
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000199 *filename = cxstring::createEmpty();
Ted Kremenekce6a5712011-10-31 22:23:51 +0000200 if (line)
201 *line = 0;
202 if (column)
203 *column = 0;
204 if (offset)
205 *offset = 0;
Ted Kremenekce6a5712011-10-31 22:23:51 +0000206}
207
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000208extern "C" {
209
Argyrios Kyrtzidis25f7af12013-04-12 17:06:51 +0000210int clang_Location_isInSystemHeader(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.isInSystemHeader(Loc);
219}
220
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000221int clang_Location_isFromMainFile(CXSourceLocation location) {
222 const SourceLocation Loc =
223 SourceLocation::getFromRawEncoding(location.int_data);
224 if (Loc.isInvalid())
225 return 0;
226
227 const SourceManager &SM =
228 *static_cast<const SourceManager*>(location.ptr_data[0]);
Eli Friedman5ba37d52013-08-22 00:27:10 +0000229 return SM.isWrittenInMainFile(Loc);
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000230}
231
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000232void clang_getExpansionLocation(CXSourceLocation location,
233 CXFile *file,
234 unsigned *line,
235 unsigned *column,
236 unsigned *offset) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000237 if (!isASTUnitSourceLocation(location)) {
238 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
239 return;
240 }
241
242 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
243
244 if (!location.ptr_data[0] || Loc.isInvalid()) {
245 createNullLocation(file, line, column, offset);
246 return;
247 }
248
249 const SourceManager &SM =
250 *static_cast<const SourceManager*>(location.ptr_data[0]);
251 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000252
Ted Kremenekd010ba42011-11-10 08:43:12 +0000253 // Check that the FileID is invalid on the expansion location.
254 // This can manifest in invalid code.
255 FileID fileID = SM.getFileID(ExpansionLoc);
256 bool Invalid = false;
257 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
258 if (Invalid || !sloc.isFile()) {
259 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidis7ca77352011-11-03 02:20:36 +0000260 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000261 }
262
Ted Kremenekd010ba42011-11-10 08:43:12 +0000263 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000264 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000265 if (line)
266 *line = SM.getExpansionLineNumber(ExpansionLoc);
267 if (column)
268 *column = SM.getExpansionColumnNumber(ExpansionLoc);
269 if (offset)
270 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000271}
272
273void clang_getPresumedLocation(CXSourceLocation location,
274 CXString *filename,
275 unsigned *line,
276 unsigned *column) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000277 if (!isASTUnitSourceLocation(location)) {
278 // Other SourceLocation implementations do not support presumed locations
279 // at this time.
280 createNullLocation(filename, line, column);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000281 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000282 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000283
284 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
285
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000286 if (!location.ptr_data[0] || Loc.isInvalid()) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000287 createNullLocation(filename, line, column);
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000288 return;
Ted Kremenekd010ba42011-11-10 08:43:12 +0000289 }
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000290
291 const SourceManager &SM =
292 *static_cast<const SourceManager *>(location.ptr_data[0]);
293 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
294 if (PreLoc.isInvalid()) {
295 createNullLocation(filename, line, column);
296 return;
297 }
298
299 if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
300 if (line) *line = PreLoc.getLine();
301 if (column) *column = PreLoc.getColumn();
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000302}
303
304void clang_getInstantiationLocation(CXSourceLocation location,
305 CXFile *file,
306 unsigned *line,
307 unsigned *column,
308 unsigned *offset) {
309 // Redirect to new API.
310 clang_getExpansionLocation(location, file, line, column, offset);
311}
312
313void clang_getSpellingLocation(CXSourceLocation location,
314 CXFile *file,
315 unsigned *line,
316 unsigned *column,
317 unsigned *offset) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000318 if (!isASTUnitSourceLocation(location)) {
319 CXLoadedDiagnostic::decodeLocation(location, file, line,
320 column, offset);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000321 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000322 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000323
324 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
325
326 if (!location.ptr_data[0] || Loc.isInvalid())
327 return createNullLocation(file, line, column, offset);
328
329 const SourceManager &SM =
330 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000331 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek372735f2012-12-19 01:16:49 +0000332 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000333 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
334 FileID FID = LocInfo.first;
335 unsigned FileOffset = LocInfo.second;
336
337 if (FID.isInvalid())
338 return createNullLocation(file, line, column, offset);
339
340 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000341 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000342 if (line)
343 *line = SM.getLineNumber(FID, FileOffset);
344 if (column)
345 *column = SM.getColumnNumber(FID, FileOffset);
346 if (offset)
347 *offset = FileOffset;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000348}
349
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000350void clang_getFileLocation(CXSourceLocation location,
351 CXFile *file,
352 unsigned *line,
353 unsigned *column,
354 unsigned *offset) {
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000355 if (!isASTUnitSourceLocation(location)) {
356 CXLoadedDiagnostic::decodeLocation(location, file, line,
357 column, offset);
358 return;
359 }
360
361 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
362
363 if (!location.ptr_data[0] || Loc.isInvalid())
364 return createNullLocation(file, line, column, offset);
365
366 const SourceManager &SM =
367 *static_cast<const SourceManager*>(location.ptr_data[0]);
368 SourceLocation FileLoc = SM.getFileLoc(Loc);
369 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
370 FileID FID = LocInfo.first;
371 unsigned FileOffset = LocInfo.second;
372
373 if (FID.isInvalid())
374 return createNullLocation(file, line, column, offset);
375
376 if (file)
Dmitri Gribenkof9304482013-01-23 15:56:07 +0000377 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000378 if (line)
379 *line = SM.getLineNumber(FID, FileOffset);
380 if (column)
381 *column = SM.getColumnNumber(FID, FileOffset);
382 if (offset)
383 *offset = FileOffset;
384}
385
386} // end extern "C"