1 /** 2 * A scope as defined by curly braces `{}`. 3 * 4 * Not to be confused with the `scope` storage class. 5 * 6 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d) 10 * Documentation: https://dlang.org/phobos/dmd_dscope.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dscope.d 12 */ 13 14 module dmd.dscope; 15 16 import core.stdc.stdio; 17 import core.stdc..string; 18 import dmd.aggregate; 19 import dmd.arraytypes; 20 import dmd.attrib; 21 import dmd.ctorflow; 22 import dmd.dclass; 23 import dmd.declaration; 24 import dmd.dmodule; 25 import dmd.doc; 26 import dmd.dsymbol; 27 import dmd.dsymbolsem; 28 import dmd.dtemplate; 29 import dmd.expression; 30 import dmd.errors; 31 import dmd.func; 32 import dmd.globals; 33 import dmd.id; 34 import dmd.identifier; 35 import dmd.root.outbuffer; 36 import dmd.root.rmem; 37 import dmd.root.speller; 38 import dmd.statement; 39 import dmd.tokens; 40 41 //version=LOGSEARCH; 42 43 44 // Flags that would not be inherited beyond scope nesting 45 enum SCOPE 46 { 47 ctor = 0x0001, /// constructor type 48 noaccesscheck = 0x0002, /// don't do access checks 49 condition = 0x0004, /// inside static if/assert condition 50 debug_ = 0x0008, /// inside debug conditional 51 constraint = 0x0010, /// inside template constraint 52 invariant_ = 0x0020, /// inside invariant code 53 require = 0x0040, /// inside in contract code 54 ensure = 0x0060, /// inside out contract code 55 contract = 0x0060, /// [mask] we're inside contract code 56 ctfe = 0x0080, /// inside a ctfe-only expression 57 compile = 0x0100, /// inside __traits(compile) 58 ignoresymbolvisibility = 0x0200, /// ignore symbol visibility 59 /// https://issues.dlang.org/show_bug.cgi?id=15907 60 onlysafeaccess = 0x0400, /// unsafe access is not allowed for @safe code 61 free = 0x8000, /// is on free list 62 63 fullinst = 0x10000, /// fully instantiate templates 64 alias_ = 0x20000, /// inside alias declaration. 65 66 // The following are mutually exclusive 67 printf = 0x4_0000, /// printf-style function 68 scanf = 0x8_0000, /// scanf-style function 69 } 70 71 // Flags that are carried along with a scope push() 72 enum SCOPEpush = SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | 73 SCOPE.noaccesscheck | SCOPE.onlysafeaccess | SCOPE.ignoresymbolvisibility | 74 SCOPE.printf | SCOPE.scanf; 75 76 struct Scope 77 { 78 Scope* enclosing; /// enclosing Scope 79 80 Module _module; /// Root module 81 ScopeDsymbol scopesym; /// current symbol 82 FuncDeclaration func; /// function we are in 83 Dsymbol parent; /// parent to use 84 LabelStatement slabel; /// enclosing labelled statement 85 SwitchStatement sw; /// enclosing switch statement 86 Statement tryBody; /// enclosing _body of TryCatchStatement or TryFinallyStatement 87 TryFinallyStatement tf; /// enclosing try finally statement 88 ScopeGuardStatement os; /// enclosing scope(xxx) statement 89 Statement sbreak; /// enclosing statement that supports "break" 90 Statement scontinue; /// enclosing statement that supports "continue" 91 ForeachStatement fes; /// if nested function for ForeachStatement, this is it 92 Scope* callsc; /// used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__ 93 Dsymbol inunion; /// != null if processing members of a union 94 bool nofree; /// true if shouldn't free it 95 bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) 96 int intypeof; /// in typeof(exp) 97 VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init 98 99 /* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope). 100 * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint). 101 * If minst && tinst, it's in instantiated code scope without speculation. 102 * If !minst && tinst, it's in instantiated code scope with speculation. 103 */ 104 Module minst; /// root module where the instantiated templates should belong to 105 TemplateInstance tinst; /// enclosing template instance 106 107 CtorFlow ctorflow; /// flow analysis for constructors 108 109 /// alignment for struct members 110 AlignDeclaration aligndecl; 111 112 /// C++ namespace this symbol is in 113 CPPNamespaceDeclaration namespace; 114 115 /// linkage for external functions 116 LINK linkage = LINK.d; 117 118 /// mangle type 119 CPPMANGLE cppmangle = CPPMANGLE.def; 120 121 /// inlining strategy for functions 122 PINLINE inlining = PINLINE.default_; 123 124 /// protection for class members 125 Prot protection = Prot(Prot.Kind.public_); 126 int explicitProtection; /// set if in an explicit protection attribute 127 128 StorageClass stc; /// storage class 129 130 DeprecatedDeclaration depdecl; /// customized deprecation message 131 132 uint flags; 133 134 // user defined attributes 135 UserAttributeDeclaration userAttribDecl; 136 137 DocComment* lastdc; /// documentation comment for last symbol at this scope 138 uint[void*] anchorCounts; /// lookup duplicate anchor name count 139 Identifier prevAnchor; /// qualified symbol name of last doc anchor 140 141 extern (D) __gshared Scope* freelist; 142 143 extern (D) static Scope* alloc() 144 { 145 if (freelist) 146 { 147 Scope* s = freelist; 148 freelist = s.enclosing; 149 //printf("freelist %p\n", s); 150 assert(s.flags & SCOPE.free); 151 s.flags &= ~SCOPE.free; 152 return s; 153 } 154 return new Scope(); 155 } 156 157 extern (D) static Scope* createGlobal(Module _module) 158 { 159 Scope* sc = Scope.alloc(); 160 *sc = Scope.init; 161 sc._module = _module; 162 sc.minst = _module; 163 sc.scopesym = new ScopeDsymbol(); 164 sc.scopesym.symtab = new DsymbolTable(); 165 // Add top level package as member of this global scope 166 Dsymbol m = _module; 167 while (m.parent) 168 m = m.parent; 169 m.addMember(null, sc.scopesym); 170 m.parent = null; // got changed by addMember() 171 // Create the module scope underneath the global scope 172 sc = sc.push(_module); 173 sc.parent = _module; 174 return sc; 175 } 176 177 extern (C++) Scope* copy() 178 { 179 Scope* sc = Scope.alloc(); 180 *sc = this; 181 /* https://issues.dlang.org/show_bug.cgi?id=11777 182 * The copied scope should not inherit fieldinit. 183 */ 184 sc.ctorflow.fieldinit = null; 185 return sc; 186 } 187 188 extern (C++) Scope* push() 189 { 190 Scope* s = copy(); 191 //printf("Scope::push(this = %p) new = %p\n", this, s); 192 assert(!(flags & SCOPE.free)); 193 s.scopesym = null; 194 s.enclosing = &this; 195 debug 196 { 197 if (enclosing) 198 assert(!(enclosing.flags & SCOPE.free)); 199 if (s == enclosing) 200 { 201 printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing); 202 } 203 assert(s != enclosing); 204 } 205 s.slabel = null; 206 s.nofree = false; 207 s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup; 208 s.flags = (flags & SCOPEpush); 209 s.lastdc = null; 210 assert(&this != s); 211 return s; 212 } 213 214 extern (C++) Scope* push(ScopeDsymbol ss) 215 { 216 //printf("Scope::push(%s)\n", ss.toChars()); 217 Scope* s = push(); 218 s.scopesym = ss; 219 return s; 220 } 221 222 extern (C++) Scope* pop() 223 { 224 //printf("Scope::pop() %p nofree = %d\n", this, nofree); 225 if (enclosing) 226 enclosing.ctorflow.OR(ctorflow); 227 ctorflow.freeFieldinit(); 228 229 Scope* enc = enclosing; 230 if (!nofree) 231 { 232 if (mem.isGCEnabled) 233 this = this.init; 234 enclosing = freelist; 235 freelist = &this; 236 flags |= SCOPE.free; 237 } 238 return enc; 239 } 240 241 /************************* 242 * Similar to pop(), but the results in `this` are not folded 243 * into `enclosing`. 244 */ 245 extern (D) void detach() 246 { 247 ctorflow.freeFieldinit(); 248 enclosing = null; 249 pop(); 250 } 251 252 extern (C++) Scope* startCTFE() 253 { 254 Scope* sc = this.push(); 255 sc.flags = this.flags | SCOPE.ctfe; 256 version (none) 257 { 258 /* TODO: Currently this is not possible, because we need to 259 * unspeculative some types and symbols if they are necessary for the 260 * final executable. Consider: 261 * 262 * struct S(T) { 263 * string toString() const { return "instantiated"; } 264 * } 265 * enum x = S!int(); 266 * void main() { 267 * // To call x.toString in runtime, compiler should unspeculative S!int. 268 * assert(x.toString() == "instantiated"); 269 * } 270 */ 271 // If a template is instantiated from CT evaluated expression, 272 // compiler can elide its code generation. 273 sc.tinst = null; 274 sc.minst = null; 275 } 276 return sc; 277 } 278 279 extern (C++) Scope* endCTFE() 280 { 281 assert(flags & SCOPE.ctfe); 282 return pop(); 283 } 284 285 286 /******************************* 287 * Merge results of `ctorflow` into `this`. 288 * Params: 289 * loc = for error messages 290 * ctorflow = flow results to merge in 291 */ 292 extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow) 293 { 294 if (!mergeCallSuper(this.ctorflow.callSuper, ctorflow.callSuper)) 295 error(loc, "one path skips constructor"); 296 297 const fies = ctorflow.fieldinit; 298 if (this.ctorflow.fieldinit.length && fies.length) 299 { 300 FuncDeclaration f = func; 301 if (fes) 302 f = fes.func; 303 auto ad = f.isMemberDecl(); 304 assert(ad); 305 foreach (i, v; ad.fields) 306 { 307 bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); 308 auto fieldInit = &this.ctorflow.fieldinit[i]; 309 const fiesCurrent = fies[i]; 310 if (fieldInit.loc is Loc.init) 311 fieldInit.loc = fiesCurrent.loc; 312 if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit) 313 { 314 error(loc, "one path skips field `%s`", v.toChars()); 315 } 316 } 317 } 318 } 319 320 extern (C++) Module instantiatingModule() 321 { 322 // TODO: in speculative context, returning 'module' is correct? 323 return minst ? minst : _module; 324 } 325 326 /************************************ 327 * Perform unqualified name lookup by following the chain of scopes up 328 * until found. 329 * 330 * Params: 331 * loc = location to use for error messages 332 * ident = name to look up 333 * pscopesym = if supplied and name is found, set to scope that ident was found in 334 * flags = modify search based on flags 335 * 336 * Returns: 337 * symbol if found, null if not 338 */ 339 extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) 340 { 341 version (LOGSEARCH) 342 { 343 printf("Scope.search(%p, '%s' flags=x%x)\n", &this, ident.toChars(), flags); 344 // Print scope chain 345 for (Scope* sc = &this; sc; sc = sc.enclosing) 346 { 347 if (!sc.scopesym) 348 continue; 349 printf("\tscope %s\n", sc.scopesym.toChars()); 350 } 351 352 static void printMsg(string txt, Dsymbol s) 353 { 354 printf("%.*s %s.%s, kind = '%s'\n", cast(int)txt.length, txt.ptr, 355 s.parent ? s.parent.toChars() : "", s.toChars(), s.kind()); 356 } 357 } 358 359 // This function is called only for unqualified lookup 360 assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); 361 362 /* If ident is "start at module scope", only look at module scope 363 */ 364 if (ident == Id.empty) 365 { 366 // Look for module scope 367 for (Scope* sc = &this; sc; sc = sc.enclosing) 368 { 369 assert(sc != sc.enclosing); 370 if (!sc.scopesym) 371 continue; 372 if (Dsymbol s = sc.scopesym.isModule()) 373 { 374 //printMsg("\tfound", s); 375 if (pscopesym) 376 *pscopesym = sc.scopesym; 377 return s; 378 } 379 } 380 return null; 381 } 382 383 Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp) 384 { 385 import dmd.mtype; 386 if (!ad || !ad.aliasthis) 387 return null; 388 389 Declaration decl = ad.aliasthis.sym.isDeclaration(); 390 if (!decl) 391 return null; 392 393 Type t = decl.type; 394 ScopeDsymbol sds; 395 TypeClass tc; 396 TypeStruct ts; 397 switch(t.ty) 398 { 399 case Tstruct: 400 ts = cast(TypeStruct)t; 401 sds = ts.sym; 402 break; 403 case Tclass: 404 tc = cast(TypeClass)t; 405 sds = tc.sym; 406 break; 407 case Tinstance: 408 sds = (cast(TypeInstance)t).tempinst; 409 break; 410 case Tenum: 411 sds = (cast(TypeEnum)t).sym; 412 break; 413 default: break; 414 } 415 416 if (!sds) 417 return null; 418 419 Dsymbol ret = sds.search(loc, ident, flags); 420 if (ret) 421 { 422 *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident); 423 *exp = new DotIdExp(loc, *exp, ident); 424 return ret; 425 } 426 427 if (!ts && !tc) 428 return null; 429 430 Dsymbol s; 431 *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident); 432 if (ts && !(ts.att & AliasThisRec.tracing)) 433 { 434 ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracing); 435 s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp); 436 ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracing); 437 } 438 else if(tc && !(tc.att & AliasThisRec.tracing)) 439 { 440 tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracing); 441 s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp); 442 tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracing); 443 } 444 return s; 445 } 446 447 Dsymbol searchScopes(int flags) 448 { 449 for (Scope* sc = &this; sc; sc = sc.enclosing) 450 { 451 assert(sc != sc.enclosing); 452 if (!sc.scopesym) 453 continue; 454 //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); 455 456 if (sc.scopesym.isModule()) 457 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 458 459 if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) 460 { 461 if (!(flags & (SearchImportsOnly | IgnoreErrors)) && 462 ident == Id.length && sc.scopesym.isArrayScopeSymbol() && 463 sc.enclosing && sc.enclosing.search(loc, ident, null, flags)) 464 { 465 warning(s.loc, "array `length` hides other `length` name in outer scope"); 466 } 467 //printMsg("\tfound local", s); 468 if (pscopesym) 469 *pscopesym = sc.scopesym; 470 return s; 471 } 472 473 if (global.params.fixAliasThis) 474 { 475 Expression exp = new ThisExp(loc); 476 Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp); 477 if (aliasSym) 478 { 479 //printf("found aliassym: %s\n", aliasSym.toChars()); 480 if (pscopesym) 481 *pscopesym = new ExpressionDsymbol(exp); 482 return aliasSym; 483 } 484 } 485 486 // Stop when we hit a module, but keep going if that is not just under the global scope 487 if (sc.scopesym.isModule() && !(sc.enclosing && !sc.enclosing.enclosing)) 488 break; 489 } 490 return null; 491 } 492 493 if (this.flags & SCOPE.ignoresymbolvisibility) 494 flags |= IgnoreSymbolVisibility; 495 496 // First look in local scopes 497 Dsymbol s = searchScopes(flags | SearchLocalsOnly); 498 version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s); 499 if (!s) 500 { 501 // Second look in imported modules 502 s = searchScopes(flags | SearchImportsOnly); 503 version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s); 504 } 505 return s; 506 } 507 508 extern (D) Dsymbol search_correct(Identifier ident) 509 { 510 if (global.gag) 511 return null; // don't do it for speculative compiles; too time consuming 512 513 /************************************************ 514 * Given the failed search attempt, try to find 515 * one with a close spelling. 516 */ 517 extern (D) Dsymbol scope_search_fp(const(char)[] seed, ref int cost) 518 { 519 //printf("scope_search_fp('%s')\n", seed); 520 /* If not in the lexer's string table, it certainly isn't in the symbol table. 521 * Doing this first is a lot faster. 522 */ 523 if (!seed.length) 524 return null; 525 Identifier id = Identifier.lookup(seed); 526 if (!id) 527 return null; 528 Scope* sc = &this; 529 Module.clearCache(); 530 Dsymbol scopesym = null; 531 Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors); 532 if (!s) 533 return null; 534 535 // Do not show `@disable`d declarations 536 if (auto decl = s.isDeclaration()) 537 if (decl.storage_class & STC.disable) 538 return null; 539 // Or `deprecated` ones if we're not in a deprecated scope 540 if (s.isDeprecated() && !sc.isDeprecated()) 541 return null; 542 543 for (cost = 0; sc; sc = sc.enclosing, ++cost) 544 if (sc.scopesym == scopesym) 545 break; 546 if (scopesym != s.parent) 547 { 548 ++cost; // got to the symbol through an import 549 if (s.prot().kind == Prot.Kind.private_) 550 return null; 551 } 552 return s; 553 } 554 555 Dsymbol scopesym = null; 556 // search for exact name first 557 if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors)) 558 return s; 559 return speller!scope_search_fp(ident.toString()); 560 } 561 562 /************************************ 563 * Maybe `ident` was a C or C++ name. Check for that, 564 * and suggest the D equivalent. 565 * Params: 566 * ident = unknown identifier 567 * Returns: 568 * D identifier string if found, null if not 569 */ 570 extern (D) static const(char)* search_correct_C(Identifier ident) 571 { 572 TOK tok; 573 if (ident == Id.NULL) 574 tok = TOK.null_; 575 else if (ident == Id.TRUE) 576 tok = TOK.true_; 577 else if (ident == Id.FALSE) 578 tok = TOK.false_; 579 else if (ident == Id.unsigned) 580 tok = TOK.uns32; 581 else if (ident == Id.wchar_t) 582 tok = global.params.isWindows ? TOK.wchar_ : TOK.dchar_; 583 else 584 return null; 585 return Token.toChars(tok); 586 } 587 588 extern (D) Dsymbol insert(Dsymbol s) 589 { 590 if (VarDeclaration vd = s.isVarDeclaration()) 591 { 592 if (lastVar) 593 vd.lastVar = lastVar; 594 lastVar = vd; 595 } 596 else if (WithScopeSymbol ss = s.isWithScopeSymbol()) 597 { 598 if (VarDeclaration vd = ss.withstate.wthis) 599 { 600 if (lastVar) 601 vd.lastVar = lastVar; 602 lastVar = vd; 603 } 604 return null; 605 } 606 for (Scope* sc = &this; sc; sc = sc.enclosing) 607 { 608 //printf("\tsc = %p\n", sc); 609 if (sc.scopesym) 610 { 611 //printf("\t\tsc.scopesym = %p\n", sc.scopesym); 612 if (!sc.scopesym.symtab) 613 sc.scopesym.symtab = new DsymbolTable(); 614 return sc.scopesym.symtabInsert(s); 615 } 616 } 617 assert(0); 618 } 619 620 /******************************************** 621 * Search enclosing scopes for ClassDeclaration. 622 */ 623 extern (C++) ClassDeclaration getClassScope() 624 { 625 for (Scope* sc = &this; sc; sc = sc.enclosing) 626 { 627 if (!sc.scopesym) 628 continue; 629 ClassDeclaration cd = sc.scopesym.isClassDeclaration(); 630 if (cd) 631 return cd; 632 } 633 return null; 634 } 635 636 /******************************************** 637 * Search enclosing scopes for ClassDeclaration. 638 */ 639 extern (C++) AggregateDeclaration getStructClassScope() 640 { 641 for (Scope* sc = &this; sc; sc = sc.enclosing) 642 { 643 if (!sc.scopesym) 644 continue; 645 AggregateDeclaration ad = sc.scopesym.isClassDeclaration(); 646 if (ad) 647 return ad; 648 ad = sc.scopesym.isStructDeclaration(); 649 if (ad) 650 return ad; 651 } 652 return null; 653 } 654 655 /******************************************* 656 * For TemplateDeclarations, we need to remember the Scope 657 * where it was declared. So mark the Scope as not 658 * to be free'd. 659 */ 660 extern (D) void setNoFree() 661 { 662 //int i = 0; 663 //printf("Scope::setNoFree(this = %p)\n", this); 664 for (Scope* sc = &this; sc; sc = sc.enclosing) 665 { 666 //printf("\tsc = %p\n", sc); 667 sc.nofree = true; 668 assert(!(flags & SCOPE.free)); 669 //assert(sc != sc.enclosing); 670 //assert(!sc.enclosing || sc != sc.enclosing.enclosing); 671 //if (++i == 10) 672 // assert(0); 673 } 674 } 675 676 extern (D) this(ref Scope sc) 677 { 678 this._module = sc._module; 679 this.scopesym = sc.scopesym; 680 this.enclosing = sc.enclosing; 681 this.parent = sc.parent; 682 this.sw = sc.sw; 683 this.tryBody = sc.tryBody; 684 this.tf = sc.tf; 685 this.os = sc.os; 686 this.tinst = sc.tinst; 687 this.minst = sc.minst; 688 this.sbreak = sc.sbreak; 689 this.scontinue = sc.scontinue; 690 this.fes = sc.fes; 691 this.callsc = sc.callsc; 692 this.aligndecl = sc.aligndecl; 693 this.func = sc.func; 694 this.slabel = sc.slabel; 695 this.linkage = sc.linkage; 696 this.cppmangle = sc.cppmangle; 697 this.inlining = sc.inlining; 698 this.protection = sc.protection; 699 this.explicitProtection = sc.explicitProtection; 700 this.stc = sc.stc; 701 this.depdecl = sc.depdecl; 702 this.inunion = sc.inunion; 703 this.nofree = sc.nofree; 704 this.inLoop = sc.inLoop; 705 this.intypeof = sc.intypeof; 706 this.lastVar = sc.lastVar; 707 this.ctorflow = sc.ctorflow; 708 this.flags = sc.flags; 709 this.lastdc = sc.lastdc; 710 this.anchorCounts = sc.anchorCounts; 711 this.prevAnchor = sc.prevAnchor; 712 this.userAttribDecl = sc.userAttribDecl; 713 } 714 715 structalign_t alignment() 716 { 717 if (aligndecl) 718 return aligndecl.getAlignment(&this); 719 else 720 return STRUCTALIGN_DEFAULT; 721 } 722 723 /********************************** 724 * Checks whether the current scope (or any of its parents) is deprecated. 725 * 726 * Returns: `true` if this or any parent scope is deprecated, `false` otherwise` 727 */ 728 extern(C++) bool isDeprecated() const 729 { 730 for (const(Dsymbol)* sp = &(this.parent); *sp; sp = &(sp.parent)) 731 { 732 if (sp.isDeprecated()) 733 return true; 734 } 735 for (const(Scope)* sc2 = &this; sc2; sc2 = sc2.enclosing) 736 { 737 if (sc2.scopesym && sc2.scopesym.isDeprecated()) 738 return true; 739 740 // If inside a StorageClassDeclaration that is deprecated 741 if (sc2.stc & STC.deprecated_) 742 return true; 743 } 744 if (_module.md && _module.md.isdeprecated) 745 { 746 return true; 747 } 748 return false; 749 } 750 }