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.

IfPseudoToken.java 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.compiler.ast;
  13. import java.lang.reflect.Modifier;
  14. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  15. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  16. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
  17. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
  18. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
  19. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
  20. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
  21. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
  34. import org.aspectj.weaver.Member;
  35. import org.aspectj.weaver.ResolvedMemberImpl;
  36. import org.aspectj.weaver.UnresolvedType;
  37. import org.aspectj.weaver.patterns.IfPointcut;
  38. import org.aspectj.weaver.patterns.Pointcut;
  39. /**
  40. * (formals*): ... if(expr) ...
  41. *
  42. * generates the following: public static final boolean ajc$if_N(formals*,
  43. * [thisJoinPoints as needed]) { return expr; }
  44. *
  45. * Here's the complicated bit, it deals with cflow: (a): ... this(a) && cflow(if
  46. * (a == foo)) is an error. The way we capture this is: We generate the ajc$if
  47. * method with an (a) parameter, we let eclipse do the proper name binding. We
  48. * then, as a post pass (that we need to do anyway) look for the used
  49. * parameters. If a is used, we signal an error because a was not one of the
  50. * cflow variables. XXX we'll do this part after we do cflow
  51. *
  52. * The IfPointcut pcd then generates itself always as a dynamic test, it has to
  53. * get the right parameters through any named pointcut references...
  54. */
  55. public class IfPseudoToken extends PseudoToken {
  56. public Expression expr;
  57. public MethodDeclaration testMethod;
  58. private IfPointcut pointcut;
  59. public IfPseudoToken(Parser parser, Expression expr) {
  60. super(parser, "if", false);
  61. this.expr = expr;
  62. }
  63. public Pointcut maybeGetParsedPointcut() {
  64. if (expr instanceof FalseLiteral) {
  65. return IfPointcut.makeIfFalsePointcut(Pointcut.SYMBOLIC);
  66. } else if (expr instanceof TrueLiteral) {
  67. return IfPointcut.makeIfTruePointcut(Pointcut.SYMBOLIC);
  68. } else {
  69. pointcut = new IfPointcut(new ResolvedMemberImpl(Member.METHOD,
  70. UnresolvedType.OBJECT, 0, "if_", "()V"), 0);
  71. }
  72. return pointcut;
  73. }
  74. /**
  75. * enclosingDec is either AdviceDeclaration or PointcutDeclaration
  76. */
  77. public int postParse(TypeDeclaration typeDec,
  78. MethodDeclaration enclosingDec, int counter) {
  79. // typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd,
  80. // "if pcd is not implemented in 1.1alpha1");
  81. // XXX need to implement correctly
  82. if (pointcut == null)
  83. return 0;
  84. testMethod = makeIfMethod(enclosingDec.compilationResult, enclosingDec, typeDec, counter);
  85. AstUtil.addMethodDeclaration(typeDec, testMethod);
  86. return 1;
  87. }
  88. private final static char[] CodeGenerationHint = "CodeGenerationHint".toCharArray();
  89. private final static char[] FullyQualifiedCodeGenerationHint = "org.aspectj.lang.annotation.control.CodeGenerationHint".toCharArray();
  90. private final static char[] IfNameSuffix = "ifNameSuffix".toCharArray();
  91. // XXX todo: make sure that errors in Arguments only get displayed once
  92. private MethodDeclaration makeIfMethod(CompilationResult result, MethodDeclaration enclosingDec, TypeDeclaration containingTypeDec, int counter) {
  93. MethodDeclaration ret = new IfMethodDeclaration(result, pointcut);
  94. ret.modifiers = ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccPublic;
  95. ret.returnType = AstUtil.makeTypeReference(TypeBinding.BOOLEAN);
  96. String nameSuffix = null;
  97. if (enclosingDec!=null && enclosingDec.annotations!=null) {
  98. NormalAnnotation interestingAnnotation = null;
  99. Annotation[] as = enclosingDec.annotations;
  100. if (as!=null) {
  101. for (int a = 0; a < as.length && interestingAnnotation == null; a++) {
  102. if (as[a] instanceof NormalAnnotation) {
  103. TypeReference tr = as[a].type;
  104. if (tr instanceof SingleTypeReference) {
  105. if (CharOperation.equals(CodeGenerationHint,((SingleTypeReference)tr).token)) {
  106. interestingAnnotation = (NormalAnnotation)as[a];
  107. }
  108. } else if (tr instanceof QualifiedTypeReference) {
  109. char[] qualifiedName = CharOperation.concatWith(((QualifiedTypeReference)tr).tokens,'.');
  110. if (CharOperation.equals(FullyQualifiedCodeGenerationHint,qualifiedName)) {
  111. interestingAnnotation = (NormalAnnotation)as[a];
  112. }
  113. }
  114. }
  115. }
  116. }
  117. if (interestingAnnotation!=null) {
  118. MemberValuePair[] memberValuePairs = interestingAnnotation.memberValuePairs;
  119. for (MemberValuePair memberValuePair: memberValuePairs) {
  120. if (CharOperation.equals(IfNameSuffix,memberValuePair.name) && (memberValuePair.value instanceof StringLiteral)) {
  121. nameSuffix = new String(((StringLiteral)memberValuePair.value).source());
  122. }
  123. }
  124. }
  125. }
  126. // create a more stable name 277508
  127. StringBuilder ifSelector = new StringBuilder();
  128. ifSelector.append("ajc$if$");
  129. if (nameSuffix == null || nameSuffix.length()==0) {
  130. boolean computedName = false;
  131. try {
  132. // possibly even better logic for more reliable name:
  133. if (enclosingDec instanceof AdviceDeclaration) {
  134. // name is ajc$if$<adviceSequenceNumber>[$<ifnumberinPcd>]$<hashcodeOfIfExpressionInHex>
  135. ifSelector.append(((AdviceDeclaration)enclosingDec).adviceSequenceNumberInType).append("$");
  136. if (counter!=0) {
  137. ifSelector.append(counter);
  138. ifSelector.append("$");
  139. }
  140. ifSelector.append(Integer.toHexString(expr.toString().hashCode()));
  141. computedName = true;
  142. } else if (enclosingDec instanceof PointcutDeclaration) {
  143. if (counter!=0) {
  144. ifSelector.append(counter);
  145. ifSelector.append("$");
  146. }
  147. StringBuilder toHash = new StringBuilder(((PointcutDeclaration) enclosingDec).getPointcutText());
  148. toHash.append(expr.toString());
  149. // name is pointcut selector then $if[$<ifnumberinpcd>]$<hashcodeofpointcuttextandexpressiontext>
  150. ifSelector.append(Integer.toHexString(toHash.toString().hashCode()));
  151. computedName = true;
  152. }
  153. } catch (Throwable t) {
  154. throw new IllegalStateException(t);
  155. // let it build a name the 'old way'
  156. }
  157. if (!computedName) {
  158. ifSelector.append(Integer.toHexString(expr.sourceStart));
  159. }
  160. } else {
  161. ifSelector.append(nameSuffix);
  162. }
  163. ret.selector = ifSelector.toString().toCharArray();
  164. ret.arguments = makeArguments(enclosingDec, containingTypeDec);
  165. ret.statements = new Statement[] { new ReturnStatement(expr,
  166. expr.sourceStart, expr.sourceEnd) };
  167. return ret;
  168. }
  169. private Argument[] makeArguments(MethodDeclaration enclosingDec,
  170. TypeDeclaration containingTypeDec) {
  171. Argument[] baseArguments = enclosingDec.arguments;
  172. int len = baseArguments.length;
  173. if (enclosingDec instanceof AdviceDeclaration) {
  174. len = ((AdviceDeclaration) enclosingDec).baseArgumentCount;
  175. }
  176. Argument[] ret = new Argument[len];
  177. for (int i = 0; i < len; i++) {
  178. Argument a = baseArguments[i];
  179. ret[i] = new Argument(a.name, AstUtil.makeLongPos(a.sourceStart,
  180. a.sourceEnd), a.type, Modifier.FINAL);
  181. }
  182. ret = AdviceDeclaration.addTjpArguments(ret, containingTypeDec);
  183. return ret;
  184. }
  185. }