blob: afbac6db5fe5cdd79631b2951b3ef5018cf0fe06 [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;
25using namespace clang::cxstring;
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +000026using namespace clang::cxindex;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000027
28//===----------------------------------------------------------------------===//
Ted Kremenekce6a5712011-10-31 22:23:51 +000029// Internal predicates on CXSourceLocations.
30//===----------------------------------------------------------------------===//
31
32static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
33 // If the lowest bit is clear then the first ptr_data entry is a SourceManager
34 // pointer, or the CXSourceLocation is a null location.
35 return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
36}
37
38//===----------------------------------------------------------------------===//
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000039// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
40//===----------------------------------------------------------------------===//
41
42extern "C" {
43
44CXSourceLocation clang_getNullLocation() {
45 CXSourceLocation Result = { { 0, 0 }, 0 };
46 return Result;
47}
48
49unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
50 return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
51 loc1.ptr_data[1] == loc2.ptr_data[1] &&
52 loc1.int_data == loc2.int_data);
53}
54
55CXSourceRange clang_getNullRange() {
56 CXSourceRange Result = { { 0, 0 }, 0, 0 };
57 return Result;
58}
59
60CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
Ted Kremenekd010ba42011-11-10 08:43:12 +000061 if (!isASTUnitSourceLocation(begin)) {
62 if (isASTUnitSourceLocation(end))
63 return clang_getNullRange();
64 CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
65 return Result;
66 }
67
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000068 if (begin.ptr_data[0] != end.ptr_data[0] ||
69 begin.ptr_data[1] != end.ptr_data[1])
70 return clang_getNullRange();
71
72 CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
73 begin.int_data, end.int_data };
74
75 return Result;
76}
77
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000078unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
79 return range1.ptr_data[0] == range2.ptr_data[0]
80 && range1.ptr_data[1] == range2.ptr_data[1]
81 && range1.begin_int_data == range2.begin_int_data
82 && range1.end_int_data == range2.end_int_data;
83}
84
85int clang_Range_isNull(CXSourceRange range) {
86 return clang_equalRanges(range, clang_getNullRange());
87}
88
89
90CXSourceLocation clang_getRangeStart(CXSourceRange range) {
Ted Kremenekd010ba42011-11-10 08:43:12 +000091 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
92 if ((uintptr_t)range.ptr_data[0] & 0x1) {
93 CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
94 return Result;
95 }
96
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000097 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
98 range.begin_int_data };
99 return Result;
100}
101
102CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000103 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
104 if ((uintptr_t)range.ptr_data[0] & 0x1) {
105 CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
106 return Result;
107 }
108
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000109 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
110 range.end_int_data };
111 return Result;
112}
113
114} // end extern "C"
115
116//===----------------------------------------------------------------------===//
117// Getting CXSourceLocations and CXSourceRanges from a translation unit.
118//===----------------------------------------------------------------------===//
119
120extern "C" {
121
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000122CXSourceLocation clang_getLocation(CXTranslationUnit TU,
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000123 CXFile file,
124 unsigned line,
125 unsigned column) {
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000126 if (!TU || !file)
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000127 return clang_getNullLocation();
128
Dmitri Gribenko5ca49f72013-01-11 02:23:13 +0000129 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000130 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000131 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
132 const FileEntry *File = static_cast<const FileEntry *>(file);
133 SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
134 if (SLoc.isInvalid()) {
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000135 if (Log)
136 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
137 File->getName(), line, column);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000138 return clang_getNullLocation();
139 }
140
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000141 CXSourceLocation CXLoc =
142 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
143 if (Log)
144 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
145 << CXLoc;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000146
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000147 return CXLoc;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000148}
149
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000150CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000151 CXFile file,
152 unsigned offset) {
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000153 if (!TU || !file)
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000154 return clang_getNullLocation();
155
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000156 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000157
158 SourceLocation SLoc
159 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
160
161 if (SLoc.isInvalid())
162 return clang_getNullLocation();
163
164 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
165}
166
167} // end extern "C"
168
169//===----------------------------------------------------------------------===//
170// Routines for expanding and manipulating CXSourceLocations, regardless
171// of their origin.
172//===----------------------------------------------------------------------===//
173
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000174static void createNullLocation(CXFile *file, unsigned *line,
175 unsigned *column, unsigned *offset) {
176 if (file)
177 *file = 0;
178 if (line)
179 *line = 0;
180 if (column)
181 *column = 0;
182 if (offset)
183 *offset = 0;
184 return;
185}
186
Ted Kremenekce6a5712011-10-31 22:23:51 +0000187static void createNullLocation(CXString *filename, unsigned *line,
188 unsigned *column, unsigned *offset = 0) {
189 if (filename)
Dmitri Gribenko36a6dd02013-02-01 14:21:22 +0000190 *filename = cxstring::createEmpty();
Ted Kremenekce6a5712011-10-31 22:23:51 +0000191 if (line)
192 *line = 0;
193 if (column)
194 *column = 0;
195 if (offset)
196 *offset = 0;
197 return;
198}
199
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000200extern "C" {
201
202void clang_getExpansionLocation(CXSourceLocation location,
203 CXFile *file,
204 unsigned *line,
205 unsigned *column,
206 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000207
Ted Kremenekd010ba42011-11-10 08:43:12 +0000208 if (!isASTUnitSourceLocation(location)) {
209 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
210 return;
211 }
212
213 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
214
215 if (!location.ptr_data[0] || Loc.isInvalid()) {
216 createNullLocation(file, line, column, offset);
217 return;
218 }
219
220 const SourceManager &SM =
221 *static_cast<const SourceManager*>(location.ptr_data[0]);
222 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000223
Ted Kremenekd010ba42011-11-10 08:43:12 +0000224 // Check that the FileID is invalid on the expansion location.
225 // This can manifest in invalid code.
226 FileID fileID = SM.getFileID(ExpansionLoc);
227 bool Invalid = false;
228 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
229 if (Invalid || !sloc.isFile()) {
230 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidis7ca77352011-11-03 02:20:36 +0000231 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000232 }
233
Ted Kremenekd010ba42011-11-10 08:43:12 +0000234 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000235 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000236 if (line)
237 *line = SM.getExpansionLineNumber(ExpansionLoc);
238 if (column)
239 *column = SM.getExpansionColumnNumber(ExpansionLoc);
240 if (offset)
241 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000242}
243
244void clang_getPresumedLocation(CXSourceLocation location,
245 CXString *filename,
246 unsigned *line,
247 unsigned *column) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000248
Ted Kremenekd010ba42011-11-10 08:43:12 +0000249 if (!isASTUnitSourceLocation(location)) {
250 // Other SourceLocation implementations do not support presumed locations
251 // at this time.
252 createNullLocation(filename, line, column);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000253 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000254 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000255
256 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
257
258 if (!location.ptr_data[0] || Loc.isInvalid())
259 createNullLocation(filename, line, column);
260 else {
261 const SourceManager &SM =
262 *static_cast<const SourceManager*>(location.ptr_data[0]);
263 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
264
265 if (filename)
266 *filename = createCXString(PreLoc.getFilename());
267 if (line)
268 *line = PreLoc.getLine();
269 if (column)
270 *column = PreLoc.getColumn();
271 }
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000272}
273
274void clang_getInstantiationLocation(CXSourceLocation location,
275 CXFile *file,
276 unsigned *line,
277 unsigned *column,
278 unsigned *offset) {
279 // Redirect to new API.
280 clang_getExpansionLocation(location, file, line, column, offset);
281}
282
283void clang_getSpellingLocation(CXSourceLocation location,
284 CXFile *file,
285 unsigned *line,
286 unsigned *column,
287 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000288
Ted Kremenekd010ba42011-11-10 08:43:12 +0000289 if (!isASTUnitSourceLocation(location)) {
290 CXLoadedDiagnostic::decodeLocation(location, file, line,
291 column, offset);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000292 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000293 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000294
295 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
296
297 if (!location.ptr_data[0] || Loc.isInvalid())
298 return createNullLocation(file, line, column, offset);
299
300 const SourceManager &SM =
301 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000302 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek372735f2012-12-19 01:16:49 +0000303 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000304 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
305 FileID FID = LocInfo.first;
306 unsigned FileOffset = LocInfo.second;
307
308 if (FID.isInvalid())
309 return createNullLocation(file, line, column, offset);
310
311 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000312 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000313 if (line)
314 *line = SM.getLineNumber(FID, FileOffset);
315 if (column)
316 *column = SM.getColumnNumber(FID, FileOffset);
317 if (offset)
318 *offset = FileOffset;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000319}
320
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000321void clang_getFileLocation(CXSourceLocation location,
322 CXFile *file,
323 unsigned *line,
324 unsigned *column,
325 unsigned *offset) {
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000326
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000327 if (!isASTUnitSourceLocation(location)) {
328 CXLoadedDiagnostic::decodeLocation(location, file, line,
329 column, offset);
330 return;
331 }
332
333 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
334
335 if (!location.ptr_data[0] || Loc.isInvalid())
336 return createNullLocation(file, line, column, offset);
337
338 const SourceManager &SM =
339 *static_cast<const SourceManager*>(location.ptr_data[0]);
340 SourceLocation FileLoc = SM.getFileLoc(Loc);
341 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
342 FileID FID = LocInfo.first;
343 unsigned FileOffset = LocInfo.second;
344
345 if (FID.isInvalid())
346 return createNullLocation(file, line, column, offset);
347
348 if (file)
Dmitri Gribenkof9304482013-01-23 15:56:07 +0000349 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000350 if (line)
351 *line = SM.getLineNumber(FID, FileOffset);
352 if (column)
353 *column = SM.getColumnNumber(FID, FileOffset);
354 if (offset)
355 *offset = FileOffset;
356}
357
358} // end extern "C"