@@ -1469,8 +1469,91 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1469
1469
};
1470
1470
1471
1471
if (values.empty ()) {
1472
+ // Couldn't resolve the reference. Try to explain the problem and leave it
1473
+ // up to the caller to recover if possible.
1474
+
1475
+ // Look for types and value decls in other modules. This extra information
1476
+ // is mostly for compiler engineers to understand a likely solution at a
1477
+ // quick glance.
1478
+ SmallVector<char > strScratch;
1479
+ SmallVector<std::string, 2 > notes;
1480
+ auto declName = getXRefDeclNameForError ();
1481
+ if (recordID == XREF_TYPE_PATH_PIECE ||
1482
+ recordID == XREF_VALUE_PATH_PIECE) {
1483
+ auto &ctx = getContext ();
1484
+ for (auto nameAndModule : ctx.getLoadedModules ()) {
1485
+ auto baseModule = nameAndModule.second ;
1486
+
1487
+ IdentifierID IID;
1488
+ IdentifierID privateDiscriminator = 0 ;
1489
+ TypeID TID = 0 ;
1490
+ bool isType = (recordID == XREF_TYPE_PATH_PIECE);
1491
+ bool inProtocolExt = false ;
1492
+ bool importedFromClang = false ;
1493
+ bool isStatic = false ;
1494
+ if (isType) {
1495
+ XRefTypePathPieceLayout::readRecord (scratch, IID, privateDiscriminator,
1496
+ inProtocolExt, importedFromClang);
1497
+ } else {
1498
+ XRefValuePathPieceLayout::readRecord (scratch, TID, IID, inProtocolExt,
1499
+ importedFromClang, isStatic);
1500
+ }
1501
+
1502
+ DeclBaseName name = getDeclBaseName (IID);
1503
+ Type filterTy;
1504
+ if (!isType) {
1505
+ auto maybeType = getTypeChecked (TID);
1506
+ // Any error here would have been handled previously.
1507
+ if (maybeType) {
1508
+ filterTy = maybeType.get ();
1509
+ }
1510
+ }
1511
+
1512
+ values.clear ();
1513
+ if (privateDiscriminator) {
1514
+ baseModule->lookupMember (values, baseModule, name,
1515
+ getIdentifier (privateDiscriminator));
1516
+ } else {
1517
+ baseModule->lookupQualified (baseModule, DeclNameRef (name),
1518
+ NL_QualifiedDefault,
1519
+ values);
1520
+ }
1521
+
1522
+ bool hadAMatchBeforeFiltering = !values.empty ();
1523
+ filterValues (filterTy, nullptr , nullptr , isType, inProtocolExt,
1524
+ importedFromClang, isStatic, None, values);
1525
+
1526
+ strScratch.clear ();
1527
+ if (!values.empty ()) {
1528
+ // Found a full match in a different module. It should be a different
1529
+ // one because otherwise it would have succeeded on the first search.
1530
+ // This is usually caused by the use of poorly modularized headers.
1531
+ auto line = " '" +
1532
+ declName.getString (strScratch).str () +
1533
+ " ' was not found in module '" +
1534
+ std::string (baseModule->getName ().str ()) +
1535
+ " ', but there is one in module '" +
1536
+ std::string (nameAndModule.first .str ()) +
1537
+ " '. If this is imported from clang, please make sure " +
1538
+ " the header is part of a single clang module." ;
1539
+ notes.emplace_back (line);
1540
+ } else if (hadAMatchBeforeFiltering) {
1541
+ // Found a match that was filtered out. This may be from the same
1542
+ // expected module if there's a type difference. This can be caused
1543
+ // by the use of different Swift language versions between a library
1544
+ // with serialized SIL and a client.
1545
+ auto line = " '" +
1546
+ declName.getString (strScratch).str () +
1547
+ " ' in module '" +
1548
+ std::string (baseModule->getName ().str ()) +
1549
+ " ' was filtered out." ;
1550
+ notes.emplace_back (line);
1551
+ }
1552
+ }
1553
+ }
1554
+
1472
1555
return llvm::make_error<XRefError>(" top-level value not found" , pathTrace,
1473
- getXRefDeclNameForError () );
1556
+ declName, notes );
1474
1557
}
1475
1558
1476
1559
// Filters for values discovered in the remaining path pieces.
0 commit comments