1 /** 2 * A `Dsymbol` representing a renamed import. 3 * 4 * Copyright: Copyright (C) 1999-2020 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.root.rmem; 26 import dmd.visitor; 27 28 /*********************************************************** 29 */ 30 extern (C++) final class Import : Dsymbol 31 { 32 /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2; 33 */ 34 Identifiers* packages; // array of Identifier's representing packages 35 Identifier id; // module Identifier 36 Identifier aliasId; 37 int isstatic; // !=0 if static import 38 Prot protection; 39 40 // Pairs of alias=name to bind into current namespace 41 Identifiers names; 42 Identifiers aliases; 43 44 Module mod; 45 Package pkg; // leftmost package/module 46 47 // corresponding AliasDeclarations for alias=name pairs 48 AliasDeclarations aliasdecls; 49 50 extern (D) this(const ref Loc loc, Identifiers* packages, Identifier id, Identifier aliasId, int isstatic) 51 { 52 Identifier selectIdent() 53 { 54 // select Dsymbol identifier (bracketed) 55 if (aliasId) 56 { 57 // import [aliasId] = std.stdio; 58 return aliasId; 59 } 60 else if (packages && packages.dim) 61 { 62 // import [std].stdio; 63 return (*packages)[0]; 64 } 65 else 66 { 67 // import [id]; 68 return id; 69 } 70 } 71 72 super(loc, selectIdent()); 73 74 assert(id); 75 version (none) 76 { 77 printf("Import::Import("); 78 if (packages && packages.dim) 79 { 80 for (size_t i = 0; i < packages.dim; i++) 81 { 82 Identifier id = (*packages)[i]; 83 printf("%s.", id.toChars()); 84 } 85 } 86 printf("%s)\n", id.toChars()); 87 } 88 this.packages = packages; 89 this.id = id; 90 this.aliasId = aliasId; 91 this.isstatic = isstatic; 92 this.protection = Prot.Kind.private_; // default to private 93 } 94 95 extern (D) void addAlias(Identifier name, Identifier _alias) 96 { 97 if (isstatic) 98 error("cannot have an import bind list"); 99 if (!aliasId) 100 this.ident = null; // make it an anonymous import 101 names.push(name); 102 aliases.push(_alias); 103 } 104 105 override const(char)* kind() const 106 { 107 return isstatic ? "static import" : "import"; 108 } 109 110 override Prot prot() pure nothrow @nogc @safe 111 { 112 return protection; 113 } 114 115 // copy only syntax trees 116 override Dsymbol syntaxCopy(Dsymbol s) 117 { 118 assert(!s); 119 auto si = new Import(loc, packages, id, aliasId, isstatic); 120 si.comment = comment; 121 for (size_t i = 0; i < names.dim; i++) 122 { 123 si.addAlias(names[i], aliases[i]); 124 } 125 return si; 126 } 127 128 /******************************* 129 * Load this module. 130 * Returns: 131 * true for errors, false for success 132 */ 133 bool load(Scope* sc) 134 { 135 //printf("Import::load('%s') %p\n", toPrettyChars(), this); 136 // See if existing module 137 const errors = global.errors; 138 DsymbolTable dst = Package.resolve(packages, null, &pkg); 139 version (none) 140 { 141 if (pkg && pkg.isModule()) 142 { 143 .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()); 144 mod = pkg.isModule(); // Error recovery - treat as import of that module 145 return true; 146 } 147 } 148 Dsymbol s = dst.lookup(id); 149 if (s) 150 { 151 if (s.isModule()) 152 mod = cast(Module)s; 153 else 154 { 155 if (s.isAliasDeclaration()) 156 { 157 .error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars()); 158 } 159 else if (Package p = s.isPackage()) 160 { 161 if (p.isPkgMod == PKG.unknown) 162 { 163 uint preverrors = global.errors; 164 mod = Module.load(loc, packages, id); 165 if (!mod) 166 p.isPkgMod = PKG.package_; 167 else 168 { 169 // mod is a package.d, or a normal module which conflicts with the package name. 170 if (mod.isPackageFile) 171 mod.tag = p.tag; // reuse the same package tag 172 else 173 { 174 // show error if Module.load does not 175 if (preverrors == global.errors) 176 .error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars()); 177 return true; 178 } 179 } 180 } 181 else 182 { 183 mod = p.isPackageMod(); 184 } 185 if (!mod) 186 { 187 .error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars()); 188 } 189 } 190 else if (pkg) 191 { 192 .error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars()); 193 } 194 else 195 { 196 .error(loc, "can only import from a module, not from package `%s`", id.toChars()); 197 } 198 } 199 } 200 if (!mod) 201 { 202 // Load module 203 mod = Module.load(loc, packages, id); 204 if (mod) 205 { 206 // id may be different from mod.ident, if so then insert alias 207 dst.insert(id, mod); 208 } 209 } 210 if (mod && !mod.importedFrom) 211 mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule; 212 if (!pkg) 213 { 214 if (mod && mod.isPackageFile) 215 { 216 // one level depth package.d file (import pkg; ./pkg/package.d) 217 // it's necessary to use the wrapping Package already created 218 pkg = mod.pkg; 219 } 220 else 221 pkg = mod; 222 } 223 //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); 224 return global.errors != errors; 225 } 226 227 override void importAll(Scope* sc) 228 { 229 if (mod) return; // Already done 230 load(sc); 231 if (!mod) return; // Failed 232 233 if (sc.stc & STC.static_) 234 isstatic = true; 235 mod.importAll(null); 236 mod.checkImportDeprecation(loc, sc); 237 if (sc.explicitProtection) 238 protection = sc.protection; 239 if (!isstatic && !aliasId && !names.dim) 240 sc.scopesym.importScope(mod, protection); 241 } 242 243 override Dsymbol toAlias() 244 { 245 if (aliasId) 246 return mod; 247 return this; 248 } 249 250 /***************************** 251 * Add import to sd's symbol table. 252 */ 253 override void addMember(Scope* sc, ScopeDsymbol sd) 254 { 255 //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc); 256 if (names.dim == 0) 257 return Dsymbol.addMember(sc, sd); 258 if (aliasId) 259 Dsymbol.addMember(sc, sd); 260 /* Instead of adding the import to sd's symbol table, 261 * add each of the alias=name pairs 262 */ 263 for (size_t i = 0; i < names.dim; i++) 264 { 265 Identifier name = names[i]; 266 Identifier _alias = aliases[i]; 267 if (!_alias) 268 _alias = name; 269 auto tname = Pool!TypeIdentifier.make(loc, name); 270 auto ad = new AliasDeclaration(loc, _alias, tname); 271 ad._import = this; 272 ad.addMember(sc, sd); 273 aliasdecls.push(ad); 274 } 275 } 276 277 override void setScope(Scope* sc) 278 { 279 Dsymbol.setScope(sc); 280 if (aliasdecls.dim) 281 { 282 if (!mod) 283 importAll(sc); 284 285 sc = sc.push(mod); 286 sc.protection = protection; 287 foreach (ad; aliasdecls) 288 ad.setScope(sc); 289 sc = sc.pop(); 290 } 291 } 292 293 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 294 { 295 //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); 296 if (!pkg) 297 { 298 load(null); 299 mod.importAll(null); 300 mod.dsymbolSemantic(null); 301 } 302 // Forward it to the package/module 303 return pkg.search(loc, ident, flags); 304 } 305 306 override bool overloadInsert(Dsymbol s) 307 { 308 /* Allow multiple imports with the same package base, but disallow 309 * alias collisions 310 * https://issues.dlang.org/show_bug.cgi?id=5412 311 */ 312 assert(ident && ident == s.ident); 313 Import imp; 314 if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId) 315 return true; 316 else 317 return false; 318 } 319 320 override inout(Import) isImport() inout 321 { 322 return this; 323 } 324 325 override void accept(Visitor v) 326 { 327 v.visit(this); 328 } 329 }