blob: b7c7622c66b213dc5d14c29f3a23a00fe96695df [file] [log] [blame]
Ted Kremenek3ddef062011-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 Kremenek3ddef062011-10-31 22:05:42 +000015#include "CIndexer.h"
Chandler Carruthb1ba0ef2013-01-19 08:09:44 +000016#include "CLog.h"
Ted Kremenek15322172011-11-10 08:43:12 +000017#include "CXLoadedDiagnostic.h"
Chandler Carruthf59edb92012-12-04 09:25:21 +000018#include "CXSourceLocation.h"
19#include "CXString.h"
20#include "CXTranslationUnit.h"
Dmitri Gribenkoacbe4ba2013-01-11 02:23:13 +000021#include "llvm/Support/Compiler.h"
Argyrios Kyrtzidisc6f5c6a2013-01-10 18:54:52 +000022#include "llvm/Support/Format.h"
Ted Kremenek3ddef062011-10-31 22:05:42 +000023
24using namespace clang;
Argyrios Kyrtzidisc6f5c6a2013-01-10 18:54:52 +000025using namespace clang::cxindex;
Ted Kremenek3ddef062011-10-31 22:05:42 +000026
27//===----------------------------------------------------------------------===//
Ted Kremenek51a7d5d2011-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 Kremenek3ddef062011-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 Kremenek15322172011-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 Kremenek3ddef062011-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 Kremenek3ddef062011-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 Kremenek15322172011-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 Kremenek3ddef062011-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 Kremenek15322172011-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 Kremenek3ddef062011-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 Gribenko5694feb2013-01-26 18:53:38 +0000121CXSourceLocation clang_getLocation(CXTranslationUnit TU,
Ted Kremenek3ddef062011-10-31 22:05:42 +0000122 CXFile file,
123 unsigned line,
124 unsigned column) {
Dmitri Gribenko5694feb2013-01-26 18:53:38 +0000125 if (!TU || !file)
Ted Kremenek3ddef062011-10-31 22:05:42 +0000126 return clang_getNullLocation();
127
Dmitri Gribenkoacbe4ba2013-01-11 02:23:13 +0000128 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
Dmitri Gribenko5694feb2013-01-26 18:53:38 +0000129 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek3ddef062011-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 Kyrtzidisc6f5c6a2013-01-10 18:54:52 +0000134 if (Log)
135 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
136 File->getName(), line, column);
Ted Kremenek3ddef062011-10-31 22:05:42 +0000137 return clang_getNullLocation();
138 }
139
Argyrios Kyrtzidisc6f5c6a2013-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 Kremenek3ddef062011-10-31 22:05:42 +0000145
Argyrios Kyrtzidisc6f5c6a2013-01-10 18:54:52 +0000146 return CXLoc;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000147}
148
Dmitri Gribenko5694feb2013-01-26 18:53:38 +0000149CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
Ted Kremenek3ddef062011-10-31 22:05:42 +0000150 CXFile file,
151 unsigned offset) {
Dmitri Gribenko5694feb2013-01-26 18:53:38 +0000152 if (!TU || !file)
Ted Kremenek3ddef062011-10-31 22:05:42 +0000153 return clang_getNullLocation();
154
Dmitri Gribenko5694feb2013-01-26 18:53:38 +0000155 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek3ddef062011-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 Kremenek3ddef062011-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 Kremenek51a7d5d2011-10-31 22:23:51 +0000186static void createNullLocation(CXString *filename, unsigned *line,
187 unsigned *column, unsigned *offset = 0) {
188 if (filename)
Dmitri Gribenkodc66adb2013-02-01 14:21:22 +0000189 *filename = cxstring::createEmpty();
Ted Kremenek51a7d5d2011-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 Kremenek3ddef062011-10-31 22:05:42 +0000199extern "C" {
200
Argyrios Kyrtzidis4522f632013-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
Ted Kremenek3ddef062011-10-31 22:05:42 +0000212void clang_getExpansionLocation(CXSourceLocation location,
213 CXFile *file,
214 unsigned *line,
215 unsigned *column,
216 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000217
Ted Kremenek15322172011-11-10 08:43:12 +0000218 if (!isASTUnitSourceLocation(location)) {
219 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
220 return;
221 }
222
223 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
224
225 if (!location.ptr_data[0] || Loc.isInvalid()) {
226 createNullLocation(file, line, column, offset);
227 return;
228 }
229
230 const SourceManager &SM =
231 *static_cast<const SourceManager*>(location.ptr_data[0]);
232 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000233
Ted Kremenek15322172011-11-10 08:43:12 +0000234 // Check that the FileID is invalid on the expansion location.
235 // This can manifest in invalid code.
236 FileID fileID = SM.getFileID(ExpansionLoc);
237 bool Invalid = false;
238 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
239 if (Invalid || !sloc.isFile()) {
240 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidisb4efaa02011-11-03 02:20:36 +0000241 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000242 }
243
Ted Kremenek15322172011-11-10 08:43:12 +0000244 if (file)
David Greene3cfa5322013-01-15 22:09:49 +0000245 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
Ted Kremenek15322172011-11-10 08:43:12 +0000246 if (line)
247 *line = SM.getExpansionLineNumber(ExpansionLoc);
248 if (column)
249 *column = SM.getExpansionColumnNumber(ExpansionLoc);
250 if (offset)
251 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000252}
253
254void clang_getPresumedLocation(CXSourceLocation location,
255 CXString *filename,
256 unsigned *line,
257 unsigned *column) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000258
Ted Kremenek15322172011-11-10 08:43:12 +0000259 if (!isASTUnitSourceLocation(location)) {
260 // Other SourceLocation implementations do not support presumed locations
261 // at this time.
262 createNullLocation(filename, line, column);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000263 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000264 }
Ted Kremenek15322172011-11-10 08:43:12 +0000265
266 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
267
268 if (!location.ptr_data[0] || Loc.isInvalid())
269 createNullLocation(filename, line, column);
270 else {
271 const SourceManager &SM =
272 *static_cast<const SourceManager*>(location.ptr_data[0]);
273 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
274
275 if (filename)
Dmitri Gribenko0c4394c2013-02-02 00:02:12 +0000276 *filename = cxstring::createRef(PreLoc.getFilename());
Ted Kremenek15322172011-11-10 08:43:12 +0000277 if (line)
278 *line = PreLoc.getLine();
279 if (column)
280 *column = PreLoc.getColumn();
281 }
Ted Kremenek3ddef062011-10-31 22:05:42 +0000282}
283
284void clang_getInstantiationLocation(CXSourceLocation location,
285 CXFile *file,
286 unsigned *line,
287 unsigned *column,
288 unsigned *offset) {
289 // Redirect to new API.
290 clang_getExpansionLocation(location, file, line, column, offset);
291}
292
293void clang_getSpellingLocation(CXSourceLocation location,
294 CXFile *file,
295 unsigned *line,
296 unsigned *column,
297 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000298
Ted Kremenek15322172011-11-10 08:43:12 +0000299 if (!isASTUnitSourceLocation(location)) {
300 CXLoadedDiagnostic::decodeLocation(location, file, line,
301 column, offset);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000302 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000303 }
Ted Kremenek15322172011-11-10 08:43:12 +0000304
305 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
306
307 if (!location.ptr_data[0] || Loc.isInvalid())
308 return createNullLocation(file, line, column, offset);
309
310 const SourceManager &SM =
311 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000312 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek6ee225c2012-12-19 01:16:49 +0000313 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenek15322172011-11-10 08:43:12 +0000314 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
315 FileID FID = LocInfo.first;
316 unsigned FileOffset = LocInfo.second;
317
318 if (FID.isInvalid())
319 return createNullLocation(file, line, column, offset);
320
321 if (file)
David Greene3cfa5322013-01-15 22:09:49 +0000322 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Ted Kremenek15322172011-11-10 08:43:12 +0000323 if (line)
324 *line = SM.getLineNumber(FID, FileOffset);
325 if (column)
326 *column = SM.getColumnNumber(FID, FileOffset);
327 if (offset)
328 *offset = FileOffset;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000329}
330
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000331void clang_getFileLocation(CXSourceLocation location,
332 CXFile *file,
333 unsigned *line,
334 unsigned *column,
335 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000336
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000337 if (!isASTUnitSourceLocation(location)) {
338 CXLoadedDiagnostic::decodeLocation(location, file, line,
339 column, offset);
340 return;
341 }
342
343 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
344
345 if (!location.ptr_data[0] || Loc.isInvalid())
346 return createNullLocation(file, line, column, offset);
347
348 const SourceManager &SM =
349 *static_cast<const SourceManager*>(location.ptr_data[0]);
350 SourceLocation FileLoc = SM.getFileLoc(Loc);
351 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
352 FileID FID = LocInfo.first;
353 unsigned FileOffset = LocInfo.second;
354
355 if (FID.isInvalid())
356 return createNullLocation(file, line, column, offset);
357
358 if (file)
Dmitri Gribenkoe4ea8792013-01-23 15:56:07 +0000359 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000360 if (line)
361 *line = SM.getLineNumber(FID, FileOffset);
362 if (column)
363 *column = SM.getColumnNumber(FID, FileOffset);
364 if (offset)
365 *offset = FileOffset;
366}
367
368} // end extern "C"