blob: 8d88a116e048f2ce3953497ba47726a99e414d72 [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"
Ted Kremenek15322172011-11-10 08:43:12 +000016#include "CXLoadedDiagnostic.h"
Chandler Carruthf59edb92012-12-04 09:25:21 +000017#include "CXSourceLocation.h"
18#include "CXString.h"
19#include "CXTranslationUnit.h"
Ted Kremenek3ddef062011-10-31 22:05:42 +000020
21using namespace clang;
22using namespace clang::cxstring;
23
24//===----------------------------------------------------------------------===//
Ted Kremenek51a7d5d2011-10-31 22:23:51 +000025// Internal predicates on CXSourceLocations.
26//===----------------------------------------------------------------------===//
27
28static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
29 // If the lowest bit is clear then the first ptr_data entry is a SourceManager
30 // pointer, or the CXSourceLocation is a null location.
31 return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
32}
33
34//===----------------------------------------------------------------------===//
Ted Kremenek3ddef062011-10-31 22:05:42 +000035// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
36//===----------------------------------------------------------------------===//
37
38extern "C" {
39
40CXSourceLocation clang_getNullLocation() {
41 CXSourceLocation Result = { { 0, 0 }, 0 };
42 return Result;
43}
44
45unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
46 return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
47 loc1.ptr_data[1] == loc2.ptr_data[1] &&
48 loc1.int_data == loc2.int_data);
49}
50
51CXSourceRange clang_getNullRange() {
52 CXSourceRange Result = { { 0, 0 }, 0, 0 };
53 return Result;
54}
55
56CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
Ted Kremenek15322172011-11-10 08:43:12 +000057 if (!isASTUnitSourceLocation(begin)) {
58 if (isASTUnitSourceLocation(end))
59 return clang_getNullRange();
60 CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
61 return Result;
62 }
63
Ted Kremenek3ddef062011-10-31 22:05:42 +000064 if (begin.ptr_data[0] != end.ptr_data[0] ||
65 begin.ptr_data[1] != end.ptr_data[1])
66 return clang_getNullRange();
67
68 CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
69 begin.int_data, end.int_data };
70
71 return Result;
72}
73
Ted Kremenek3ddef062011-10-31 22:05:42 +000074unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
75 return range1.ptr_data[0] == range2.ptr_data[0]
76 && range1.ptr_data[1] == range2.ptr_data[1]
77 && range1.begin_int_data == range2.begin_int_data
78 && range1.end_int_data == range2.end_int_data;
79}
80
81int clang_Range_isNull(CXSourceRange range) {
82 return clang_equalRanges(range, clang_getNullRange());
83}
84
85
86CXSourceLocation clang_getRangeStart(CXSourceRange range) {
Ted Kremenek15322172011-11-10 08:43:12 +000087 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
88 if ((uintptr_t)range.ptr_data[0] & 0x1) {
89 CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
90 return Result;
91 }
92
Ted Kremenek3ddef062011-10-31 22:05:42 +000093 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
94 range.begin_int_data };
95 return Result;
96}
97
98CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
Ted Kremenek15322172011-11-10 08:43:12 +000099 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
100 if ((uintptr_t)range.ptr_data[0] & 0x1) {
101 CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
102 return Result;
103 }
104
Ted Kremenek3ddef062011-10-31 22:05:42 +0000105 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
106 range.end_int_data };
107 return Result;
108}
109
110} // end extern "C"
111
112//===----------------------------------------------------------------------===//
113// Getting CXSourceLocations and CXSourceRanges from a translation unit.
114//===----------------------------------------------------------------------===//
115
116extern "C" {
117
118CXSourceLocation clang_getLocation(CXTranslationUnit tu,
119 CXFile file,
120 unsigned line,
121 unsigned column) {
122 if (!tu || !file)
123 return clang_getNullLocation();
124
125 bool Logging = ::getenv("LIBCLANG_LOGGING");
126 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
127 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
128 const FileEntry *File = static_cast<const FileEntry *>(file);
129 SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
130 if (SLoc.isInvalid()) {
131 if (Logging)
132 llvm::errs() << "clang_getLocation(\"" << File->getName()
133 << "\", " << line << ", " << column << ") = invalid\n";
134 return clang_getNullLocation();
135 }
136
137 if (Logging)
138 llvm::errs() << "clang_getLocation(\"" << File->getName()
139 << "\", " << line << ", " << column << ") = "
140 << SLoc.getRawEncoding() << "\n";
141
142 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
143}
144
145CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
146 CXFile file,
147 unsigned offset) {
148 if (!tu || !file)
149 return clang_getNullLocation();
150
151 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
152
153 SourceLocation SLoc
154 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
155
156 if (SLoc.isInvalid())
157 return clang_getNullLocation();
158
159 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
160}
161
162} // end extern "C"
163
164//===----------------------------------------------------------------------===//
165// Routines for expanding and manipulating CXSourceLocations, regardless
166// of their origin.
167//===----------------------------------------------------------------------===//
168
Ted Kremenek3ddef062011-10-31 22:05:42 +0000169static void createNullLocation(CXFile *file, unsigned *line,
170 unsigned *column, unsigned *offset) {
171 if (file)
172 *file = 0;
173 if (line)
174 *line = 0;
175 if (column)
176 *column = 0;
177 if (offset)
178 *offset = 0;
179 return;
180}
181
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000182static void createNullLocation(CXString *filename, unsigned *line,
183 unsigned *column, unsigned *offset = 0) {
184 if (filename)
185 *filename = createCXString("");
186 if (line)
187 *line = 0;
188 if (column)
189 *column = 0;
190 if (offset)
191 *offset = 0;
192 return;
193}
194
Ted Kremenek3ddef062011-10-31 22:05:42 +0000195extern "C" {
196
197void clang_getExpansionLocation(CXSourceLocation location,
198 CXFile *file,
199 unsigned *line,
200 unsigned *column,
201 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000202
Ted Kremenek15322172011-11-10 08:43:12 +0000203 if (!isASTUnitSourceLocation(location)) {
204 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
205 return;
206 }
207
208 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
209
210 if (!location.ptr_data[0] || Loc.isInvalid()) {
211 createNullLocation(file, line, column, offset);
212 return;
213 }
214
215 const SourceManager &SM =
216 *static_cast<const SourceManager*>(location.ptr_data[0]);
217 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000218
Ted Kremenek15322172011-11-10 08:43:12 +0000219 // Check that the FileID is invalid on the expansion location.
220 // This can manifest in invalid code.
221 FileID fileID = SM.getFileID(ExpansionLoc);
222 bool Invalid = false;
223 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
224 if (Invalid || !sloc.isFile()) {
225 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidisb4efaa02011-11-03 02:20:36 +0000226 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000227 }
228
Ted Kremenek15322172011-11-10 08:43:12 +0000229 if (file)
230 *file = (void *)SM.getFileEntryForSLocEntry(sloc);
231 if (line)
232 *line = SM.getExpansionLineNumber(ExpansionLoc);
233 if (column)
234 *column = SM.getExpansionColumnNumber(ExpansionLoc);
235 if (offset)
236 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000237}
238
239void clang_getPresumedLocation(CXSourceLocation location,
240 CXString *filename,
241 unsigned *line,
242 unsigned *column) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000243
Ted Kremenek15322172011-11-10 08:43:12 +0000244 if (!isASTUnitSourceLocation(location)) {
245 // Other SourceLocation implementations do not support presumed locations
246 // at this time.
247 createNullLocation(filename, line, column);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000248 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000249 }
Ted Kremenek15322172011-11-10 08:43:12 +0000250
251 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
252
253 if (!location.ptr_data[0] || Loc.isInvalid())
254 createNullLocation(filename, line, column);
255 else {
256 const SourceManager &SM =
257 *static_cast<const SourceManager*>(location.ptr_data[0]);
258 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
259
260 if (filename)
261 *filename = createCXString(PreLoc.getFilename());
262 if (line)
263 *line = PreLoc.getLine();
264 if (column)
265 *column = PreLoc.getColumn();
266 }
Ted Kremenek3ddef062011-10-31 22:05:42 +0000267}
268
269void clang_getInstantiationLocation(CXSourceLocation location,
270 CXFile *file,
271 unsigned *line,
272 unsigned *column,
273 unsigned *offset) {
274 // Redirect to new API.
275 clang_getExpansionLocation(location, file, line, column, offset);
276}
277
278void clang_getSpellingLocation(CXSourceLocation location,
279 CXFile *file,
280 unsigned *line,
281 unsigned *column,
282 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000283
Ted Kremenek15322172011-11-10 08:43:12 +0000284 if (!isASTUnitSourceLocation(location)) {
285 CXLoadedDiagnostic::decodeLocation(location, file, line,
286 column, offset);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000287 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000288 }
Ted Kremenek15322172011-11-10 08:43:12 +0000289
290 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
291
292 if (!location.ptr_data[0] || Loc.isInvalid())
293 return createNullLocation(file, line, column, offset);
294
295 const SourceManager &SM =
296 *static_cast<const SourceManager*>(location.ptr_data[0]);
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000297 // FIXME: This should call SourceManager::getSpellingLoc().
Ted Kremenek6ee225c2012-12-19 01:16:49 +0000298 SourceLocation SpellLoc = SM.getFileLoc(Loc);
Ted Kremenek15322172011-11-10 08:43:12 +0000299 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
300 FileID FID = LocInfo.first;
301 unsigned FileOffset = LocInfo.second;
302
303 if (FID.isInvalid())
304 return createNullLocation(file, line, column, offset);
305
306 if (file)
307 *file = (void *)SM.getFileEntryForID(FID);
308 if (line)
309 *line = SM.getLineNumber(FID, FileOffset);
310 if (column)
311 *column = SM.getColumnNumber(FID, FileOffset);
312 if (offset)
313 *offset = FileOffset;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000314}
315
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000316void clang_getFileLocation(CXSourceLocation location,
317 CXFile *file,
318 unsigned *line,
319 unsigned *column,
320 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000321
Argyrios Kyrtzidis2d5c1332013-01-04 18:30:13 +0000322 if (!isASTUnitSourceLocation(location)) {
323 CXLoadedDiagnostic::decodeLocation(location, file, line,
324 column, offset);
325 return;
326 }
327
328 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
329
330 if (!location.ptr_data[0] || Loc.isInvalid())
331 return createNullLocation(file, line, column, offset);
332
333 const SourceManager &SM =
334 *static_cast<const SourceManager*>(location.ptr_data[0]);
335 SourceLocation FileLoc = SM.getFileLoc(Loc);
336 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
337 FileID FID = LocInfo.first;
338 unsigned FileOffset = LocInfo.second;
339
340 if (FID.isInvalid())
341 return createNullLocation(file, line, column, offset);
342
343 if (file)
344 *file = (void *)SM.getFileEntryForID(FID);
345 if (line)
346 *line = SM.getLineNumber(FID, FileOffset);
347 if (column)
348 *column = SM.getColumnNumber(FID, FileOffset);
349 if (offset)
350 *offset = FileOffset;
351}
352
353} // end extern "C"