1 /** 2 * A `Dsymbol` representing a renamed import. 3 * 4 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d) 8 * Documentation: https://dlang.org/phobos/dmd_dimport.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dimport.d 10 */ 11 12 module dmd.dimport; 13 14 import dmd.arraytypes; 15 import dmd.declaration; 16 import dmd.dmodule; 17 import dmd.dscope; 18 import dmd.dsymbol; 19 import dmd.dsymbolsem; 20 import dmd.errors; 21 import dmd.expression; 22 import dmd.globals; 23 import dmd.identifier; 24 import dmd.mtype; 25 import dmd.visitor; 26 27 /*********************************************************** 28 */ 29 extern (C++) final class Import : Dsymbol 30 { 31 /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2; 32 */ 33 Identifier[] packages; // array of Identifier's representing packages 34 Identifier id; // module Identifier 35 Identifier aliasId; 36 int isstatic; // !=0 if static import 37 Visibility visibility; 38 39 // Pairs of alias=name to bind into current namespace 40 Identifiers names; 41 Identifiers aliases; 42 43 Module mod; 44 Package pkg; // leftmost package/module 45 46 // corresponding AliasDeclarations for alias=name pairs 47 AliasDeclarations aliasdecls; 48 49 extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Identifier aliasId, int isstatic) 50 { 51 Identifier selectIdent() 52 { 53 // select Dsymbol identifier (bracketed) 54 if (aliasId) 55 { 56 // import [aliasId] = std.stdio; 57 return aliasId; 58 } 59 else if (packages.length > 0) 60 { 61 // import [std].stdio; 62 return packages[0]; 63 } 64 else 65 { 66 // import [id]; 67 return id; 68 } 69 } 70 71 super(loc, selectIdent()); 72 73 assert(id); 74 version (none) 75 { 76 printf("Import::Import("); 77 foreach (id; packages) 78 { 79 printf("%s.", id.toChars()); 80 } 81 printf("%s)\n", id.toChars()); 82 } 83 this.packages = packages; 84 this.id = id; 85 this.aliasId = aliasId; 86 this.isstatic = isstatic; 87 this.visibility = Visibility.Kind.private_; // default to private 88 } 89 90 extern (D) void addAlias(Identifier name, Identifier _alias) 91 { 92 if (isstatic) 93 error("cannot have an import bind list"); 94 if (!aliasId) 95 this.ident = null; // make it an anonymous import 96 names.push(name); 97 aliases.push(_alias); 98 } 99 100 override const(char)* kind() const 101 { 102 return isstatic ? "static import" : "import"; 103 } 104 105 override Visibility visible() pure nothrow @nogc @safe 106 { 107 return visibility; 108 } 109 110 // copy only syntax trees 111 override Import syntaxCopy(Dsymbol s) 112 { 113 assert(!s); 114 auto si = new Import(loc, packages, id, aliasId, isstatic); 115 si.comment = comment; 116 for (size_t i = 0; i < names.dim; i++) 117 { 118 si.addAlias(names[i], aliases[i]); 119 } 120 return si; 121 } 122 123 /******************************* 124 * Load this module. 125 * Returns: 126 * true for errors, false for success 127 */ 128 bool load(Scope* sc) 129 { 130 //printf("Import::load('%s') %p\n", toPrettyChars(), this); 131 // See if existing module 132 const errors = global.errors; 133 DsymbolTable dst = Package.resolve(packages, null, &pkg); 134 version (none) 135 { 136 if (pkg && pkg.isModule()) 137 { 138 .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars()); 139 mod = pkg.isModule(); // Error recovery - treat as import of that module 140 return true; 141 } 142 } 143 Dsymbol s = dst.lookup(id); 144 if (s) 145 { 146 if (s.isModule()) 147 mod = cast(Module)s; 148 else 149 { 150 if (s.isAliasDeclaration()) 151 { 152 .error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars()); 153 } 154 else if (Package p = s.isPackage()) 155 { 156 if (p.isPkgMod == PKG.unknown) 157 { 158 uint preverrors = global.errors; 159 mod = Module.load(loc, packages, id); 160 if (!mod) 161 p.isPkgMod = PKG.package_; 162 else 163 { 164 // mod is a package.d, or a normal module which conflicts with the package name. 165 if (mod.isPackageFile) 166 mod.tag = p.tag; // reuse the same package tag 167 else 168 { 169 // show error if Module.load does not 170 if (preverrors == global.errors) 171 .error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars()); 172 return true; 173 } 174 } 175 } 176 else 177 { 178 mod = p.isPackageMod(); 179 } 180 if (!mod) 181 { 182 .error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars()); 183 } 184 } 185 else if (pkg) 186 { 187 .error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars()); 188 } 189 else 190 { 191 .error(loc, "can only import from a module, not from package `%s`", id.toChars()); 192 } 193 } 194 } 195 if (!mod) 196 { 197 // Load module 198 mod = Module.load(loc, packages, id); 199 if (mod) 200 { 201 // id may be different from mod.ident, if so then insert alias 202 dst.insert(id, mod); 203 } 204 } 205 if (mod && !mod.importedFrom) 206 mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule; 207 if (!pkg) 208 { 209 if (mod && mod.isPackageFile) 210 { 211 // one level depth package.d file (import pkg; ./pkg/package.d) 212 // it's necessary to use the wrapping Package already created 213 pkg = mod.pkg; 214 } 215 else 216 pkg = mod; 217 } 218 //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); 219 return global.errors != errors; 220 } 221 222 override void importAll(Scope* sc) 223 { 224 if (mod) return; // Already done 225 load(sc); 226 if (!mod) return; // Failed 227 228 if (sc.stc & STC.static_) 229 isstatic = true; 230 mod.importAll(null); 231 mod.checkImportDeprecation(loc, sc); 232 if (sc.explicitVisibility) 233 visibility = sc.visibility; 234 if (!isstatic && !aliasId && !names.dim) 235 sc.scopesym.importScope(mod, visibility); 236 // Enable access to pkgs/mod as soon as posible, because compiler 237 // can traverse them before the import gets semantic (Issue: 21501) 238 if (!aliasId && !names.dim) 239 addPackageAccess(sc.scopesym); 240 } 241 242 /******************************* 243 * Mark the imported packages as accessible from the current 244 * scope. This access check is necessary when using FQN b/c 245 * we're using a single global package tree. 246 * https://issues.dlang.org/show_bug.cgi?id=313 247 */ 248 extern (D) void addPackageAccess(ScopeDsymbol scopesym) 249 { 250 //printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this); 251 if (packages.length > 0) 252 { 253 // import a.b.c.d; 254 auto p = pkg; // a 255 scopesym.addAccessiblePackage(p, visibility); 256 foreach (id; packages[1 .. $]) // [b, c] 257 { 258 p = cast(Package) p.symtab.lookup(id); 259 // https://issues.dlang.org/show_bug.cgi?id=17991 260 // An import of truly empty file/package can happen 261 // https://issues.dlang.org/show_bug.cgi?id=20151 262 // Package in the path conflicts with a module name 263 if (p is null) 264 break; 265 scopesym.addAccessiblePackage(p, visibility); 266 } 267 } 268 scopesym.addAccessiblePackage(mod, visibility); // d 269 } 270 271 override Dsymbol toAlias() 272 { 273 if (aliasId) 274 return mod; 275 return this; 276 } 277 278 /***************************** 279 * Add import to sd's symbol table. 280 */ 281 override void addMember(Scope* sc, ScopeDsymbol sd) 282 { 283 //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc); 284 if (names.dim == 0) 285 return Dsymbol.addMember(sc, sd); 286 if (aliasId) 287 Dsymbol.addMember(sc, sd); 288 /* Instead of adding the import to sd's symbol table, 289 * add each of the alias=name pairs 290 */ 291 for (size_t i = 0; i < names.dim; i++) 292 { 293 Identifier name = names[i]; 294 Identifier _alias = aliases[i]; 295 if (!_alias) 296 _alias = name; 297 auto tname = new TypeIdentifier(loc, name); 298 auto ad = new AliasDeclaration(loc, _alias, tname); 299 ad._import = this; 300 ad.addMember(sc, sd); 301 aliasdecls.push(ad); 302 } 303 } 304 305 override void setScope(Scope* sc) 306 { 307 Dsymbol.setScope(sc); 308 if (aliasdecls.dim) 309 { 310 if (!mod) 311 importAll(sc); 312 313 sc = sc.push(mod); 314 sc.visibility = visibility; 315 foreach (ad; aliasdecls) 316 ad.setScope(sc); 317 sc = sc.pop(); 318 } 319 } 320 321 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 322 { 323 //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); 324 if (!pkg) 325 { 326 load(null); 327 mod.importAll(null); 328 mod.dsymbolSemantic(null); 329 } 330 // Forward it to the package/module 331 return pkg.search(loc, ident, flags); 332 } 333 334 override bool overloadInsert(Dsymbol s) 335 { 336 /* Allow multiple imports with the same package base, but disallow 337 * alias collisions 338 * https://issues.dlang.org/show_bug.cgi?id=5412 339 */ 340 assert(ident && ident == s.ident); 341 Import imp; 342 if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId) 343 return true; 344 else 345 return false; 346 } 347 348 override inout(Import) isImport() inout 349 { 350 return this; 351 } 352 353 override void accept(Visitor v) 354 { 355 v.visit(this); 356 } 357 }