head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC4:1.1.1.5
	netbsd-11-0-RC3:1.1.1.5
	netbsd-11-0-RC2:1.1.1.5
	netbsd-11-0-RC1:1.1.1.5
	perseant-exfatfs-base-20250801:1.1.1.5
	netbsd-11:1.1.1.5.0.10
	netbsd-11-base:1.1.1.5
	netbsd-10-1-RELEASE:1.1.1.5
	perseant-exfatfs-base-20240630:1.1.1.5
	perseant-exfatfs:1.1.1.5.0.8
	perseant-exfatfs-base:1.1.1.5
	netbsd-8-3-RELEASE:1.1.1.4
	netbsd-9-4-RELEASE:1.1.1.4
	netbsd-10-0-RELEASE:1.1.1.5
	netbsd-10-0-RC6:1.1.1.5
	netbsd-10-0-RC5:1.1.1.5
	netbsd-10-0-RC4:1.1.1.5
	netbsd-10-0-RC3:1.1.1.5
	netbsd-10-0-RC2:1.1.1.5
	netbsd-10-0-RC1:1.1.1.5
	netbsd-10:1.1.1.5.0.6
	netbsd-10-base:1.1.1.5
	netbsd-9-3-RELEASE:1.1.1.4
	cjep_sun2x:1.1.1.5.0.4
	cjep_sun2x-base:1.1.1.5
	cjep_staticlib_x-base1:1.1.1.5
	netbsd-9-2-RELEASE:1.1.1.4
	cjep_staticlib_x:1.1.1.5.0.2
	cjep_staticlib_x-base:1.1.1.5
	netbsd-9-1-RELEASE:1.1.1.4
	phil-wifi-20200421:1.1.1.5
	phil-wifi-20200411:1.1.1.5
	phil-wifi-20200406:1.1.1.5
	netbsd-8-2-RELEASE:1.1.1.4
	netbsd-9-0-RELEASE:1.1.1.4
	netbsd-9-0-RC2:1.1.1.4
	netbsd-9-0-RC1:1.1.1.4
	netbsd-9:1.1.1.4.0.16
	netbsd-9-base:1.1.1.4
	phil-wifi-20190609:1.1.1.4
	netbsd-8-1-RELEASE:1.1.1.4
	netbsd-8-1-RC1:1.1.1.4
	pgoyette-compat-merge-20190127:1.1.1.4
	pgoyette-compat-20190127:1.1.1.4
	pgoyette-compat-20190118:1.1.1.4
	pgoyette-compat-1226:1.1.1.4
	pgoyette-compat-1126:1.1.1.4
	pgoyette-compat-1020:1.1.1.4
	pgoyette-compat-0930:1.1.1.4
	pgoyette-compat-0906:1.1.1.4
	netbsd-7-2-RELEASE:1.1.1.3
	pgoyette-compat-0728:1.1.1.4
	clang-337282:1.1.1.4
	netbsd-8-0-RELEASE:1.1.1.4
	phil-wifi:1.1.1.4.0.14
	phil-wifi-base:1.1.1.4
	pgoyette-compat-0625:1.1.1.4
	netbsd-8-0-RC2:1.1.1.4
	pgoyette-compat-0521:1.1.1.4
	pgoyette-compat-0502:1.1.1.4
	pgoyette-compat-0422:1.1.1.4
	netbsd-8-0-RC1:1.1.1.4
	pgoyette-compat-0415:1.1.1.4
	pgoyette-compat-0407:1.1.1.4
	pgoyette-compat-0330:1.1.1.4
	pgoyette-compat-0322:1.1.1.4
	pgoyette-compat-0315:1.1.1.4
	netbsd-7-1-2-RELEASE:1.1.1.3
	pgoyette-compat:1.1.1.4.0.12
	pgoyette-compat-base:1.1.1.4
	netbsd-7-1-1-RELEASE:1.1.1.3
	clang-319952:1.1.1.4
	matt-nb8-mediatek:1.1.1.4.0.10
	matt-nb8-mediatek-base:1.1.1.4
	clang-309604:1.1.1.4
	perseant-stdc-iso10646:1.1.1.4.0.8
	perseant-stdc-iso10646-base:1.1.1.4
	netbsd-8:1.1.1.4.0.6
	netbsd-8-base:1.1.1.4
	prg-localcount2-base3:1.1.1.4
	prg-localcount2-base2:1.1.1.4
	prg-localcount2-base1:1.1.1.4
	prg-localcount2:1.1.1.4.0.4
	prg-localcount2-base:1.1.1.4
	pgoyette-localcount-20170426:1.1.1.4
	bouyer-socketcan-base1:1.1.1.4
	pgoyette-localcount-20170320:1.1.1.4
	netbsd-7-1:1.1.1.3.0.12
	netbsd-7-1-RELEASE:1.1.1.3
	netbsd-7-1-RC2:1.1.1.3
	clang-294123:1.1.1.4
	netbsd-7-nhusb-base-20170116:1.1.1.3
	bouyer-socketcan:1.1.1.4.0.2
	bouyer-socketcan-base:1.1.1.4
	clang-291444:1.1.1.4
	pgoyette-localcount-20170107:1.1.1.3
	netbsd-7-1-RC1:1.1.1.3
	pgoyette-localcount-20161104:1.1.1.3
	netbsd-7-0-2-RELEASE:1.1.1.3
	localcount-20160914:1.1.1.3
	netbsd-7-nhusb:1.1.1.3.0.10
	netbsd-7-nhusb-base:1.1.1.3
	clang-280599:1.1.1.3
	pgoyette-localcount-20160806:1.1.1.3
	pgoyette-localcount-20160726:1.1.1.3
	pgoyette-localcount:1.1.1.3.0.8
	pgoyette-localcount-base:1.1.1.3
	netbsd-7-0-1-RELEASE:1.1.1.3
	clang-261930:1.1.1.3
	netbsd-7-0:1.1.1.3.0.6
	netbsd-7-0-RELEASE:1.1.1.3
	netbsd-7-0-RC3:1.1.1.3
	netbsd-7-0-RC2:1.1.1.3
	netbsd-7-0-RC1:1.1.1.3
	clang-237755:1.1.1.3
	clang-232565:1.1.1.3
	clang-227398:1.1.1.3
	tls-maxphys-base:1.1.1.3
	tls-maxphys:1.1.1.3.0.4
	netbsd-7:1.1.1.3.0.2
	netbsd-7-base:1.1.1.3
	clang-215315:1.1.1.3
	clang-209886:1.1.1.2
	yamt-pagecache:1.1.1.2.0.4
	yamt-pagecache-base9:1.1.1.2
	tls-earlyentropy:1.1.1.2.0.2
	tls-earlyentropy-base:1.1.1.2
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.2
	riastradh-drm2-base3:1.1.1.2
	clang-202566:1.1.1.2
	clang-201163:1.1.1.2
	clang-199312:1.1.1.1
	clang-198450:1.1.1.1
	clang-196603:1.1.1.1
	clang-195771:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2013.11.28.14.14.48;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	ow8OybrawrB1f3fx;

