root/branches/dmdfe/access.c

Revision 458, 8.9 kB (checked in by Gregor, 2 years ago)

MERGE: DMD 1.011

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