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