1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711
|
//===--- SourceManager.h - Track and cache source files ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines the SourceManager interface.
///
/// There are three different types of locations in a %file: a spelling
/// location, an expansion location, and a presumed location.
///
/// Given an example of:
/// \code
/// #define min(x, y) x < y ? x : y
/// \endcode
///
/// and then later on a use of min:
/// \code
/// #line 17
/// return min(a, b);
/// \endcode
///
/// The expansion location is the line in the source code where the macro
/// was expanded (the return statement), the spelling location is the
/// location in the source where the macro was originally defined,
/// and the presumed location is where the line directive states that
/// the line is 17, or any other line.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_SOURCEMANAGER_H
#define LLVM_CLANG_BASIC_SOURCEMANAGER_H
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cassert>
#include <map>
#include <memory>
#include <vector>
namespace clang {
class DiagnosticsEngine;
class SourceManager;
class FileManager;
class FileEntry;
class LineTableInfo;
class LangOptions;
class ASTWriter;
class ASTReader;
/// \brief Public enums and private classes that are part of the
/// SourceManager implementation.
///
namespace SrcMgr {
/// \brief Indicates whether a file or directory holds normal user code,
/// system code, or system code which is implicitly 'extern "C"' in C++ mode.
///
/// Entire directories can be tagged with this (this is maintained by
/// DirectoryLookup and friends) as can specific FileInfos when a \#pragma
/// system_header is seen or in various other cases.
///
enum CharacteristicKind {
C_User, C_System, C_ExternCSystem
};
/// \brief One instance of this struct is kept for every file loaded or used.
///
/// This object owns the MemoryBuffer object.
class LLVM_ALIGNAS(8) ContentCache {
enum CCFlags {
/// \brief Whether the buffer is invalid.
InvalidFlag = 0x01,
/// \brief Whether the buffer should not be freed on destruction.
DoNotFreeFlag = 0x02
};
/// \brief The actual buffer containing the characters from the input
/// file.
///
/// This is owned by the ContentCache object. The bits indicate
/// whether the buffer is invalid.
mutable llvm::PointerIntPair<llvm::MemoryBuffer *, 2> Buffer;
public:
/// \brief Reference to the file entry representing this ContentCache.
///
/// This reference does not own the FileEntry object.
///
/// It is possible for this to be NULL if the ContentCache encapsulates
/// an imaginary text buffer.
const FileEntry *OrigEntry;
/// \brief References the file which the contents were actually loaded from.
///
/// Can be different from 'Entry' if we overridden the contents of one file
/// with the contents of another file.
const FileEntry *ContentsEntry;
/// \brief A bump pointer allocated array of offsets for each source line.
///
/// This is lazily computed. This is owned by the SourceManager
/// BumpPointerAllocator object.
unsigned *SourceLineCache;
/// \brief The number of lines in this ContentCache.
///
/// This is only valid if SourceLineCache is non-null.
unsigned NumLines;
/// \brief Indicates whether the buffer itself was provided to override
/// the actual file contents.
///
/// When true, the original entry may be a virtual file that does not
/// exist.
unsigned BufferOverridden : 1;
/// \brief True if this content cache was initially created for a source
/// file considered as a system one.
unsigned IsSystemFile : 1;
/// \brief True if this file may be transient, that is, if it might not
/// exist at some later point in time when this content entry is used,
/// after serialization and deserialization.
unsigned IsTransient : 1;
ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {}
ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
: Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt),
SourceLineCache(nullptr), NumLines(0), BufferOverridden(false),
IsSystemFile(false), IsTransient(false) {}
~ContentCache();
/// The copy ctor does not allow copies where source object has either
/// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
/// is not transferred, so this is a logical error.
ContentCache(const ContentCache &RHS)
: Buffer(nullptr, false), SourceLineCache(nullptr),
BufferOverridden(false), IsSystemFile(false), IsTransient(false) {
OrigEntry = RHS.OrigEntry;
ContentsEntry = RHS.ContentsEntry;
assert(RHS.Buffer.getPointer() == nullptr &&
RHS.SourceLineCache == nullptr &&
"Passed ContentCache object cannot own a buffer.");
NumLines = RHS.NumLines;
}
/// \brief Returns the memory buffer for the associated content.
///
/// \param Diag Object through which diagnostics will be emitted if the
/// buffer cannot be retrieved.
///
/// \param Loc If specified, is the location that invalid file diagnostics
/// will be emitted at.
///
/// \param Invalid If non-NULL, will be set \c true if an error occurred.
llvm::MemoryBuffer *getBuffer(DiagnosticsEngine &Diag,
const SourceManager &SM,
SourceLocation Loc = SourceLocation(),
bool *Invalid = nullptr) const;
/// \brief Returns the size of the content encapsulated by this
/// ContentCache.
///
/// This can be the size of the source file or the size of an
/// arbitrary scratch buffer. If the ContentCache encapsulates a source
/// file this size is retrieved from the file's FileEntry.
unsigned getSize() const;
/// \brief Returns the number of bytes actually mapped for this
/// ContentCache.
///
/// This can be 0 if the MemBuffer was not actually expanded.
unsigned getSizeBytesMapped() const;
/// Returns the kind of memory used to back the memory buffer for
/// this content cache. This is used for performance analysis.
llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const;
void setBuffer(std::unique_ptr<llvm::MemoryBuffer> B) {
assert(!Buffer.getPointer() && "MemoryBuffer already set.");
Buffer.setPointer(B.release());
Buffer.setInt(0);
}
/// \brief Get the underlying buffer, returning NULL if the buffer is not
/// yet available.
llvm::MemoryBuffer *getRawBuffer() const { return Buffer.getPointer(); }
/// \brief Replace the existing buffer (which will be deleted)
/// with the given buffer.
void replaceBuffer(llvm::MemoryBuffer *B, bool DoNotFree = false);
/// \brief Determine whether the buffer itself is invalid.
bool isBufferInvalid() const {
return Buffer.getInt() & InvalidFlag;
}
/// \brief Determine whether the buffer should be freed.
bool shouldFreeBuffer() const {
return (Buffer.getInt() & DoNotFreeFlag) == 0;
}
private:
// Disable assignments.
ContentCache &operator=(const ContentCache& RHS) = delete;
};
// Assert that the \c ContentCache objects will always be 8-byte aligned so
// that we can pack 3 bits of integer into pointers to such objects.
static_assert(llvm::AlignOf<ContentCache>::Alignment >= 8,
"ContentCache must be 8-byte aligned.");
/// \brief Information about a FileID, basically just the logical file
/// that it represents and include stack information.
///
/// Each FileInfo has include stack information, indicating where it came
/// from. This information encodes the \#include chain that a token was
/// expanded from. The main include file has an invalid IncludeLoc.
///
/// FileInfos contain a "ContentCache *", with the contents of the file.
///
class FileInfo {
/// \brief The location of the \#include that brought in this file.
///
/// This is an invalid SLOC for the main file (top of the \#include chain).
unsigned IncludeLoc; // Really a SourceLocation
/// \brief Number of FileIDs (files and macros) that were created during
/// preprocessing of this \#include, including this SLocEntry.
///
/// Zero means the preprocessor didn't provide such info for this SLocEntry.
unsigned NumCreatedFIDs;
/// \brief Contains the ContentCache* and the bits indicating the
/// characteristic of the file and whether it has \#line info, all
/// bitmangled together.
uintptr_t Data;
friend class clang::SourceManager;
friend class clang::ASTWriter;
friend class clang::ASTReader;
public:
/// \brief Return a FileInfo object.
static FileInfo get(SourceLocation IL, const ContentCache *Con,
CharacteristicKind FileCharacter) {
FileInfo X;
X.IncludeLoc = IL.getRawEncoding();
X.NumCreatedFIDs = 0;
X.Data = (uintptr_t)Con;
assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned");
assert((unsigned)FileCharacter < 4 && "invalid file character");
X.Data |= (unsigned)FileCharacter;
return X;
}
SourceLocation getIncludeLoc() const {
return SourceLocation::getFromRawEncoding(IncludeLoc);
}
const ContentCache* getContentCache() const {
return reinterpret_cast<const ContentCache*>(Data & ~uintptr_t(7));
}
/// \brief Return whether this is a system header or not.
CharacteristicKind getFileCharacteristic() const {
return (CharacteristicKind)(Data & 3);
}
/// \brief Return true if this FileID has \#line directives in it.
bool hasLineDirectives() const { return (Data & 4) != 0; }
/// \brief Set the flag that indicates that this FileID has
/// line table entries associated with it.
void setHasLineDirectives() {
Data |= 4;
}
};
/// \brief Each ExpansionInfo encodes the expansion location - where
/// the token was ultimately expanded, and the SpellingLoc - where the actual
/// character data for the token came from.
class ExpansionInfo {
// Really these are all SourceLocations.
/// \brief Where the spelling for the token can be found.
unsigned SpellingLoc;
/// In a macro expansion, ExpansionLocStart and ExpansionLocEnd
/// indicate the start and end of the expansion. In object-like macros,
/// they will be the same. In a function-like macro expansion, the start
/// will be the identifier and the end will be the ')'. Finally, in
/// macro-argument instantiations, the end will be 'SourceLocation()', an
/// invalid location.
unsigned ExpansionLocStart, ExpansionLocEnd;
public:
SourceLocation getSpellingLoc() const {
return SourceLocation::getFromRawEncoding(SpellingLoc);
}
SourceLocation getExpansionLocStart() const {
return SourceLocation::getFromRawEncoding(ExpansionLocStart);
}
SourceLocation getExpansionLocEnd() const {
SourceLocation EndLoc =
SourceLocation::getFromRawEncoding(ExpansionLocEnd);
return EndLoc.isInvalid() ? getExpansionLocStart() : EndLoc;
}
std::pair<SourceLocation,SourceLocation> getExpansionLocRange() const {
return std::make_pair(getExpansionLocStart(), getExpansionLocEnd());
}
bool isMacroArgExpansion() const {
// Note that this needs to return false for default constructed objects.
return getExpansionLocStart().isValid() &&
SourceLocation::getFromRawEncoding(ExpansionLocEnd).isInvalid();
}
bool isMacroBodyExpansion() const {
return getExpansionLocStart().isValid() &&
SourceLocation::getFromRawEncoding(ExpansionLocEnd).isValid();
}
bool isFunctionMacroExpansion() const {
return getExpansionLocStart().isValid() &&
getExpansionLocStart() != getExpansionLocEnd();
}
/// \brief Return a ExpansionInfo for an expansion.
///
/// Start and End specify the expansion range (where the macro is
/// expanded), and SpellingLoc specifies the spelling location (where
/// the characters from the token come from). All three can refer to
/// normal File SLocs or expansion locations.
static ExpansionInfo create(SourceLocation SpellingLoc,
SourceLocation Start, SourceLocation End) {
ExpansionInfo X;
X.SpellingLoc = SpellingLoc.getRawEncoding();
X.ExpansionLocStart = Start.getRawEncoding();
X.ExpansionLocEnd = End.getRawEncoding();
return X;
}
/// \brief Return a special ExpansionInfo for the expansion of
/// a macro argument into a function-like macro's body.
///
/// ExpansionLoc specifies the expansion location (where the macro is
/// expanded). This doesn't need to be a range because a macro is always
/// expanded at a macro parameter reference, and macro parameters are
/// always exactly one token. SpellingLoc specifies the spelling location
/// (where the characters from the token come from). ExpansionLoc and
/// SpellingLoc can both refer to normal File SLocs or expansion locations.
///
/// Given the code:
/// \code
/// #define F(x) f(x)
/// F(42);
/// \endcode
///
/// When expanding '\c F(42)', the '\c x' would call this with an
/// SpellingLoc pointing at '\c 42' and an ExpansionLoc pointing at its
/// location in the definition of '\c F'.
static ExpansionInfo createForMacroArg(SourceLocation SpellingLoc,
SourceLocation ExpansionLoc) {
// We store an intentionally invalid source location for the end of the
// expansion range to mark that this is a macro argument ion rather than
// a normal one.
return create(SpellingLoc, ExpansionLoc, SourceLocation());
}
};
/// \brief This is a discriminated union of FileInfo and ExpansionInfo.
///
/// SourceManager keeps an array of these objects, and they are uniquely
/// identified by the FileID datatype.
class SLocEntry {
unsigned Offset : 31;
unsigned IsExpansion : 1;
union {
FileInfo File;
ExpansionInfo Expansion;
};
public:
unsigned getOffset() const { return Offset; }
bool isExpansion() const { return IsExpansion; }
bool isFile() const { return !isExpansion(); }
const FileInfo &getFile() const {
assert(isFile() && "Not a file SLocEntry!");
return File;
}
const ExpansionInfo &getExpansion() const {
assert(isExpansion() && "Not a macro expansion SLocEntry!");
return Expansion;
}
static SLocEntry get(unsigned Offset, const FileInfo &FI) {
assert(!(Offset & (1 << 31)) && "Offset is too large");
SLocEntry E;
E.Offset = Offset;
E.IsExpansion = false;
E.File = FI;
return E;
}
static SLocEntry get(unsigned Offset, const ExpansionInfo &Expansion) {
assert(!(Offset & (1 << 31)) && "Offset is too large");
SLocEntry E;
E.Offset = Offset;
E.IsExpansion = true;
E.Expansion = Expansion;
return E;
}
};
} // end SrcMgr namespace.
/// \brief External source of source location entries.
class ExternalSLocEntrySource {
public:
virtual ~ExternalSLocEntrySource();
/// \brief Read the source location entry with index ID, which will always be
/// less than -1.
///
/// \returns true if an error occurred that prevented the source-location
/// entry from being loaded.
virtual bool ReadSLocEntry(int ID) = 0;
/// \brief Retrieve the module import location and name for the given ID, if
/// in fact it was loaded from a module (rather than, say, a precompiled
/// header).
virtual std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) = 0;
};
/// \brief Holds the cache used by isBeforeInTranslationUnit.
///
/// The cache structure is complex enough to be worth breaking out of
/// SourceManager.
class InBeforeInTUCacheEntry {
/// \brief The FileID's of the cached query.
///
/// If these match up with a subsequent query, the result can be reused.
FileID LQueryFID, RQueryFID;
/// \brief True if LQueryFID was created before RQueryFID.
///
/// This is used to compare macro expansion locations.
bool IsLQFIDBeforeRQFID;
/// \brief The file found in common between the two \#include traces, i.e.,
/// the nearest common ancestor of the \#include tree.
FileID CommonFID;
/// \brief The offset of the previous query in CommonFID.
///
/// Usually, this represents the location of the \#include for QueryFID, but
/// if LQueryFID is a parent of RQueryFID (or vice versa) then these can be a
/// random token in the parent.
unsigned LCommonOffset, RCommonOffset;
public:
/// \brief Return true if the currently cached values match up with
/// the specified LHS/RHS query.
///
/// If not, we can't use the cache.
bool isCacheValid(FileID LHS, FileID RHS) const {
return LQueryFID == LHS && RQueryFID == RHS;
}
/// \brief If the cache is valid, compute the result given the
/// specified offsets in the LHS/RHS FileID's.
bool getCachedResult(unsigned LOffset, unsigned ROffset) const {
// If one of the query files is the common file, use the offset. Otherwise,
// use the #include loc in the common file.
if (LQueryFID != CommonFID) LOffset = LCommonOffset;
if (RQueryFID != CommonFID) ROffset = RCommonOffset;
// It is common for multiple macro expansions to be "included" from the same
// location (expansion location), in which case use the order of the FileIDs
// to determine which came first. This will also take care the case where
// one of the locations points at the inclusion/expansion point of the other
// in which case its FileID will come before the other.
if (LOffset == ROffset)
return IsLQFIDBeforeRQFID;
return LOffset < ROffset;
}
/// \brief Set up a new query.
void setQueryFIDs(FileID LHS, FileID RHS, bool isLFIDBeforeRFID) {
assert(LHS != RHS);
LQueryFID = LHS;
RQueryFID = RHS;
IsLQFIDBeforeRQFID = isLFIDBeforeRFID;
}
void clear() {
LQueryFID = RQueryFID = FileID();
IsLQFIDBeforeRQFID = false;
}
void setCommonLoc(FileID commonFID, unsigned lCommonOffset,
unsigned rCommonOffset) {
CommonFID = commonFID;
LCommonOffset = lCommonOffset;
RCommonOffset = rCommonOffset;
}
};
/// \brief The stack used when building modules on demand, which is used
/// to provide a link between the source managers of the different compiler
/// instances.
typedef ArrayRef<std::pair<std::string, FullSourceLoc> > ModuleBuildStack;
/// \brief This class handles loading and caching of source files into memory.
///
/// This object owns the MemoryBuffer objects for all of the loaded
/// files and assigns unique FileID's for each unique \#include chain.
///
/// The SourceManager can be queried for information about SourceLocation
/// objects, turning them into either spelling or expansion locations. Spelling
/// locations represent where the bytes corresponding to a token came from and
/// expansion locations represent where the location is in the user's view. In
/// the case of a macro expansion, for example, the spelling location indicates
/// where the expanded token came from and the expansion location specifies
/// where it was expanded.
class SourceManager : public RefCountedBase<SourceManager> {
/// \brief DiagnosticsEngine object.
DiagnosticsEngine &Diag;
FileManager &FileMgr;
mutable llvm::BumpPtrAllocator ContentCacheAlloc;
/// \brief Memoized information about all of the files tracked by this
/// SourceManager.
///
/// This map allows us to merge ContentCache entries based
/// on their FileEntry*. All ContentCache objects will thus have unique,
/// non-null, FileEntry pointers.
llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos;
/// \brief True if the ContentCache for files that are overridden by other
/// files, should report the original file name. Defaults to true.
bool OverridenFilesKeepOriginalName;
/// \brief True if non-system source files should be treated as volatile
/// (likely to change while trying to use them). Defaults to false.
bool UserFilesAreVolatile;
/// \brief True if all files read during this compilation should be treated
/// as transient (may not be present in later compilations using a module
/// file created from this compilation). Defaults to false.
bool FilesAreTransient;
struct OverriddenFilesInfoTy {
/// \brief Files that have been overridden with the contents from another
/// file.
llvm::DenseMap<const FileEntry *, const FileEntry *> OverriddenFiles;
/// \brief Files that were overridden with a memory buffer.
llvm::DenseSet<const FileEntry *> OverriddenFilesWithBuffer;
};
/// \brief Lazily create the object keeping overridden files info, since
/// it is uncommonly used.
std::unique_ptr<OverriddenFilesInfoTy> OverriddenFilesInfo;
OverriddenFilesInfoTy &getOverriddenFilesInfo() {
if (!OverriddenFilesInfo)
OverriddenFilesInfo.reset(new OverriddenFilesInfoTy);
return *OverriddenFilesInfo;
}
/// \brief Information about various memory buffers that we have read in.
///
/// All FileEntry* within the stored ContentCache objects are NULL,
/// as they do not refer to a file.
std::vector<SrcMgr::ContentCache*> MemBufferInfos;
/// \brief The table of SLocEntries that are local to this module.
///
/// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid
/// expansion.
SmallVector<SrcMgr::SLocEntry, 0> LocalSLocEntryTable;
/// \brief The table of SLocEntries that are loaded from other modules.
///
/// Negative FileIDs are indexes into this table. To get from ID to an index,
/// use (-ID - 2).
mutable SmallVector<SrcMgr::SLocEntry, 0> LoadedSLocEntryTable;
/// \brief The starting offset of the next local SLocEntry.
///
/// This is LocalSLocEntryTable.back().Offset + the size of that entry.
unsigned NextLocalOffset;
/// \brief The starting offset of the latest batch of loaded SLocEntries.
///
/// This is LoadedSLocEntryTable.back().Offset, except that that entry might
/// not have been loaded, so that value would be unknown.
unsigned CurrentLoadedOffset;
/// \brief The highest possible offset is 2^31-1, so CurrentLoadedOffset
/// starts at 2^31.
static const unsigned MaxLoadedOffset = 1U << 31U;
/// \brief A bitmap that indicates whether the entries of LoadedSLocEntryTable
/// have already been loaded from the external source.
///
/// Same indexing as LoadedSLocEntryTable.
llvm::BitVector SLocEntryLoaded;
/// \brief An external source for source location entries.
ExternalSLocEntrySource *ExternalSLocEntries;
/// \brief A one-entry cache to speed up getFileID.
///
/// LastFileIDLookup records the last FileID looked up or created, because it
/// is very common to look up many tokens from the same file.
mutable FileID LastFileIDLookup;
/// \brief Holds information for \#line directives.
///
/// This is referenced by indices from SLocEntryTable.
LineTableInfo *LineTable;
/// \brief These ivars serve as a cache used in the getLineNumber
/// method which is used to speedup getLineNumber calls to nearby locations.
mutable FileID LastLineNoFileIDQuery;
mutable SrcMgr::ContentCache *LastLineNoContentCache;
mutable unsigned LastLineNoFilePos;
mutable unsigned LastLineNoResult;
/// \brief The file ID for the main source file of the translation unit.
FileID MainFileID;
/// \brief The file ID for the precompiled preamble there is one.
FileID PreambleFileID;
// Statistics for -print-stats.
mutable unsigned NumLinearScans, NumBinaryProbes;
/// \brief Associates a FileID with its "included/expanded in" decomposed
/// location.
///
/// Used to cache results from and speed-up \c getDecomposedIncludedLoc
/// function.
mutable llvm::DenseMap<FileID, std::pair<FileID, unsigned> > IncludedLocMap;
/// The key value into the IsBeforeInTUCache table.
typedef std::pair<FileID, FileID> IsBeforeInTUCacheKey;
/// The IsBeforeInTranslationUnitCache is a mapping from FileID pairs
/// to cache results.
typedef llvm::DenseMap<IsBeforeInTUCacheKey, InBeforeInTUCacheEntry>
InBeforeInTUCache;
/// Cache results for the isBeforeInTranslationUnit method.
mutable InBeforeInTUCache IBTUCache;
mutable InBeforeInTUCacheEntry IBTUCacheOverflow;
/// Return the cache entry for comparing the given file IDs
/// for isBeforeInTranslationUnit.
InBeforeInTUCacheEntry &getInBeforeInTUCache(FileID LFID, FileID RFID) const;
// Cache for the "fake" buffer used for error-recovery purposes.
mutable std::unique_ptr<llvm::MemoryBuffer> FakeBufferForRecovery;
mutable std::unique_ptr<SrcMgr::ContentCache> FakeContentCacheForRecovery;
/// \brief Lazily computed map of macro argument chunks to their expanded
/// source location.
typedef std::map<unsigned, SourceLocation> MacroArgsMap;
mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap;
/// \brief The stack of modules being built, which is used to detect
/// cycles in the module dependency graph as modules are being built, as
/// well as to describe why we're rebuilding a particular module.
///
/// There is no way to set this value from the command line. If we ever need
/// to do so (e.g., if on-demand module construction moves out-of-process),
/// we can add a cc1-level option to do so.
SmallVector<std::pair<std::string, FullSourceLoc>, 2> StoredModuleBuildStack;
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&) = delete;
void operator=(const SourceManager&) = delete;
public:
SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr,
bool UserFilesAreVolatile = false);
~SourceManager();
void clearIDTables();
DiagnosticsEngine &getDiagnostics() const { return Diag; }
FileManager &getFileManager() const { return FileMgr; }
/// \brief Set true if the SourceManager should report the original file name
/// for contents of files that were overridden by other files. Defaults to
/// true.
void setOverridenFilesKeepOriginalName(bool value) {
OverridenFilesKeepOriginalName = value;
}
/// \brief True if non-system source files should be treated as volatile
/// (likely to change while trying to use them).
bool userFilesAreVolatile() const { return UserFilesAreVolatile; }
/// \brief Retrieve the module build stack.
ModuleBuildStack getModuleBuildStack() const {
return StoredModuleBuildStack;
}
/// \brief Set the module build stack.
void setModuleBuildStack(ModuleBuildStack stack) {
StoredModuleBuildStack.clear();
StoredModuleBuildStack.append(stack.begin(), stack.end());
}
/// \brief Push an entry to the module build stack.
void pushModuleBuildStack(StringRef moduleName, FullSourceLoc importLoc) {
StoredModuleBuildStack.push_back(std::make_pair(moduleName.str(),importLoc));
}
//===--------------------------------------------------------------------===//
// MainFileID creation and querying methods.
//===--------------------------------------------------------------------===//
/// \brief Returns the FileID of the main source file.
FileID getMainFileID() const { return MainFileID; }
/// \brief Set the file ID for the main source file.
void setMainFileID(FileID FID) {
MainFileID = FID;
}
/// \brief Set the file ID for the precompiled preamble.
void setPreambleFileID(FileID Preamble) {
assert(PreambleFileID.isInvalid() && "PreambleFileID already set!");
PreambleFileID = Preamble;
}
/// \brief Get the file ID for the precompiled preamble if there is one.
FileID getPreambleFileID() const { return PreambleFileID; }
//===--------------------------------------------------------------------===//
// Methods to create new FileID's and macro expansions.
//===--------------------------------------------------------------------===//
/// \brief Create a new FileID that represents the specified file
/// being \#included from the specified IncludePosition.
///
/// This translates NULL into standard input.
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
int LoadedID = 0, unsigned LoadedOffset = 0) {
const SrcMgr::ContentCache *
IR = getOrCreateContentCache(SourceFile,
/*isSystemFile=*/FileCharacter != SrcMgr::C_User);
assert(IR && "getOrCreateContentCache() cannot return NULL");
return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
}
/// \brief Create a new FileID that represents the specified memory buffer.
///
/// This does no caching of the buffer and takes ownership of the
/// MemoryBuffer, so only pass a MemoryBuffer to this once.
FileID createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer,
SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
int LoadedID = 0, unsigned LoadedOffset = 0,
SourceLocation IncludeLoc = SourceLocation()) {
return createFileID(createMemBufferContentCache(std::move(Buffer)),
IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
}
/// \brief Return a new SourceLocation that encodes the
/// fact that a token from SpellingLoc should actually be referenced from
/// ExpansionLoc, and that it represents the expansion of a macro argument
/// into the function-like macro body.
SourceLocation createMacroArgExpansionLoc(SourceLocation Loc,
SourceLocation ExpansionLoc,
unsigned TokLength);
/// \brief Return a new SourceLocation that encodes the fact
/// that a token from SpellingLoc should actually be referenced from
/// ExpansionLoc.
SourceLocation createExpansionLoc(SourceLocation Loc,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd,
unsigned TokLength,
int LoadedID = 0,
unsigned LoadedOffset = 0);
/// \brief Retrieve the memory buffer associated with the given file.
///
/// \param Invalid If non-NULL, will be set \c true if an error
/// occurs while retrieving the memory buffer.
llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File,
bool *Invalid = nullptr);
/// \brief Override the contents of the given source file by providing an
/// already-allocated buffer.
///
/// \param SourceFile the source file whose contents will be overridden.
///
/// \param Buffer the memory buffer whose contents will be used as the
/// data in the given source file.
///
/// \param DoNotFree If true, then the buffer will not be freed when the
/// source manager is destroyed.
void overrideFileContents(const FileEntry *SourceFile,
llvm::MemoryBuffer *Buffer, bool DoNotFree);
void overrideFileContents(const FileEntry *SourceFile,
std::unique_ptr<llvm::MemoryBuffer> Buffer) {
overrideFileContents(SourceFile, Buffer.release(), /*DoNotFree*/ false);
}
/// \brief Override the given source file with another one.
///
/// \param SourceFile the source file which will be overridden.
///
/// \param NewFile the file whose contents will be used as the
/// data instead of the contents of the given source file.
void overrideFileContents(const FileEntry *SourceFile,
const FileEntry *NewFile);
/// \brief Returns true if the file contents have been overridden.
bool isFileOverridden(const FileEntry *File) {
if (OverriddenFilesInfo) {
if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File))
return true;
if (OverriddenFilesInfo->OverriddenFiles.find(File) !=
OverriddenFilesInfo->OverriddenFiles.end())
return true;
}
return false;
}
/// \brief Disable overridding the contents of a file, previously enabled
/// with #overrideFileContents.
///
/// This should be called before parsing has begun.
void disableFileContentsOverride(const FileEntry *File);
/// \brief Specify that a file is transient.
void setFileIsTransient(const FileEntry *SourceFile);
/// \brief Specify that all files that are read during this compilation are
/// transient.
void setAllFilesAreTransient(bool Transient) {
FilesAreTransient = Transient;
}
//===--------------------------------------------------------------------===//
// FileID manipulation methods.
//===--------------------------------------------------------------------===//
/// \brief Return the buffer for the specified FileID.
///
/// If there is an error opening this buffer the first time, this
/// manufactures a temporary buffer and returns a non-empty error string.
llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc,
bool *Invalid = nullptr) const {
bool MyInvalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
if (MyInvalid || !Entry.isFile()) {
if (Invalid)
*Invalid = true;
return getFakeBufferForRecovery();
}
return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc,
Invalid);
}
llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = nullptr) const {
bool MyInvalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
if (MyInvalid || !Entry.isFile()) {
if (Invalid)
*Invalid = true;
return getFakeBufferForRecovery();
}
return Entry.getFile().getContentCache()->getBuffer(Diag, *this,
SourceLocation(),
Invalid);
}
/// \brief Returns the FileEntry record for the provided FileID.
const FileEntry *getFileEntryForID(FileID FID) const {
bool MyInvalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
if (MyInvalid || !Entry.isFile())
return nullptr;
const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache();
if (!Content)
return nullptr;
return Content->OrigEntry;
}
/// \brief Returns the FileEntry record for the provided SLocEntry.
const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const
{
const SrcMgr::ContentCache *Content = sloc.getFile().getContentCache();
if (!Content)
return nullptr;
return Content->OrigEntry;
}
/// \brief Return a StringRef to the source buffer data for the
/// specified FileID.
///
/// \param FID The file ID whose contents will be returned.
/// \param Invalid If non-NULL, will be set true if an error occurred.
StringRef getBufferData(FileID FID, bool *Invalid = nullptr) const;
/// \brief Get the number of FileIDs (files and macros) that were created
/// during preprocessing of \p FID, including it.
unsigned getNumCreatedFIDsForFileID(FileID FID) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid || !Entry.isFile())
return 0;
return Entry.getFile().NumCreatedFIDs;
}
/// \brief Set the number of FileIDs (files and macros) that were created
/// during preprocessing of \p FID, including it.
void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid || !Entry.isFile())
return;
assert(Entry.getFile().NumCreatedFIDs == 0 && "Already set!");
const_cast<SrcMgr::FileInfo &>(Entry.getFile()).NumCreatedFIDs = NumFIDs;
}
//===--------------------------------------------------------------------===//
// SourceLocation manipulation methods.
//===--------------------------------------------------------------------===//
/// \brief Return the FileID for a SourceLocation.
///
/// This is a very hot method that is used for all SourceManager queries
/// that start with a SourceLocation object. It is responsible for finding
/// the entry in SLocEntryTable which contains the specified location.
///
FileID getFileID(SourceLocation SpellingLoc) const {
unsigned SLocOffset = SpellingLoc.getOffset();
// If our one-entry cache covers this offset, just return it.
if (isOffsetInFileID(LastFileIDLookup, SLocOffset))
return LastFileIDLookup;
return getFileIDSlow(SLocOffset);
}
/// \brief Return the filename of the file containing a SourceLocation.
StringRef getFilename(SourceLocation SpellingLoc) const {
if (const FileEntry *F = getFileEntryForID(getFileID(SpellingLoc)))
return F->getName();
return StringRef();
}
/// \brief Return the source location corresponding to the first byte of
/// the specified file.
SourceLocation getLocForStartOfFile(FileID FID) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid || !Entry.isFile())
return SourceLocation();
unsigned FileOffset = Entry.getOffset();
return SourceLocation::getFileLoc(FileOffset);
}
/// \brief Return the source location corresponding to the last byte of the
/// specified file.
SourceLocation getLocForEndOfFile(FileID FID) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid || !Entry.isFile())
return SourceLocation();
unsigned FileOffset = Entry.getOffset();
return SourceLocation::getFileLoc(FileOffset + getFileIDSize(FID));
}
/// \brief Returns the include location if \p FID is a \#include'd file
/// otherwise it returns an invalid location.
SourceLocation getIncludeLoc(FileID FID) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid || !Entry.isFile())
return SourceLocation();
return Entry.getFile().getIncludeLoc();
}
// \brief Returns the import location if the given source location is
// located within a module, or an invalid location if the source location
// is within the current translation unit.
std::pair<SourceLocation, StringRef>
getModuleImportLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
// Positive file IDs are in the current translation unit, and -1 is a
// placeholder.
if (FID.ID >= -1)
return std::make_pair(SourceLocation(), "");
return ExternalSLocEntries->getModuleImportLoc(FID.ID);
}
/// \brief Given a SourceLocation object \p Loc, return the expansion
/// location referenced by the ID.
SourceLocation getExpansionLoc(SourceLocation Loc) const {
// Handle the non-mapped case inline, defer to out of line code to handle
// expansions.
if (Loc.isFileID()) return Loc;
return getExpansionLocSlowCase(Loc);
}
/// \brief Given \p Loc, if it is a macro location return the expansion
/// location or the spelling location, depending on if it comes from a
/// macro argument or not.
SourceLocation getFileLoc(SourceLocation Loc) const {
if (Loc.isFileID()) return Loc;
return getFileLocSlowCase(Loc);
}
/// \brief Return the start/end of the expansion information for an
/// expansion location.
///
/// \pre \p Loc is required to be an expansion location.
std::pair<SourceLocation,SourceLocation>
getImmediateExpansionRange(SourceLocation Loc) const;
/// \brief Given a SourceLocation object, return the range of
/// tokens covered by the expansion in the ultimate file.
std::pair<SourceLocation,SourceLocation>
getExpansionRange(SourceLocation Loc) const;
/// \brief Given a SourceRange object, return the range of
/// tokens covered by the expansion in the ultimate file.
SourceRange getExpansionRange(SourceRange Range) const {
return SourceRange(getExpansionRange(Range.getBegin()).first,
getExpansionRange(Range.getEnd()).second);
}
/// \brief Given a SourceLocation object, return the spelling
/// location referenced by the ID.
///
/// This is the place where the characters that make up the lexed token
/// can be found.
SourceLocation getSpellingLoc(SourceLocation Loc) const {
// Handle the non-mapped case inline, defer to out of line code to handle
// expansions.
if (Loc.isFileID()) return Loc;
return getSpellingLocSlowCase(Loc);
}
/// \brief Given a SourceLocation object, return the spelling location
/// referenced by the ID.
///
/// This is the first level down towards the place where the characters
/// that make up the lexed token can be found. This should not generally
/// be used by clients.
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const;
/// \brief Decompose the specified location into a raw FileID + Offset pair.
///
/// The first element is the FileID, the second is the offset from the
/// start of the buffer of the location.
std::pair<FileID, unsigned> getDecomposedLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
bool Invalid = false;
const SrcMgr::SLocEntry &E = getSLocEntry(FID, &Invalid);
if (Invalid)
return std::make_pair(FileID(), 0);
return std::make_pair(FID, Loc.getOffset()-E.getOffset());
}
/// \brief Decompose the specified location into a raw FileID + Offset pair.
///
/// If the location is an expansion record, walk through it until we find
/// the final location expanded.
std::pair<FileID, unsigned>
getDecomposedExpansionLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
bool Invalid = false;
const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid);
if (Invalid)
return std::make_pair(FileID(), 0);
unsigned Offset = Loc.getOffset()-E->getOffset();
if (Loc.isFileID())
return std::make_pair(FID, Offset);
return getDecomposedExpansionLocSlowCase(E);
}
/// \brief Decompose the specified location into a raw FileID + Offset pair.
///
/// If the location is an expansion record, walk through it until we find
/// its spelling record.
std::pair<FileID, unsigned>
getDecomposedSpellingLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
bool Invalid = false;
const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid);
if (Invalid)
return std::make_pair(FileID(), 0);
unsigned Offset = Loc.getOffset()-E->getOffset();
if (Loc.isFileID())
return std::make_pair(FID, Offset);
return getDecomposedSpellingLocSlowCase(E, Offset);
}
/// \brief Returns the "included/expanded in" decomposed location of the given
/// FileID.
std::pair<FileID, unsigned> getDecomposedIncludedLoc(FileID FID) const;
/// \brief Returns the offset from the start of the file that the
/// specified SourceLocation represents.
///
/// This is not very meaningful for a macro ID.
unsigned getFileOffset(SourceLocation SpellingLoc) const {
return getDecomposedLoc(SpellingLoc).second;
}
/// \brief Tests whether the given source location represents a macro
/// argument's expansion into the function-like macro definition.
///
/// \param StartLoc If non-null and function returns true, it is set to the
/// start location of the macro argument expansion.
///
/// Such source locations only appear inside of the expansion
/// locations representing where a particular function-like macro was
/// expanded.
bool isMacroArgExpansion(SourceLocation Loc,
SourceLocation *StartLoc = nullptr) const;
/// \brief Tests whether the given source location represents the expansion of
/// a macro body.
///
/// This is equivalent to testing whether the location is part of a macro
/// expansion but not the expansion of an argument to a function-like macro.
bool isMacroBodyExpansion(SourceLocation Loc) const;
/// \brief Returns true if the given MacroID location points at the beginning
/// of the immediate macro expansion.
///
/// \param MacroBegin If non-null and function returns true, it is set to the
/// begin location of the immediate macro expansion.
bool isAtStartOfImmediateMacroExpansion(SourceLocation Loc,
SourceLocation *MacroBegin = nullptr) const;
/// \brief Returns true if the given MacroID location points at the character
/// end of the immediate macro expansion.
///
/// \param MacroEnd If non-null and function returns true, it is set to the
/// character end location of the immediate macro expansion.
bool
isAtEndOfImmediateMacroExpansion(SourceLocation Loc,
SourceLocation *MacroEnd = nullptr) const;
/// \brief Returns true if \p Loc is inside the [\p Start, +\p Length)
/// chunk of the source location address space.
///
/// If it's true and \p RelativeOffset is non-null, it will be set to the
/// relative offset of \p Loc inside the chunk.
bool isInSLocAddrSpace(SourceLocation Loc,
SourceLocation Start, unsigned Length,
unsigned *RelativeOffset = nullptr) const {
assert(((Start.getOffset() < NextLocalOffset &&
Start.getOffset()+Length <= NextLocalOffset) ||
(Start.getOffset() >= CurrentLoadedOffset &&
Start.getOffset()+Length < MaxLoadedOffset)) &&
"Chunk is not valid SLoc address space");
unsigned LocOffs = Loc.getOffset();
unsigned BeginOffs = Start.getOffset();
unsigned EndOffs = BeginOffs + Length;
if (LocOffs >= BeginOffs && LocOffs < EndOffs) {
if (RelativeOffset)
*RelativeOffset = LocOffs - BeginOffs;
return true;
}
return false;
}
/// \brief Return true if both \p LHS and \p RHS are in the local source
/// location address space or the loaded one.
///
/// If it's true and \p RelativeOffset is non-null, it will be set to the
/// offset of \p RHS relative to \p LHS.
bool isInSameSLocAddrSpace(SourceLocation LHS, SourceLocation RHS,
int *RelativeOffset) const {
unsigned LHSOffs = LHS.getOffset(), RHSOffs = RHS.getOffset();
bool LHSLoaded = LHSOffs >= CurrentLoadedOffset;
bool RHSLoaded = RHSOffs >= CurrentLoadedOffset;
if (LHSLoaded == RHSLoaded) {
if (RelativeOffset)
*RelativeOffset = RHSOffs - LHSOffs;
return true;
}
return false;
}
//===--------------------------------------------------------------------===//
// Queries about the code at a SourceLocation.
//===--------------------------------------------------------------------===//
/// \brief Return a pointer to the start of the specified location
/// in the appropriate spelling MemoryBuffer.
///
/// \param Invalid If non-NULL, will be set \c true if an error occurs.
const char *getCharacterData(SourceLocation SL,
bool *Invalid = nullptr) const;
/// \brief Return the column # for the specified file position.
///
/// This is significantly cheaper to compute than the line number. This
/// returns zero if the column number isn't known. This may only be called
/// on a file sloc, so you must choose a spelling or expansion location
/// before calling this method.
unsigned getColumnNumber(FileID FID, unsigned FilePos,
bool *Invalid = nullptr) const;
unsigned getSpellingColumnNumber(SourceLocation Loc,
bool *Invalid = nullptr) const;
unsigned getExpansionColumnNumber(SourceLocation Loc,
bool *Invalid = nullptr) const;
unsigned getPresumedColumnNumber(SourceLocation Loc,
bool *Invalid = nullptr) const;
/// \brief Given a SourceLocation, return the spelling line number
/// for the position indicated.
///
/// This requires building and caching a table of line offsets for the
/// MemoryBuffer, so this is not cheap: use only when about to emit a
/// diagnostic.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = nullptr) const;
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const;
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const;
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const;
/// \brief Return the filename or buffer identifier of the buffer the
/// location is in.
///
/// Note that this name does not respect \#line directives. Use
/// getPresumedLoc for normal clients.
const char *getBufferName(SourceLocation Loc, bool *Invalid = nullptr) const;
/// \brief Return the file characteristic of the specified source
/// location, indicating whether this is a normal file, a system
/// header, or an "implicit extern C" system header.
///
/// This state can be modified with flags on GNU linemarker directives like:
/// \code
/// # 4 "foo.h" 3
/// \endcode
/// which changes all source locations in the current file after that to be
/// considered to be from a system header.
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const;
/// \brief Returns the "presumed" location of a SourceLocation specifies.
///
/// A "presumed location" can be modified by \#line or GNU line marker
/// directives. This provides a view on the data that a user should see
/// in diagnostics, for example.
///
/// Note that a presumed location is always given as the expansion point of
/// an expansion location, not at the spelling location.
///
/// \returns The presumed location of the specified SourceLocation. If the
/// presumed location cannot be calculated (e.g., because \p Loc is invalid
/// or the file containing \p Loc has changed on disk), returns an invalid
/// presumed location.
PresumedLoc getPresumedLoc(SourceLocation Loc,
bool UseLineDirectives = true) const;
/// \brief Returns whether the PresumedLoc for a given SourceLocation is
/// in the main file.
///
/// This computes the "presumed" location for a SourceLocation, then checks
/// whether it came from a file other than the main file. This is different
/// from isWrittenInMainFile() because it takes line marker directives into
/// account.
bool isInMainFile(SourceLocation Loc) const;
/// \brief Returns true if the spelling locations for both SourceLocations
/// are part of the same file buffer.
///
/// This check ignores line marker directives.
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const {
return getFileID(Loc1) == getFileID(Loc2);
}
/// \brief Returns true if the spelling location for the given location
/// is in the main file buffer.
///
/// This check ignores line marker directives.
bool isWrittenInMainFile(SourceLocation Loc) const {
return getFileID(Loc) == getMainFileID();
}
/// \brief Returns if a SourceLocation is in a system header.
bool isInSystemHeader(SourceLocation Loc) const {
return getFileCharacteristic(Loc) != SrcMgr::C_User;
}
/// \brief Returns if a SourceLocation is in an "extern C" system header.
bool isInExternCSystemHeader(SourceLocation Loc) const {
return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem;
}
/// \brief Returns whether \p Loc is expanded from a macro in a system header.
bool isInSystemMacro(SourceLocation loc) {
return loc.isMacroID() && isInSystemHeader(getSpellingLoc(loc));
}
/// \brief The size of the SLocEntry that \p FID represents.
unsigned getFileIDSize(FileID FID) const;
/// \brief Given a specific FileID, returns true if \p Loc is inside that
/// FileID chunk and sets relative offset (offset of \p Loc from beginning
/// of FileID) to \p relativeOffset.
bool isInFileID(SourceLocation Loc, FileID FID,
unsigned *RelativeOffset = nullptr) const {
unsigned Offs = Loc.getOffset();
if (isOffsetInFileID(FID, Offs)) {
if (RelativeOffset)
*RelativeOffset = Offs - getSLocEntry(FID).getOffset();
return true;
}
return false;
}
//===--------------------------------------------------------------------===//
// Line Table Manipulation Routines
//===--------------------------------------------------------------------===//
/// \brief Return the uniqued ID for the specified filename.
///
unsigned getLineTableFilenameID(StringRef Str);
/// \brief Add a line note to the line table for the FileID and offset
/// specified by Loc.
///
/// If FilenameID is -1, it is considered to be unspecified.
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID);
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID,
bool IsFileEntry, bool IsFileExit,
bool IsSystemHeader, bool IsExternCHeader);
/// \brief Determine if the source manager has a line table.
bool hasLineTable() const { return LineTable != nullptr; }
/// \brief Retrieve the stored line table.
LineTableInfo &getLineTable();
//===--------------------------------------------------------------------===//
// Queries for performance analysis.
//===--------------------------------------------------------------------===//
/// \brief Return the total amount of physical memory allocated by the
/// ContentCache allocator.
size_t getContentCacheSize() const {
return ContentCacheAlloc.getTotalMemory();
}
struct MemoryBufferSizes {
const size_t malloc_bytes;
const size_t mmap_bytes;
MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
: malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
};
/// \brief Return the amount of memory used by memory buffers, breaking down
/// by heap-backed versus mmap'ed memory.
MemoryBufferSizes getMemoryBufferSizes() const;
/// \brief Return the amount of memory used for various side tables and
/// data structures in the SourceManager.
size_t getDataStructureSizes() const;
//===--------------------------------------------------------------------===//
// Other miscellaneous methods.
//===--------------------------------------------------------------------===//
/// \brief Get the source location for the given file:line:col triplet.
///
/// If the source file is included multiple times, the source location will
/// be based upon the first inclusion.
SourceLocation translateFileLineCol(const FileEntry *SourceFile,
unsigned Line, unsigned Col) const;
/// \brief Get the FileID for the given file.
///
/// If the source file is included multiple times, the FileID will be the
/// first inclusion.
FileID translateFile(const FileEntry *SourceFile) const;
/// \brief Get the source location in \p FID for the given line:col.
/// Returns null location if \p FID is not a file SLocEntry.
SourceLocation translateLineCol(FileID FID,
unsigned Line, unsigned Col) const;
/// \brief If \p Loc points inside a function macro argument, the returned
/// location will be the macro location in which the argument was expanded.
/// If a macro argument is used multiple times, the expanded location will
/// be at the first expansion of the argument.
/// e.g.
/// MY_MACRO(foo);
/// ^
/// Passing a file location pointing at 'foo', will yield a macro location
/// where 'foo' was expanded into.
SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const;
/// \brief Determines the order of 2 source locations in the translation unit.
///
/// \returns true if LHS source location comes before RHS, false otherwise.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
/// \brief Determines the order of 2 source locations in the "source location
/// address space".
bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const {
return isBeforeInSLocAddrSpace(LHS, RHS.getOffset());
}
/// \brief Determines the order of a source location and a source location
/// offset in the "source location address space".
///
/// Note that we always consider source locations loaded from
bool isBeforeInSLocAddrSpace(SourceLocation LHS, unsigned RHS) const {
unsigned LHSOffset = LHS.getOffset();
bool LHSLoaded = LHSOffset >= CurrentLoadedOffset;
bool RHSLoaded = RHS >= CurrentLoadedOffset;
if (LHSLoaded == RHSLoaded)
return LHSOffset < RHS;
return LHSLoaded;
}
// Iterators over FileInfos.
typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>
::const_iterator fileinfo_iterator;
fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); }
fileinfo_iterator fileinfo_end() const { return FileInfos.end(); }
bool hasFileInfo(const FileEntry *File) const {
return FileInfos.find(File) != FileInfos.end();
}
/// \brief Print statistics to stderr.
///
void PrintStats() const;
void dump() const;
/// \brief Get the number of local SLocEntries we have.
unsigned local_sloc_entry_size() const { return LocalSLocEntryTable.size(); }
/// \brief Get a local SLocEntry. This is exposed for indexing.
const SrcMgr::SLocEntry &getLocalSLocEntry(unsigned Index,
bool *Invalid = nullptr) const {
assert(Index < LocalSLocEntryTable.size() && "Invalid index");
return LocalSLocEntryTable[Index];
}
/// \brief Get the number of loaded SLocEntries we have.
unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();}
/// \brief Get a loaded SLocEntry. This is exposed for indexing.
const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index,
bool *Invalid = nullptr) const {
assert(Index < LoadedSLocEntryTable.size() && "Invalid index");
if (SLocEntryLoaded[Index])
return LoadedSLocEntryTable[Index];
return loadSLocEntry(Index, Invalid);
}
const SrcMgr::SLocEntry &getSLocEntry(FileID FID,
bool *Invalid = nullptr) const {
if (FID.ID == 0 || FID.ID == -1) {
if (Invalid) *Invalid = true;
return LocalSLocEntryTable[0];
}
return getSLocEntryByID(FID.ID, Invalid);
}
unsigned getNextLocalOffset() const { return NextLocalOffset; }
void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) {
assert(LoadedSLocEntryTable.empty() &&
"Invalidating existing loaded entries");
ExternalSLocEntries = Source;
}
/// \brief Allocate a number of loaded SLocEntries, which will be actually
/// loaded on demand from the external source.
///
/// NumSLocEntries will be allocated, which occupy a total of TotalSize space
/// in the global source view. The lowest ID and the base offset of the
/// entries will be returned.
std::pair<int, unsigned>
AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize);
/// \brief Returns true if \p Loc came from a PCH/Module.
bool isLoadedSourceLocation(SourceLocation Loc) const {
return Loc.getOffset() >= CurrentLoadedOffset;
}
/// \brief Returns true if \p Loc did not come from a PCH/Module.
bool isLocalSourceLocation(SourceLocation Loc) const {
return Loc.getOffset() < NextLocalOffset;
}
/// \brief Returns true if \p FID came from a PCH/Module.
bool isLoadedFileID(FileID FID) const {
assert(FID.ID != -1 && "Using FileID sentinel value");
return FID.ID < 0;
}
/// \brief Returns true if \p FID did not come from a PCH/Module.
bool isLocalFileID(FileID FID) const {
return !isLoadedFileID(FID);
}
/// Gets the location of the immediate macro caller, one level up the stack
/// toward the initial macro typed into the source.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const {
if (!Loc.isMacroID()) return Loc;
// When we have the location of (part of) an expanded parameter, its
// spelling location points to the argument as expanded in the macro call,
// and therefore is used to locate the macro caller.
if (isMacroArgExpansion(Loc))
return getImmediateSpellingLoc(Loc);
// Otherwise, the caller of the macro is located where this macro is
// expanded (while the spelling is part of the macro definition).
return getImmediateExpansionRange(Loc).first;
}
private:
llvm::MemoryBuffer *getFakeBufferForRecovery() const;
const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const;
const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const;
/// \brief Get the entry with the given unwrapped FileID.
const SrcMgr::SLocEntry &getSLocEntryByID(int ID,
bool *Invalid = nullptr) const {
assert(ID != -1 && "Using FileID sentinel value");
if (ID < 0)
return getLoadedSLocEntryByID(ID, Invalid);
return getLocalSLocEntry(static_cast<unsigned>(ID), Invalid);
}
const SrcMgr::SLocEntry &
getLoadedSLocEntryByID(int ID, bool *Invalid = nullptr) const {
return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2), Invalid);
}
/// Implements the common elements of storing an expansion info struct into
/// the SLocEntry table and producing a source location that refers to it.
SourceLocation createExpansionLocImpl(const SrcMgr::ExpansionInfo &Expansion,
unsigned TokLength,
int LoadedID = 0,
unsigned LoadedOffset = 0);
/// \brief Return true if the specified FileID contains the
/// specified SourceLocation offset. This is a very hot method.
inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const {
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID);
// If the entry is after the offset, it can't contain it.
if (SLocOffset < Entry.getOffset()) return false;
// If this is the very last entry then it does.
if (FID.ID == -2)
return true;
// If it is the last local entry, then it does if the location is local.
if (FID.ID+1 == static_cast<int>(LocalSLocEntryTable.size()))
return SLocOffset < NextLocalOffset;
// Otherwise, the entry after it has to not include it. This works for both
// local and loaded entries.
return SLocOffset < getSLocEntryByID(FID.ID+1).getOffset();
}
/// \brief Returns the previous in-order FileID or an invalid FileID if there
/// is no previous one.
FileID getPreviousFileID(FileID FID) const;
/// \brief Returns the next in-order FileID or an invalid FileID if there is
/// no next one.
FileID getNextFileID(FileID FID) const;
/// \brief Create a new fileID for the specified ContentCache and
/// include position.
///
/// This works regardless of whether the ContentCache corresponds to a
/// file or some other input source.
FileID createFileID(const SrcMgr::ContentCache* File,
SourceLocation IncludePos,
SrcMgr::CharacteristicKind DirCharacter,
int LoadedID, unsigned LoadedOffset);
const SrcMgr::ContentCache *
getOrCreateContentCache(const FileEntry *SourceFile,
bool isSystemFile = false);
/// \brief Create a new ContentCache for the specified memory buffer.
const SrcMgr::ContentCache *
createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buf);
FileID getFileIDSlow(unsigned SLocOffset) const;
FileID getFileIDLocal(unsigned SLocOffset) const;
FileID getFileIDLoaded(unsigned SLocOffset) const;
SourceLocation getExpansionLocSlowCase(SourceLocation Loc) const;
SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const;
SourceLocation getFileLocSlowCase(SourceLocation Loc) const;
std::pair<FileID, unsigned>
getDecomposedExpansionLocSlowCase(const SrcMgr::SLocEntry *E) const;
std::pair<FileID, unsigned>
getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
unsigned Offset) const;
void computeMacroArgsCache(MacroArgsMap *&MacroArgsCache, FileID FID) const;
void associateFileChunkWithMacroArgExp(MacroArgsMap &MacroArgsCache,
FileID FID,
SourceLocation SpellLoc,
SourceLocation ExpansionLoc,
unsigned ExpansionLength) const;
friend class ASTReader;
friend class ASTWriter;
};
/// \brief Comparison function object.
template<typename T>
class BeforeThanCompare;
/// \brief Compare two source locations.
template<>
class BeforeThanCompare<SourceLocation> {
SourceManager &SM;
public:
explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { }
bool operator()(SourceLocation LHS, SourceLocation RHS) const {
return SM.isBeforeInTranslationUnit(LHS, RHS);
}
};
/// \brief Compare two non-overlapping source ranges.
template<>
class BeforeThanCompare<SourceRange> {
SourceManager &SM;
public:
explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { }
bool operator()(SourceRange LHS, SourceRange RHS) const {
return SM.isBeforeInTranslationUnit(LHS.getBegin(), RHS.getBegin());
}
};
} // end namespace clang
#endif
|