Clang Project

clang_source_code/tools/libclang/CXSourceLocation.cpp
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 "clang/Frontend/ASTUnit.h"
14#include "CIndexer.h"
15#include "CLog.h"
16#include "CXLoadedDiagnostic.h"
17#include "CXSourceLocation.h"
18#include "CXString.h"
19#include "CXTranslationUnit.h"
20#include "llvm/Support/Compiler.h"
21#include "llvm/Support/Format.h"
22
23using namespace clang;
24using namespace clang::cxindex;
25
26//===----------------------------------------------------------------------===//
27// Internal predicates on CXSourceLocations.
28//===----------------------------------------------------------------------===//
29
30static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
31  // If the lowest bit is clear then the first ptr_data entry is a SourceManager
32  // pointer, or the CXSourceLocation is a null location.
33  return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
34}
35
36//===----------------------------------------------------------------------===//
37// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
38//===----------------------------------------------------------------------===//
39
40CXSourceLocation clang_getNullLocation() {
41  CXSourceLocation Result = { { nullptrnullptr }, 0 };
42  return Result;
43}
44
45unsigned clang_equalLocations(CXSourceLocation loc1CXSourceLocation loc2) {
46  return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
47          loc1.ptr_data[1] == loc2.ptr_data[1] &&
48          loc1.int_data == loc2.int_data);
49}
50
51CXSourceRange clang_getNullRange() {
52  CXSourceRange Result = { { nullptrnullptr }, 00 };
53  return Result;
54}
55
56CXSourceRange clang_getRange(CXSourceLocation beginCXSourceLocation end) {
57  if (!isASTUnitSourceLocation(begin)) {
58    if (isASTUnitSourceLocation(end))
59      return clang_getNullRange();
60    CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 00 };
61    return Result;
62  }
63  
64  if (begin.ptr_data[0] != end.ptr_data[0] ||
65      begin.ptr_data[1] != end.ptr_data[1])
66    return clang_getNullRange();
67  
68  CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
69                           begin.int_dataend.int_data };
70
71  return Result;
72}
73
74unsigned clang_equalRanges(CXSourceRange range1CXSourceRange range2) {
75  return range1.ptr_data[0] == range2.ptr_data[0]
76    && range1.ptr_data[1] == range2.ptr_data[1]
77    && range1.begin_int_data == range2.begin_int_data
78    && range1.end_int_data == range2.end_int_data;
79}
80
81int clang_Range_isNull(CXSourceRange range) {
82  return clang_equalRanges(rangeclang_getNullRange());
83}
84  
85  
86CXSourceLocation clang_getRangeStart(CXSourceRange range) {
87  // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
88  if ((uintptr_t)range.ptr_data[0] & 0x1) {
89    CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
90    return Result;    
91  }
92  
93  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
94    range.begin_int_data };
95  return Result;
96}
97
98CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
99  // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
100  if ((uintptr_t)range.ptr_data[0] & 0x1) {
101    CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
102    return Result;    
103  }
104
105  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
106    range.end_int_data };
107  return Result;
108}
109
110//===----------------------------------------------------------------------===//
111//  Getting CXSourceLocations and CXSourceRanges from a translation unit.
112//===----------------------------------------------------------------------===//
113
114CXSourceLocation clang_getLocation(CXTranslationUnit TU,
115                                   CXFile file,
116                                   unsigned line,
117                                   unsigned column) {
118  if (cxtu::isNotUsableTU(TU)) {
119    LOG_BAD_TU(TU);
120    return clang_getNullLocation();
121  }
122  if (!file)
123    return clang_getNullLocation();
124  if (line == 0 || column == 0)
125    return clang_getNullLocation();
126  
127  LogRef Log = Logger::make(__func__);
128  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
129  ASTUnit::ConcurrencyCheck Check(*CXXUnit);
130  const FileEntry *File = static_cast<const FileEntry *>(file);
131  SourceLocation SLoc = CXXUnit->getLocation(Filelinecolumn);
132  if (SLoc.isInvalid()) {
133    if (Log)
134      *Log << llvm::format("(\"%s\", %d, %d) = invalid",
135                           File->getName().str().c_str(), line, column);
136    return clang_getNullLocation();
137  }
138  
139  CXSourceLocation CXLoc =
140      cxloc::translateSourceLocation(CXXUnit->getASTContext()SLoc);
141  if (Log)
142    *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
143                         line, column)
144         << CXLoc;
145
146  return CXLoc;
147}
148  
149CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
150                                            CXFile file,
151                                            unsigned offset) {
152  if (cxtu::isNotUsableTU(TU)) {
153    LOG_BAD_TU(TU);
154    return clang_getNullLocation();
155  }
156  if (!file)
157    return clang_getNullLocation();
158
159  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
160
161  SourceLocation SLoc 
162    = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
163
164  if (SLoc.isInvalid())
165    return clang_getNullLocation();
166  
167  return cxloc::translateSourceLocation(CXXUnit->getASTContext()SLoc);
168}
169
170//===----------------------------------------------------------------------===//
171// Routines for expanding and manipulating CXSourceLocations, regardless
172// of their origin.
173//===----------------------------------------------------------------------===//
174
175static void createNullLocation(CXFile *fileunsigned *line,
176                               unsigned *columnunsigned *offset) {
177  if (file)
178    *file = nullptr;
179  if (line)
180    *line = 0;
181  if (column)
182    *column = 0;
183  if (offset)
184    *offset = 0;
185}
186
187static void createNullLocation(CXString *filenameunsigned *line,
188                               unsigned *columnunsigned *offset = nullptr) {
189  if (filename)
190    *filename = cxstring::createEmpty();
191  if (line)
192    *line = 0;
193  if (column)
194    *column = 0;
195  if (offset)
196    *offset = 0;
197}
198
199int clang_Location_isInSystemHeader(CXSourceLocation location) {
200  const SourceLocation Loc =
201    SourceLocation::getFromRawEncoding(location.int_data);
202  if (Loc.isInvalid())
203    return 0;
204
205  const SourceManager &SM =
206    *static_cast<const SourceManager*>(location.ptr_data[0]);
207  return SM.isInSystemHeader(Loc);
208}
209
210int clang_Location_isFromMainFile(CXSourceLocation location) {
211  const SourceLocation Loc =
212    SourceLocation::getFromRawEncoding(location.int_data);
213  if (Loc.isInvalid())
214    return 0;
215
216  const SourceManager &SM =
217    *static_cast<const SourceManager*>(location.ptr_data[0]);
218  return SM.isWrittenInMainFile(Loc);
219}
220
221void clang_getExpansionLocation(CXSourceLocation location,
222                                CXFile *file,
223                                unsigned *line,
224                                unsigned *column,
225                                unsigned *offset) {
226  if (!isASTUnitSourceLocation(location)) {
227    CXLoadedDiagnostic::decodeLocation(locationfilelinecolumnoffset);
228    return;
229  }
230
231  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
232
233  if (!location.ptr_data[0] || Loc.isInvalid()) {
234    createNullLocation(filelinecolumnoffset);
235    return;
236  }
237
238  const SourceManager &SM =
239  *static_cast<const SourceManager*>(location.ptr_data[0]);
240  SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
241  
242  // Check that the FileID is invalid on the expansion location.
243  // This can manifest in invalid code.
244  FileID fileID = SM.getFileID(ExpansionLoc);
245  bool Invalid = false;
246  const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
247  if (Invalid || !sloc.isFile()) {
248    createNullLocation(filelinecolumnoffset);
249    return;
250  }
251  
252  if (file)
253    *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
254  if (line)
255    *line = SM.getExpansionLineNumber(ExpansionLoc);
256  if (column)
257    *column = SM.getExpansionColumnNumber(ExpansionLoc);
258  if (offset)
259    *offset = SM.getDecomposedLoc(ExpansionLoc).second;
260}
261
262void clang_getPresumedLocation(CXSourceLocation location,
263                               CXString *filename,
264                               unsigned *line,
265                               unsigned *column) {
266  if (!isASTUnitSourceLocation(location)) {
267    // Other SourceLocation implementations do not support presumed locations
268    // at this time.
269    createNullLocation(filenamelinecolumn);
270    return;
271  }
272
273  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
274
275  if (!location.ptr_data[0] || Loc.isInvalid()) {
276    createNullLocation(filenamelinecolumn);
277    return;
278  }
279
280  const SourceManager &SM =
281      *static_cast<const SourceManager *>(location.ptr_data[0]);
282  PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
283  if (PreLoc.isInvalid()) {
284    createNullLocation(filenamelinecolumn);
285    return;
286  }
287
288  if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
289  if (line) *line = PreLoc.getLine();
290  if (column) *column = PreLoc.getColumn();
291}
292
293void clang_getInstantiationLocation(CXSourceLocation location,
294                                    CXFile *file,
295                                    unsigned *line,
296                                    unsigned *column,
297                                    unsigned *offset) {
298  // Redirect to new API.
299  clang_getExpansionLocation(locationfilelinecolumnoffset);
300}
301
302void clang_getSpellingLocation(CXSourceLocation location,
303                               CXFile *file,
304                               unsigned *line,
305                               unsigned *column,
306                               unsigned *offset) {
307  if (!isASTUnitSourceLocation(location)) {
308    CXLoadedDiagnostic::decodeLocation(locationfileline,
309                                           columnoffset);
310    return;
311  }
312  
313  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
314  
315  if (!location.ptr_data[0] || Loc.isInvalid())
316    return createNullLocation(filelinecolumnoffset);
317  
318  const SourceManager &SM =
319  *static_cast<const SourceManager*>(location.ptr_data[0]);
320  // FIXME: This should call SourceManager::getSpellingLoc().
321  SourceLocation SpellLoc = SM.getFileLoc(Loc);
322  std::pair<FileIDunsignedLocInfo = SM.getDecomposedLoc(SpellLoc);
323  FileID FID = LocInfo.first;
324  unsigned FileOffset = LocInfo.second;
325  
326  if (FID.isInvalid())
327    return createNullLocation(filelinecolumnoffset);
328  
329  if (file)
330    *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
331  if (line)
332    *line = SM.getLineNumber(FIDFileOffset);
333  if (column)
334    *column = SM.getColumnNumber(FIDFileOffset);
335  if (offset)
336    *offset = FileOffset;
337}
338
339void clang_getFileLocation(CXSourceLocation location,
340                           CXFile *file,
341                           unsigned *line,
342                           unsigned *column,
343                           unsigned *offset) {
344  if (!isASTUnitSourceLocation(location)) {
345    CXLoadedDiagnostic::decodeLocation(locationfileline,
346                                           columnoffset);
347    return;
348  }
349
350  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
351
352  if (!location.ptr_data[0] || Loc.isInvalid())
353    return createNullLocation(filelinecolumnoffset);
354
355  const SourceManager &SM =
356  *static_cast<const SourceManager*>(location.ptr_data[0]);
357  SourceLocation FileLoc = SM.getFileLoc(Loc);
358  std::pair<FileIDunsignedLocInfo = SM.getDecomposedLoc(FileLoc);
359  FileID FID = LocInfo.first;
360  unsigned FileOffset = LocInfo.second;
361
362  if (FID.isInvalid())
363    return createNullLocation(filelinecolumnoffset);
364
365  if (file)
366    *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
367  if (line)
368    *line = SM.getLineNumber(FIDFileOffset);
369  if (column)
370    *column = SM.getColumnNumber(FIDFileOffset);
371  if (offset)
372    *offset = FileOffset;
373}
374