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 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 41 CXSourceLocation clang_getNullLocation() { 42 CXSourceLocation Result = { { 0, 0 }, 0 }; 43 return Result; 44 } 45 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 52 CXSourceRange clang_getNullRange() { 53 CXSourceRange Result = { { 0, 0 }, 0, 0 }; 54 return Result; 55 } 56 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 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 82 int clang_Range_isNull(CXSourceRange range) { 83 return clang_equalRanges(range, clang_getNullRange()); 84 } 85 86 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 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 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 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 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 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 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 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 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 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