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