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.
10//
11//===----------------------------------------------------------------------===//
12
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"
24
25using namespace clang;
26using namespace clang::cxindex;
27
28//===----------------------------------------------------------------------===//
29// Internal predicates on CXSourceLocations.
30//===----------------------------------------------------------------------===//
31
32static 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;
36}
37
38//===----------------------------------------------------------------------===//
39// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
40//===----------------------------------------------------------------------===//
41
42CXSourceLocation clang_getNullLocation() {
43 CXSourceLocation Result = { .ptr_data: { nullptr, nullptr }, .int_data: 0 };
44 return Result;
45}
46
47unsigned 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);
51}
52
53unsigned clang_isBeforeInTranslationUnit(CXSourceLocation loc1,
54 CXSourceLocation loc2) {
55 const SourceLocation Loc1 = SourceLocation::getFromRawEncoding(Encoding: loc1.int_data);
56 const SourceLocation Loc2 = SourceLocation::getFromRawEncoding(Encoding: loc2.int_data);
57
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(LHS: Loc1, RHS: Loc2);
63}
64
65CXSourceRange clang_getNullRange() {
66 CXSourceRange Result = { .ptr_data: { nullptr, nullptr }, .begin_int_data: 0, .end_int_data: 0 };
67 return Result;
68}
69
70CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
71 if (!isASTUnitSourceLocation(L: begin)) {
72 if (isASTUnitSourceLocation(L: end))
73 return clang_getNullRange();
74 CXSourceRange Result = { .ptr_data: { begin.ptr_data[0], end.ptr_data[0] }, .begin_int_data: 0, .end_int_data: 0 };
75 return Result;
76 }
77
78 if (begin.ptr_data[0] != end.ptr_data[0] ||
79 begin.ptr_data[1] != end.ptr_data[1])
80 return clang_getNullRange();
81
82 CXSourceRange Result = { .ptr_data: { begin.ptr_data[0], begin.ptr_data[1] },
83 .begin_int_data: begin.int_data, .end_int_data: end.int_data };
84
85 return Result;
86}
87
88unsigned 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;
93}
94
95int clang_Range_isNull(CXSourceRange range) {
96 return clang_equalRanges(range1: range, range2: clang_getNullRange());
97}
98
99
100CXSourceLocation clang_getRangeStart(CXSourceRange range) {
101 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
102 if ((uintptr_t)range.ptr_data[0] & 0x1) {
103 CXSourceLocation Result = { .ptr_data: { range.ptr_data[0], nullptr }, .int_data: 0 };
104 return Result;
105 }
106
107 CXSourceLocation Result = { .ptr_data: { range.ptr_data[0], range.ptr_data[1] },
108 .int_data: range.begin_int_data };
109 return Result;
110}
111
112CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
113 // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
114 if ((uintptr_t)range.ptr_data[0] & 0x1) {
115 CXSourceLocation Result = { .ptr_data: { range.ptr_data[1], nullptr }, .int_data: 0 };
116 return Result;
117 }
118
119 CXSourceLocation Result = { .ptr_data: { range.ptr_data[0], range.ptr_data[1] },
120 .int_data: range.end_int_data };
121 return Result;
122}
123
124//===----------------------------------------------------------------------===//
125// Getting CXSourceLocations and CXSourceRanges from a translation unit.
126//===----------------------------------------------------------------------===//
127
128CXSourceLocation 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();
135 }
136 if (!file)
137 return clang_getNullLocation();
138 if (line == 0 || column == 0)
139 return clang_getNullLocation();
140
141 LogRef Log = Logger::make(name: __func__);
142 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
143 ASTUnit::ConcurrencyCheck Check(*CXXUnit);
144 FileEntryRef File = *cxfile::getFileEntryRef(File: file);
145 SourceLocation SLoc = CXXUnit->getLocation(File, Line: line, Col: column);
146 if (SLoc.isInvalid()) {
147 if (Log)
148 *Log << llvm::format(Fmt: "(\"%s\", %d, %d) = invalid",
149 Vals: File.getName().str().c_str(), Vals: line, Vals: column);
150 return clang_getNullLocation();
151 }
152
153 CXSourceLocation CXLoc =
154 cxloc::translateSourceLocation(Context&: CXXUnit->getASTContext(), Loc: SLoc);
155 if (Log)
156 *Log << llvm::format(Fmt: "(\"%s\", %d, %d) = ", Vals: File.getName().str().c_str(),
157 Vals: line, Vals: column)
158 << CXLoc;
159
160 return CXLoc;
161}
162
163CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
164 CXFile file,
165 unsigned offset) {
166 if (cxtu::isNotUsableTU(TU)) {
167 LOG_BAD_TU(TU);
168 return clang_getNullLocation();
169 }
170 if (!file)
171 return clang_getNullLocation();
172
173 ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
174
175 SourceLocation SLoc
176 = CXXUnit->getLocation(File: *cxfile::getFileEntryRef(File: file), Offset: offset);
177
178 if (SLoc.isInvalid())
179 return clang_getNullLocation();
180
181 return cxloc::translateSourceLocation(Context&: CXXUnit->getASTContext(), Loc: SLoc);
182}
183
184//===----------------------------------------------------------------------===//
185// Routines for expanding and manipulating CXSourceLocations, regardless
186// of their origin.
187//===----------------------------------------------------------------------===//
188
189static 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;
199}
200
201static 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;
211}
212
213int clang_Location_isInSystemHeader(CXSourceLocation location) {
214 const SourceLocation Loc =
215 SourceLocation::getFromRawEncoding(Encoding: location.int_data);
216 if (Loc.isInvalid())
217 return 0;
218
219 const SourceManager &SM =
220 *static_cast<const SourceManager*>(location.ptr_data[0]);
221 return SM.isInSystemHeader(Loc);
222}
223
224int clang_Location_isFromMainFile(CXSourceLocation location) {
225 const SourceLocation Loc =
226 SourceLocation::getFromRawEncoding(Encoding: location.int_data);
227 if (Loc.isInvalid())
228 return 0;
229
230 const SourceManager &SM =
231 *static_cast<const SourceManager*>(location.ptr_data[0]);
232 return SM.isWrittenInMainFile(Loc);
233}
234
235void clang_getExpansionLocation(CXSourceLocation location,
236 CXFile *file,
237 unsigned *line,
238 unsigned *column,
239 unsigned *offset) {
240 if (!isASTUnitSourceLocation(L: location)) {
241 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
242 return;
243 }
244
245 SourceLocation Loc = SourceLocation::getFromRawEncoding(Encoding: location.int_data);
246
247 if (!location.ptr_data[0] || Loc.isInvalid()) {
248 createNullLocation(file, line, column, offset);
249 return;
250 }
251
252 const SourceManager &SM =
253 *static_cast<const SourceManager*>(location.ptr_data[0]);
254 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
255
256 // Check that the FileID is invalid on the expansion location.
257 // This can manifest in invalid code.
258 FileID fileID = SM.getFileID(SpellingLoc: ExpansionLoc);
259 bool Invalid = false;
260 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(FID: fileID, Invalid: &Invalid);
261 if (Invalid || !sloc.isFile()) {
262 createNullLocation(file, line, column, offset);
263 return;
264 }
265
266 if (file)
267 *file = cxfile::makeCXFile(FE: SM.getFileEntryRefForID(FID: fileID));
268 if (line)
269 *line = SM.getExpansionLineNumber(Loc: ExpansionLoc);
270 if (column)
271 *column = SM.getExpansionColumnNumber(Loc: ExpansionLoc);
272 if (offset)
273 *offset = SM.getDecomposedLoc(Loc: ExpansionLoc).second;
274}
275
276void clang_getPresumedLocation(CXSourceLocation location,
277 CXString *filename,
278 unsigned *line,
279 unsigned *column) {
280 if (!isASTUnitSourceLocation(L: location)) {
281 // Other SourceLocation implementations do not support presumed locations
282 // at this time.
283 createNullLocation(filename, line, column);
284 return;
285 }
286
287 SourceLocation Loc = SourceLocation::getFromRawEncoding(Encoding: location.int_data);
288
289 if (!location.ptr_data[0] || Loc.isInvalid()) {
290 createNullLocation(filename, line, column);
291 return;
292 }
293
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;
300 }
301
302 if (filename) *filename = cxstring::createRef(String: PreLoc.getFilename());
303 if (line) *line = PreLoc.getLine();
304 if (column) *column = PreLoc.getColumn();
305}
306
307void 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);
314}
315
316void clang_getSpellingLocation(CXSourceLocation location,
317 CXFile *file,
318 unsigned *line,
319 unsigned *column,
320 unsigned *offset) {
321 if (!isASTUnitSourceLocation(L: location)) {
322 CXLoadedDiagnostic::decodeLocation(location, file, line,
323 column, offset);
324 return;
325 }
326
327 SourceLocation Loc = SourceLocation::getFromRawEncoding(Encoding: location.int_data);
328
329 if (!location.ptr_data[0] || Loc.isInvalid())
330 return createNullLocation(file, line, column, offset);
331
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(Loc: SpellLoc);
336 FileID FID = LocInfo.first;
337 unsigned FileOffset = LocInfo.second;
338
339 if (FID.isInvalid())
340 return createNullLocation(file, line, column, offset);
341
342 if (file)
343 *file = cxfile::makeCXFile(FE: SM.getFileEntryRefForID(FID));
344 if (line)
345 *line = SM.getLineNumber(FID, FilePos: FileOffset);
346 if (column)
347 *column = SM.getColumnNumber(FID, FilePos: FileOffset);
348 if (offset)
349 *offset = FileOffset;
350}
351
352void clang_getFileLocation(CXSourceLocation location,
353 CXFile *file,
354 unsigned *line,
355 unsigned *column,
356 unsigned *offset) {
357 if (!isASTUnitSourceLocation(L: location)) {
358 CXLoadedDiagnostic::decodeLocation(location, file, line,
359 column, offset);
360 return;
361 }
362
363 SourceLocation Loc = SourceLocation::getFromRawEncoding(Encoding: location.int_data);
364
365 if (!location.ptr_data[0] || Loc.isInvalid())
366 return createNullLocation(file, line, column, offset);
367
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(Loc: FileLoc);
372 FileID FID = LocInfo.first;
373 unsigned FileOffset = LocInfo.second;
374
375 if (FID.isInvalid())
376 return createNullLocation(file, line, column, offset);
377
378 if (file)
379 *file = cxfile::makeCXFile(FE: SM.getFileEntryRefForID(FID));
380 if (line)
381 *line = SM.getLineNumber(FID, FilePos: FileOffset);
382 if (column)
383 *column = SM.getColumnNumber(FID, FilePos: FileOffset);
384 if (offset)
385 *offset = FileOffset;
386}
387

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/tools/libclang/CXSourceLocation.cpp