1 /**
2 * A `Dsymbol` representing a renamed import.
3 *
4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d)
8 * Documentation: https://dlang.org/phobos/dmd_dimport.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dimport.d
10 */
11
12 module dmd.dimport;
13
14 import dmd.arraytypes;
15 import dmd.declaration;
16 import dmd.dmodule;
17 import dmd.dscope;
18 import dmd.dsymbol;
19 import dmd.dsymbolsem;
20 import dmd.errors;
21 import dmd.expression;
22 import dmd.globals;
23 import dmd.identifier;
24 import dmd.mtype;
25 import dmd.visitor;
26
27 /***********************************************************
28 */
29 extern (C++) final class Import : Dsymbol
30 {
31 /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
32 */
33 Identifiers* packages; // array of Identifier's representing packages
34 Identifier id; // module Identifier
35 Identifier aliasId;
36 int isstatic; // !=0 if static import
37 Prot protection;
38
39 // Pairs of alias=name to bind into current namespace
40 Identifiers names;
41 Identifiers aliases;
42
43 Module mod;
44 Package pkg; // leftmost package/module
45
46 // corresponding AliasDeclarations for alias=name pairs
47 AliasDeclarations aliasdecls;
48
49 extern (D) this(const ref Loc loc, Identifiers* packages, Identifier id, Identifier aliasId, int isstatic)
50 {
51 Identifier selectIdent()
52 {
53 // select Dsymbol identifier (bracketed)
54 if (aliasId)
55 {
56 // import [aliasId] = std.stdio;
57 return aliasId;
58 }
59 else if (packages && packages.dim)
60 {
61 // import [std].stdio;
62 return (*packages)[0];
63 }
64 else
65 {
66 // import [id];
67 return id;
68 }
69 }
70
71 super(loc, selectIdent());
72
73 assert(id);
74 version (none)
75 {
76 printf("Import::Import(");
77 if (packages && packages.dim)
78 {
79 for (size_t i = 0; i < packages.dim; i++)
80 {
81 Identifier id = (*packages)[i];
82 printf("%s.", id.toChars());
83 }
84 }
85 printf("%s)\n", id.toChars());
86 }
87 this.packages = packages;
88 this.id = id;
89 this.aliasId = aliasId;
90 this.isstatic = isstatic;
91 this.protection = Prot.Kind.private_; // default to private
92 }
93
94 extern (D) void addAlias(Identifier name, Identifier _alias)
95 {
96 if (isstatic)
97 error("cannot have an import bind list");
98 if (!aliasId)
99 this.ident = null; // make it an anonymous import
100 names.push(name);
101 aliases.push(_alias);
102 }
103
104 override const(char)* kind() const
105 {
106 return isstatic ? "static import" : "import";
107 }
108
109 override Prot prot() pure nothrow @nogc @safe
110 {
111 return protection;
112 }
113
114 // copy only syntax trees
115 override Dsymbol syntaxCopy(Dsymbol s)
116 {
117 assert(!s);
118 auto si = new Import(loc, packages, id, aliasId, isstatic);
119 si.comment = comment;
120 for (size_t i = 0; i < names.dim; i++)
121 {
122 si.addAlias(names[i], aliases[i]);
123 }
124 return si;
125 }
126
127 /*******************************
128 * Load this module.
129 * Returns:
130 * true for errors, false for success
131 */
132 bool load(Scope* sc)
133 {
134 //printf("Import::load('%s') %p\n", toPrettyChars(), this);
135 // See if existing module
136 const errors = global.errors;
137 DsymbolTable dst = Package.resolve(packages, null, &pkg);
138 version (none)
139 {
140 if (pkg && pkg.isModule())
141 {
142 .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars());
143 mod = pkg.isModule(); // Error recovery - treat as import of that module
144 return true;
145 }
146 }
147 Dsymbol s = dst.lookup(id);
148 if (s)
149 {
150 if (s.isModule())
151 mod = cast(Module)s;
152 else
153 {
154 if (s.isAliasDeclaration())
155 {
156 .error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars());
157 }
158 else if (Package p = s.isPackage())
159 {
160 if (p.isPkgMod == PKG.unknown)
161 {
162 uint preverrors = global.errors;
163 mod = Module.load(loc, packages, id);
164 if (!mod)
165 p.isPkgMod = PKG.package_;
166 else
167 {
168 // mod is a package.d, or a normal module which conflicts with the package name.
169 if (mod.isPackageFile)
170 mod.tag = p.tag; // reuse the same package tag
171 else
172 {
173 // show error if Module.load does not
174 if (preverrors == global.errors)
175 .error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars());
176 return true;
177 }
178 }
179 }
180 else
181 {
182 mod = p.isPackageMod();
183 }
184 if (!mod)
185 {
186 .error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars());
187 }
188 }
189 else if (pkg)
190 {
191 .error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars());
192 }
193 else
194 {
195 .error(loc, "can only import from a module, not from package `%s`", id.toChars());
196 }
197 }
198 }
199 if (!mod)
200 {
201 // Load module
202 mod = Module.load(loc, packages, id);
203 if (mod)
204 {
205 // id may be different from mod.ident, if so then insert alias
206 dst.insert(id, mod);
207 }
208 }
209 if (mod && !mod.importedFrom)
210 mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule;
211 if (!pkg)
212 {
213 if (mod && mod.isPackageFile)
214 {
215 // one level depth package.d file (import pkg; ./pkg/package.d)
216 // it's necessary to use the wrapping Package already created
217 pkg = mod.pkg;
218 }
219 else
220 pkg = mod;
221 }
222 //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
223 return global.errors != errors;
224 }
225
226 override void importAll(Scope* sc)
227 {
228 if (mod) return; // Already done
229 load(sc);
230 if (!mod) return; // Failed
231
232 if (sc.stc & STC.static_)
233 isstatic = true;
234 mod.importAll(null);
235 mod.checkImportDeprecation(loc, sc);
236 if (sc.explicitProtection)
237 protection = sc.protection;
238 if (!isstatic && !aliasId && !names.dim)
239 sc.scopesym.importScope(mod, protection);
240 }
241
242 override Dsymbol toAlias()
243 {
244 if (aliasId)
245 return mod;
246 return this;
247 }
248
249 /*****************************
250 * Add import to sd's symbol table.
251 */
252 override void addMember(Scope* sc, ScopeDsymbol sd)
253 {
254 //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc);
255 if (names.dim == 0)
256 return Dsymbol.addMember(sc, sd);
257 if (aliasId)
258 Dsymbol.addMember(sc, sd);
259 /* Instead of adding the import to sd's symbol table,
260 * add each of the alias=name pairs
261 */
262 for (size_t i = 0; i < names.dim; i++)
263 {
264 Identifier name = names[i];
265 Identifier _alias = aliases[i];
266 if (!_alias)
267 _alias = name;
268 auto tname = new TypeIdentifier(loc, name);
269 auto ad = new AliasDeclaration(loc, _alias, tname);
270 ad._import = this;
271 ad.addMember(sc, sd);
272 aliasdecls.push(ad);
273 }
274 }
275
276 override void setScope(Scope* sc)
277 {
278 Dsymbol.setScope(sc);
279 if (aliasdecls.dim)
280 {
281 if (!mod)
282 importAll(sc);
283
284 sc = sc.push(mod);
285 sc.protection = protection;
286 foreach (ad; aliasdecls)
287 ad.setScope(sc);
288 sc = sc.pop();
289 }
290 }
291
292 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
293 {
294 //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
295 if (!pkg)
296 {
297 load(null);
298 mod.importAll(null);
299 mod.dsymbolSemantic(null);
300 }
301 // Forward it to the package/module
302 return pkg.search(loc, ident, flags);
303 }
304
305 override bool overloadInsert(Dsymbol s)
306 {
307 /* Allow multiple imports with the same package base, but disallow
308 * alias collisions
309 * https://issues.dlang.org/show_bug.cgi?id=5412
310 */
311 assert(ident && ident == s.ident);
312 Import imp;
313 if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId)
314 return true;
315 else
316 return false;
317 }
318
319 override inout(Import) isImport() inout
320 {
321 return this;
322 }
323
324 override void accept(Visitor v)
325 {
326 v.visit(this);
327 }
328 }