• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 using namespace clang;
23 using namespace clang::cxstring;
24 
25 //===----------------------------------------------------------------------===//
26 // Internal predicates on CXSourceLocations.
27 //===----------------------------------------------------------------------===//
28 
isASTUnitSourceLocation(const CXSourceLocation & L)29 static 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 
39 extern "C" {
40 
clang_getNullLocation()41 CXSourceLocation clang_getNullLocation() {
42   CXSourceLocation Result = { { 0, 0 }, 0 };
43   return Result;
44 }
45 
clang_equalLocations(CXSourceLocation loc1,CXSourceLocation loc2)46 unsigned 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 
clang_getNullRange()52 CXSourceRange clang_getNullRange() {
53   CXSourceRange Result = { { 0, 0 }, 0, 0 };
54   return Result;
55 }
56 
clang_getRange(CXSourceLocation begin,CXSourceLocation end)57 CXSourceRange 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 
clang_equalRanges(CXSourceRange range1,CXSourceRange range2)75 unsigned 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 
clang_Range_isNull(CXSourceRange range)82 int clang_Range_isNull(CXSourceRange range) {
83   return clang_equalRanges(range, clang_getNullRange());
84 }
85 
86 
clang_getRangeStart(CXSourceRange range)87 CXSourceLocation 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 
clang_getRangeEnd(CXSourceRange range)99 CXSourceLocation 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 
117 extern "C" {
118 
clang_getLocation(CXTranslationUnit tu,CXFile file,unsigned line,unsigned column)119 CXSourceLocation 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 
clang_getLocationForOffset(CXTranslationUnit tu,CXFile file,unsigned offset)146 CXSourceLocation 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 
createNullLocation(CXFile * file,unsigned * line,unsigned * column,unsigned * offset)170 static 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 
createNullLocation(CXString * filename,unsigned * line,unsigned * column,unsigned * offset=0)183 static 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 
196 extern "C" {
197 
clang_getExpansionLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)198 void 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 
clang_getPresumedLocation(CXSourceLocation location,CXString * filename,unsigned * line,unsigned * column)240 void 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 
clang_getInstantiationLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)270 void 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 
clang_getSpellingLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)279 void 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