Sema: Prefer the submodule import for access-levels diagnostics

Update logic finding the import to point in diagnostics to avoid relying
on the implicit import of the top-level module when importing a clang
submodule. A recent change avoids duplicating the implicit imports and
broke the old logic.

rdar://162151660
This commit is contained in:
Alexis Laferrière
2025-10-10 14:23:49 -07:00
parent a956308a07
commit ca8792ca37
5 changed files with 130 additions and 13 deletions

View File

@@ -2971,10 +2971,10 @@ SourceFile::getImportAccessLevel(const ModuleDecl *targetModule) const {
assert(targetModule != getParentModule() &&
"getImportAccessLevel doesn't support checking for a self-import");
/// Order of relevancy of `import` to reach `targetModule`.
/// Lower is better/more authoritative.
/// Order of relevancy of `import` to reach `targetModule` assuming the same
/// visibility level. Lower is better/more authoritative.
auto rateImport = [&](const ImportAccessLevel import) -> int {
auto importedModule = import->module.importedModule;
auto importedModule = import->module.importedModule->getTopLevelModule();
// Prioritize public names:
if (targetModule->getExportAsName() == importedModule->getBaseIdentifier())
@@ -2989,9 +2989,14 @@ SourceFile::getImportAccessLevel(const ModuleDecl *targetModule) const {
if (targetModule == importedModule->getUnderlyingModuleIfOverlay())
return 3;
// Any import in the sources.
if (import->importLoc.isValid())
return 4;
// Any import in the sources:
if (import->importLoc.isValid()) {
// Prefer clang submodules to their top level modules:
if (import->module.importedModule != importedModule)
return 4;
return 5;
}
return 10;
};
@@ -3001,11 +3006,12 @@ SourceFile::getImportAccessLevel(const ModuleDecl *targetModule) const {
auto &imports = getASTContext().getImportCache();
ImportAccessLevel restrictiveImport = std::nullopt;
for (auto &import : *Imports) {
auto importedModule = import.module.importedModule->getTopLevelModule();
if ((!restrictiveImport.has_value() ||
import.accessLevel > restrictiveImport->accessLevel ||
(import.accessLevel == restrictiveImport->accessLevel &&
rateImport(import) < rateImport(restrictiveImport))) &&
imports.isImportedBy(targetModule, import.module.importedModule)) {
imports.isImportedBy(targetModule, importedModule)) {
restrictiveImport = import;
}
}