blob: a6bf8fcf1cc13700b0abf3cf695ec0fdb06e7f8c [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"
15
16#include "CIndexer.h"
17#include "CXString.h"
18#include "CXSourceLocation.h"
19#include "CXTranslationUnit.h"
Ted Kremenek15322172011-11-10 08:43:12 +000020#include "CXLoadedDiagnostic.h"
Ted Kremenek3ddef062011-10-31 22:05:42 +000021
22using namespace clang;
23using namespace clang::cxstring;
24
25//===----------------------------------------------------------------------===//
Ted Kremenek51a7d5d2011-10-31 22:23:51 +000026// Internal predicates on CXSourceLocations.
27//===----------------------------------------------------------------------===//
28
29static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
30 // If the lowest bit is clear then the first ptr_data entry is a SourceManager
31 // pointer, or the CXSourceLocation is a null location.
32 return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
33}
34
35//===----------------------------------------------------------------------===//
Ted Kremenek3ddef062011-10-31 22:05:42 +000036// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
37//===----------------------------------------------------------------------===//
38
39extern "C" {
40
41CXSourceLocation clang_getNullLocation() {
42 CXSourceLocation Result = { { 0, 0 }, 0 };
43 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() {
53 CXSourceRange Result = { { 0, 0 }, 0, 0 };
54 return Result;
55}
56
57CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
Ted Kremenek15322172011-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 Kremenek3ddef062011-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 Kremenek3ddef062011-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 Kremenek15322172011-11-10 08:43:12 +000088 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
89 if ((uintptr_t)range.ptr_data[0] & 0x1) {
90 CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
91 return Result;
92 }
93
Ted Kremenek3ddef062011-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 Kremenek15322172011-11-10 08:43:12 +0000100 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
101 if ((uintptr_t)range.ptr_data[0] & 0x1) {
102 CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
103 return Result;
104 }
105
Ted Kremenek3ddef062011-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
111} // end extern "C"
112
113//===----------------------------------------------------------------------===//
114// Getting CXSourceLocations and CXSourceRanges from a translation unit.
115//===----------------------------------------------------------------------===//
116
117extern "C" {
118
119CXSourceLocation clang_getLocation(CXTranslationUnit tu,
120 CXFile file,
121 unsigned line,
122 unsigned column) {
123 if (!tu || !file)
124 return clang_getNullLocation();
125
126 bool Logging = ::getenv("LIBCLANG_LOGGING");
127 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
128 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
129 const FileEntry *File = static_cast<const FileEntry *>(file);
130 SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
131 if (SLoc.isInvalid()) {
132 if (Logging)
133 llvm::errs() << "clang_getLocation(\"" << File->getName()
134 << "\", " << line << ", " << column << ") = invalid\n";
135 return clang_getNullLocation();
136 }
137
138 if (Logging)
139 llvm::errs() << "clang_getLocation(\"" << File->getName()
140 << "\", " << line << ", " << column << ") = "
141 << SLoc.getRawEncoding() << "\n";
142
143 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
144}
145
146CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
147 CXFile file,
148 unsigned offset) {
149 if (!tu || !file)
150 return clang_getNullLocation();
151
152 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
153
154 SourceLocation SLoc
155 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
156
157 if (SLoc.isInvalid())
158 return clang_getNullLocation();
159
160 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
161}
162
163} // end extern "C"
164
165//===----------------------------------------------------------------------===//
166// Routines for expanding and manipulating CXSourceLocations, regardless
167// of their origin.
168//===----------------------------------------------------------------------===//
169
Ted Kremenek3ddef062011-10-31 22:05:42 +0000170static void createNullLocation(CXFile *file, unsigned *line,
171 unsigned *column, unsigned *offset) {
172 if (file)
173 *file = 0;
174 if (line)
175 *line = 0;
176 if (column)
177 *column = 0;
178 if (offset)
179 *offset = 0;
180 return;
181}
182
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000183static void createNullLocation(CXString *filename, unsigned *line,
184 unsigned *column, unsigned *offset = 0) {
185 if (filename)
186 *filename = createCXString("");
187 if (line)
188 *line = 0;
189 if (column)
190 *column = 0;
191 if (offset)
192 *offset = 0;
193 return;
194}
195
Ted Kremenek3ddef062011-10-31 22:05:42 +0000196extern "C" {
197
198void clang_getExpansionLocation(CXSourceLocation location,
199 CXFile *file,
200 unsigned *line,
201 unsigned *column,
202 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000203
Ted Kremenek15322172011-11-10 08:43:12 +0000204 if (!isASTUnitSourceLocation(location)) {
205 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
206 return;
207 }
208
209 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
210
211 if (!location.ptr_data[0] || Loc.isInvalid()) {
212 createNullLocation(file, line, column, offset);
213 return;
214 }
215
216 const SourceManager &SM =
217 *static_cast<const SourceManager*>(location.ptr_data[0]);
218 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000219
Ted Kremenek15322172011-11-10 08:43:12 +0000220 // Check that the FileID is invalid on the expansion location.
221 // This can manifest in invalid code.
222 FileID fileID = SM.getFileID(ExpansionLoc);
223 bool Invalid = false;
224 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
225 if (Invalid || !sloc.isFile()) {
226 createNullLocation(file, line, column, offset);
Argyrios Kyrtzidisb4efaa02011-11-03 02:20:36 +0000227 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000228 }
229
Ted Kremenek15322172011-11-10 08:43:12 +0000230 if (file)
231 *file = (void *)SM.getFileEntryForSLocEntry(sloc);
232 if (line)
233 *line = SM.getExpansionLineNumber(ExpansionLoc);
234 if (column)
235 *column = SM.getExpansionColumnNumber(ExpansionLoc);
236 if (offset)
237 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000238}
239
240void clang_getPresumedLocation(CXSourceLocation location,
241 CXString *filename,
242 unsigned *line,
243 unsigned *column) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000244
Ted Kremenek15322172011-11-10 08:43:12 +0000245 if (!isASTUnitSourceLocation(location)) {
246 // Other SourceLocation implementations do not support presumed locations
247 // at this time.
248 createNullLocation(filename, line, column);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000249 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000250 }
Ted Kremenek15322172011-11-10 08:43:12 +0000251
252 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
253
254 if (!location.ptr_data[0] || Loc.isInvalid())
255 createNullLocation(filename, line, column);
256 else {
257 const SourceManager &SM =
258 *static_cast<const SourceManager*>(location.ptr_data[0]);
259 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
260
261 if (filename)
262 *filename = createCXString(PreLoc.getFilename());
263 if (line)
264 *line = PreLoc.getLine();
265 if (column)
266 *column = PreLoc.getColumn();
267 }
Ted Kremenek3ddef062011-10-31 22:05:42 +0000268}
269
270void clang_getInstantiationLocation(CXSourceLocation location,
271 CXFile *file,
272 unsigned *line,
273 unsigned *column,
274 unsigned *offset) {
275 // Redirect to new API.
276 clang_getExpansionLocation(location, file, line, column, offset);
277}
278
279void clang_getSpellingLocation(CXSourceLocation location,
280 CXFile *file,
281 unsigned *line,
282 unsigned *column,
283 unsigned *offset) {
Ted Kremenek3ddef062011-10-31 22:05:42 +0000284
Ted Kremenek15322172011-11-10 08:43:12 +0000285 if (!isASTUnitSourceLocation(location)) {
286 CXLoadedDiagnostic::decodeLocation(location, file, line,
287 column, offset);
Ted Kremenek51a7d5d2011-10-31 22:23:51 +0000288 return;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000289 }
Ted Kremenek15322172011-11-10 08:43:12 +0000290
291 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
292
293 if (!location.ptr_data[0] || Loc.isInvalid())
294 return createNullLocation(file, line, column, offset);
295
296 const SourceManager &SM =
297 *static_cast<const SourceManager*>(location.ptr_data[0]);
298 SourceLocation SpellLoc = Loc;
299 if (SpellLoc.isMacroID()) {
300 SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
301 if (SimpleSpellingLoc.isFileID() &&
302 SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
303 SpellLoc = SimpleSpellingLoc;
304 else
305 SpellLoc = SM.getExpansionLoc(SpellLoc);
306 }
307
308 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
309 FileID FID = LocInfo.first;
310 unsigned FileOffset = LocInfo.second;
311
312 if (FID.isInvalid())
313 return createNullLocation(file, line, column, offset);
314
315 if (file)
316 *file = (void *)SM.getFileEntryForID(FID);
317 if (line)
318 *line = SM.getLineNumber(FID, FileOffset);
319 if (column)
320 *column = SM.getColumnNumber(FID, FileOffset);
321 if (offset)
322 *offset = FileOffset;
Ted Kremenek3ddef062011-10-31 22:05:42 +0000323}
324
325} // end extern "C"
326