comparison dmd2/access.c @ 758:f04dde6e882c

Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 11 Nov 2008 01:38:48 +0100
parents
children 638d16625da2
comparison
equal deleted inserted replaced
757:2c730d530c98 758:f04dde6e882c
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 #include <assert.h>
14
15 #include "root.h"
16 #include "mem.h"
17
18 #include "enum.h"
19 #include "aggregate.h"
20 #include "init.h"
21 #include "attrib.h"
22 #include "scope.h"
23 #include "id.h"
24 #include "mtype.h"
25 #include "declaration.h"
26 #include "aggregate.h"
27 #include "expression.h"
28 #include "module.h"
29
30 #define LOG 0
31
32 /* Code to do access checks
33 */
34
35 int hasPackageAccess(Scope *sc, Dsymbol *s);
36
37 /****************************************
38 * Return PROT access for Dsymbol smember in this declaration.
39 */
40
41 enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
42 {
43 return PROTpublic;
44 }
45
46 enum PROT StructDeclaration::getAccess(Dsymbol *smember)
47 {
48 enum PROT access_ret = PROTnone;
49
50 #if LOG
51 printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
52 toChars(), smember->toChars());
53 #endif
54 if (smember->toParent() == this)
55 {
56 access_ret = smember->prot();
57 }
58 else if (smember->isDeclaration()->isStatic())
59 {
60 access_ret = smember->prot();
61 }
62 return access_ret;
63 }
64
65 enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
66 {
67 enum PROT access_ret = PROTnone;
68
69 #if LOG
70 printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
71 toChars(), smember->toChars());
72 #endif
73 if (smember->toParent() == this)
74 {
75 access_ret = smember->prot();
76 }
77 else
78 {
79 enum PROT access;
80 int i;
81
82 if (smember->isDeclaration()->isStatic())
83 {
84 access_ret = smember->prot();
85 }
86
87 for (i = 0; i < baseclasses.dim; i++)
88 { BaseClass *b = (BaseClass *)baseclasses.data[i];
89
90 access = b->base->getAccess(smember);
91 switch (access)
92 {
93 case PROTnone:
94 break;
95
96 case PROTprivate:
97 access = PROTnone; // private members of base class not accessible
98 break;
99
100 case PROTpackage:
101 case PROTprotected:
102 case PROTpublic:
103 case PROTexport:
104 // If access is to be tightened
105 if (b->protection < access)
106 access = b->protection;
107
108 // Pick path with loosest access
109 if (access > access_ret)
110 access_ret = access;
111 break;
112
113 default:
114 assert(0);
115 }
116 }
117 }
118 #if LOG
119 printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
120 toChars(), smember->toChars(), access_ret);
121 #endif
122 return access_ret;
123 }
124
125 /********************************************************
126 * Helper function for ClassDeclaration::accessCheck()
127 * Returns:
128 * 0 no access
129 * 1 access
130 */
131
132 static int accessCheckX(
133 Dsymbol *smember,
134 Dsymbol *sfunc,
135 AggregateDeclaration *dthis,
136 AggregateDeclaration *cdscope)
137 {
138 assert(dthis);
139
140 #if 0
141 printf("accessCheckX for %s.%s in function %s() in scope %s\n",
142 dthis->toChars(), smember->toChars(),
143 sfunc ? sfunc->toChars() : "NULL",
144 cdscope ? cdscope->toChars() : "NULL");
145 #endif
146 if (dthis->hasPrivateAccess(sfunc) ||
147 dthis->isFriendOf(cdscope))
148 {
149 if (smember->toParent() == dthis)
150 return 1;
151 else
152 {
153 ClassDeclaration *cdthis = dthis->isClassDeclaration();
154 if (cdthis)
155 {
156 for (int i = 0; i < cdthis->baseclasses.dim; i++)
157 { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
158 enum PROT access;
159
160 access = b->base->getAccess(smember);
161 if (access >= PROTprotected ||
162 accessCheckX(smember, sfunc, b->base, cdscope)
163 )
164 return 1;
165
166 }
167 }
168 }
169 }
170 else
171 {
172 if (smember->toParent() != dthis)
173 {
174 ClassDeclaration *cdthis = dthis->isClassDeclaration();
175 if (cdthis)
176 {
177 for (int i = 0; i < cdthis->baseclasses.dim; i++)
178 { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
179
180 if (accessCheckX(smember, sfunc, b->base, cdscope))
181 return 1;
182 }
183 }
184 }
185 }
186 return 0;
187 }
188
189 /*******************************
190 * Do access check for member of this class, this class being the
191 * type of the 'this' pointer used to access smember.
192 */
193
194 void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
195 {
196 int result;
197
198 FuncDeclaration *f = sc->func;
199 AggregateDeclaration *cdscope = sc->getStructClassScope();
200 enum PROT access;
201
202 #if LOG
203 printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
204 toChars(), smember->toChars(),
205 f ? f->toChars() : NULL,
206 cdscope ? cdscope->toChars() : NULL);
207 #endif
208
209 Dsymbol *smemberparent = smember->toParent();
210 if (!smemberparent || !smemberparent->isAggregateDeclaration())
211 {
212 #if LOG
213 printf("not an aggregate member\n");
214 #endif
215 return; // then it is accessible
216 }
217
218 // BUG: should enable this check
219 //assert(smember->parent->isBaseOf(this, NULL));
220
221 if (smemberparent == this)
222 { enum PROT access = smember->prot();
223
224 result = access >= PROTpublic ||
225 hasPrivateAccess(f) ||
226 isFriendOf(cdscope) ||
227 (access == PROTpackage && hasPackageAccess(sc, this));
228 #if LOG
229 printf("result1 = %d\n", result);
230 #endif
231 }
232 else if ((access = this->getAccess(smember)) >= PROTpublic)
233 {
234 result = 1;
235 #if LOG
236 printf("result2 = %d\n", result);
237 #endif
238 }
239 else if (access == PROTpackage && hasPackageAccess(sc, this))
240 {
241 result = 1;
242 #if LOG
243 printf("result3 = %d\n", result);
244 #endif
245 }
246 else
247 {
248 result = accessCheckX(smember, f, this, cdscope);
249 #if LOG
250 printf("result4 = %d\n", result);
251 #endif
252 }
253 if (!result)
254 {
255 error(loc, "member %s is not accessible", smember->toChars());
256 halt();
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 }