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 
201     if (_scope)
202     {
203         sc = _scope;
204         _scope = NULL;
205     }
206 
207     // Load if not already done so
208     if (!mod)
209     {
210         load(sc);
211         if (mod)
212             mod->importAll(NULL);
213     }
214 
215     if (mod)
216     {
217         // Modules need a list of each imported module
218         //printf("%s imports %s\n", sc->_module->toChars(), mod->toChars());
219         sc->_module->aimports.push(mod);
220 
221         if (sc->explicitProtection)
222             protection = sc->protection;
223 
224         if (!aliasId && !names.dim) // neither a selective nor a renamed import
225         {
226             ScopeDsymbol *scopesym = NULL;
227             if (sc->explicitProtection)
228                 protection = sc->protection.kind;
229             for (Scope *scd = sc; scd; scd = scd->enclosing)
230             {
231                 if (!scd->scopesym)
232                     continue;
233                 scopesym = scd->scopesym;
234                 break;
235             }
236 
237             if (!isstatic)
238             {
239                 scopesym->importScope(mod, protection);
240             }
241 
242             // Mark the imported packages as accessible from the current
243             // scope. This access check is necessary when using FQN b/c
244             // we're using a single global package tree. See Bugzilla 313.
245             if (packages)
246             {
247                 // import a.b.c.d;
248                 Package *p = pkg; // a
249                 scopesym->addAccessiblePackage(p, protection);
250                 for (size_t i = 1; i < packages->dim; i++) // [b, c]
251                 {
252                     Identifier *id = (*packages)[i];
253                     p = (Package *) p->symtab->lookup(id);
254                     scopesym->addAccessiblePackage(p, protection);
255                 }
256             }
257             scopesym->addAccessiblePackage(mod, protection); // d
258         }
259 
260         mod->semantic(NULL);
261 
262         if (mod->needmoduleinfo)
263         {
264             //printf("module4 %s because of %s\n", sc->_module->toChars(), mod->toChars());
265             sc->_module->needmoduleinfo = 1;
266         }
267 
268         sc = sc->push(mod);
269         sc->protection = protection;
270         for (size_t i = 0; i < aliasdecls.dim; i++)
271         {
272             AliasDeclaration *ad = aliasdecls[i];
273             //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i]->toChars(), names[i]->toChars(), ad->_scope);
274             if (mod->search(loc, names[i]))
275             {
276                 ad->semantic(sc);
277                 // If the import declaration is in non-root module,
278                 // analysis of the aliased symbol is deferred.
279                 // Therefore, don't see the ad->aliassym or ad->type here.
280             }
281             else
282             {
283                 Dsymbol *s = mod->search_correct(names[i]);
284                 if (s)
285                     mod->error(loc, "import '%s' not found, did you mean %s '%s'?", names[i]->toChars(), s->kind(), s->toChars());
286                 else
287                     mod->error(loc, "import '%s' not found", names[i]->toChars());
288                 ad->type = Type::terror;
289             }
290         }
291         sc = sc->pop();
292     }
293 
294     // object self-imports itself, so skip that (Bugzilla 7547)
295     // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164)
296     if (global.params.moduleDeps != NULL &&
297         !(id == Id::object && sc->_module->ident == Id::object) &&
298         sc->_module->ident != Id::entrypoint &&
299         strcmp(sc->_module->ident->toChars(), "__main") != 0)
300     {
301         /* The grammar of the file is:
302          *      ImportDeclaration
303          *          ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
304          *      ModuleAliasIdentifier ] "\n"
305          *
306          *      BasicImportDeclaration
307          *          ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
308          *              " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
309          *
310          *      FilePath
311          *          - any string with '(', ')' and '\' escaped with the '\' character
312          */
313 
314         OutBuffer *ob = global.params.moduleDeps;
315         Module* imod = sc->instantiatingModule();
316         if (!global.params.moduleDepsFile)
317             ob->writestring("depsImport ");
318         ob->writestring(imod->toPrettyChars());
319         ob->writestring(" (");
320         escapePath(ob,  imod->srcfile->toChars());
321         ob->writestring(") : ");
322 
323         // use protection instead of sc->protection because it couldn't be
324         // resolved yet, see the comment above
325         protectionToBuffer(ob, protection);
326         ob->writeByte(' ');
327         if (isstatic)
328         {
329             stcToBuffer(ob, STCstatic);
330             ob->writeByte(' ');
331         }
332         ob->writestring(": ");
333 
334         if (packages)
335         {
336             for (size_t i = 0; i < packages->dim; i++)
337             {
338                 Identifier *pid = (*packages)[i];
339                 ob->printf("%s.", pid->toChars());
340             }
341         }
342 
343         ob->writestring(id->toChars());
344         ob->writestring(" (");
345         if (mod)
346             escapePath(ob, mod->srcfile->toChars());
347         else
348             ob->writestring("???");
349         ob->writeByte(')');
350 
351         for (size_t i = 0; i < names.dim; i++)
352         {
353             if (i == 0)
354                 ob->writeByte(':');
355             else
356                 ob->writeByte(',');
357 
358             Identifier *name = names[i];
359             Identifier *alias = aliases[i];
360 
361             if (!alias)
362             {
363                 ob->printf("%s", name->toChars());
364                 alias = name;
365             }
366             else
367                 ob->printf("%s=%s", alias->toChars(), name->toChars());
368         }
369 
370         if (aliasId)
371                 ob->printf(" -> %s", aliasId->toChars());
372 
373         ob->writenl();
374     }
375 
376     //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
377 }
378 
semantic2(Scope * sc)379 void Import::semantic2(Scope *sc)
380 {
381     //printf("Import::semantic2('%s')\n", toChars());
382     if (mod)
383     {
384         mod->semantic2(NULL);
385         if (mod->needmoduleinfo)
386         {
387             //printf("module5 %s because of %s\n", sc->_module->toChars(), mod->toChars());
388             if (sc)
389                 sc->_module->needmoduleinfo = 1;
390         }
391     }
392 }
393 
toAlias()394 Dsymbol *Import::toAlias()
395 {
396     if (aliasId)
397         return mod;
398     return this;
399 }
400 
401 /*****************************
402  * Add import to sd's symbol table.
403  */
404 
addMember(Scope * sc,ScopeDsymbol * sd)405 void Import::addMember(Scope *sc, ScopeDsymbol *sd)
406 {
407     //printf("Import::addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd->toChars(), sc);
408     if (names.dim == 0)
409         return Dsymbol::addMember(sc, sd);
410 
411     if (aliasId)
412         Dsymbol::addMember(sc, sd);
413 
414     /* Instead of adding the import to sd's symbol table,
415      * add each of the alias=name pairs
416      */
417     for (size_t i = 0; i < names.dim; i++)
418     {
419         Identifier *name = names[i];
420         Identifier *alias = aliases[i];
421 
422         if (!alias)
423             alias = name;
424 
425         TypeIdentifier *tname = new TypeIdentifier(loc, name);
426         AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
427         ad->_import = this;
428         ad->addMember(sc, sd);
429 
430         aliasdecls.push(ad);
431     }
432 }
433 
setScope(Scope * sc)434 void Import::setScope(Scope *sc)
435 {
436     Dsymbol::setScope(sc);
437     if (aliasdecls.dim)
438     {
439         if (!mod)
440             importAll(sc);
441 
442         sc = sc->push(mod);
443         sc->protection = protection;
444         for (size_t i = 0; i < aliasdecls.dim; i++)
445         {
446             AliasDeclaration *ad = aliasdecls[i];
447             ad->setScope(sc);
448         }
449         sc = sc->pop();
450     }
451 }
452 
search(const Loc & loc,Identifier * ident,int flags)453 Dsymbol *Import::search(const Loc &loc, Identifier *ident, int flags)
454 {
455     //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
456 
457     if (!pkg)
458     {
459         load(NULL);
460         mod->importAll(NULL);
461         mod->semantic(NULL);
462     }
463 
464     // Forward it to the package/module
465     return pkg->search(loc, ident, flags);
466 }
467 
overloadInsert(Dsymbol * s)468 bool Import::overloadInsert(Dsymbol *s)
469 {
470     /* Allow multiple imports with the same package base, but disallow
471      * alias collisions (Bugzilla 5412).
472      */
473     assert(ident && ident == s->ident);
474     Import *imp;
475     if (!aliasId && (imp = s->isImport()) != NULL && !imp->aliasId)
476         return true;
477     else
478         return false;
479 }
480