1.1.1.1
date	2013.11.28.14.14.48;	author joerg;	state Exp;
branches;
next	1.1.1.2;
commitid	ow8OybrawrB1f3fx;

1.1.1.2
date	2014.02.14.20.07.01;	author joerg;	state Exp;
branches
	1.1.1.2.4.1;
next	1.1.1.3;
commitid	annVkZ1sc17rF6px;

1.1.1.3
date	2014.08.10.17.08.24;	author joerg;	state Exp;
branches
	1.1.1.3.4.1
	1.1.1.3.8.1;
next	1.1.1.4;
commitid	N85tXAN6Ex9VZPLx;

1.1.1.4
date	2017.01.11.10.32.22;	author joerg;	state Exp;
branches
	1.1.1.4.14.1;
next	1.1.1.5;
commitid	CNnUNfII1jgNmxBz;

1.1.1.5
date	2019.11.13.22.23.06;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.2.4.1
date	2014.02.14.20.07.01;	author yamt;	state dead;
branches;
next	1.1.1.2.4.2;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.2.4.2
date	2014.05.22.16.19.48;	author yamt;	state Exp;
branches;
next	;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.3.4.1
date	2014.08.10.17.08.24;	author tls;	state dead;
branches;
next	1.1.1.3.4.2;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.3.4.2
date	2014.08.19.23.49.27;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.3.8.1
date	2017.03.20.06.53.37;	author pgoyette;	state Exp;
branches;
next	;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.4.14.1
date	2020.04.13.07.50.33;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@//===- 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 "CLog.h"
#include "CXLoadedDiagnostic.h"
#include "CXSourceLocation.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"

