336
|
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 }
|