brintos

brintos / llvm-project-archived public Read only

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