a253b40c3a977b07e7c040463201b9ee29a4b8c9
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / QualifiedThisReference.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
22
23 public class QualifiedThisReference extends ThisReference {
24         
25         public TypeReference qualification;
26         ReferenceBinding currentCompatibleType;
27
28         public QualifiedThisReference(TypeReference name, int pos, int sourceEnd) {
29
30                 qualification = name;
31                 this.sourceEnd = sourceEnd;
32                 this.sourceStart = name.sourceStart;
33         }
34
35         public FlowInfo analyseCode(
36                 BlockScope currentScope,
37                 FlowContext flowContext,
38                 FlowInfo flowInfo) {
39
40                 manageEnclosingInstanceAccessIfNecessary(currentScope);
41                 return flowInfo;
42         }
43
44         public FlowInfo analyseCode(
45                 BlockScope currentScope,
46                 FlowContext flowContext,
47                 FlowInfo flowInfo,
48                 boolean valueRequired) {
49
50                 if (valueRequired) {
51                         manageEnclosingInstanceAccessIfNecessary(currentScope);
52                 }
53                 return flowInfo;
54         }
55
56         protected boolean checkAccess(
57                 MethodScope methodScope,
58                 TypeBinding targetType) {
59
60                 // this/super cannot be used in constructor call
61                 if (methodScope.isConstructorCall) {
62                         methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this);
63                         return false;
64                 }
65
66                 // static may not refer to this/super
67                 if (methodScope.isStatic) {
68                         methodScope.problemReporter().incorrectEnclosingInstanceReference(
69                                 this,
70                                 targetType);
71                         return false;
72                 }
73                 return true;
74         }
75
76         /**
77          * Code generation for QualifiedThisReference
78          *
79          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
80          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
81          * @param valueRequired boolean
82          */
83         public void generateCode(
84                 BlockScope currentScope,
85                 CodeStream codeStream,
86                 boolean valueRequired) {
87
88                 int pc = codeStream.position;
89                 if (valueRequired) {
90                         if ((bits & DepthMASK) != 0) {
91                                 Object[] emulationPath =
92                                         currentScope.getExactEmulationPath(currentCompatibleType);
93                                 if (emulationPath == null) {
94                                         // internal error, per construction we should have found it
95                                         currentScope.problemReporter().needImplementation();
96                                 } else {
97                                         codeStream.generateOuterAccess(emulationPath, this, currentScope);
98                                 }
99                         } else {
100                                 // nothing particular after all
101                                 codeStream.aload_0();
102                         }
103                 }
104                 codeStream.recordPositionsFrom(pc, this.sourceStart);
105         }
106
107         void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
108
109                 currentScope.emulateOuterAccess(
110                         (SourceTypeBinding) currentCompatibleType,
111                         false);
112                 // request cascade of accesses
113         }
114
115         public TypeBinding resolveType(BlockScope scope) {
116
117                 constant = NotAConstant;
118                 TypeBinding qualificationTb = qualification.resolveType(scope);
119                 if (qualificationTb == null)
120                         return null;
121
122                 // the qualification MUST exactly match some enclosing type name
123                 // Its possible to qualify 'this' by the name of the current class
124                 int depth = 0;
125                 currentCompatibleType = scope.referenceType().binding;
126                 while (currentCompatibleType != null
127                         && currentCompatibleType != qualificationTb) {
128                         depth++;
129                         currentCompatibleType =
130                                 currentCompatibleType.isStatic() ? null : currentCompatibleType.enclosingType();
131                 }
132                 bits &= ~DepthMASK; // flush previous depth if any                      
133                 bits |= (depth & 0xFF) << DepthSHIFT; // encoded depth into 8 bits
134
135                 if (currentCompatibleType == null) {
136                         scope.problemReporter().incorrectEnclosingInstanceReference(
137                                 this,
138                                 qualificationTb);
139                         return null;
140                 }
141
142                 // Ensure one cannot write code like: B() { super(B.this); }
143                 if (depth == 0) {
144                         if (!checkAccess(scope.methodScope(), qualificationTb))
145                                 return null;
146                 } else {
147                         // Could also be targeting an enclosing instance inside a super constructor invocation
148                         //      class X {
149                         //              public X(int i) {
150                         //                      this(new Object() { Object obj = X.this; });
151                         //              }
152                         //      }
153
154                         MethodScope methodScope = scope.methodScope();
155                         while (methodScope != null) {
156                                 if (methodScope.enclosingSourceType() == currentCompatibleType) {
157                                         if (!this.checkAccess(methodScope, qualificationTb))
158                                                 return null;
159                                         break;
160                                 }
161                                 methodScope = methodScope.parent.methodScope();
162                         }
163                 }
164                 return qualificationTb;
165         }
166
167         public String toStringExpression() {
168
169                 return qualification.toString(0) + ".this"; //$NON-NLS-1$
170         }
171
172         public void traverse(
173                 IAbstractSyntaxTreeVisitor visitor,
174                 BlockScope blockScope) {
175
176                 if (visitor.visit(this, blockScope)) {
177                         qualification.traverse(visitor, blockScope);
178                 }
179                 visitor.endVisit(this, blockScope);
180         }
181 }