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