]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | |
2 | /* Compiler implementation of the D programming language | |
8e788ac6 | 3 | * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved |
b4c522fa IB |
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/dsymbol.c | |
9 | */ | |
10 | ||
f9ab59ff | 11 | #include "root/dsystem.h" |
b4c522fa IB |
12 | #include "root/rmem.h" |
13 | #include "root/speller.h" | |
14 | #include "root/aav.h" | |
15 | ||
16 | #include "mars.h" | |
17 | #include "dsymbol.h" | |
18 | #include "aggregate.h" | |
19 | #include "identifier.h" | |
20 | #include "module.h" | |
21 | #include "mtype.h" | |
22 | #include "expression.h" | |
23 | #include "statement.h" | |
24 | #include "declaration.h" | |
25 | #include "id.h" | |
26 | #include "scope.h" | |
27 | #include "init.h" | |
28 | #include "import.h" | |
29 | #include "template.h" | |
30 | #include "attrib.h" | |
31 | #include "enum.h" | |
32 | #include "lexer.h" | |
9503d7b1 | 33 | #include "nspace.h" |
b4c522fa IB |
34 | |
35 | bool symbolIsVisible(Dsymbol *origin, Dsymbol *s); | |
36 | typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); | |
37 | int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL); | |
38 | Expression *semantic(Expression *e, Scope *sc); | |
39 | ||
40 | ||
41 | /****************************** Dsymbol ******************************/ | |
42 | ||
43 | Dsymbol::Dsymbol() | |
44 | { | |
45 | //printf("Dsymbol::Dsymbol(%p)\n", this); | |
46 | this->ident = NULL; | |
47 | this->parent = NULL; | |
48 | this->csym = NULL; | |
49 | this->isym = NULL; | |
50 | this->loc = Loc(); | |
51 | this->comment = NULL; | |
52 | this->_scope = NULL; | |
53 | this->prettystring = NULL; | |
54 | this->semanticRun = PASSinit; | |
55 | this->errors = false; | |
56 | this->depdecl = NULL; | |
57 | this->userAttribDecl = NULL; | |
58 | this->ddocUnittest = NULL; | |
59 | } | |
60 | ||
61 | Dsymbol::Dsymbol(Identifier *ident) | |
62 | { | |
63 | //printf("Dsymbol::Dsymbol(%p, ident)\n", this); | |
64 | this->ident = ident; | |
65 | this->parent = NULL; | |
66 | this->csym = NULL; | |
67 | this->isym = NULL; | |
68 | this->loc = Loc(); | |
69 | this->comment = NULL; | |
70 | this->_scope = NULL; | |
71 | this->prettystring = NULL; | |
72 | this->semanticRun = PASSinit; | |
73 | this->errors = false; | |
74 | this->depdecl = NULL; | |
75 | this->userAttribDecl = NULL; | |
76 | this->ddocUnittest = NULL; | |
77 | } | |
78 | ||
79 | Dsymbol *Dsymbol::create(Identifier *ident) | |
80 | { | |
81 | return new Dsymbol(ident); | |
82 | } | |
83 | ||
84 | bool Dsymbol::equals(RootObject *o) | |
85 | { | |
86 | if (this == o) | |
87 | return true; | |
88 | Dsymbol *s = (Dsymbol *)(o); | |
89 | // Overload sets don't have an ident | |
90 | if (s && ident && s->ident && ident->equals(s->ident)) | |
91 | return true; | |
92 | return false; | |
93 | } | |
94 | ||
95 | /************************************** | |
96 | * Copy the syntax. | |
97 | * Used for template instantiations. | |
98 | * If s is NULL, allocate the new object, otherwise fill it in. | |
99 | */ | |
100 | ||
101 | Dsymbol *Dsymbol::syntaxCopy(Dsymbol *) | |
102 | { | |
103 | print(); | |
104 | printf("%s %s\n", kind(), toChars()); | |
105 | assert(0); | |
106 | return NULL; | |
107 | } | |
108 | ||
109 | /************************************** | |
110 | * Determine if this symbol is only one. | |
111 | * Returns: | |
112 | * false, *ps = NULL: There are 2 or more symbols | |
113 | * true, *ps = NULL: There are zero symbols | |
114 | * true, *ps = symbol: The one and only one symbol | |
115 | */ | |
116 | ||
117 | bool Dsymbol::oneMember(Dsymbol **ps, Identifier *) | |
118 | { | |
119 | //printf("Dsymbol::oneMember()\n"); | |
120 | *ps = this; | |
121 | return true; | |
122 | } | |
123 | ||
124 | /***************************************** | |
125 | * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. | |
126 | */ | |
127 | ||
128 | bool Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) | |
129 | { | |
2cbc99d1 | 130 | //printf("Dsymbol::oneMembers() %d\n", members ? members->length : 0); |
b4c522fa IB |
131 | Dsymbol *s = NULL; |
132 | ||
133 | if (members) | |
134 | { | |
2cbc99d1 | 135 | for (size_t i = 0; i < members->length; i++) |
b4c522fa IB |
136 | { |
137 | Dsymbol *sx = (*members)[i]; | |
138 | bool x = sx->oneMember(ps, ident); | |
139 | //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); | |
140 | if (!x) | |
141 | { | |
142 | //printf("\tfalse 1\n"); | |
143 | assert(*ps == NULL); | |
144 | return false; | |
145 | } | |
146 | if (*ps) | |
147 | { | |
148 | assert(ident); | |
149 | if (!(*ps)->ident || !(*ps)->ident->equals(ident)) | |
150 | continue; | |
151 | if (!s) | |
152 | s = *ps; | |
153 | else if (s->isOverloadable() && (*ps)->isOverloadable()) | |
154 | { | |
155 | // keep head of overload set | |
156 | FuncDeclaration *f1 = s->isFuncDeclaration(); | |
157 | FuncDeclaration *f2 = (*ps)->isFuncDeclaration(); | |
158 | if (f1 && f2) | |
159 | { | |
160 | assert(!f1->isFuncAliasDeclaration()); | |
161 | assert(!f2->isFuncAliasDeclaration()); | |
162 | for (; f1 != f2; f1 = f1->overnext0) | |
163 | { | |
164 | if (f1->overnext0 == NULL) | |
165 | { | |
166 | f1->overnext0 = f2; | |
167 | break; | |
168 | } | |
169 | } | |
170 | } | |
171 | } | |
172 | else // more than one symbol | |
173 | { | |
174 | *ps = NULL; | |
175 | //printf("\tfalse 2\n"); | |
176 | return false; | |
177 | } | |
178 | } | |
179 | } | |
180 | } | |
181 | *ps = s; // s is the one symbol, NULL if none | |
182 | //printf("\ttrue\n"); | |
183 | return true; | |
184 | } | |
185 | ||
186 | /***************************************** | |
187 | * Is Dsymbol a variable that contains pointers? | |
188 | */ | |
189 | ||
190 | bool Dsymbol::hasPointers() | |
191 | { | |
192 | //printf("Dsymbol::hasPointers() %s\n", toChars()); | |
193 | return false; | |
194 | } | |
195 | ||
196 | bool Dsymbol::hasStaticCtorOrDtor() | |
197 | { | |
198 | //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); | |
199 | return false; | |
200 | } | |
201 | ||
202 | void Dsymbol::setFieldOffset(AggregateDeclaration *, unsigned *, bool) | |
203 | { | |
204 | } | |
205 | ||
206 | Identifier *Dsymbol::getIdent() | |
207 | { | |
208 | return ident; | |
209 | } | |
210 | ||
211 | const char *Dsymbol::toChars() | |
212 | { | |
213 | return ident ? ident->toChars() : "__anonymous"; | |
214 | } | |
215 | ||
216 | const char *Dsymbol::toPrettyCharsHelper() | |
217 | { | |
218 | return toChars(); | |
219 | } | |
220 | ||
221 | const char *Dsymbol::toPrettyChars(bool QualifyTypes) | |
222 | { | |
223 | if (prettystring && !QualifyTypes) | |
224 | return (const char *)prettystring; | |
225 | ||
226 | //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); | |
227 | if (!parent) | |
228 | { | |
229 | const char *s = toChars(); | |
230 | if (!QualifyTypes) | |
231 | prettystring = (const utf8_t *)s; | |
232 | return s; | |
233 | } | |
234 | ||
235 | // Computer number of components | |
236 | size_t complength = 0; | |
237 | for (Dsymbol *p = this; p; p = p->parent) | |
238 | ++complength; | |
239 | ||
240 | // Allocate temporary array comp[] | |
f9ab59ff | 241 | const char **comp = (const char **)mem.xmalloc(complength * sizeof(char**)); |
b4c522fa IB |
242 | |
243 | // Fill in comp[] and compute length of final result | |
244 | size_t length = 0; | |
245 | int i = 0; | |
246 | for (Dsymbol *p = this; p; p = p->parent) | |
247 | { | |
248 | const char *s = QualifyTypes ? p->toPrettyCharsHelper() : p->toChars(); | |
249 | const size_t len = strlen(s); | |
250 | comp[i] = s; | |
251 | ++i; | |
252 | length += len + 1; | |
253 | } | |
254 | ||
255 | char *s = (char *)mem.xmalloc(length); | |
256 | char *q = s + length - 1; | |
257 | *q = 0; | |
258 | for (size_t j = 0; j < complength; j++) | |
259 | { | |
260 | const char *t = comp[j]; | |
261 | const size_t len = strlen(t); | |
262 | q -= len; | |
263 | memcpy(q, t, len); | |
264 | if (q == s) | |
265 | break; | |
266 | *--q = '.'; | |
267 | } | |
268 | free(comp); | |
269 | if (!QualifyTypes) | |
270 | prettystring = (utf8_t *)s; | |
271 | return s; | |
272 | } | |
273 | ||
274 | Loc& Dsymbol::getLoc() | |
275 | { | |
276 | if (!loc.filename) // avoid bug 5861. | |
277 | { | |
278 | Module *m = getModule(); | |
279 | ||
280 | if (m && m->srcfile) | |
281 | loc.filename = m->srcfile->toChars(); | |
282 | } | |
283 | return loc; | |
284 | } | |
285 | ||
286 | const char *Dsymbol::locToChars() | |
287 | { | |
288 | return getLoc().toChars(); | |
289 | } | |
290 | ||
f9ab59ff | 291 | const char *Dsymbol::kind() const |
b4c522fa IB |
292 | { |
293 | return "symbol"; | |
294 | } | |
295 | ||
296 | /********************************* | |
297 | * If this symbol is really an alias for another, | |
298 | * return that other. | |
299 | * If needed, semantic() is invoked due to resolve forward reference. | |
300 | */ | |
301 | Dsymbol *Dsymbol::toAlias() | |
302 | { | |
303 | return this; | |
304 | } | |
305 | ||
306 | /********************************* | |
307 | * Resolve recursive tuple expansion in eponymous template. | |
308 | */ | |
309 | Dsymbol *Dsymbol::toAlias2() | |
310 | { | |
311 | return toAlias(); | |
312 | } | |
313 | ||
9503d7b1 IB |
314 | /** |
315 | * `pastMixin` returns the enclosing symbol if this is a template mixin. | |
316 | * | |
317 | * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that | |
318 | * are mangleOnly. | |
319 | * | |
320 | * See also `parent`, `toParent`, `toParent2` and `toParent3`. | |
321 | */ | |
b4c522fa IB |
322 | Dsymbol *Dsymbol::pastMixin() |
323 | { | |
b4c522fa | 324 | //printf("Dsymbol::pastMixin() %s\n", toChars()); |
5b74dd0a IB |
325 | if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol()) |
326 | return this; | |
327 | if (!parent) | |
328 | return NULL; | |
329 | return parent->pastMixin(); | |
b4c522fa IB |
330 | } |
331 | ||
9503d7b1 IB |
332 | /// ditto |
333 | Dsymbol *Dsymbol::pastMixinAndNspace() | |
334 | { | |
335 | //printf("Dsymbol::pastMixinAndNspace() %s\n", toChars()); | |
336 | Nspace *ns = isNspace(); | |
5b74dd0a IB |
337 | if (!(ns && ns->mangleOnly) && |
338 | !isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol()) | |
9503d7b1 IB |
339 | return this; |
340 | if (!parent) | |
341 | return NULL; | |
342 | return parent->pastMixinAndNspace(); | |
343 | } | |
344 | ||
b4c522fa IB |
345 | /********************************** |
346 | * `parent` field returns a lexically enclosing scope symbol this is a member of. | |
347 | * | |
348 | * `toParent()` returns a logically enclosing scope symbol this is a member of. | |
9503d7b1 | 349 | * It skips over TemplateMixin's and Nspaces that are mangleOnly. |
b4c522fa IB |
350 | * |
351 | * `toParent2()` returns an enclosing scope symbol this is living at runtime. | |
352 | * It skips over both TemplateInstance's and TemplateMixin's. | |
353 | * It's used when looking for the 'this' pointer of the enclosing function/class. | |
354 | * | |
9503d7b1 IB |
355 | * `toParent3()` returns a logically enclosing scope symbol this is a member of. |
356 | * It skips over TemplateMixin's. | |
357 | * | |
b4c522fa IB |
358 | * Examples: |
359 | * module mod; | |
360 | * template Foo(alias a) { mixin Bar!(); } | |
361 | * mixin template Bar() { | |
362 | * public { // ProtDeclaration | |
363 | * void baz() { a = 2; } | |
364 | * } | |
365 | * } | |
366 | * void test() { | |
367 | * int v = 1; | |
368 | * alias foo = Foo!(v); | |
369 | * foo.baz(); | |
370 | * assert(v == 2); | |
371 | * } | |
372 | * | |
373 | * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()') | |
374 | * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()') | |
375 | * // s.toParent() == TemplateInstance('mod.test.Foo!()') | |
376 | * // s.toParent2() == FuncDeclaration('mod.test') | |
377 | */ | |
378 | Dsymbol *Dsymbol::toParent() | |
379 | { | |
9503d7b1 | 380 | return parent ? parent->pastMixinAndNspace() : NULL; |
b4c522fa IB |
381 | } |
382 | ||
383 | /// ditto | |
384 | Dsymbol *Dsymbol::toParent2() | |
385 | { | |
5b74dd0a IB |
386 | if (!parent || |
387 | (!parent->isTemplateInstance() && | |
388 | !parent->isForwardingAttribDeclaration() && | |
389 | !parent->isForwardingScopeDsymbol())) | |
390 | return parent; | |
391 | return parent->toParent2(); | |
b4c522fa IB |
392 | } |
393 | ||
9503d7b1 IB |
394 | /// ditto |
395 | Dsymbol *Dsymbol::toParent3() | |
396 | { | |
397 | return parent ? parent->pastMixin() : NULL; | |
398 | } | |
399 | ||
b4c522fa IB |
400 | TemplateInstance *Dsymbol::isInstantiated() |
401 | { | |
402 | for (Dsymbol *s = parent; s; s = s->parent) | |
403 | { | |
404 | TemplateInstance *ti = s->isTemplateInstance(); | |
405 | if (ti && !ti->isTemplateMixin()) | |
406 | return ti; | |
407 | } | |
408 | return NULL; | |
409 | } | |
410 | ||
411 | // Check if this function is a member of a template which has only been | |
412 | // instantiated speculatively, eg from inside is(typeof()). | |
413 | // Return the speculative template instance it is part of, | |
414 | // or NULL if not speculative. | |
415 | TemplateInstance *Dsymbol::isSpeculative() | |
416 | { | |
417 | Dsymbol *par = parent; | |
418 | while (par) | |
419 | { | |
420 | TemplateInstance *ti = par->isTemplateInstance(); | |
421 | if (ti && ti->gagged) | |
422 | return ti; | |
423 | par = par->toParent(); | |
424 | } | |
425 | return NULL; | |
426 | } | |
427 | ||
428 | Ungag Dsymbol::ungagSpeculative() | |
429 | { | |
430 | unsigned oldgag = global.gag; | |
431 | ||
432 | if (global.gag && !isSpeculative() && !toParent2()->isFuncDeclaration()) | |
433 | global.gag = 0; | |
434 | ||
435 | return Ungag(oldgag); | |
436 | } | |
437 | ||
438 | bool Dsymbol::isAnonymous() | |
439 | { | |
440 | return ident == NULL; | |
441 | } | |
442 | ||
443 | /************************************* | |
444 | * Set scope for future semantic analysis so we can | |
445 | * deal better with forward references. | |
446 | */ | |
447 | ||
448 | void Dsymbol::setScope(Scope *sc) | |
449 | { | |
450 | //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc); | |
451 | if (!sc->nofree) | |
452 | sc->setNoFree(); // may need it even after semantic() finishes | |
453 | _scope = sc; | |
454 | if (sc->depdecl) | |
455 | depdecl = sc->depdecl; | |
456 | ||
457 | if (!userAttribDecl) | |
458 | userAttribDecl = sc->userAttribDecl; | |
459 | } | |
460 | ||
461 | void Dsymbol::importAll(Scope *) | |
462 | { | |
463 | } | |
464 | ||
465 | /************************************* | |
466 | * Does semantic analysis on the public face of declarations. | |
467 | */ | |
468 | ||
469 | void Dsymbol::semantic(Scope *) | |
470 | { | |
471 | error("%p has no semantic routine", this); | |
472 | } | |
473 | ||
474 | /************************************* | |
475 | * Does semantic analysis on initializers and members of aggregates. | |
476 | */ | |
477 | ||
478 | void Dsymbol::semantic2(Scope *) | |
479 | { | |
480 | // Most Dsymbols have no further semantic analysis needed | |
481 | } | |
482 | ||
483 | /************************************* | |
484 | * Does semantic analysis on function bodies. | |
485 | */ | |
486 | ||
487 | void Dsymbol::semantic3(Scope *) | |
488 | { | |
489 | // Most Dsymbols have no further semantic analysis needed | |
490 | } | |
491 | ||
492 | /********************************************* | |
493 | * Search for ident as member of s. | |
494 | * Params: | |
495 | * loc = location to print for error messages | |
496 | * ident = identifier to search for | |
497 | * flags = IgnoreXXXX | |
498 | * Returns: | |
499 | * NULL if not found | |
500 | */ | |
501 | ||
502 | Dsymbol *Dsymbol::search(const Loc &, Identifier *, int) | |
503 | { | |
504 | //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); | |
505 | return NULL; | |
506 | } | |
507 | ||
508 | /*************************************************** | |
509 | * Search for symbol with correct spelling. | |
510 | */ | |
511 | ||
512 | void *symbol_search_fp(void *arg, const char *seed, int *cost) | |
513 | { | |
514 | /* If not in the lexer's string table, it certainly isn't in the symbol table. | |
515 | * Doing this first is a lot faster. | |
516 | */ | |
517 | size_t len = strlen(seed); | |
518 | if (!len) | |
519 | return NULL; | |
520 | Identifier *id = Identifier::lookup(seed, len); | |
521 | if (!id) | |
522 | return NULL; | |
523 | ||
524 | *cost = 0; | |
525 | Dsymbol *s = (Dsymbol *)arg; | |
526 | Module::clearCache(); | |
527 | return (void *)s->search(Loc(), id, IgnoreErrors); | |
528 | } | |
529 | ||
530 | Dsymbol *Dsymbol::search_correct(Identifier *ident) | |
531 | { | |
532 | if (global.gag) | |
533 | return NULL; // don't do it for speculative compiles; too time consuming | |
534 | ||
535 | return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, (void *)this, idchars); | |
536 | } | |
537 | ||
538 | /*************************************** | |
539 | * Search for identifier id as a member of 'this'. | |
540 | * id may be a template instance. | |
541 | * Returns: | |
542 | * symbol found, NULL if not | |
543 | */ | |
544 | Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id) | |
545 | { | |
546 | //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); | |
547 | Dsymbol *s = toAlias(); | |
548 | Dsymbol *sm; | |
549 | ||
550 | if (Declaration *d = s->isDeclaration()) | |
551 | { | |
552 | if (d->inuse) | |
553 | { | |
554 | ::error(loc, "circular reference to '%s'", d->toPrettyChars()); | |
555 | return NULL; | |
556 | } | |
557 | } | |
558 | ||
559 | switch (id->dyncast()) | |
560 | { | |
561 | case DYNCAST_IDENTIFIER: | |
562 | sm = s->search(loc, (Identifier *)id); | |
563 | break; | |
564 | ||
565 | case DYNCAST_DSYMBOL: | |
566 | { | |
567 | // It's a template instance | |
568 | //printf("\ttemplate instance id\n"); | |
569 | Dsymbol *st = (Dsymbol *)id; | |
570 | TemplateInstance *ti = st->isTemplateInstance(); | |
571 | sm = s->search(loc, ti->name); | |
572 | if (!sm) | |
573 | { | |
574 | sm = s->search_correct(ti->name); | |
575 | if (sm) | |
576 | ::error(loc, "template identifier '%s' is not a member of %s '%s', did you mean %s '%s'?", | |
577 | ti->name->toChars(), s->kind(), s->toPrettyChars(), sm->kind(), sm->toChars()); | |
578 | else | |
579 | ::error(loc, "template identifier '%s' is not a member of %s '%s'", | |
580 | ti->name->toChars(), s->kind(), s->toPrettyChars()); | |
581 | return NULL; | |
582 | } | |
583 | sm = sm->toAlias(); | |
584 | TemplateDeclaration *td = sm->isTemplateDeclaration(); | |
585 | if (!td) | |
586 | { | |
587 | ::error(loc, "%s.%s is not a template, it is a %s", s->toPrettyChars(), ti->name->toChars(), sm->kind()); | |
588 | return NULL; | |
589 | } | |
590 | ti->tempdecl = td; | |
591 | if (!ti->semanticRun) | |
592 | ti->semantic(sc); | |
593 | sm = ti->toAlias(); | |
594 | break; | |
595 | } | |
596 | ||
597 | case DYNCAST_TYPE: | |
598 | case DYNCAST_EXPRESSION: | |
599 | default: | |
600 | assert(0); | |
601 | } | |
602 | return sm; | |
603 | } | |
604 | ||
605 | bool Dsymbol::overloadInsert(Dsymbol *) | |
606 | { | |
607 | //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); | |
608 | return false; | |
609 | } | |
610 | ||
611 | d_uns64 Dsymbol::size(Loc) | |
612 | { | |
613 | error("Dsymbol '%s' has no size", toChars()); | |
614 | return SIZE_INVALID; | |
615 | } | |
616 | ||
617 | bool Dsymbol::isforwardRef() | |
618 | { | |
619 | return false; | |
620 | } | |
621 | ||
622 | AggregateDeclaration *Dsymbol::isThis() | |
623 | { | |
624 | return NULL; | |
625 | } | |
626 | ||
627 | bool Dsymbol::isExport() const | |
628 | { | |
629 | return false; | |
630 | } | |
631 | ||
632 | bool Dsymbol::isImportedSymbol() const | |
633 | { | |
634 | return false; | |
635 | } | |
636 | ||
637 | bool Dsymbol::isDeprecated() | |
638 | { | |
639 | return false; | |
640 | } | |
641 | ||
642 | bool Dsymbol::isOverloadable() | |
643 | { | |
644 | return false; | |
645 | } | |
646 | ||
647 | LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? | |
648 | { | |
649 | return NULL; | |
650 | } | |
651 | ||
652 | /// Returns an AggregateDeclaration when toParent() is that. | |
653 | AggregateDeclaration *Dsymbol::isMember() | |
654 | { | |
655 | //printf("Dsymbol::isMember() %s\n", toChars()); | |
656 | Dsymbol *parent = toParent(); | |
657 | //printf("parent is %s %s\n", parent->kind(), parent->toChars()); | |
658 | return parent ? parent->isAggregateDeclaration() : NULL; | |
659 | } | |
660 | ||
661 | /// Returns an AggregateDeclaration when toParent2() is that. | |
662 | AggregateDeclaration *Dsymbol::isMember2() | |
663 | { | |
664 | //printf("Dsymbol::isMember2() %s\n", toChars()); | |
665 | Dsymbol *parent = toParent2(); | |
666 | //printf("parent is %s %s\n", parent->kind(), parent->toChars()); | |
667 | return parent ? parent->isAggregateDeclaration() : NULL; | |
668 | } | |
669 | ||
670 | // is this a member of a ClassDeclaration? | |
671 | ClassDeclaration *Dsymbol::isClassMember() | |
672 | { | |
673 | AggregateDeclaration *ad = isMember(); | |
674 | return ad ? ad->isClassDeclaration() : NULL; | |
675 | } | |
676 | ||
677 | Type *Dsymbol::getType() | |
678 | { | |
679 | return NULL; | |
680 | } | |
681 | ||
682 | bool Dsymbol::needThis() | |
683 | { | |
684 | return false; | |
685 | } | |
686 | ||
687 | /********************************* | |
688 | * Iterate this dsymbol or members of this scoped dsymbol, then | |
689 | * call `fp` with the found symbol and `param`. | |
690 | * Params: | |
691 | * fp = function pointer to process the iterated symbol. | |
692 | * If it returns nonzero, the iteration will be aborted. | |
693 | * param = a parameter passed to fp. | |
694 | * Returns: | |
695 | * nonzero if the iteration is aborted by the return value of fp, | |
696 | * or 0 if it's completed. | |
697 | */ | |
698 | int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) | |
699 | { | |
700 | return (*fp)(this, param); | |
701 | } | |
702 | ||
703 | void Dsymbol::addMember(Scope *, ScopeDsymbol *sds) | |
704 | { | |
705 | //printf("Dsymbol::addMember('%s')\n", toChars()); | |
706 | //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds->toChars()); | |
707 | //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds->symtab = %p)\n", this, toChars(), sds, sds->symtab); | |
708 | parent = sds; | |
709 | if (!isAnonymous()) // no name, so can't add it to symbol table | |
710 | { | |
711 | if (!sds->symtabInsert(this)) // if name is already defined | |
712 | { | |
713 | Dsymbol *s2 = sds->symtabLookup(this, ident); | |
714 | if (!s2->overloadInsert(this)) | |
715 | { | |
716 | sds->multiplyDefined(Loc(), this, s2); | |
717 | errors = true; | |
718 | } | |
719 | } | |
720 | if (sds->isAggregateDeclaration() || sds->isEnumDeclaration()) | |
721 | { | |
722 | if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof) | |
723 | { | |
724 | error(".%s property cannot be redefined", ident->toChars()); | |
725 | errors = true; | |
726 | } | |
727 | } | |
728 | } | |
729 | } | |
730 | ||
731 | void Dsymbol::error(const char *format, ...) | |
732 | { | |
733 | va_list ap; | |
734 | va_start(ap, format); | |
735 | ::verror(getLoc(), format, ap, kind(), toPrettyChars()); | |
736 | va_end(ap); | |
737 | } | |
738 | ||
739 | void Dsymbol::error(Loc loc, const char *format, ...) | |
740 | { | |
741 | va_list ap; | |
742 | va_start(ap, format); | |
743 | ::verror(loc, format, ap, kind(), toPrettyChars()); | |
744 | va_end(ap); | |
745 | } | |
746 | ||
747 | void Dsymbol::deprecation(Loc loc, const char *format, ...) | |
748 | { | |
749 | va_list ap; | |
750 | va_start(ap, format); | |
751 | ::vdeprecation(loc, format, ap, kind(), toPrettyChars()); | |
752 | va_end(ap); | |
753 | } | |
754 | ||
755 | void Dsymbol::deprecation(const char *format, ...) | |
756 | { | |
757 | va_list ap; | |
758 | va_start(ap, format); | |
759 | ::vdeprecation(getLoc(), format, ap, kind(), toPrettyChars()); | |
760 | va_end(ap); | |
761 | } | |
762 | ||
763 | void Dsymbol::checkDeprecated(Loc loc, Scope *sc) | |
764 | { | |
765 | if (global.params.useDeprecated != DIAGNOSTICoff && isDeprecated()) | |
766 | { | |
767 | // Don't complain if we're inside a deprecated symbol's scope | |
768 | for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) | |
769 | { | |
770 | if (sp->isDeprecated()) | |
771 | goto L1; | |
772 | } | |
773 | ||
774 | for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) | |
775 | { | |
776 | if (sc2->scopesym && sc2->scopesym->isDeprecated()) | |
777 | goto L1; | |
778 | ||
779 | // If inside a StorageClassDeclaration that is deprecated | |
780 | if (sc2->stc & STCdeprecated) | |
781 | goto L1; | |
782 | } | |
783 | ||
784 | const char *message = NULL; | |
785 | for (Dsymbol *p = this; p; p = p->parent) | |
786 | { | |
787 | message = p->depdecl ? p->depdecl->getMessage() : NULL; | |
788 | if (message) | |
789 | break; | |
790 | } | |
791 | ||
792 | if (message) | |
793 | deprecation(loc, "is deprecated - %s", message); | |
794 | else | |
795 | deprecation(loc, "is deprecated"); | |
796 | } | |
797 | ||
798 | L1: | |
799 | Declaration *d = isDeclaration(); | |
800 | if (d && d->storage_class & STCdisable) | |
801 | { | |
802 | if (!(sc->func && sc->func->storage_class & STCdisable)) | |
803 | { | |
804 | if (d->toParent() && d->isPostBlitDeclaration()) | |
805 | d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); | |
806 | else | |
807 | error(loc, "is not callable because it is annotated with @disable"); | |
808 | } | |
809 | } | |
810 | } | |
811 | ||
812 | /********************************** | |
813 | * Determine which Module a Dsymbol is in. | |
814 | */ | |
815 | ||
816 | Module *Dsymbol::getModule() | |
817 | { | |
818 | //printf("Dsymbol::getModule()\n"); | |
819 | if (TemplateInstance *ti = isInstantiated()) | |
820 | return ti->tempdecl->getModule(); | |
821 | ||
822 | Dsymbol *s = this; | |
823 | while (s) | |
824 | { | |
825 | //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); | |
826 | Module *m = s->isModule(); | |
827 | if (m) | |
828 | return m; | |
829 | s = s->parent; | |
830 | } | |
831 | return NULL; | |
832 | } | |
833 | ||
834 | /********************************** | |
835 | * Determine which Module a Dsymbol is in, as far as access rights go. | |
836 | */ | |
837 | ||
838 | Module *Dsymbol::getAccessModule() | |
839 | { | |
840 | //printf("Dsymbol::getAccessModule()\n"); | |
841 | if (TemplateInstance *ti = isInstantiated()) | |
842 | return ti->tempdecl->getAccessModule(); | |
843 | ||
844 | Dsymbol *s = this; | |
845 | while (s) | |
846 | { | |
847 | //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); | |
848 | Module *m = s->isModule(); | |
849 | if (m) | |
850 | return m; | |
851 | TemplateInstance *ti = s->isTemplateInstance(); | |
852 | if (ti && ti->enclosing) | |
853 | { | |
854 | /* Because of local template instantiation, the parent isn't where the access | |
855 | * rights come from - it's the template declaration | |
856 | */ | |
857 | s = ti->tempdecl; | |
858 | } | |
859 | else | |
860 | s = s->parent; | |
861 | } | |
862 | return NULL; | |
863 | } | |
864 | ||
865 | /************************************* | |
866 | */ | |
867 | ||
868 | Prot Dsymbol::prot() | |
869 | { | |
0a2ee409 | 870 | return Prot(Prot::public_); |
b4c522fa IB |
871 | } |
872 | ||
873 | /************************************* | |
874 | * Do syntax copy of an array of Dsymbol's. | |
875 | */ | |
876 | ||
877 | Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) | |
878 | { | |
879 | ||
880 | Dsymbols *b = NULL; | |
881 | if (a) | |
882 | { | |
883 | b = a->copy(); | |
2cbc99d1 | 884 | for (size_t i = 0; i < b->length; i++) |
b4c522fa IB |
885 | { |
886 | (*b)[i] = (*b)[i]->syntaxCopy(NULL); | |
887 | } | |
888 | } | |
889 | return b; | |
890 | } | |
891 | ||
892 | /**************************************** | |
893 | * Add documentation comment to Dsymbol. | |
894 | * Ignore NULL comments. | |
895 | */ | |
896 | ||
897 | void Dsymbol::addComment(const utf8_t *comment) | |
898 | { | |
899 | //if (comment) | |
900 | //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); | |
901 | ||
902 | if (!this->comment) | |
903 | this->comment = comment; | |
904 | else if (comment && strcmp((const char *)comment, (const char *)this->comment) != 0) | |
905 | { // Concatenate the two | |
906 | this->comment = Lexer::combineComments(this->comment, comment); | |
907 | } | |
908 | } | |
909 | ||
910 | /**************************************** | |
911 | * Returns true if this symbol is defined in a non-root module without instantiation. | |
912 | */ | |
913 | bool Dsymbol::inNonRoot() | |
914 | { | |
915 | Dsymbol *s = parent; | |
916 | for (; s; s = s->toParent()) | |
917 | { | |
918 | if (s->isTemplateInstance()) | |
919 | { | |
920 | return false; | |
921 | } | |
922 | if (Module *m = s->isModule()) | |
923 | { | |
924 | if (!m->isRoot()) | |
925 | return true; | |
926 | break; | |
927 | } | |
928 | } | |
929 | return false; | |
930 | } | |
931 | ||
932 | /********************************* OverloadSet ****************************/ | |
933 | ||
934 | OverloadSet::OverloadSet(Identifier *ident, OverloadSet *os) | |
935 | : Dsymbol(ident) | |
936 | { | |
937 | if (os) | |
938 | { | |
2cbc99d1 | 939 | for (size_t i = 0; i < os->a.length; i++) |
b4c522fa IB |
940 | { |
941 | a.push(os->a[i]); | |
942 | } | |
943 | } | |
944 | } | |
945 | ||
946 | void OverloadSet::push(Dsymbol *s) | |
947 | { | |
948 | a.push(s); | |
949 | } | |
950 | ||
f9ab59ff | 951 | const char *OverloadSet::kind() const |
b4c522fa IB |
952 | { |
953 | return "overloadset"; | |
954 | } | |
955 | ||
956 | ||
5b74dd0a IB |
957 | /********************************* ForwardingScopeDsymbol ******************/ |
958 | ||
959 | ForwardingScopeDsymbol::ForwardingScopeDsymbol(ScopeDsymbol *forward) | |
960 | : ScopeDsymbol() | |
961 | { | |
962 | this->forward = forward; | |
963 | } | |
964 | ||
965 | Dsymbol *ForwardingScopeDsymbol::symtabInsert(Dsymbol *s) | |
966 | { | |
967 | assert(forward); | |
968 | if (Declaration *d = s->isDeclaration()) | |
969 | { | |
970 | if (d->storage_class & STClocal) | |
971 | { | |
972 | // Symbols with storage class STClocal are not | |
973 | // forwarded, but stored in the local symbol | |
974 | // table. (Those are the `static foreach` variables.) | |
975 | if (!symtab) | |
976 | { | |
977 | symtab = new DsymbolTable(); | |
978 | } | |
979 | return ScopeDsymbol::symtabInsert(s); // insert locally | |
980 | } | |
981 | } | |
982 | if (!forward->symtab) | |
983 | { | |
984 | forward->symtab = new DsymbolTable(); | |
985 | } | |
986 | // Non-STClocal symbols are forwarded to `forward`. | |
987 | return forward->symtabInsert(s); | |
988 | } | |
989 | ||
990 | /************************ | |
991 | * This override handles the following two cases: | |
992 | * static foreach (i, i; [0]) { ... } | |
993 | * and | |
994 | * static foreach (i; [0]) { enum i = 2; } | |
995 | */ | |
996 | Dsymbol *ForwardingScopeDsymbol::symtabLookup(Dsymbol *s, Identifier *id) | |
997 | { | |
998 | assert(forward); | |
999 | // correctly diagnose clashing foreach loop variables. | |
1000 | if (Declaration *d = s->isDeclaration()) | |
1001 | { | |
1002 | if (d->storage_class & STClocal) | |
1003 | { | |
1004 | if (!symtab) | |
1005 | { | |
1006 | symtab = new DsymbolTable(); | |
1007 | } | |
1008 | return ScopeDsymbol::symtabLookup(s,id); | |
1009 | } | |
1010 | } | |
1011 | // Declarations within `static foreach` do not clash with | |
1012 | // `static foreach` loop variables. | |
1013 | if (!forward->symtab) | |
1014 | { | |
1015 | forward->symtab = new DsymbolTable(); | |
1016 | } | |
1017 | return forward->symtabLookup(s,id); | |
1018 | } | |
1019 | ||
1020 | void ForwardingScopeDsymbol::importScope(Dsymbol *s, Prot protection) | |
1021 | { | |
1022 | forward->importScope(s, protection); | |
1023 | } | |
1024 | ||
1025 | void ForwardingScopeDsymbol::semantic(Scope *) | |
1026 | { | |
1027 | } | |
1028 | ||
1029 | const char *ForwardingScopeDsymbol::kind() const | |
1030 | { | |
1031 | return "local scope"; | |
1032 | } | |
1033 | ||
b4c522fa IB |
1034 | /********************************* ScopeDsymbol ****************************/ |
1035 | ||
1036 | ScopeDsymbol::ScopeDsymbol() | |
1037 | : Dsymbol() | |
1038 | { | |
1039 | members = NULL; | |
1040 | symtab = NULL; | |
1041 | endlinnum = 0; | |
1042 | importedScopes = NULL; | |
1043 | prots = NULL; | |
1044 | } | |
1045 | ||
1046 | ScopeDsymbol::ScopeDsymbol(Identifier *id) | |
1047 | : Dsymbol(id) | |
1048 | { | |
1049 | members = NULL; | |
1050 | symtab = NULL; | |
1051 | endlinnum = 0; | |
1052 | importedScopes = NULL; | |
1053 | prots = NULL; | |
1054 | } | |
1055 | ||
1056 | Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) | |
1057 | { | |
1058 | //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); | |
1059 | ScopeDsymbol *sds = s ? (ScopeDsymbol *)s : new ScopeDsymbol(ident); | |
1060 | sds->members = arraySyntaxCopy(members); | |
1061 | sds->endlinnum = endlinnum; | |
1062 | return sds; | |
1063 | } | |
1064 | ||
1065 | void ScopeDsymbol::semantic(Scope *) | |
1066 | { | |
1067 | } | |
1068 | ||
1069 | /***************************************** | |
1070 | * This function is #1 on the list of functions that eat cpu time. | |
1071 | * Be very, very careful about slowing it down. | |
1072 | */ | |
1073 | ||
1074 | Dsymbol *ScopeDsymbol::search(const Loc &loc, Identifier *ident, int flags) | |
1075 | { | |
1076 | //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); | |
1077 | //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; | |
1078 | ||
1079 | // Look in symbols declared in this module | |
1080 | if (symtab && !(flags & SearchImportsOnly)) | |
1081 | { | |
1082 | //printf(" look in locals\n"); | |
1083 | Dsymbol *s1 = symtab->lookup(ident); | |
1084 | if (s1) | |
1085 | { | |
1086 | //printf("\tfound in locals = '%s.%s'\n",toChars(),s1->toChars()); | |
1087 | return s1; | |
1088 | } | |
1089 | } | |
1090 | //printf(" not found in locals\n"); | |
1091 | ||
1092 | // Look in imported scopes | |
1093 | if (importedScopes) | |
1094 | { | |
1095 | //printf(" look in imports\n"); | |
1096 | Dsymbol *s = NULL; | |
1097 | OverloadSet *a = NULL; | |
1098 | ||
1099 | // Look in imported modules | |
2cbc99d1 | 1100 | for (size_t i = 0; i < importedScopes->length; i++) |
b4c522fa IB |
1101 | { |
1102 | // If private import, don't search it | |
0a2ee409 | 1103 | if ((flags & IgnorePrivateImports) && prots[i] == Prot::private_) |
b4c522fa IB |
1104 | continue; |
1105 | ||
1106 | int sflags = flags & (IgnoreErrors | IgnoreAmbiguous | IgnoreSymbolVisibility); // remember these in recursive searches | |
1107 | Dsymbol *ss = (*importedScopes)[i]; | |
1108 | ||
1109 | //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); | |
1110 | ||
1111 | if (ss->isModule()) | |
1112 | { | |
1113 | if (flags & SearchLocalsOnly) | |
1114 | continue; | |
1115 | } | |
1116 | else // mixin template | |
1117 | { | |
1118 | if (flags & SearchImportsOnly) | |
1119 | continue; | |
1120 | // compatibility with -transition=import (Bugzilla 15925) | |
1121 | // SearchLocalsOnly should always get set for new lookup rules | |
1122 | sflags |= (flags & SearchLocalsOnly); | |
1123 | } | |
1124 | ||
1125 | /* Don't find private members if ss is a module | |
1126 | */ | |
1127 | Dsymbol *s2 = ss->search(loc, ident, sflags | (ss->isModule() ? IgnorePrivateImports : IgnoreNone)); | |
1128 | if (!s2 || (!(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))) | |
1129 | continue; | |
1130 | if (!s) | |
1131 | { | |
1132 | s = s2; | |
1133 | if (s && s->isOverloadSet()) | |
1134 | a = mergeOverloadSet(ident, a, s); | |
1135 | } | |
1136 | else if (s2 && s != s2) | |
1137 | { | |
1138 | if (s->toAlias() == s2->toAlias() || | |
1139 | (s->getType() == s2->getType() && s->getType())) | |
1140 | { | |
1141 | /* After following aliases, we found the same | |
1142 | * symbol, so it's not an ambiguity. But if one | |
1143 | * alias is deprecated or less accessible, prefer | |
1144 | * the other. | |
1145 | */ | |
1146 | if (s->isDeprecated() || | |
0a2ee409 | 1147 | (s->prot().isMoreRestrictiveThan(s2->prot()) && s2->prot().kind != Prot::none)) |
b4c522fa IB |
1148 | s = s2; |
1149 | } | |
1150 | else | |
1151 | { | |
1152 | /* Two imports of the same module should be regarded as | |
1153 | * the same. | |
1154 | */ | |
1155 | Import *i1 = s->isImport(); | |
1156 | Import *i2 = s2->isImport(); | |
1157 | if (!(i1 && i2 && | |
1158 | (i1->mod == i2->mod || | |
1159 | (!i1->parent->isImport() && !i2->parent->isImport() && | |
1160 | i1->ident->equals(i2->ident)) | |
1161 | ) | |
1162 | ) | |
1163 | ) | |
1164 | { | |
1165 | /* Bugzilla 8668: | |
1166 | * Public selective import adds AliasDeclaration in module. | |
1167 | * To make an overload set, resolve aliases in here and | |
1168 | * get actual overload roots which accessible via s and s2. | |
1169 | */ | |
1170 | s = s->toAlias(); | |
1171 | s2 = s2->toAlias(); | |
1172 | ||
1173 | /* If both s2 and s are overloadable (though we only | |
1174 | * need to check s once) | |
1175 | */ | |
1176 | if ((s2->isOverloadSet() || s2->isOverloadable()) && | |
1177 | (a || s->isOverloadable())) | |
1178 | { | |
1179 | a = mergeOverloadSet(ident, a, s2); | |
1180 | continue; | |
1181 | } | |
1182 | if (flags & IgnoreAmbiguous) // if return NULL on ambiguity | |
1183 | return NULL; | |
1184 | if (!(flags & IgnoreErrors)) | |
1185 | ScopeDsymbol::multiplyDefined(loc, s, s2); | |
1186 | break; | |
1187 | } | |
1188 | } | |
1189 | } | |
1190 | } | |
1191 | ||
1192 | if (s) | |
1193 | { | |
1194 | /* Build special symbol if we had multiple finds | |
1195 | */ | |
1196 | if (a) | |
1197 | { | |
1198 | if (!s->isOverloadSet()) | |
1199 | a = mergeOverloadSet(ident, a, s); | |
1200 | s = a; | |
1201 | } | |
1202 | ||
1203 | // TODO: remove once private symbol visibility has been deprecated | |
0a2ee409 | 1204 | if (!(flags & IgnoreErrors) && s->prot().kind == Prot::private_ && |
b4c522fa IB |
1205 | !s->isOverloadable() && !s->parent->isTemplateMixin() && !s->parent->isNspace()) |
1206 | { | |
1207 | AliasDeclaration *ad; | |
1208 | // accessing private selective and renamed imports is | |
1209 | // deprecated by restricting the symbol visibility | |
1210 | if (s->isImport() || ((ad = s->isAliasDeclaration()) != NULL && ad->_import != NULL)) | |
1211 | {} | |
1212 | else | |
1213 | error(loc, "%s %s is private", s->kind(), s->toPrettyChars()); | |
1214 | } | |
1215 | //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); | |
1216 | return s; | |
1217 | } | |
1218 | //printf(" not found in imports\n"); | |
1219 | } | |
1220 | ||
1221 | return NULL; | |
1222 | } | |
1223 | ||
1224 | OverloadSet *ScopeDsymbol::mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s) | |
1225 | { | |
1226 | if (!os) | |
1227 | { | |
1228 | os = new OverloadSet(ident); | |
1229 | os->parent = this; | |
1230 | } | |
1231 | if (OverloadSet *os2 = s->isOverloadSet()) | |
1232 | { | |
1233 | // Merge the cross-module overload set 'os2' into 'os' | |
2cbc99d1 | 1234 | if (os->a.length == 0) |
b4c522fa | 1235 | { |
2cbc99d1 IB |
1236 | os->a.setDim(os2->a.length); |
1237 | memcpy(os->a.tdata(), os2->a.tdata(), sizeof(os->a[0]) * os2->a.length); | |
b4c522fa IB |
1238 | } |
1239 | else | |
1240 | { | |
2cbc99d1 | 1241 | for (size_t i = 0; i < os2->a.length; i++) |
b4c522fa IB |
1242 | { |
1243 | os = mergeOverloadSet(ident, os, os2->a[i]); | |
1244 | } | |
1245 | } | |
1246 | } | |
1247 | else | |
1248 | { | |
1249 | assert(s->isOverloadable()); | |
1250 | ||
1251 | /* Don't add to os[] if s is alias of previous sym | |
1252 | */ | |
2cbc99d1 | 1253 | for (size_t j = 0; j < os->a.length; j++) |
b4c522fa IB |
1254 | { |
1255 | Dsymbol *s2 = os->a[j]; | |
1256 | if (s->toAlias() == s2->toAlias()) | |
1257 | { | |
1258 | if (s2->isDeprecated() || | |
1259 | (s2->prot().isMoreRestrictiveThan(s->prot()) && | |
0a2ee409 | 1260 | s->prot().kind != Prot::none)) |
b4c522fa IB |
1261 | { |
1262 | os->a[j] = s; | |
1263 | } | |
1264 | goto Lcontinue; | |
1265 | } | |
1266 | } | |
1267 | os->push(s); | |
1268 | Lcontinue: | |
1269 | ; | |
1270 | } | |
1271 | return os; | |
1272 | } | |
1273 | ||
1274 | void ScopeDsymbol::importScope(Dsymbol *s, Prot protection) | |
1275 | { | |
1276 | //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); | |
1277 | ||
1278 | // No circular or redundant import's | |
1279 | if (s != this) | |
1280 | { | |
1281 | if (!importedScopes) | |
1282 | importedScopes = new Dsymbols(); | |
1283 | else | |
1284 | { | |
2cbc99d1 | 1285 | for (size_t i = 0; i < importedScopes->length; i++) |
b4c522fa IB |
1286 | { |
1287 | Dsymbol *ss = (*importedScopes)[i]; | |
1288 | if (ss == s) // if already imported | |
1289 | { | |
1290 | if (protection.kind > prots[i]) | |
1291 | prots[i] = protection.kind; // upgrade access | |
1292 | return; | |
1293 | } | |
1294 | } | |
1295 | } | |
1296 | importedScopes->push(s); | |
0a2ee409 | 1297 | prots = (Prot::Kind *)mem.xrealloc(prots, importedScopes->length * sizeof(prots[0])); |
2cbc99d1 | 1298 | prots[importedScopes->length - 1] = protection.kind; |
b4c522fa IB |
1299 | } |
1300 | } | |
1301 | ||
255b2d91 IB |
1302 | #define BITS_PER_INDEX (sizeof(size_t) * CHAR_BIT) |
1303 | ||
b4c522fa IB |
1304 | static void bitArraySet(BitArray *array, size_t idx) |
1305 | { | |
255b2d91 | 1306 | array->ptr[idx / BITS_PER_INDEX] |= 1ULL << (idx % BITS_PER_INDEX); |
b4c522fa IB |
1307 | } |
1308 | ||
1309 | static bool bitArrayGet(BitArray *array, size_t idx) | |
1310 | { | |
255b2d91 IB |
1311 | const size_t boffset = idx % BITS_PER_INDEX; |
1312 | return (array->ptr[idx / BITS_PER_INDEX] & (1ULL << boffset)) >> boffset; | |
b4c522fa IB |
1313 | } |
1314 | ||
1315 | static void bitArrayLength(BitArray *array, size_t len) | |
1316 | { | |
255b2d91 | 1317 | if (array->len < len) |
b4c522fa | 1318 | { |
255b2d91 IB |
1319 | const size_t obytes = (array->len + BITS_PER_INDEX - 1) / BITS_PER_INDEX; |
1320 | const size_t nbytes = (len + BITS_PER_INDEX - 1) / BITS_PER_INDEX; | |
1321 | ||
b4c522fa IB |
1322 | if (!array->ptr) |
1323 | array->ptr = (size_t *)mem.xmalloc(nbytes * sizeof(size_t)); | |
1324 | else | |
1325 | array->ptr = (size_t *)mem.xrealloc(array->ptr, nbytes * sizeof(size_t)); | |
1326 | ||
1327 | for (size_t i = obytes; i < nbytes; i++) | |
1328 | array->ptr[i] = 0; | |
255b2d91 IB |
1329 | |
1330 | array->len = nbytes * BITS_PER_INDEX; | |
b4c522fa | 1331 | } |
b4c522fa IB |
1332 | } |
1333 | ||
1334 | void ScopeDsymbol::addAccessiblePackage(Package *p, Prot protection) | |
1335 | { | |
0a2ee409 | 1336 | BitArray *pary = protection.kind == Prot::private_ ? &privateAccessiblePackages : &accessiblePackages; |
b4c522fa IB |
1337 | if (pary->len <= p->tag) |
1338 | bitArrayLength(pary, p->tag + 1); | |
1339 | bitArraySet(pary, p->tag); | |
1340 | } | |
1341 | ||
1342 | bool ScopeDsymbol::isPackageAccessible(Package *p, Prot protection, int) | |
1343 | { | |
1344 | if ((p->tag < accessiblePackages.len && bitArrayGet(&accessiblePackages, p->tag)) || | |
0a2ee409 | 1345 | (protection.kind == Prot::private_ && p->tag < privateAccessiblePackages.len && bitArrayGet(&privateAccessiblePackages, p->tag))) |
b4c522fa IB |
1346 | return true; |
1347 | if (importedScopes) | |
1348 | { | |
2cbc99d1 | 1349 | for (size_t i = 0; i < importedScopes->length; i++) |
b4c522fa IB |
1350 | { |
1351 | // only search visible scopes && imported modules should ignore private imports | |
1352 | Dsymbol *ss = (*importedScopes)[i]; | |
1353 | if (protection.kind <= prots[i] && | |
1354 | ss->isScopeDsymbol()->isPackageAccessible(p, protection, IgnorePrivateImports)) | |
1355 | return true; | |
1356 | } | |
1357 | } | |
1358 | return false; | |
1359 | } | |
1360 | ||
1361 | bool ScopeDsymbol::isforwardRef() | |
1362 | { | |
1363 | return (members == NULL); | |
1364 | } | |
1365 | ||
1366 | void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) | |
1367 | { | |
1368 | if (loc.filename) | |
1369 | { ::error(loc, "%s at %s conflicts with %s at %s", | |
1370 | s1->toPrettyChars(), | |
1371 | s1->locToChars(), | |
1372 | s2->toPrettyChars(), | |
1373 | s2->locToChars()); | |
1374 | } | |
1375 | else | |
1376 | { | |
1377 | s1->error(s1->loc, "conflicts with %s %s at %s", | |
1378 | s2->kind(), | |
1379 | s2->toPrettyChars(), | |
1380 | s2->locToChars()); | |
1381 | } | |
1382 | } | |
1383 | ||
f9ab59ff | 1384 | const char *ScopeDsymbol::kind() const |
b4c522fa IB |
1385 | { |
1386 | return "ScopeDsymbol"; | |
1387 | } | |
1388 | ||
1389 | Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) | |
1390 | { | |
1391 | return symtab->insert(s); | |
1392 | } | |
1393 | ||
1394 | /**************************************** | |
1395 | * Look up identifier in symbol table. | |
1396 | */ | |
1397 | ||
1398 | Dsymbol *ScopeDsymbol::symtabLookup(Dsymbol *, Identifier *id) | |
1399 | { | |
1400 | return symtab->lookup(id); | |
1401 | } | |
1402 | ||
1403 | /**************************************** | |
1404 | * Return true if any of the members are static ctors or static dtors, or if | |
1405 | * any members have members that are. | |
1406 | */ | |
1407 | ||
1408 | bool ScopeDsymbol::hasStaticCtorOrDtor() | |
1409 | { | |
1410 | if (members) | |
1411 | { | |
2cbc99d1 | 1412 | for (size_t i = 0; i < members->length; i++) |
b4c522fa IB |
1413 | { Dsymbol *member = (*members)[i]; |
1414 | ||
1415 | if (member->hasStaticCtorOrDtor()) | |
1416 | return true; | |
1417 | } | |
1418 | } | |
1419 | return false; | |
1420 | } | |
1421 | ||
1422 | /*************************************** | |
1423 | * Determine number of Dsymbols, folding in AttribDeclaration members. | |
1424 | */ | |
1425 | ||
1426 | static int dimDg(void *ctx, size_t, Dsymbol *) | |
1427 | { | |
1428 | ++*(size_t *)ctx; | |
1429 | return 0; | |
1430 | } | |
1431 | ||
1432 | size_t ScopeDsymbol::dim(Dsymbols *members) | |
1433 | { | |
1434 | size_t n = 0; | |
1435 | ScopeDsymbol_foreach(NULL, members, &dimDg, &n); | |
1436 | return n; | |
1437 | } | |
1438 | ||
1439 | /*************************************** | |
1440 | * Get nth Dsymbol, folding in AttribDeclaration members. | |
1441 | * Returns: | |
1442 | * Dsymbol* nth Dsymbol | |
1443 | * NULL not found, *pn gets incremented by the number | |
1444 | * of Dsymbols | |
1445 | */ | |
1446 | ||
1447 | struct GetNthSymbolCtx | |
1448 | { | |
1449 | size_t nth; | |
1450 | Dsymbol *sym; | |
1451 | }; | |
1452 | ||
1453 | static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) | |
1454 | { | |
1455 | GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; | |
1456 | if (n == p->nth) | |
1457 | { p->sym = sym; | |
1458 | return 1; | |
1459 | } | |
1460 | return 0; | |
1461 | } | |
1462 | ||
1463 | Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *) | |
1464 | { | |
1465 | GetNthSymbolCtx ctx = { nth, NULL }; | |
1466 | int res = ScopeDsymbol_foreach(NULL, members, &getNthSymbolDg, &ctx); | |
1467 | return res ? ctx.sym : NULL; | |
1468 | } | |
1469 | ||
1470 | /*************************************** | |
1471 | * Expands attribute declarations in members in depth first | |
1472 | * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each | |
1473 | * member. | |
1474 | * If dg returns !=0, stops and returns that value else returns 0. | |
1475 | * Use this function to avoid the O(N + N^2/2) complexity of | |
1476 | * calculating dim and calling N times getNth. | |
1477 | */ | |
1478 | ||
1479 | int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn) | |
1480 | { | |
1481 | assert(dg); | |
1482 | if (!members) | |
1483 | return 0; | |
1484 | ||
1485 | size_t n = pn ? *pn : 0; // take over index | |
1486 | int result = 0; | |
2cbc99d1 | 1487 | for (size_t i = 0; i < members->length; i++) |
b4c522fa IB |
1488 | { Dsymbol *s = (*members)[i]; |
1489 | ||
1490 | if (AttribDeclaration *a = s->isAttribDeclaration()) | |
d3da83f6 | 1491 | result = ScopeDsymbol_foreach(sc, a->include(sc), dg, ctx, &n); |
b4c522fa IB |
1492 | else if (TemplateMixin *tm = s->isTemplateMixin()) |
1493 | result = ScopeDsymbol_foreach(sc, tm->members, dg, ctx, &n); | |
1494 | else if (s->isTemplateInstance()) | |
1495 | ; | |
1496 | else if (s->isUnitTestDeclaration()) | |
1497 | ; | |
1498 | else | |
1499 | result = dg(ctx, n++, s); | |
1500 | ||
1501 | if (result) | |
1502 | break; | |
1503 | } | |
1504 | ||
1505 | if (pn) | |
1506 | *pn = n; // update index | |
1507 | return result; | |
1508 | } | |
1509 | ||
1510 | /******************************************* | |
1511 | * Look for member of the form: | |
1512 | * const(MemberInfo)[] getMembers(string); | |
1513 | * Returns NULL if not found | |
1514 | */ | |
1515 | ||
1516 | FuncDeclaration *ScopeDsymbol::findGetMembers() | |
1517 | { | |
1518 | Dsymbol *s = search_function(this, Id::getmembers); | |
1519 | FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; | |
1520 | ||
1521 | if (fdx && fdx->isVirtual()) | |
1522 | fdx = NULL; | |
1523 | ||
1524 | return fdx; | |
1525 | } | |
1526 | ||
1527 | ||
1528 | /****************************** WithScopeSymbol ******************************/ | |
1529 | ||
1530 | WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) | |
1531 | : ScopeDsymbol() | |
1532 | { | |
1533 | this->withstate = withstate; | |
1534 | } | |
1535 | ||
1536 | Dsymbol *WithScopeSymbol::search(const Loc &loc, Identifier *ident, int flags) | |
1537 | { | |
1538 | //printf("WithScopeSymbol::search(%s)\n", ident->toChars()); | |
1539 | if (flags & SearchImportsOnly) | |
1540 | return NULL; | |
1541 | ||
1542 | // Acts as proxy to the with class declaration | |
1543 | Dsymbol *s = NULL; | |
1544 | Expression *eold = NULL; | |
1545 | for (Expression *e = withstate->exp; e != eold; e = resolveAliasThis(_scope, e)) | |
1546 | { | |
1547 | if (e->op == TOKscope) | |
1548 | { | |
1549 | s = ((ScopeExp *)e)->sds; | |
1550 | } | |
1551 | else if (e->op == TOKtype) | |
1552 | { | |
1553 | s = e->type->toDsymbol(NULL); | |
1554 | } | |
1555 | else | |
1556 | { | |
1557 | Type *t = e->type->toBasetype(); | |
1558 | s = t->toDsymbol(NULL); | |
1559 | } | |
1560 | if (s) | |
1561 | { | |
1562 | s = s->search(loc, ident, flags); | |
1563 | if (s) | |
1564 | return s; | |
1565 | } | |
1566 | eold = e; | |
1567 | } | |
1568 | return NULL; | |
1569 | } | |
1570 | ||
1571 | /****************************** ArrayScopeSymbol ******************************/ | |
1572 | ||
1573 | ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) | |
1574 | : ScopeDsymbol() | |
1575 | { | |
1576 | assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray); | |
1577 | exp = e; | |
1578 | type = NULL; | |
1579 | td = NULL; | |
1580 | this->sc = sc; | |
1581 | } | |
1582 | ||
1583 | ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) | |
1584 | : ScopeDsymbol() | |
1585 | { | |
1586 | exp = NULL; | |
1587 | type = t; | |
1588 | td = NULL; | |
1589 | this->sc = sc; | |
1590 | } | |
1591 | ||
1592 | ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) | |
1593 | : ScopeDsymbol() | |
1594 | { | |
1595 | exp = NULL; | |
1596 | type = NULL; | |
1597 | td = s; | |
1598 | this->sc = sc; | |
1599 | } | |
1600 | ||
1601 | Dsymbol *ArrayScopeSymbol::search(const Loc &loc, Identifier *ident, int) | |
1602 | { | |
1603 | //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); | |
1604 | if (ident == Id::dollar) | |
1605 | { | |
1606 | VarDeclaration **pvar; | |
1607 | Expression *ce; | |
1608 | ||
1609 | L1: | |
1610 | if (td) | |
1611 | { | |
1612 | /* $ gives the number of elements in the tuple | |
1613 | */ | |
1614 | VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); | |
2cbc99d1 | 1615 | Expression *e = new IntegerExp(Loc(), td->objects->length, Type::tsize_t); |
b4c522fa IB |
1616 | v->_init = new ExpInitializer(Loc(), e); |
1617 | v->storage_class |= STCtemp | STCstatic | STCconst; | |
1618 | v->semantic(sc); | |
1619 | return v; | |
1620 | } | |
1621 | ||
1622 | if (type) | |
1623 | { | |
1624 | /* $ gives the number of type entries in the type tuple | |
1625 | */ | |
1626 | VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); | |
2cbc99d1 | 1627 | Expression *e = new IntegerExp(Loc(), type->arguments->length, Type::tsize_t); |
b4c522fa IB |
1628 | v->_init = new ExpInitializer(Loc(), e); |
1629 | v->storage_class |= STCtemp | STCstatic | STCconst; | |
1630 | v->semantic(sc); | |
1631 | return v; | |
1632 | } | |
1633 | ||
1634 | if (exp->op == TOKindex) | |
1635 | { | |
1636 | /* array[index] where index is some function of $ | |
1637 | */ | |
1638 | IndexExp *ie = (IndexExp *)exp; | |
1639 | pvar = &ie->lengthVar; | |
1640 | ce = ie->e1; | |
1641 | } | |
1642 | else if (exp->op == TOKslice) | |
1643 | { | |
1644 | /* array[lwr .. upr] where lwr or upr is some function of $ | |
1645 | */ | |
1646 | SliceExp *se = (SliceExp *)exp; | |
1647 | pvar = &se->lengthVar; | |
1648 | ce = se->e1; | |
1649 | } | |
1650 | else if (exp->op == TOKarray) | |
1651 | { | |
1652 | /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ | |
1653 | * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) | |
1654 | */ | |
1655 | ArrayExp *ae = (ArrayExp *)exp; | |
1656 | pvar = &ae->lengthVar; | |
1657 | ce = ae->e1; | |
1658 | } | |
1659 | else | |
1660 | { | |
1661 | /* Didn't find $, look in enclosing scope(s). | |
1662 | */ | |
1663 | return NULL; | |
1664 | } | |
1665 | ||
1666 | while (ce->op == TOKcomma) | |
1667 | ce = ((CommaExp *)ce)->e2; | |
1668 | ||
1669 | /* If we are indexing into an array that is really a type | |
1670 | * tuple, rewrite this as an index into a type tuple and | |
1671 | * try again. | |
1672 | */ | |
1673 | if (ce->op == TOKtype) | |
1674 | { | |
1675 | Type *t = ((TypeExp *)ce)->type; | |
1676 | if (t->ty == Ttuple) | |
1677 | { | |
1678 | type = (TypeTuple *)t; | |
1679 | goto L1; | |
1680 | } | |
1681 | } | |
1682 | ||
1683 | /* *pvar is lazily initialized, so if we refer to $ | |
1684 | * multiple times, it gets set only once. | |
1685 | */ | |
1686 | if (!*pvar) // if not already initialized | |
1687 | { | |
1688 | /* Create variable v and set it to the value of $ | |
1689 | */ | |
1690 | VarDeclaration *v; | |
1691 | Type *t; | |
1692 | if (ce->op == TOKtuple) | |
1693 | { | |
1694 | /* It is for an expression tuple, so the | |
1695 | * length will be a const. | |
1696 | */ | |
2cbc99d1 | 1697 | Expression *e = new IntegerExp(Loc(), ((TupleExp *)ce)->exps->length, Type::tsize_t); |
b4c522fa IB |
1698 | v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(Loc(), e)); |
1699 | v->storage_class |= STCtemp | STCstatic | STCconst; | |
1700 | } | |
1701 | else if (ce->type && (t = ce->type->toBasetype()) != NULL && | |
1702 | (t->ty == Tstruct || t->ty == Tclass)) | |
1703 | { | |
1704 | // Look for opDollar | |
1705 | assert(exp->op == TOKarray || exp->op == TOKslice); | |
1706 | AggregateDeclaration *ad = isAggregate(t); | |
1707 | assert(ad); | |
1708 | ||
1709 | Dsymbol *s = ad->search(loc, Id::opDollar); | |
1710 | if (!s) // no dollar exists -- search in higher scope | |
1711 | return NULL; | |
1712 | s = s->toAlias(); | |
1713 | ||
1714 | Expression *e = NULL; | |
1715 | // Check for multi-dimensional opDollar(dim) template. | |
1716 | if (TemplateDeclaration *td = s->isTemplateDeclaration()) | |
1717 | { | |
1718 | dinteger_t dim = 0; | |
1719 | if (exp->op == TOKarray) | |
1720 | { | |
1721 | dim = ((ArrayExp *)exp)->currentDimension; | |
1722 | } | |
1723 | else if (exp->op == TOKslice) | |
1724 | { | |
1725 | dim = 0; // slices are currently always one-dimensional | |
1726 | } | |
1727 | else | |
1728 | { | |
1729 | assert(0); | |
1730 | } | |
1731 | ||
1732 | Objects *tiargs = new Objects(); | |
1733 | Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t); | |
1734 | edim = ::semantic(edim, sc); | |
1735 | tiargs->push(edim); | |
1736 | e = new DotTemplateInstanceExp(loc, ce, td->ident, tiargs); | |
1737 | } | |
1738 | else | |
1739 | { | |
1740 | /* opDollar exists, but it's not a template. | |
1741 | * This is acceptable ONLY for single-dimension indexing. | |
1742 | * Note that it's impossible to have both template & function opDollar, | |
1743 | * because both take no arguments. | |
1744 | */ | |
2cbc99d1 | 1745 | if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->length != 1) |
b4c522fa IB |
1746 | { |
1747 | exp->error("%s only defines opDollar for one dimension", ad->toChars()); | |
1748 | return NULL; | |
1749 | } | |
1750 | Declaration *d = s->isDeclaration(); | |
1751 | assert(d); | |
1752 | e = new DotVarExp(loc, ce, d); | |
1753 | } | |
1754 | e = ::semantic(e, sc); | |
1755 | if (!e->type) | |
1756 | exp->error("%s has no value", e->toChars()); | |
1757 | t = e->type->toBasetype(); | |
1758 | if (t && t->ty == Tfunction) | |
1759 | e = new CallExp(e->loc, e); | |
1760 | v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e)); | |
1761 | v->storage_class |= STCtemp | STCctfe | STCrvalue; | |
1762 | } | |
1763 | else | |
1764 | { | |
1765 | /* For arrays, $ will either be a compile-time constant | |
1766 | * (in which case its value in set during constant-folding), | |
1767 | * or a variable (in which case an expression is created in | |
1768 | * toir.c). | |
1769 | */ | |
1770 | VoidInitializer *e = new VoidInitializer(Loc()); | |
1771 | e->type = Type::tsize_t; | |
1772 | v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e); | |
1773 | v->storage_class |= STCtemp | STCctfe; // it's never a true static variable | |
1774 | } | |
1775 | *pvar = v; | |
1776 | } | |
1777 | (*pvar)->semantic(sc); | |
1778 | return (*pvar); | |
1779 | } | |
1780 | return NULL; | |
1781 | } | |
1782 | ||
1783 | ||
1784 | /****************************** DsymbolTable ******************************/ | |
1785 | ||
1786 | DsymbolTable::DsymbolTable() | |
1787 | { | |
1788 | tab = NULL; | |
1789 | } | |
1790 | ||
1791 | Dsymbol *DsymbolTable::lookup(Identifier const * const ident) | |
1792 | { | |
1793 | //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); | |
1794 | return (Dsymbol *)dmd_aaGetRvalue(tab, const_cast<void *>((const void *)ident)); | |
1795 | } | |
1796 | ||
1797 | Dsymbol *DsymbolTable::insert(Dsymbol *s) | |
1798 | { | |
1799 | //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); | |
1800 | Identifier *ident = s->ident; | |
1801 | Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident); | |
1802 | if (*ps) | |
1803 | return NULL; // already in table | |
1804 | *ps = s; | |
1805 | return s; | |
1806 | } | |
1807 | ||
1808 | Dsymbol *DsymbolTable::insert(Identifier const * const ident, Dsymbol *s) | |
1809 | { | |
1810 | //printf("DsymbolTable::insert()\n"); | |
1811 | Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, const_cast<void *>((const void *)ident)); | |
1812 | if (*ps) | |
1813 | return NULL; // already in table | |
1814 | *ps = s; | |
1815 | return s; | |
1816 | } | |
1817 | ||
1818 | Dsymbol *DsymbolTable::update(Dsymbol *s) | |
1819 | { | |
1820 | Identifier *ident = s->ident; | |
1821 | Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident); | |
1822 | *ps = s; | |
1823 | return s; | |
1824 | } | |
1825 | ||
1826 | /****************************** Prot ******************************/ | |
1827 | ||
1828 | Prot::Prot() | |
1829 | { | |
0a2ee409 | 1830 | this->kind = Prot::undefined; |
b4c522fa IB |
1831 | this->pkg = NULL; |
1832 | } | |
1833 | ||
0a2ee409 | 1834 | Prot::Prot(Prot::Kind kind) |
b4c522fa IB |
1835 | { |
1836 | this->kind = kind; | |
1837 | this->pkg = NULL; | |
1838 | } | |
1839 | ||
1840 | /** | |
1841 | * Checks if `this` is superset of `other` restrictions. | |
1842 | * For example, "protected" is more restrictive than "public". | |
1843 | */ | |
1844 | bool Prot::isMoreRestrictiveThan(const Prot other) const | |
1845 | { | |
1846 | return this->kind < other.kind; | |
1847 | } | |
1848 | ||
1849 | /** | |
1850 | * Checks if `this` is absolutely identical protection attribute to `other` | |
1851 | */ | |
1852 | bool Prot::operator==(const Prot& other) const | |
1853 | { | |
1854 | if (this->kind == other.kind) | |
1855 | { | |
0a2ee409 | 1856 | if (this->kind == Prot::package_) |
b4c522fa IB |
1857 | return this->pkg == other.pkg; |
1858 | return true; | |
1859 | } | |
1860 | return false; | |
1861 | } | |
1862 | ||
1863 | /** | |
1864 | * Checks if parent defines different access restrictions than this one. | |
1865 | * | |
1866 | * Params: | |
1867 | * parent = protection attribute for scope that hosts this one | |
1868 | * | |
1869 | * Returns: | |
1870 | * 'true' if parent is already more restrictive than this one and thus | |
1871 | * no differentiation is needed. | |
1872 | */ | |
1873 | bool Prot::isSubsetOf(const Prot& parent) const | |
1874 | { | |
1875 | if (this->kind != parent.kind) | |
1876 | return false; | |
1877 | ||
0a2ee409 | 1878 | if (this->kind == Prot::package_) |
b4c522fa IB |
1879 | { |
1880 | if (!this->pkg) | |
1881 | return true; | |
1882 | if (!parent.pkg) | |
1883 | return false; | |
1884 | if (parent.pkg->isAncestorPackageOf(this->pkg)) | |
1885 | return true; | |
1886 | } | |
1887 | ||
1888 | return true; | |
1889 | } |