//===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines routines for manipulating CXSourceLocations. // //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTUnit.h" #include "CIndexer.h" #include "CXString.h" #include "CXSourceLocation.h" #include "CXTranslationUnit.h" #include "CXLoadedDiagnostic.h" using namespace clang; using namespace clang::cxstring; //===----------------------------------------------------------------------===// // Internal predicates on CXSourceLocations. //===----------------------------------------------------------------------===// static bool isASTUnitSourceLocation(const CXSourceLocation &L) { // If the lowest bit is clear then the first ptr_data entry is a SourceManager // pointer, or the CXSourceLocation is a null location. return ((uintptr_t)L.ptr_data[0] & 0x1) == 0; } //===----------------------------------------------------------------------===// // Basic construction and comparison of CXSourceLocations and CXSourceRanges. //===----------------------------------------------------------------------===// extern "C" { CXSourceLocation clang_getNullLocation() { CXSourceLocation Result = { { 0, 0 }, 0 }; return Result; } unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { return (loc1.ptr_data[0] == loc2.ptr_data[0] && loc1.ptr_data[1] == loc2.ptr_data[1] && loc1.int_data == loc2.int_data); } CXSourceRange clang_getNullRange() { CXSourceRange Result = { { 0, 0 }, 0, 0 }; return Result; } CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { if (!isASTUnitSourceLocation(begin)) { if (isASTUnitSourceLocation(end)) return clang_getNullRange(); CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 }; return Result; } if (begin.ptr_data[0] != end.ptr_data[0] || begin.ptr_data[1] != end.ptr_data[1]) return clang_getNullRange(); CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] }, begin.int_data, end.int_data }; return Result; } unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) { return range1.ptr_data[0] == range2.ptr_data[0] && range1.ptr_data[1] == range2.ptr_data[1] && range1.begin_int_data == range2.begin_int_data && range1.end_int_data == range2.end_int_data; } int clang_Range_isNull(CXSourceRange range) { return clang_equalRanges(range, clang_getNullRange()); } CXSourceLocation clang_getRangeStart(CXSourceRange range) { // Special decoding for CXSourceLocations for CXLoadedDiagnostics. if ((uintptr_t)range.ptr_data[0] & 0x1) { CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 }; return Result; } CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, range.begin_int_data }; return Result; } CXSourceLocation clang_getRangeEnd(CXSourceRange range) { // Special decoding for CXSourceLocations for CXLoadedDiagnostics. if ((uintptr_t)range.ptr_data[0] & 0x1) { CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 }; return Result; } CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, range.end_int_data }; return Result; } } // end extern "C" //===----------------------------------------------------------------------===// // Getting CXSourceLocations and CXSourceRanges from a translation unit. //===----------------------------------------------------------------------===// extern "C" { CXSourceLocation clang_getLocation(CXTranslationUnit tu, CXFile file, unsigned line, unsigned column) { if (!tu || !file) return clang_getNullLocation(); bool Logging = ::getenv("LIBCLANG_LOGGING"); ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); ASTUnit::ConcurrencyCheck Check(*CXXUnit); const FileEntry *File = static_cast<const FileEntry *>(file); SourceLocation SLoc = CXXUnit->getLocation(File, line, column); if (SLoc.isInvalid()) { if (Logging) llvm::errs() << "clang_getLocation(\"" << File->getName() << "\", " << line << ", " << column << ") = invalid\n"; return clang_getNullLocation(); } if (Logging) llvm::errs() << "clang_getLocation(\"" << File->getName() << "\", " << line << ", " << column << ") = " << SLoc.getRawEncoding() << "\n"; return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); } CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu, CXFile file, unsigned offset) { if (!tu || !file) return clang_getNullLocation(); ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); SourceLocation SLoc = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset); if (SLoc.isInvalid()) return clang_getNullLocation(); return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); } } // end extern "C" //===----------------------------------------------------------------------===// // Routines for expanding and manipulating CXSourceLocations, regardless // of their origin. //===----------------------------------------------------------------------===// static void createNullLocation(CXFile *file, unsigned *line, unsigned *column, unsigned *offset) { if (file) *file = 0; if (line) *line = 0; if (column) *column = 0; if (offset) *offset = 0; return; } static void createNullLocation(CXString *filename, unsigned *line, unsigned *column, unsigned *offset = 0) { if (filename) *filename = createCXString(""); if (line) *line = 0; if (column) *column = 0; if (offset) *offset = 0; return; } extern "C" { void clang_getExpansionLocation(CXSourceLocation location, CXFile *file, unsigned *line, unsigned *column, unsigned *offset) { if (!isASTUnitSourceLocation(location)) { CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset); return; } SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); if (!location.ptr_data[0] || Loc.isInvalid()) { createNullLocation(file, line, column, offset); return; } const SourceManager &SM = *static_cast<const SourceManager*>(location.ptr_data[0]); SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); // Check that the FileID is invalid on the expansion location. // This can manifest in invalid code. FileID fileID = SM.getFileID(ExpansionLoc); bool Invalid = false; const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); if (Invalid || !sloc.isFile()) { createNullLocation(file, line, column, offset); return; } if (file) *file = (void *)SM.getFileEntryForSLocEntry(sloc); if (line) *line = SM.getExpansionLineNumber(ExpansionLoc); if (column) *column = SM.getExpansionColumnNumber(ExpansionLoc); if (offset) *offset = SM.getDecomposedLoc(ExpansionLoc).second; } void clang_getPresumedLocation(CXSourceLocation location, CXString *filename, unsigned *line, unsigned *column) { if (!isASTUnitSourceLocation(location)) { // Other SourceLocation implementations do not support presumed locations // at this time. createNullLocation(filename, line, column); return; } SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); if (!location.ptr_data[0] || Loc.isInvalid()) createNullLocation(filename, line, column); else { const SourceManager &SM = *static_cast<const SourceManager*>(location.ptr_data[0]); PresumedLoc PreLoc = SM.getPresumedLoc(Loc); if (filename) *filename = createCXString(PreLoc.getFilename()); if (line) *line = PreLoc.getLine(); if (column) *column = PreLoc.getColumn(); } } void clang_getInstantiationLocation(CXSourceLocation location, CXFile *file, unsigned *line, unsigned *column, unsigned *offset) { // Redirect to new API. clang_getExpansionLocation(location, file, line, column, offset); } void clang_getSpellingLocation(CXSourceLocation location, CXFile *file, unsigned *line, unsigned *column, unsigned *offset) { if (!isASTUnitSourceLocation(location)) { CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset); return; } SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); if (!location.ptr_data[0] || Loc.isInvalid()) return createNullLocation(file, line, column, offset); const SourceManager &SM = *static_cast<const SourceManager*>(location.ptr_data[0]); SourceLocation SpellLoc = Loc; if (SpellLoc.isMacroID()) { SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc); if (SimpleSpellingLoc.isFileID() && SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first)) SpellLoc = SimpleSpellingLoc; else SpellLoc = SM.getExpansionLoc(SpellLoc); } std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; if (FID.isInvalid()) return createNullLocation(file, line, column, offset); if (file) *file = (void *)SM.getFileEntryForID(FID); if (line) *line = SM.getLineNumber(FID, FileOffset); if (column) *column = SM.getColumnNumber(FID, FileOffset); if (offset) *offset = FileOffset; } } // end extern "C"