1:
2: // Copyright (c) 1999-2006 by Digital Mars
3: // All Rights Reserved
4: // written by Walter Bright
5: // http://www.digitalmars.com
6: // License for redistribution is by either the Artistic License
7: // in artistic.txt, or the GNU General Public License in gnu.txt.
8: // See the included readme.txt for details.
9:
10:
11: #include <stdio.h>
12: #include <stdlib.h>
13: static char __file__[] = __FILE__; /* for tassert.h */
14: #include "tassert.h"
15:
16: #include "root.h"
17: #include "rmem.h"
18:
19: #include "enum.h"
20: #include "aggregate.h"
21: #include "init.h"
22: #include "attrib.h"
23: #include "scope.h"
24: #include "id.h"
25: #include "mtype.h"
26: #include "declaration.h"
27: #include "aggregate.h"
28: #include "expression.h"
29: #include "module.h"
30:
31: #define LOG 0
32:
33: /* Code to do access checks
34: */
35:
36: int hasPackageAccess(Scope *sc, Dsymbol *s);
37:
38: /****************************************
39: * Return PROT access for Dsymbol smember in this declaration.
40: */
41:
42: enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
43: {
44: return PROTpublic;
45: }
46:
47: enum PROT StructDeclaration::getAccess(Dsymbol *smember)
48: {
49: enum PROT access_ret = PROTnone;
50:
51: #if LOG
52: printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
53: toChars(), smember->toChars());
54: #endif
55: if (smember->toParent() == this)
56: {
57: access_ret = smember->prot();
58: }
59: else if (smember->isDeclaration()->isStatic())
60: {
61: access_ret = smember->prot();
62: }
63: return access_ret;
64: }
65:
66: enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
67: {
68: enum PROT access_ret = PROTnone;
69:
70: #if LOG
71: printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
72: toChars(), smember->toChars());
73: #endif
74: if (smember->toParent() == this)
75: {
76: access_ret = smember->prot();
77: }
78: else
79: {
80: enum PROT access;
81: int i;
82:
83: if (smember->isDeclaration()->isStatic())
84: {
85: access_ret = smember->prot();
86: }
87:
88: for (i = 0; i < baseclasses->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
89: { BaseClass *b = baseclasses->tdata()[i];
90:
91: access = b->base->getAccess(smember);
92: switch (access)
93: {
94: case PROTnone:
95: break;
96:
97: case PROTprivate:
98: access = PROTnone; // private members of base class not accessible
99: break;
100:
101: case PROTpackage:
102: case PROTprotected:
103: case PROTpublic:
104: case PROTexport:
105: // If access is to be tightened
106: if (b->protection < access)
107: access = b->protection;
108:
109: // Pick path with loosest access
110: if (access > access_ret)
111: access_ret = access;
112: break;
113:
114: default:
115: assert(0);
116: }
117: }
118: }
119: #if LOG
120: printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
121: toChars(), smember->toChars(), access_ret);
122: #endif
123: return access_ret;
124: }
125:
126: /********************************************************
127: * Helper function for ClassDeclaration::accessCheck()
128: * Returns:
129: * 0 no access
130: * 1 access
131: */
132:
133: static int accessCheckX(
134: Dsymbol *smember,
135: Dsymbol *sfunc,
136: AggregateDeclaration *dthis,
137: AggregateDeclaration *cdscope)
138: {
139: assert(dthis);
140:
141: #if 0
142: printf("accessCheckX for %s.%s in function %s() in scope %s\n",
143: dthis->toChars(), smember->toChars(),
144: sfunc ? sfunc->toChars() : "NULL",
145: cdscope ? cdscope->toChars() : "NULL");
146: #endif
147: if (dthis->hasPrivateAccess(sfunc) ||
148: dthis->isFriendOf(cdscope))
149: {
150: if (smember->toParent() == dthis)
151: return 1;
152: else
153: {
154: ClassDeclaration *cdthis = dthis->isClassDeclaration();
155: if (cdthis)
156: {
157: for (int i = 0; i < cdthis->baseclasses->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
158: { BaseClass *b = cdthis->baseclasses->tdata()[i];
159: enum PROT access;
160:
161: access = b->base->getAccess(smember);
162: if (access >= PROTprotected ||
163: accessCheckX(smember, sfunc, b->base, cdscope)
164: )
165: return 1;
166:
167: }
168: }
169: }
170: }
171: else
172: {
173: if (smember->toParent() != dthis)
174: {
175: ClassDeclaration *cdthis = dthis->isClassDeclaration();
176: if (cdthis)
177: {
178: for (int i = 0; i < cdthis->baseclasses->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
179: { BaseClass *b = cdthis->baseclasses->tdata()[i];
180:
181: if (accessCheckX(smember, sfunc, b->base, cdscope))
182: return 1;
183: }
184: }
185: }
186: }
187: return 0;
188: }
189:
190: /*******************************
191: * Do access check for member of this class, this class being the
192: * type of the 'this' pointer used to access smember.
193: */
194:
195: void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
196: {
197: int result;
198:
199: FuncDeclaration *f = sc->func;
200: AggregateDeclaration *cdscope = sc->getStructClassScope();
201: enum PROT access;
202:
203: #if LOG
204: printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
205: toChars(), smember->toChars(),
206: f ? f->toChars() : NULL,
207: cdscope ? cdscope->toChars() : NULL);
208: #endif
209:
210: Dsymbol *smemberparent = smember->toParent();
211: if (!smemberparent || !smemberparent->isAggregateDeclaration())
212: {
213: #if LOG
214: printf("not an aggregate member\n");
215: #endif
216: return; // then it is accessible
217: }
218:
219: // BUG: should enable this check
220: //assert(smember->parent->isBaseOf(this, NULL));
221:
222: if (smemberparent == this)
223: { enum PROT access = smember->prot();
warning C6246: Local declaration of 'access' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '201' of 'c:\projects\extern\d\dmd\src\access.c': Lines: 201
224:
225: result = access >= PROTpublic ||
226: hasPrivateAccess(f) ||
227: isFriendOf(cdscope) ||
228: (access == PROTpackage && hasPackageAccess(sc, this));
229: #if LOG
230: printf("result1 = %d\n", result);
231: #endif
232: }
233: else if ((access = this->getAccess(smember)) >= PROTpublic)
234: {
235: result = 1;
236: #if LOG
237: printf("result2 = %d\n", result);
238: #endif
239: }
240: else if (access == PROTpackage && hasPackageAccess(sc, this))
241: {
242: result = 1;
243: #if LOG
244: printf("result3 = %d\n", result);
245: #endif
246: }
247: else
248: {
249: result = accessCheckX(smember, f, this, cdscope);
250: #if LOG
251: printf("result4 = %d\n", result);
252: #endif
253: }
254: if (!result)
255: {
256: error(loc, "member %s is not accessible", smember->toChars());
257: }
258: }
259:
260: /****************************************
261: * Determine if this is the same or friend of cd.
262: */
263:
264: int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
265: {
266: #if LOG
267: printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
268: #endif
269: if (this == cd)
270: return 1;
271:
272: // Friends if both are in the same module
273: //if (toParent() == cd->toParent())
274: if (cd && getModule() == cd->getModule())
275: {
276: #if LOG
277: printf("\tin same module\n");
278: #endif
279: return 1;
280: }
281:
282: #if LOG
283: printf("\tnot friend\n");
284: #endif
285: return 0;
286: }
287:
288: /****************************************
289: * Determine if scope sc has package level access to s.
290: */
291:
292: int hasPackageAccess(Scope *sc, Dsymbol *s)
293: {
294: #if LOG
295: printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
296: #endif
297:
298: for (; s; s = s->parent)
299: {
300: if (s->isPackage() && !s->isModule())
301: break;
302: }
303: #if LOG
304: if (s)
305: printf("\tthis is in package '%s'\n", s->toChars());
306: #endif
307:
308: if (s && s == sc->module->parent)
309: {
310: #if LOG
311: printf("\ts is in same package as sc\n");
312: #endif
313: return 1;
314: }
315:
316:
317: #if LOG
318: printf("\tno package access\n");
319: #endif
320: return 0;
321: }
322:
323: /**********************************
324: * Determine if smember has access to private members of this declaration.
325: */
326:
327: int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
328: {
329: if (smember)
330: { AggregateDeclaration *cd = NULL;
331: Dsymbol *smemberparent = smember->toParent();
332: if (smemberparent)
333: cd = smemberparent->isAggregateDeclaration();
334:
335: #if LOG
336: printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
337: toChars(), smember->toChars());
338: #endif
339:
340: if (this == cd) // smember is a member of this class
341: {
342: #if LOG
343: printf("\tyes 1\n");
344: #endif
345: return 1; // so we get private access
346: }
347:
348: // If both are members of the same module, grant access
349: while (1)
350: { Dsymbol *sp = smember->toParent();
351: if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
352: smember = sp;
353: else
354: break;
355: }
356: if (!cd && toParent() == smember->toParent())
357: {
358: #if LOG
359: printf("\tyes 2\n");
360: #endif
361: return 1;
362: }
363: if (!cd && getModule() == smember->getModule())
364: {
365: #if LOG
366: printf("\tyes 3\n");
367: #endif
368: return 1;
369: }
370: }
371: #if LOG
372: printf("\tno\n");
373: #endif
374: return 0;
375: }
376:
377: /****************************************
378: * Check access to d for expression e.d
379: */
380:
381: void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
382: {
383: #if LOG
384: if (e)
385: { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
386: printf("\te->type = %s\n", e->type->toChars());
387: }
388: else
389: {
390: //printf("accessCheck(%s)\n", d->toChars());
391: }
392: #endif
393: if (!e)
394: {
395: if (d->prot() == PROTprivate && d->getModule() != sc->module ||
396: d->prot() == PROTpackage && !hasPackageAccess(sc, d))
397:
398: error(loc, "%s %s.%s is not accessible from %s",
399: d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars());
400: }
401: else if (e->type->ty == Tclass)
402: { // Do access check
403: ClassDeclaration *cd;
404:
405: cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
406: #if 1
407: if (e->op == TOKsuper)
408: { ClassDeclaration *cd2;
409:
410: cd2 = sc->func->toParent()->isClassDeclaration();
411: if (cd2)
412: cd = cd2;
413: }
414: #endif
415: cd->accessCheck(loc, sc, d);
416: }
417: else if (e->type->ty == Tstruct)
418: { // Do access check
419: StructDeclaration *cd;
420:
421: cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
422: cd->accessCheck(loc, sc, d);
423: }
424: }
425: