You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FieldReference.java 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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. * Palo Alto Research Center, Incorporated - AspectJ adaptation
  11. ******************************************************************************/
  12. package org.eclipse.jdt.internal.compiler.ast;
  13. import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
  14. import org.eclipse.jdt.internal.compiler.impl.*;
  15. import org.eclipse.jdt.internal.compiler.codegen.*;
  16. import org.eclipse.jdt.internal.compiler.flow.*;
  17. import org.eclipse.jdt.internal.compiler.lookup.*;
  18. /**
  19. * AspectJ - support for FieldBinding.alwaysNeedsAccessMethod
  20. */
  21. public class FieldReference extends Reference implements InvocationSite {
  22. public Expression receiver;
  23. public char[] token;
  24. public FieldBinding binding, codegenBinding;
  25. public long nameSourcePosition; //(start<<32)+end
  26. MethodBinding syntheticReadAccessor, syntheticWriteAccessor;
  27. public TypeBinding receiverType;
  28. public FieldReference(char[] source, long pos) {
  29. token = source;
  30. nameSourcePosition = pos;
  31. //by default the position are the one of the field (not true for super access)
  32. sourceStart = (int) (pos >>> 32);
  33. sourceEnd = (int) (pos & 0x00000000FFFFFFFFL);
  34. bits |= BindingIds.FIELD;
  35. }
  36. public FlowInfo analyseAssignment(
  37. BlockScope currentScope,
  38. FlowContext flowContext,
  39. FlowInfo flowInfo,
  40. Assignment assignment,
  41. boolean isCompound) {
  42. // compound assignment extra work
  43. if (isCompound) { // check the variable part is initialized if blank final
  44. if (binding.isFinal()
  45. && receiver.isThis()
  46. && currentScope.allowBlankFinalFieldAssignment(binding)
  47. && (!flowInfo.isDefinitelyAssigned(binding))) {
  48. currentScope.problemReporter().uninitializedBlankFinalField(binding, this);
  49. // we could improve error msg here telling "cannot use compound assignment on final blank field"
  50. }
  51. manageSyntheticReadAccessIfNecessary(currentScope);
  52. }
  53. if (assignment.expression != null) {
  54. flowInfo =
  55. assignment
  56. .expression
  57. .analyseCode(currentScope, flowContext, flowInfo)
  58. .unconditionalInits();
  59. }
  60. flowInfo =
  61. receiver
  62. .analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic())
  63. .unconditionalInits();
  64. manageSyntheticWriteAccessIfNecessary(currentScope);
  65. // check if assigning a final field
  66. if (binding.isFinal()) {
  67. // in a context where it can be assigned?
  68. if (receiver.isThis()
  69. && !(receiver instanceof QualifiedThisReference)
  70. && currentScope.allowBlankFinalFieldAssignment(binding)) {
  71. if (flowInfo.isPotentiallyAssigned(binding)) {
  72. currentScope.problemReporter().duplicateInitializationOfBlankFinalField(
  73. binding,
  74. this);
  75. }
  76. flowInfo.markAsDefinitelyAssigned(binding);
  77. flowContext.recordSettingFinal(binding, this);
  78. } else {
  79. // assigning a final field outside an initializer or constructor
  80. currentScope.problemReporter().cannotAssignToFinalField(binding, this);
  81. }
  82. }
  83. return flowInfo;
  84. }
  85. public FlowInfo analyseCode(
  86. BlockScope currentScope,
  87. FlowContext flowContext,
  88. FlowInfo flowInfo) {
  89. return analyseCode(currentScope, flowContext, flowInfo, true);
  90. }
  91. public FlowInfo analyseCode(
  92. BlockScope currentScope,
  93. FlowContext flowContext,
  94. FlowInfo flowInfo,
  95. boolean valueRequired) {
  96. receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic());
  97. if (valueRequired) {
  98. manageSyntheticReadAccessIfNecessary(currentScope);
  99. }
  100. return flowInfo;
  101. }
  102. public FieldBinding fieldBinding() {
  103. return binding;
  104. }
  105. public void generateAssignment(
  106. BlockScope currentScope,
  107. CodeStream codeStream,
  108. Assignment assignment,
  109. boolean valueRequired) {
  110. receiver.generateCode(
  111. currentScope,
  112. codeStream,
  113. !this.codegenBinding.isStatic());
  114. assignment.expression.generateCode(currentScope, codeStream, true);
  115. fieldStore(
  116. codeStream,
  117. this.codegenBinding,
  118. syntheticWriteAccessor,
  119. valueRequired);
  120. if (valueRequired) {
  121. codeStream.generateImplicitConversion(assignment.implicitConversion);
  122. }
  123. }
  124. /**
  125. * Field reference code generation
  126. *
  127. * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
  128. * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
  129. * @param valueRequired boolean
  130. */
  131. public void generateCode(
  132. BlockScope currentScope,
  133. CodeStream codeStream,
  134. boolean valueRequired) {
  135. int pc = codeStream.position;
  136. if (constant != NotAConstant) {
  137. if (valueRequired) {
  138. codeStream.generateConstant(constant, implicitConversion);
  139. }
  140. } else {
  141. boolean isStatic = this.codegenBinding.isStatic();
  142. receiver.generateCode(
  143. currentScope,
  144. codeStream,
  145. valueRequired && (!isStatic) && (this.codegenBinding.constant == NotAConstant));
  146. if (valueRequired) {
  147. if (this.codegenBinding.constant == NotAConstant) {
  148. if (this.codegenBinding.declaringClass == null) { // array length
  149. codeStream.arraylength();
  150. } else {
  151. if (syntheticReadAccessor == null) {
  152. if (isStatic) {
  153. codeStream.getstatic(this.codegenBinding);
  154. } else {
  155. codeStream.getfield(this.codegenBinding);
  156. }
  157. } else {
  158. codeStream.invokestatic(syntheticReadAccessor);
  159. }
  160. }
  161. codeStream.generateImplicitConversion(implicitConversion);
  162. } else {
  163. codeStream.generateConstant(this.codegenBinding.constant, implicitConversion);
  164. }
  165. }
  166. }
  167. codeStream.recordPositionsFrom(pc, this.sourceStart);
  168. }
  169. public void generateCompoundAssignment(
  170. BlockScope currentScope,
  171. CodeStream codeStream,
  172. Expression expression,
  173. int operator,
  174. int assignmentImplicitConversion,
  175. boolean valueRequired) {
  176. boolean isStatic;
  177. receiver.generateCode(
  178. currentScope,
  179. codeStream,
  180. !(isStatic = this.codegenBinding.isStatic()));
  181. if (isStatic) {
  182. if (syntheticReadAccessor == null) {
  183. codeStream.getstatic(this.codegenBinding);
  184. } else {
  185. codeStream.invokestatic(syntheticReadAccessor);
  186. }
  187. } else {
  188. codeStream.dup();
  189. if (syntheticReadAccessor == null) {
  190. codeStream.getfield(this.codegenBinding);
  191. } else {
  192. codeStream.invokestatic(syntheticReadAccessor);
  193. }
  194. }
  195. int operationTypeID;
  196. if ((operationTypeID = implicitConversion >> 4) == T_String) {
  197. codeStream.generateStringAppend(currentScope, null, expression);
  198. } else {
  199. // promote the array reference to the suitable operation type
  200. codeStream.generateImplicitConversion(implicitConversion);
  201. // generate the increment value (will by itself be promoted to the operation value)
  202. if (expression == IntLiteral.One) { // prefix operation
  203. codeStream.generateConstant(expression.constant, implicitConversion);
  204. } else {
  205. expression.generateCode(currentScope, codeStream, true);
  206. }
  207. // perform the operation
  208. codeStream.sendOperator(operator, operationTypeID);
  209. // cast the value back to the array reference type
  210. codeStream.generateImplicitConversion(assignmentImplicitConversion);
  211. }
  212. fieldStore(
  213. codeStream,
  214. this.codegenBinding,
  215. syntheticWriteAccessor,
  216. valueRequired);
  217. }
  218. public void generatePostIncrement(
  219. BlockScope currentScope,
  220. CodeStream codeStream,
  221. CompoundAssignment postIncrement,
  222. boolean valueRequired) {
  223. boolean isStatic;
  224. receiver.generateCode(
  225. currentScope,
  226. codeStream,
  227. !(isStatic = this.codegenBinding.isStatic()));
  228. if (isStatic) {
  229. if (syntheticReadAccessor == null) {
  230. codeStream.getstatic(this.codegenBinding);
  231. } else {
  232. codeStream.invokestatic(syntheticReadAccessor);
  233. }
  234. } else {
  235. codeStream.dup();
  236. if (syntheticReadAccessor == null) {
  237. codeStream.getfield(this.codegenBinding);
  238. } else {
  239. codeStream.invokestatic(syntheticReadAccessor);
  240. }
  241. }
  242. if (valueRequired) {
  243. if (isStatic) {
  244. if ((this.codegenBinding.type == LongBinding)
  245. || (this.codegenBinding.type == DoubleBinding)) {
  246. codeStream.dup2();
  247. } else {
  248. codeStream.dup();
  249. }
  250. } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
  251. if ((this.codegenBinding.type == LongBinding)
  252. || (this.codegenBinding.type == DoubleBinding)) {
  253. codeStream.dup2_x1();
  254. } else {
  255. codeStream.dup_x1();
  256. }
  257. }
  258. }
  259. codeStream.generateConstant(
  260. postIncrement.expression.constant,
  261. implicitConversion);
  262. codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id);
  263. codeStream.generateImplicitConversion(
  264. postIncrement.assignmentImplicitConversion);
  265. fieldStore(codeStream, this.codegenBinding, syntheticWriteAccessor, false);
  266. }
  267. public static final Constant getConstantFor(
  268. FieldBinding binding,
  269. boolean implicitReceiver,
  270. Reference reference,
  271. Scope referenceScope,
  272. int indexInQualification) {
  273. //propagation of the constant.
  274. //ref can be a FieldReference, a SingleNameReference or a QualifiedNameReference
  275. //indexInQualification may have a value greater than zero only for QualifiednameReference
  276. //if ref==null then indexInQualification==0 AND implicitReceiver == false. This case is a
  277. //degenerated case where a fake reference field (null)
  278. //is associted to a real FieldBinding in order
  279. //to allow its constant computation using the regular path (i.e. find the fieldDeclaration
  280. //and proceed to its type resolution). As implicitReceiver is false, no error reporting
  281. //against ref will be used ==> no nullPointerException risk ....
  282. //special treatment for langage-built-in field (their declaring class is null)
  283. if (binding.declaringClass == null) {
  284. //currently only one field "length" : the constant computation is never done
  285. return NotAConstant;
  286. }
  287. if (!binding.isFinal()) {
  288. return binding.constant = NotAConstant;
  289. }
  290. if (binding.constant != null) {
  291. if (indexInQualification == 0) {
  292. return binding.constant;
  293. }
  294. //see previous comment for the (sould-always-be) valid cast
  295. QualifiedNameReference qualifiedReference = (QualifiedNameReference) reference;
  296. if (indexInQualification == (qualifiedReference.indexOfFirstFieldBinding - 1)) {
  297. return binding.constant;
  298. }
  299. return NotAConstant;
  300. }
  301. //The field has not been yet type checked.
  302. //It also means that the field is not coming from a class that
  303. //has already been compiled. It can only be from a class within
  304. //compilation units to process. Thus the field is NOT from a BinaryTypeBinbing
  305. SourceTypeBinding typeBinding = (SourceTypeBinding) binding.declaringClass;
  306. TypeDeclaration typeDecl = typeBinding.scope.referenceContext;
  307. FieldDeclaration fieldDecl = typeDecl.declarationOf(binding.getFieldBindingForLookup());
  308. //System.err.println(typeDecl + " and " + fieldDecl + ", " + binding);
  309. //what scope to use (depend on the staticness of the field binding)
  310. MethodScope fieldScope =
  311. binding.isStatic()
  312. ? typeDecl.staticInitializerScope
  313. : typeDecl.initializerScope;
  314. if (implicitReceiver) { //Determine if the ref is legal in the current class of the field
  315. //i.e. not a forward reference .... (they are allowed when the receiver is explicit ! ... Please don't ask me why !...yet another java mystery...)
  316. if (fieldScope.fieldDeclarationIndex == MethodScope.NotInFieldDecl) {
  317. // no field is currently being analysed in typeDecl
  318. fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
  319. return binding.constant;
  320. }
  321. //We are re-entering the same class fields analysing
  322. if ((reference != null)
  323. && (binding.declaringClass == referenceScope.enclosingSourceType()) // only complain for access inside same type
  324. && (binding.id > fieldScope.fieldDeclarationIndex)) {
  325. //forward reference. The declaration remains unresolved.
  326. referenceScope.problemReporter().forwardReference(reference, indexInQualification, typeBinding);
  327. return NotAConstant;
  328. }
  329. fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
  330. return binding.constant;
  331. }
  332. //the field reference is explicity. It has to be a "simple" like field reference to get the
  333. //constant propagation. For example in Packahe.Type.field1.field2 , field1 may have its
  334. //constant having a propagation where field2 is always not propagating its
  335. if (indexInQualification == 0) {
  336. fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
  337. return binding.constant;
  338. }
  339. // Side-effect on the field binding may not be propagated out for the qualified reference
  340. // unless it occurs in first place of the name sequence
  341. fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
  342. //see previous comment for the cast that should always be valid
  343. QualifiedNameReference qualifiedReference = (QualifiedNameReference) reference;
  344. if (indexInQualification == (qualifiedReference.indexOfFirstFieldBinding - 1)) {
  345. return binding.constant;
  346. } else {
  347. return NotAConstant;
  348. }
  349. }
  350. public boolean isSuperAccess() {
  351. return receiver.isSuper();
  352. }
  353. public boolean isTypeAccess() {
  354. return receiver != null && receiver.isTypeReference();
  355. }
  356. /*
  357. * No need to emulate access to protected fields since not implicitly accessed
  358. */
  359. public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
  360. if (binding.alwaysNeedsAccessMethod(true)) {
  361. syntheticReadAccessor = binding.getAccessMethod(true);
  362. return;
  363. }
  364. if (binding.isPrivate()) {
  365. if ((currentScope.enclosingSourceType() != binding.declaringClass)
  366. && (binding.constant == NotAConstant)) {
  367. syntheticReadAccessor =
  368. ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, true);
  369. currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this);
  370. return;
  371. }
  372. } else if (receiver instanceof QualifiedSuperReference) { // qualified super
  373. // qualified super need emulation always
  374. SourceTypeBinding destinationType =
  375. (SourceTypeBinding) (((QualifiedSuperReference) receiver)
  376. .currentCompatibleType);
  377. syntheticReadAccessor = destinationType.addSyntheticMethod(binding, true);
  378. currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this);
  379. return;
  380. } else if (binding.isProtected()) {
  381. SourceTypeBinding enclosingSourceType;
  382. if (((bits & DepthMASK) != 0)
  383. && binding.declaringClass.getPackage()
  384. != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) {
  385. SourceTypeBinding currentCompatibleType =
  386. (SourceTypeBinding) enclosingSourceType.enclosingTypeAt(
  387. (bits & DepthMASK) >> DepthSHIFT);
  388. syntheticReadAccessor = currentCompatibleType.addSyntheticMethod(binding, true);
  389. currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this);
  390. return;
  391. }
  392. }
  393. // if the binding declaring class is not visible, need special action
  394. // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
  395. // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
  396. if (binding.declaringClass != this.receiverType
  397. && !this.receiverType.isArrayType()
  398. && binding.declaringClass != null // array.length
  399. && binding.constant == NotAConstant
  400. && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
  401. && binding.declaringClass.id != T_Object)
  402. //no change for Object fields (in case there was)
  403. || !binding.declaringClass.canBeSeenBy(currentScope))) {
  404. this.codegenBinding =
  405. currentScope.enclosingSourceType().getUpdatedFieldBinding(
  406. binding,
  407. (ReferenceBinding) this.receiverType);
  408. }
  409. }
  410. /*
  411. * No need to emulate access to protected fields since not implicitly accessed
  412. */
  413. public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
  414. //System.err.println("manage synthetic: " + this + " with " + binding + ", " + binding.getClass());
  415. if (binding.alwaysNeedsAccessMethod(false)) {
  416. syntheticWriteAccessor = binding.getAccessMethod(false);
  417. return;
  418. }
  419. if (binding.isPrivate()) {
  420. if (currentScope.enclosingSourceType() != binding.declaringClass) {
  421. syntheticWriteAccessor =
  422. ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, false);
  423. currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this);
  424. return;
  425. }
  426. } else if (receiver instanceof QualifiedSuperReference) { // qualified super
  427. // qualified super need emulation always
  428. SourceTypeBinding destinationType =
  429. (SourceTypeBinding) (((QualifiedSuperReference) receiver)
  430. .currentCompatibleType);
  431. syntheticWriteAccessor = destinationType.addSyntheticMethod(binding, false);
  432. currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this);
  433. return;
  434. } else if (binding.isProtected()) {
  435. SourceTypeBinding enclosingSourceType;
  436. if (((bits & DepthMASK) != 0)
  437. && binding.declaringClass.getPackage()
  438. != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) {
  439. SourceTypeBinding currentCompatibleType =
  440. (SourceTypeBinding) enclosingSourceType.enclosingTypeAt(
  441. (bits & DepthMASK) >> DepthSHIFT);
  442. syntheticWriteAccessor =
  443. currentCompatibleType.addSyntheticMethod(binding, false);
  444. currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this);
  445. return;
  446. }
  447. }
  448. // if the binding declaring class is not visible, need special action
  449. // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
  450. // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
  451. if (binding.declaringClass != this.receiverType
  452. && !this.receiverType.isArrayType()
  453. && binding.declaringClass != null // array.length
  454. && binding.constant == NotAConstant
  455. && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
  456. && binding.declaringClass.id != T_Object)
  457. //no change for Object fields (in case there was)
  458. || !binding.declaringClass.canBeSeenBy(currentScope))) {
  459. this.codegenBinding =
  460. currentScope.enclosingSourceType().getUpdatedFieldBinding(
  461. binding,
  462. (ReferenceBinding) this.receiverType);
  463. }
  464. }
  465. public TypeBinding resolveType(BlockScope scope) {
  466. // Answer the signature type of the field.
  467. // constants are propaged when the field is final
  468. // and initialized with a (compile time) constant
  469. // regular receiver reference
  470. this.receiverType = receiver.resolveType(scope);
  471. if (this.receiverType == null) {
  472. constant = NotAConstant;
  473. return null;
  474. }
  475. // the case receiverType.isArrayType and token = 'length' is handled by the scope API
  476. this.codegenBinding =
  477. this.binding = scope.getField(this.receiverType, token, this);
  478. if (!binding.isValidBinding()) {
  479. constant = NotAConstant;
  480. scope.problemReporter().invalidField(this, this.receiverType);
  481. return null;
  482. }
  483. if (isFieldUseDeprecated(binding, scope))
  484. scope.problemReporter().deprecatedField(binding, this);
  485. // check for this.x in static is done in the resolution of the receiver
  486. constant =
  487. FieldReference.getConstantFor(
  488. binding,
  489. receiver == ThisReference.ThisImplicit,
  490. this,
  491. scope,
  492. 0);
  493. if (receiver != ThisReference.ThisImplicit)
  494. constant = NotAConstant;
  495. return binding.type;
  496. }
  497. public void setActualReceiverType(ReferenceBinding receiverType) {
  498. // ignored
  499. }
  500. public void setDepth(int depth) {
  501. if (depth > 0) {
  502. bits &= ~DepthMASK; // flush previous depth if any
  503. bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits
  504. }
  505. }
  506. public void setFieldIndex(int index) {
  507. // ignored
  508. }
  509. public String toStringExpression() {
  510. return receiver.toString() + "." //$NON-NLS-1$
  511. + new String(token);
  512. }
  513. public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
  514. if (visitor.visit(this, scope)) {
  515. receiver.traverse(visitor, scope);
  516. }
  517. visitor.endVisit(this, scope);
  518. }
  519. }