xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/dmd/dimport.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
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