CXSourceLocation.cpp revision 153221717e39ce41323d5bc6b8b8bf130923c1bd
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 22using namespace clang; 23using namespace clang::cxstring; 24 25//===----------------------------------------------------------------------===// 26// Internal predicates on CXSourceLocations. 27//===----------------------------------------------------------------------===// 28 29static 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 39extern "C" { 40 41CXSourceLocation clang_getNullLocation() { 42 CXSourceLocation Result = { { 0, 0 }, 0 }; 43 return Result; 44} 45 46unsigned 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 52CXSourceRange clang_getNullRange() { 53 CXSourceRange Result = { { 0, 0 }, 0, 0 }; 54 return Result; 55} 56 57CXSourceRange 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 75unsigned 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 82int clang_Range_isNull(CXSourceRange range) { 83 return clang_equalRanges(range, clang_getNullRange()); 84} 85 86 87CXSourceLocation 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 99CXSourceLocation 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 117extern "C" { 118 119CXSourceLocation 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 146CXSourceLocation 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 170static 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 183static 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 196extern "C" { 197 198void 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 240void 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 270void 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 279void 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