|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v 2.0
- * which accompanies this distribution and is available at
- * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
- *
- * Contributors:
- * PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.ajdt.internal.compiler.ast;
-
- import java.lang.reflect.Modifier;
-
- import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
- import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation;
- import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger;
- import org.aspectj.ajdt.internal.compiler.lookup.InterTypeScope;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
- import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CastExpression;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NullLiteral;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
- import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
- import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
- import org.aspectj.weaver.AjAttribute;
- import org.aspectj.weaver.AjcMemberMaker;
- import org.aspectj.weaver.Constants;
- import org.aspectj.weaver.Member;
- import org.aspectj.weaver.NameMangler;
- import org.aspectj.weaver.NewConstructorTypeMunger;
- import org.aspectj.weaver.ResolvedMember;
- import org.aspectj.weaver.ResolvedMemberImpl;
- import org.aspectj.weaver.ResolvedType;
- import org.aspectj.weaver.Shadow;
- import org.aspectj.weaver.UnresolvedType;
-
- /**
- * An inter-type constructor declaration.
- *
- * This will generate two implementation methods in the aspect, the main one for the body of the constructor, and an additional
- * <code>preMethod</code> for the code that runs before the super constructor is called.
- *
- * @author Jim Hugunin
- */
- public class InterTypeConstructorDeclaration extends InterTypeDeclaration {
- private static final String SUPPRESSAJWARNINGS = "Lorg/aspectj/lang/annotation/SuppressAjWarnings;";
- private static final String NOEXPLICITCONSTRUCTORCALL = "noExplicitConstructorCall";
- private MethodDeclaration preMethod;
- private ExplicitConstructorCall explicitConstructorCall = null;
-
- public InterTypeConstructorDeclaration(CompilationResult result, TypeReference onType) {
- super(result, onType);
- }
-
- public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
- if (ignoreFurtherInvestigation)
- return;
- parser.parse(this, unit);
- }
-
- protected char[] getPrefix() {
- return (NameMangler.ITD_PREFIX + "interConstructor$").toCharArray();
- }
-
- public void resolve(ClassScope upperScope) {
- if (munger == null || binding == null)
- ignoreFurtherInvestigation = true;
- if (ignoreFurtherInvestigation)
- return;
-
- explicitConstructorCall = null;
- if (statements != null && statements.length > 0 && statements[0] instanceof ExplicitConstructorCall) {
- explicitConstructorCall = (ExplicitConstructorCall) statements[0];
- statements = AstUtil.remove(0, statements);
- }
-
- preMethod = makePreMethod(upperScope, explicitConstructorCall);
-
- binding.parameters = AstUtil.insert(onTypeBinding, binding.parameters);
- this.arguments = AstUtil.insert(AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding), this.arguments);
-
- super.resolve(upperScope);
-
- // after annotations have been resolved...
- if (explicitConstructorCall == null) {
- raiseNoFieldInitializersWarning();
- }
- }
-
- /**
- * Warning added in response to PR 62606 - if an ITD constructor does not make an explicit constructor call then field
- * initializers in the target class will not be executed leading to unexpected behaviour.
- */
- private void raiseNoFieldInitializersWarning() {
- if (suppressingNoExplicitConstructorCall())
- return;
- EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
- ISourceLocation location = new EclipseSourceLocation(scope.problemReporter().referenceContext.compilationResult(),
- sourceStart(), sourceEnd());
- world.getWorld().getLint().noExplicitConstructorCall.signal(null, location);
- }
-
- /**
- * true iff constructor has @SuppressAjWarnings or @SuppressAjWarnings("xyz,noExplicitConstructorCall,def,...")
- *
- * @return
- */
- private boolean suppressingNoExplicitConstructorCall() {
- if (this.annotations == null)
- return false;
- for (org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation annotation : this.annotations) {
- if (new String(annotation.resolvedType.signature()).equals(SUPPRESSAJWARNINGS)) {
- if (annotation instanceof MarkerAnnotation) {
- return true;
- } else if (annotation instanceof SingleMemberAnnotation) {
- SingleMemberAnnotation sma = (SingleMemberAnnotation) annotation;
- if (sma.memberValue instanceof ArrayInitializer) {
- ArrayInitializer memberValue = (ArrayInitializer) sma.memberValue;
- for (int j = 0; j < memberValue.expressions.length; j++) {
- if (memberValue.expressions[j] instanceof StringLiteral) {
- StringLiteral val = (StringLiteral) memberValue.expressions[j];
- if (new String(val.source()).equals(NOEXPLICITCONSTRUCTORCALL))
- return true;
- }
- }
- }
- }
- }
- }
- return false;
- }
-
- private MethodDeclaration makePreMethod(ClassScope scope, ExplicitConstructorCall explicitConstructorCall) {
- EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
-
- UnresolvedType aspectTypeX = world.fromBinding(binding.declaringClass);
- UnresolvedType targetTypeX = world.fromBinding(onTypeBinding);
-
- ArrayBinding objectArrayBinding = scope.createArrayType(scope.getJavaLangObject(), 1);
-
- MethodDeclaration pre = new MethodDeclaration(compilationResult);
- pre.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
- pre.returnType = AstUtil.makeTypeReference(objectArrayBinding);
- pre.selector = NameMangler.postIntroducedConstructor(aspectTypeX, targetTypeX).toCharArray();
-
- pre.arguments = AstUtil.copyArguments(this.arguments);
-
- // XXX should do exceptions
-
- pre.scope = new MethodScope(scope, pre, true);
- // ??? do we need to do anything with scope???
-
- // Use the factory to build a semi-correct resolvedmember - then patch it up with
- // reset calls. This is SAFE
- ResolvedMemberImpl preIntroducedConstructorRM = world.makeResolvedMember(binding);
- preIntroducedConstructorRM.resetName(NameMangler.preIntroducedConstructor(aspectTypeX, targetTypeX));
- preIntroducedConstructorRM.resetModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
- preIntroducedConstructorRM.resetReturnTypeToObjectArray();
-
- pre.binding = world.makeMethodBinding(preIntroducedConstructorRM);
-
- pre.bindArguments();
- pre.bindThrownExceptions();
-
- if (explicitConstructorCall == null) {
- pre.statements = new Statement[] {};
- } else {
- pre.statements = new Statement[] { explicitConstructorCall };
- }
-
- InterTypeScope newParent = new InterTypeScope(scope, onTypeBinding);
- // Use setter in order to also update member 'compilationUnitScope'
- pre.scope.setParent(newParent);
-
- pre.resolveStatements(); // newParent);
-
- int nParams = pre.arguments.length;
- MethodBinding explicitConstructor = null;
- if (explicitConstructorCall != null) {
- explicitConstructor = explicitConstructorCall.binding;
- // If it is null then we are going to report something else is wrong with this code!
- if (explicitConstructor != null && explicitConstructor.alwaysNeedsAccessMethod()) {
- explicitConstructor = explicitConstructor.getAccessMethod(true);
- }
- }
-
- int nExprs;
- if (explicitConstructor == null)
- nExprs = 0;
- else
- nExprs = explicitConstructor.parameters.length;
-
- ArrayInitializer init = new ArrayInitializer();
- init.expressions = new Expression[nExprs + nParams];
- int index = 0;
- for (int i = 0; i < nExprs; i++) {
- if (i >= (explicitConstructorCall.arguments == null ? 0 : explicitConstructorCall.arguments.length)) {
- init.expressions[index++] = new NullLiteral(0, 0);
- continue;
- }
-
- Expression arg = explicitConstructorCall.arguments[i];
- ResolvedMember conversionMethod = AjcMemberMaker.toObjectConversionMethod(world
- .fromBinding(explicitConstructorCall.binding.parameters[i]));
- if (conversionMethod != null) {
- arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod), new CastExpression(new NullLiteral(0,
- 0), AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
- new Expression[] { arg });
- }
- init.expressions[index++] = arg;
- }
-
- for (int i = 0; i < nParams; i++) {
- LocalVariableBinding binding = pre.arguments[i].binding;
- Expression arg = AstUtil.makeResolvedLocalVariableReference(binding);
- ResolvedMember conversionMethod = AjcMemberMaker.toObjectConversionMethod(world.fromBinding(binding.type));
- if (conversionMethod != null) {
- arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod), new CastExpression(new NullLiteral(0,
- 0), AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
- new Expression[] { arg });
- }
- init.expressions[index++] = arg;
- }
-
- init.binding = objectArrayBinding;
-
- ArrayAllocationExpression newArray = new ArrayAllocationExpression();
- newArray.initializer = init;
- newArray.type = AstUtil.makeTypeReference(scope.getJavaLangObject());
- newArray.dimensions = new Expression[1];
- newArray.constant = Constant.NotAConstant;
-
- pre.statements = new Statement[] { new ReturnStatement(newArray, 0, 0), };
- return pre;
- }
-
- public EclipseTypeMunger build(ClassScope classScope) {
- EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
-
- resolveOnType(classScope);
- if (ignoreFurtherInvestigation)
- return null;
-
- binding = classScope.referenceContext.binding.resolveTypesFor(binding);
-
- if (isTargetAnnotation(classScope, "constructor"))
- return null; // Error message output in isTargetAnnotation
- if (isTargetEnum(classScope, "constructor"))
- return null; // Error message output in isTargetEnum
-
- if (onTypeBinding.isInterface()) {
- classScope.problemReporter().signalError(sourceStart, sourceEnd, "can't define constructors on interfaces");
- ignoreFurtherInvestigation = true;
- return null;
- }
-
- if (onTypeBinding.isNestedType()) {
- classScope.problemReporter().signalError(sourceStart, sourceEnd,
- "can't define constructors on nested types (compiler limitation)");
- ignoreFurtherInvestigation = true;
- return null;
- }
-
- ResolvedType declaringTypeX = world.fromEclipse(onTypeBinding);
- ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
-
- if (interTypeScope == null)
- return null; // We encountered a problem building the scope, don't continue - error already reported
-
- // This signature represents what we want consumers of the targetted type to 'see'
- ResolvedMemberImpl signature = world.makeResolvedMemberForITD(binding, onTypeBinding, interTypeScope.getRecoveryAliases());
- signature.resetKind(Member.CONSTRUCTOR);
- signature.resetName("<init>");
- int resetModifiers = declaredModifiers;
- if (binding.isVarargs())
- resetModifiers = resetModifiers | Constants.ACC_VARARGS;
- signature.resetModifiers(resetModifiers);
-
- ResolvedMember syntheticInterMember = AjcMemberMaker.interConstructor(declaringTypeX, signature, aspectType);
-
- NewConstructorTypeMunger myMunger = new NewConstructorTypeMunger(signature, syntheticInterMember, null, null,
- typeVariableAliases);
- setMunger(myMunger);
- myMunger.check(world.getWorld());
-
- this.selector = binding.selector = NameMangler.postIntroducedConstructor(world.fromBinding(binding.declaringClass),
- declaringTypeX).toCharArray();
-
- return new EclipseTypeMunger(world, myMunger, aspectType, this);
- }
-
- private AjAttribute makeAttribute(EclipseFactory world) {
- if (explicitConstructorCall != null && (explicitConstructorCall.binding != null)
- && !(explicitConstructorCall.binding instanceof ProblemMethodBinding)) {
- MethodBinding explicitConstructor = explicitConstructorCall.binding;
- if (explicitConstructor.alwaysNeedsAccessMethod()) {
- explicitConstructor = explicitConstructor.getAccessMethod(true);
- }
- if (explicitConstructor instanceof ParameterizedMethodBinding) {
- explicitConstructor = explicitConstructor.original();
- }
- ((NewConstructorTypeMunger) munger).setExplicitConstructor(world.makeResolvedMember(explicitConstructor));
- } else {
- ((NewConstructorTypeMunger) munger).setExplicitConstructor(new ResolvedMemberImpl(Member.CONSTRUCTOR, world
- .fromBinding(onTypeBinding.superclass()), 0, UnresolvedType.VOID, "<init>", UnresolvedType.NONE));
- }
- return new AjAttribute.TypeMunger(munger);
- }
-
- public void generateCode(ClassScope classScope, ClassFile classFile) {
- if (ignoreFurtherInvestigation)
- return;
- EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
- classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute(world)));
- super.generateCode(classScope, classFile);
- // classFile.codeStream.generateAttributes &= ~ClassFileConstants.ATTR_VARS;
- preMethod.generateCode(classScope, classFile);
- }
-
- protected Shadow.Kind getShadowKindForBody() {
- return Shadow.ConstructorExecution;
- }
-
- }
|