using namespace clang;
using namespace clang::cxindex;

//===----------------------------------------------------------------------===//
// 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();
  if (line == 0 || column == 0)
    return clang_getNullLocation();
  
  LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
  ASTUnit::ConcurrencyCheck Check(*CXXUnit);
  const FileEntry *File = static_cast<const FileEntry *>(file);
  SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
  if (SLoc.isInvalid()) {
    if (Log)
      *Log << llvm::format("(\"%s\", %d, %d) = invalid",
                           File->getName(), line, column);
    return clang_getNullLocation();
  }
  
  CXSourceLocation CXLoc =
      cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
  if (Log)
    *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
         << CXLoc;
  
  return CXLoc;
}
  
CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
                                            CXFile file,
                                            unsigned offset) {
  if (!TU || !file)
    return clang_getNullLocation();
  
  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);

  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 = cxstring::createEmpty();
  if (line)
    *line = 0;
  if (column)
    *column = 0;
  if (offset)
    *offset = 0;
  return;
}

extern "C" {

int clang_Location_isInSystemHeader(CXSourceLocation location) {
  const SourceLocation Loc =
    SourceLocation::getFromRawEncoding(location.int_data);
  if (Loc.isInvalid())
    return 0;

  const SourceManager &SM =
    *static_cast<const SourceManager*>(location.ptr_data[0]);
  return SM.isInSystemHeader(Loc);
}

int clang_Location_isFromMainFile(CXSourceLocation location) {
  const SourceLocation Loc =
    SourceLocation::getFromRawEncoding(location.int_data);
  if (Loc.isInvalid())
    return 0;

  const SourceManager &SM =
    *static_cast<const SourceManager*>(location.ptr_data[0]);
  return SM.isWrittenInMainFile(Loc);
}

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 = const_cast<FileEntry *>(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);
    return;
  }

  const SourceManager &SM =
      *static_cast<const SourceManager *>(location.ptr_data[0]);
  PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
  if (PreLoc.isInvalid()) {
    createNullLocation(filename, line, column);
    return;
  }

  if (filename) *filename = cxstring::createRef(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]);
  // FIXME: This should call SourceManager::getSpellingLoc().
  SourceLocation SpellLoc = SM.getFileLoc(Loc);
  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 = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
  if (line)
    *line = SM.getLineNumber(FID, FileOffset);
  if (column)
    *column = SM.getColumnNumber(FID, FileOffset);
  if (offset)
    *offset = FileOffset;
}

void clang_getFileLocation(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 FileLoc = SM.getFileLoc(Loc);
  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
  FileID FID = LocInfo.first;
  unsigned FileOffset = LocInfo.second;

  if (FID.isInvalid())
    return createNullLocation(file, line, column, offset);

  if (file)
    *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
  if (line)
    *line = SM.getLineNumber(FID, FileOffset);
  if (column)
    *column = SM.getColumnNumber(FID, FileOffset);
  if (offset)
    *offset = FileOffset;
}

} // end extern "C"
@


1.1.1.1
log
@Import Clang 3.4rc1 r195771.
@
text
@@


1.1.1.2
log
@Import Clang 3.5svn r201163.
@
text
@d125 1
a125 5
  if (cxtu::isNotUsableTU(TU)) {
    LOG_BAD_TU(TU);
    return clang_getNullLocation();
  }
  if (!file)
d154 1
a154 2
  if (cxtu::isNotUsableTU(TU)) {
    LOG_BAD_TU(TU);
d156 1
a156 4
  }
  if (!file)
    return clang_getNullLocation();

@


1.1.1.3
log
@Import clang 3.6svn r215315.
@
text
@d44 1
a44 1
  CXSourceLocation Result = { { nullptr, nullptr }, 0 };
d55 1
a55 1
  CXSourceRange Result = { { nullptr, nullptr }, 0, 0 };
d92 1
a92 1
    CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
d104 1
a104 1
    CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
d186 1
a186 1
    *file = nullptr;
d197 1
a197 1
                               unsigned *column, unsigned *offset = nullptr) {
@


1.1.1.3.8.1
log
@Sync with HEAD
@
text
@d41 2
d113 2
d119 2
d134 1
a134 1
  LogRef Log = Logger::make(__func__);
d142 1
a142 1
                           File->getName().str().c_str(), line, column);
