CXSourceLocation.cpp revision 153221717e39ce41323d5bc6b8b8bf130923c1bd
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
16#include "CIndexer.h"
17#include "CXString.h"
18#include "CXSourceLocation.h"
19#include "CXTranslationUnit.h"
20#include "CXLoadedDiagnostic.h"
21
22using namespace clang;
23using namespace clang::cxstring;
24
25//===----------------------------------------------------------------------===//
26// Internal predicates on CXSourceLocations.
27//===----------------------------------------------------------------------===//
28
29static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
30  // If the lowest bit is clear then the first ptr_data entry is a SourceManager
31  // pointer, or the CXSourceLocation is a null location.
32  return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
33}
34
35//===----------------------------------------------------------------------===//
36// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
37//===----------------------------------------------------------------------===//
38
39extern "C" {
40
41CXSourceLocation clang_getNullLocation() {
42  CXSourceLocation Result = { { 0, 0 }, 0 };
43  return Result;
44}
45
46unsigned 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);
50}
51
52CXSourceRange clang_getNullRange() {
53  CXSourceRange Result = { { 0, 0 }, 0, 0 };
54  return Result;
55}
56
57CXSourceRange 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 };
62    return Result;
63  }
64
65  if (begin.ptr_data[0] != end.ptr_data[0] ||
66      begin.ptr_data[1] != end.ptr_data[1])
67    return clang_getNullRange();
68
69  CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
70                           begin.int_data, end.int_data };
71
72  return Result;
73}
74
75unsigned 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;
80}
81
82int clang_Range_isNull(CXSourceRange range) {
83  return clang_equalRanges(range, clang_getNullRange());
84}
85
86
87CXSourceLocation 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], 0 }, 0 };
91    return Result;
92  }
93
94  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
95    range.begin_int_data };
96  return Result;
97}
98
99CXSourceLocation 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], 0 }, 0 };
103    return Result;
104  }
105
106  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
107    range.end_int_data };
108  return Result;
109}
110
111} // end extern "C"
112
113//===----------------------------------------------------------------------===//
114//  Getting CXSourceLocations and CXSourceRanges from a translation unit.
115//===----------------------------------------------------------------------===//
116
117extern "C" {
118
119CXSourceLocation clang_getLocation(CXTranslationUnit tu,
120                                   CXFile file,
121                                   unsigned line,
122                                   unsigned column) {
123  if (!tu || !file)
124    return clang_getNullLocation();
125
126  bool Logging = ::getenv("LIBCLANG_LOGGING");
127  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
128  ASTUnit::ConcurrencyCheck Check(*CXXUnit);
129  const FileEntry *File = static_cast<const FileEntry *>(file);
130  SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
131  if (SLoc.isInvalid()) {
132    if (Logging)
133      llvm::errs() << "clang_getLocation(\"" << File->getName()
134      << "\", " << line << ", " << column << ") = invalid\n";
135    return clang_getNullLocation();
136  }
137
138  if (Logging)
139    llvm::errs() << "clang_getLocation(\"" << File->getName()
140    << "\", " << line << ", " << column << ") = "
141    << SLoc.getRawEncoding() << "\n";
142
143  return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
144}
145
146CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
147                                            CXFile file,
148                                            unsigned offset) {
149  if (!tu || !file)
150    return clang_getNullLocation();
151
152  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
153
154  SourceLocation SLoc
155    = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
156
157  if (SLoc.isInvalid())
158    return clang_getNullLocation();
159
160  return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
161}
162
163} // end extern "C"
164
165//===----------------------------------------------------------------------===//
166// Routines for expanding and manipulating CXSourceLocations, regardless
167// of their origin.
168//===----------------------------------------------------------------------===//
169
170static void createNullLocation(CXFile *file, unsigned *line,
171                               unsigned *column, unsigned *offset) {
172  if (file)
173    *file = 0;
174  if (line)
175    *line = 0;
176  if (column)
177    *column = 0;
178  if (offset)
179    *offset = 0;
180  return;
181}
182
183static void createNullLocation(CXString *filename, unsigned *line,
184                               unsigned *column, unsigned *offset = 0) {
185  if (filename)
186    *filename = createCXString("");
187  if (line)
188    *line = 0;
189  if (column)
190    *column = 0;
191  if (offset)
192    *offset = 0;
193  return;
194}
195
196extern "C" {
197
198void clang_getExpansionLocation(CXSourceLocation location,
199                                CXFile *file,
200                                unsigned *line,
201                                unsigned *column,
202                                unsigned *offset) {
203
204  if (!isASTUnitSourceLocation(location)) {
205    CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
206    return;
207  }
208
209  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
210
211  if (!location.ptr_data[0] || Loc.isInvalid()) {
212    createNullLocation(file, line, column, offset);
213    return;
214  }
215
216  const SourceManager &SM =
217  *static_cast<const SourceManager*>(location.ptr_data[0]);
218  SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
219
220  // Check that the FileID is invalid on the expansion location.
221  // This can manifest in invalid code.
222  FileID fileID = SM.getFileID(ExpansionLoc);
223  bool Invalid = false;
224  const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
225  if (Invalid || !sloc.isFile()) {
226    createNullLocation(file, line, column, offset);
227    return;
228  }
229
230  if (file)
231    *file = (void *)SM.getFileEntryForSLocEntry(sloc);
232  if (line)
233    *line = SM.getExpansionLineNumber(ExpansionLoc);
234  if (column)
235    *column = SM.getExpansionColumnNumber(ExpansionLoc);
236  if (offset)
237    *offset = SM.getDecomposedLoc(ExpansionLoc).second;
238}
239
240void clang_getPresumedLocation(CXSourceLocation location,
241                               CXString *filename,
242                               unsigned *line,
243                               unsigned *column) {
244
245  if (!isASTUnitSourceLocation(location)) {
246    // Other SourceLocation implementations do not support presumed locations
247    // at this time.
248    createNullLocation(filename, line, column);
249    return;
250  }
251
252  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
253
254  if (!location.ptr_data[0] || Loc.isInvalid())
255    createNullLocation(filename, line, column);
256  else {
257    const SourceManager &SM =
258    *static_cast<const SourceManager*>(location.ptr_data[0]);
259    PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
260
261    if (filename)
262      *filename = createCXString(PreLoc.getFilename());
263    if (line)
264      *line = PreLoc.getLine();
265    if (column)
266      *column = PreLoc.getColumn();
267  }
268}
269
270void clang_getInstantiationLocation(CXSourceLocation location,
271                                    CXFile *file,
272                                    unsigned *line,
273                                    unsigned *column,
274                                    unsigned *offset) {
275  // Redirect to new API.
276  clang_getExpansionLocation(location, file, line, column, offset);
277}
278
279void clang_getSpellingLocation(CXSourceLocation location,
280                               CXFile *file,
281                               unsigned *line,
282                               unsigned *column,
283                               unsigned *offset) {
284
285  if (!isASTUnitSourceLocation(location)) {
286    CXLoadedDiagnostic::decodeLocation(location, file, line,
287                                           column, offset);
288    return;
289  }
290
291  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
292
293  if (!location.ptr_data[0] || Loc.isInvalid())
294    return createNullLocation(file, line, column, offset);
295
296  const SourceManager &SM =
297  *static_cast<const SourceManager*>(location.ptr_data[0]);
298  SourceLocation SpellLoc = Loc;
299  if (SpellLoc.isMacroID()) {
300    SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
301    if (SimpleSpellingLoc.isFileID() &&
302        SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
303      SpellLoc = SimpleSpellingLoc;
304    else
305      SpellLoc = SM.getExpansionLoc(SpellLoc);
306  }
307
308  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
309  FileID FID = LocInfo.first;
310  unsigned FileOffset = LocInfo.second;
311
312  if (FID.isInvalid())
313    return createNullLocation(file, line, column, offset);
314
315  if (file)
316    *file = (void *)SM.getFileEntryForID(FID);
317  if (line)
318    *line = SM.getLineNumber(FID, FileOffset);
319  if (column)
320    *column = SM.getColumnNumber(FID, FileOffset);
321  if (offset)
322    *offset = FileOffset;
323}
324
325} // end extern "C"
326
327