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