1 //===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines routines for manipulating CXSourceLocations.
11 //===----------------------------------------------------------------------===//
13 #include "CXSourceLocation.h"
17 #include "CXLoadedDiagnostic.h"
19 #include "CXTranslationUnit.h"
20 #include "clang/Basic/FileManager.h"
21 #include "clang/Frontend/ASTUnit.h"
22 #include "llvm/Support/Compiler.h"
23 #include "llvm/Support/Format.h"
25 using namespace clang
;
26 using namespace clang::cxindex
;
28 //===----------------------------------------------------------------------===//
29 // Internal predicates on CXSourceLocations.
30 //===----------------------------------------------------------------------===//
32 static bool isASTUnitSourceLocation(const CXSourceLocation
&L
) {
33 // If the lowest bit is clear then the first ptr_data entry is a SourceManager
34 // pointer, or the CXSourceLocation is a null location.
35 return ((uintptr_t)L
.ptr_data
[0] & 0x1) == 0;
38 //===----------------------------------------------------------------------===//
39 // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
40 //===----------------------------------------------------------------------===//
42 CXSourceLocation
clang_getNullLocation() {
43 CXSourceLocation Result
= { { nullptr, nullptr }, 0 };
47 unsigned clang_equalLocations(CXSourceLocation loc1
, CXSourceLocation loc2
) {
48 return (loc1
.ptr_data
[0] == loc2
.ptr_data
[0] &&
49 loc1
.ptr_data
[1] == loc2
.ptr_data
[1] &&
50 loc1
.int_data
== loc2
.int_data
);
53 unsigned clang_isBeforeInTranslationUnit(CXSourceLocation loc1
,
54 CXSourceLocation loc2
) {
55 const SourceLocation Loc1
= SourceLocation::getFromRawEncoding(loc1
.int_data
);
56 const SourceLocation Loc2
= SourceLocation::getFromRawEncoding(loc2
.int_data
);
58 const SourceManager
&SM
=
59 *static_cast<const SourceManager
*>(loc1
.ptr_data
[0]);
60 // Use the appropriate SourceManager method here rather than operator< because
61 // ordering is meaningful only if LHS and RHS have the same FileID.
62 return SM
.isBeforeInTranslationUnit(Loc1
, Loc2
);
65 CXSourceRange
clang_getNullRange() {
66 CXSourceRange Result
= { { nullptr, nullptr }, 0, 0 };
70 CXSourceRange
clang_getRange(CXSourceLocation begin
, CXSourceLocation end
) {
71 if (!isASTUnitSourceLocation(begin
)) {
72 if (isASTUnitSourceLocation(end
))
73 return clang_getNullRange();
74 CXSourceRange Result
= { { begin
.ptr_data
[0], end
.ptr_data
[0] }, 0, 0 };
78 if (begin
.ptr_data
[0] != end
.ptr_data
[0] ||
79 begin
.ptr_data
[1] != end
.ptr_data
[1])
80 return clang_getNullRange();
82 CXSourceRange Result
= { { begin
.ptr_data
[0], begin
.ptr_data
[1] },
83 begin
.int_data
, end
.int_data
};
88 unsigned clang_equalRanges(CXSourceRange range1
, CXSourceRange range2
) {
89 return range1
.ptr_data
[0] == range2
.ptr_data
[0]
90 && range1
.ptr_data
[1] == range2
.ptr_data
[1]
91 && range1
.begin_int_data
== range2
.begin_int_data
92 && range1
.end_int_data
== range2
.end_int_data
;
95 int clang_Range_isNull(CXSourceRange range
) {
96 return clang_equalRanges(range
, clang_getNullRange());
100 CXSourceLocation
clang_getRangeStart(CXSourceRange range
) {
101 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
102 if ((uintptr_t)range
.ptr_data
[0] & 0x1) {
103 CXSourceLocation Result
= { { range
.ptr_data
[0], nullptr }, 0 };
107 CXSourceLocation Result
= { { range
.ptr_data
[0], range
.ptr_data
[1] },
108 range
.begin_int_data
};
112 CXSourceLocation
clang_getRangeEnd(CXSourceRange range
) {
113 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
114 if ((uintptr_t)range
.ptr_data
[0] & 0x1) {
115 CXSourceLocation Result
= { { range
.ptr_data
[1], nullptr }, 0 };
119 CXSourceLocation Result
= { { range
.ptr_data
[0], range
.ptr_data
[1] },
120 range
.end_int_data
};
124 //===----------------------------------------------------------------------===//
125 // Getting CXSourceLocations and CXSourceRanges from a translation unit.
126 //===----------------------------------------------------------------------===//
128 CXSourceLocation
clang_getLocation(CXTranslationUnit TU
,
132 if (cxtu::isNotUsableTU(TU
)) {
134 return clang_getNullLocation();
137 return clang_getNullLocation();
138 if (line
== 0 || column
== 0)
139 return clang_getNullLocation();
141 LogRef Log
= Logger::make(__func__
);
142 ASTUnit
*CXXUnit
= cxtu::getASTUnit(TU
);
143 ASTUnit::ConcurrencyCheck
Check(*CXXUnit
);
144 FileEntryRef File
= *cxfile::getFileEntryRef(file
);
145 SourceLocation SLoc
= CXXUnit
->getLocation(File
, line
, column
);
146 if (SLoc
.isInvalid()) {
148 *Log
<< llvm::format("(\"%s\", %d, %d) = invalid",
149 File
.getName().str().c_str(), line
, column
);
150 return clang_getNullLocation();
153 CXSourceLocation CXLoc
=
154 cxloc::translateSourceLocation(CXXUnit
->getASTContext(), SLoc
);
156 *Log
<< llvm::format("(\"%s\", %d, %d) = ", File
.getName().str().c_str(),
163 CXSourceLocation
clang_getLocationForOffset(CXTranslationUnit TU
,
166 if (cxtu::isNotUsableTU(TU
)) {
168 return clang_getNullLocation();
171 return clang_getNullLocation();
173 ASTUnit
*CXXUnit
= cxtu::getASTUnit(TU
);
176 = CXXUnit
->getLocation(*cxfile::getFileEntryRef(file
), offset
);
178 if (SLoc
.isInvalid())
179 return clang_getNullLocation();
181 return cxloc::translateSourceLocation(CXXUnit
->getASTContext(), SLoc
);
184 //===----------------------------------------------------------------------===//
185 // Routines for expanding and manipulating CXSourceLocations, regardless
187 //===----------------------------------------------------------------------===//
189 static void createNullLocation(CXFile
*file
, unsigned *line
,
190 unsigned *column
, unsigned *offset
) {
201 static void createNullLocation(CXString
*filename
, unsigned *line
,
202 unsigned *column
, unsigned *offset
= nullptr) {
204 *filename
= cxstring::createEmpty();
213 int clang_Location_isInSystemHeader(CXSourceLocation location
) {
214 const SourceLocation Loc
=
215 SourceLocation::getFromRawEncoding(location
.int_data
);
219 const SourceManager
&SM
=
220 *static_cast<const SourceManager
*>(location
.ptr_data
[0]);
221 return SM
.isInSystemHeader(Loc
);
224 int clang_Location_isFromMainFile(CXSourceLocation location
) {
225 const SourceLocation Loc
=
226 SourceLocation::getFromRawEncoding(location
.int_data
);
230 const SourceManager
&SM
=
231 *static_cast<const SourceManager
*>(location
.ptr_data
[0]);
232 return SM
.isWrittenInMainFile(Loc
);
235 void clang_getExpansionLocation(CXSourceLocation location
,
240 if (!isASTUnitSourceLocation(location
)) {
241 CXLoadedDiagnostic::decodeLocation(location
, file
, line
, column
, offset
);
245 SourceLocation Loc
= SourceLocation::getFromRawEncoding(location
.int_data
);
247 if (!location
.ptr_data
[0] || Loc
.isInvalid()) {
248 createNullLocation(file
, line
, column
, offset
);
252 const SourceManager
&SM
=
253 *static_cast<const SourceManager
*>(location
.ptr_data
[0]);
254 SourceLocation ExpansionLoc
= SM
.getExpansionLoc(Loc
);
256 // Check that the FileID is invalid on the expansion location.
257 // This can manifest in invalid code.
258 FileID fileID
= SM
.getFileID(ExpansionLoc
);
259 bool Invalid
= false;
260 const SrcMgr::SLocEntry
&sloc
= SM
.getSLocEntry(fileID
, &Invalid
);
261 if (Invalid
|| !sloc
.isFile()) {
262 createNullLocation(file
, line
, column
, offset
);
267 *file
= cxfile::makeCXFile(SM
.getFileEntryRefForID(fileID
));
269 *line
= SM
.getExpansionLineNumber(ExpansionLoc
);
271 *column
= SM
.getExpansionColumnNumber(ExpansionLoc
);
273 *offset
= SM
.getDecomposedLoc(ExpansionLoc
).second
;
276 void clang_getPresumedLocation(CXSourceLocation location
,
280 if (!isASTUnitSourceLocation(location
)) {
281 // Other SourceLocation implementations do not support presumed locations
283 createNullLocation(filename
, line
, column
);
287 SourceLocation Loc
= SourceLocation::getFromRawEncoding(location
.int_data
);
289 if (!location
.ptr_data
[0] || Loc
.isInvalid()) {
290 createNullLocation(filename
, line
, column
);
294 const SourceManager
&SM
=
295 *static_cast<const SourceManager
*>(location
.ptr_data
[0]);
296 PresumedLoc PreLoc
= SM
.getPresumedLoc(Loc
);
297 if (PreLoc
.isInvalid()) {
298 createNullLocation(filename
, line
, column
);
302 if (filename
) *filename
= cxstring::createRef(PreLoc
.getFilename());
303 if (line
) *line
= PreLoc
.getLine();
304 if (column
) *column
= PreLoc
.getColumn();
307 void clang_getInstantiationLocation(CXSourceLocation location
,
312 // Redirect to new API.
313 clang_getExpansionLocation(location
, file
, line
, column
, offset
);
316 void clang_getSpellingLocation(CXSourceLocation location
,
321 if (!isASTUnitSourceLocation(location
)) {
322 CXLoadedDiagnostic::decodeLocation(location
, file
, line
,
327 SourceLocation Loc
= SourceLocation::getFromRawEncoding(location
.int_data
);
329 if (!location
.ptr_data
[0] || Loc
.isInvalid())
330 return createNullLocation(file
, line
, column
, offset
);
332 const SourceManager
&SM
=
333 *static_cast<const SourceManager
*>(location
.ptr_data
[0]);
334 SourceLocation SpellLoc
= SM
.getSpellingLoc(Loc
);
335 std::pair
<FileID
, unsigned> LocInfo
= SM
.getDecomposedLoc(SpellLoc
);
336 FileID FID
= LocInfo
.first
;
337 unsigned FileOffset
= LocInfo
.second
;
340 return createNullLocation(file
, line
, column
, offset
);
343 *file
= cxfile::makeCXFile(SM
.getFileEntryRefForID(FID
));
345 *line
= SM
.getLineNumber(FID
, FileOffset
);
347 *column
= SM
.getColumnNumber(FID
, FileOffset
);
349 *offset
= FileOffset
;
352 void clang_getFileLocation(CXSourceLocation location
,
357 if (!isASTUnitSourceLocation(location
)) {
358 CXLoadedDiagnostic::decodeLocation(location
, file
, line
,
363 SourceLocation Loc
= SourceLocation::getFromRawEncoding(location
.int_data
);
365 if (!location
.ptr_data
[0] || Loc
.isInvalid())
366 return createNullLocation(file
, line
, column
, offset
);
368 const SourceManager
&SM
=
369 *static_cast<const SourceManager
*>(location
.ptr_data
[0]);
370 SourceLocation FileLoc
= SM
.getFileLoc(Loc
);
371 std::pair
<FileID
, unsigned> LocInfo
= SM
.getDecomposedLoc(FileLoc
);
372 FileID FID
= LocInfo
.first
;
373 unsigned FileOffset
= LocInfo
.second
;
376 return createNullLocation(file
, line
, column
, offset
);
379 *file
= cxfile::makeCXFile(SM
.getFileEntryRefForID(FID
));
381 *line
= SM
.getLineNumber(FID
, FileOffset
);
383 *column
= SM
.getColumnNumber(FID
, FileOffset
);
385 *offset
= FileOffset
;