145
|
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
|
|
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
|
|
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
|
|
72 const char *Import::kind() const
|
|
73 {
|
|
74 return isstatic ? "static import" : "import";
|
|
75 }
|
|
76
|
|
77 Prot Import::prot()
|
|
78 {
|
|
79 return protection;
|
|
80 }
|
|
81
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 }
|