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