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_Location_isInSystemHeader(CXSourceLocation location)201 int clang_Location_isInSystemHeader(CXSourceLocation location) {
202 const SourceLocation Loc =
203 SourceLocation::getFromRawEncoding(location.int_data);
204 if (Loc.isInvalid())
205 return 0;
206
207 const SourceManager &SM =
208 *static_cast<const SourceManager*>(location.ptr_data[0]);
209 return SM.isInSystemHeader(Loc);
210 }
211
clang_getExpansionLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)212 void clang_getExpansionLocation(CXSourceLocation location,
213 CXFile *file,
214 unsigned *line,
215 unsigned *column,
216 unsigned *offset) {
217
218 if (!isASTUnitSourceLocation(location)) {
219 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
220 return;
221 }
222
223 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
224
225 if (!location.ptr_data[0] || Loc.isInvalid()) {
226 createNullLocation(file, line, column, offset);
227 return;
228 }
229
230 const SourceManager &SM =
231 *static_cast<const SourceManager*>(location.ptr_data[0]);
232 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
233
234 // Check that the FileID is invalid on the expansion location.
235 // This can manifest in invalid code.
236 FileID fileID = SM.getFileID(ExpansionLoc);
237 bool Invalid = false;
238 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
239 if (Invalid || !sloc.isFile()) {
240 createNullLocation(file, line, column, offset);
241 return;
242 }
243
244 if (file)
245 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
246 if (line)
247 *line = SM.getExpansionLineNumber(ExpansionLoc);
248 if (column)
249 *column = SM.getExpansionColumnNumber(ExpansionLoc);
250 if (offset)
251 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
252 }
253
clang_getPresumedLocation(CXSourceLocation location,CXString * filename,unsigned * line,unsigned * column)254 void clang_getPresumedLocation(CXSourceLocation location,
255 CXString *filename,
256 unsigned *line,
257 unsigned *column) {
258
259 if (!isASTUnitSourceLocation(location)) {
260 // Other SourceLocation implementations do not support presumed locations
261 // at this time.
262 createNullLocation(filename, line, column);
263 return;
264 }
265
266 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
267
268 if (!location.ptr_data[0] || Loc.isInvalid())
269 createNullLocation(filename, line, column);
270 else {
271 const SourceManager &SM =
272 *static_cast<const SourceManager*>(location.ptr_data[0]);
273 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
274
275 if (filename)
276 *filename = cxstring::createRef(PreLoc.getFilename());
277 if (line)
278 *line = PreLoc.getLine();
279 if (column)
280 *column = PreLoc.getColumn();
281 }
282 }
283
clang_getInstantiationLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)284 void clang_getInstantiationLocation(CXSourceLocation location,
285 CXFile *file,
286 unsigned *line,
287 unsigned *column,
288 unsigned *offset) {
289 // Redirect to new API.
290 clang_getExpansionLocation(location, file, line, column, offset);
291 }
292
clang_getSpellingLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)293 void clang_getSpellingLocation(CXSourceLocation location,
294 CXFile *file,
295 unsigned *line,
296 unsigned *column,
297 unsigned *offset) {
298
299 if (!isASTUnitSourceLocation(location)) {
300 CXLoadedDiagnostic::decodeLocation(location, file, line,
301 column, offset);
302 return;
303 }
304
305 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
306
307 if (!location.ptr_data[0] || Loc.isInvalid())
308 return createNullLocation(file, line, column, offset);
309
310 const SourceManager &SM =
311 *static_cast<const SourceManager*>(location.ptr_data[0]);
312 // FIXME: This should call SourceManager::getSpellingLoc().
313 SourceLocation SpellLoc = SM.getFileLoc(Loc);
314 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
315 FileID FID = LocInfo.first;
316 unsigned FileOffset = LocInfo.second;
317
318 if (FID.isInvalid())
319 return createNullLocation(file, line, column, offset);
320
321 if (file)
322 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
323 if (line)
324 *line = SM.getLineNumber(FID, FileOffset);
325 if (column)
326 *column = SM.getColumnNumber(FID, FileOffset);
327 if (offset)
328 *offset = FileOffset;
329 }
330
clang_getFileLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)331 void clang_getFileLocation(CXSourceLocation location,
332 CXFile *file,
333 unsigned *line,
334 unsigned *column,
335 unsigned *offset) {
336
337 if (!isASTUnitSourceLocation(location)) {
338 CXLoadedDiagnostic::decodeLocation(location, file, line,
339 column, offset);
340 return;
341 }
342
343 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
344
345 if (!location.ptr_data[0] || Loc.isInvalid())
346 return createNullLocation(file, line, column, offset);
347
348 const SourceManager &SM =
349 *static_cast<const SourceManager*>(location.ptr_data[0]);
350 SourceLocation FileLoc = SM.getFileLoc(Loc);
351 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
352 FileID FID = LocInfo.first;
353 unsigned FileOffset = LocInfo.second;
354
355 if (FID.isInvalid())
356 return createNullLocation(file, line, column, offset);
357
358 if (file)
359 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
360 if (line)
361 *line = SM.getLineNumber(FID, FileOffset);
362 if (column)
363 *column = SM.getColumnNumber(FID, FileOffset);
364 if (offset)
365 *offset = FileOffset;
366 }
367
368 } // end extern "C"
369