blob: bc8d5751903c92b0ecc9218e654f56a9fd182c4a [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
201void clang_getExpansionLocation(CXSourceLocation location,
202 CXFile *file,
203 unsigned *line,
204 unsigned *column,
205 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000206
Ted Kremenek15322172011-11-10 08:43:12 +0000207 if (!isASTUnitSourceLocation(location)) {
208 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
209 return;
210 }
211
212 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
213
214 if (!location.ptr_data[0] || Loc.isInvalid()) {
215 createNullLocation(file, line, column, offset);
216 return;
217 }
218
219 const SourceManager &SM =
220 *static_cast<const SourceManager*>(location.ptr_data[0]);
221 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000222
Ted Kremenek15322172011-11-10 08:43:12 +0000223 // Check that the FileID is invalid on the expansion location.
224 // This can manifest in invalid code.
225 FileID fileID = SM.getFileID(ExpansionLoc);
226 bool Invalid = false;
227 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
228 if (Invalid || !sloc.isFile()) {
229 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidisb4efaa02011-11-03 02:20:36 +0000230 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000231 }
232
Ted Kremenek15322172011-11-10 08:43:12 +0000233 if (file)
David Greene3cfa5322013-01-15 22:09:49 +0000234 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
Ted Kremenek15322172011-11-10 08:43:12 +0000235 if (line)
236 *line = SM.getExpansionLineNumber(ExpansionLoc);
237 if (column)
238 *column = SM.getExpansionColumnNumber(ExpansionLoc);
239 if (offset)
240 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000241}
242
243void clang_getPresumedLocation(CXSourceLocation location,
244 CXString *filename,
245 unsigned *line,
246 unsigned *column) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000247
Ted Kremenek15322172011-11-10 08:43:12 +0000248 if (!isASTUnitSourceLocation(location)) {
249 // Other SourceLocation implementations do not support presumed locations
250 // at this time.
251 createNullLocation(filename, line, column);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000252 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000253 }
Ted Kremenek15322172011-11-10 08:43:12 +0000254
255 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
256
257 if (!location.ptr_data[0] || Loc.isInvalid())
258 createNullLocation(filename, line, column);
259 else {
260 const SourceManager &SM =
261 *static_cast<const SourceManager*>(location.ptr_data[0]);
262 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
263
264 if (filename)
Dmitri Gribenko0c4394c2013-02-02 00:02:12 +0000265 *filename = cxstring::createRef(PreLoc.getFilename());
Ted Kremenek15322172011-11-10 08:43:12 +0000266 if (line)
267 *line = PreLoc.getLine();
268 if (column)
269 *column = PreLoc.getColumn();
270 }
Ted Kremenek3ddef062011-10-31 22:05:42 +0000271}
272
273void clang_getInstantiationLocation(CXSourceLocation location,
274 CXFile *file,
275 unsigned *line,
276 unsigned *column,
277 unsigned *offset) {
278 // Redirect to new API.
279 clang_getExpansionLocation(location, file, line, column, offset);
280}
281
282void clang_getSpellingLocation(CXSourceLocation location,
283 CXFile *file,
284 unsigned *line,
285 unsigned *column,
286 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000287
Ted Kremenek15322172011-11-10 08:43:12 +0000288 if (!isASTUnitSourceLocation(location)) {
289 CXLoadedDiagnostic::decodeLocation(location, file, line,
290 column, offset);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000291 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000292 }
Ted Kremenek15322172011-11-10 08:43:12 +0000293
294 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
295
296 if (!location.ptr_data[0] || Loc.isInvalid())
297 return createNullLocation(file, line, column, offset);
298
299 const SourceManager &SM =
300 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000301 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek6ee225c2012-12-19 01:16:49 +0000302 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenek15322172011-11-10 08:43:12 +0000303 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
304 FileID FID = LocInfo.first;
305 unsigned FileOffset = LocInfo.second;
306
307 if (FID.isInvalid())
308 return createNullLocation(file, line, column, offset);
309
310 if (file)
David Greene3cfa5322013-01-15 22:09:49 +0000311 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Ted Kremenek15322172011-11-10 08:43:12 +0000312 if (line)
313 *line = SM.getLineNumber(FID, FileOffset);
314 if (column)
315 *column = SM.getColumnNumber(FID, FileOffset);
316 if (offset)
317 *offset = FileOffset;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000318}
319
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000320void clang_getFileLocation(CXSourceLocation location,
321 CXFile *file,
322 unsigned *line,
323 unsigned *column,
324 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000325
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000326 if (!isASTUnitSourceLocation(location)) {
327 CXLoadedDiagnostic::decodeLocation(location, file, line,
328 column, offset);
329 return;
330 }
331
332 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
333
334 if (!location.ptr_data[0] || Loc.isInvalid())
335 return createNullLocation(file, line, column, offset);
336
337 const SourceManager &SM =
338 *static_cast<const SourceManager*>(location.ptr_data[0]);
339 SourceLocation FileLoc = SM.getFileLoc(Loc);
340 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
341 FileID FID = LocInfo.first;
342 unsigned FileOffset = LocInfo.second;
343
344 if (FID.isInvalid())
345 return createNullLocation(file, line, column, offset);
346
347 if (file)
Dmitri Gribenkoe4ea8792013-01-23 15:56:07 +0000348 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000349 if (line)
350 *line = SM.getLineNumber(FID, FileOffset);
351 if (column)
352 *column = SM.getColumnNumber(FID, FileOffset);
353 if (offset)
354 *offset = FileOffset;
355}
356
357} // end extern "C"