1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _dimport.d) 9 */ 10 11 module ddmd.dimport; 12 13 import core.stdc..string; 14 import core.stdc.stdio; 15 16 import ddmd.arraytypes; 17 import ddmd.declaration; 18 import ddmd.dmodule; 19 import ddmd.dscope; 20 import ddmd.dsymbol; 21 import ddmd.errors; 22 import ddmd.expression; 23 import ddmd.globals; 24 import ddmd.hdrgen; 25 import ddmd.id; 26 import ddmd.identifier; 27 import ddmd.mtype; 28 import ddmd.root.outbuffer; 29 import ddmd.utils; 30 import ddmd.visitor; 31 32 /*********************************************************** 33 */ 34 extern (C++) final class Import : Dsymbol 35 { 36 /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2; 37 */ 38 Identifiers* packages; // array of Identifier's representing packages 39 Identifier id; // module Identifier 40 Identifier aliasId; 41 int isstatic; // !=0 if static import 42 Prot protection; 43 44 // Pairs of alias=name to bind into current namespace 45 Identifiers names; 46 Identifiers aliases; 47 48 Module mod; 49 Package pkg; // leftmost package/module 50 51 // corresponding AliasDeclarations for alias=name pairs 52 AliasDeclarations aliasdecls; 53 54 extern (D) this(Loc loc, Identifiers* packages, Identifier id, Identifier aliasId, int isstatic) 55 { 56 super(null); 57 assert(id); 58 version (none) 59 { 60 printf("Import::Import("); 61 if (packages && packages.dim) 62 { 63 for (size_t i = 0; i < packages.dim; i++) 64 { 65 Identifier id = (*packages)[i]; 66 printf("%s.", id.toChars()); 67 } 68 } 69 printf("%s)\n", id.toChars()); 70 } 71 this.loc = loc; 72 this.packages = packages; 73 this.id = id; 74 this.aliasId = aliasId; 75 this.isstatic = isstatic; 76 this.protection = PROTprivate; // default to private 77 // Set symbol name (bracketed) 78 if (aliasId) 79 { 80 // import [cstdio] = std.stdio; 81 this.ident = aliasId; 82 } 83 else if (packages && packages.dim) 84 { 85 // import [std].stdio; 86 this.ident = (*packages)[0]; 87 } 88 else 89 { 90 // import [foo]; 91 this.ident = id; 92 } 93 } 94 95 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 ? cast(char*)"static import" : cast(char*)"import"; 108 } 109 110 override Prot prot() 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 for (size_t i = 0; i < names.dim; i++) 121 { 122 si.addAlias(names[i], aliases[i]); 123 } 124 return si; 125 } 126 127 void load(Scope* sc) 128 { 129 //printf("Import::load('%s') %p\n", toPrettyChars(), this); 130 // See if existing module 131 DsymbolTable dst = Package.resolve(packages, null, &pkg); 132 version (none) 133 { 134 if (pkg && pkg.isModule()) 135 { 136 .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()); 137 mod = pkg.isModule(); // Error recovery - treat as import of that module 138 return; 139 } 140 } 141 Dsymbol s = dst.lookup(id); 142 if (s) 143 { 144 if (s.isModule()) 145 mod = cast(Module)s; 146 else 147 { 148 if (s.isAliasDeclaration()) 149 { 150 .error(loc, "%s %s conflicts with %s", s.kind(), s.toPrettyChars(), id.toChars()); 151 } 152 else if (Package p = s.isPackage()) 153 { 154 if (p.isPkgMod == PKGunknown) 155 { 156 mod = Module.load(loc, packages, id); 157 if (!mod) 158 p.isPkgMod = PKGpackage; 159 else 160 { 161 // mod is a package.d, or a normal module which conflicts with the package name. 162 assert(mod.isPackageFile == (p.isPkgMod == PKGmodule)); 163 if (mod.isPackageFile) 164 mod.tag = p.tag; // reuse the same package tag 165 } 166 } 167 else 168 { 169 mod = p.isPackageMod(); 170 } 171 if (!mod) 172 { 173 .error(loc, "can only import from a module, not from package %s.%s", p.toPrettyChars(), id.toChars()); 174 } 175 } 176 else if (pkg) 177 { 178 .error(loc, "can only import from a module, not from package %s.%s", pkg.toPrettyChars(), id.toChars()); 179 } 180 else 181 { 182 .error(loc, "can only import from a module, not from package %s", id.toChars()); 183 } 184 } 185 } 186 if (!mod) 187 { 188 // Load module 189 mod = Module.load(loc, packages, id); 190 if (mod) 191 { 192 // id may be different from mod.ident, if so then insert alias 193 dst.insert(id, mod); 194 } 195 } 196 if (mod && !mod.importedFrom) 197 mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule; 198 if (!pkg) 199 pkg = mod; 200 //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); 201 } 202 203 override void importAll(Scope* sc) 204 { 205 if (!mod) 206 { 207 load(sc); 208 if (mod) // if successfully loaded module 209 { 210 if (mod.md && mod.md.isdeprecated) 211 { 212 Expression msg = mod.md.msg; 213 if (StringExp se = msg ? msg.toStringExp() : null) 214 mod.deprecation(loc, "is deprecated - %s", se..string); 215 else 216 mod.deprecation(loc, "is deprecated"); 217 } 218 mod.importAll(null); 219 if (sc.explicitProtection) 220 protection = sc.protection; 221 if (!isstatic && !aliasId && !names.dim) 222 { 223 sc.scopesym.importScope(mod, protection); 224 } 225 } 226 } 227 } 228 229 override void semantic(Scope* sc) 230 { 231 //printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars()); 232 if (_scope) 233 { 234 sc = _scope; 235 _scope = null; 236 } 237 // Load if not already done so 238 if (!mod) 239 { 240 load(sc); 241 if (mod) 242 mod.importAll(null); 243 } 244 if (mod) 245 { 246 // Modules need a list of each imported module 247 //printf("%s imports %s\n", sc.module.toChars(), mod.toChars()); 248 sc._module.aimports.push(mod); 249 250 if (sc.explicitProtection) 251 protection = sc.protection; 252 253 if (!aliasId && !names.dim) // neither a selective nor a renamed import 254 { 255 ScopeDsymbol scopesym; 256 for (Scope* scd = sc; scd; scd = scd.enclosing) 257 { 258 if (!scd.scopesym) 259 continue; 260 scopesym = scd.scopesym; 261 break; 262 } 263 264 if (!isstatic) 265 { 266 scopesym.importScope(mod, protection); 267 } 268 269 // Mark the imported packages as accessible from the current 270 // scope. This access check is necessary when using FQN b/c 271 // we're using a single global package tree. See Bugzilla 313. 272 if (packages) 273 { 274 // import a.b.c.d; 275 auto p = pkg; // a 276 scopesym.addAccessiblePackage(p, protection); 277 foreach (id; (*packages)[1 .. packages.dim]) // [b, c] 278 { 279 p = cast(Package) p.symtab.lookup(id); 280 scopesym.addAccessiblePackage(p, protection); 281 } 282 } 283 scopesym.addAccessiblePackage(mod, protection); // d 284 } 285 286 mod.semantic(null); 287 if (mod.needmoduleinfo) 288 { 289 //printf("module4 %s because of %s\n", sc.module.toChars(), mod.toChars()); 290 sc._module.needmoduleinfo = 1; 291 } 292 293 sc = sc.push(mod); 294 sc.protection = protection; 295 for (size_t i = 0; i < aliasdecls.dim; i++) 296 { 297 AliasDeclaration ad = aliasdecls[i]; 298 //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope); 299 if (mod.search(loc, names[i])) 300 { 301 ad.semantic(sc); 302 // If the import declaration is in non-root module, 303 // analysis of the aliased symbol is deferred. 304 // Therefore, don't see the ad.aliassym or ad.type here. 305 } 306 else 307 { 308 Dsymbol s = mod.search_correct(names[i]); 309 if (s) 310 mod.error(loc, "import '%s' not found, did you mean %s '%s'?", names[i].toChars(), s.kind(), s.toChars()); 311 else 312 mod.error(loc, "import '%s' not found", names[i].toChars()); 313 ad.type = Type.terror; 314 } 315 } 316 sc = sc.pop(); 317 } 318 319 // object self-imports itself, so skip that (Bugzilla 7547) 320 // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164) 321 if (global.params.moduleDeps !is null && !(id == Id.object && sc._module.ident == Id.object) && 322 sc._module.ident != Id.entrypoint && 323 strcmp(sc._module.ident.toChars(), "__main") != 0) 324 { 325 /* The grammar of the file is: 326 * ImportDeclaration 327 * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " 328 * ModuleAliasIdentifier ] "\n" 329 * 330 * BasicImportDeclaration 331 * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string" 332 * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" 333 * 334 * FilePath 335 * - any string with '(', ')' and '\' escaped with the '\' character 336 */ 337 OutBuffer* ob = global.params.moduleDeps; 338 Module imod = sc.instantiatingModule(); 339 if (!global.params.moduleDepsFile) 340 ob.writestring("depsImport "); 341 ob.writestring(imod.toPrettyChars()); 342 ob.writestring(" ("); 343 escapePath(ob, imod.srcfile.toChars()); 344 ob.writestring(") : "); 345 // use protection instead of sc.protection because it couldn't be 346 // resolved yet, see the comment above 347 protectionToBuffer(ob, protection); 348 ob.writeByte(' '); 349 if (isstatic) 350 { 351 stcToBuffer(ob, STCstatic); 352 ob.writeByte(' '); 353 } 354 ob.writestring(": "); 355 if (packages) 356 { 357 for (size_t i = 0; i < packages.dim; i++) 358 { 359 Identifier pid = (*packages)[i]; 360 ob.printf("%s.", pid.toChars()); 361 } 362 } 363 ob.writestring(id.toChars()); 364 ob.writestring(" ("); 365 if (mod) 366 escapePath(ob, mod.srcfile.toChars()); 367 else 368 ob.writestring("???"); 369 ob.writeByte(')'); 370 for (size_t i = 0; i < names.dim; i++) 371 { 372 if (i == 0) 373 ob.writeByte(':'); 374 else 375 ob.writeByte(','); 376 Identifier name = names[i]; 377 Identifier _alias = aliases[i]; 378 if (!_alias) 379 { 380 ob.printf("%s", name.toChars()); 381 _alias = name; 382 } 383 else 384 ob.printf("%s=%s", _alias.toChars(), name.toChars()); 385 } 386 if (aliasId) 387 ob.printf(" -> %s", aliasId.toChars()); 388 ob.writenl(); 389 } 390 //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); 391 } 392 393 override void semantic2(Scope* sc) 394 { 395 //printf("Import::semantic2('%s')\n", toChars()); 396 if (mod) 397 { 398 mod.semantic2(null); 399 if (mod.needmoduleinfo) 400 { 401 //printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars()); 402 if (sc) 403 sc._module.needmoduleinfo = 1; 404 } 405 } 406 } 407 408 override Dsymbol toAlias() 409 { 410 if (aliasId) 411 return mod; 412 return this; 413 } 414 415 /***************************** 416 * Add import to sd's symbol table. 417 */ 418 override void addMember(Scope* sc, ScopeDsymbol sd) 419 { 420 //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc); 421 if (names.dim == 0) 422 return Dsymbol.addMember(sc, sd); 423 if (aliasId) 424 Dsymbol.addMember(sc, sd); 425 /* Instead of adding the import to sd's symbol table, 426 * add each of the alias=name pairs 427 */ 428 for (size_t i = 0; i < names.dim; i++) 429 { 430 Identifier name = names[i]; 431 Identifier _alias = aliases[i]; 432 if (!_alias) 433 _alias = name; 434 auto tname = new TypeIdentifier(loc, name); 435 auto ad = new AliasDeclaration(loc, _alias, tname); 436 ad._import = this; 437 ad.addMember(sc, sd); 438 aliasdecls.push(ad); 439 } 440 } 441 442 override void setScope(Scope* sc) 443 { 444 Dsymbol.setScope(sc); 445 if (aliasdecls.dim) 446 { 447 if (!mod) 448 importAll(sc); 449 450 sc = sc.push(mod); 451 sc.protection = protection; 452 foreach (ad; aliasdecls) 453 ad.setScope(sc); 454 sc = sc.pop(); 455 } 456 } 457 458 override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) 459 { 460 //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); 461 if (!pkg) 462 { 463 load(null); 464 mod.importAll(null); 465 mod.semantic(null); 466 } 467 // Forward it to the package/module 468 return pkg.search(loc, ident, flags); 469 } 470 471 override bool overloadInsert(Dsymbol s) 472 { 473 /* Allow multiple imports with the same package base, but disallow 474 * alias collisions (Bugzilla 5412). 475 */ 476 assert(ident && ident == s.ident); 477 Import imp; 478 if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId) 479 return true; 480 else 481 return false; 482 } 483 484 override inout(Import) isImport() inout 485 { 486 return this; 487 } 488 489 override void accept(Visitor v) 490 { 491 v.visit(this); 492 } 493 }