blob: 2e0ea4e440999ecb6955367653d18a70089246e5 [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
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000041CXSourceLocation clang_getNullLocation() {
Craig Topper69186e72014-06-08 08:38:04 +000042 CXSourceLocation Result = { { nullptr, nullptr }, 0 };
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000043 return Result;
44}
45
46unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
47 return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
48 loc1.ptr_data[1] == loc2.ptr_data[1] &&
49 loc1.int_data == loc2.int_data);
50}
51
52CXSourceRange clang_getNullRange() {
Craig Topper69186e72014-06-08 08:38:04 +000053 CXSourceRange Result = { { nullptr, nullptr }, 0, 0 };
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000054 return Result;
55}
56
57CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
Ted Kremenekd010ba42011-11-10 08:43:12 +000058 if (!isASTUnitSourceLocation(begin)) {
59 if (isASTUnitSourceLocation(end))
60 return clang_getNullRange();
61 CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
62 return Result;
63 }
64
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000065 if (begin.ptr_data[0] != end.ptr_data[0] ||
66 begin.ptr_data[1] != end.ptr_data[1])
67 return clang_getNullRange();
68
69 CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
70 begin.int_data, end.int_data };
71
72 return Result;
73}
74
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000075unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
76 return range1.ptr_data[0] == range2.ptr_data[0]
77 && range1.ptr_data[1] == range2.ptr_data[1]
78 && range1.begin_int_data == range2.begin_int_data
79 && range1.end_int_data == range2.end_int_data;
80}
81
82int clang_Range_isNull(CXSourceRange range) {
83 return clang_equalRanges(range, clang_getNullRange());
84}
85
86
87CXSourceLocation clang_getRangeStart(CXSourceRange range) {
Ted Kremenekd010ba42011-11-10 08:43:12 +000088 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
89 if ((uintptr_t)range.ptr_data[0] & 0x1) {
Craig Topper69186e72014-06-08 08:38:04 +000090 CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
Ted Kremenekd010ba42011-11-10 08:43:12 +000091 return Result;
92 }
93
Ted Kremenek4c4f08d2011-10-31 22:05:42 +000094 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
95 range.begin_int_data };
96 return Result;
97}
98
99CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000100 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
101 if ((uintptr_t)range.ptr_data[0] & 0x1) {
Craig Topper69186e72014-06-08 08:38:04 +0000102 CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
Ted Kremenekd010ba42011-11-10 08:43:12 +0000103 return Result;
104 }
105
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000106 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
107 range.end_int_data };
108 return Result;
109}
110
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000111//===----------------------------------------------------------------------===//
112// Getting CXSourceLocations and CXSourceRanges from a translation unit.
113//===----------------------------------------------------------------------===//
114
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000115CXSourceLocation clang_getLocation(CXTranslationUnit TU,
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000116 CXFile file,
117 unsigned line,
118 unsigned column) {
Dmitri Gribenko852d6222014-02-11 15:02:48 +0000119 if (cxtu::isNotUsableTU(TU)) {
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000120 LOG_BAD_TU(TU);
121 return clang_getNullLocation();
122 }
123 if (!file)
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000124 return clang_getNullLocation();
Argyrios Kyrtzidis5fcef772013-09-12 01:10:36 +0000125 if (line == 0 || column == 0)
126 return clang_getNullLocation();
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000127
Erik Pilkington53937db2016-10-20 02:46:22 +0000128 LogRef Log = Logger::make(__func__);
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",
Mehdi Amini004b9c72016-10-10 22:52:47 +0000136 File->getName().str().c_str(), 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)
Mehdi Amini004b9c72016-10-10 22:52:47 +0000143 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
144 line, column)
Argyrios Kyrtzidisea474352013-01-10 18:54:52 +0000145 << CXLoc;
Mehdi Amini004b9c72016-10-10 22:52:47 +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 Gribenko852d6222014-02-11 15:02:48 +0000153 if (cxtu::isNotUsableTU(TU)) {
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000154 LOG_BAD_TU(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000155 return clang_getNullLocation();
Dmitri Gribenko256454f2014-02-11 14:34:14 +0000156 }
157 if (!file)
158 return clang_getNullLocation();
159
Dmitri Gribenkoc22ea1c2013-01-26 18:53:38 +0000160 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000161
162 SourceLocation SLoc
163 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
164
165 if (SLoc.isInvalid())
166 return clang_getNullLocation();
167
168 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
169}
170
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000171//===----------------------------------------------------------------------===//
172// Routines for expanding and manipulating CXSourceLocations, regardless
173// of their origin.
174//===----------------------------------------------------------------------===//
175
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000176static void createNullLocation(CXFile *file, unsigned *line,
177 unsigned *column, unsigned *offset) {
178 if (file)
Craig Topper69186e72014-06-08 08:38:04 +0000179 *file = nullptr;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000180 if (line)
181 *line = 0;
182 if (column)
183 *column = 0;
184 if (offset)
185 *offset = 0;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000186}
187
Ted Kremenekce6a5712011-10-31 22:23:51 +0000188static void createNullLocation(CXString *filename, unsigned *line,
Craig Topper69186e72014-06-08 08:38:04 +0000189 unsigned *column, unsigned *offset = nullptr) {
Ted Kremenekce6a5712011-10-31 22:23:51 +0000190 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;
Ted Kremenekce6a5712011-10-31 22:23:51 +0000198}
199
Argyrios Kyrtzidis25f7af12013-04-12 17:06:51 +0000200int clang_Location_isInSystemHeader(CXSourceLocation location) {
201 const SourceLocation Loc =
202 SourceLocation::getFromRawEncoding(location.int_data);
203 if (Loc.isInvalid())
204 return 0;
205
206 const SourceManager &SM =
207 *static_cast<const SourceManager*>(location.ptr_data[0]);
208 return SM.isInSystemHeader(Loc);
209}
210
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000211int clang_Location_isFromMainFile(CXSourceLocation location) {
212 const SourceLocation Loc =
213 SourceLocation::getFromRawEncoding(location.int_data);
214 if (Loc.isInvalid())
215 return 0;
216
217 const SourceManager &SM =
218 *static_cast<const SourceManager*>(location.ptr_data[0]);
Eli Friedman5ba37d52013-08-22 00:27:10 +0000219 return SM.isWrittenInMainFile(Loc);
Stefanus Du Toitdb51c632013-08-08 17:48:14 +0000220}
221
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000222void clang_getExpansionLocation(CXSourceLocation location,
223 CXFile *file,
224 unsigned *line,
225 unsigned *column,
226 unsigned *offset) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000227 if (!isASTUnitSourceLocation(location)) {
228 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
229 return;
230 }
231
232 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
233
234 if (!location.ptr_data[0] || Loc.isInvalid()) {
235 createNullLocation(file, line, column, offset);
236 return;
237 }
238
239 const SourceManager &SM =
240 *static_cast<const SourceManager*>(location.ptr_data[0]);
241 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000242
Ted Kremenekd010ba42011-11-10 08:43:12 +0000243 // Check that the FileID is invalid on the expansion location.
244 // This can manifest in invalid code.
245 FileID fileID = SM.getFileID(ExpansionLoc);
246 bool Invalid = false;
247 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
248 if (Invalid || !sloc.isFile()) {
249 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidis7ca77352011-11-03 02:20:36 +0000250 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000251 }
252
Ted Kremenekd010ba42011-11-10 08:43:12 +0000253 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000254 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000255 if (line)
256 *line = SM.getExpansionLineNumber(ExpansionLoc);
257 if (column)
258 *column = SM.getExpansionColumnNumber(ExpansionLoc);
259 if (offset)
260 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000261}
262
263void clang_getPresumedLocation(CXSourceLocation location,
264 CXString *filename,
265 unsigned *line,
266 unsigned *column) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000267 if (!isASTUnitSourceLocation(location)) {
268 // Other SourceLocation implementations do not support presumed locations
269 // at this time.
270 createNullLocation(filename, line, column);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000271 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000272 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000273
274 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
275
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000276 if (!location.ptr_data[0] || Loc.isInvalid()) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000277 createNullLocation(filename, line, column);
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000278 return;
Ted Kremenekd010ba42011-11-10 08:43:12 +0000279 }
Evgeniy Stepanova98799f2013-09-11 12:33:58 +0000280
281 const SourceManager &SM =
282 *static_cast<const SourceManager *>(location.ptr_data[0]);
283 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
284 if (PreLoc.isInvalid()) {
285 createNullLocation(filename, line, column);
286 return;
287 }
288
289 if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
290 if (line) *line = PreLoc.getLine();
291 if (column) *column = PreLoc.getColumn();
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000292}
293
294void clang_getInstantiationLocation(CXSourceLocation location,
295 CXFile *file,
296 unsigned *line,
297 unsigned *column,
298 unsigned *offset) {
299 // Redirect to new API.
300 clang_getExpansionLocation(location, file, line, column, offset);
301}
302
303void clang_getSpellingLocation(CXSourceLocation location,
304 CXFile *file,
305 unsigned *line,
306 unsigned *column,
307 unsigned *offset) {
Ted Kremenekd010ba42011-11-10 08:43:12 +0000308 if (!isASTUnitSourceLocation(location)) {
309 CXLoadedDiagnostic::decodeLocation(location, file, line,
310 column, offset);
Ted Kremenekce6a5712011-10-31 22:23:51 +0000311 return;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000312 }
Ted Kremenekd010ba42011-11-10 08:43:12 +0000313
314 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
315
316 if (!location.ptr_data[0] || Loc.isInvalid())
317 return createNullLocation(file, line, column, offset);
318
319 const SourceManager &SM =
320 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000321 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek372735f2012-12-19 01:16:49 +0000322 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenekd010ba42011-11-10 08:43:12 +0000323 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
324 FileID FID = LocInfo.first;
325 unsigned FileOffset = LocInfo.second;
326
327 if (FID.isInvalid())
328 return createNullLocation(file, line, column, offset);
329
330 if (file)
David Greene02b002a2013-01-15 22:09:49 +0000331 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Ted Kremenekd010ba42011-11-10 08:43:12 +0000332 if (line)
333 *line = SM.getLineNumber(FID, FileOffset);
334 if (column)
335 *column = SM.getColumnNumber(FID, FileOffset);
336 if (offset)
337 *offset = FileOffset;
Ted Kremenek4c4f08d2011-10-31 22:05:42 +0000338}
339
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000340void clang_getFileLocation(CXSourceLocation location,
341 CXFile *file,
342 unsigned *line,
343 unsigned *column,
344 unsigned *offset) {
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000345 if (!isASTUnitSourceLocation(location)) {
346 CXLoadedDiagnostic::decodeLocation(location, file, line,
347 column, offset);
348 return;
349 }
350
351 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
352
353 if (!location.ptr_data[0] || Loc.isInvalid())
354 return createNullLocation(file, line, column, offset);
355
356 const SourceManager &SM =
357 *static_cast<const SourceManager*>(location.ptr_data[0]);
358 SourceLocation FileLoc = SM.getFileLoc(Loc);
359 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
360 FileID FID = LocInfo.first;
361 unsigned FileOffset = LocInfo.second;
362
363 if (FID.isInvalid())
364 return createNullLocation(file, line, column, offset);
365
366 if (file)
Dmitri Gribenkof9304482013-01-23 15:56:07 +0000367 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
Argyrios Kyrtzidis56be7162013-01-04 18:30:13 +0000368 if (line)
369 *line = SM.getLineNumber(FID, FileOffset);
370 if (column)
371 *column = SM.getColumnNumber(FID, FileOffset);
372 if (offset)
373 *offset = FileOffset;
374}