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 = { { nullptr, nullptr }, 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 = { { nullptr, nullptr }, 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], nullptr }, 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], nullptr }, 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 (cxtu::isNotUsableTU(TU)) {
126 LOG_BAD_TU(TU);
127 return clang_getNullLocation();
128 }
129 if (!file)
130 return clang_getNullLocation();
131 if (line == 0 || column == 0)
132 return clang_getNullLocation();
133
134 LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
135 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
136 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
137 const FileEntry *File = static_cast<const FileEntry *>(file);
138 SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
139 if (SLoc.isInvalid()) {
140 if (Log)
141 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
142 File->getName(), line, column);
143 return clang_getNullLocation();
144 }
145
146 CXSourceLocation CXLoc =
147 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
148 if (Log)
149 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
150 << CXLoc;
151
152 return CXLoc;
153 }
154
clang_getLocationForOffset(CXTranslationUnit TU,CXFile file,unsigned offset)155 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
156 CXFile file,
157 unsigned offset) {
158 if (cxtu::isNotUsableTU(TU)) {
159 LOG_BAD_TU(TU);
160 return clang_getNullLocation();
161 }
162 if (!file)
163 return clang_getNullLocation();
164
165 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
166
167 SourceLocation SLoc
168 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
169
170 if (SLoc.isInvalid())
171 return clang_getNullLocation();
172
173 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
174 }
175
176 } // end extern "C"
177
178 //===----------------------------------------------------------------------===//
179 // Routines for expanding and manipulating CXSourceLocations, regardless
180 // of their origin.
181 //===----------------------------------------------------------------------===//
182
createNullLocation(CXFile * file,unsigned * line,unsigned * column,unsigned * offset)183 static void createNullLocation(CXFile *file, unsigned *line,
184 unsigned *column, unsigned *offset) {
185 if (file)
186 *file = nullptr;
187 if (line)
188 *line = 0;
189 if (column)
190 *column = 0;
191 if (offset)
192 *offset = 0;
193 }
194
createNullLocation(CXString * filename,unsigned * line,unsigned * column,unsigned * offset=nullptr)195 static void createNullLocation(CXString *filename, unsigned *line,
196 unsigned *column, unsigned *offset = nullptr) {
197 if (filename)
198 *filename = cxstring::createEmpty();
199 if (line)
200 *line = 0;
201 if (column)
202 *column = 0;
203 if (offset)
204 *offset = 0;
205 }
206
207 extern "C" {
208
clang_Location_isInSystemHeader(CXSourceLocation location)209 int clang_Location_isInSystemHeader(CXSourceLocation location) {
210 const SourceLocation Loc =
211 SourceLocation::getFromRawEncoding(location.int_data);
212 if (Loc.isInvalid())
213 return 0;
214
215 const SourceManager &SM =
216 *static_cast<const SourceManager*>(location.ptr_data[0]);
217 return SM.isInSystemHeader(Loc);
218 }
219
clang_Location_isFromMainFile(CXSourceLocation location)220 int clang_Location_isFromMainFile(CXSourceLocation location) {
221 const SourceLocation Loc =
222 SourceLocation::getFromRawEncoding(location.int_data);
223 if (Loc.isInvalid())
224 return 0;
225
226 const SourceManager &SM =
227 *static_cast<const SourceManager*>(location.ptr_data[0]);
228 return SM.isWrittenInMainFile(Loc);
229 }
230
clang_getExpansionLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)231 void clang_getExpansionLocation(CXSourceLocation location,
232 CXFile *file,
233 unsigned *line,
234 unsigned *column,
235 unsigned *offset) {
236 if (!isASTUnitSourceLocation(location)) {
237 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
238 return;
239 }
240
241 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
242
243 if (!location.ptr_data[0] || Loc.isInvalid()) {
244 createNullLocation(file, line, column, offset);
245 return;
246 }
247
248 const SourceManager &SM =
249 *static_cast<const SourceManager*>(location.ptr_data[0]);
250 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
251
252 // Check that the FileID is invalid on the expansion location.
253 // This can manifest in invalid code.
254 FileID fileID = SM.getFileID(ExpansionLoc);
255 bool Invalid = false;
256 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
257 if (Invalid || !sloc.isFile()) {
258 createNullLocation(file, line, column, offset);
259 return;
260 }
261
262 if (file)
263 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
264 if (line)
265 *line = SM.getExpansionLineNumber(ExpansionLoc);
266 if (column)
267 *column = SM.getExpansionColumnNumber(ExpansionLoc);
268 if (offset)
269 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
270 }
271
clang_getPresumedLocation(CXSourceLocation location,CXString * filename,unsigned * line,unsigned * column)272 void clang_getPresumedLocation(CXSourceLocation location,
273 CXString *filename,
274 unsigned *line,
275 unsigned *column) {
276 if (!isASTUnitSourceLocation(location)) {
277 // Other SourceLocation implementations do not support presumed locations
278 // at this time.
279 createNullLocation(filename, line, column);
280 return;
281 }
282
283 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
284
285 if (!location.ptr_data[0] || Loc.isInvalid()) {
286 createNullLocation(filename, line, column);
287 return;
288 }
289
290 const SourceManager &SM =
291 *static_cast<const SourceManager *>(location.ptr_data[0]);
292 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
293 if (PreLoc.isInvalid()) {
294 createNullLocation(filename, line, column);
295 return;
296 }
297
298 if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
299 if (line) *line = PreLoc.getLine();
300 if (column) *column = PreLoc.getColumn();
301 }
302
clang_getInstantiationLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)303 void clang_getInstantiationLocation(CXSourceLocation location,
304 CXFile *file,
305 unsigned *line,
306 unsigned *column,
307 unsigned *offset) {
308 // Redirect to new API.
309 clang_getExpansionLocation(location, file, line, column, offset);
310 }
311
clang_getSpellingLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)312 void clang_getSpellingLocation(CXSourceLocation location,
313 CXFile *file,
314 unsigned *line,
315 unsigned *column,
316 unsigned *offset) {
317 if (!isASTUnitSourceLocation(location)) {
318 CXLoadedDiagnostic::decodeLocation(location, file, line,
319 column, offset);
320 return;
321 }
322
323 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
324
325 if (!location.ptr_data[0] || Loc.isInvalid())
326 return createNullLocation(file, line, column, offset);
327
328 const SourceManager &SM =
329 *static_cast<const SourceManager*>(location.ptr_data[0]);
330 // FIXME: This should call SourceManager::getSpellingLoc().
331 SourceLocation SpellLoc = SM.getFileLoc(Loc);
332 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
333 FileID FID = LocInfo.first;
334 unsigned FileOffset = LocInfo.second;
335
336 if (FID.isInvalid())
337 return createNullLocation(file, line, column, offset);
338
339 if (file)
340 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
341 if (line)
342 *line = SM.getLineNumber(FID, FileOffset);
343 if (column)
344 *column = SM.getColumnNumber(FID, FileOffset);
345 if (offset)
346 *offset = FileOffset;
347 }
348
clang_getFileLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)349 void clang_getFileLocation(CXSourceLocation location,
350 CXFile *file,
351 unsigned *line,
352 unsigned *column,
353 unsigned *offset) {
354 if (!isASTUnitSourceLocation(location)) {
355 CXLoadedDiagnostic::decodeLocation(location, file, line,
356 column, offset);
357 return;
358 }
359
360 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
361
362 if (!location.ptr_data[0] || Loc.isInvalid())
363 return createNullLocation(file, line, column, offset);
364
365 const SourceManager &SM =
366 *static_cast<const SourceManager*>(location.ptr_data[0]);
367 SourceLocation FileLoc = SM.getFileLoc(Loc);
368 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
369 FileID FID = LocInfo.first;
370 unsigned FileOffset = LocInfo.second;
371
372 if (FID.isInvalid())
373 return createNullLocation(file, line, column, offset);
374
375 if (file)
376 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
377 if (line)
378 *line = SM.getLineNumber(FID, FileOffset);
379 if (column)
380 *column = SM.getColumnNumber(FID, FileOffset);
381 if (offset)
382 *offset = FileOffset;
383 }
384
385 } // end extern "C"
386