@@ -1469,8 +1469,91 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
14691469 };
14701470
14711471 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+
14721555 return llvm::make_error<XRefError>(" top-level value not found" , pathTrace,
1473- getXRefDeclNameForError () );
1556+ declName, notes );
14741557 }
14751558
14761559 // Filters for values discovered in the remaining path pieces.
0 commit comments