[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang / tools / libclang / CXSourceLocation.cpp
blobcd41e9f0d64031b63b855f9933603e76993001d1
1 //===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines routines for manipulating CXSourceLocations.
11 //===----------------------------------------------------------------------===//
13 #include "CXSourceLocation.h"
14 #include "CIndexer.h"
15 #include "CLog.h"
16 #include "CXFile.h"
17 #include "CXLoadedDiagnostic.h"
18 #include "CXString.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 };
44 return Result;
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 };
67 return Result;
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 };
75 return Result;
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 };
85 return Result;
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 };
104 return Result;
107 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
108 range.begin_int_data };
109 return Result;
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 };
116 return Result;
119 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
120 range.end_int_data };
121 return Result;
124 //===----------------------------------------------------------------------===//
125 // Getting CXSourceLocations and CXSourceRanges from a translation unit.
126 //===----------------------------------------------------------------------===//
128 CXSourceLocation clang_getLocation(CXTranslationUnit TU,
129 CXFile file,
130 unsigned line,
131 unsigned column) {
132 if (cxtu::isNotUsableTU(TU)) {
133 LOG_BAD_TU(TU);
134 return clang_getNullLocation();
136 if (!file)
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()) {
147 if (Log)
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);
155 if (Log)
156 *Log << llvm::format("(\"%s\", %d, %d) = ", File.getName().str().c_str(),
157 line, column)
158 << CXLoc;
160 return CXLoc;
163 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
164 CXFile file,
165 unsigned offset) {
166 if (cxtu::isNotUsableTU(TU)) {
167 LOG_BAD_TU(TU);
168 return clang_getNullLocation();
170 if (!file)
171 return clang_getNullLocation();
173 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
175 SourceLocation SLoc
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
186 // of their origin.
187 //===----------------------------------------------------------------------===//
189 static void createNullLocation(CXFile *file, unsigned *line,
190 unsigned *column, unsigned *offset) {
191 if (file)
192 *file = nullptr;
193 if (line)
194 *line = 0;
195 if (column)
196 *column = 0;
197 if (offset)
198 *offset = 0;
201 static void createNullLocation(CXString *filename, unsigned *line,
202 unsigned *column, unsigned *offset = nullptr) {
203 if (filename)
204 *filename = cxstring::createEmpty();
205 if (line)
206 *line = 0;
207 if (column)
208 *column = 0;
209 if (offset)
210 *offset = 0;
213 int clang_Location_isInSystemHeader(CXSourceLocation location) {
214 const SourceLocation Loc =
215 SourceLocation::getFromRawEncoding(location.int_data);
216 if (Loc.isInvalid())
217 return 0;
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);
227 if (Loc.isInvalid())
228 return 0;
230 const SourceManager &SM =
231 *static_cast<const SourceManager*>(location.ptr_data[0]);
232 return SM.isWrittenInMainFile(Loc);
235 void clang_getExpansionLocation(CXSourceLocation location,
236 CXFile *file,
237 unsigned *line,
238 unsigned *column,
239 unsigned *offset) {
240 if (!isASTUnitSourceLocation(location)) {
241 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
242 return;
245 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
247 if (!location.ptr_data[0] || Loc.isInvalid()) {
248 createNullLocation(file, line, column, offset);
249 return;
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);
263 return;
266 if (file)
267 *file = cxfile::makeCXFile(SM.getFileEntryRefForID(fileID));
268 if (line)
269 *line = SM.getExpansionLineNumber(ExpansionLoc);
270 if (column)
271 *column = SM.getExpansionColumnNumber(ExpansionLoc);
272 if (offset)
273 *offset = SM.getDecomposedLoc(ExpansionLoc).second;
276 void clang_getPresumedLocation(CXSourceLocation location,
277 CXString *filename,
278 unsigned *line,
279 unsigned *column) {
280 if (!isASTUnitSourceLocation(location)) {
281 // Other SourceLocation implementations do not support presumed locations
282 // at this time.
283 createNullLocation(filename, line, column);
284 return;
287 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
289 if (!location.ptr_data[0] || Loc.isInvalid()) {
290 createNullLocation(filename, line, column);
291 return;
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);
299 return;
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,
308 CXFile *file,
309 unsigned *line,
310 unsigned *column,
311 unsigned *offset) {
312 // Redirect to new API.
313 clang_getExpansionLocation(location, file, line, column, offset);
316 void clang_getSpellingLocation(CXSourceLocation location,
317 CXFile *file,
318 unsigned *line,
319 unsigned *column,
320 unsigned *offset) {
321 if (!isASTUnitSourceLocation(location)) {
322 CXLoadedDiagnostic::decodeLocation(location, file, line,
323 column, offset);
324 return;
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;
339 if (FID.isInvalid())
340 return createNullLocation(file, line, column, offset);
342 if (file)
343 *file = cxfile::makeCXFile(SM.getFileEntryRefForID(FID));
344 if (line)
345 *line = SM.getLineNumber(FID, FileOffset);
346 if (column)
347 *column = SM.getColumnNumber(FID, FileOffset);
348 if (offset)
349 *offset = FileOffset;
352 void clang_getFileLocation(CXSourceLocation location,
353 CXFile *file,
354 unsigned *line,
355 unsigned *column,
356 unsigned *offset) {
357 if (!isASTUnitSourceLocation(location)) {
358 CXLoadedDiagnostic::decodeLocation(location, file, line,
359 column, offset);
360 return;
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;
375 if (FID.isInvalid())
376 return createNullLocation(file, line, column, offset);
378 if (file)
379 *file = cxfile::makeCXFile(SM.getFileEntryRefForID(FID));
380 if (line)
381 *line = SM.getLineNumber(FID, FileOffset);
382 if (column)
383 *column = SM.getColumnNumber(FID, FileOffset);
384 if (offset)
385 *offset = FileOffset;