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
Import(Loc loc,Identifiers * packages,Identifier * id,Identifier * aliasId,int isstatic)28 Import::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
addAlias(Identifier * name,Identifier * alias)60 void 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
kind()72 const char *Import::kind() const
73 {
74 return isstatic ? "static import" : "import";
75 }
76
prot()77 Prot Import::prot()
78 {
79 return protection;
80 }
81
syntaxCopy(Dsymbol * s)82 Dsymbol *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
load(Scope * sc)96 void 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
importAll(Scope * sc)169 void 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
semantic(Scope * sc)197 void 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
semantic2(Scope * sc)387 void 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
toAlias()402 Dsymbol *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
addMember(Scope * sc,ScopeDsymbol * sd)413 void 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
setScope(Scope * sc)442 void 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
search(const Loc & loc,Identifier * ident,int flags)461 Dsymbol *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
overloadInsert(Dsymbol * s)476 bool 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