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