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 void clang_getExpansionLocation(CXSourceLocation location,
    202                                 CXFile *file,
    203                                 unsigned *line,
    204                                 unsigned *column,
    205                                 unsigned *offset) {
    206 
    207   if (!isASTUnitSourceLocation(location)) {
    208     CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
    209     return;
    210   }
    211 
    212   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    213 
    214   if (!location.ptr_data[0] || Loc.isInvalid()) {
    215     createNullLocation(file, line, column, offset);
    216     return;
    217   }
    218 
    219   const SourceManager &SM =
    220   *static_cast<const SourceManager*>(location.ptr_data[0]);
    221   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
    222 
    223   // Check that the FileID is invalid on the expansion location.
    224   // This can manifest in invalid code.
    225   FileID fileID = SM.getFileID(ExpansionLoc);
    226   bool Invalid = false;
    227   const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
    228   if (Invalid || !sloc.isFile()) {
    229     createNullLocation(file, line, column, offset);
    230     return;
    231   }
    232 
    233   if (file)
    234     *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
    235   if (line)
    236     *line = SM.getExpansionLineNumber(ExpansionLoc);
    237   if (column)
    238     *column = SM.getExpansionColumnNumber(ExpansionLoc);
    239   if (offset)
    240     *offset = SM.getDecomposedLoc(ExpansionLoc).second;
    241 }
    242 
    243 void clang_getPresumedLocation(CXSourceLocation location,
    244                                CXString *filename,
    245                                unsigned *line,
    246                                unsigned *column) {
    247 
    248   if (!isASTUnitSourceLocation(location)) {
    249     // Other SourceLocation implementations do not support presumed locations
    250     // at this time.
    251     createNullLocation(filename, line, column);
    252     return;
    253   }
    254 
    255   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    256 
    257   if (!location.ptr_data[0] || Loc.isInvalid())
    258     createNullLocation(filename, line, column);
    259   else {
    260     const SourceManager &SM =
    261     *static_cast<const SourceManager*>(location.ptr_data[0]);
    262     PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
    263 
    264     if (filename)
    265       *filename = cxstring::createRef(PreLoc.getFilename());
    266     if (line)
    267       *line = PreLoc.getLine();
    268     if (column)
    269       *column = PreLoc.getColumn();
    270   }
    271 }
    272 
    273 void clang_getInstantiationLocation(CXSourceLocation location,
    274                                     CXFile *file,
    275                                     unsigned *line,
    276                                     unsigned *column,
    277                                     unsigned *offset) {
    278   // Redirect to new API.
    279   clang_getExpansionLocation(location, file, line, column, offset);
    280 }
    281 
    282 void clang_getSpellingLocation(CXSourceLocation location,
    283                                CXFile *file,
    284                                unsigned *line,
    285                                unsigned *column,
    286                                unsigned *offset) {
    287 
    288   if (!isASTUnitSourceLocation(location)) {
    289     CXLoadedDiagnostic::decodeLocation(location, file, line,
    290                                            column, offset);
    291     return;
    292   }
    293 
    294   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    295 
    296   if (!location.ptr_data[0] || Loc.isInvalid())
    297     return createNullLocation(file, line, column, offset);
    298 
    299   const SourceManager &SM =
    300   *static_cast<const SourceManager*>(location.ptr_data[0]);
    301   // FIXME: This should call SourceManager::getSpellingLoc().
    302   SourceLocation SpellLoc = SM.getFileLoc(Loc);
    303   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
    304   FileID FID = LocInfo.first;
    305   unsigned FileOffset = LocInfo.second;
    306 
    307   if (FID.isInvalid())
    308     return createNullLocation(file, line, column, offset);
    309 
    310   if (file)
    311     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
    312   if (line)
    313     *line = SM.getLineNumber(FID, FileOffset);
    314   if (column)
    315     *column = SM.getColumnNumber(FID, FileOffset);
    316   if (offset)
    317     *offset = FileOffset;
    318 }
    319 
    320 void clang_getFileLocation(CXSourceLocation location,
    321                            CXFile *file,
    322                            unsigned *line,
    323                            unsigned *column,
    324                            unsigned *offset) {
    325 
    326   if (!isASTUnitSourceLocation(location)) {
    327     CXLoadedDiagnostic::decodeLocation(location, file, line,
    328                                            column, offset);
    329     return;
    330   }
    331 
    332   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    333 
    334   if (!location.ptr_data[0] || Loc.isInvalid())
    335     return createNullLocation(file, line, column, offset);
    336 
    337   const SourceManager &SM =
    338   *static_cast<const SourceManager*>(location.ptr_data[0]);
    339   SourceLocation FileLoc = SM.getFileLoc(Loc);
    340   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
    341   FileID FID = LocInfo.first;
    342   unsigned FileOffset = LocInfo.second;
    343 
    344   if (FID.isInvalid())
    345     return createNullLocation(file, line, column, offset);
    346 
    347   if (file)
    348     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
    349   if (line)
    350     *line = SM.getLineNumber(FID, FileOffset);
    351   if (column)
    352     *column = SM.getColumnNumber(FID, FileOffset);
    353   if (offset)
    354     *offset = FileOffset;
    355 }
    356 
    357 } // end extern "C"
    358