d149 1
a149 2
    *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
                         line, column)
d151 1
a151 1

d176 2
d193 1
d206 1
d209 2
d238 1
d279 1
d321 1
d359 1
d390 2
@


1.1.1.4
log
@Import Clang pre-4.0.0 r291444.
@
text
@d41 2
d113 2
d119 2
d134 1
a134 1
  LogRef Log = Logger::make(__func__);
d142 1
a142 1
                           File->getName().str().c_str(), line, column);
d149 1
a149 2
    *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
                         line, column)
d151 1
a151 1

d176 2
d193 1
d206 1
d209 2
d238 1
d279 1
d321 1
d359 1
d390 2
@


1.1.1.4.14.1
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.5
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.3.4.1
log
@file CXSourceLocation.cpp was added on branch tls-maxphys on 2014-08-19 23:49:27 +0000
@
text
@d1 391
@


1.1.1.3.4.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 391
//===- 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 "CLog.h"
#include "CXLoadedDiagnostic.h"
#include "CXSourceLocation.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"

using namespace clang;
using namespace clang::cxindex;

//===----------------------------------------------------------------------===//
// 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 = { { nullptr, nullptr }, 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 = { { nullptr, nullptr }, 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], nullptr }, 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], nullptr }, 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 (cxtu::isNotUsableTU(TU)) {
    LOG_BAD_TU(TU);
    return clang_getNullLocation();
  }
  if (!file)
    return clang_getNullLocation();
  if (line == 0 || column == 0)
    return clang_getNullLocation();
  
  LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
  ASTUnit::ConcurrencyCheck Check(*CXXUnit);
  const FileEntry *File = static_cast<const FileEntry *>(file);
  SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
  if (SLoc.isInvalid()) {
    if (Log)
      *Log << llvm::format("(\"%s\", %d, %d) = invalid",
                           File->getName(), line, column);
    return clang_getNullLocation();
  }
  
  CXSourceLocation CXLoc =
      cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
  if (Log)
    *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
         << CXLoc;
  
  return CXLoc;
}
  
CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
                                            CXFile file,
                                            unsigned offset) {
  if (cxtu::isNotUsableTU(TU)) {
    LOG_BAD_TU(TU);
    return clang_getNullLocation();
  }
  if (!file)
    return clang_getNullLocation();

  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);

  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 = nullptr;
  if (line)
    *line = 0;
  if (column)
    *column = 0;
  if (offset)
    *offset = 0;
  return;
}

static void createNullLocation(CXString *filename, unsigned *line,
                               unsigned *column, unsigned *offset = nullptr) {
  if (filename)
    *filename = cxstring::createEmpty();
  if (line)
    *line = 0;
  if (column)
    *column = 0;
  if (offset)
    *offset = 0;
  return;
}

extern "C" {

int clang_Location_isInSystemHeader(CXSourceLocation location) {
  const SourceLocation Loc =
    SourceLocation::getFromRawEncoding(location.int_data);
  if (Loc.isInvalid())
    return 0;

  const SourceManager &SM =
    *static_cast<const SourceManager*>(location.ptr_data[0]);
  return SM.isInSystemHeader(Loc);
}

int clang_Location_isFromMainFile(CXSourceLocation location) {
  const SourceLocation Loc =
    SourceLocation::getFromRawEncoding(location.int_data);
  if (Loc.isInvalid())
    return 0;

  const SourceManager &SM =
    *static_cast<const SourceManager*>(location.ptr_data[0]);
  return SM.isWrittenInMainFile(Loc);
}

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 = const_cast<FileEntry *>(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);
    return;
  }

  const SourceManager &SM =
      *static_cast<const SourceManager *>(location.ptr_data[0]);
  PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
  if (PreLoc.isInvalid()) {
    createNullLocation(filename, line, column);
    return;
  }

  if (filename) *filename = cxstring::createRef(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]);
  // FIXME: This should call SourceManager::getSpellingLoc().
  SourceLocation SpellLoc = SM.getFileLoc(Loc);
  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 = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
  if (line)
    *line = SM.getLineNumber(FID, FileOffset);
  if (column)
    *column = SM.getColumnNumber(FID, FileOffset);
  if (offset)
    *offset = FileOffset;
}

