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 21 using namespace clang; 22 using namespace clang::cxstring; 23 24 //===----------------------------------------------------------------------===// 25 // Internal predicates on CXSourceLocations. 26 //===----------------------------------------------------------------------===// 27 28 static 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 38 extern "C" { 39 40 CXSourceLocation clang_getNullLocation() { 41 CXSourceLocation Result = { { 0, 0 }, 0 }; 42 return Result; 43 } 44 45 unsigned 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 51 CXSourceRange clang_getNullRange() { 52 CXSourceRange Result = { { 0, 0 }, 0, 0 }; 53 return Result; 54 } 55 56 CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { 57 if (begin.ptr_data[0] != end.ptr_data[0] || 58 begin.ptr_data[1] != end.ptr_data[1]) 59 return clang_getNullRange(); 60 61 CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] }, 62 begin.int_data, end.int_data }; 63 64 return Result; 65 } 66 67 68 unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) { 69 return range1.ptr_data[0] == range2.ptr_data[0] 70 && range1.ptr_data[1] == range2.ptr_data[1] 71 && range1.begin_int_data == range2.begin_int_data 72 && range1.end_int_data == range2.end_int_data; 73 } 74 75 int clang_Range_isNull(CXSourceRange range) { 76 return clang_equalRanges(range, clang_getNullRange()); 77 } 78 79 80 CXSourceLocation clang_getRangeStart(CXSourceRange range) { 81 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, 82 range.begin_int_data }; 83 return Result; 84 } 85 86 CXSourceLocation clang_getRangeEnd(CXSourceRange range) { 87 CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, 88 range.end_int_data }; 89 return Result; 90 } 91 92 } // end extern "C" 93 94 //===----------------------------------------------------------------------===// 95 // Getting CXSourceLocations and CXSourceRanges from a translation unit. 96 //===----------------------------------------------------------------------===// 97 98 extern "C" { 99 100 CXSourceLocation clang_getLocation(CXTranslationUnit tu, 101 CXFile file, 102 unsigned line, 103 unsigned column) { 104 if (!tu || !file) 105 return clang_getNullLocation(); 106 107 bool Logging = ::getenv("LIBCLANG_LOGGING"); 108 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); 109 ASTUnit::ConcurrencyCheck Check(*CXXUnit); 110 const FileEntry *File = static_cast<const FileEntry *>(file); 111 SourceLocation SLoc = CXXUnit->getLocation(File, line, column); 112 if (SLoc.isInvalid()) { 113 if (Logging) 114 llvm::errs() << "clang_getLocation(\"" << File->getName() 115 << "\", " << line << ", " << column << ") = invalid\n"; 116 return clang_getNullLocation(); 117 } 118 119 if (Logging) 120 llvm::errs() << "clang_getLocation(\"" << File->getName() 121 << "\", " << line << ", " << column << ") = " 122 << SLoc.getRawEncoding() << "\n"; 123 124 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); 125 } 126 127 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu, 128 CXFile file, 129 unsigned offset) { 130 if (!tu || !file) 131 return clang_getNullLocation(); 132 133 ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); 134 135 SourceLocation SLoc 136 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset); 137 138 if (SLoc.isInvalid()) 139 return clang_getNullLocation(); 140 141 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); 142 } 143 144 } // end extern "C" 145 146 //===----------------------------------------------------------------------===// 147 // Routines for expanding and manipulating CXSourceLocations, regardless 148 // of their origin. 149 //===----------------------------------------------------------------------===// 150 151 static void createNullLocation(CXFile *file, unsigned *line, 152 unsigned *column, unsigned *offset) { 153 if (file) 154 *file = 0; 155 if (line) 156 *line = 0; 157 if (column) 158 *column = 0; 159 if (offset) 160 *offset = 0; 161 return; 162 } 163 164 static void createNullLocation(CXString *filename, unsigned *line, 165 unsigned *column, unsigned *offset = 0) { 166 if (filename) 167 *filename = createCXString(""); 168 if (line) 169 *line = 0; 170 if (column) 171 *column = 0; 172 if (offset) 173 *offset = 0; 174 return; 175 } 176 177 extern "C" { 178 179 void clang_getExpansionLocation(CXSourceLocation location, 180 CXFile *file, 181 unsigned *line, 182 unsigned *column, 183 unsigned *offset) { 184 185 if (isASTUnitSourceLocation(location)) { 186 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 187 188 if (!location.ptr_data[0] || Loc.isInvalid()) { 189 createNullLocation(file, line, column, offset); 190 return; 191 } 192 193 const SourceManager &SM = 194 *static_cast<const SourceManager*>(location.ptr_data[0]); 195 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); 196 197 // Check that the FileID is invalid on the expansion location. 198 // This can manifest in invalid code. 199 FileID fileID = SM.getFileID(ExpansionLoc); 200 bool Invalid = false; 201 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); 202 if (Invalid || !sloc.isFile()) { 203 createNullLocation(file, line, column, offset); 204 return; 205 } 206 207 if (file) 208 *file = (void *)SM.getFileEntryForSLocEntry(sloc); 209 if (line) 210 *line = SM.getExpansionLineNumber(ExpansionLoc); 211 if (column) 212 *column = SM.getExpansionColumnNumber(ExpansionLoc); 213 if (offset) 214 *offset = SM.getDecomposedLoc(ExpansionLoc).second; 215 return; 216 } 217 218 // FIXME: 219 createNullLocation(file, line, column, offset); 220 } 221 222 void clang_getPresumedLocation(CXSourceLocation location, 223 CXString *filename, 224 unsigned *line, 225 unsigned *column) { 226 227 if (isASTUnitSourceLocation(location)) { 228 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 229 230 if (!location.ptr_data[0] || Loc.isInvalid()) 231 createNullLocation(filename, line, column); 232 else { 233 const SourceManager &SM = 234 *static_cast<const SourceManager*>(location.ptr_data[0]); 235 PresumedLoc PreLoc = SM.getPresumedLoc(Loc); 236 237 if (filename) 238 *filename = createCXString(PreLoc.getFilename()); 239 if (line) 240 *line = PreLoc.getLine(); 241 if (column) 242 *column = PreLoc.getColumn(); 243 } 244 return; 245 } 246 247 // FIXME: 248 createNullLocation(filename, line, column); 249 } 250 251 void clang_getInstantiationLocation(CXSourceLocation location, 252 CXFile *file, 253 unsigned *line, 254 unsigned *column, 255 unsigned *offset) { 256 // Redirect to new API. 257 clang_getExpansionLocation(location, file, line, column, offset); 258 } 259 260 void clang_getSpellingLocation(CXSourceLocation location, 261 CXFile *file, 262 unsigned *line, 263 unsigned *column, 264 unsigned *offset) { 265 266 if (isASTUnitSourceLocation(location)) { 267 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 268 269 if (!location.ptr_data[0] || Loc.isInvalid()) 270 return createNullLocation(file, line, column, offset); 271 272 const SourceManager &SM = 273 *static_cast<const SourceManager*>(location.ptr_data[0]); 274 SourceLocation SpellLoc = Loc; 275 if (SpellLoc.isMacroID()) { 276 SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc); 277 if (SimpleSpellingLoc.isFileID() && 278 SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first)) 279 SpellLoc = SimpleSpellingLoc; 280 else 281 SpellLoc = SM.getExpansionLoc(SpellLoc); 282 } 283 284 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc); 285 FileID FID = LocInfo.first; 286 unsigned FileOffset = LocInfo.second; 287 288 if (FID.isInvalid()) 289 return createNullLocation(file, line, column, offset); 290 291 if (file) 292 *file = (void *)SM.getFileEntryForID(FID); 293 if (line) 294 *line = SM.getLineNumber(FID, FileOffset); 295 if (column) 296 *column = SM.getColumnNumber(FID, FileOffset); 297 if (offset) 298 *offset = FileOffset; 299 return; 300 } 301 302 // FIXME: 303 createNullLocation(file, line, column, offset); 304 } 305 306 } // end extern "C" 307 308