Skip to content

Commit b4cbf53

Browse files
dima74yopox
authored andcommitted
RES: Add extern crate alloc; in auto-import if needed
1 parent b81bf85 commit b4cbf53

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

src/main/kotlin/org/rust/ide/utils/import/ImportCandidatesCollector2.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ private fun ImportContext2.convertToCandidates(itemsPaths: List<ItemUsePath>): L
146146
itemsPsi.flatMap { itemPsi ->
147147
paths.map { path ->
148148
val qualifiedItem = QualifiedNamedItem2(itemPsi, path.path, path.crate)
149-
val importInfo = qualifiedItem.toImportInfo(rootDefMap, rootModData)
149+
val importInfo = qualifiedItem.toImportInfo(rootDefMap, rootModData, path.needExternCrate)
150150
ImportCandidate2(qualifiedItem, importInfo)
151151
}
152152
}
@@ -163,7 +163,8 @@ private data class ModUsePath(
163163
/** corresponds to `path.first()` */
164164
val crate: Crate,
165165
/** corresponds to `path.last()` */
166-
val mod: ModData
166+
val mod: ModData,
167+
val needExternCrate: Boolean,
167168
) {
168169
override fun toString(): String = path.joinToString("::")
169170
}
@@ -175,7 +176,7 @@ private fun ImportContext2.getAllModPaths(): List<ModUsePath> {
175176
for ((crateName, defMap) in defMaps.all) {
176177
val filterCrate = { crate: CratePersistentId -> crate == defMap.crate || crate !in explicitCrates }
177178
val crate = project.crateGraph.findCrateById(defMap.crate) ?: continue
178-
val rootPath = ModUsePath(arrayOf(crateName), crate, defMap.root)
179+
val rootPath = ModUsePath(arrayOf(crateName), crate, defMap.root, needExternCrate = defMap.crate !in explicitCrates)
179180
visitVisibleModules(rootPath, filterCrate, result::add)
180181
}
181182
return result
@@ -211,7 +212,7 @@ private fun ImportContext2.findPathsToModulesInScope(path: ModUsePath): List<Mod
211212
it.isModOrEnum && checkVisibility(it, path.mod)
212213
} ?: return@mapNotNull null
213214
val childModData = rootDefMap.tryCastToModData(childMod) ?: return@mapNotNull null
214-
ModUsePath(path.path + name, path.crate, childModData)
215+
path.copy(path = path.path + name, mod = childModData)
215216
}
216217

217218
private data class InitialDefMaps(
@@ -293,7 +294,8 @@ private data class ItemUsePath(
293294
val crate: Crate,
294295
/** corresponds to `path.last()` */
295296
val item: VisItem,
296-
val namespace: Namespace
297+
val namespace: Namespace,
298+
val needExternCrate: Boolean,
297299
) {
298300
fun toItemWithNamespace(): ItemWithNamespace = ItemWithNamespace(item.path, item.isModOrEnum, namespace)
299301

@@ -317,7 +319,7 @@ private fun ImportContext2.getPerNsPaths(modPath: ModUsePath, perNs: PerNs, name
317319
checkVisibility(it, modPath.mod)
318320
&& (type == ImportContext2.Type.OTHER || !hasVisibleItemInRootScope(name, namespace))
319321
}
320-
.map { ItemUsePath(modPath.path + name, modPath.crate, it, namespace) }
322+
.map { ItemUsePath(modPath.path + name, modPath.crate, it, namespace, modPath.needExternCrate) }
321323
}
322324

323325
private fun ImportContext2.hasVisibleItemInRootScope(name: String, namespace: Namespace): Boolean {
@@ -331,7 +333,7 @@ private fun ImportContext2.getTraitsPathsInMod(modPath: ModUsePath, traits: Set<
331333
.flatMap { (name, perNs) ->
332334
perNs.types
333335
.filter { checkVisibility(it, modPath.mod) && it.path in traits }
334-
.map { ItemUsePath(modPath.path + name, modPath.crate, it, Namespace.Types) }
336+
.map { ItemUsePath(modPath.path + name, modPath.crate, it, Namespace.Types, modPath.needExternCrate) }
335337
}
336338

337339

@@ -388,15 +390,16 @@ private fun ImportContext2.isUsefulTraitImport(usePath: String): Boolean {
388390
|| element.canBeAccessedByTraitName
389391
}
390392

391-
private fun QualifiedNamedItem2.toImportInfo(defMap: CrateDefMap, modData: ModData): ImportInfo {
393+
private fun QualifiedNamedItem2.toImportInfo(defMap: CrateDefMap, modData: ModData, needExternCrate: Boolean): ImportInfo {
392394
val crateName = path.first()
393395
return if (crateName == "crate") {
394396
val usePath = path.joinToString("::").let {
395397
if (defMap.isAtLeastEdition2018) it else it.removePrefix("crate::")
396398
}
397399
ImportInfo.LocalImportInfo(usePath)
398400
} else {
399-
val needInsertExternCrateItem = !defMap.isAtLeastEdition2018 && !defMap.hasExternCrateInCrateRoot(crateName)
401+
val needInsertExternCrateItem = needExternCrate
402+
|| !defMap.isAtLeastEdition2018 && !defMap.hasExternCrateInCrateRoot(crateName)
400403
val crateRelativePath = path.copyOfRange(1, path.size).joinToString("::")
401404
ImportInfo.ExternCrateImportInfo(
402405
crate = containingCrate,

src/main/kotlin/org/rust/ide/utils/import/importUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ fun ImportInfo.insertExternCrateIfNeeded(context: RsElement): Int? {
7070
// we don't add corresponding extern crate item manually for the same reason
7171
attributes == RsFile.Attributes.NO_STD && crate.isCore -> Testmarks.autoInjectedCoreCrate.hit()
7272
else -> {
73-
if (needInsertExternCrateItem && !context.isAtLeastEdition2018) {
73+
if (needInsertExternCrateItem) {
7474
crateRoot?.insertExternCrateItem(RsPsiFactory(context.project), externCrateName)
7575
} else {
7676
if (depth != null) {

src/test/kotlin/org/rust/ide/inspections/import/AutoImportFixStdTest.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,4 +805,21 @@ class AutoImportFixStdTest : AutoImportFixTestBase() {
805805
test_main();
806806
}
807807
""")
808+
809+
@MockEdition(CargoWorkspace.Edition.EDITION_2018)
810+
fun `test add extern crate for alloc (with no_std)`() = checkAutoImportFixByTextWithoutHighlighting("""
811+
#![no_std]
812+
fn main() {
813+
Vec/*caret*/::new();
814+
}
815+
""", """
816+
#![no_std]
817+
extern crate alloc;
818+
819+
use alloc::vec::Vec;
820+
821+
fn main() {
822+
Vec::new();
823+
}
824+
""")
808825
}

0 commit comments

Comments
 (0)