CXSourceLocation.cpp revision 6ee225c8d4381e728c73252ed589f13e9f546def
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 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 (!isASTUnitSourceLocation(begin)) { 58 if (isASTUnitSourceLocation(end)) 59 return clang_getNullRange(); 60 CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 }; 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_data, end.int_data }; 70 71 return Result; 72} 73 74unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange 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(range, clang_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], 0 }, 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], 0 }, 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} // end extern "C" 111 112//===----------------------------------------------------------------------===// 113// Getting CXSourceLocations and CXSourceRanges from a translation unit. 114//===----------------------------------------------------------------------===// 115 116extern "C" { 117 118CXSourceLocation clang_getLocation(CXTranslationUnit tu, 119 CXFile file, 120 unsigned line, 121 unsigned column) { 122 if (!tu || !file) 123 return clang_getNullLocation(); 124 125 bool Logging = ::getenv("LIBCLANG_LOGGING"); 126 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); 127 ASTUnit::ConcurrencyCheck Check(*CXXUnit); 128 const FileEntry *File = static_cast<const FileEntry *>(file); 129 SourceLocation SLoc = CXXUnit->getLocation(File, line, column); 130 if (SLoc.isInvalid()) { 131 if (Logging) 132 llvm::errs() << "clang_getLocation(\"" << File->getName() 133 << "\", " << line << ", " << column << ") = invalid\n"; 134 return clang_getNullLocation(); 135 } 136 137 if (Logging) 138 llvm::errs() << "clang_getLocation(\"" << File->getName() 139 << "\", " << line << ", " << column << ") = " 140 << SLoc.getRawEncoding() << "\n"; 141 142 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); 143} 144 145CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu, 146 CXFile file, 147 unsigned offset) { 148 if (!tu || !file) 149 return clang_getNullLocation(); 150 151 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); 152 153 SourceLocation SLoc 154 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset); 155 156 if (SLoc.isInvalid()) 157 return clang_getNullLocation(); 158 159 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); 160} 161 162} // end extern "C" 163 164//===----------------------------------------------------------------------===// 165// Routines for expanding and manipulating CXSourceLocations, regardless 166// of their origin. 167//===----------------------------------------------------------------------===// 168 169static void createNullLocation(CXFile *file, unsigned *line, 170 unsigned *column, unsigned *offset) { 171 if (file) 172 *file = 0; 173 if (line) 174 *line = 0; 175 if (column) 176 *column = 0; 177 if (offset) 178 *offset = 0; 179 return; 180} 181 182static void createNullLocation(CXString *filename, unsigned *line, 183 unsigned *column, unsigned *offset = 0) { 184 if (filename) 185 *filename = createCXString(""); 186 if (line) 187 *line = 0; 188 if (column) 189 *column = 0; 190 if (offset) 191 *offset = 0; 192 return; 193} 194 195extern "C" { 196 197void clang_getExpansionLocation(CXSourceLocation location, 198 CXFile *file, 199 unsigned *line, 200 unsigned *column, 201 unsigned *offset) { 202 203 if (!isASTUnitSourceLocation(location)) { 204 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset); 205 return; 206 } 207 208 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 209 210 if (!location.ptr_data[0] || Loc.isInvalid()) { 211 createNullLocation(file, line, column, offset); 212 return; 213 } 214 215 const SourceManager &SM = 216 *static_cast<const SourceManager*>(location.ptr_data[0]); 217 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); 218 219 // Check that the FileID is invalid on the expansion location. 220 // This can manifest in invalid code. 221 FileID fileID = SM.getFileID(ExpansionLoc); 222 bool Invalid = false; 223 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); 224 if (Invalid || !sloc.isFile()) { 225 createNullLocation(file, line, column, offset); 226 return; 227 } 228 229 if (file) 230 *file = (void *)SM.getFileEntryForSLocEntry(sloc); 231 if (line) 232 *line = SM.getExpansionLineNumber(ExpansionLoc); 233 if (column) 234 *column = SM.getExpansionColumnNumber(ExpansionLoc); 235 if (offset) 236 *offset = SM.getDecomposedLoc(ExpansionLoc).second; 237} 238 239void clang_getPresumedLocation(CXSourceLocation location, 240 CXString *filename, 241 unsigned *line, 242 unsigned *column) { 243 244 if (!isASTUnitSourceLocation(location)) { 245 // Other SourceLocation implementations do not support presumed locations 246 // at this time. 247 createNullLocation(filename, line, column); 248 return; 249 } 250 251 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 252 253 if (!location.ptr_data[0] || Loc.isInvalid()) 254 createNullLocation(filename, line, column); 255 else { 256 const SourceManager &SM = 257 *static_cast<const SourceManager*>(location.ptr_data[0]); 258 PresumedLoc PreLoc = SM.getPresumedLoc(Loc); 259 260 if (filename) 261 *filename = createCXString(PreLoc.getFilename()); 262 if (line) 263 *line = PreLoc.getLine(); 264 if (column) 265 *column = PreLoc.getColumn(); 266 } 267} 268 269void clang_getInstantiationLocation(CXSourceLocation location, 270 CXFile *file, 271 unsigned *line, 272 unsigned *column, 273 unsigned *offset) { 274 // Redirect to new API. 275 clang_getExpansionLocation(location, file, line, column, offset); 276} 277 278void clang_getSpellingLocation(CXSourceLocation location, 279 CXFile *file, 280 unsigned *line, 281 unsigned *column, 282 unsigned *offset) { 283 284 if (!isASTUnitSourceLocation(location)) { 285 CXLoadedDiagnostic::decodeLocation(location, file, line, 286 column, offset); 287 return; 288 } 289 290 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 291 292 if (!location.ptr_data[0] || Loc.isInvalid()) 293 return createNullLocation(file, line, column, offset); 294 295 const SourceManager &SM = 296 *static_cast<const SourceManager*>(location.ptr_data[0]); 297 SourceLocation SpellLoc = SM.getFileLoc(Loc); 298 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc); 299 FileID FID = LocInfo.first; 300 unsigned FileOffset = LocInfo.second; 301 302 if (FID.isInvalid()) 303 return createNullLocation(file, line, column, offset); 304 305 if (file) 306 *file = (void *)SM.getFileEntryForID(FID); 307 if (line) 308 *line = SM.getLineNumber(FID, FileOffset); 309 if (column) 310 *column = SM.getColumnNumber(FID, FileOffset); 311 if (offset) 312 *offset = FileOffset; 313} 314 315} // end extern "C" 316 317