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