blob: 73711772fc0170e2422d3939d6536b1689da653f [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();
Argyrios Kyrtzidis5fcef772013-09-12 01:10:36 +0000127 if (line == 0 || column == 0)
128 return clang_getNullLocation();
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000129
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +0000130 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000131 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000132 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
133 const FileEntry *File = static_cast<const FileEntry *>(file);
134 SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
135 if (SLoc.isInvalid()) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000136 if (Log)
137 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
138 File->getName(), line, column);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000139 return clang_getNullLocation();
140 }
141
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000142 CXSourceLocation CXLoc =
143 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
144 if (Log)
145 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
146 << CXLoc;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000147
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000148 return CXLoc;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000149}
150
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000151CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000152 CXFile file,
153 unsigned offset) {
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000154 if (!TU || !file)
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000155 return clang_getNullLocation();
156
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000157 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000158
159 SourceLocation SLoc
160 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
161
162 if (SLoc.isInvalid())
163 return clang_getNullLocation();
164
165 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
166}
167
168} // end extern "C"
169
170//===----------------------------------------------------------------------===//
171// Routines for expanding and manipulating CXSourceLocations, regardless
172// of their origin.
173//===----------------------------------------------------------------------===//
174
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000175static void createNullLocation(CXFile *file, unsigned *line,
176 unsigned *column, unsigned *offset) {
177 if (file)
178 *file = 0;
179 if (line)
180 *line = 0;
181 if (column)
182 *column = 0;
183 if (offset)
184 *offset = 0;
185 return;
186}
187
Ted Kremenekce6a5712011-10-31 22:23:51 +0000188static void createNullLocation(CXString *filename, unsigned *line,
189 unsigned *column, unsigned *offset = 0) {
190 if (filename)
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000191 *filename = cxstring::createEmpty();
Ted Kremenekce6a5712011-10-31 22:23:51 +0000192 if (line)
193 *line = 0;
194 if (column)
195 *column = 0;
196 if (offset)
197 *offset = 0;
198 return;
199}
200
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000201extern "C" {
202
Argyrios Kyrtzidis25f7af12013-04-12 17:06:51 +0000203int clang_Location_isInSystemHeader(CXSourceLocation location) {
204 const SourceLocation Loc =
205 SourceLocation::getFromRawEncoding(location.int_data);
206 if (Loc.isInvalid())
207 return 0;
208
209 const SourceManager &SM =
210 *static_cast<const SourceManager*>(location.ptr_data[0]);
211 return SM.isInSystemHeader(Loc);
212}
213
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000214int clang_Location_isFromMainFile(CXSourceLocation location) {
215 const SourceLocation Loc =
216 SourceLocation::getFromRawEncoding(location.int_data);
217 if (Loc.isInvalid())
218 return 0;
219
220 const SourceManager &SM =
221 *static_cast<const SourceManager*>(location.ptr_data[0]);
Eli Friedman5ba37d52013-08-22 00:27:10 +0000222 return SM.isWrittenInMainFile(Loc);
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000223}
224
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000225void clang_getExpansionLocation(CXSourceLocation location,
226 CXFile *file,
227 unsigned *line,
228 unsigned *column,
229 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000230
Ted Kremenekd010ba42011-11-10 08:43:12 +0000231 if (!isASTUnitSourceLocation(location)) {
232 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
233 return;
234 }
235
236 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
237
238 if (!location.ptr_data[0] || Loc.isInvalid()) {
239 createNullLocation(file, line, column, offset);
240 return;
241 }
242
243 const SourceManager &SM =
244 *static_cast<const SourceManager*>(location.ptr_data[0]);
245 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000246
Ted Kremenekd010ba42011-11-10 08:43:12 +0000247 // Check that the FileID is invalid on the expansion location.
248 // This can manifest in invalid code.
249 FileID fileID = SM.getFileID(ExpansionLoc);
250 bool Invalid = false;
251 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
252 if (Invalid || !sloc.isFile()) {
253 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidis7ca77352011-11-03 02:20:36 +0000254 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000255 }
256
Ted Kremenekd010ba42011-11-10 08:43:12 +0000257 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000258 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000259 if (line)
260 *line = SM.getExpansionLineNumber(ExpansionLoc);
261 if (column)
262 *column = SM.getExpansionColumnNumber(ExpansionLoc);
263 if (offset)
264 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000265}
266
267void clang_getPresumedLocation(CXSourceLocation location,
268 CXString *filename,
269 unsigned *line,
270 unsigned *column) {
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000271
Ted Kremenekd010ba42011-11-10 08:43:12 +0000272 if (!isASTUnitSourceLocation(location)) {
273 // Other SourceLocation implementations do not support presumed locations
274 // at this time.
275 createNullLocation(filename, line, column);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000276 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000277 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000278
279 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
280
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000281 if (!location.ptr_data[0] || Loc.isInvalid()) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000282 createNullLocation(filename, line, column);
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000283 return;
Ted Kremenekd010ba42011-11-10 08:43:12 +0000284 }
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000285
286 const SourceManager &SM =
287 *static_cast<const SourceManager *>(location.ptr_data[0]);
288 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
289 if (PreLoc.isInvalid()) {
290 createNullLocation(filename, line, column);
291 return;
292 }
293
294 if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
295 if (line) *line = PreLoc.getLine();
296 if (column) *column = PreLoc.getColumn();
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000297}
298
299void clang_getInstantiationLocation(CXSourceLocation location,
300 CXFile *file,
301 unsigned *line,
302 unsigned *column,
303 unsigned *offset) {
304 // Redirect to new API.
305 clang_getExpansionLocation(location, file, line, column, offset);
306}
307
308void clang_getSpellingLocation(CXSourceLocation location,
309 CXFile *file,
310 unsigned *line,
311 unsigned *column,
312 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000313
Ted Kremenekd010ba42011-11-10 08:43:12 +0000314 if (!isASTUnitSourceLocation(location)) {
315 CXLoadedDiagnostic::decodeLocation(location, file, line,
316 column, offset);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000317 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000318 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000319
320 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
321
322 if (!location.ptr_data[0] || Loc.isInvalid())
323 return createNullLocation(file, line, column, offset);
324
325 const SourceManager &SM =
326 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000327 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek372735f2012-12-19 01:16:49 +0000328 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000329 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
330 FileID FID = LocInfo.first;
331 unsigned FileOffset = LocInfo.second;
332
333 if (FID.isInvalid())
334 return createNullLocation(file, line, column, offset);
335
336 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000337 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000338 if (line)
339 *line = SM.getLineNumber(FID, FileOffset);
340 if (column)
341 *column = SM.getColumnNumber(FID, FileOffset);
342 if (offset)
343 *offset = FileOffset;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000344}
345
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000346void clang_getFileLocation(CXSourceLocation location,
347 CXFile *file,
348 unsigned *line,
349 unsigned *column,
350 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000351
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000352 if (!isASTUnitSourceLocation(location)) {
353 CXLoadedDiagnostic::decodeLocation(location, file, line,
354 column, offset);
355 return;
356 }
357
358 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
359
360 if (!location.ptr_data[0] || Loc.isInvalid())
361 return createNullLocation(file, line, column, offset);
362
363 const SourceManager &SM =
364 *static_cast<const SourceManager*>(location.ptr_data[0]);
365 SourceLocation FileLoc = SM.getFileLoc(Loc);
366 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
367 FileID FID = LocInfo.first;
368 unsigned FileOffset = LocInfo.second;
369
370 if (FID.isInvalid())
371 return createNullLocation(file, line, column, offset);
372
373 if (file)
Dmitri Gribenkof9304482013-01-23 15:56:07 +0000374 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000375 if (line)
376 *line = SM.getLineNumber(FID, FileOffset);
377 if (column)
378 *column = SM.getColumnNumber(FID, FileOffset);
379 if (offset)
380 *offset = FileOffset;
381}
382
383} // end extern "C"