Skip to main content
summaryrefslogtreecommitdiffstats
blob: 8df58818df656079261741f4dbc475f955b8440e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
package org.eclipse.jdt.internal.compiler.ast;

/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */
import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.lookup.*;

public class ExplicitConstructorCall extends Statement implements InvocationSite {
	public Expression[] arguments;
	public Expression qualification;
	public MethodBinding binding;

	public int accessMode;

	public final static int ImplicitSuper = 1;
	public final static int Super = 2;
	public final static int This = 3;

	public VariableBinding[][] implicitArguments;
	boolean discardEnclosingInstance;

	MethodBinding syntheticAccessor;

public ExplicitConstructorCall(int accessMode) {
	this.accessMode = accessMode;
}
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {

	// must verify that exceptions potentially thrown by this expression are caught in the method.

	try {
		((MethodScope) currentScope).isConstructorCall = true;
		
		// process enclosing instance
		if (qualification != null){
			flowInfo = qualification.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
		}
		// process arguments
		if (arguments != null){
			for (int i = 0, max = arguments.length; i < max; i++) {
				flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
			}
		}

		ReferenceBinding[] thrownExceptions;
		if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
			// check exceptions
			flowContext.checkExceptionHandlers(
				thrownExceptions, 
				(accessMode == ImplicitSuper) ? (AstNode)currentScope.methodScope().referenceContext : (AstNode)this, 
				flowInfo, 
				currentScope);
		}
		manageEnclosingInstanceAccessIfNecessary(currentScope);
		manageSyntheticAccessIfNecessary(currentScope);
		return flowInfo;
	} finally {
		((MethodScope) currentScope).isConstructorCall = false;
	}
}
/**
 * Constructor call code generation
 *
 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
 */
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
	if ((bits & IsReachableMASK) == 0) {
		return;
	}
	try {
		((MethodScope) currentScope).isConstructorCall = true;
	
		int pc = codeStream.position;
		codeStream.aload_0();

		// handling innerclass constructor invocation
		ReferenceBinding targetType;
		if ((targetType = binding.declaringClass).isNestedType()){
			codeStream.generateSyntheticArgumentValues(currentScope, targetType, discardEnclosingInstance ? null : qualification, this);
		}	
		// regular code gen
		if (arguments != null){
			for (int i = 0, max = arguments.length; i < max; i++) {
				arguments[i].generateCode(currentScope, codeStream, true);
			}
		}
		if (syntheticAccessor != null){
			// synthetic accessor got some extra arguments appended to its signature, which need values
			for (int i = 0, max = syntheticAccessor.parameters.length - binding.parameters.length; i < max; i++){
				codeStream.aconst_null();
			}
			codeStream.invokespecial(syntheticAccessor);			
		} else {
			codeStream.invokespecial(binding);
		}
		codeStream.recordPositionsFrom(pc, this);
	} finally {
		((MethodScope) currentScope).isConstructorCall = false;
	}
}
public boolean isImplicitSuper(){
	//return true if I'm of these compiler added statement super();

	return (accessMode == ImplicitSuper) ;}
public boolean isSuperAccess(){
	return accessMode != This;
}
public boolean isTypeAccess(){
	return true;
}
/* Inner emulation consists in either recording a dependency 
 * link only, or performing one level of propagation.
 *
 * Dependency mechanism is used whenever dealing with source target
 * types, since by the time we reach them, we might not yet know their
 * exact need.
 */
void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
	ReferenceBinding invocationType, superType;

	// perform some emulation work in case there is some and we are inside a local type only
	if ((superType = binding.declaringClass).isNestedType() 
		&& currentScope.enclosingSourceType().isLocalType()) {

		if (superType.isLocalType()){
			((LocalTypeBinding)superType).addInnerEmulationDependent(currentScope, qualification != null, true); // request direct access
		} else {
			// locally propagate, since we already now the desired shape for sure
			currentScope.propagateInnerEmulation(superType, qualification != null, true); // request direct access
			
		}
	}
}
public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {

	// perform some emulation work in case there is some and we are inside a local type only
	if (binding.isPrivate() && (accessMode != This)) {

		if (currentScope.environment().options.isPrivateConstructorAccessChangingVisibility){
			binding.tagForClearingPrivateModifier(); // constructor will not be dumped as private, no emulation required thus
		} else {
			syntheticAccessor = ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
			currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
		}
	}
}
public void resolve(BlockScope scope) {
	// the return type should be void for a constructor.
	// the test is made into getConstructor

	// mark the fact that we are in a constructor call.....
	// unmark at all returns
	try {
		((MethodScope) scope).isConstructorCall = true;
		ReferenceBinding receiverType = scope.enclosingSourceType();
		if (accessMode != This)
			receiverType = receiverType.superclass();

		if (receiverType == null) { 
			return;
		}

		// qualification should be from the type of the enclosingType
		if (qualification != null) {
			if (accessMode != Super){
				scope.problemReporter().unnecessaryEnclosingInstanceSpecification(qualification, receiverType);
			}
			ReferenceBinding enclosingType = receiverType.enclosingType();
			if (enclosingType == null) {
				scope.problemReporter().unnecessaryEnclosingInstanceSpecification(qualification, receiverType);
				discardEnclosingInstance = true;
			} else {
				TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
				qualification.implicitWidening(qTb, qTb);
			}
		}

		// arguments buffering for the method lookup
		TypeBinding[] argTypes = NoParameters;
		if (arguments != null) {
			boolean argHasError = false; // typeChecks all arguments
			int length = arguments.length;
			argTypes = new TypeBinding[length];
			for (int i = 0; i < length; i++)
				if ((argTypes[i] = arguments[i].resolveType(scope)) == null)
					argHasError = true;
			if (argHasError)
				return;
		}
		if ((binding = scope.getConstructor(receiverType, argTypes, this)).isValidBinding()) {
			if (isMethodUseDeprecated(binding, scope))
				scope.problemReporter().deprecatedMethod(binding, this);
			
			// see for user-implicit widening conversion 
			if (arguments != null) {
				int length = arguments.length;
				TypeBinding[] paramTypes = binding.parameters;
				for (int i = 0; i < length; i++)
					arguments[i].implicitWidening(paramTypes[i], argTypes[i]);
			}
		} else {
			if (binding.declaringClass == null)
				binding.declaringClass = receiverType;
			scope.problemReporter().invalidConstructor(this, binding);
		}
	} finally {
		((MethodScope) scope).isConstructorCall = false;
	}
}
public void setDepth(int depth){
	// ignore for here
}
public void setFieldIndex(int depth){
	// ignore for here
}
public String toString(int tab){
	/* slow code */

	String s = tabString(tab);
	if (qualification != null) 
		s = s + qualification.toStringExpression() + "."/*nonNLS*/ ;
	if (accessMode == This){
		s = s + "this("/*nonNLS*/;
	} else {
		s = s + "super("/*nonNLS*/;
	}
	if (arguments != null)
		for (int i=0 ; i < arguments.length ; i++)
		{	s = s + arguments[i].toStringExpression();
			if (i != arguments.length-1) s = s + ", "/*nonNLS*/;};;
	s = s+")"/*nonNLS*/ ;
	return s;}
public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
	if (visitor.visit(this, scope)) {
		if (qualification != null) {
			qualification.traverse(visitor, scope);
		}
		if (arguments != null) {
			int argumentLength = arguments.length;
			for (int i = 0; i < argumentLength; i++)
				arguments[i].traverse(visitor, scope);
		}
	}
	visitor.endVisit(this, scope);
}
}

Back to the top