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