void clang_getFileLocation(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 FileLoc = SM.getFileLoc(Loc);
  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
  FileID FID = LocInfo.first;
  unsigned FileOffset = LocInfo.second;

  if (FID.isInvalid())
    return createNullLocation(file, line, column, offset);

  if (file)
    *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
  if (line)
    *line = SM.getLineNumber(FID, FileOffset);
  if (column)
    *column = SM.getColumnNumber(FID, FileOffset);
  if (offset)
    *offset = FileOffset;
}

} // end extern "C"
@


1.1.1.2.4.1
log
@file CXSourceLocation.cpp was added on branch yamt-pagecache on 2014-05-22 16:19:48 +0000
@
text
@d1 391
@


1.1.1.2.4.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@a0 391
//===- 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 "CLog.h"
#include "CXLoadedDiagnostic.h"
#include "CXSourceLocation.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"

using namespace clang;
using namespace clang::cxindex;

//===----------------------------------------------------------------------===//
// 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 (cxtu::isNotUsableTU(TU)) {
    LOG_BAD_TU(TU);
    return clang_getNullLocation();
  }
  if (!file)
    return clang_getNullLocation();
  if (line == 0 || column == 0)
    return clang_getNullLocation();
  
  LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
  ASTUnit::ConcurrencyCheck Check(*CXXUnit);
  const FileEntry *File = static_cast<const FileEntry *>(file);
  SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
  if (SLoc.isInvalid()) {
    if (Log)
      *Log << llvm::format("(\"%s\", %d, %d) = invalid",
                           File->getName(), line, column);
    return clang_getNullLocation();
  }
  
  CXSourceLocation CXLoc =
      cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
  if (Log)
    *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
         << CXLoc;
  
  return CXLoc;
}
  
CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
                                            CXFile file,
                                            unsigned offset) {
  if (cxtu::isNotUsableTU(TU)) {
    LOG_BAD_TU(TU);
    return clang_getNullLocation();
  }
  if (!file)
    return clang_getNullLocation();

  ASTUnit *CXXUnit = cxtu::getASTUnit(TU);

  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 = cxstring::createEmpty();
  if (line)
    *line = 0;
  if (column)
    *column = 0;
  if (offset)
    *offset = 0;
  return;
}

extern "C" {

int clang_Location_isInSystemHeader(CXSourceLocation location) {
  const SourceLocation Loc =
    SourceLocation::getFromRawEncoding(location.int_data);
  if (Loc.isInvalid())
    return 0;

  const SourceManager &SM =
    *static_cast<const SourceManager*>(location.ptr_data[0]);
  return SM.isInSystemHeader(Loc);
}

int clang_Location_isFromMainFile(CXSourceLocation location) {
  const SourceLocation Loc =
    SourceLocation::getFromRawEncoding(location.int_data);
  if (Loc.isInvalid())
    return 0;

  const SourceManager &SM =
    *static_cast<const SourceManager*>(location.ptr_data[0]);
  return SM.isWrittenInMainFile(Loc);
}

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 = const_cast<FileEntry *>(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);
    return;
  }

  const SourceManager &SM =
      *static_cast<const SourceManager *>(location.ptr_data[0]);
  PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
  if (PreLoc.isInvalid()) {
    createNullLocation(filename, line, column);
    return;
  }

  if (filename) *filename = cxstring::createRef(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]);
  // FIXME: This should call SourceManager::getSpellingLoc().
  SourceLocation SpellLoc = SM.getFileLoc(Loc);
  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 = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
  if (line)
    *line = SM.getLineNumber(FID, FileOffset);
  if (column)
    *column = SM.getColumnNumber(FID, FileOffset);
  if (offset)
    *offset = FileOffset;
}

void clang_getFileLocation(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 FileLoc = SM.getFileLoc(Loc);
  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
  FileID FID = LocInfo.first;
  unsigned FileOffset = LocInfo.second;

  if (FID.isInvalid())
    return createNullLocation(file, line, column, offset);

  if (file)
    *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
  if (line)
    *line = SM.getLineNumber(FID, FileOffset);
  if (column)
    *column = SM.getColumnNumber(FID, FileOffset);
  if (offset)
    *offset = FileOffset;
}

} // end extern "C"
@


