blob: 64b2908c49da0b647e0af1a7bdcca97a9b3c6c4d [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() {
44 CXSourceLocation Result = { { 0, 0 }, 0 };
45 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() {
55 CXSourceRange Result = { { 0, 0 }, 0, 0 };
56 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) {
92 CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
93 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) {
104 CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
105 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 Gribenkoc22ea1c2013-01-26 18:53:38 +0000125 if (!TU || !file)
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000126 return clang_getNullLocation();
127
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +0000128 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000129 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000130 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
131 const FileEntry *File = static_cast<const FileEntry *>(file);
132 SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
133 if (SLoc.isInvalid()) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000134 if (Log)
135 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
136 File->getName(), line, column);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000137 return clang_getNullLocation();
138 }
139
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000140 CXSourceLocation CXLoc =
141 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
142 if (Log)
143 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
144 << CXLoc;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000145
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000146 return CXLoc;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000147}
148
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000149CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000150 CXFile file,
151 unsigned offset) {
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000152 if (!TU || !file)
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000153 return clang_getNullLocation();
154
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000155 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000156
157 SourceLocation SLoc
158 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
159
160 if (SLoc.isInvalid())
161 return clang_getNullLocation();
162
163 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
164}
165
166} // end extern "C"
167
168//===----------------------------------------------------------------------===//
169// Routines for expanding and manipulating CXSourceLocations, regardless
170// of their origin.
171//===----------------------------------------------------------------------===//
172
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000173static void createNullLocation(CXFile *file, unsigned *line,
174 unsigned *column, unsigned *offset) {
175 if (file)
176 *file = 0;
177 if (line)
178 *line = 0;
179 if (column)
180 *column = 0;
181 if (offset)
182 *offset = 0;
183 return;
184}
185
Ted Kremenekce6a5712011-10-31 22:23:51 +0000186static void createNullLocation(CXString *filename, unsigned *line,
187 unsigned *column, unsigned *offset = 0) {
188 if (filename)
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000189 *filename = cxstring::createEmpty();
Ted Kremenekce6a5712011-10-31 22:23:51 +0000190 if (line)
191 *line = 0;
192 if (column)
193 *column = 0;
194 if (offset)
195 *offset = 0;
196 return;
197}
198
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000199extern "C" {
200
Argyrios Kyrtzidis25f7af12013-04-12 17:06:51 +0000201int clang_Location_isInSystemHeader(CXSourceLocation location) {
202 const SourceLocation Loc =
203 SourceLocation::getFromRawEncoding(location.int_data);
204 if (Loc.isInvalid())
205 return 0;
206
207 const SourceManager &SM =
208 *static_cast<const SourceManager*>(location.ptr_data[0]);
209 return SM.isInSystemHeader(Loc);
210}
211
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000212int clang_Location_isFromMainFile(CXSourceLocation location) {
213 const SourceLocation Loc =
214 SourceLocation::getFromRawEncoding(location.int_data);
215 if (Loc.isInvalid())
216 return 0;
217
218 const SourceManager &SM =
219 *static_cast<const SourceManager*>(location.ptr_data[0]);
Eli Friedman5ba37d52013-08-22 00:27:10 +0000220 return SM.isWrittenInMainFile(Loc);
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000221}
222
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000223void clang_getExpansionLocation(CXSourceLocation location,
224 CXFile *file,
225 unsigned *line,
226 unsigned *column,
227 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000228
Ted Kremenekd010ba42011-11-10 08:43:12 +0000229 if (!isASTUnitSourceLocation(location)) {
230 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
231 return;
232 }
233
234 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
235
236 if (!location.ptr_data[0] || Loc.isInvalid()) {
237 createNullLocation(file, line, column, offset);
238 return;
239 }
240
241 const SourceManager &SM =
242 *static_cast<const SourceManager*>(location.ptr_data[0]);
243 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000244
Ted Kremenekd010ba42011-11-10 08:43:12 +0000245 // Check that the FileID is invalid on the expansion location.
246 // This can manifest in invalid code.
247 FileID fileID = SM.getFileID(ExpansionLoc);
248 bool Invalid = false;
249 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
250 if (Invalid || !sloc.isFile()) {
251 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidis7ca77352011-11-03 02:20:36 +0000252 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000253 }
254
Ted Kremenekd010ba42011-11-10 08:43:12 +0000255 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000256 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000257 if (line)
258 *line = SM.getExpansionLineNumber(ExpansionLoc);
259 if (column)
260 *column = SM.getExpansionColumnNumber(ExpansionLoc);
261 if (offset)
262 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000263}
264
265void clang_getPresumedLocation(CXSourceLocation location,
266 CXString *filename,
267 unsigned *line,
268 unsigned *column) {
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000269
Ted Kremenekd010ba42011-11-10 08:43:12 +0000270 if (!isASTUnitSourceLocation(location)) {
271 // Other SourceLocation implementations do not support presumed locations
272 // at this time.
273 createNullLocation(filename, line, column);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000274 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000275 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000276
277 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
278
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000279 if (!location.ptr_data[0] || Loc.isInvalid()) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000280 createNullLocation(filename, line, column);
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000281 return;
Ted Kremenekd010ba42011-11-10 08:43:12 +0000282 }
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000283
284 const SourceManager &SM =
285 *static_cast<const SourceManager *>(location.ptr_data[0]);
286 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
287 if (PreLoc.isInvalid()) {
288 createNullLocation(filename, line, column);
289 return;
290 }
291
292 if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
293 if (line) *line = PreLoc.getLine();
294 if (column) *column = PreLoc.getColumn();
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000295}
296
297void clang_getInstantiationLocation(CXSourceLocation location,
298 CXFile *file,
299 unsigned *line,
300 unsigned *column,
301 unsigned *offset) {
302 // Redirect to new API.
303 clang_getExpansionLocation(location, file, line, column, offset);
304}
305
306void clang_getSpellingLocation(CXSourceLocation location,
307 CXFile *file,
308 unsigned *line,
309 unsigned *column,
310 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000311
Ted Kremenekd010ba42011-11-10 08:43:12 +0000312 if (!isASTUnitSourceLocation(location)) {
313 CXLoadedDiagnostic::decodeLocation(location, file, line,
314 column, offset);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000315 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000316 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000317
318 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
319
320 if (!location.ptr_data[0] || Loc.isInvalid())
321 return createNullLocation(file, line, column, offset);
322
323 const SourceManager &SM =
324 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000325 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek372735f2012-12-19 01:16:49 +0000326 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000327 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
328 FileID FID = LocInfo.first;
329 unsigned FileOffset = LocInfo.second;
330
331 if (FID.isInvalid())
332 return createNullLocation(file, line, column, offset);
333
334 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000335 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000336 if (line)
337 *line = SM.getLineNumber(FID, FileOffset);
338 if (column)
339 *column = SM.getColumnNumber(FID, FileOffset);
340 if (offset)
341 *offset = FileOffset;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000342}
343
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000344void clang_getFileLocation(CXSourceLocation location,
345 CXFile *file,
346 unsigned *line,
347 unsigned *column,
348 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000349
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000350 if (!isASTUnitSourceLocation(location)) {
351 CXLoadedDiagnostic::decodeLocation(location, file, line,
352 column, offset);
353 return;
354 }
355
356 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
357
358 if (!location.ptr_data[0] || Loc.isInvalid())
359 return createNullLocation(file, line, column, offset);
360
361 const SourceManager &SM =
362 *static_cast<const SourceManager*>(location.ptr_data[0]);
363 SourceLocation FileLoc = SM.getFileLoc(Loc);
364 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
365 FileID FID = LocInfo.first;
366 unsigned FileOffset = LocInfo.second;
367
368 if (FID.isInvalid())
369 return createNullLocation(file, line, column, offset);
370
371 if (file)
Dmitri Gribenkof9304482013-01-23 15:56:07 +0000372 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000373 if (line)
374 *line = SM.getLineNumber(FID, FileOffset);
375 if (column)
376 *column = SM.getColumnNumber(FID, FileOffset);
377 if (offset)
378 *offset = FileOffset;
379}
380
381} // end extern "C"