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