yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
5f632cd20
master
1// slang-source-loc.cpp 2#include "slang-source-loc.h" 3 4#include "../core/slang-char-encode.h" 5#include "../core/slang-string-escape-util.h" 6#include "../core/slang-string-util.h" 7#include "slang-artifact-desc-util.h" 8#include "slang-artifact-impl.h" 9#include "slang-artifact-representation-impl.h" 10#include "slang-artifact-util.h" 11 12namespace Slang 13{ 14 15/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 16 17const String PathInfo ::getMostUniqueIdentity ()const 18{ 19switch (type ) 20 { 21case Type ::Normal : 22return uniqueIdentity ; 23case Type ::FoundPath : 24case Type ::FromString : 25 { 26return foundPath ; 27 } 28default : 29return "" ; 30 } 31} 32 33String PathInfo ::getName ()const 34{ 35switch (type ) 36 { 37case Type ::Normal : 38case Type ::FromString : 39case Type ::FoundPath : 40 { 41return foundPath ; 42 } 43 } 44return String (); 45} 46 47bool PathInfo ::operator== (const ThisType & rhs )const 48{ 49// They must be the same type 50if (type != rhs .type ) 51 { 52return false; 53 } 54 55switch (type ) 56 { 57case Type ::TokenPaste : 58case Type ::TypeParse : 59case Type ::Unknown : 60case Type ::CommandLine : 61 { 62return true; 63 } 64case Type ::Normal : 65 { 66return foundPath == rhs .foundPath && uniqueIdentity == rhs .uniqueIdentity ; 67 } 68case Type ::FromString : 69case Type ::FoundPath : 70 { 71// Only have a found path 72return foundPath == rhs .foundPath ; 73 } 74default : 75break ; 76 } 77 78return false; 79} 80 81void PathInfo ::appendDisplayName (StringBuilder & out )const 82{ 83switch (type ) 84 { 85case Type ::TokenPaste : 86out <<"[Token Paste]" ; 87break ; 88case Type ::TypeParse : 89out <<"[Type Parse]" ; 90break ; 91case Type ::Unknown : 92out <<"[Unknown]" ; 93break ; 94case Type ::CommandLine : 95out <<"[Command Line]" ; 96break ; 97case Type ::Normal : 98case Type ::FromString : 99case Type ::FoundPath : 100 { 101StringEscapeUtil ::appendQuoted ( 102StringEscapeUtil ::getHandler (StringEscapeUtil ::Style ::Cpp ), 103foundPath .getUnownedSlice (), 104out ); 105break ; 106 } 107default : 108break ; 109 } 110} 111 112/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 113 114int SourceView ::findEntryIndex (SourceLoc sourceLoc )const 115{ 116if (!m_range .contains (sourceLoc )) 117 { 118return -1 ; 119 } 120 121const auto rawValue = sourceLoc .getRaw (); 122 123Index hi = m_entries .getCount (); 124// If there are no entries, or it is in front of the first entry, then there is no associated 125// entry 126if (hi == 0 || m_entries [0 ].m_startLoc .getRaw ()> sourceLoc .getRaw ()) 127 { 128return -1 ; 129 } 130 131Index lo = 0 ; 132while (lo + 1 < hi ) 133 { 134const Index mid = (hi + lo ) >>1 ; 135const Entry & midEntry = m_entries [mid ]; 136SourceLoc ::RawValue midValue = midEntry .m_startLoc .getRaw (); 137if (midValue <=rawValue ) 138 { 139// The location we seek is at or after this entry 140lo = mid ; 141 } 142else 143 { 144// The location we seek is before this entry 145hi = mid ; 146 } 147 } 148 149return int (lo ); 150} 151 152void SourceView ::addLineDirective ( 153SourceLoc directiveLoc , 154StringSlicePool ::Handle pathHandle , 155int line ) 156{ 157SLANG_ASSERT (pathHandle != StringSlicePool ::Handle (0 )); 158SLANG_ASSERT (m_range .contains (directiveLoc )); 159 160// Check that the directiveLoc values are always increasing 161SLANG_ASSERT ( 162m_entries .getCount ()== 0 || 163 (m_entries .getLast ().m_startLoc .getRaw ()< directiveLoc .getRaw ())); 164 165// Calculate the offset 166const int offset = m_range .getOffset (directiveLoc ); 167 168// Get the line index in the original file 169const int lineIndex = m_sourceFile -> calcLineIndexFromOffset (offset ); 170 171Entry entry ; 172entry .m_startLoc = directiveLoc ; 173entry .m_pathHandle = pathHandle ; 174 175// We also need to make sure that any lookups for line numbers will 176// get corrected based on this files location. 177// We assume the line number coming from the directive is a line number, NOT an index, so the 178// correction needs + 1 There is an additional + 1 because we want the NEXT line - ie the line 179// after the #line directive, to the specified value Taking both into account means +2 is 180// correct 'fix' 181entry .m_lineAdjust = line - (lineIndex + 2 ); 182 183m_entries .add (entry ); 184} 185 186void SourceView ::addLineDirective (SourceLoc directiveLoc ,const String & path ,int line ) 187{ 188StringSlicePool ::Handle pathHandle = 189getSourceManager ()-> getStringSlicePool ().add (path .getUnownedSlice ()); 190return addLineDirective (directiveLoc ,pathHandle ,line ); 191} 192 193void SourceView ::addDefaultLineDirective (SourceLoc directiveLoc ) 194{ 195SLANG_ASSERT (m_range .contains (directiveLoc )); 196// Check that the directiveLoc values are always increasing 197SLANG_ASSERT ( 198m_entries .getCount ()== 0 || 199 (m_entries .getLast ().m_startLoc .getRaw ()< directiveLoc .getRaw ())); 200 201// Well if there are no entries, or the last one puts it in default case, then we don't need to 202// add anything 203if (m_entries .getCount ()== 0 || (m_entries .getCount ()&& m_entries .getLast ().isDefault ())) 204 { 205return ; 206 } 207 208Entry entry ; 209entry .m_startLoc = directiveLoc ; 210entry .m_lineAdjust = 0 ;// No line adjustment... we are going back to default 211entry .m_pathHandle = 212StringSlicePool ::Handle (0 );// Mark that there is no path, and that this is a 'default' 213 214SLANG_ASSERT (entry .isDefault ()); 215 216m_entries .add (entry ); 217} 218 219// Nominal-like types take into account line directives, and potentially source maps 220static bool _isNominalLike (SourceLocType type ) 221{ 222return type == SourceLocType ::Nominal || type == SourceLocType ::Emit ; 223} 224 225static bool _canFollowSourceMap (SourceFile * sourceFile ,SourceLocType type ) 226{ 227// If we don't have a source map we have nothing to follow 228if (!sourceFile -> getSourceMap ()) 229 { 230return false; 231 } 232 233// If it's obfuscated we can't follow if we are emitting 234if (sourceFile -> getSourceMapKind ()== SourceMapKind ::Obfuscated && type == SourceLocType ::Emit ) 235 { 236return false; 237 } 238 239return _isNominalLike (type ); 240} 241 242static SlangResult _findLocWithSourceMap ( 243SourceManager * lookupSourceManager , 244SourceView * sourceView , 245SourceLoc loc , 246SourceLocType type , 247HandleSourceLoc & outLoc ) 248{ 249auto sourceFile = sourceView -> getSourceFile (); 250 251if (!_canFollowSourceMap (sourceFile ,type )) 252 { 253return SLANG_E_NOT_FOUND ; 254 } 255 256// Hold a list of sourceFiles visited so we can't end up in a loop of lookups 257ShortList < SourceFile * ,8 > sourceFiles ; 258sourceFiles .add (sourceFile ); 259 260Index entryIndex = -1 ; 261 262// Do the initial lookup using the loc 263 { 264const auto offset = sourceView -> getRange ().getOffset (loc ); 265 266const auto lineIndex = sourceFile -> calcLineIndexFromOffset (offset ); 267const auto colIndex = sourceFile -> calcColumnIndex (lineIndex ,offset ); 268 269// If we are in this function the sourceFile should have a map 270auto sourceMap = sourceFile -> getSourceMap (); 271SLANG_ASSERT (sourceMap ); 272 273entryIndex = sourceMap -> get ().findEntry (lineIndex ,colIndex ); 274 } 275 276if (entryIndex < 0 ) 277 { 278return SLANG_FAIL ; 279 } 280 281// Keep searching through source maps 282do 283 { 284auto sourceMap = sourceFile -> getSourceMap ()-> getPtr (); 285 286// Find the entry 287const auto & entry = sourceMap -> getEntryByIndex (entryIndex ); 288const auto sourceFileName = sourceMap -> getSourceFileName (entry .sourceFileIndex ); 289 290// If we have a source name, see if it already exists in source manager 291if (sourceFileName .getLength ()) 292 { 293if (auto foundSourceFile = 294lookupSourceManager -> findSourceFileByPathRecursively (sourceFileName )) 295 { 296// We only follow if the source file hasn't already been visisted 297if (sourceFiles .indexOf (foundSourceFile )< 0 ) 298 { 299// Add so we don't reprocess 300sourceFiles .add (foundSourceFile ); 301 302// If it has a source map, we try and look up the current location in it's 303// source map 304if (_canFollowSourceMap (foundSourceFile ,type )) 305 { 306auto foundSourceMap = foundSourceFile -> getSourceMap (); 307 308const auto foundEntryIndex = 309foundSourceMap -> get ().findEntry (entry .sourceLine ,entry .sourceColumn ); 310 311// If we found the entry repeat the lookup 312if (foundEntryIndex >=0 ) 313 { 314sourceFile = foundSourceFile ; 315entryIndex = foundEntryIndex ; 316continue ; 317 } 318 } 319 } 320 } 321 } 322 }while (false); 323 324// Generate the HandleSourceLoc 325auto sourceMap = sourceFile -> getSourceMap ()-> getPtr (); 326const auto & entry = sourceMap -> getEntryByIndex (entryIndex ); 327 328// We need to add the pool of the originating source view/file 329const auto originatingSourceManager = sourceView -> getSourceManager (); 330 331auto & managerPool = originatingSourceManager -> getStringSlicePool (); 332 333outLoc .line = entry .sourceLine + 1 ; 334outLoc .column = entry .sourceColumn + 1 ; 335outLoc .pathHandle = managerPool .add (sourceMap -> getSourceFileName (entry .sourceFileIndex )); 336 337return SLANG_OK ; 338} 339 340 341SlangResult SourceView ::_findSourceMapLoc ( 342SourceLoc loc , 343SourceLocType type , 344HandleSourceLoc & outLoc ) 345{ 346// We only do source map lookups with nominal 347if (!_isNominalLike (type )) 348 { 349return SLANG_E_NOT_FOUND ; 350 } 351 352// TODO(JS): 353// Ideally we'd do the lookup on the "current" source manager rather than the source manager on 354// this view, which may be a parent to the current one. 355auto lookupSourceManager = m_sourceFile -> getSourceManager (); 356 357SLANG_RETURN_ON_FAIL (_findLocWithSourceMap (lookupSourceManager ,this ,loc ,type ,outLoc )); 358 359return SLANG_OK ; 360} 361 362HandleSourceLoc SourceView ::getHandleLoc (SourceLoc loc ,SourceLocType type ) 363{ 364 { 365HandleSourceLoc handleLoc ; 366if (SLANG_SUCCEEDED (_findSourceMapLoc (loc ,type ,handleLoc ))) 367 { 368return handleLoc ; 369 } 370 } 371 372// Get the offset in bytes for this loc 373const int offset = m_range .getOffset (loc ); 374 375// We need the line index from the original source file 376const int lineIndex = m_sourceFile -> calcLineIndexFromOffset (offset ); 377 378// TODO: 379// - Tab characters, which should really adjust how we report 380// columns (although how are we supposed to know the setting 381// that an IDE expects us to use when reporting locations?) 382// 383// For now we just count tabs as single chars 384const int columnIndex = m_sourceFile -> calcColumnIndex (lineIndex ,offset ); 385 386HandleSourceLoc handleLoc ; 387handleLoc .column = columnIndex + 1 ; 388handleLoc .line = lineIndex + 1 ; 389 390// Only bother looking up the entry information if we want a 'Norminal'-like lookup 391if (_isNominalLike (type )) 392 { 393const int entryIndex = findEntryIndex (loc ); 394if (entryIndex >=0 ) 395 { 396const Entry & entry = m_entries [entryIndex ]; 397// Adjust the line 398handleLoc .line += entry .m_lineAdjust ; 399// Get the pathHandle.. 400handleLoc .pathHandle = entry .m_pathHandle ; 401 } 402 } 403 404return handleLoc ; 405} 406 407HumaneSourceLoc SourceView ::getHumaneLoc (SourceLoc loc ,SourceLocType type ) 408{ 409HandleSourceLoc handleLoc = getHandleLoc (loc ,type ); 410 411HumaneSourceLoc humaneLoc ; 412humaneLoc .column = handleLoc .column ; 413humaneLoc .line = handleLoc .line ; 414humaneLoc .pathInfo = _getPathInfoFromHandle (handleLoc .pathHandle ); 415return humaneLoc ; 416} 417 418PathInfo SourceView ::getViewPathInfo ()const 419{ 420if (m_viewPath .getLength ()) 421 { 422PathInfo pathInfo (m_sourceFile -> getPathInfo ()); 423pathInfo .foundPath = m_viewPath ; 424return pathInfo ; 425 } 426else 427 { 428return m_sourceFile -> getPathInfo (); 429 } 430} 431 432PathInfo SourceView ::_getPathInfoFromHandle (StringSlicePool ::Handle pathHandle )const 433{ 434// If there is no override path, then just the source files path 435if (pathHandle == StringSlicePool ::Handle (0 )) 436 { 437return getViewPathInfo (); 438 } 439else 440 { 441return PathInfo ::makePath (getSourceManager ()-> getStringSlicePool ().getSlice (pathHandle )); 442 } 443} 444 445PathInfo SourceView ::getPathInfo (SourceLoc loc ,SourceLocType type ) 446{ 447if (type == SourceLocType ::Actual ) 448 { 449return getViewPathInfo (); 450 } 451 452 { 453HandleSourceLoc handleLoc ; 454if (SLANG_SUCCEEDED (_findSourceMapLoc (loc ,type ,handleLoc ))) 455 { 456return _getPathInfoFromHandle (handleLoc .pathHandle ); 457 } 458 } 459 460const int entryIndex = findEntryIndex (loc ); 461return _getPathInfoFromHandle ( 462 (entryIndex >=0 ) ?m_entries [entryIndex ].m_pathHandle :StringSlicePool ::Handle (0 )); 463} 464 465/* !!!!!!!!!!!!!!!!!!!!!!! SourceFile !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 466 467void SourceFile ::setLineBreakOffsets (const uint32_t * offsets ,UInt numOffsets ) 468{ 469m_lineBreakOffsets .clear (); 470m_lineBreakOffsets .addRange (offsets ,numOffsets ); 471} 472 473const List < uint32_t >& SourceFile ::getLineBreakOffsets () 474{ 475// We now have a raw input file that we can search for line breaks. 476// We obviously don't want to do a linear scan over and over, so we will 477// cache an array of line break locations in the file. 478if (m_lineBreakOffsets .getCount ()== 0 ) 479 { 480UnownedStringSlice content (getContent ()),line ; 481char const * contentBegin = content .begin (); 482while (StringUtil ::extractLine (content ,line )) 483 { 484m_lineBreakOffsets .add (uint32_t (line .begin ()- contentBegin )); 485 } 486// Note that we do *not* treat the end of the file as a line 487// break, because otherwise we would report errors like 488// "end of file inside string literal" with a line number 489// that points at a line that doesn't exist. 490 } 491 492return m_lineBreakOffsets ; 493} 494 495SourceFile ::OffsetRange SourceFile ::getOffsetRangeAtLineIndex (Index lineIndex ) 496{ 497const List < uint32_t >& offsets = getLineBreakOffsets (); 498const Index count = offsets .getCount (); 499 500if (lineIndex >=count - 1 ) 501 { 502// Work out the line start 503const uint32_t offsetEnd = uint32_t (getContentSize ()); 504const uint32_t offsetStart = (lineIndex >=count ) ?offsetEnd :offsets [lineIndex ]; 505// The line is the span from start, to the end of the content 506return OffsetRange {offsetStart ,offsetEnd }; 507 } 508else 509 { 510const uint32_t offsetStart = offsets [lineIndex ]; 511const uint32_t offsetEnd = offsets [lineIndex + 1 ]; 512return OffsetRange {offsetStart ,offsetEnd }; 513 } 514} 515 516UnownedStringSlice SourceFile ::getLineAtIndex (Index lineIndex ) 517{ 518const OffsetRange range = getOffsetRangeAtLineIndex (lineIndex ); 519 520if (range .isValid ()&& hasContent ()) 521 { 522const UnownedStringSlice content = getContent (); 523SLANG_ASSERT (range .end <=uint32_t (content .getLength ())); 524 525const char * const text = content .begin (); 526return UnownedStringSlice (text + range .start ,text + range .end ); 527 } 528 529return UnownedStringSlice (); 530} 531 532UnownedStringSlice SourceFile ::getLineContainingOffset (uint32_t offset ) 533{ 534const Index lineIndex = calcLineIndexFromOffset (offset ); 535return getLineAtIndex (lineIndex ); 536} 537 538bool SourceFile ::isOffsetOnLine (uint32_t offset ,Index lineIndex ) 539{ 540const OffsetRange range = getOffsetRangeAtLineIndex (lineIndex ); 541return range .isValid ()&& range .containsInclusive (offset ); 542} 543 544int SourceFile ::calcLineIndexFromOffset (int offset ) 545{ 546SLANG_ASSERT (UInt (offset ) <=getContentSize ()); 547 548// Make sure we have the line break offsets 549const auto & lineBreakOffsets = getLineBreakOffsets (); 550 551// At this point we can assume the `lineBreakOffsets` array has been filled in. 552// We will use a binary search to find the line index that contains our 553// chosen offset. 554Index lo = 0 ; 555Index hi = lineBreakOffsets .getCount (); 556 557while (lo + 1 < hi ) 558 { 559const Index mid = (hi + lo ) >>1 ; 560const uint32_t midOffset = lineBreakOffsets [mid ]; 561if (midOffset <=uint32_t (offset )) 562 { 563lo = mid ; 564 } 565else 566 { 567hi = mid ; 568 } 569 } 570 571return int (lo ); 572} 573 574int SourceFile ::calcColumnOffset (int lineIndex ,int offset ) 575{ 576const auto & lineBreakOffsets = getLineBreakOffsets (); 577return offset - lineBreakOffsets [lineIndex ]; 578} 579 580int SourceFile ::calcColumnIndex (int lineIndex ,int offset ,int tabSize ) 581{ 582const int colOffset = calcColumnOffset (lineIndex ,offset ); 583 584// If we don't have the content of the file, the best we can do is to assume there is a char per 585// column 586if (!hasContent ()) 587 { 588return colOffset ; 589 } 590 591const auto line = getLineAtIndex (lineIndex ); 592 593const auto head = line .head (colOffset ); 594 595auto colCount = UTF8Util ::calcCodePointCount (head ); 596 597if (tabSize >=0 ) 598 { 599Count tabCount = 0 ; 600for (auto c :head ) 601 { 602tabCount += Count (c == '\t' ); 603 } 604 605// We substract one from tabSize, because colCount will already holds a +1 for each tab. 606colCount += tabCount * (tabSize - 1 ); 607 } 608 609return int (colCount ); 610} 611 612/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceFile !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 613 614void SourceFile ::setContents (ISlangBlob * blob ) 615{ 616const UInt rawContentSize = blob -> getBufferSize (); 617 618SLANG_ASSERT (rawContentSize == m_contentSize ); 619 620Byte * rawContentBegin = (Byte * )blob -> getBufferPointer (); 621 622// Query the encoding type and discard the Unicode Byte-Order-Marker before decoding 623size_t offset ; 624auto type = CharEncoding ::determineEncoding (rawContentBegin ,rawContentSize ,offset ); 625SLANG_ASSERT (rawContentSize >=offset ); 626 627List < char > decodedBuffer ; 628CharEncoding ::getEncoding (type )-> decode ( 629rawContentBegin + offset , 630int (rawContentSize - offset ), 631decodedBuffer ); 632 633m_contentBlob = RawBlob ::create (decodedBuffer .getBuffer (),decodedBuffer .getCount ()); 634 635char const * decodedContentBegin = (char const * )m_contentBlob -> getBufferPointer (); 636const UInt decodedContentSize = m_contentBlob -> getBufferSize (); 637char const * decodedContentEnd = decodedContentBegin + decodedContentSize ; 638 639m_content = UnownedStringSlice (decodedContentBegin ,decodedContentEnd ); 640} 641 642void SourceFile ::setContents (const String & content ) 643{ 644ComPtr < ISlangBlob > contentBlob = StringUtil ::createStringBlob (content ); 645setContents (contentBlob ); 646} 647 648SourceFile ::SourceFile (SourceManager * sourceManager ,const PathInfo & pathInfo ,size_t contentSize ) 649 :m_sourceManager (sourceManager ),m_pathInfo (pathInfo ),m_contentSize (contentSize ) 650{ 651} 652 653SourceFile ::~SourceFile () {} 654 655SHA1 ::Digest SourceFile ::getDigest () 656{ 657if (m_digest == SHA1 ::Digest ()) 658 { 659DigestBuilder < SHA1 > builder ; 660builder .append (getContent ()); 661m_digest = builder .finalize (); 662 } 663return m_digest ; 664} 665 666String SourceFile ::calcVerbosePath ()const 667{ 668ISlangFileSystemExt * fileSystemExt = getSourceManager ()-> getFileSystemExt (); 669 670if (fileSystemExt ) 671 { 672String displayPath ; 673ComPtr < ISlangBlob > displayPathBlob ; 674if (SLANG_SUCCEEDED (fileSystemExt -> getPath ( 675PathKind ::Display , 676m_pathInfo .foundPath .getBuffer (), 677displayPathBlob .writeRef ()))) 678 { 679displayPath = StringUtil ::getString (displayPathBlob ); 680 } 681if (displayPath .getLength ()> 0 ) 682 { 683return displayPath ; 684 } 685 } 686 687return m_pathInfo .foundPath ; 688} 689 690/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceManager !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 691 692void SourceManager ::initialize (SourceManager * p ,ISlangFileSystemExt * fileSystemExt ) 693{ 694m_fileSystemExt = fileSystemExt ; 695 696m_parent = p ; 697 698_resetLoc (); 699} 700 701SourceManager ::~SourceManager () 702{ 703_resetSource (); 704} 705 706void SourceManager ::_resetLoc () 707{ 708if (m_parent ) 709 { 710// If we have a parent source manager, then we assume that all code at that level 711// has already been loaded, and it is safe to start our own source locations 712// right after those from the parent. 713// 714// TODO: more clever allocation in cases where that might not be reasonable 715m_startLoc = m_parent -> m_nextLoc ; 716 } 717else 718 { 719// Location zero is reserved for an invalid location, 720// so we need to start reserving locations starting at 1. 721m_startLoc = SourceLoc ::fromRaw (1 ); 722 } 723 724m_nextLoc = m_startLoc ; 725} 726 727void SourceManager ::_resetSource () 728{ 729for (auto item :m_sourceViews ) 730 { 731delete item ; 732 } 733 734for (auto item :m_sourceFiles ) 735 { 736delete item ; 737 } 738 739m_sourceViews .clear (); 740m_sourceFiles .clear (); 741 742m_sourceFileMap .clear (); 743} 744 745 746void SourceManager ::reset () 747{ 748_resetSource (); 749_resetLoc (); 750} 751 752UnownedStringSlice SourceManager ::allocateStringSlice (const UnownedStringSlice & slice ) 753{ 754const UInt numChars = slice .getLength (); 755 756char * dst = (char * )m_memoryArena .allocate (numChars ); 757 ::memcpy (dst ,slice .begin (),numChars ); 758 759return UnownedStringSlice (dst ,numChars ); 760} 761 762SourceRange SourceManager ::allocateSourceRange (UInt size ) 763{ 764// TODO: consider using atomics here 765 766 767SourceLoc beginLoc = m_nextLoc ; 768SourceLoc endLoc = beginLoc + size ; 769 770// We need to be able to represent the location that is *at* the end of 771// the input source, so the next available location for a new file 772// must be placed one after the end of this one. 773 774m_nextLoc = endLoc + 1 ; 775 776return SourceRange (beginLoc ,endLoc ); 777} 778 779SourceFile * SourceManager ::createSourceFileWithSize (const PathInfo & pathInfo ,size_t contentSize ) 780{ 781SourceFile * sourceFile = new SourceFile (this ,pathInfo ,contentSize ); 782m_sourceFiles .add (sourceFile ); 783return sourceFile ; 784} 785 786SourceFile * SourceManager ::createSourceFileWithString ( 787const PathInfo & pathInfo , 788const String & contents ) 789{ 790SourceFile * sourceFile = new SourceFile (this ,pathInfo ,contents .getLength ()); 791m_sourceFiles .add (sourceFile ); 792sourceFile -> setContents (contents ); 793return sourceFile ; 794} 795 796SourceFile * SourceManager ::createSourceFileWithBlob (const PathInfo & pathInfo ,ISlangBlob * blob ) 797{ 798SourceFile * sourceFile = new SourceFile (this ,pathInfo ,blob -> getBufferSize ()); 799m_sourceFiles .add (sourceFile ); 800sourceFile -> setContents (blob ); 801return sourceFile ; 802} 803 804SourceView * SourceManager ::createSourceView ( 805SourceFile * sourceFile , 806const PathInfo * pathInfo , 807SourceLoc initiatingSourceLoc ) 808{ 809SourceRange range = allocateSourceRange (sourceFile -> getContentSize ()); 810 811SourceView * sourceView = nullptr ; 812if (pathInfo && (pathInfo -> foundPath .getLength ()&& 813sourceFile -> getPathInfo ().foundPath != pathInfo -> foundPath )) 814 { 815sourceView = new SourceView (sourceFile ,range ,& pathInfo -> foundPath ,initiatingSourceLoc ); 816 } 817else 818 { 819sourceView = new SourceView (sourceFile ,range ,nullptr ,initiatingSourceLoc ); 820 } 821 822m_sourceViews .add (sourceView ); 823 824return sourceView ; 825} 826 827SourceView * SourceManager ::findSourceView (SourceLoc loc )const 828{ 829Index hi = m_sourceViews .getCount (); 830// It must be in the range of this manager and have associated views for it to possibly be a hit 831if (!getSourceRange ().contains (loc )|| hi == 0 ) 832 { 833return nullptr ; 834 } 835 836// If we don't have very many, we may as well just linearly search 837if (hi <=8 ) 838 { 839for (int i = 0 ;i < hi ;++ i ) 840 { 841SourceView * view = m_sourceViews [i ]; 842if (view -> getRange ().contains (loc )) 843 { 844return view ; 845 } 846 } 847return nullptr ; 848 } 849 850const SourceLoc ::RawValue rawLoc = loc .getRaw (); 851 852// Binary chop to see if we can find the associated SourceUnit 853Index lo = 0 ; 854while (lo + 1 < hi ) 855 { 856Index mid = (hi + lo ) >>1 ; 857 858SourceView * midView = m_sourceViews [mid ]; 859if (midView -> getRange ().contains (loc )) 860 { 861return midView ; 862 } 863 864const SourceLoc ::RawValue midValue = midView -> getRange ().begin .getRaw (); 865if (midValue <=rawLoc ) 866 { 867// The location we seek is at or after this entry 868lo = mid ; 869 } 870else 871 { 872// The location we seek is before this entry 873hi = mid ; 874 } 875 } 876 877// Check if low is actually a hit 878SourceView * view = m_sourceViews [lo ]; 879return (view -> getRange ().contains (loc )) ?view :nullptr ; 880} 881 882SourceView * SourceManager ::findSourceViewRecursively (SourceLoc loc )const 883{ 884// Start with this manager 885const SourceManager * manager = this ; 886do 887 { 888SourceView * sourceView = manager -> findSourceView (loc ); 889// If we found a hit we are done 890if (sourceView ) 891 { 892return sourceView ; 893 } 894// Try the parent 895manager = manager -> m_parent ; 896 }while (manager ); 897// Didn't find it 898return nullptr ; 899} 900 901SourceFile * SourceManager ::findSourceFileByPathRecursively (const String & name )const 902{ 903// Start with this manager 904const SourceManager * manager = this ; 905do 906 { 907SourceFile * sourceFile = manager -> findSourceFileByPath (name ); 908// If we found a hit we are done 909if (sourceFile ) 910 { 911return sourceFile ; 912 } 913// Try the parent 914manager = manager -> m_parent ; 915 }while (manager ); 916// Didn't find it 917return nullptr ; 918} 919 920SourceFile * SourceManager ::findSourceFileByPath (const String & name )const 921{ 922for (auto sourceFile :m_sourceFiles ) 923 { 924if (sourceFile -> getPathInfo ().foundPath == name ) 925 { 926return sourceFile ; 927 } 928 } 929return nullptr ; 930} 931 932SourceFile * SourceManager ::findSourceFile (const String & uniqueIdentity )const 933{ 934SourceFile * const * filePtr = m_sourceFileMap .tryGetValue (uniqueIdentity ); 935return (filePtr ) ?* filePtr :nullptr ; 936} 937 938SourceFile * SourceManager ::findSourceFileRecursively (const String & uniqueIdentity )const 939{ 940const SourceManager * manager = this ; 941do 942 { 943SourceFile * sourceFile = manager -> findSourceFile (uniqueIdentity ); 944if (sourceFile ) 945 { 946return sourceFile ; 947 } 948manager = manager -> m_parent ; 949 }while (manager ); 950return nullptr ; 951} 952 953SourceFile * SourceManager ::findSourceFileByContentRecursively (const char * text ) 954{ 955const SourceManager * manager = this ; 956do 957 { 958SourceFile * sourceFile = manager -> findSourceFileByContent (text ); 959if (sourceFile ) 960 { 961return sourceFile ; 962 } 963manager = manager -> m_parent ; 964 }while (manager ); 965return nullptr ; 966} 967 968SourceFile * SourceManager ::findSourceFileByContent (const char * text )const 969{ 970for (SourceFile * sourceFile :getSourceFiles ()) 971 { 972auto content = sourceFile -> getContent (); 973 974if (text >=content .begin ()&& text <=content .end ()) 975 { 976return sourceFile ; 977 } 978 } 979return nullptr ; 980} 981 982void SourceManager ::addSourceFile (const String & uniqueIdentity ,SourceFile * sourceFile ) 983{ 984SLANG_ASSERT (!findSourceFileRecursively (uniqueIdentity )); 985m_sourceFileMap .add (uniqueIdentity ,sourceFile ); 986} 987 988void SourceManager ::addSourceFileIfNotExist (const String & uniqueIdentity ,SourceFile * sourceFile ) 989{ 990if (findSourceFileRecursively (uniqueIdentity )) 991return ; 992m_sourceFileMap .addIfNotExists (uniqueIdentity ,sourceFile ); 993} 994 995HumaneSourceLoc SourceManager ::getHumaneLoc (SourceLoc loc ,SourceLocType type ) 996{ 997SourceView * sourceView = findSourceViewRecursively (loc ); 998if (sourceView ) 999 { 1000return sourceView -> getHumaneLoc (loc ,type ); 1001 } 1002else 1003 { 1004return HumaneSourceLoc (); 1005 } 1006} 1007 1008PathInfo SourceManager ::getPathInfo (SourceLoc loc ,SourceLocType type ) 1009{ 1010SourceView * sourceView = findSourceViewRecursively (loc ); 1011if (sourceView ) 1012 { 1013return sourceView -> getPathInfo (loc ,type ); 1014 } 1015else 1016 { 1017return PathInfo ::makeUnknown (); 1018 } 1019} 1020 1021SourceLoc ::RawValue SourceView ::getAbsoluteLocation (SourceLoc location )const 1022{ 1023AbsoluteSegment segment ; 1024if (m_absSegments .getCount ()) 1025 { 1026if (m_absSegments .getFirst ().begin > location ) 1027 { 1028segment .begin = m_range .begin ; 1029segment .absoluteBegin = m_absoluteLocationBase ; 1030 } 1031else 1032 { 1033auto it = std::upper_bound ( 1034m_absSegments .begin (), 1035m_absSegments .end (), 1036location , 1037 [](SourceLoc const & loc ,AbsoluteSegment const & seg ) 1038 {return loc < seg .begin ; })- 10391 ; 1040segment = * it ; 1041 } 1042 } 1043else 1044 { 1045segment = getLastSegment (); 1046 } 1047auto offset = SourceRange (segment .begin ,location ).getSize (); 1048return segment .absoluteBegin + offset ; 1049} 1050 1051SourceLoc ::RawValue SourceManager ::getAbsoluteLocation (SourceLoc location )const 1052{ 1053SourceLoc ::RawValue res = 0 ; 1054if (const SourceView * view = findSourceView (location )) 1055 { 1056res = view -> getAbsoluteLocation (location ); 1057 } 1058return res ; 1059} 1060 1061}// namespace Slang