1 //===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines routines for manipulating CXSourceLocations.
12 //===----------------------------------------------------------------------===//
14 #include "clang/Frontend/ASTUnit.h"
17 #include "CXLoadedDiagnostic.h"
18 #include "CXSourceLocation.h"
20 #include "CXTranslationUnit.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/Format.h"
24 using namespace clang;
25 using namespace clang::cxindex;
27 //===----------------------------------------------------------------------===//
28 // Internal predicates on CXSourceLocations.
29 //===----------------------------------------------------------------------===//
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;
37 //===----------------------------------------------------------------------===//
38 // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
39 //===----------------------------------------------------------------------===//
41 CXSourceLocation clang_getNullLocation() {
42 CXSourceLocation Result = { { nullptr, nullptr }, 0 };
46 unsigned 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);
52 CXSourceRange clang_getNullRange() {
53 CXSourceRange Result = { { nullptr, nullptr }, 0, 0 };
57 CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
58 if (!isASTUnitSourceLocation(begin)) {
59 if (isASTUnitSourceLocation(end))
60 return clang_getNullRange();
61 CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
65 if (begin.ptr_data[0] != end.ptr_data[0] ||
66 begin.ptr_data[1] != end.ptr_data[1])
67 return clang_getNullRange();
69 CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
70 begin.int_data, end.int_data };
75 unsigned 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;
82 int clang_Range_isNull(CXSourceRange range) {
83 return clang_equalRanges(range, clang_getNullRange());
87 CXSourceLocation clang_getRangeStart(CXSourceRange range) {
88 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
89 if ((uintptr_t)range.ptr_data[0] & 0x1) {
90 CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
94 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
95 range.begin_int_data };
99 CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
100 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
101 if ((uintptr_t)range.ptr_data[0] & 0x1) {
102 CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
106 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
107 range.end_int_data };
111 //===----------------------------------------------------------------------===//
112 // Getting CXSourceLocations and CXSourceRanges from a translation unit.
113 //===----------------------------------------------------------------------===//
115 CXSourceLocation clang_getLocation(CXTranslationUnit TU,
119 if (cxtu::isNotUsableTU(TU)) {
121 return clang_getNullLocation();
124 return clang_getNullLocation();
125 if (line == 0 || column == 0)
126 return clang_getNullLocation();
128 LogRef Log = Logger::make(__func__);
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()) {
135 *Log << llvm::format("(\"%s\", %d, %d) = invalid",
136 File->getName().str().c_str(), line, column);
137 return clang_getNullLocation();
140 CXSourceLocation CXLoc =
141 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
143 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
150 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
153 if (cxtu::isNotUsableTU(TU)) {
155 return clang_getNullLocation();
158 return clang_getNullLocation();
160 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
163 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
165 if (SLoc.isInvalid())
166 return clang_getNullLocation();
168 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
171 //===----------------------------------------------------------------------===//
172 // Routines for expanding and manipulating CXSourceLocations, regardless
174 //===----------------------------------------------------------------------===//
176 static void createNullLocation(CXFile *file, unsigned *line,
177 unsigned *column, unsigned *offset) {
188 static void createNullLocation(CXString *filename, unsigned *line,
189 unsigned *column, unsigned *offset = nullptr) {
191 *filename = cxstring::createEmpty();
200 int clang_Location_isInSystemHeader(CXSourceLocation location) {
201 const SourceLocation Loc =
202 SourceLocation::getFromRawEncoding(location.int_data);
206 const SourceManager &SM =
207 *static_cast<const SourceManager*>(location.ptr_data[0]);
208 return SM.isInSystemHeader(Loc);
211 int clang_Location_isFromMainFile(CXSourceLocation location) {
212 const SourceLocation Loc =
213 SourceLocation::getFromRawEncoding(location.int_data);
217 const SourceManager &SM =
218 *static_cast<const SourceManager*>(location.ptr_data[0]);
219 return SM.isWrittenInMainFile(Loc);
222 void clang_getExpansionLocation(CXSourceLocation location,
227 if (!isASTUnitSourceLocation(location)) {
228 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
232 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
234 if (!location.ptr_data[0] || Loc.isInvalid()) {
235 createNullLocation(file, line, column, offset);
239 const SourceManager &SM =
240 *static_cast<const SourceManager*>(location.ptr_data[0]);
241 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
243 // Check that the FileID is invalid on the expansion location.
244 // This can manifest in invalid code.
245 FileID fileID = SM.getFileID(ExpansionLoc);
246 bool Invalid = false;
247 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
248 if (Invalid || !sloc.isFile()) {
249 createNullLocation(file, line, column, offset);
254 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
256 *line = SM.getExpansionLineNumber(ExpansionLoc);
258 *column = SM.getExpansionColumnNumber(ExpansionLoc);
260 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
263 void clang_getPresumedLocation(CXSourceLocation location,
267 if (!isASTUnitSourceLocation(location)) {
268 // Other SourceLocation implementations do not support presumed locations
270 createNullLocation(filename, line, column);
274 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
276 if (!location.ptr_data[0] || Loc.isInvalid()) {
277 createNullLocation(filename, line, column);
281 const SourceManager &SM =
282 *static_cast<const SourceManager *>(location.ptr_data[0]);
283 PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
284 if (PreLoc.isInvalid()) {
285 createNullLocation(filename, line, column);
289 if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
290 if (line) *line = PreLoc.getLine();
291 if (column) *column = PreLoc.getColumn();
294 void clang_getInstantiationLocation(CXSourceLocation location,
299 // Redirect to new API.
300 clang_getExpansionLocation(location, file, line, column, offset);
303 void clang_getSpellingLocation(CXSourceLocation location,
308 if (!isASTUnitSourceLocation(location)) {
309 CXLoadedDiagnostic::decodeLocation(location, file, line,
314 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
316 if (!location.ptr_data[0] || Loc.isInvalid())
317 return createNullLocation(file, line, column, offset);
319 const SourceManager &SM =
320 *static_cast<const SourceManager*>(location.ptr_data[0]);
321 // FIXME: This should call SourceManager::getSpellingLoc().
322 SourceLocation SpellLoc = SM.getFileLoc(Loc);
323 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
324 FileID FID = LocInfo.first;
325 unsigned FileOffset = LocInfo.second;
328 return createNullLocation(file, line, column, offset);
331 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
333 *line = SM.getLineNumber(FID, FileOffset);
335 *column = SM.getColumnNumber(FID, FileOffset);
337 *offset = FileOffset;
340 void clang_getFileLocation(CXSourceLocation location,
345 if (!isASTUnitSourceLocation(location)) {
346 CXLoadedDiagnostic::decodeLocation(location, file, line,
351 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
353 if (!location.ptr_data[0] || Loc.isInvalid())
354 return createNullLocation(file, line, column, offset);
356 const SourceManager &SM =
357 *static_cast<const SourceManager*>(location.ptr_data[0]);
358 SourceLocation FileLoc = SM.getFileLoc(Loc);
359 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
360 FileID FID = LocInfo.first;
361 unsigned FileOffset = LocInfo.second;
364 return createNullLocation(file, line, column, offset);
367 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
369 *line = SM.getLineNumber(FID, FileOffset);
371 *column = SM.getColumnNumber(FID, FileOffset);
373 *offset = FileOffset;