1 //===- 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 #include "CIndexer.h"
16 #include "CLog.h"
17 #include "CXLoadedDiagnostic.h"
18 #include "CXSourceLocation.h"
19 #include "CXString.h"
20 #include "CXTranslationUnit.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/Format.h"
23
24 using namespace clang;
25 using namespace clang::cxindex;
26
27 //===----------------------------------------------------------------------===//
28 // Internal predicates on CXSourceLocations.
29 //===----------------------------------------------------------------------===//
30
isASTUnitSourceLocation(const CXSourceLocation & L)31 static 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 //===----------------------------------------------------------------------===//
38 // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
39 //===----------------------------------------------------------------------===//
40
41 extern "C" {
42
clang_getNullLocation()43 CXSourceLocation clang_getNullLocation() {
44 CXSourceLocation Result = { { 0, 0 }, 0 };
45 return Result;
46 }
47
clang_equalLocations(CXSourceLocation loc1,CXSourceLocation loc2)48 unsigned 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
clang_getNullRange()54 CXSourceRange clang_getNullRange() {
55 CXSourceRange Result = { { 0, 0 }, 0, 0 };
56 return Result;
57 }
58
clang_getRange(CXSourceLocation begin,CXSourceLocation end)59 CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
60 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
67 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
clang_equalRanges(CXSourceRange range1,CXSourceRange range2)77 unsigned 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
clang_Range_isNull(CXSourceRange range)84 int clang_Range_isNull(CXSourceRange range) {
85 return clang_equalRanges(range, clang_getNullRange());
86 }
87
88
clang_getRangeStart(CXSourceRange range)89 CXSourceLocation clang_getRangeStart(CXSourceRange range) {
90 // 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
96 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
97 range.begin_int_data };
98 return Result;
99 }
100
clang_getRangeEnd(CXSourceRange range)101 CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
102 // 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
108 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
119 extern "C" {
120
clang_getLocation(CXTranslationUnit TU,CXFile file,unsigned line,unsigned column)121 CXSourceLocation clang_getLocation(CXTranslationUnit TU,
122 CXFile file,
123 unsigned line,
124 unsigned column) {
125 if (!TU || !file)
126 return clang_getNullLocation();
127
128 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
129 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
130 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()) {
134 if (Log)
135 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
136 File->getName(), line, column);
137 return clang_getNullLocation();
138 }
139
140 CXSourceLocation CXLoc =
141 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
142 if (Log)
143 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
144 << CXLoc;
145
146 return CXLoc;
147 }
148
clang_getLocationForOffset(CXTranslationUnit TU,CXFile file,unsigned offset)149 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
150 CXFile file,
151 unsigned offset) {
152 if (!TU || !file)
153 return clang_getNullLocation();
154
155 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
156
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
createNullLocation(CXFile * file,unsigned * line,unsigned * column,unsigned * offset)173 static 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
createNullLocation(CXString * filename,unsigned * line,unsigned * column,unsigned * offset=0)186 static void createNullLocation(CXString *filename, unsigned *line,
187 unsigned *column, unsigned *offset = 0) {
188 if (filename)
189 *filename = cxstring::createEmpty();
190 if (line)
191 *line = 0;
192 if (column)
193 *column = 0;
194 if (offset)
195 *offset = 0;
196 return;
197 }
198
199 extern "C" {
200
clang_getExpansionLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)201 void clang_getExpansionLocation(CXSourceLocation location,
202 CXFile *file,
203 unsigned *line,
204 unsigned *column,
205 unsigned *offset) {
206
207 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);
222
223 // 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);
230 return;
231 }
232
233 if (file)
234 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
235 if (line)
236 *line = SM.getExpansionLineNumber(ExpansionLoc);
237 if (column)
238 *column = SM.getExpansionColumnNumber(ExpansionLoc);
239 if (offset)
240 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
241 }
242
clang_getPresumedLocation(CXSourceLocation location,CXString * filename,unsigned * line,unsigned * column)243 void clang_getPresumedLocation(CXSourceLocation location,
244 CXString *filename,
245 unsigned *line,
246 unsigned *column) {
247
248 if (!isASTUnitSourceLocation(location)) {
249 // Other SourceLocation implementations do not support presumed locations
250 // at this time.
251 createNullLocation(filename, line, column);
252 return;
253 }
254
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)
265 *filename = cxstring::createRef(PreLoc.getFilename());
266 if (line)
267 *line = PreLoc.getLine();
268 if (column)
269 *column = PreLoc.getColumn();
270 }
271 }
272
clang_getInstantiationLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)273 void 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
clang_getSpellingLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)282 void clang_getSpellingLocation(CXSourceLocation location,
283 CXFile *file,
284 unsigned *line,
285 unsigned *column,
286 unsigned *offset) {
287
288 if (!isASTUnitSourceLocation(location)) {
289 CXLoadedDiagnostic::decodeLocation(location, file, line,
290 column, offset);
291 return;
292 }
293
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]);
301 // FIXME: This should call SourceManager::getSpellingLoc().
302 SourceLocation SpellLoc = SM.getFileLoc(Loc);
303 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)
311 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
312 if (line)
313 *line = SM.getLineNumber(FID, FileOffset);
314 if (column)
315 *column = SM.getColumnNumber(FID, FileOffset);
316 if (offset)
317 *offset = FileOffset;
318 }
319
clang_getFileLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)320 void clang_getFileLocation(CXSourceLocation location,
321 CXFile *file,
322 unsigned *line,
323 unsigned *column,
324 unsigned *offset) {
325
326 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)
348 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
349 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"
358