aboutsummaryrefslogtreecommitdiffstats
path: root/org.aspectj.matcher/src/main/java/org/aspectj
diff options
context:
space:
mode:
authorAndy Clement <aclement@pivotal.io>2019-01-23 18:53:51 -0800
committerAndy Clement <aclement@pivotal.io>2019-01-23 18:53:51 -0800
commitafaa961b294eca20fa9d54359c53a1de2d3c41fd (patch)
tree4b756f0f0dc4764cfcaeb200756de79cd4cdf56a /org.aspectj.matcher/src/main/java/org/aspectj
parent74dcae875f1c89b7e3fa2ffa6b524a3c187a597e (diff)
downloadaspectj-afaa961b294eca20fa9d54359c53a1de2d3c41fd.tar.gz
aspectj-afaa961b294eca20fa9d54359c53a1de2d3c41fd.zip
mavenized org.aspectj.matcher module - wip
Diffstat (limited to 'org.aspectj.matcher/src/main/java/org/aspectj')
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractAnnotationAJ.java158
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractReferenceTypeDelegate.java158
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Advice.java515
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AdviceKind.java135
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjAttribute.java757
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjcMemberMaker.java698
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotatedElement.java21
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAJ.java102
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAnnotationValue.java35
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationNameValuePair.java47
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationOnTypeMunger.java56
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationTargetKind.java59
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationValue.java71
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayAnnotationValue.java59
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayReferenceType.java211
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/BCException.java63
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/BindingScope.java68
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceType.java236
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceTypeDelegate.java138
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Checker.java281
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ClassAnnotationValue.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/CompressingDataOutputStream.java98
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConcreteTypeMunger.java164
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolReader.java23
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolWriter.java23
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Constants.java29
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java591
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembersSet.java459
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/CustomMungerFactory.java52
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Dump.java523
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/EnumAnnotationValue.java41
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ExposeTypeMunger.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/GeneratedReferenceTypeDelegate.java155
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IClassWeaver.java28
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ICrossReferenceHandler.java23
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IEclipseSourceContext.java15
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasPosition.java32
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasSourceLocation.java21
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ISourceContext.java25
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IUnwovenClassFile.java27
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeaveRequestor.java37
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeavingSupport.java45
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/IntMap.java150
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Iterators.java359
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignature.java378
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignatureIterator.java281
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Lint.java355
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/LintMessage.java44
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Member.java93
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberImpl.java542
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberKind.java48
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberUtils.java25
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/MethodDelegateTypeMunger.java298
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/MissingResolvedTypeWithKnownSignature.java253
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/NameMangler.java357
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewConstructorTypeMunger.java163
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewFieldTypeMunger.java160
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMemberClassTypeMunger.java90
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMethodTypeMunger.java149
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewParentTypeMunger.java68
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerObjectInterfaceTypeMunger.java96
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerTypeWithinTargetTypeMunger.java86
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/PersistenceSupport.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/PoliceExtensionUse.java80
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Position.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/PrivilegedAccessMunger.java94
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceType.java1280
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceTypeDelegate.java148
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvableTypeList.java43
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMember.java158
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMemberImpl.java1266
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedPointcutDefinition.java142
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedType.java2933
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedTypeMunger.java499
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/RuntimeVersion.java47
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Shadow.java687
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ShadowMunger.java307
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/SignatureUtils.java240
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/SimpleAnnotationValue.java110
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/SourceContextImpl.java98
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/StandardAnnotation.java157
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/StaticJoinPointFactory.java54
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/TemporaryTypeMunger.java37
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeFactory.java377
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariable.java371
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableDeclaringElement.java21
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReference.java22
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReferenceType.java154
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedType.java968
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java90
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/Utils.java43
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/VersionedDataInputStream.java87
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeakClassLoaderReference.java69
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverMessages.java213
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverStateInfo.java581
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/WildcardedUnresolvedType.java70
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/World.java2029
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/XlintDefault.properties50
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ASTNode.java22
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/And.java51
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Call.java41
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/CallExpr.java48
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Expr.java34
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGet.java44
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGetCall.java47
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/HasAnnotation.java59
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/IExprVisitor.java23
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ITestVisitor.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Instanceof.java56
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Literal.java39
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Not.java49
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Or.java56
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Test.java95
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Var.java49
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/MatchingContextBasedTest.java43
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutDesignatorHandlerBasedPointcut.java187
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutExpressionImpl.java442
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/StandardPointcutExpressionImpl.java385
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/TypePatternMatcherImpl.java34
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java253
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractSignaturePattern.java79
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndAnnotationTypePattern.java142
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndPointcut.java138
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndSignaturePattern.java104
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndTypePattern.java198
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPatternList.java215
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPointcut.java339
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationTypePattern.java158
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyAnnotationTypePattern.java74
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyTypePattern.java113
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyWithAnnotationTypePattern.java143
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java250
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsPointcut.java288
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicToken.java75
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicTokenSource.java188
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationFieldTypePattern.java198
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java138
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingPattern.java19
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingTypePattern.java110
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Bindings.java136
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/CflowPointcut.java355
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java184
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Declare.java89
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareAnnotation.java537
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareErrorOrWarning.java130
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParents.java364
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParentsMixin.java83
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclarePrecedence.java197
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareSoft.java139
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareTypeErrorOrWarning.java135
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/EllipsisTypePattern.java109
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationFieldTypePattern.java253
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java470
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactTypePattern.java341
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExposedState.java117
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FastMatchInfo.java52
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FormalBinding.java82
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HandlerPointcut.java141
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePattern.java196
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternFinder.java33
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternForPerThisMatching.java65
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor.java50
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IScope.java59
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ISignaturePattern.java32
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IToken.java53
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ITokenSource.java27
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IVerificationRequired.java22
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IfPointcut.java614
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/KindedPointcut.java478
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ModifiersPattern.java105
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NameBindingPointcut.java52
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NamePattern.java208
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NoTypePattern.java118
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotAnnotationTypePattern.java136
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotPointcut.java140
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotSignaturePattern.java91
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotTypePattern.java180
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrAnnotationTypePattern.java131
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrPointcut.java146
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrSignaturePattern.java104
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrTypePattern.java193
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ParserException.java28
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNode.java88
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNodeVisitor.java96
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternParser.java1914
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerCflow.java175
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerClause.java91
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerFromSuper.java132
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerObject.java193
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerSingleton.java175
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java233
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerTypeWithin.java249
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Pointcut.java436
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java161
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutRewriter.java443
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ReferencePointcut.java414
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ScopeWithTypeVariables.java130
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SignaturePattern.java1009
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SimpleScope.java173
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java337
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java242
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThrowsPattern.java146
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java146
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePattern.java360
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternList.java585
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternQuestions.java106
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePattern.java243
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePatternList.java84
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildAnnotationTypePattern.java434
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildChildFinder.java68
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildTypePattern.java1405
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java241
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java230
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinPointcut.java149
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithincodePointcut.java141
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/AnnotationFinder.java43
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/GenericSignatureInformationProvider.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/IReflectionWorld.java19
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/Java14GenericSignatureInformationProvider.java60
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/JoinPointMatchImpl.java53
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/PointcutParameterImpl.java43
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegate.java403
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegateFactory.java219
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedResolvedMemberImpl.java162
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionFastMatchInfo.java42
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionShadow.java366
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionVar.java169
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionWorld.java248
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ShadowMatchImpl.java202
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadow.java401
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadowMatchImpl.java196
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/AbstractTrace.java202
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTrace.java106
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTraceFactory.java23
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ContextBasedMatcher.java65
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultMatchingContext.java56
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTrace.java123
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTraceFactory.java50
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/FuzzyBoolean.java37
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/GeneratedClassHandler.java30
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ISupportsMessageContext.java18
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/JoinPointMatch.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/MatchingContext.java43
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutDesignatorHandler.java49
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutExpression.java204
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParameter.java36
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParser.java582
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutPrimitive.java50
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ShadowMatch.java58
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutExpression.java233
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutParser.java508
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Trace.java58
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TraceFactory.java83
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Traceable.java17
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TypePatternMatcher.java23
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/UnsupportedPointcutPrimitiveException.java44
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/WeavingClassLoader.java31
-rw-r--r--org.aspectj.matcher/src/main/java/org/aspectj/weaver/weaver-messages.properties201
258 files changed, 52802 insertions, 0 deletions
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractAnnotationAJ.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractAnnotationAJ.java
new file mode 100644
index 000000000..503d6b3b5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractAnnotationAJ.java
@@ -0,0 +1,158 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+public abstract class AbstractAnnotationAJ implements AnnotationAJ {
+
+ protected final ResolvedType type;
+
+ private Set<String> supportedTargets = null; // @target meta annotation
+
+ public AbstractAnnotationAJ(ResolvedType type) {
+ this.type = type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final ResolvedType getType() {
+ return type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final String getTypeSignature() {
+ return type.getSignature();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final String getTypeName() {
+ return type.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final boolean allowedOnAnnotationType() {
+ ensureAtTargetInitialized();
+ if (supportedTargets.isEmpty()) {
+ return true;
+ }
+ return supportedTargets.contains("ANNOTATION_TYPE");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final boolean allowedOnField() {
+ ensureAtTargetInitialized();
+ if (supportedTargets.isEmpty()) {
+ return true;
+ }
+ return supportedTargets.contains("FIELD");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final boolean allowedOnRegularType() {
+ ensureAtTargetInitialized();
+ if (supportedTargets.isEmpty()) {
+ return true;
+ }
+ return supportedTargets.contains("TYPE");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final void ensureAtTargetInitialized() {
+ if (supportedTargets == null) {
+ AnnotationAJ atTargetAnnotation = retrieveAnnotationOnAnnotation(UnresolvedType.AT_TARGET);
+ if (atTargetAnnotation == null) {
+ supportedTargets = Collections.emptySet();
+ } else {
+ supportedTargets = atTargetAnnotation.getTargets();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final String getValidTargets() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("{");
+ for (Iterator<String> iter = supportedTargets.iterator(); iter.hasNext();) {
+ String evalue = iter.next();
+ sb.append(evalue);
+ if (iter.hasNext()) {
+ sb.append(",");
+ }
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final boolean specifiesTarget() {
+ ensureAtTargetInitialized();
+ return !supportedTargets.isEmpty();
+ }
+
+ /**
+ * Helper method to retrieve an annotation on an annotation e.g. retrieveAnnotationOnAnnotation(UnresolvedType.AT_TARGET)
+ */
+ private final AnnotationAJ retrieveAnnotationOnAnnotation(UnresolvedType requiredAnnotationSignature) {
+ AnnotationAJ[] annos = type.getAnnotations();
+ for (int i = 0; i < annos.length; i++) {
+ AnnotationAJ a = annos[i];
+ if (a.getTypeSignature().equals(requiredAnnotationSignature.getSignature())) {
+ return annos[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract boolean isRuntimeVisible();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract Set<String> getTargets();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract boolean hasNameValuePair(String name, String value);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract boolean hasNamedValue(String name);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract String stringify();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractReferenceTypeDelegate.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractReferenceTypeDelegate.java
new file mode 100644
index 000000000..7f3fb60ee
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AbstractReferenceTypeDelegate.java
@@ -0,0 +1,158 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Andy Clement - June 2005 - separated out from ResolvedType
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.util.GenericSignature;
+import org.aspectj.util.GenericSignature.ClassSignature;
+import org.aspectj.util.GenericSignatureParser;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+
+public abstract class AbstractReferenceTypeDelegate implements ReferenceTypeDelegate {
+
+ private String sourcefilename = UNKNOWN_SOURCE_FILE;
+ private ISourceContext sourceContext = SourceContextImpl.UNKNOWN_SOURCE_CONTEXT;
+
+ protected boolean exposedToWeaver;
+ protected ReferenceType resolvedTypeX;
+ protected ClassSignature cachedGenericClassTypeSignature;
+
+ // Happens to match Bcel javaClass default of '<Unknown>'
+ public final static String UNKNOWN_SOURCE_FILE = "<Unknown>";
+
+ public AbstractReferenceTypeDelegate(ReferenceType resolvedTypeX, boolean exposedToWeaver) {
+ this.resolvedTypeX = resolvedTypeX;
+ this.exposedToWeaver = exposedToWeaver;
+ }
+
+ public final boolean isClass() {
+ return !isAspect() && !isInterface();
+ }
+
+ public boolean isCacheable() {
+ return false;
+ }
+
+ /**
+ * Designed to be overriden by EclipseType to disable collection of shadow mungers during pre-weave compilation phase
+ */
+ public boolean doesNotExposeShadowMungers() {
+ return false;
+ }
+
+ public boolean isExposedToWeaver() {
+ return exposedToWeaver;
+ }
+
+ public ReferenceType getResolvedTypeX() {
+ return resolvedTypeX;
+ }
+
+ public final String getSourcefilename() {
+ return sourcefilename;
+ }
+
+ public final void setSourcefilename(String sourceFileName) {
+ sourcefilename = sourceFileName;
+ if (sourceFileName != null && sourceFileName.equals(AbstractReferenceTypeDelegate.UNKNOWN_SOURCE_FILE)) {
+ sourcefilename = "Type '" + getResolvedTypeX().getName() + "' (no debug info available)";
+ } else {
+ String pname = getResolvedTypeX().getPackageName();
+ if (pname != null) {
+ sourcefilename = pname.replace('.', '/') + '/' + sourceFileName;
+ }
+ }
+ if (sourcefilename != null && sourceContext instanceof SourceContextImpl) {
+ ((SourceContextImpl) sourceContext).setSourceFileName(sourcefilename);
+ }
+ }
+
+ public ISourceLocation getSourceLocation() {
+ return getSourceContext().makeSourceLocation(0, 0);
+ }
+
+ public ISourceContext getSourceContext() {
+ return sourceContext;
+ }
+
+ public void setSourceContext(ISourceContext isc) {
+ sourceContext = isc;
+ }
+
+ public GenericSignature.ClassSignature getGenericClassTypeSignature() {
+ if (cachedGenericClassTypeSignature == null) {
+ String sig = getDeclaredGenericSignature();
+ if (sig != null) {
+ GenericSignatureParser parser = new GenericSignatureParser();
+ cachedGenericClassTypeSignature = parser.parseAsClassSignature(sig);
+ }
+ }
+ return cachedGenericClassTypeSignature;
+ }
+
+ protected GenericSignature.FormalTypeParameter[] getFormalTypeParametersFromOuterClass() {
+ List<GenericSignature.FormalTypeParameter> typeParameters = new ArrayList<GenericSignature.FormalTypeParameter>();
+ ResolvedType outerClassType = getOuterClass();
+ if (!(outerClassType instanceof ReferenceType)) {
+ if (outerClassType == null) {
+ return GenericSignature.FormalTypeParameter.NONE;
+ } else {
+ throw new BCException("Whilst processing type '" + this.resolvedTypeX.getSignature()
+ + "' - cannot cast the outer type to a reference type. Signature=" + outerClassType.getSignature()
+ + " toString()=" + outerClassType.toString()+" class=" + outerClassType.getClassName());
+ }
+ }
+ ReferenceType outer = (ReferenceType) outerClassType;
+ ReferenceTypeDelegate outerDelegate = outer.getDelegate();
+ AbstractReferenceTypeDelegate outerObjectType = (AbstractReferenceTypeDelegate) outerDelegate;
+ if (outerObjectType.isNested()) {
+ GenericSignature.FormalTypeParameter[] parentParams = outerObjectType.getFormalTypeParametersFromOuterClass();
+ for (int i = 0; i < parentParams.length; i++) {
+ typeParameters.add(parentParams[i]);
+ }
+ }
+ GenericSignature.ClassSignature outerSig = outerObjectType.getGenericClassTypeSignature();
+ if (outerSig != null) {
+ for (int i = 0; i < outerSig.formalTypeParameters.length; i++) {
+ typeParameters.add(outerSig.formalTypeParameters[i]);
+ }
+ }
+
+ GenericSignature.FormalTypeParameter[] ret = new GenericSignature.FormalTypeParameter[typeParameters.size()];
+ typeParameters.toArray(ret);
+ return ret;
+ }
+
+ public boolean copySourceContext() {
+ return true;
+ }
+
+ public int getCompilerVersion() {
+ return WeaverVersionInfo.getCurrentWeaverMajorVersion();
+ }
+
+ public void ensureConsistent() {
+
+ }
+
+ public boolean isWeavable() {
+ return false;
+ }
+
+ public boolean hasBeenWoven() {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Advice.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Advice.java
new file mode 100644
index 000000000..d6c8ea87f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Advice.java
@@ -0,0 +1,515 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.patterns.AndPointcut;
+import org.aspectj.weaver.patterns.PerClause;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+
+public abstract class Advice extends ShadowMunger {
+
+ protected AjAttribute.AdviceAttribute attribute;
+ protected transient AdviceKind kind; // alias for attribute.getKind()
+ protected Member signature;
+ private boolean isAnnotationStyle;
+
+ // not necessarily declaring aspect, this is a semantics change from 1.0
+ protected ResolvedType concreteAspect; // null until after concretize
+
+ // Just for Cflow*entry kinds
+ protected List<ShadowMunger> innerCflowEntries = Collections.emptyList();
+ protected int nFreeVars;
+
+ protected TypePattern exceptionType; // just for Softener kind
+
+ // if we are parameterized, these type may be different to the advice
+ // signature types
+ protected UnresolvedType[] bindingParameterTypes;
+
+ protected boolean hasMatchedAtLeastOnce = false;
+
+ // based on annotations on this advice
+ protected List<Lint.Kind> suppressedLintKinds = null;
+
+ public ISourceLocation lastReportedMonitorExitJoinpointLocation = null;
+
+ public static Advice makeCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, int nFreeVars,
+ List<ShadowMunger> innerCflowEntries, ResolvedType inAspect) {
+ Advice ret = world.createAdviceMunger(isBelow ? AdviceKind.CflowBelowEntry : AdviceKind.CflowEntry, entry, stackField, 0,
+ entry, inAspect);
+ ret.innerCflowEntries = innerCflowEntries;
+ ret.nFreeVars = nFreeVars;
+ ret.setDeclaringType(inAspect); // correct?
+ return ret;
+ }
+
+ public static Advice makePerCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, ResolvedType inAspect,
+ List<ShadowMunger> innerCflowEntries) {
+ Advice ret = world.createAdviceMunger(isBelow ? AdviceKind.PerCflowBelowEntry : AdviceKind.PerCflowEntry, entry,
+ stackField, 0, entry, inAspect);
+ ret.innerCflowEntries = innerCflowEntries;
+ ret.concreteAspect = inAspect;
+ return ret;
+ }
+
+ public static Advice makePerObjectEntry(World world, Pointcut entry, boolean isThis, ResolvedType inAspect) {
+ Advice ret = world.createAdviceMunger(isThis ? AdviceKind.PerThisEntry : AdviceKind.PerTargetEntry, entry, null, 0, entry,
+ inAspect);
+
+ ret.concreteAspect = inAspect;
+ return ret;
+ }
+
+ // PTWIMPL per type within entry advice is what initializes the aspect
+ // instance in the matched type
+ public static Advice makePerTypeWithinEntry(World world, Pointcut p, ResolvedType inAspect) {
+ Advice ret = world.createAdviceMunger(AdviceKind.PerTypeWithinEntry, p, null, 0, p, inAspect);
+ ret.concreteAspect = inAspect;
+ return ret;
+ }
+
+ public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType, ResolvedType inAspect,
+ IHasSourceLocation loc) {
+ Advice ret = world.createAdviceMunger(AdviceKind.Softener, entry, null, 0, loc, inAspect);
+ ret.exceptionType = exceptionType;
+ return ret;
+ }
+
+ public Advice(AjAttribute.AdviceAttribute attribute, Pointcut pointcut, Member signature) {
+ super(pointcut, attribute.getStart(), attribute.getEnd(), attribute.getSourceContext(), ShadowMungerAdvice);
+ this.attribute = attribute;
+ this.isAnnotationStyle = signature != null && !signature.getName().startsWith("ajc$");
+ this.kind = attribute.getKind(); // alias
+ this.signature = signature;
+ if (signature != null) {
+ bindingParameterTypes = signature.getParameterTypes();
+ } else {
+ bindingParameterTypes = new UnresolvedType[0];
+ }
+ }
+
+ @Override
+ public boolean match(Shadow shadow, World world) {
+ if (super.match(shadow, world)) {
+ if (shadow.getKind() == Shadow.ExceptionHandler) {
+ if (kind.isAfter() || kind == AdviceKind.Around) {
+ world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.ONLY_BEFORE_ON_HANDLER),
+ getSourceLocation(), shadow.getSourceLocation());
+ return false;
+ }
+ }
+ if (shadow.getKind() == Shadow.SynchronizationLock || shadow.getKind() == Shadow.SynchronizationUnlock) {
+ if (kind == AdviceKind.Around
+ // Don't work, see comments in SynchronizationTests
+ // && attribute.getProceedCallSignatures()!=null
+ // && attribute.getProceedCallSignatures().length!=0
+ ) {
+ world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.NO_AROUND_ON_SYNCHRONIZATION),
+ getSourceLocation(), shadow.getSourceLocation());
+ return false;
+ }
+ }
+
+ if (hasExtraParameter() && kind == AdviceKind.AfterReturning) {
+ ResolvedType resolvedExtraParameterType = getExtraParameterType().resolve(world);
+ ResolvedType shadowReturnType = shadow.getReturnType().resolve(world);
+ boolean matches = (resolvedExtraParameterType.isConvertableFrom(shadowReturnType) && shadow.getKind()
+ .hasReturnValue());
+ if (matches && resolvedExtraParameterType.isParameterizedType()) {
+ maybeIssueUncheckedMatchWarning(resolvedExtraParameterType, shadowReturnType, shadow, world);
+ }
+ return matches;
+ } else if (hasExtraParameter() && kind == AdviceKind.AfterThrowing) { // pr119749
+ ResolvedType exceptionType = getExtraParameterType().resolve(world);
+ if (!exceptionType.isCheckedException() || exceptionType.getName().equals("java.lang.Exception")) { // pr292239
+ return true;
+ }
+ UnresolvedType[] shadowThrows = shadow.getSignature().getExceptions(world);
+ boolean matches = false;
+ for (int i = 0; i < shadowThrows.length && !matches; i++) {
+ ResolvedType type = shadowThrows[i].resolve(world);
+ if (exceptionType.isAssignableFrom(type)) {
+ matches = true;
+ }
+ }
+ return matches;
+ } else if (kind == AdviceKind.PerTargetEntry) {
+ return shadow.hasTarget();
+ } else if (kind == AdviceKind.PerThisEntry) {
+ // Groovy Constructors have a strange switch statement in them - this switch statement can leave us in places where
+ // the
+ // instance is not initialized (a super ctor hasn't been called yet).
+ // In these situations it isn't safe to do a perObjectBind, the instance is not initialized and cannot be passed
+ // over.
+ if (shadow.getEnclosingCodeSignature().getName().equals("<init>")) {
+ if (world.resolve(shadow.getEnclosingType()).isGroovyObject()) {
+ return false;
+ }
+ }
+ return shadow.hasThis();
+ } else if (kind == AdviceKind.Around) {
+ if (shadow.getKind() == Shadow.PreInitialization) {
+ world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.AROUND_ON_PREINIT),
+ getSourceLocation(), shadow.getSourceLocation());
+ return false;
+ } else if (shadow.getKind() == Shadow.Initialization) {
+ world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.AROUND_ON_INIT), getSourceLocation(),
+ shadow.getSourceLocation());
+ return false;
+ } else if (shadow.getKind() == Shadow.StaticInitialization
+ && shadow.getEnclosingType().resolve(world).isInterface()) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.AROUND_ON_INTERFACE_STATICINIT, shadow
+ .getEnclosingType().getName()), getSourceLocation(), shadow.getSourceLocation());
+ return false;
+ } else {
+ // System.err.println(getSignature().getReturnType() +
+ // " from " + shadow.getReturnType());
+ if (getSignature().getReturnType().equals(UnresolvedType.VOID)) {
+ if (!shadow.getReturnType().equals(UnresolvedType.VOID)) {
+ String s = shadow.toString();
+ String s2 = WeaverMessages.format(WeaverMessages.NON_VOID_RETURN, s);
+ world.showMessage(IMessage.ERROR, s2, getSourceLocation(), shadow.getSourceLocation());
+ return false;
+ }
+ } else if (getSignature().getReturnType().equals(UnresolvedType.OBJECT)) {
+ return true;
+ } else {
+ ResolvedType shadowReturnType = shadow.getReturnType().resolve(world);
+ ResolvedType adviceReturnType = getSignature().getGenericReturnType().resolve(world);
+
+ if (shadowReturnType.isParameterizedType() && adviceReturnType.isRawType()) { // Set
+ // <
+ // Integer
+ // >
+ // and
+ // Set
+ ResolvedType shadowReturnGenericType = shadowReturnType.getGenericType(); // Set
+ ResolvedType adviceReturnGenericType = adviceReturnType.getGenericType(); // Set
+ if (shadowReturnGenericType.isAssignableFrom(adviceReturnGenericType)
+ && world.getLint().uncheckedAdviceConversion.isEnabled()) {
+ world.getLint().uncheckedAdviceConversion.signal(
+ new String[] { shadow.toString(), shadowReturnType.getName(), adviceReturnType.getName() },
+ shadow.getSourceLocation(), new ISourceLocation[] { getSourceLocation() });
+ }
+ } else if (!shadowReturnType.isAssignableFrom(adviceReturnType)) {
+ // System.err.println(this + ", " + sourceContext +
+ // ", " + start);
+ world.showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.INCOMPATIBLE_RETURN_TYPE, shadow), getSourceLocation(),
+ shadow.getSourceLocation());
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * In after returning advice if we are binding the extra parameter to a parameterized type we may not be able to do a type-safe
+ * conversion.
+ *
+ * @param resolvedExtraParameterType the type in the after returning declaration
+ * @param shadowReturnType the type at the shadow
+ * @param world
+ */
+ private void maybeIssueUncheckedMatchWarning(ResolvedType afterReturningType, ResolvedType shadowReturnType, Shadow shadow,
+ World world) {
+ boolean inDoubt = !afterReturningType.isAssignableFrom(shadowReturnType);
+ if (inDoubt && world.getLint().uncheckedArgument.isEnabled()) {
+ String uncheckedMatchWith = afterReturningType.getSimpleBaseName();
+ if (shadowReturnType.isParameterizedType() && (shadowReturnType.getRawType() == afterReturningType.getRawType())) {
+ uncheckedMatchWith = shadowReturnType.getSimpleName();
+ }
+ if (!Utils.isSuppressing(getSignature().getAnnotations(), "uncheckedArgument")) {
+ world.getLint().uncheckedArgument.signal(new String[] { afterReturningType.getSimpleName(), uncheckedMatchWith,
+ afterReturningType.getSimpleBaseName(), shadow.toResolvedString(world) }, getSourceLocation(),
+ new ISourceLocation[] { shadow.getSourceLocation() });
+ }
+ }
+ }
+
+ // ----
+
+ public AdviceKind getKind() {
+ return kind;
+ }
+
+ public Member getSignature() {
+ return signature;
+ }
+
+ public boolean hasExtraParameter() {
+ return (getExtraParameterFlags() & ExtraArgument) != 0;
+ }
+
+ protected int getExtraParameterFlags() {
+ return attribute.getExtraParameterFlags();
+ }
+
+ protected int getExtraParameterCount() {
+ return countOnes(getExtraParameterFlags() & ParameterMask);
+ }
+
+ public UnresolvedType[] getBindingParameterTypes() {
+ return bindingParameterTypes;
+ }
+
+ public void setBindingParameterTypes(UnresolvedType[] types) {
+ bindingParameterTypes = types;
+ }
+
+ public static int countOnes(int bits) {
+ int ret = 0;
+ while (bits != 0) {
+ if ((bits & 1) != 0) {
+ ret += 1;
+ }
+ bits = bits >> 1;
+ }
+ return ret;
+ }
+
+ public int getBaseParameterCount() {
+ return getSignature().getParameterTypes().length - getExtraParameterCount();
+ }
+
+ public String[] getBaseParameterNames(World world) {
+ String[] allNames = getSignature().getParameterNames(world);
+ int extras = getExtraParameterCount();
+ if (extras == 0) {
+ return allNames;
+ }
+ String[] result = new String[getBaseParameterCount()];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = allNames[i];
+ }
+ return result;
+ }
+
+ /**
+ * Return the type of the 'extra argument'. For either after returning or after throwing advice, the extra argument will be the
+ * returned value or the thrown exception respectively. With annotation style the user may declare the parameters in any order,
+ * whereas for code style they are in a well defined order. So there is some extra complexity in here for annotation style that
+ * looks up the correct parameter in the advice signature by name, based on the name specified in the annotation. If this fails
+ * then we 'fallback' to guessing at positions, where the extra argument is presumed to come at the end.
+ *
+ * @return the type of the extraParameter
+ */
+ public UnresolvedType getExtraParameterType() {
+ if (!hasExtraParameter()) {
+ return ResolvedType.MISSING;
+ }
+ if (signature instanceof ResolvedMember) {
+ ResolvedMember method = (ResolvedMember) signature;
+ UnresolvedType[] parameterTypes = method.getGenericParameterTypes();
+ if (getConcreteAspect().isAnnotationStyleAspect()) {
+
+ // Examine the annotation to determine the parameter name then look it up in the parameters for the method
+ String[] pnames = method.getParameterNames();
+ if (pnames != null) {
+ // It is worth attempting to look up the correct parameter
+ AnnotationAJ[] annos = getSignature().getAnnotations();
+ String parameterToLookup = null;
+ if (annos != null && (getKind() == AdviceKind.AfterThrowing || getKind() == AdviceKind.AfterReturning)) {
+ for (int i = 0; i < annos.length && parameterToLookup == null; i++) {
+ AnnotationAJ anno = annos[i];
+ String annosig = anno.getType().getSignature();
+ if (annosig.equals("Lorg/aspectj/lang/annotation/AfterThrowing;")) {
+ // the 'throwing' value in the annotation will name the parameter to bind to
+ parameterToLookup = anno.getStringFormOfValue("throwing");
+ } else if (annosig.equals("Lorg/aspectj/lang/annotation/AfterReturning;")) {
+ // the 'returning' value in the annotation will name the parameter to bind to
+ parameterToLookup = anno.getStringFormOfValue("returning");
+ }
+ }
+ }
+ if (parameterToLookup != null) {
+ for (int i = 0; i < pnames.length; i++) {
+ if (pnames[i].equals(parameterToLookup)) {
+ return parameterTypes[i];
+ }
+ }
+ }
+ }
+
+ // Don't think this code works so well... why isnt it getBaseParameterCount()-1 ?
+
+ int baseParmCnt = getBaseParameterCount();
+
+ // bug 122742 - if we're an annotation style aspect then one
+ // of the extra parameters could be JoinPoint which we want
+ // to ignore
+ while ((baseParmCnt + 1 < parameterTypes.length)
+ && (parameterTypes[baseParmCnt].equals(AjcMemberMaker.TYPEX_JOINPOINT)
+ || parameterTypes[baseParmCnt].equals(AjcMemberMaker.TYPEX_STATICJOINPOINT) || parameterTypes[baseParmCnt]
+ .equals(AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT))) {
+ baseParmCnt++;
+ }
+ return parameterTypes[baseParmCnt];
+ } else {
+ return parameterTypes[getBaseParameterCount()];
+ }
+ } else {
+ return signature.getParameterTypes()[getBaseParameterCount()];
+ }
+ }
+
+ public UnresolvedType getDeclaringAspect() {
+ return getOriginalSignature().getDeclaringType();
+ }
+
+ protected Member getOriginalSignature() {
+ return signature;
+ }
+
+ protected String extraParametersToString() {
+ if (getExtraParameterFlags() == 0) {
+ return "";
+ } else {
+ return "(extraFlags: " + getExtraParameterFlags() + ")";
+ }
+ }
+
+ @Override
+ public Pointcut getPointcut() {
+ return pointcut;
+ }
+
+ // ----
+
+ /**
+ * @param fromType is guaranteed to be a non-abstract aspect
+ * @param clause has been concretized at a higher level
+ */
+ @Override
+ public ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause) {
+ // assert !fromType.isAbstract();
+ Pointcut p = pointcut.concretize(fromType, getDeclaringType(), signature.getArity(), this);
+ if (clause != null) {
+ Pointcut oldP = p;
+ p = new AndPointcut(clause, p);
+ p.copyLocationFrom(oldP);
+ p.state = Pointcut.CONCRETE;
+
+ // FIXME ? ATAJ copy unbound bindings to ignore
+ p.m_ignoreUnboundBindingForNames = oldP.m_ignoreUnboundBindingForNames;
+ }
+
+ Advice munger = world.getWeavingSupport().createAdviceMunger(attribute, p, signature, fromType);
+ munger.bindingParameterTypes = bindingParameterTypes;
+ munger.setDeclaringType(getDeclaringType());
+ // System.err.println("concretizing here " + p + " with clause " +
+ // clause);
+ return munger;
+ }
+
+ // ---- from object
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("(").append(getKind()).append(extraParametersToString());
+ sb.append(": ").append(pointcut).append("->").append(signature).append(")");
+ return sb.toString();
+ // return "("
+ // + getKind()
+ // + extraParametersToString()
+ // + ": "
+ // + pointcut
+ // + "->"
+ // + signature
+ // + ")";
+ }
+
+ // XXX this perhaps ought to take account of the other fields in advice ...
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Advice)) {
+ return false;
+ }
+ Advice o = (Advice) other;
+ return o.kind.equals(kind) && ((o.pointcut == null) ? (pointcut == null) : o.pointcut.equals(pointcut))
+ && ((o.signature == null) ? (signature == null) : o.signature.equals(signature));
+ // && (AsmManager.getDefault().getHandleProvider().dependsOnLocation() ? ((o.getSourceLocation() == null) ?
+ // (getSourceLocation() == null)
+ // : o.getSourceLocation().equals(getSourceLocation()))
+ // : true) // pr134471 - remove when handles are improved
+ // // to be independent of location
+ // ;
+
+ }
+
+ private volatile int hashCode = 0;
+
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + ((pointcut == null) ? 0 : pointcut.hashCode());
+ result = 37 * result + ((signature == null) ? 0 : signature.hashCode());
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ // ---- fields
+
+ public static final int ExtraArgument = 0x01;
+ public static final int ThisJoinPoint = 0x02;
+ public static final int ThisJoinPointStaticPart = 0x04;
+ public static final int ThisEnclosingJoinPointStaticPart = 0x08;
+ public static final int ParameterMask = 0x0f;
+ // For an if pointcut, this indicates it is hard wired to access a constant of either true or false
+ public static final int ConstantReference = 0x10;
+ // When the above flag is set, this indicates whether it is true or false
+ public static final int ConstantValue = 0x20;
+ // public static final int CanInline = 0x40; // didnt appear to be getting used
+ public static final int ThisAspectInstance = 0x40;
+
+ // cant use 0x80 ! the value is written out as a byte and -1 has special meaning (-1 is 0x80...)
+
+ // for testing only
+ public void setLexicalPosition(int lexicalPosition) {
+ start = lexicalPosition;
+ }
+
+ public boolean isAnnotationStyle() {
+ return isAnnotationStyle;
+ }
+
+ public ResolvedType getConcreteAspect() {
+ return concreteAspect;
+ }
+
+ public boolean hasMatchedSomething() {
+ return hasMatchedAtLeastOnce;
+ }
+
+ public void setHasMatchedSomething(boolean hasMatchedSomething) {
+ hasMatchedAtLeastOnce = hasMatchedSomething;
+ }
+
+ public abstract boolean hasDynamicTests();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AdviceKind.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AdviceKind.java
new file mode 100644
index 000000000..af0646935
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AdviceKind.java
@@ -0,0 +1,135 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+import org.aspectj.util.TypeSafeEnum;
+
+/**
+ * The five kinds of advice in AspectJ.
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public class AdviceKind extends TypeSafeEnum {
+ private int precedence;
+ private boolean isAfter;
+ private boolean isCflow;
+
+ public AdviceKind(String name, int key, int precedence, boolean isAfter, boolean isCflow) {
+ super(name, key);
+ this.precedence = precedence;
+ this.isAfter = isAfter;
+ this.isCflow = isCflow;
+ }
+
+ public static AdviceKind read(VersionedDataInputStream s) throws IOException {
+ int key = s.readByte();
+ switch (key) {
+ case 1:
+ return Before;
+ case 2:
+ return After;
+ case 3:
+ return AfterThrowing;
+ case 4:
+ return AfterReturning;
+ case 5:
+ return Around;
+ case 6:
+ return CflowEntry;
+ case 7:
+ return CflowBelowEntry;
+
+ case 8:
+ return InterInitializer;
+
+ case 9:
+ return PerCflowEntry;
+ case 10:
+ return PerCflowBelowEntry;
+ case 11:
+ return PerThisEntry;
+ case 12:
+ return PerTargetEntry;
+
+ case 13:
+ return Softener;
+
+ case 14:
+ return PerTypeWithinEntry;
+ }
+ throw new RuntimeException("unimplemented kind: " + key);
+ }
+
+ public static final AdviceKind Before = new AdviceKind("before", 1, 0, false, false);
+ public static final AdviceKind After = new AdviceKind("after", 2, 0, true, false);
+ public static final AdviceKind AfterThrowing = new AdviceKind("afterThrowing", 3, 0, true, false);
+ public static final AdviceKind AfterReturning = new AdviceKind("afterReturning", 4, 0, true, false);
+ public static final AdviceKind Around = new AdviceKind("around", 5, 0, false, false);
+
+ // these kinds can't be declared, but are used by the weaver
+ public static final AdviceKind CflowEntry = new AdviceKind("cflowEntry", 6, 1, false, true);
+ public static final AdviceKind CflowBelowEntry = new AdviceKind("cflowBelowEntry", 7, -1, false, true); // XXX resolve
+ // precednece with the
+ // below
+ public static final AdviceKind InterInitializer = new AdviceKind("interInitializer", 8, -2, false, false);
+
+ public static final AdviceKind PerCflowEntry = new AdviceKind("perCflowEntry", 9, 1, false, true);
+ public static final AdviceKind PerCflowBelowEntry = new AdviceKind("perCflowBelowEntry", 10, -1, false, true);
+
+ public static final AdviceKind PerThisEntry = new AdviceKind("perThisEntry", 11, 1, false, false);
+ public static final AdviceKind PerTargetEntry = new AdviceKind("perTargetEntry", 12, 1, false, false);
+
+ public static final AdviceKind Softener = new AdviceKind("softener", 13, 1, false, false);
+
+ // PTWIMPL Advice representing when aspect should be initialized
+ public static final AdviceKind PerTypeWithinEntry = new AdviceKind("perTypeWithinEntry", 14, 1, false, false);
+
+ public static AdviceKind stringToKind(String s) {
+ if (s.equals(Before.getName()))
+ return Before;
+ if (s.equals(After.getName()))
+ return After;
+ if (s.equals(AfterThrowing.getName()))
+ return AfterThrowing;
+ if (s.equals(AfterReturning.getName()))
+ return AfterReturning;
+ if (s.equals(Around.getName()))
+ return Around;
+ throw new IllegalArgumentException("unknown kind: " + "\"" + s + "\"");
+ }
+
+ public boolean isAfter() {
+ return this.isAfter;
+ }
+
+ public boolean isCflow() {
+ return this.isCflow;
+ }
+
+ public int getPrecedence() {
+ return precedence;
+ }
+
+ public boolean isPerEntry() {
+ return this == PerCflowEntry || this == PerCflowBelowEntry || this == PerThisEntry || this == PerTargetEntry
+ || this == PerTypeWithinEntry; // PTWIMPL Allow for PTW case
+ }
+
+ public boolean isPerObjectEntry() {
+ return this == PerThisEntry || this == PerTargetEntry;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjAttribute.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjAttribute.java
new file mode 100644
index 000000000..781227141
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjAttribute.java
@@ -0,0 +1,757 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.bridge.Version;
+import org.aspectj.util.FileUtil;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.IScope;
+import org.aspectj.weaver.patterns.PerClause;
+import org.aspectj.weaver.patterns.Pointcut;
+
+/**
+ * These attributes are written to and read from .class files (see the JVM spec).
+ *
+ * <p>
+ * Each member or type can have a number of AjAttributes. Each such attribute is in 1-1 correspondence with an Unknown bcel
+ * attribute. Creating one of these does NOTHING to the underlying thing, so if you really want to add an attribute to a particular
+ * thing, well, you'd better actually do that.
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public abstract class AjAttribute {
+
+ public static final String AttributePrefix = "org.aspectj.weaver";
+
+ protected abstract void write(CompressingDataOutputStream s) throws IOException;
+
+ public abstract String getNameString();
+
+ public char[] getNameChars() {
+ return getNameString().toCharArray();
+ }
+
+ /**
+ * Just writes the contents
+ */
+ public byte[] getBytes(ConstantPoolWriter compressor) {
+ try {
+ ByteArrayOutputStream b0 = new ByteArrayOutputStream();
+ CompressingDataOutputStream s0 = new CompressingDataOutputStream(b0, compressor);
+ write(s0);
+ s0.close();
+ return b0.toByteArray();
+ } catch (IOException e) {
+ // shouldn't happen with ByteArrayOutputStreams
+ throw new RuntimeException("sanity check");
+ }
+ }
+
+ /**
+ * Writes the full attribute, i.e. name_index, length, and contents
+ *
+ * @param constantPool
+ */
+ public byte[] getAllBytes(short nameIndex, ConstantPoolWriter dataCompressor) {
+ try {
+ byte[] bytes = getBytes(dataCompressor);
+
+ ByteArrayOutputStream b0 = new ByteArrayOutputStream();
+ DataOutputStream s0 = new DataOutputStream(b0);
+
+ s0.writeShort(nameIndex);
+ s0.writeInt(bytes.length);
+ s0.write(bytes);
+ s0.close();
+ return b0.toByteArray();
+ } catch (IOException e) {
+ // shouldn't happen with ByteArrayOutputStreams
+ throw new RuntimeException("sanity check");
+ }
+ }
+
+ public static AjAttribute read(AjAttribute.WeaverVersionInfo v, String name, byte[] bytes, ISourceContext context, World w,
+ ConstantPoolReader dataDecompressor) {
+ try {
+ if (bytes == null) {
+ bytes = new byte[0];
+ }
+
+ VersionedDataInputStream s = new VersionedDataInputStream(new ByteArrayInputStream(bytes), dataDecompressor);
+ s.setVersion(v);
+ if (name.equals(Aspect.AttributeName)) {
+ return new Aspect(PerClause.readPerClause(s, context));
+ } else if (name.equals(MethodDeclarationLineNumberAttribute.AttributeName)) {
+ return MethodDeclarationLineNumberAttribute.read(s);
+ } else if (name.equals(WeaverState.AttributeName)) {
+ return new WeaverState(WeaverStateInfo.read(s, context));
+ } else if (name.equals(WeaverVersionInfo.AttributeName)) {
+ return WeaverVersionInfo.read(s);
+ } else if (name.equals(AdviceAttribute.AttributeName)) {
+ AdviceAttribute aa = AdviceAttribute.read(s, context);
+ aa.getPointcut().check(context, w);
+ return aa;
+ } else if (name.equals(PointcutDeclarationAttribute.AttributeName)) {
+ PointcutDeclarationAttribute pda = new PointcutDeclarationAttribute(ResolvedPointcutDefinition.read(s, context));
+ pda.pointcutDef.getPointcut().check(context, w);
+ return pda;
+ } else if (name.equals(TypeMunger.AttributeName)) {
+ return new TypeMunger(ResolvedTypeMunger.read(s, context));
+ } else if (name.equals(AjSynthetic.AttributeName)) {
+ return new AjSynthetic();
+ } else if (name.equals(DeclareAttribute.AttributeName)) {
+ return new DeclareAttribute(Declare.read(s, context));
+ } else if (name.equals(PrivilegedAttribute.AttributeName)) {
+ return PrivilegedAttribute.read(s, context);
+ } else if (name.equals(SourceContextAttribute.AttributeName)) {
+ return SourceContextAttribute.read(s);
+ } else if (name.equals(EffectiveSignatureAttribute.AttributeName)) {
+ return EffectiveSignatureAttribute.read(s, context);
+ } else {
+ // We have to tell the user about this...
+ if (w == null || w.getMessageHandler() == null) {
+ throw new BCException("unknown attribute" + name);
+ }
+ w.getMessageHandler().handleMessage(MessageUtil.warn("unknown attribute encountered " + name));
+ return null;
+ }
+ } catch (BCException e) {
+ throw new BCException("malformed " + name + " attribute (length:" + bytes.length + ")" + e);
+ } catch (IOException e) {
+ throw new BCException("malformed " + name + " attribute (length:" + bytes.length + ")" + e);
+ }
+ }
+
+ // ----
+
+ /**
+ * Synthetic members should have NO advice put on them or on their contents. This attribute is currently unused as we consider
+ * all members starting with NameMangler.PREFIX to automatically be synthetic. As we use this we might find that we want
+ * multiple kinds of synthetic. In particular, if we want to treat the call to a synthetic getter (say, of an introduced field)
+ * as a field reference itself, then a method might want a particular kind of AjSynthetic attribute that also includes a
+ * signature of what it stands for.
+ */
+ public static class AjSynthetic extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.AjSynthetic";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ // private ResolvedTypeMunger munger;
+ public AjSynthetic() {
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ }
+ }
+
+ public static class TypeMunger extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.TypeMunger";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final ResolvedTypeMunger munger;
+
+ public TypeMunger(ResolvedTypeMunger munger) {
+ this.munger = munger;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ munger.write(s);
+ }
+
+ public ConcreteTypeMunger reify(World world, ResolvedType aspectType) {
+ return world.getWeavingSupport().concreteTypeMunger(munger, aspectType);
+ }
+ }
+
+ public static class WeaverState extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.WeaverState";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final WeaverStateInfo kind;
+
+ public WeaverState(WeaverStateInfo kind) {
+ this.kind = kind;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ }
+
+ public WeaverStateInfo reify() {
+ return kind;
+ }
+ }
+
+ public static class WeaverVersionInfo extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.WeaverVersion";
+
+ // If you change the format of an AspectJ class file, you have two
+ // options:
+ // - changing the minor version means you have not added anything that
+ // prevents
+ // previous versions of the weaver from operating (e.g.
+ // MethodDeclarationLineNumber attribute)
+ // - changing the major version means you have added something that
+ // prevents previous
+ // versions of the weaver from operating correctly.
+ //
+ // The user will get a warning for any org.aspectj.weaver attributes the
+ // weaver does
+ // not recognize.
+
+ // When we don't know ... (i.e. pre 1.2.1)
+ public final static short WEAVER_VERSION_MAJOR_UNKNOWN = 0;
+ public final static short WEAVER_VERSION_MINOR_UNKNOWN = 0;
+
+ // These are the weaver major/minor numbers for AspectJ 1.2.1
+ public final static short WEAVER_VERSION_MAJOR_AJ121 = 1;
+ public final static short WEAVER_VERSION_MINOR_AJ121 = 0;
+
+ // These are the weaver major/minor numbers for AspectJ 1.5.0
+ public final static short WEAVER_VERSION_MAJOR_AJ150M4 = 3;
+ public final static short WEAVER_VERSION_MAJOR_AJ150 = 2;
+ public final static short WEAVER_VERSION_MINOR_AJ150 = 0;
+
+ // These are the weaver major/minor numbers for AspectJ 1.6.0
+ public final static short WEAVER_VERSION_MAJOR_AJ160M2 = 5;
+ public final static short WEAVER_VERSION_MAJOR_AJ160 = 4;
+ public final static short WEAVER_VERSION_MINOR_AJ160 = 0;
+
+ // These are the weaver major/minor numbers for AspectJ 1.6.1
+ // added annotation value binding
+ public final static short WEAVER_VERSION_MAJOR_AJ161 = 6;
+ public final static short WEAVER_VERSION_MINOR_AJ161 = 0;
+
+ // 1.6.9 adds new style ITDs. This is used to see what version of AJ was used to
+ // build the ITDs so we know id the generated get/set dispatchers are using old
+ // or new style (new style will be get/setters for private ITD fields)
+ public final static short WEAVER_VERSION_AJ169 = 7;
+
+ // These are the weaver major/minor versions for *this* weaver
+ private final static short CURRENT_VERSION_MAJOR = WEAVER_VERSION_AJ169;
+ private final static short CURRENT_VERSION_MINOR = 0;
+
+ public final static WeaverVersionInfo UNKNOWN = new WeaverVersionInfo(WEAVER_VERSION_MAJOR_UNKNOWN,
+ WEAVER_VERSION_MINOR_UNKNOWN);
+ public final static WeaverVersionInfo CURRENT = new WeaverVersionInfo(CURRENT_VERSION_MAJOR, CURRENT_VERSION_MINOR);
+
+ // These are the versions read in from a particular class file.
+ private final short major_version;
+ private final short minor_version;
+
+ private long buildstamp = Version.NOTIME;
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ // Default ctor uses the current version numbers
+ public WeaverVersionInfo() {
+ major_version = CURRENT_VERSION_MAJOR;
+ minor_version = CURRENT_VERSION_MINOR;
+ }
+
+ public WeaverVersionInfo(short major, short minor) {
+ major_version = major;
+ minor_version = minor;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeShort(CURRENT_VERSION_MAJOR);
+ s.writeShort(CURRENT_VERSION_MINOR);
+ s.writeLong(Version.getTime()); // build used to construct the
+ // class...
+ }
+
+ public static WeaverVersionInfo read(VersionedDataInputStream s) throws IOException {
+ short major = s.readShort();
+ short minor = s.readShort();
+ WeaverVersionInfo wvi = new WeaverVersionInfo(major, minor);
+ if (s.getMajorVersion() >= WEAVER_VERSION_MAJOR_AJ150M4) {
+ long stamp = 0;
+ try {
+ stamp = s.readLong();
+ wvi.setBuildstamp(stamp);
+ } catch (EOFException eof) {
+ // didnt find that build stamp - its not the end of the
+ // world
+ }
+ }
+ return wvi;
+ }
+
+ public short getMajorVersion() {
+ return major_version;
+ }
+
+ public short getMinorVersion() {
+ return minor_version;
+ }
+
+ public static short getCurrentWeaverMajorVersion() {
+ return CURRENT_VERSION_MAJOR;
+ }
+
+ public static short getCurrentWeaverMinorVersion() {
+ return CURRENT_VERSION_MINOR;
+ }
+
+ public void setBuildstamp(long stamp) {
+ buildstamp = stamp;
+ }
+
+ public long getBuildstamp() {
+ return buildstamp;
+ }
+
+ @Override
+ public String toString() {
+ return major_version + "." + minor_version;
+ }
+
+ public static String toCurrentVersionString() {
+ return CURRENT_VERSION_MAJOR + "." + CURRENT_VERSION_MINOR;
+ }
+
+ }
+
+ public static class SourceContextAttribute extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.SourceContext";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final String sourceFileName;
+ private final int[] lineBreaks;
+
+ public SourceContextAttribute(String sourceFileName, int[] lineBreaks) {
+ this.sourceFileName = sourceFileName;
+ this.lineBreaks = lineBreaks;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ if (s.canCompress()) {
+ s.writeCompressedPath(sourceFileName);
+ } else {
+ s.writeUTF(sourceFileName);
+ }
+ s.writeInt(lineBreaks.length);
+ int previous = 0;
+ for (int i = 0, max = lineBreaks.length; i < max; i++) {
+ s.writeShort(lineBreaks[i] - previous);
+ previous = lineBreaks[i];
+ }
+ }
+
+ public static SourceContextAttribute read(VersionedDataInputStream s) throws IOException {
+ String sourceFileName = s.isAtLeast169() ? s.readPath() : s.readUTF();
+ int lineBreaks = s.readInt();
+ int[] lines = new int[lineBreaks];
+ int previous = 0;
+ for (int i = 0; i < lineBreaks; i++) {
+ if (s.isAtLeast169()) {
+ lines[i] = s.readShort() + previous;
+ previous = lines[i];
+ } else {
+ lines[i] = s.readInt();
+ }
+ }
+ return new SourceContextAttribute(sourceFileName, lines);
+ }
+
+ public int[] getLineBreaks() {
+ return lineBreaks;
+ }
+
+ public String getSourceFileName() {
+ return sourceFileName;
+ }
+ }
+
+ public static class MethodDeclarationLineNumberAttribute extends AjAttribute {
+
+ public static final String AttributeName = "org.aspectj.weaver.MethodDeclarationLineNumber";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final int lineNumber;
+
+ // AV: added in 1.5 M3 thus handling cases where we don't have that
+ // information
+ private final int offset;
+
+ public MethodDeclarationLineNumberAttribute(int line, int offset) {
+ lineNumber = line;
+ this.offset = offset;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeInt(lineNumber);
+ s.writeInt(offset);
+ }
+
+ public static MethodDeclarationLineNumberAttribute read(VersionedDataInputStream s) throws IOException {
+ int line = s.readInt();
+ int offset = 0;
+ if (s.available() > 0) {
+ offset = s.readInt();
+ }
+ return new MethodDeclarationLineNumberAttribute(line, offset);
+ }
+
+ @Override
+ public String toString() {
+ return AttributeName + ": " + lineNumber + ":" + offset;
+ }
+ }
+
+ public static class PointcutDeclarationAttribute extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.PointcutDeclaration";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final ResolvedPointcutDefinition pointcutDef;
+
+ public PointcutDeclarationAttribute(ResolvedPointcutDefinition pointcutDef) {
+ this.pointcutDef = pointcutDef;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ pointcutDef.write(s);
+ }
+
+ public ResolvedPointcutDefinition reify() {
+ return pointcutDef;
+ }
+ }
+
+ public static class DeclareAttribute extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.Declare";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final Declare declare;
+
+ public DeclareAttribute(Declare declare) {
+ this.declare = declare;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ declare.write(s);
+ }
+
+ public Declare getDeclare() {
+ return declare;
+ }
+ }
+
+ public static class AdviceAttribute extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.Advice";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final AdviceKind kind;
+ private final Pointcut pointcut;
+ private final int extraParameterFlags;
+ private final int start;
+ private final int end;
+ private final ISourceContext sourceContext;
+
+ // these are only used by around advice
+ private boolean proceedInInners;
+ private ResolvedMember[] proceedCallSignatures; // size == # of proceed
+ // calls in body
+ private boolean[] formalsUnchangedToProceed; // size == formals.size
+ private UnresolvedType[] declaredExceptions;
+
+ /**
+ * @param lexicalPosition must be greater than the lexicalPosition of any advice declared before this one in an aspect,
+ * otherwise, it can be any value.
+ */
+ public AdviceAttribute(AdviceKind kind, Pointcut pointcut, int extraArgumentFlags, int start, int end,
+ ISourceContext sourceContext) {
+ this.kind = kind;
+ this.pointcut = pointcut;
+ extraParameterFlags = extraArgumentFlags;
+ this.start = start;
+ this.end = end;
+ this.sourceContext = sourceContext;
+
+ // XXX put this back when testing works better (or fails better)
+ // if (kind == AdviceKind.Around) throw new
+ // IllegalArgumentException("not for around");
+ }
+
+ public AdviceAttribute(AdviceKind kind, Pointcut pointcut, int extraArgumentFlags, int start, int end,
+ ISourceContext sourceContext, boolean proceedInInners, ResolvedMember[] proceedCallSignatures,
+ boolean[] formalsUnchangedToProceed, UnresolvedType[] declaredExceptions) {
+ this.kind = kind;
+ this.pointcut = pointcut;
+ extraParameterFlags = extraArgumentFlags;
+ this.start = start;
+ this.end = end;
+ this.sourceContext = sourceContext;
+
+ if (kind != AdviceKind.Around) {
+ throw new IllegalArgumentException("only for around");
+ }
+
+ this.proceedInInners = proceedInInners;
+ this.proceedCallSignatures = proceedCallSignatures;
+ this.formalsUnchangedToProceed = formalsUnchangedToProceed;
+ this.declaredExceptions = declaredExceptions;
+ }
+
+ public static AdviceAttribute read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AdviceKind kind = AdviceKind.read(s);
+ if (kind == AdviceKind.Around) {
+ return new AdviceAttribute(kind, Pointcut.read(s, context), s.readByte(), s.readInt(), s.readInt(), context,
+ s.readBoolean(), ResolvedMemberImpl.readResolvedMemberArray(s, context), FileUtil.readBooleanArray(s),
+ UnresolvedType.readArray(s));
+ } else {
+ return new AdviceAttribute(kind, Pointcut.read(s, context), s.readByte(), s.readInt(), s.readInt(), context);
+ }
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ pointcut.write(s);
+ s.writeByte(extraParameterFlags);
+ s.writeInt(start);
+ s.writeInt(end);
+
+ if (kind == AdviceKind.Around) {
+ s.writeBoolean(proceedInInners);
+ ResolvedMemberImpl.writeArray(proceedCallSignatures, s);
+ FileUtil.writeBooleanArray(formalsUnchangedToProceed, s);
+ UnresolvedType.writeArray(declaredExceptions, s);
+ }
+ }
+
+ public Advice reify(Member signature, World world, ResolvedType concreteAspect) {
+ return world.getWeavingSupport().createAdviceMunger(this, pointcut, signature, concreteAspect);
+ }
+
+ @Override
+ public String toString() {
+ return "AdviceAttribute(" + kind + ", " + pointcut + ", " + extraParameterFlags + ", " + start + ")";
+ }
+
+ public int getExtraParameterFlags() {
+ return extraParameterFlags;
+ }
+
+ public AdviceKind getKind() {
+ return kind;
+ }
+
+ public Pointcut getPointcut() {
+ return pointcut;
+ }
+
+ public UnresolvedType[] getDeclaredExceptions() {
+ return declaredExceptions;
+ }
+
+ public boolean[] getFormalsUnchangedToProceed() {
+ return formalsUnchangedToProceed;
+ }
+
+ public ResolvedMember[] getProceedCallSignatures() {
+ return proceedCallSignatures;
+ }
+
+ public boolean isProceedInInners() {
+ return proceedInInners;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public ISourceContext getSourceContext() {
+ return sourceContext;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ }
+
+ public static class Aspect extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.Aspect";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final PerClause perClause;
+ private IScope resolutionScope;
+
+ public Aspect(PerClause perClause) {
+ this.perClause = perClause;
+ }
+
+ public PerClause reify(ResolvedType inAspect) {
+ // XXXperClause.concretize(inAspect);
+ return perClause;
+ }
+
+ public PerClause reifyFromAtAspectJ(ResolvedType inAspect) {
+ perClause.resolve(resolutionScope);
+ return perClause;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ perClause.write(s);
+ }
+
+ public void setResolutionScope(IScope binding) {
+ resolutionScope = binding;
+ }
+ }
+
+ public static class PrivilegedAttribute extends AjAttribute {
+
+ public static final String AttributeName = "org.aspectj.weaver.Privileged";
+
+ private final ResolvedMember[] accessedMembers;
+
+ public PrivilegedAttribute(ResolvedMember[] accessedMembers) {
+ this.accessedMembers = accessedMembers;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ ResolvedMemberImpl.writeArray(accessedMembers, s);
+ }
+
+ public ResolvedMember[] getAccessedMembers() {
+ return accessedMembers;
+ }
+
+ public static PrivilegedAttribute read(VersionedDataInputStream stream, ISourceContext context) throws IOException {
+ PrivilegedAttribute pa = new PrivilegedAttribute(ResolvedMemberImpl.readResolvedMemberArray(stream, context));
+ return pa;
+ }
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+ }
+
+ public static class EffectiveSignatureAttribute extends AjAttribute {
+ public static final String AttributeName = "org.aspectj.weaver.EffectiveSignature";
+
+ @Override
+ public String getNameString() {
+ return AttributeName;
+ }
+
+ private final ResolvedMember effectiveSignature;
+ private final Shadow.Kind shadowKind;
+ private final boolean weaveBody;
+
+ public EffectiveSignatureAttribute(ResolvedMember effectiveSignature, Shadow.Kind shadowKind, boolean weaveBody) {
+ this.effectiveSignature = effectiveSignature;
+ this.shadowKind = shadowKind;
+ this.weaveBody = weaveBody;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ effectiveSignature.write(s);
+ shadowKind.write(s);
+ s.writeBoolean(weaveBody);
+ }
+
+ public static EffectiveSignatureAttribute read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ResolvedMember member = ResolvedMemberImpl.readResolvedMember(s, context);
+ return new EffectiveSignatureAttribute(member, Shadow.Kind.read(s), s.readBoolean());
+ }
+
+ public ResolvedMember getEffectiveSignature() {
+ return effectiveSignature;
+ }
+
+ @Override
+ public String toString() {
+ return "EffectiveSignatureAttribute(" + effectiveSignature + ", " + shadowKind + ")";
+ }
+
+ public Shadow.Kind getShadowKind() {
+ return shadowKind;
+ }
+
+ public boolean isWeaveBody() {
+ return weaveBody;
+ }
+
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjcMemberMaker.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjcMemberMaker.java
new file mode 100644
index 000000000..1ba711baa
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AjcMemberMaker.java
@@ -0,0 +1,698 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * The AjcMemberMaker is responsible for creating the representations of methods/fields/etc that are placed in both aspects and
+ * affected target types. It uses the NameMangler class to create the actual names that will be used.
+ */
+public class AjcMemberMaker {
+
+ private static final int PUBLIC_STATIC_FINAL = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;
+
+ private static final int PRIVATE_STATIC = Modifier.PRIVATE | Modifier.STATIC;
+
+ private static final int PUBLIC_STATIC = Modifier.PUBLIC | Modifier.STATIC;
+
+ private static final int BRIDGE = 0x0040;
+
+ private static final int VISIBILITY = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
+
+ public static final UnresolvedType CFLOW_STACK_TYPE = UnresolvedType.forName(NameMangler.CFLOW_STACK_TYPE);
+
+ public static final UnresolvedType AROUND_CLOSURE_TYPE = UnresolvedType
+ .forSignature("Lorg/aspectj/runtime/internal/AroundClosure;");
+
+ public static final UnresolvedType CONVERSIONS_TYPE = UnresolvedType.forSignature("Lorg/aspectj/runtime/internal/Conversions;");
+
+ public static final UnresolvedType NO_ASPECT_BOUND_EXCEPTION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/NoAspectBoundException;");
+
+ public static ResolvedMember ajcPreClinitMethod(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PRIVATE_STATIC, NameMangler.AJC_PRE_CLINIT_NAME, "()V");
+ }
+
+ public static ResolvedMember ajcPostClinitMethod(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PRIVATE_STATIC, NameMangler.AJC_POST_CLINIT_NAME, "()V");
+ }
+
+ public static Member noAspectBoundExceptionInit() {
+ return new ResolvedMemberImpl(Member.METHOD, NO_ASPECT_BOUND_EXCEPTION, Modifier.PUBLIC, "<init>", "()V");
+ }
+
+ public static Member noAspectBoundExceptionInit2() {
+ return new ResolvedMemberImpl(Member.METHOD, NO_ASPECT_BOUND_EXCEPTION, Modifier.PUBLIC, "<init>",
+ "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+ }
+
+ public static Member noAspectBoundExceptionInitWithCause() {
+ return new ResolvedMemberImpl(Member.METHOD, NO_ASPECT_BOUND_EXCEPTION, Modifier.PUBLIC, "<init>",
+ "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+ }
+
+ public static ResolvedMember perCflowPush(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, NameMangler.PERCFLOW_PUSH_METHOD, "()V");
+ }
+
+ public static ResolvedMember perCflowField(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.FIELD, declaringType, PUBLIC_STATIC, NameMangler.PERCFLOW_FIELD_NAME,
+ CFLOW_STACK_TYPE.getSignature());
+ }
+
+ public static ResolvedMember perSingletonField(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.FIELD, declaringType, PUBLIC_STATIC, NameMangler.PERSINGLETON_FIELD_NAME,
+ declaringType.getSignature());
+ }
+
+ public static ResolvedMember initFailureCauseField(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.FIELD, declaringType, PRIVATE_STATIC, NameMangler.INITFAILURECAUSE_FIELD_NAME,
+ UnresolvedType.THROWABLE.getSignature());
+ }
+
+ public static ResolvedMember perObjectField(UnresolvedType declaringType, ResolvedType aspectType) {
+ int modifiers = Modifier.PRIVATE;
+ if (!UnresolvedType.SERIALIZABLE.resolve(aspectType.getWorld()).isAssignableFrom(aspectType)) {
+ modifiers |= Modifier.TRANSIENT;
+ }
+ return new ResolvedMemberImpl(Member.FIELD, declaringType, modifiers, aspectType,
+ NameMangler.perObjectInterfaceField(aspectType), UnresolvedType.NONE);
+ }
+
+ // PTWIMPL ResolvedMember for aspect instance field, declared in matched type
+ public static ResolvedMember perTypeWithinField(UnresolvedType declaringType, ResolvedType aspectType) {
+ int modifiers = Modifier.PRIVATE | Modifier.STATIC;
+ if (!isSerializableAspect(aspectType)) {
+ modifiers |= Modifier.TRANSIENT;
+ }
+ return new ResolvedMemberImpl(Member.FIELD, declaringType, modifiers, aspectType,
+ NameMangler.perTypeWithinFieldForTarget(aspectType), UnresolvedType.NONE);
+ }
+
+ // PTWIMPL ResolvedMember for type instance field, declared in aspect
+ // (holds typename for which aspect instance exists)
+ public static ResolvedMember perTypeWithinWithinTypeField(UnresolvedType declaringType, ResolvedType aspectType) {
+ int modifiers = Modifier.PRIVATE;
+ if (!isSerializableAspect(aspectType)) {
+ modifiers |= Modifier.TRANSIENT;
+ }
+ return new ResolvedMemberImpl(Member.FIELD, declaringType, modifiers, UnresolvedType.JL_STRING,
+ NameMangler.PERTYPEWITHIN_WITHINTYPEFIELD, UnresolvedType.NONE);
+ }
+
+ private static boolean isSerializableAspect(ResolvedType aspectType) {
+ return UnresolvedType.SERIALIZABLE.resolve(aspectType.getWorld()).isAssignableFrom(aspectType);
+ }
+
+ public static ResolvedMember perObjectBind(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC | Modifier.SYNCHRONIZED, NameMangler.PEROBJECT_BIND_METHOD,
+ "(Ljava/lang/Object;)V");
+ }
+
+ // PTWIMPL ResolvedMember for getInstance() method, declared in aspect
+ public static ResolvedMember perTypeWithinGetInstance(UnresolvedType declaringType) {
+ // private static a.X ajc$getInstance(java.lang.Class)
+ ResolvedMemberImpl rm = new ResolvedMemberImpl(Member.METHOD, declaringType, PRIVATE_STATIC, declaringType, // return value
+ NameMangler.PERTYPEWITHIN_GETINSTANCE_METHOD, new UnresolvedType[] { UnresolvedType.JL_CLASS });
+ return rm;
+ }
+
+ // PTWIMPL ResolvedMember for getWithinTypeName() method
+ public static ResolvedMember perTypeWithinGetWithinTypeNameMethod(UnresolvedType declaringType, boolean inJava5Mode) {
+ // public String getWithinTypeName()
+ ResolvedMemberImpl rm = new ResolvedMemberImpl(Member.METHOD, declaringType, Modifier.PUBLIC, UnresolvedType.JL_STRING, // return
+ // value
+ NameMangler.PERTYPEWITHIN_GETWITHINTYPENAME_METHOD, UnresolvedType.NONE);
+ return rm;
+ }
+
+ public static ResolvedMember perTypeWithinCreateAspectInstance(UnresolvedType declaringType) {
+ // public static a.X ajc$createAspectInstance(java.lang.String)
+ ResolvedMemberImpl rm = new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, declaringType, // return value
+ NameMangler.PERTYPEWITHIN_CREATEASPECTINSTANCE_METHOD,
+ new UnresolvedType[] { UnresolvedType.forSignature("Ljava/lang/String;") }, new UnresolvedType[] {});
+ return rm;
+ }
+
+ public static UnresolvedType perObjectInterfaceType(UnresolvedType aspectType) {
+ return UnresolvedType.forName(aspectType.getName() + "$ajcMightHaveAspect");
+ }
+
+ public static ResolvedMember perObjectInterfaceGet(UnresolvedType aspectType) {
+ return new ResolvedMemberImpl(Member.METHOD, perObjectInterfaceType(aspectType), Modifier.PUBLIC | Modifier.ABSTRACT,
+ NameMangler.perObjectInterfaceGet(aspectType), "()" + aspectType.getSignature());
+ }
+
+ public static ResolvedMember perObjectInterfaceSet(UnresolvedType aspectType) {
+ return new ResolvedMemberImpl(Member.METHOD, perObjectInterfaceType(aspectType), Modifier.PUBLIC | Modifier.ABSTRACT,
+ NameMangler.perObjectInterfaceSet(aspectType), "(" + aspectType.getSignature() + ")V");
+ }
+
+ // PTWIMPL ResolvedMember for localAspectOf() method, declared in matched type
+ public static ResolvedMember perTypeWithinLocalAspectOf(UnresolvedType shadowType, UnresolvedType aspectType) {
+ return new ResolvedMemberImpl(Member.METHOD, shadowType,// perTypeWithinInterfaceType(aspectType),
+ Modifier.PUBLIC | Modifier.STATIC, NameMangler.perTypeWithinLocalAspectOf(aspectType), "()"
+ + aspectType.getSignature());
+ }
+
+ public static ResolvedMember perSingletonAspectOfMethod(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "aspectOf", "()" + declaringType.getSignature());
+ }
+
+ public static ResolvedMember perSingletonHasAspectMethod(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "hasAspect", "()Z");
+ }
+
+ public static ResolvedMember perCflowAspectOfMethod(UnresolvedType declaringType) {
+ return perSingletonAspectOfMethod(declaringType);
+ }
+
+ public static ResolvedMember perCflowHasAspectMethod(UnresolvedType declaringType) {
+ return perSingletonHasAspectMethod(declaringType);
+ }
+
+ public static ResolvedMember perObjectAspectOfMethod(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "aspectOf", "(Ljava/lang/Object;)"
+ + declaringType.getSignature());
+ }
+
+ public static ResolvedMember perObjectHasAspectMethod(UnresolvedType declaringType) {
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, "hasAspect", "(Ljava/lang/Object;)Z");
+ }
+
+ // PTWIMPL ResolvedMember for aspectOf(), declared in aspect
+ public static ResolvedMember perTypeWithinAspectOfMethod(UnresolvedType declaringType, boolean inJava5Mode) {
+ UnresolvedType parameterType = null;
+ if (inJava5Mode) {
+ parameterType = UnresolvedType.forRawTypeName("java.lang.Class");
+ } else {
+ parameterType = UnresolvedType.forSignature("Ljava/lang/Class;");
+ }
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, declaringType, "aspectOf",
+ new UnresolvedType[] { parameterType });
+ // return new ResolvedMemberImpl(Member.METHOD,
+ // declaringType, PUBLIC_STATIC, "aspectOf",
+ // "(Ljava/lang/Class;)" + declaringType.getSignature());
+ }
+
+ /*
+ * public static ResolvedMember perTypeWithinGetWithinTypeMethod(UnresolvedType declaringType, boolean inJava5Mode) {
+ * UnresolvedType returnType = null; if (inJava5Mode) { returnType = UnresolvedType.forRawTypeName("java.lang.Class"); } else {
+ * returnType = UnresolvedType.forSignature("Ljava/lang/Class;"); } return new
+ * ResolvedMemberImpl(Member.METHOD,declaringType,Modifier.PUBLIC,ResolvedType.JAVA_LANG_STRING,"getWithinType",new
+ * UnresolvedType[]{}); }
+ */
+
+ // PTWIMPL ResolvedMember for hasAspect(), declared in aspect
+ public static ResolvedMember perTypeWithinHasAspectMethod(UnresolvedType declaringType, boolean inJava5Mode) {
+ UnresolvedType parameterType = null;
+ if (inJava5Mode) {
+ parameterType = UnresolvedType.forRawTypeName("java.lang.Class");
+ } else {
+ parameterType = UnresolvedType.forSignature("Ljava/lang/Class;");
+ }
+ return new ResolvedMemberImpl(Member.METHOD, declaringType, PUBLIC_STATIC, UnresolvedType.BOOLEAN, "hasAspect",
+ new UnresolvedType[] { parameterType });
+ // return new ResolvedMemberImpl(Member.METHOD,
+ // declaringType, PUBLIC_STATIC, "hasAspect",
+ // "(Ljava/lang/Class;)Z");
+ }
+
+ // -- privileged accessors
+
+ public static ResolvedMember privilegedAccessMethodForMethod(UnresolvedType aspectType, ResolvedMember method) {
+ return new ResolvedMemberImpl(Member.METHOD, method.getDeclaringType(), Modifier.PUBLIC
+ | (Modifier.isStatic(method.getModifiers()) ? Modifier.STATIC : 0), method.getReturnType(),
+ NameMangler.privilegedAccessMethodForMethod(method.getName(), method.getDeclaringType(), aspectType),
+ method.getParameterTypes(), method.getExceptions());
+ }
+
+ /**
+ * Return a resolvedmember representing the synthetic getter for the field. The old style (<1.6.9) is a heavyweight static
+ * method with a long name. The new style (1.6.9 and later) is short, and reusable across aspects.
+ *
+ * @param aspectType the aspect attempting the access
+ * @param field the field to be accessed
+ * @param shortSyntax is the old (long) or new (short) style format being used
+ * @return a resolvedmember representing the synthetic getter
+ */
+ public static ResolvedMember privilegedAccessMethodForFieldGet(UnresolvedType aspectType, Member field, boolean shortSyntax) {
+ UnresolvedType fieldDeclaringType = field.getDeclaringType();
+ if (shortSyntax) {
+ UnresolvedType[] args = null;
+ if (Modifier.isStatic(field.getModifiers())) {
+ args = ResolvedType.NONE;
+ } else {
+ args = new UnresolvedType[] { fieldDeclaringType };
+ }
+ StringBuffer name = new StringBuffer("ajc$get$");
+ name.append(field.getName());
+ return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, field.getReturnType(), name.toString(),
+ args);
+ } else {
+ String getterName = NameMangler.privilegedAccessMethodForFieldGet(field.getName(), fieldDeclaringType, aspectType);
+ String sig;
+ if (Modifier.isStatic(field.getModifiers())) {
+ sig = "()" + field.getReturnType().getSignature();
+ } else {
+ sig = "(" + fieldDeclaringType.getSignature() + ")" + field.getReturnType().getSignature();
+ }
+ return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, getterName, sig);
+ }
+ }
+
+ /**
+ * Return a resolvedmember representing the synthetic setter for the field. The old style (<1.6.9) is a heavyweight static
+ * method with a long name. The new style (1.6.9 and later) is short, not always static, and reusable across aspects.
+ *
+ * @param aspectType the aspect attempting the access
+ * @param field the field to be accessed
+ * @param shortSyntax is the old or new style format being used
+ * @return a resolvedmember representing the synthetic setter
+ */
+ public static ResolvedMember privilegedAccessMethodForFieldSet(UnresolvedType aspectType, Member field, boolean shortSyntax) {
+ UnresolvedType fieldDeclaringType = field.getDeclaringType();
+ if (shortSyntax) {
+ UnresolvedType[] args = null;
+ if (Modifier.isStatic(field.getModifiers())) {
+ args = new UnresolvedType[] { field.getType() };
+ } else {
+ args = new UnresolvedType[] { fieldDeclaringType, field.getType() };
+ }
+ StringBuffer name = new StringBuffer("ajc$set$");
+ name.append(field.getName());
+ return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, UnresolvedType.VOID, name.toString(),
+ args);
+ } else {
+ String setterName = NameMangler.privilegedAccessMethodForFieldSet(field.getName(), fieldDeclaringType, aspectType);
+ String sig;
+ if (Modifier.isStatic(field.getModifiers())) {
+ sig = "(" + field.getReturnType().getSignature() + ")V";
+ } else {
+ sig = "(" + fieldDeclaringType.getSignature() + field.getReturnType().getSignature() + ")V";
+ }
+ return new ResolvedMemberImpl(Member.METHOD, fieldDeclaringType, PUBLIC_STATIC, setterName, sig);
+ }
+ }
+
+ // --- inline accessors
+ // ??? can eclipse handle a transform this weird without putting synthetics into the mix
+ public static ResolvedMember superAccessMethod(UnresolvedType baseType, ResolvedMember method) {
+ UnresolvedType[] paramTypes = method.getParameterTypes();
+ // if (!method.isStatic()) {
+ // paramTypes = UnresolvedType.insert(method.getDeclaringType(), paramTypes);
+ // }
+ return new ResolvedMemberImpl(Member.METHOD, baseType, Modifier.PUBLIC, method.getReturnType(),
+ NameMangler.superDispatchMethod(baseType, method.getName()), paramTypes, method.getExceptions());
+ }
+
+ public static ResolvedMember inlineAccessMethodForMethod(UnresolvedType aspectType, ResolvedMember method) {
+ UnresolvedType[] paramTypes = method.getParameterTypes();
+ if (!Modifier.isStatic(method.getModifiers())) {
+ paramTypes = UnresolvedType.insert(method.getDeclaringType(), paramTypes);
+ }
+ return new ResolvedMemberImpl(Member.METHOD, aspectType,
+ PUBLIC_STATIC, // ??? what about privileged and super access
+ // ???Modifier.PUBLIC | (method.isStatic() ? Modifier.STATIC : 0),
+ method.getReturnType(),
+
+ NameMangler.inlineAccessMethodForMethod(method.getName(), method.getDeclaringType(), aspectType), paramTypes,
+ method.getExceptions());
+ }
+
+ public static ResolvedMember inlineAccessMethodForFieldGet(UnresolvedType aspectType, Member field) {
+ String sig;
+ if (Modifier.isStatic(field.getModifiers())) {
+ sig = "()" + field.getReturnType().getSignature();
+ } else {
+ sig = "(" + field.getDeclaringType().getSignature() + ")" + field.getReturnType().getSignature();
+ }
+
+ return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, // Modifier.PUBLIC | (field.isStatic() ?
+ // Modifier.STATIC : 0),
+ NameMangler.inlineAccessMethodForFieldGet(field.getName(), field.getDeclaringType(), aspectType), sig);
+ }
+
+ public static ResolvedMember inlineAccessMethodForFieldSet(UnresolvedType aspectType, Member field) {
+ String sig;
+ if (Modifier.isStatic(field.getModifiers())) {
+ sig = "(" + field.getReturnType().getSignature() + ")V";
+ } else {
+ sig = "(" + field.getDeclaringType().getSignature() + field.getReturnType().getSignature() + ")V";
+ }
+
+ return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, // Modifier.PUBLIC | (field.isStatic() ?
+ // Modifier.STATIC : 0),
+ NameMangler.inlineAccessMethodForFieldSet(field.getName(), field.getDeclaringType(), aspectType), sig);
+ }
+
+ // --- runtimeLibrary api stuff
+
+ public static Member cflowStackPeekInstance() {
+ return new MemberImpl(Member.METHOD, CFLOW_STACK_TYPE, 0, "peekInstance", "()Ljava/lang/Object;");
+ }
+
+ public static Member cflowStackPushInstance() {
+ return new MemberImpl(Member.METHOD, CFLOW_STACK_TYPE, 0, "pushInstance", "(Ljava/lang/Object;)V");
+ }
+
+ public static Member cflowStackIsValid() {
+ return new MemberImpl(Member.METHOD, CFLOW_STACK_TYPE, 0, "isValid", "()Z");
+ }
+
+ public static Member cflowStackInit() {
+ return new MemberImpl(Member.CONSTRUCTOR, CFLOW_STACK_TYPE, 0, "<init>", "()V");
+ }
+
+ public static Member aroundClosurePreInitializationField() {
+ return new MemberImpl(Member.FIELD, AROUND_CLOSURE_TYPE, 0, "preInitializationState", "[Ljava/lang/Object;");
+ }
+
+ public static Member aroundClosurePreInitializationGetter() {
+ return new MemberImpl(Member.METHOD, AROUND_CLOSURE_TYPE, 0, "getPreInitializationState", "()[Ljava/lang/Object;");
+ }
+
+ public static ResolvedMember preIntroducedConstructor(UnresolvedType aspectType, UnresolvedType targetType,
+ UnresolvedType[] paramTypes) {
+ return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC_FINAL, UnresolvedType.OBJECTARRAY,
+ NameMangler.preIntroducedConstructor(aspectType, targetType), paramTypes);
+ }
+
+ public static ResolvedMember postIntroducedConstructor(UnresolvedType aspectType, UnresolvedType targetType,
+ UnresolvedType[] paramTypes) {
+ return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC_FINAL, UnresolvedType.VOID,
+ NameMangler.postIntroducedConstructor(aspectType, targetType), UnresolvedType.insert(targetType, paramTypes));
+ }
+
+ public static ResolvedMember itdAtDeclareParentsField(ResolvedType targetType, UnresolvedType itdType, UnresolvedType aspectType) {
+ return new ResolvedMemberImpl(Member.FIELD, targetType, Modifier.PRIVATE, itdType, NameMangler.itdAtDeclareParentsField(
+ aspectType, itdType), ResolvedType.NONE);
+ }
+
+ public static ResolvedMember interConstructor(ResolvedType targetType, ResolvedMember constructor, UnresolvedType aspectType) {
+ //
+ // ResolvedType targetType,
+ // UnresolvedType[] argTypes,
+ // int modifiers)
+ // {
+ ResolvedMember ret = new ResolvedMemberImpl(Member.CONSTRUCTOR, targetType, Modifier.PUBLIC, UnresolvedType.VOID, "<init>",
+ constructor.getParameterTypes(), constructor.getExceptions());
+ // System.out.println("ret: " + ret + " mods: " + Modifier.toString(modifiers));
+ if (Modifier.isPublic(constructor.getModifiers())) {
+ return ret;
+ }
+ while (true) {
+ ret = addCookieTo(ret, aspectType);
+ if (targetType.lookupMemberNoSupers(ret) == null) {
+ return ret;
+ }
+ }
+ }
+
+ public static ResolvedMember interFieldInitializer(ResolvedMember field, UnresolvedType aspectType) {
+ return new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, NameMangler.interFieldInitializer(aspectType,
+ field.getDeclaringType(), field.getName()), Modifier.isStatic(field.getModifiers()) ? "()V" : "("
+ + field.getDeclaringType().getSignature() + ")V");
+ }
+
+ private static int makePublicNonFinal(int modifiers) {
+ return (modifiers & ~VISIBILITY & ~Modifier.FINAL) | Modifier.PUBLIC;
+ }
+
+ private static int makeNonFinal(int modifiers) {
+ return (modifiers & ~Modifier.FINAL);
+ }
+
+ /**
+ * This static method goes on the aspect that declares the inter-type field
+ */
+ public static ResolvedMember interFieldSetDispatcher(ResolvedMember field, UnresolvedType aspectType) {
+ ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, UnresolvedType.VOID,
+ NameMangler.interFieldSetDispatcher(aspectType, field.getDeclaringType(), field.getName()), Modifier.isStatic(field
+ .getModifiers()) ? new UnresolvedType[] { field.getReturnType() } : new UnresolvedType[] {
+ field.getDeclaringType(), field.getReturnType() });
+ rm.setTypeVariables(field.getTypeVariables());
+ return rm;
+ }
+
+ /**
+ * This static method goes on the aspect that declares the inter-type field
+ */
+ public static ResolvedMember interFieldGetDispatcher(ResolvedMember field, UnresolvedType aspectType) {
+ ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, field.getReturnType(),
+ NameMangler.interFieldGetDispatcher(aspectType, field.getDeclaringType(), field.getName()), Modifier.isStatic(field
+ .getModifiers()) ? UnresolvedType.NONE : new UnresolvedType[] { field.getDeclaringType() },
+ UnresolvedType.NONE);
+ rm.setTypeVariables(field.getTypeVariables());
+ return rm;
+ }
+
+ // private static int makeFieldModifiers(int declaredModifiers) {
+ // int ret = Modifier.PUBLIC;
+ // if (Modifier.isTransient(declaredModifiers)) ret |= Modifier.TRANSIENT;
+ // if (Modifier.isVolatile(declaredModifiers)) ret |= Modifier.VOLATILE;
+ // return ret;
+ // }
+
+ /**
+ * This field goes on the class the field is declared onto. Field names for ITDs onto interfaces are handled below.
+ */
+ public static ResolvedMember interFieldClassField(ResolvedMember field, UnresolvedType aspectType, boolean newStyle) {
+ int modifiers = (newStyle ? makeNonFinal(field.getModifiers()) : makePublicNonFinal(field.getModifiers()));
+ String name = null;
+ if (newStyle) {
+ name = field.getName();
+ } else {
+ name = NameMangler.interFieldClassField(field.getModifiers(), aspectType, field.getDeclaringType(), field.getName());
+ }
+ return new ResolvedMemberImpl(Member.FIELD, field.getDeclaringType(), modifiers, field.getReturnType(), name,
+ UnresolvedType.NONE, UnresolvedType.NONE);
+ }
+
+ /**
+ * This field goes on top-most implementers of the interface the field is declared onto
+ */
+ public static ResolvedMember interFieldInterfaceField(ResolvedMember field, UnresolvedType onClass, UnresolvedType aspectType, boolean newStyle) {
+ String name = null;
+ if (newStyle) {
+ name = field.getName();
+ } else {
+ name = NameMangler.interFieldInterfaceField(aspectType, field.getDeclaringType(), field.getName());
+ }
+ return new ResolvedMemberImpl(Member.FIELD, onClass, makePublicNonFinal(field.getModifiers()), field.getReturnType(),
+ name, UnresolvedType.NONE, UnresolvedType.NONE);
+ }
+
+ /**
+ * This instance method goes on the interface the field is declared onto as well as its top-most implementors
+ */
+ public static ResolvedMember interFieldInterfaceSetter(ResolvedMember field, ResolvedType onType, UnresolvedType aspectType) {
+ int modifiers = Modifier.PUBLIC;
+ if (onType.isInterface()) {
+ modifiers |= Modifier.ABSTRACT;
+ }
+ ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, onType, modifiers, UnresolvedType.VOID,
+ NameMangler.interFieldInterfaceSetter(aspectType, field.getDeclaringType(), field.getName()),
+ new UnresolvedType[] { field.getReturnType() }, UnresolvedType.NONE);
+ rm.setTypeVariables(field.getTypeVariables());
+ return rm;
+ }
+
+ /**
+ * This instance method goes on the interface the field is declared onto as well as its top-most implementors
+ */
+ public static ResolvedMember interFieldInterfaceGetter(ResolvedMember field, ResolvedType onType, UnresolvedType aspectType) {
+ int modifiers = Modifier.PUBLIC;
+ if (onType.isInterface()) {
+ modifiers |= Modifier.ABSTRACT;
+ }
+ ResolvedMember rm = new ResolvedMemberImpl(Member.METHOD, onType, modifiers, field.getReturnType(),
+ NameMangler.interFieldInterfaceGetter(aspectType, field.getDeclaringType(), field.getName()), UnresolvedType.NONE,
+ UnresolvedType.NONE);
+ rm.setTypeVariables(field.getTypeVariables());
+ return rm;
+ }
+
+ /**
+ * This method goes on the target type of the inter-type method. (and possibly the topmost-implementors, if the target type is
+ * an interface). The implementation will call the interMethodDispatch method on the aspect.
+ */
+ public static ResolvedMember interMethod(ResolvedMember meth, UnresolvedType aspectType, boolean onInterface) {
+ if (Modifier.isPublic(meth.getModifiers()) && !onInterface) {
+ return meth;
+ }
+
+ int modifiers = makePublicNonFinal(meth.getModifiers());
+ if (onInterface) {
+ modifiers |= Modifier.ABSTRACT;
+ }
+
+ ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, meth.getDeclaringType(), modifiers, meth.getReturnType(),
+ NameMangler.interMethod(meth.getModifiers(), aspectType, meth.getDeclaringType(), meth.getName()),
+ meth.getParameterTypes(), meth.getExceptions());
+ rmi.setParameterNames(meth.getParameterNames());
+ rmi.setTypeVariables(meth.getTypeVariables());
+ return rmi;
+ }
+
+ /**
+ * This method goes on the target type of the inter-type method. (and possibly the topmost-implementors, if the target type is
+ * an interface). The implementation will call the interMethodDispatch method on the aspect.
+ */
+ public static ResolvedMember interMethodBridger(ResolvedMember meth, UnresolvedType aspectType, boolean onInterface) {
+ // if (Modifier.isPublic(meth.getModifiers()) && !onInterface)
+ // return meth;
+
+ int modifiers = makePublicNonFinal(meth.getModifiers()) | BRIDGE;
+ if (onInterface) {
+ modifiers |= Modifier.ABSTRACT;
+ }
+
+ ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, meth.getDeclaringType(), modifiers, meth.getReturnType(),
+ NameMangler.interMethod(meth.getModifiers(), aspectType, meth.getDeclaringType(), meth.getName()),
+ meth.getParameterTypes(), meth.getExceptions());
+ rmi.setTypeVariables(meth.getTypeVariables());
+ return rmi;
+ }
+
+ /**
+ * Sometimes the intertyped method requires a bridge method alongside it. For example if the method 'N SomeI<N>.m()' is put onto
+ * an interface 'interface I<N extends Number>' and then a concrete implementation is 'class C implements I<Float>' then the ITD
+ * on the interface will be 'Number m()', whereas the ITD on the 'topmostimplementor' will be 'Float m()'. A bridge method needs
+ * to be created in the topmostimplementor 'Number m()' that delegates to 'Float m()'
+ */
+ public static ResolvedMember bridgerToInterMethod(ResolvedMember meth, UnresolvedType aspectType) {
+
+ int modifiers = makePublicNonFinal(meth.getModifiers());
+
+ ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, aspectType, modifiers, meth.getReturnType(),
+ NameMangler.interMethod(meth.getModifiers(), aspectType, meth.getDeclaringType(), meth.getName()),
+ meth.getParameterTypes(), meth.getExceptions());
+ rmi.setTypeVariables(meth.getTypeVariables());
+ return rmi;
+ }
+
+ /**
+ * This static method goes on the declaring aspect of the inter-type method. The implementation calls the interMethodBody()
+ * method on the aspect.
+ */
+ public static ResolvedMember interMethodDispatcher(ResolvedMember meth, UnresolvedType aspectType) {
+ UnresolvedType[] paramTypes = meth.getParameterTypes();
+ if (!Modifier.isStatic(meth.getModifiers())) {
+ paramTypes = UnresolvedType.insert(meth.getDeclaringType(), paramTypes);
+ }
+
+ ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, aspectType, PUBLIC_STATIC, meth.getReturnType(),
+ NameMangler.interMethodDispatcher(aspectType, meth.getDeclaringType(), meth.getName()), paramTypes,
+ meth.getExceptions());
+ rmi.setParameterNames(meth.getParameterNames());
+ rmi.setTypeVariables(meth.getTypeVariables());
+
+ return rmi;
+ }
+
+ /**
+ * This method goes on the declaring aspect of the inter-type method. It contains the real body of the ITD method.
+ */
+ public static ResolvedMember interMethodBody(ResolvedMember meth, UnresolvedType aspectType) {
+ UnresolvedType[] paramTypes = meth.getParameterTypes();
+ if (!Modifier.isStatic(meth.getModifiers())) {
+ paramTypes = UnresolvedType.insert(meth.getDeclaringType(), paramTypes);
+ }
+
+ int modifiers = PUBLIC_STATIC;
+ if (Modifier.isStrict(meth.getModifiers())) {
+ modifiers |= Modifier.STRICT;
+ }
+
+ ResolvedMemberImpl rmi = new ResolvedMemberImpl(Member.METHOD, aspectType, modifiers, meth.getReturnType(),
+ NameMangler.interMethodBody(aspectType, meth.getDeclaringType(), meth.getName()), paramTypes, meth.getExceptions());
+ rmi.setParameterNames(meth.getParameterNames());
+ rmi.setTypeVariables(meth.getTypeVariables());
+ return rmi;
+ }
+
+ private static ResolvedMember addCookieTo(ResolvedMember ret, UnresolvedType aspectType) {
+ UnresolvedType[] params = ret.getParameterTypes();
+
+ UnresolvedType[] freshParams = UnresolvedType.add(params, aspectType);
+ return new ResolvedMemberImpl(ret.getKind(), ret.getDeclaringType(), ret.getModifiers(), ret.getReturnType(),
+ ret.getName(), freshParams, ret.getExceptions());
+ }
+
+ public static ResolvedMember toObjectConversionMethod(UnresolvedType fromType) {
+ if (fromType.isPrimitiveType()) {
+ String name = fromType.toString() + "Object";
+ return new ResolvedMemberImpl(Member.METHOD, CONVERSIONS_TYPE, PUBLIC_STATIC, UnresolvedType.OBJECT, name,
+ new UnresolvedType[] { fromType }, UnresolvedType.NONE);
+ } else {
+ return null;
+ }
+ }
+
+ public static Member interfaceConstructor(ResolvedType resolvedTypeX) {
+ // AMC next two lines should not be needed when sig for generic type is changed
+ ResolvedType declaringType = resolvedTypeX;
+ if (declaringType.isRawType()) {
+ declaringType = declaringType.getGenericType();
+ }
+ return new ResolvedMemberImpl(Member.CONSTRUCTOR, declaringType, Modifier.PUBLIC, "<init>", "()V");
+ }
+
+ // -- common types we use. Note: Java 5 dependand types are refered to as String
+ public final static UnresolvedType ASPECT_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Aspect;");
+
+ public final static UnresolvedType BEFORE_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Before;");
+
+ public final static UnresolvedType AROUND_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Around;");
+
+ public final static UnresolvedType AFTERRETURNING_ANNOTATION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/annotation/AfterReturning;");
+
+ public final static UnresolvedType AFTERTHROWING_ANNOTATION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/annotation/AfterThrowing;");
+
+ public final static UnresolvedType AFTER_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/After;");
+
+ public final static UnresolvedType POINTCUT_ANNOTATION = UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/Pointcut;");
+
+ public final static UnresolvedType DECLAREERROR_ANNOTATION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/annotation/DeclareError;");
+
+ public final static UnresolvedType DECLAREWARNING_ANNOTATION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/annotation/DeclareWarning;");
+
+ public final static UnresolvedType DECLAREPRECEDENCE_ANNOTATION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/annotation/DeclarePrecedence;");
+
+ // public final static UnresolvedType DECLAREIMPLEMENTS_ANNOTATION =
+ // UnresolvedType.forSignature("Lorg/aspectj/lang/annotation/DeclareImplements;");
+
+ public final static UnresolvedType DECLAREPARENTS_ANNOTATION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/annotation/DeclareParents;");
+
+ public final static UnresolvedType DECLAREMIXIN_ANNOTATION = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/annotation/DeclareMixin;");
+
+ public final static UnresolvedType TYPEX_JOINPOINT = UnresolvedType.forSignature("Lorg/aspectj/lang/JoinPoint;");
+
+ public final static UnresolvedType TYPEX_PROCEEDINGJOINPOINT = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/ProceedingJoinPoint;");
+
+ public final static UnresolvedType TYPEX_STATICJOINPOINT = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/JoinPoint$StaticPart;");
+
+ public final static UnresolvedType TYPEX_ENCLOSINGSTATICJOINPOINT = UnresolvedType
+ .forSignature("Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;");
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotatedElement.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotatedElement.java
new file mode 100644
index 000000000..86297b85b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotatedElement.java
@@ -0,0 +1,21 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Represents any element that may have annotations
+ */
+public interface AnnotatedElement {
+ boolean hasAnnotation(UnresolvedType ofType);
+
+ ResolvedType[] getAnnotationTypes();
+
+ AnnotationAJ getAnnotationOfType(UnresolvedType ofType);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAJ.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAJ.java
new file mode 100644
index 000000000..311b12e1f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAJ.java
@@ -0,0 +1,102 @@
+/* *******************************************************************
+ * Copyright (c) 2006-2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Set;
+
+/**
+ * Simple representation of an annotation that the weaver can work with.
+ *
+ * @author AndyClement
+ */
+public interface AnnotationAJ {
+
+ public static final AnnotationAJ[] EMPTY_ARRAY = new AnnotationAJ[0];
+
+ /**
+ * @return the signature for the annotation type, eg. Lcom/foo/MyAnno;
+ */
+ public String getTypeSignature();
+
+ /**
+ * @return the type name for the annotation, eg. com.foo.MyAnno
+ */
+ public String getTypeName();
+
+ /**
+ * @return the type of the annotation
+ */
+ public ResolvedType getType();
+
+ /**
+ * return true if this annotation can target an annotation type
+ */
+ public boolean allowedOnAnnotationType();
+
+ /**
+ * @return true if this annotation can be put on a field
+ */
+ public boolean allowedOnField();
+
+ /**
+ * @return true if this annotation can target a 'regular' type. A 'regular' type is enum/class/interface - it is *not*
+ * annotation.
+ */
+ public boolean allowedOnRegularType();
+
+ /**
+ * @return for the @target annotation, this will return a set of the element-types it can be applied to. For other annotations ,
+ * it returns the empty set.
+ */
+ public Set<String> getTargets();
+
+ /**
+ * @param name the name of the value
+ * @return true if there is a value with that name
+ */
+ public boolean hasNamedValue(String name);
+
+ /**
+ * @param name the name of the annotation field
+ * @param value the value of the annotation field
+ * @return true if there is a value with the specified name and value
+ */
+ public boolean hasNameValuePair(String name, String value);
+
+ /**
+ * @return String representation of the valid targets for this annotation, eg. "{TYPE,FIELD}"
+ */
+ public String getValidTargets();
+
+ /**
+ * @return String form of the annotation and any values, eg. @Foo(a=b,c=d)
+ */
+ public String stringify();
+
+ /**
+ * @return true if this annotation is marked with @target
+ */
+ public boolean specifiesTarget();
+
+ /**
+ * @return true if the annotation is marked for runtime visibility
+ */
+ public boolean isRuntimeVisible();
+
+ /**
+ * Determine the string representation of the value of a field. For example in @SuppressAjWarnings({"adviceDidNotMatch"}) the
+ * return value for getStringFormOfValue("value") would be "[adviceDidNotMatch]".
+ *
+ * @param name the name of the annotation field being looked up
+ * @return string representation of the value of that field, may be null if no such field set
+ */
+ public String getStringFormOfValue(String name);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAnnotationValue.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAnnotationValue.java
new file mode 100644
index 000000000..c25c33cd2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationAnnotationValue.java
@@ -0,0 +1,35 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+public class AnnotationAnnotationValue extends AnnotationValue {
+
+ private AnnotationAJ value;
+
+ public AnnotationAnnotationValue(AnnotationAJ value) {
+ super(AnnotationValue.ANNOTATION);
+ this.value = value;
+ }
+
+ public AnnotationAJ getAnnotation() {
+ return value;
+ }
+
+ public String stringify() {
+ return value.stringify();
+ }
+
+ public String toString() {
+ return value.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationNameValuePair.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationNameValuePair.java
new file mode 100644
index 000000000..17824ac69
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationNameValuePair.java
@@ -0,0 +1,47 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+public class AnnotationNameValuePair {
+
+ private String name;
+
+ private AnnotationValue val;
+
+ public AnnotationNameValuePair(String name, AnnotationValue val) {
+ this.name = name;
+ this.val = val;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public AnnotationValue getValue() {
+ return val;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(name + "=" + val.toString());
+ return sb.toString();
+ }
+
+ public String stringify() {
+ StringBuffer sb = new StringBuffer();
+ if (!name.equals("value")) {
+ sb.append(name + "=");
+ }
+ sb.append(val.stringify());
+ return sb.toString();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationOnTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationOnTypeMunger.java
new file mode 100644
index 000000000..6390ed311
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationOnTypeMunger.java
@@ -0,0 +1,56 @@
+/* *******************************************************************
+ * Copyright (c) 2005 IBM
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+/**
+ * Represents adding an annotation to a type
+ */
+public class AnnotationOnTypeMunger extends ResolvedTypeMunger {
+ AnnotationAJ newAnnotation;
+
+ public AnnotationOnTypeMunger(AnnotationAJ anno) {
+ super(AnnotationOnType, null);
+ newAnnotation = anno;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public AnnotationAJ getNewAnnotation() {
+ return newAnnotation;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof AnnotationOnTypeMunger)) {
+ return false;
+ }
+ AnnotationOnTypeMunger o = (AnnotationOnTypeMunger) other;
+ // TODO does not check equality of annotation values
+ return newAnnotation.getTypeSignature().equals(o.newAnnotation.getTypeSignature());
+ }
+
+ private volatile int hashCode = 0;
+
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + newAnnotation.getTypeSignature().hashCode();
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationTargetKind.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationTargetKind.java
new file mode 100644
index 000000000..fe2104484
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationTargetKind.java
@@ -0,0 +1,59 @@
+/********************************************************************
+ * Copyright (c) 2005 Contributors. All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Helen Hawkins - Initial implementation
+ *******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.aspectj.util.TypeSafeEnum;
+
+/**
+ * A TypeSafeEnum similar to the Java5 ElementType Enum
+ */
+public class AnnotationTargetKind extends TypeSafeEnum {
+
+ public AnnotationTargetKind(String name, int key) {
+ super(name, key);
+ }
+
+ public static AnnotationTargetKind read(DataInputStream s) throws IOException {
+ int key = s.readByte();
+ switch (key) {
+ case 1:
+ return ANNOTATION_TYPE;
+ case 2:
+ return CONSTRUCTOR;
+ case 3:
+ return FIELD;
+ case 4:
+ return LOCAL_VARIABLE;
+ case 5:
+ return METHOD;
+ case 6:
+ return PACKAGE;
+ case 7:
+ return PARAMETER;
+ case 8:
+ return TYPE;
+ }
+ throw new BCException("weird annotation target kind " + key);
+ }
+
+ public static final AnnotationTargetKind ANNOTATION_TYPE = new AnnotationTargetKind("ANNOTATION_TYPE", 1);
+ public static final AnnotationTargetKind CONSTRUCTOR = new AnnotationTargetKind("CONSTRUCTOR", 2);
+ public static final AnnotationTargetKind FIELD = new AnnotationTargetKind("FIELD", 3);
+ public static final AnnotationTargetKind LOCAL_VARIABLE = new AnnotationTargetKind("LOCAL_VARIABLE", 4);
+ public static final AnnotationTargetKind METHOD = new AnnotationTargetKind("METHOD", 5);
+ public static final AnnotationTargetKind PACKAGE = new AnnotationTargetKind("PACKAGE", 6);
+ public static final AnnotationTargetKind PARAMETER = new AnnotationTargetKind("PARAMETER", 7);
+ public static final AnnotationTargetKind TYPE = new AnnotationTargetKind("TYPE", 8);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationValue.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationValue.java
new file mode 100644
index 000000000..32f366774
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/AnnotationValue.java
@@ -0,0 +1,71 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+public abstract class AnnotationValue {
+
+ protected int valueKind;
+
+ public static final int STRING = 's';
+ public static final int ENUM_CONSTANT = 'e';
+ public static final int CLASS = 'c';
+ public static final int ANNOTATION = '@';
+ public static final int ARRAY = '[';
+
+ public static final int PRIMITIVE_INT = 'I';
+ public static final int PRIMITIVE_BYTE = 'B';
+ public static final int PRIMITIVE_CHAR = 'C';
+ public static final int PRIMITIVE_DOUBLE = 'D';
+ public static final int PRIMITIVE_FLOAT = 'F';
+ public static final int PRIMITIVE_LONG = 'J';
+ public static final int PRIMITIVE_SHORT = 'S';
+ public static final int PRIMITIVE_BOOLEAN = 'Z';
+
+ public abstract String stringify();
+
+ public AnnotationValue(int kind) {
+ valueKind = kind;
+ }
+
+ public static String whatKindIsThis(int kind) {
+ switch (kind) {
+ case PRIMITIVE_BYTE: // byte
+ return "byte";
+ case PRIMITIVE_CHAR: // char
+ return "char";
+ case PRIMITIVE_DOUBLE: // double
+ return "double";
+ case PRIMITIVE_FLOAT: // float
+ return "float";
+ case PRIMITIVE_INT: // int
+ return "int";
+ case PRIMITIVE_LONG: // long
+ return "long";
+ case PRIMITIVE_SHORT: // short
+ return "short";
+ case PRIMITIVE_BOOLEAN: // boolean
+ return "boolean";
+ case 's': // String
+ return "string";
+ case 'e': // Enum constant
+ return "enum";
+ case 'c': // Class
+ return "class";
+ case '@': // Annotation
+ return "annotation";
+ case '[': // Array
+ return "array";
+ default:
+ throw new RuntimeException("Dont know what this is : " + kind);
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayAnnotationValue.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayAnnotationValue.java
new file mode 100644
index 000000000..f4ef760bb
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayAnnotationValue.java
@@ -0,0 +1,59 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+public class ArrayAnnotationValue extends AnnotationValue {
+
+ private AnnotationValue[] values;
+
+ public ArrayAnnotationValue() {
+ super(AnnotationValue.ARRAY);
+ }
+
+ public void setValues(AnnotationValue[] values) {
+ this.values = values;
+ }
+
+ public ArrayAnnotationValue(AnnotationValue[] values) {
+ super(AnnotationValue.ARRAY);
+ this.values = values;
+ }
+
+ public AnnotationValue[] getValues() {
+ return values;
+ }
+
+ public String stringify() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("[");
+ for (int i = 0; i < values.length; i++) {
+ sb.append(values[i].stringify());
+ if (i + 1 < values.length)
+ sb.append(",");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("{");
+ for (int i = 0; i < values.length; i++) {
+ sb.append(values[i].toString());
+ if ((i + 1) < values.length)
+ sb.append(",");
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayReferenceType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayReferenceType.java
new file mode 100644
index 000000000..aa4fa55c0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ArrayReferenceType.java
@@ -0,0 +1,211 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Represents a resolved array type
+ *
+ * @author Andy Clement
+ */
+public class ArrayReferenceType extends ReferenceType {
+
+ private final ResolvedType componentType;
+
+ public ArrayReferenceType(String sig, String erasureSig, World world, ResolvedType componentType) {
+ super(sig, erasureSig, world);
+ this.componentType = componentType;
+ }
+
+ // These methods are from the original implementation when Array was a ResolvedType and not a ReferenceType
+
+ public final ResolvedMember[] getDeclaredFields() {
+ return ResolvedMember.NONE;
+ }
+
+ public final ResolvedMember[] getDeclaredMethods() {
+ // ??? should this return clone? Probably not...
+ // If it ever does, here is the code:
+ // ResolvedMember cloneMethod =
+ // new ResolvedMember(Member.METHOD,this,Modifier.PUBLIC,UnresolvedType.OBJECT,"clone",new UnresolvedType[]{});
+ // return new ResolvedMember[]{cloneMethod};
+ return ResolvedMember.NONE;
+ }
+
+ public final ResolvedType[] getDeclaredInterfaces() {
+ return new ResolvedType[] { world.getCoreType(CLONEABLE), world.getCoreType(SERIALIZABLE) };
+ }
+
+ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
+ return null;
+ }
+
+ public AnnotationAJ[] getAnnotations() {
+ return AnnotationAJ.EMPTY_ARRAY;
+ }
+
+ public ResolvedType[] getAnnotationTypes() {
+ return ResolvedType.NONE;
+ }
+
+ public final ResolvedMember[] getDeclaredPointcuts() {
+ return ResolvedMember.NONE;
+ }
+
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ return false;
+ }
+
+ public final ResolvedType getSuperclass() {
+ return world.getCoreType(OBJECT);
+ }
+
+ public final boolean isAssignableFrom(ResolvedType o) {
+ if (!o.isArray())
+ return false;
+ if (o.getComponentType().isPrimitiveType()) {
+ return o.equals(this);
+ } else {
+ return getComponentType().resolve(world).isAssignableFrom(o.getComponentType().resolve(world));
+ }
+ }
+
+ public boolean isAssignableFrom(ResolvedType o, boolean allowMissing) {
+ return isAssignableFrom(o);
+ }
+
+ public final boolean isCoerceableFrom(ResolvedType o) {
+ if (o.equals(UnresolvedType.OBJECT) || o.equals(UnresolvedType.SERIALIZABLE) || o.equals(UnresolvedType.CLONEABLE)) {
+ return true;
+ }
+ if (!o.isArray())
+ return false;
+ if (o.getComponentType().isPrimitiveType()) {
+ return o.equals(this);
+ } else {
+ return getComponentType().resolve(world).isCoerceableFrom(o.getComponentType().resolve(world));
+ }
+ }
+
+ public final int getModifiers() {
+ int mask = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
+ return (componentType.getModifiers() & mask) | Modifier.FINAL;
+ }
+
+ public UnresolvedType getComponentType() {
+ return componentType;
+ }
+
+ public ResolvedType getResolvedComponentType() {
+ return componentType;
+ }
+
+ public ISourceContext getSourceContext() {
+ return getResolvedComponentType().getSourceContext();
+ }
+
+ // Methods overridden from ReferenceType follow
+
+ public TypeVariable[] getTypeVariables() {
+ if (this.typeVariables == null && componentType.getTypeVariables() != null) {
+ this.typeVariables = componentType.getTypeVariables();
+ for (int i = 0; i < this.typeVariables.length; i++) {
+ this.typeVariables[i].resolve(world);
+ }
+ }
+ return this.typeVariables;
+ }
+
+ public boolean isAnnotation() {
+ return false;
+ }
+
+ public boolean isAnonymous() {
+ return false;
+ }
+
+ public boolean isAnnotationStyleAspect() {
+ return false;
+ }
+
+ public boolean isAspect() {
+ return false;
+ }
+
+ public boolean isPrimitiveType() {
+ return typeKind == TypeKind.PRIMITIVE;
+ }
+
+ public boolean isSimpleType() {
+ return typeKind == TypeKind.SIMPLE;
+ }
+
+ public boolean isRawType() {
+ return typeKind == TypeKind.RAW;
+ }
+
+ public boolean isGenericType() {
+ return typeKind == TypeKind.GENERIC;
+ }
+
+ public boolean isParameterizedType() {
+ return typeKind == TypeKind.PARAMETERIZED;
+ }
+
+ public boolean isTypeVariableReference() {
+ return typeKind == TypeKind.TYPE_VARIABLE;
+ }
+
+ public boolean isGenericWildcard() {
+ return typeKind == TypeKind.WILDCARD;
+ }
+
+ public boolean isEnum() {
+ return false;
+ }
+
+ public boolean isNested() {
+ return false;
+ }
+
+ public boolean isClass() {
+ return false;
+ }
+
+ @Override
+ public boolean isExposedToWeaver() {
+ return false;
+ }
+
+ public boolean canAnnotationTargetType() {
+ return false;
+ }
+
+ public AnnotationTargetKind[] getAnnotationTargetKinds() {
+ return null;
+ }
+
+ public boolean isAnnotationWithRuntimeRetention() {
+ return false;
+ }
+
+ public boolean isPrimitiveArray() {
+ if (componentType.isPrimitiveType()) {
+ return true;
+ } else if (componentType.isArray()) {
+ return componentType.isPrimitiveArray();
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BCException.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BCException.java
new file mode 100644
index 000000000..81bf607ed
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BCException.java
@@ -0,0 +1,63 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import org.aspectj.bridge.context.CompilationAndWeavingContext;
+
+/**
+ * Exception to use inside the bcweaver.
+ */
+@SuppressWarnings("serial")
+public class BCException extends RuntimeException {
+ Throwable thrown;
+
+ public BCException() {
+ super();
+ }
+
+ public BCException(String s) {
+ super(s + "\n" + CompilationAndWeavingContext.getCurrentContext());
+ }
+
+ public BCException(String s, Throwable thrown) {
+ this(s);
+ this.thrown = thrown;
+ }
+
+ public void printStackTrace() {
+ printStackTrace(System.err);
+ }
+
+ public void printStackTrace(PrintStream s) {
+ printStackTrace(new PrintWriter(s));
+ }
+
+ public void printStackTrace(PrintWriter s) {
+ super.printStackTrace(s);
+ if (null != thrown) {
+ s.print("Caused by: ");
+ s.print(thrown.getClass().getName());
+ String message = thrown.getMessage();
+ if (null != message) {
+ s.print(": ");
+ s.print(message);
+ }
+ s.println();
+ thrown.printStackTrace(s);
+ }
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BindingScope.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BindingScope.java
new file mode 100644
index 000000000..d97fb8fb6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BindingScope.java
@@ -0,0 +1,68 @@
+/* *******************************************************************
+ * Copyright (c) 2006-2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.patterns.FormalBinding;
+import org.aspectj.weaver.patterns.SimpleScope;
+
+/**
+ * BindingScope that knows the enclosingType, which is needed for pointcut reference resolution
+ *
+ * @author Alexandre Vasseur
+ * @author Andy Clement
+ */
+public class BindingScope extends SimpleScope {
+ private final ResolvedType enclosingType;
+ private final ISourceContext sourceContext;
+ private boolean importsUpdated = false;
+
+ public BindingScope(ResolvedType type, ISourceContext sourceContext, FormalBinding[] bindings) {
+ super(type.getWorld(), bindings);
+ this.enclosingType = type;
+ this.sourceContext = sourceContext;
+ }
+
+ public ResolvedType getEnclosingType() {
+ return enclosingType;
+ }
+
+ public ISourceLocation makeSourceLocation(IHasPosition location) {
+ return sourceContext.makeSourceLocation(location);
+ }
+
+ public UnresolvedType lookupType(String name, IHasPosition location) {
+ // bug 126560
+ if (enclosingType != null && !importsUpdated) {
+ // add the package we're in to the list of imported
+ // prefixes so that we can find types in the same package
+ String pkgName = enclosingType.getPackageName();
+ if (pkgName != null && !pkgName.equals("")) {
+ String[] existingImports = getImportedPrefixes();
+ String pkgNameWithDot = pkgName.concat(".");
+ boolean found = false;
+ for (String existingImport : existingImports) {
+ if (existingImport.equals(pkgNameWithDot)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ String[] newImports = new String[existingImports.length + 1];
+ System.arraycopy(existingImports, 0, newImports, 0, existingImports.length);
+ newImports[existingImports.length] = pkgNameWithDot;
+ setImportedPrefixes(newImports);
+ }
+ }
+ importsUpdated = true;
+ }
+ return super.lookupType(name, location);
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceType.java
new file mode 100644
index 000000000..62bd4d23a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceType.java
@@ -0,0 +1,236 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Map;
+
+/**
+ * A BoundedReferenceType is the result of a generics wildcard expression ? extends String, ? super Foo etc..
+ *
+ * The "signature" for a bounded reference type follows the generic signature specification in section 4.4 of JVM spec: *,+,- plus
+ * signature strings.
+ *
+ * The bound may be a type variable (e.g. ? super T)
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class BoundedReferenceType extends ReferenceType {
+
+ // possible kinds of BoundedReferenceType
+ public static final int UNBOUND = 0;
+ public static final int EXTENDS = 1;
+ public static final int SUPER = 2;
+
+ public int kind;
+
+ private ResolvedType lowerBound;
+
+ private ResolvedType upperBound;
+
+ protected ReferenceType[] additionalInterfaceBounds = ReferenceType.EMPTY_ARRAY;
+
+ public BoundedReferenceType(ReferenceType aBound, boolean isExtends, World world) {
+ super((isExtends ? "+" : "-") + aBound.signature, aBound.signatureErasure, world);
+ if (isExtends) {
+ this.kind = EXTENDS;
+ } else {
+ this.kind = SUPER;
+ }
+ if (isExtends) {
+ upperBound = aBound;
+ } else {
+ lowerBound = aBound;
+ upperBound = world.resolve(UnresolvedType.OBJECT);
+ }
+ setDelegate(new BoundedReferenceTypeDelegate((ReferenceType) getUpperBound()));
+ }
+
+ public BoundedReferenceType(ReferenceType aBound, boolean isExtends, World world, ReferenceType[] additionalInterfaces) {
+ this(aBound, isExtends, world);
+ this.additionalInterfaceBounds = additionalInterfaces;
+ }
+
+ /**
+ * only for use when resolving GenericsWildcardTypeX or a TypeVariableReferenceType
+ */
+ protected BoundedReferenceType(String signature, String erasedSignature, World world) {
+ super(signature, erasedSignature, world);
+ if (signature.equals("*")) {
+ // pure wildcard
+ this.kind = UNBOUND;
+ upperBound = world.resolve(UnresolvedType.OBJECT);
+ } else {
+ upperBound = world.resolve(forSignature(erasedSignature));
+ }
+ setDelegate(new BoundedReferenceTypeDelegate((ReferenceType) upperBound));
+ }
+
+ /**
+ * Constructs the BoundedReferenceType representing an unbounded wildcard '?'. In this situation the signature is '*' and the
+ * erased signature is Ljava/lang/Object;
+ */
+ public BoundedReferenceType(World world) {
+ super("*", "Ljava/lang/Object;", world);
+ this.kind = UNBOUND;
+ upperBound = world.resolve(UnresolvedType.OBJECT);
+ setDelegate(new BoundedReferenceTypeDelegate((ReferenceType) upperBound));
+ }
+
+ public UnresolvedType getUpperBound() {
+ return upperBound;
+ }
+
+ public UnresolvedType getLowerBound() {
+ return lowerBound;
+ }
+
+ public ReferenceType[] getAdditionalBounds() {
+ return additionalInterfaceBounds;
+ }
+
+ @Override
+ public UnresolvedType parameterize(Map<String, UnresolvedType> typeBindings) {
+ if (this.kind == UNBOUND) {
+ return this;
+ }
+ ReferenceType[] parameterizedAdditionalInterfaces = new ReferenceType[additionalInterfaceBounds == null ? 0
+ : additionalInterfaceBounds.length];
+ for (int i = 0; i < parameterizedAdditionalInterfaces.length; i++) {
+ parameterizedAdditionalInterfaces[i] = (ReferenceType) additionalInterfaceBounds[i].parameterize(typeBindings);
+ }
+ if (this.kind == EXTENDS) {
+ return new BoundedReferenceType((ReferenceType) getUpperBound().parameterize(typeBindings), true, world,
+ parameterizedAdditionalInterfaces);
+ } else {
+ // (this.kind == SUPER)
+ UnresolvedType parameterizedLowerBound = getLowerBound().parameterize(typeBindings);
+ if (!(parameterizedLowerBound instanceof ReferenceType)) {
+ throw new IllegalStateException("PR543023: Unexpectedly found a non reference type: "+
+ parameterizedLowerBound.getClass().getName()+" with signature "+parameterizedLowerBound.getSignature());
+ }
+ return new BoundedReferenceType((ReferenceType)parameterizedLowerBound , false, world,
+ parameterizedAdditionalInterfaces);
+ }
+ }
+
+ @Override
+ public String getSignatureForAttribute() {
+ StringBuilder ret = new StringBuilder();
+ if (kind==SUPER){
+ ret.append("-");
+ ret.append(lowerBound.getSignatureForAttribute());
+ for (int i=0;i<additionalInterfaceBounds.length;i++) {
+ ret.append(additionalInterfaceBounds[i].getSignatureForAttribute());
+ }
+ } else if (kind==EXTENDS) {
+ ret.append("+");
+ ret.append(upperBound.getSignatureForAttribute());
+ for (int i=0;i<additionalInterfaceBounds.length;i++) {
+ ret.append(additionalInterfaceBounds[i].getSignatureForAttribute());
+ }
+ } else if (kind==UNBOUND) {
+ ret.append("*");
+ }
+ return ret.toString();
+ }
+
+
+ public boolean hasLowerBound() {
+ return lowerBound != null;
+ }
+
+ public boolean isExtends() {
+ return this.kind == EXTENDS;
+ }
+
+ public boolean isSuper() {
+ return this.kind == SUPER;
+ }
+
+ public boolean isUnbound() {
+ return this.kind == UNBOUND;
+ }
+
+ public boolean alwaysMatches(ResolvedType aCandidateType) {
+ if (isExtends()) {
+ // aCandidateType must be a subtype of upperBound
+ return ((ReferenceType) getUpperBound()).isAssignableFrom(aCandidateType);
+ } else if (isSuper()) {
+ // aCandidateType must be a supertype of lowerBound
+ return aCandidateType.isAssignableFrom((ReferenceType) getLowerBound());
+ } else {
+ return true; // straight '?'
+ }
+ }
+
+ // this "maybe matches" that
+ public boolean canBeCoercedTo(ResolvedType aCandidateType) {
+ if (alwaysMatches(aCandidateType)) {
+ return true;
+ }
+ if (aCandidateType.isGenericWildcard()) {
+ BoundedReferenceType boundedRT = (BoundedReferenceType) aCandidateType;
+ ResolvedType myUpperBound = (ResolvedType) getUpperBound();
+ ResolvedType myLowerBound = (ResolvedType) getLowerBound();
+ if (isExtends()) {
+ if (boundedRT.isExtends()) {
+ return myUpperBound.isAssignableFrom((ResolvedType) boundedRT.getUpperBound());
+ } else if (boundedRT.isSuper()) {
+ return myUpperBound == boundedRT.getLowerBound();
+ } else {
+ return true; // it's '?'
+ }
+ } else if (isSuper()) {
+ if (boundedRT.isSuper()) {
+ return ((ResolvedType) boundedRT.getLowerBound()).isAssignableFrom(myLowerBound);
+ } else if (boundedRT.isExtends()) {
+ return myLowerBound == boundedRT.getUpperBound();
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String getSimpleName() {
+ if (!isExtends() && !isSuper()) {
+ return "?";
+ }
+ if (isExtends()) {
+ return ("? extends " + getUpperBound().getSimpleName());
+ } else {
+ return ("? super " + getLowerBound().getSimpleName());
+ }
+ }
+
+ // override to include additional interface bounds...
+ @Override
+ public ResolvedType[] getDeclaredInterfaces() {
+ ResolvedType[] interfaces = super.getDeclaredInterfaces();
+ if (additionalInterfaceBounds.length > 0) {
+ ResolvedType[] allInterfaces = new ResolvedType[interfaces.length + additionalInterfaceBounds.length];
+ System.arraycopy(interfaces, 0, allInterfaces, 0, interfaces.length);
+ System.arraycopy(additionalInterfaceBounds, 0, allInterfaces, interfaces.length, additionalInterfaceBounds.length);
+ return allInterfaces;
+ } else {
+ return interfaces;
+ }
+ }
+
+ @Override
+ public boolean isGenericWildcard() {
+ return true;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceTypeDelegate.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceTypeDelegate.java
new file mode 100644
index 000000000..f928b729b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/BoundedReferenceTypeDelegate.java
@@ -0,0 +1,138 @@
+/**
+ *
+ */
+package org.aspectj.weaver;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.PerClause;
+
+class BoundedReferenceTypeDelegate extends AbstractReferenceTypeDelegate {
+
+ public BoundedReferenceTypeDelegate(ReferenceType backing) {
+ super(backing, false);
+ }
+
+ public boolean isAspect() {
+ return resolvedTypeX.isAspect();
+ }
+
+ public boolean isAnnotationStyleAspect() {
+ return resolvedTypeX.isAnnotationStyleAspect();
+ }
+
+ public boolean isInterface() {
+ return resolvedTypeX.isInterface();
+ }
+
+ public boolean isEnum() {
+ return resolvedTypeX.isEnum();
+ }
+
+ public boolean isAnnotation() {
+ return resolvedTypeX.isAnnotation();
+ }
+
+ public boolean isAnnotationWithRuntimeRetention() {
+ return resolvedTypeX.isAnnotationWithRuntimeRetention();
+ }
+
+ public boolean isAnonymous() {
+ return resolvedTypeX.isAnonymous();
+ }
+
+ public boolean isNested() {
+ return resolvedTypeX.isNested();
+ }
+
+ public ResolvedType getOuterClass() {
+ return resolvedTypeX.getOuterClass();
+ }
+
+ public String getRetentionPolicy() {
+ return resolvedTypeX.getRetentionPolicy();
+ }
+
+ public boolean canAnnotationTargetType() {
+ return resolvedTypeX.canAnnotationTargetType();
+ }
+
+ public AnnotationTargetKind[] getAnnotationTargetKinds() {
+ return resolvedTypeX.getAnnotationTargetKinds();
+ }
+
+ public boolean isGeneric() {
+ return resolvedTypeX.isGenericType();
+ }
+
+ public String getDeclaredGenericSignature() {
+ return resolvedTypeX.getDeclaredGenericSignature();
+ }
+
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ return resolvedTypeX.hasAnnotation(ofType);
+ }
+
+ public AnnotationAJ[] getAnnotations() {
+ return resolvedTypeX.getAnnotations();
+ }
+
+ public boolean hasAnnotations() {
+ return resolvedTypeX.hasAnnotations();
+ }
+
+ public ResolvedType[] getAnnotationTypes() {
+ return resolvedTypeX.getAnnotationTypes();
+ }
+
+ public ResolvedMember[] getDeclaredFields() {
+ return resolvedTypeX.getDeclaredFields();
+ }
+
+ public ResolvedType[] getDeclaredInterfaces() {
+ return resolvedTypeX.getDeclaredInterfaces();
+ }
+
+ public ResolvedMember[] getDeclaredMethods() {
+ return resolvedTypeX.getDeclaredMethods();
+ }
+
+ public ResolvedMember[] getDeclaredPointcuts() {
+ return resolvedTypeX.getDeclaredPointcuts();
+ }
+
+ public PerClause getPerClause() {
+ return resolvedTypeX.getPerClause();
+ }
+
+ public Collection<Declare> getDeclares() {
+ return resolvedTypeX.getDeclares();
+ }
+
+ public Collection<ConcreteTypeMunger> getTypeMungers() {
+ return resolvedTypeX.getTypeMungers();
+ }
+
+ public Collection<ResolvedMember> getPrivilegedAccesses() {
+ return Collections.emptyList();
+ }
+
+ public int getModifiers() {
+ return resolvedTypeX.getModifiers();
+ }
+
+ public ResolvedType getSuperclass() {
+ return resolvedTypeX.getSuperclass();
+ }
+
+ public WeaverStateInfo getWeaverState() {
+ return null;
+ }
+
+ public TypeVariable[] getTypeVariables() {
+ return resolvedTypeX.getTypeVariables();
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Checker.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Checker.java
new file mode 100644
index 000000000..4a765a9e5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Checker.java
@@ -0,0 +1,281 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
+import org.aspectj.weaver.patterns.PerClause;
+import org.aspectj.weaver.patterns.Pointcut;
+
+/**
+ * Representation of a shadow munger for a declare error or warning declaration.
+ *
+ * @author Andy Clement
+ */
+public class Checker extends ShadowMunger {
+
+ private boolean isError; // if not error then it is a warning
+ private String message;
+ private volatile int hashCode = -1;
+
+ @SuppressWarnings("unused")
+ private Checker() {
+ }
+
+ /**
+ * Create a Checker for a declare error or declare warning.
+ *
+ * @param deow the declare error or declare warning for which to create the checker munger
+ */
+ public Checker(DeclareErrorOrWarning deow) {
+ super(deow.getPointcut(), deow.getStart(), deow.getEnd(), deow.getSourceContext(), ShadowMungerDeow);
+ this.message = deow.getMessage();
+ this.isError = deow.isError();
+ }
+
+ /**
+ * Only used when filling in a parameterized Checker
+ */
+ private Checker(Pointcut pointcut, int start, int end, ISourceContext context, String message, boolean isError) {
+ super(pointcut, start, end, context, ShadowMungerDeow);
+ this.message = message;
+ this.isError = isError;
+ }
+
+ public boolean isError() {
+ return isError;
+ }
+
+ public String getMessage(Shadow shadow) {
+ return format(this.message, shadow);
+ }
+
+ @Override
+ public void specializeOn(Shadow shadow) {
+ throw new IllegalStateException("Cannot call specializeOn(...) for a Checker");
+ }
+
+ @Override
+ public boolean implementOn(Shadow shadow) {
+ throw new IllegalStateException("Cannot call implementOn(...) for a Checker");
+ }
+
+ /**
+ * Determine if the Checker matches at a shadow. If it does then we can immediately report the message. Currently, there can
+ * never be a non-statically determinable match.
+ *
+ * @param shadow the shadow which to match against
+ * @param world the world through which to access message handlers
+ */
+ @Override
+ public boolean match(Shadow shadow, World world) {
+ if (super.match(shadow, world)) {
+ world.reportCheckerMatch(this, shadow);
+ }
+ return false;
+ }
+
+ // implementation for PartialOrder.PartialComparable
+ public int compareTo(Object other) {
+ return 0;
+ }
+
+ @Override
+ public boolean mustCheckExceptions() {
+ return true;
+ }
+
+ @Override
+ public Collection<ResolvedType> getThrownExceptions() {
+ return Collections.emptyList();
+ }
+
+ // FIXME this perhaps ought to take account of the other fields in advice (use super.equals?)
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Checker)) {
+ return false;
+ }
+ Checker o = (Checker) other;
+ return o.isError == isError && ((o.pointcut == null) ? (pointcut == null) : o.pointcut.equals(pointcut));
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode == -1) {
+ int result = 17;
+ result = 37 * result + (isError ? 1 : 0);
+ result = 37 * result + ((pointcut == null) ? 0 : pointcut.hashCode());
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ /**
+ * Parameterize the Checker by parameterizing the pointcut
+ */
+ @Override
+ public ShadowMunger parameterizeWith(ResolvedType declaringType, Map<String, UnresolvedType> typeVariableMap) {
+ Checker ret = new Checker(this.pointcut.parameterizeWith(typeVariableMap, declaringType.getWorld()), this.start, this.end,
+ this.sourceContext, this.message, this.isError);
+ return ret;
+ }
+
+ /**
+ * Concretize this Checker by concretizing the pointcut
+ */
+ @Override
+ public ShadowMunger concretize(ResolvedType theAspect, World world, PerClause clause) {
+ this.pointcut = this.pointcut.concretize(theAspect, getDeclaringType(), 0, this);
+ this.hashCode = -1;
+ return this;
+ }
+
+ @Override
+ public ResolvedType getConcreteAspect() {
+ return getDeclaringType();
+ }
+
+ // public void write(DataOutputStream stream) throws IOException {
+ // super.write(stream);
+ // stream.writeBoolean(isError);
+ // stream.writeUTF(message);
+ // }
+ //
+ // public static Checker read(DataInputStream stream, World world) throws IOException {
+ // Checker checker = new Checker();
+ // checker.isError = stream.readBoolean();
+ // checker.message = stream.readUTF();
+ // return checker;
+ // }
+
+ // Return the next non-escaped (with a '\') open curly
+ private int nextCurly(String string, int pos) {
+ do {
+ int curlyIndex = string.indexOf('{', pos);
+ if (curlyIndex == -1) {
+ return -1;
+ }
+ if (curlyIndex == 0) {
+ return 0;
+ }
+ if (string.charAt(curlyIndex - 1) != '\\') {
+ return curlyIndex;
+ }
+ pos = curlyIndex + 1;
+ } while (pos < string.length());
+ return -1;
+ }
+
+ private String format(String msg, Shadow shadow) {
+ int pos = 0;
+ int curlyIndex = nextCurly(msg, 0);
+ if (curlyIndex == -1) {
+ // was there an escaped one?
+ if (msg.indexOf('{') != -1) {
+ return msg.replace("\\{", "{");
+ } else {
+ return msg;
+ }
+ }
+ StringBuffer ret = new StringBuffer();
+ while (curlyIndex >= 0) {
+ if (curlyIndex > 0) {
+ ret.append(msg.substring(pos, curlyIndex).replace("\\{", "{"));
+ }
+ int endCurly = msg.indexOf('}', curlyIndex);
+ if (endCurly == -1) {
+ // wasn't closed properly - ignore it
+ ret.append('{');
+ pos = curlyIndex + 1;
+ } else {
+ ret.append(getValue(msg.substring(curlyIndex + 1, endCurly), shadow));
+ }
+ pos = endCurly + 1;
+ curlyIndex = nextCurly(msg, pos);
+ }
+ ret.append(msg.substring(pos, msg.length()));
+ return ret.toString();
+ }
+
+ /**
+ * @param buf the buffer in which to insert the substitution
+ * @param shadow shadow from which to draw context info
+ * @param c the substitution character
+ */
+ private String getValue(String key, Shadow shadow) {
+ if (key.equalsIgnoreCase("joinpoint")) {
+ return shadow.toString();
+ } else if (key.equalsIgnoreCase("joinpoint.kind")) {
+ return shadow.getKind().getName();
+ } else if (key.equalsIgnoreCase("joinpoint.enclosingclass")) {
+ return shadow.getEnclosingType().getName();
+ } else if (key.equalsIgnoreCase("joinpoint.enclosingmember.name")) {
+ Member member = shadow.getEnclosingCodeSignature();
+ if (member==null) {
+ return "";
+ } else {
+ return member.getName();
+ }
+ } else if (key.equalsIgnoreCase("joinpoint.enclosingmember")) {
+ Member member = shadow.getEnclosingCodeSignature();
+ if (member==null) {
+ return "";
+ } else {
+ return member.toString();
+ }
+ } else if (key.equalsIgnoreCase("joinpoint.signature")) {
+ return shadow.getSignature().toString();
+ } else if (key.equalsIgnoreCase("joinpoint.signature.declaringtype")) {
+ return shadow.getSignature().getDeclaringType().toString();
+ } else if (key.equalsIgnoreCase("joinpoint.signature.name")) {
+ return shadow.getSignature().getName();
+ } else if (key.equalsIgnoreCase("joinpoint.sourcelocation.sourcefile")) {
+ ISourceLocation loc = shadow.getSourceLocation();
+ if ((loc != null) && (loc.getSourceFile() != null)) {
+ return loc.getSourceFile().toString();
+ } else {
+ return "UNKNOWN";
+ }
+ } else if (key.equalsIgnoreCase("joinpoint.sourcelocation.line")) {
+ ISourceLocation loc = shadow.getSourceLocation();
+ if (loc != null) {
+ return Integer.toString(loc.getLine());
+ } else {
+ return "-1";
+ }
+ } else if (key.equalsIgnoreCase("advice.aspecttype")) {
+ return getDeclaringType().getName();
+ } else if (key.equalsIgnoreCase("advice.sourcelocation.line")) {
+ ISourceLocation loc = getSourceLocation();
+ if ((loc != null) && (loc.getSourceFile() != null)) {
+ return Integer.toString(loc.getLine());
+ } else {
+ return "-1";
+ }
+ } else if (key.equalsIgnoreCase("advice.sourcelocation.sourcefile")) {
+ ISourceLocation loc = getSourceLocation();
+ if ((loc != null) && (loc.getSourceFile() != null)) {
+ return loc.getSourceFile().toString();
+ } else {
+ return "UNKNOWN";
+ }
+ } else {
+ return "UNKNOWN_KEY{" + key + "}";
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ClassAnnotationValue.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ClassAnnotationValue.java
new file mode 100644
index 000000000..cb7476c32
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ClassAnnotationValue.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+public class ClassAnnotationValue extends AnnotationValue {
+
+ private String signature;
+
+ public ClassAnnotationValue(String sig) {
+ super(AnnotationValue.CLASS);
+ this.signature = sig;
+ }
+
+ public String stringify() {
+ return signature;
+ }
+
+ public String toString() {
+ return signature;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CompressingDataOutputStream.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CompressingDataOutputStream.java
new file mode 100644
index 000000000..43a66ff4f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CompressingDataOutputStream.java
@@ -0,0 +1,98 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement (SpringSource)
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * A variation of a DataOutputStream that is linked to a constant pool writer. The linked constant pool can be used to compress
+ * objects into to simple index references into the constant pool. The corresponding decompression is done in the
+ * VersionedDataInputStream.
+ *
+ * @author Andy Clement
+ */
+public class CompressingDataOutputStream extends DataOutputStream {
+
+ private ConstantPoolWriter constantPoolWriter;
+ public boolean compressionEnabled = true;
+
+ public CompressingDataOutputStream(ByteArrayOutputStream baos, ConstantPoolWriter constantPoolWriter) {
+ super(baos);
+ this.constantPoolWriter = constantPoolWriter;
+ }
+
+ public CompressingDataOutputStream(FileOutputStream fos) {
+ super(fos);
+ }
+
+ public boolean canCompress() {
+ return constantPoolWriter != null && compressionEnabled;
+ }
+
+ /**
+ * @param signature of the form 'La/b/c/d;'
+ * @return the constant pool index
+ */
+ public int compressSignature(String signature) {
+ if (constantPoolWriter == null) {
+ throw new IllegalStateException();
+ }
+ return constantPoolWriter.writeUtf8(signature);
+ }
+
+ /**
+ * @param filepath a file system path 'c:\a\b\c.txt' or '/a/b/c.txt'
+ * @return the constant pool index
+ */
+ public int compressFilepath(String filepath) {
+ if (constantPoolWriter == null) {
+ throw new IllegalStateException();
+ }
+ return constantPoolWriter.writeUtf8(filepath);
+ }
+
+ /**
+ * @param name a simple name (for example a method or field name)
+ * @return the constant pool index
+ */
+ public int compressName(String name) {
+ if (constantPoolWriter == null) {
+ throw new IllegalStateException();
+ }
+ return constantPoolWriter.writeUtf8(name);
+ }
+
+ /**
+ * @param name a simple name (for example a method or field name)
+ */
+ public void writeCompressedName(String name) throws IOException {
+ writeShort(compressName(name));
+ }
+
+ /**
+ * @param signature of the form 'La/b/c/d;'
+ */
+ public void writeCompressedSignature(String signature) throws IOException {
+ writeShort(compressSignature(signature));
+ }
+
+ /**
+ * @param path a file system path 'c:\a\b\c.txt' or '/a/b/c.txt'
+ */
+ public void writeCompressedPath(String path) throws IOException {
+ writeShort(compressFilepath(path));
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConcreteTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConcreteTypeMunger.java
new file mode 100644
index 000000000..81cf351a9
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConcreteTypeMunger.java
@@ -0,0 +1,164 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.util.PartialOrder;
+
+public abstract class ConcreteTypeMunger implements PartialOrder.PartialComparable {
+ protected ResolvedTypeMunger munger;
+ protected ResolvedType aspectType;
+
+ public ConcreteTypeMunger(ResolvedTypeMunger munger, ResolvedType aspectType) {
+ this.munger = munger;
+ this.aspectType = aspectType;
+ }
+
+ /**
+ * Equivalence can be true for an EclipseTypeMunger and a BcelTypeMunger that represent the same transformation (just at
+ * different points in the pipeline).
+ */
+ public boolean equivalentTo(Object other) {
+ if (!(other instanceof ConcreteTypeMunger)) {
+ return false;
+ }
+ ConcreteTypeMunger o = (ConcreteTypeMunger) other;
+ ResolvedTypeMunger otherTypeMunger = o.getMunger();
+ ResolvedTypeMunger thisTypeMunger = getMunger();
+ if (thisTypeMunger instanceof NewConstructorTypeMunger && otherTypeMunger instanceof NewConstructorTypeMunger) {
+ return (((NewConstructorTypeMunger) otherTypeMunger).equivalentTo(thisTypeMunger))
+ && ((o.getAspectType() == null) ? (getAspectType() == null) : o.getAspectType().equals(getAspectType()));
+ } else {
+ return ((otherTypeMunger == null) ? (thisTypeMunger == null) : otherTypeMunger.equals(thisTypeMunger))
+ && ((o.getAspectType() == null) ? (getAspectType() == null) : o.getAspectType().equals(getAspectType()));
+ }
+ }
+
+ // public abstract boolean munge(LazyClassGen gen);
+
+ /**
+ * returns null for mungers that are used internally, but were not part of a declared thing in source code.
+ */
+ public ResolvedTypeMunger getMunger() {
+ return munger;
+ }
+
+ public ResolvedType getAspectType() {
+ return aspectType;
+ }
+
+ public ResolvedMember getSignature() {
+ return munger.getSignature();
+ }
+
+ public World getWorld() {
+ return aspectType.getWorld();
+ }
+
+ public ISourceLocation getSourceLocation() {
+ if (munger == null) {
+ return null;
+ }
+ return munger.getSourceLocation(); // XXX
+ }
+
+ public boolean matches(ResolvedType onType) {
+ if (munger == null) {
+ throw new RuntimeException("huh: " + this);
+ }
+ return munger.matches(onType, aspectType);
+ }
+
+ public ResolvedMember getMatchingSyntheticMember(Member member) {
+ return munger.getMatchingSyntheticMember(member, aspectType);
+ }
+
+ public int compareTo(Object other) {
+ ConcreteTypeMunger o = (ConcreteTypeMunger) other;
+
+ ResolvedType otherAspect = o.aspectType;
+
+ if (aspectType.equals(otherAspect)) {
+ return getSignature().getStart() < o.getSignature().getStart() ? -1 : +1;
+ } else if (aspectType.isAssignableFrom(o.aspectType)) {
+ return +1;
+ } else if (o.aspectType.isAssignableFrom(aspectType)) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ public int fallbackCompareTo(Object other) {
+ // ConcreteTypeMunger o = (ConcreteTypeMunger) other;
+ return 0;
+ }
+
+ /**
+ * returns true if the ITD target type used type variables, for example I<T>. When they are specified like this, the ITDs
+ * 'share' type variables with the generic type. Usually this method is called because we need to know whether to tailor the
+ * munger for addition to a particular type. For example: <code>
+ * interface I<T> {}
+ *
+ * aspect X implements I<String> {
+ * List<T> I<T>.foo { return null; }
+ * }
+ * </code> In this case the munger matches X but it matches with the form <code>
+ * List<String> foo() { return null; }
+ * </code>
+ */
+ public boolean isTargetTypeParameterized() {
+ if (munger == null) {
+ return false;
+ }
+ return munger.sharesTypeVariablesWithGenericType();
+ }
+
+ /**
+ * For an ITD made on a generic type that shares type variables with that target type, this method will tailor the ITD for a
+ * particular usage of the generic type - either in its raw or parameterized form.
+ */
+ public abstract ConcreteTypeMunger parameterizedFor(ResolvedType targetType);
+
+ public boolean isLateMunger() {
+ if (munger == null) {
+ return false;
+ }
+ return munger.isLateMunger();
+ }
+
+ public abstract ConcreteTypeMunger parameterizeWith(Map<String, UnresolvedType> parameterizationMap, World world);
+
+ /**
+ * Some type mungers are created purely to help with the implementation of shadow mungers. For example to support the cflow()
+ * pointcut we create a new cflow field in the aspect, and that is added via a BcelCflowCounterFieldAdder.
+ *
+ * During compilation we need to compare sets of type mungers, and if some only come into existence after the 'shadowy' type
+ * things have been processed, we need to ignore them during the comparison.
+ *
+ * Returning true from this method indicates the type munger exists to support 'shadowy' stuff - and so can be ignored in some
+ * comparison.
+ */
+ public boolean existsToSupportShadowMunging() {
+ if (munger != null) {
+ return munger.existsToSupportShadowMunging();
+ }
+ return false;
+ }
+
+ public boolean shouldOverwrite() {
+ return true;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolReader.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolReader.java
new file mode 100644
index 000000000..1345e7e09
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolReader.java
@@ -0,0 +1,23 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement (SpringSource)
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Used during attribute reading to decode constant pool references.
+ *
+ * @author Andy Clement
+ */
+public interface ConstantPoolReader {
+
+ String readUtf8(int constantPoolIndex);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolWriter.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolWriter.java
new file mode 100644
index 000000000..2b145a1de
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ConstantPoolWriter.java
@@ -0,0 +1,23 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement (SpringSource)
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Used during attribute writing to encode common strings/etc as constant pool references.
+ *
+ * @author Andy Clement
+ */
+public interface ConstantPoolWriter {
+
+ int writeUtf8(String string);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Constants.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Constants.java
new file mode 100644
index 000000000..bdbde3853
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Constants.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Some useful weaver constants.
+ *
+ * Current uses: 1. Holds values that are necessary for working with 1.5 code but which don't exist in a 1.4 world.
+ */
+public interface Constants {
+
+ public final static int ACC_BRIDGE = 0x0040;
+ public final static int ACC_VARARGS = 0x0080;
+
+ public final static String RUNTIME_LEVEL_12 = "1.2";
+ public final static String RUNTIME_LEVEL_15 = "1.5";
+ public final static String RUNTIME_LEVEL_19 = "1.9";
+
+ // Default for 1.5.0
+ public final static String RUNTIME_LEVEL_DEFAULT = RUNTIME_LEVEL_15;
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java
new file mode 100644
index 000000000..8e41c0a82
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembers.java
@@ -0,0 +1,591 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.DeclareAnnotation;
+import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
+import org.aspectj.weaver.patterns.DeclareParents;
+import org.aspectj.weaver.patterns.DeclarePrecedence;
+import org.aspectj.weaver.patterns.DeclareSoft;
+import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
+import org.aspectj.weaver.patterns.PerClause;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.PointcutRewriter;
+
+/**
+ * This holds on to all members that have an invasive effect outside of there own compilation unit. These members need to be all
+ * gathered up and in a world before any weaving can take place.
+ *
+ * They are also important in the compilation process and need to be gathered up before the inter-type declaration weaving stage
+ * (unsurprisingly).
+ *
+ * All members are concrete.
+ *
+ * @author Jim Hugunin
+ */
+public class CrosscuttingMembers {
+ private final ResolvedType inAspect;
+ private final World world;
+
+ private PerClause perClause;
+
+ private List<ShadowMunger> shadowMungers = new ArrayList<ShadowMunger>(4);
+ private List<ConcreteTypeMunger> typeMungers = new ArrayList<ConcreteTypeMunger>(4);
+ private List<ConcreteTypeMunger> lateTypeMungers = new ArrayList<ConcreteTypeMunger>(0);
+
+ private Set<DeclareParents> declareParents = new HashSet<DeclareParents>();
+ private Set<DeclareSoft> declareSofts = new HashSet<DeclareSoft>();
+ private List<Declare> declareDominates = new ArrayList<Declare>(4);
+
+ // These are like declare parents type mungers
+ private Set<DeclareAnnotation> declareAnnotationsOnType = new LinkedHashSet<DeclareAnnotation>();
+ private Set<DeclareAnnotation> declareAnnotationsOnField = new LinkedHashSet<DeclareAnnotation>();
+ private Set<DeclareAnnotation> declareAnnotationsOnMethods = new LinkedHashSet<DeclareAnnotation>();
+ // declareAnnotationsOnMethods includes constructors too
+
+ private Set<DeclareTypeErrorOrWarning> declareTypeEow = new HashSet<DeclareTypeErrorOrWarning>();
+
+ private boolean shouldConcretizeIfNeeded = true;
+
+ public CrosscuttingMembers(ResolvedType inAspect, boolean shouldConcretizeIfNeeded) {
+ this.inAspect = inAspect;
+ world = inAspect.getWorld();
+ this.shouldConcretizeIfNeeded = shouldConcretizeIfNeeded;
+ }
+
+ private final Hashtable<String, Object> cflowFields = new Hashtable<String, Object>();
+ private final Hashtable<String, Object> cflowBelowFields = new Hashtable<String, Object>();
+
+ // public void addConcreteShadowMungers(Collection c) {
+ // shadowMungers.addAll(c);
+ // }
+
+ public void addConcreteShadowMunger(ShadowMunger m) {
+ // assert m is concrete
+ shadowMungers.add(m);
+ }
+
+ public void addShadowMungers(Collection<ShadowMunger> c) {
+ for (ShadowMunger munger : c) {
+ addShadowMunger(munger);
+ }
+ }
+
+ private void addShadowMunger(ShadowMunger m) {
+ if (inAspect.isAbstract()) {
+ return; // mungers for abstract aspects are not added
+ }
+ addConcreteShadowMunger(m.concretize(inAspect, world, perClause));
+ }
+
+ public void addTypeMungers(Collection<ConcreteTypeMunger> c) {
+ typeMungers.addAll(c);
+ }
+
+ public void addTypeMunger(ConcreteTypeMunger m) {
+ if (m == null) {
+ throw new Error("FIXME AV - should not happen or what ?");// return;
+ }
+ typeMungers.add(m);
+ }
+
+ public void addLateTypeMungers(Collection<ConcreteTypeMunger> c) {
+ lateTypeMungers.addAll(c);
+ }
+
+ public void addLateTypeMunger(ConcreteTypeMunger m) {
+ lateTypeMungers.add(m);
+ }
+
+ public void addDeclares(Collection<Declare> declares) {
+ for (Declare declare : declares) {
+ addDeclare(declare);
+ }
+ }
+
+ public void addDeclare(Declare declare) {
+ // this is not extensible, oh well
+ if (declare instanceof DeclareErrorOrWarning) {
+ ShadowMunger m = new Checker((DeclareErrorOrWarning) declare);
+ m.setDeclaringType(declare.getDeclaringType());
+ addShadowMunger(m);
+ } else if (declare instanceof DeclarePrecedence) {
+ declareDominates.add(declare);
+ } else if (declare instanceof DeclareParents) {
+ DeclareParents dp = (DeclareParents) declare;
+ exposeTypes(dp.getParents().getExactTypes());
+ declareParents.add(dp);
+ } else if (declare instanceof DeclareSoft) {
+ DeclareSoft d = (DeclareSoft) declare;
+ // Ordered so that during concretization we can check the related
+ // munger
+ ShadowMunger m = Advice.makeSoftener(world, d.getPointcut(), d.getException(), inAspect, d);
+ m.setDeclaringType(d.getDeclaringType());
+ Pointcut concretePointcut = d.getPointcut().concretize(inAspect, d.getDeclaringType(), 0, m);
+ m.pointcut = concretePointcut;
+ declareSofts.add(new DeclareSoft(d.getException(), concretePointcut));
+ addConcreteShadowMunger(m);
+ } else if (declare instanceof DeclareAnnotation) {
+ // FIXME asc perf Possible Improvement. Investigate why this is
+ // called twice in a weave ?
+ DeclareAnnotation da = (DeclareAnnotation) declare;
+ if (da.getAspect() == null) {
+ da.setAspect(inAspect);
+ }
+ if (da.isDeclareAtType()) {
+ declareAnnotationsOnType.add(da);
+ } else if (da.isDeclareAtField()) {
+ declareAnnotationsOnField.add(da);
+ } else if (da.isDeclareAtMethod() || da.isDeclareAtConstuctor()) {
+ declareAnnotationsOnMethods.add(da);
+ }
+ } else if (declare instanceof DeclareTypeErrorOrWarning) {
+ declareTypeEow.add((DeclareTypeErrorOrWarning) declare);
+ } else {
+ throw new RuntimeException("unimplemented");
+ }
+ }
+
+ public void exposeTypes(List<UnresolvedType> typesToExpose) {
+ for (UnresolvedType typeToExpose : typesToExpose) {
+ exposeType(typeToExpose);
+ }
+ }
+
+ public void exposeType(UnresolvedType typeToExpose) {
+ if (ResolvedType.isMissing(typeToExpose)) {
+ return;
+ }
+ if (typeToExpose.isParameterizedType() || typeToExpose.isRawType()) {
+ if (typeToExpose instanceof ResolvedType) {
+ typeToExpose = ((ResolvedType) typeToExpose).getGenericType();
+ } else {
+ typeToExpose = UnresolvedType.forSignature(typeToExpose.getErasureSignature());
+ }
+ }
+ // Check we haven't already got a munger for this:
+ String signatureToLookFor = typeToExpose.getSignature();
+ for (Iterator<ConcreteTypeMunger> iterator = typeMungers.iterator(); iterator.hasNext();) {
+ ConcreteTypeMunger cTM = iterator.next();
+ ResolvedTypeMunger rTM = cTM.getMunger();
+ if (rTM != null && rTM instanceof ExposeTypeMunger) {
+ String exposedType = ((ExposeTypeMunger) rTM).getExposedTypeSignature();
+ if (exposedType.equals(signatureToLookFor)) {
+ return; // dont need to bother
+ }
+ }
+ }
+ addTypeMunger(world.getWeavingSupport().concreteTypeMunger(new ExposeTypeMunger(typeToExpose), inAspect));
+ // ResolvedMember member = new ResolvedMemberImpl(
+ // Member.STATIC_INITIALIZATION, typeToExpose, 0, UnresolvedType.VOID,
+ // "<clinit>", UnresolvedType.NONE);
+ // addTypeMunger(world.concreteTypeMunger(
+ // new PrivilegedAccessMunger(member), inAspect));
+ }
+
+ public void addPrivilegedAccesses(Collection<ResolvedMember> accessedMembers) {
+ int version = inAspect.getCompilerVersion();
+ for (ResolvedMember member : accessedMembers) {
+ // Looking it up ensures we get the annotations - the accessedMembers are just retrieved from the attribute and
+ // don't have that information
+ ResolvedMember resolvedMember = world.resolve(member);
+
+ // pr333469
+ // If the member is for an ITD (e.g. serialVersionUID) then during resolution we may resolve it on
+ // a supertype because it doesn't yet exist on the target.
+ // For example: MyList extends ArrayList<String> and the ITD is on MyList - after resolution it may be:
+ // ArrayList<String>.serialVersionUID, we need to avoid that happening
+
+ if (resolvedMember == null) {
+ // can happen for ITDs - are there many privileged access ITDs??
+ resolvedMember = member;
+ if (resolvedMember.hasBackingGenericMember()) {
+ resolvedMember = resolvedMember.getBackingGenericMember();
+ }
+ } else {
+ UnresolvedType unresolvedDeclaringType = member.getDeclaringType().getRawType();
+ UnresolvedType resolvedDeclaringType = resolvedMember.getDeclaringType().getRawType();
+ if (!unresolvedDeclaringType.equals(resolvedDeclaringType)) {
+ resolvedMember = member;
+ }
+ }
+ PrivilegedAccessMunger privilegedAccessMunger = new PrivilegedAccessMunger(resolvedMember,
+ version >= WeaverVersionInfo.WEAVER_VERSION_AJ169);
+ ConcreteTypeMunger concreteTypeMunger = world.getWeavingSupport().concreteTypeMunger(privilegedAccessMunger, inAspect);
+ addTypeMunger(concreteTypeMunger);
+ }
+ }
+
+ public Collection<ShadowMunger> getCflowEntries() {
+ List<ShadowMunger> ret = new ArrayList<ShadowMunger>();
+ for (ShadowMunger m : shadowMungers) {
+ if (m instanceof Advice) {
+ Advice a = (Advice) m;
+ if (a.getKind().isCflow()) {
+ ret.add(a);
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Updates the records if something has changed. This is called at most twice, firstly whilst collecting ITDs and declares. At
+ * this point the CrosscuttingMembers we're comparing ourselves with doesn't know about shadowmungers. Therefore a straight
+ * comparison with the existing list of shadowmungers would return that something has changed even though it might not have, so
+ * in this first round we ignore the shadowMungers. The second time this is called is whilst we're preparing to weave. At this
+ * point we know everything in the system and so we're able to compare the shadowMunger list. (see bug 129163)
+ *
+ * @param other
+ * @param careAboutShadowMungers
+ * @return true if something has changed since the last time this method was called, false otherwise
+ */
+ public boolean replaceWith(CrosscuttingMembers other, boolean careAboutShadowMungers) {
+ boolean changed = false;
+
+ if (careAboutShadowMungers) {
+ if (perClause == null || !perClause.equals(other.perClause)) {
+ changed = true;
+ perClause = other.perClause;
+ }
+ }
+
+ // XXX all of the below should be set equality rather than list equality
+ // System.err.println("old: " + shadowMungers + " new: " +
+ // other.shadowMungers);
+
+ if (careAboutShadowMungers) {
+ // bug 129163: use set equality rather than list equality
+ Set<ShadowMunger> theseShadowMungers = new HashSet<ShadowMunger>();
+ Set<ShadowMunger> theseInlinedAroundMungers = new HashSet<ShadowMunger>();
+ for (ShadowMunger munger : shadowMungers) {
+ if (munger instanceof Advice) {
+ Advice adviceMunger = (Advice) munger;
+ // bug 154054: if we're around advice that has been inlined
+ // then we need to do more checking than existing equals
+ // methods allow
+ if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
+ theseInlinedAroundMungers.add(adviceMunger);
+ } else {
+ theseShadowMungers.add(adviceMunger);
+ }
+ } else {
+ theseShadowMungers.add(munger);
+ }
+ }
+ Set<ShadowMunger> tempSet = new HashSet<ShadowMunger>();
+ tempSet.addAll(other.shadowMungers);
+ Set<ShadowMunger> otherShadowMungers = new HashSet<ShadowMunger>();
+ Set<ShadowMunger> otherInlinedAroundMungers = new HashSet<ShadowMunger>();
+ for (ShadowMunger munger : tempSet) {
+ if (munger instanceof Advice) {
+ Advice adviceMunger = (Advice) munger;
+ // bug 154054: if we're around advice that has been inlined
+ // then we need to do more checking than existing equals
+ // methods allow
+ if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
+ otherInlinedAroundMungers.add(rewritePointcutInMunger(adviceMunger));
+ } else {
+ otherShadowMungers.add(rewritePointcutInMunger(adviceMunger));
+ }
+ } else {
+ otherShadowMungers.add(rewritePointcutInMunger(munger));
+ }
+ }
+ if (!theseShadowMungers.equals(otherShadowMungers)) {
+ changed = true;
+ }
+ if (!equivalent(theseInlinedAroundMungers, otherInlinedAroundMungers)) {
+ changed = true;
+ }
+
+ // bug 158573 - if there are no changes then preserve whether
+ // or not a particular shadowMunger has matched something.
+ if (!changed) {
+ for (ShadowMunger munger : shadowMungers) {
+ int i = other.shadowMungers.indexOf(munger);
+ ShadowMunger otherMunger = other.shadowMungers.get(i);
+ if (munger instanceof Advice) {
+ ((Advice) otherMunger).setHasMatchedSomething(((Advice) munger).hasMatchedSomething());
+ }
+ }
+ }
+ // replace the existing list of shadowmungers with the
+ // new ones in case anything like the sourcelocation has
+ // changed, however, don't want this flagged as a change
+ // which will force a full build - bug 134541
+ shadowMungers = other.shadowMungers;
+ }
+
+ // bug 129163: use set equality rather than list equality and
+ // if we dont care about shadow mungers then ignore those
+ // typeMungers which are created to help with the implementation
+ // of shadowMungers
+ Set<Object> theseTypeMungers = new HashSet<Object>();
+ Set<Object> otherTypeMungers = new HashSet<Object>();
+ if (!careAboutShadowMungers) {
+ for (Iterator<ConcreteTypeMunger> iter = typeMungers.iterator(); iter.hasNext();) {
+ Object o = iter.next();
+ if (o instanceof ConcreteTypeMunger) {
+ ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) o;
+ if (!typeMunger.existsToSupportShadowMunging()) {
+ theseTypeMungers.add(typeMunger);
+ }
+ } else {
+ theseTypeMungers.add(o);
+ }
+ }
+
+ for (Iterator<ConcreteTypeMunger> iter = other.typeMungers.iterator(); iter.hasNext();) {
+ Object o = iter.next();
+ if (o instanceof ConcreteTypeMunger) {
+ ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) o;
+ if (!typeMunger.existsToSupportShadowMunging()) {
+ otherTypeMungers.add(typeMunger);
+ }
+ } else {
+ otherTypeMungers.add(o);
+ }
+ }
+ } else {
+ theseTypeMungers.addAll(typeMungers);
+ otherTypeMungers.addAll(other.typeMungers);
+ }
+
+ // initial go at equivalence logic rather than set compare (see
+ // pr133532)
+ if (theseTypeMungers.size() != otherTypeMungers.size()) {
+ changed = true;
+ typeMungers = other.typeMungers;
+ } else {
+ boolean shouldOverwriteThis = false;
+ boolean foundInequality = false;
+ for (Iterator<Object> iter = theseTypeMungers.iterator(); iter.hasNext() && !foundInequality;) {
+ Object thisOne = iter.next();
+ boolean foundInOtherSet = false;
+ for (Object otherOne : otherTypeMungers) {
+ if (thisOne instanceof ConcreteTypeMunger) {
+ if (((ConcreteTypeMunger) thisOne).shouldOverwrite()) {
+ shouldOverwriteThis = true;
+ }
+ }
+ if (thisOne instanceof ConcreteTypeMunger && otherOne instanceof ConcreteTypeMunger) {
+ if (((ConcreteTypeMunger) thisOne).equivalentTo(otherOne)) {
+ foundInOtherSet = true;
+ } else if (thisOne.equals(otherOne)) {
+ foundInOtherSet = true;
+ }
+ } else {
+ if (thisOne.equals(otherOne)) {
+ foundInOtherSet = true;
+ }
+ }
+ }
+ if (!foundInOtherSet) {
+ foundInequality = true;
+ }
+ }
+ if (foundInequality) {
+ // System.out.println("type munger change");
+ changed = true;
+ }
+ if (shouldOverwriteThis) {
+ typeMungers = other.typeMungers;
+ }
+ }
+ // if (!theseTypeMungers.equals(otherTypeMungers)) {
+ // changed = true;
+ // typeMungers = other.typeMungers;
+ // }
+
+ if (!lateTypeMungers.equals(other.lateTypeMungers)) {
+ changed = true;
+ lateTypeMungers = other.lateTypeMungers;
+ }
+
+ if (!declareDominates.equals(other.declareDominates)) {
+ changed = true;
+ declareDominates = other.declareDominates;
+ }
+
+ if (!declareParents.equals(other.declareParents)) {
+ // Are the differences just because of a mixin? These are not created until weave time so should be gotten rid of for
+ // the up front comparison
+ if (!careAboutShadowMungers) {
+ // this means we are in front end compilation and if the differences are purely mixin parents, we can continue OK
+ Set<DeclareParents> trimmedThis = new HashSet<DeclareParents>();
+ for (Iterator<DeclareParents> iterator = declareParents.iterator(); iterator.hasNext();) {
+ DeclareParents decp = iterator.next();
+ if (!decp.isMixin()) {
+ trimmedThis.add(decp);
+ }
+ }
+ Set<DeclareParents> trimmedOther = new HashSet<DeclareParents>();
+ for (Iterator<DeclareParents> iterator = other.declareParents.iterator(); iterator.hasNext();) {
+ DeclareParents decp = iterator.next();
+ if (!decp.isMixin()) {
+ trimmedOther.add(decp);
+ }
+ }
+ if (!trimmedThis.equals(trimmedOther)) {
+ changed = true;
+ declareParents = other.declareParents;
+ }
+ } else {
+ changed = true;
+ declareParents = other.declareParents;
+ }
+ }
+
+ if (!declareSofts.equals(other.declareSofts)) {
+ changed = true;
+ declareSofts = other.declareSofts;
+ }
+
+ // DECAT for when attempting to replace an aspect
+ if (!declareAnnotationsOnType.equals(other.declareAnnotationsOnType)) {
+ changed = true;
+ declareAnnotationsOnType = other.declareAnnotationsOnType;
+ }
+
+ if (!declareAnnotationsOnField.equals(other.declareAnnotationsOnField)) {
+ changed = true;
+ declareAnnotationsOnField = other.declareAnnotationsOnField;
+ }
+
+ if (!declareAnnotationsOnMethods.equals(other.declareAnnotationsOnMethods)) {
+ changed = true;
+ declareAnnotationsOnMethods = other.declareAnnotationsOnMethods;
+ }
+ if (!declareTypeEow.equals(other.declareTypeEow)) {
+ changed = true;
+ declareTypeEow = other.declareTypeEow;
+ }
+
+ return changed;
+ }
+
+ private boolean equivalent(Set<ShadowMunger> theseInlinedAroundMungers, Set<ShadowMunger> otherInlinedAroundMungers) {
+ if (theseInlinedAroundMungers.size() != otherInlinedAroundMungers.size()) {
+ return false;
+ }
+ for (Iterator<ShadowMunger> iter = theseInlinedAroundMungers.iterator(); iter.hasNext();) {
+ Advice thisAdvice = (Advice) iter.next();
+ boolean foundIt = false;
+ for (Iterator<ShadowMunger> iterator = otherInlinedAroundMungers.iterator(); iterator.hasNext();) {
+ Advice otherAdvice = (Advice) iterator.next();
+ if (thisAdvice.equals(otherAdvice)) {
+ if (thisAdvice.getSignature() instanceof ResolvedMemberImpl) {
+ if (((ResolvedMemberImpl) thisAdvice.getSignature()).isEquivalentTo(otherAdvice.getSignature())) {
+ foundIt = true;
+ continue;
+ }
+ }
+ return false;
+ }
+ }
+ if (!foundIt) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private ShadowMunger rewritePointcutInMunger(ShadowMunger munger) {
+ PointcutRewriter pr = new PointcutRewriter();
+ Pointcut p = munger.getPointcut();
+ Pointcut newP = pr.rewrite(p);
+ if (p.m_ignoreUnboundBindingForNames.length != 0) {
+ // *sigh* dirty fix for dirty hacky implementation pr149305
+ newP.m_ignoreUnboundBindingForNames = p.m_ignoreUnboundBindingForNames;
+ }
+ munger.setPointcut(newP);
+ return munger;
+ }
+
+ public void setPerClause(PerClause perClause) {
+ if (shouldConcretizeIfNeeded) {
+ this.perClause = perClause.concretize(inAspect);
+ } else {
+ this.perClause = perClause;
+ }
+ }
+
+ public List<Declare> getDeclareDominates() {
+ return declareDominates;
+ }
+
+ public Collection<DeclareParents> getDeclareParents() {
+ return declareParents;
+ }
+
+ public Collection<DeclareSoft> getDeclareSofts() {
+ return declareSofts;
+ }
+
+ public List<ShadowMunger> getShadowMungers() {
+ return shadowMungers;
+ }
+
+ public List<ConcreteTypeMunger> getTypeMungers() {
+ return typeMungers;
+ }
+
+ public List<ConcreteTypeMunger> getLateTypeMungers() {
+ return lateTypeMungers;
+ }
+
+ public Collection<DeclareAnnotation> getDeclareAnnotationOnTypes() {
+ return declareAnnotationsOnType;
+ }
+
+ public Collection<DeclareAnnotation> getDeclareAnnotationOnFields() {
+ return declareAnnotationsOnField;
+ }
+
+ /**
+ * includes declare @method and @constructor
+ */
+ public Collection<DeclareAnnotation> getDeclareAnnotationOnMethods() {
+ return declareAnnotationsOnMethods;
+ }
+
+ public Collection<DeclareTypeErrorOrWarning> getDeclareTypeErrorOrWarning() {
+ return declareTypeEow;
+ }
+
+ public Map<String, Object> getCflowBelowFields() {
+ return cflowBelowFields;
+ }
+
+ public Map<String, Object> getCflowFields() {
+ return cflowFields;
+ }
+
+ public void clearCaches() {
+ cflowFields.clear();
+ cflowBelowFields.clear();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembersSet.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembersSet.java
new file mode 100644
index 000000000..969f96ece
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CrosscuttingMembersSet.java
@@ -0,0 +1,459 @@
+/* *******************************************************************
+ * Copyright (c) 2002-2009 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.DeclareAnnotation;
+import org.aspectj.weaver.patterns.DeclareParents;
+import org.aspectj.weaver.patterns.DeclareSoft;
+import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
+import org.aspectj.weaver.patterns.IVerificationRequired;
+
+/**
+ * This holds on to all CrosscuttingMembers for a world. It handles management of change.
+ *
+ * @author Jim Hugunin
+ * @author Andy Clement
+ */
+public class CrosscuttingMembersSet {
+
+ private transient World world;
+
+ // FIXME AV - ? we may need a sequencedHashMap there to ensure source based precedence for @AJ advice
+ private final Map<ResolvedType, CrosscuttingMembers> members = new HashMap<ResolvedType, CrosscuttingMembers>();
+
+ // List of things to be verified once the type system is 'complete'
+ private transient List<IVerificationRequired> verificationList = null;
+
+ private List<ShadowMunger> shadowMungers = null;
+ private List<ConcreteTypeMunger> typeMungers = null;
+ private List<ConcreteTypeMunger> lateTypeMungers = null;
+ private List<DeclareSoft> declareSofts = null;
+ private List<DeclareParents> declareParents = null;
+ private List<DeclareAnnotation> declareAnnotationOnTypes = null;
+ private List<DeclareAnnotation> declareAnnotationOnFields = null;
+ private List<DeclareAnnotation> declareAnnotationOnMethods = null; // includes constructors
+ private List<DeclareTypeErrorOrWarning> declareTypeEows = null;
+ private List<Declare> declareDominates = null;
+ private boolean changedSinceLastReset = false;
+
+ public CrosscuttingMembersSet(World world) {
+ this.world = world;
+ }
+
+ public boolean addOrReplaceAspect(ResolvedType aspectType) {
+ return addOrReplaceAspect(aspectType, true);
+ }
+
+ /**
+ * Check if any parent aspects of the supplied aspect have unresolved dependencies (and so
+ * should cause this aspect to be turned off).
+ * @param aspectType the aspect whose parents should be checked
+ * @return true if this aspect should be excluded because of a parents' missing dependencies
+ */
+ private boolean excludeDueToParentAspectHavingUnresolvedDependency(ResolvedType aspectType) {
+ ResolvedType parent = aspectType.getSuperclass();
+ boolean excludeDueToParent = false;
+ while (parent != null) {
+ if (parent.isAspect() && parent.isAbstract() && world.hasUnsatisfiedDependency(parent)) {
+ if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
+ world.getMessageHandler().handleMessage(
+ MessageUtil.info("deactivating aspect '" + aspectType.getName() + "' as the parent aspect '"+parent.getName()+
+ "' has unsatisfied dependencies"));
+ }
+ excludeDueToParent = true;
+ }
+ parent = parent.getSuperclass();
+ }
+ return excludeDueToParent;
+ }
+
+ /**
+ * @return whether or not that was a change to the global signature XXX for efficiency we will need a richer representation than
+ * this
+ */
+ public boolean addOrReplaceAspect(ResolvedType aspectType, boolean inWeavingPhase) {
+ if (!world.isAspectIncluded(aspectType)) {
+ return false;
+ }
+ if (world.hasUnsatisfiedDependency(aspectType)) {
+ return false;
+ }
+ // Abstract super aspects might have unsatisfied dependencies
+ if (excludeDueToParentAspectHavingUnresolvedDependency(aspectType)) {
+ return false;
+ }
+
+ boolean change = false;
+ CrosscuttingMembers xcut = members.get(aspectType);
+ if (xcut == null) {
+ members.put(aspectType, aspectType.collectCrosscuttingMembers(inWeavingPhase));
+ clearCaches();
+ change = true;
+ } else {
+ if (xcut.replaceWith(aspectType.collectCrosscuttingMembers(inWeavingPhase), inWeavingPhase)) {
+ clearCaches();
+ change = true;
+ } else {
+ if (inWeavingPhase) {
+ // bug 134541 - even though we haven't changed we may have updated the
+ // sourcelocation for the shadowMunger which we need to pick up
+ shadowMungers = null;
+ }
+ change = false;
+ }
+ }
+ if (aspectType.isAbstract()) {
+ // we might have sub-aspects that need to re-collect their crosscutting members from us
+ boolean ancestorChange = addOrReplaceDescendantsOf(aspectType, inWeavingPhase);
+ change = change || ancestorChange;
+ }
+ changedSinceLastReset = changedSinceLastReset || change;
+
+ return change;
+ }
+
+ private boolean addOrReplaceDescendantsOf(ResolvedType aspectType, boolean inWeavePhase) {
+ // System.err.println("Looking at descendants of "+aspectType.getName());
+ Set<ResolvedType> knownAspects = members.keySet();
+ Set<ResolvedType> toBeReplaced = new HashSet<ResolvedType>();
+ for (Iterator<ResolvedType> it = knownAspects.iterator(); it.hasNext();) {
+ ResolvedType candidateDescendant = it.next();
+ // allowMissing = true - if something is missing, it really probably is not a descendant
+ if ((candidateDescendant != aspectType) && (aspectType.isAssignableFrom(candidateDescendant, true))) {
+ toBeReplaced.add(candidateDescendant);
+ }
+ }
+ boolean change = false;
+ for (Iterator<ResolvedType> it = toBeReplaced.iterator(); it.hasNext();) {
+ ResolvedType next = it.next();
+ boolean thisChange = addOrReplaceAspect(next, inWeavePhase);
+ change = change || thisChange;
+ }
+ return change;
+ }
+
+ public void addAdviceLikeDeclares(ResolvedType aspectType) {
+ if (!members.containsKey(aspectType)) {
+ return;
+ }
+ CrosscuttingMembers xcut = members.get(aspectType);
+ xcut.addDeclares(aspectType.collectDeclares(true));
+ }
+
+ public boolean deleteAspect(UnresolvedType aspectType) {
+ boolean isAspect = members.remove(aspectType) != null;
+ clearCaches();
+ return isAspect;
+ }
+
+ public boolean containsAspect(UnresolvedType aspectType) {
+ return members.containsKey(aspectType);
+ }
+
+ // XXX only for testing
+ public void addFixedCrosscuttingMembers(ResolvedType aspectType) {
+ members.put(aspectType, aspectType.crosscuttingMembers);
+ clearCaches();
+ }
+
+ private void clearCaches() {
+ shadowMungers = null;
+ typeMungers = null;
+ lateTypeMungers = null;
+ declareSofts = null;
+ declareParents = null;
+ declareAnnotationOnFields = null;
+ declareAnnotationOnMethods = null;
+ declareAnnotationOnTypes = null;
+ declareDominates = null;
+ }
+
+ public List<ShadowMunger> getShadowMungers() {
+ if (shadowMungers == null) {
+ List<ShadowMunger> ret = new ArrayList<ShadowMunger>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getShadowMungers());
+ }
+ shadowMungers = ret;
+ }
+ return shadowMungers;
+ }
+
+ public List<ConcreteTypeMunger> getTypeMungers() {
+ if (typeMungers == null) {
+ List<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
+ for (CrosscuttingMembers xmembers : members.values()) {
+ // With 1.6.9 there is a change that enables use of more optimal accessors (accessors for private fields).
+ // Here is where we determine if two aspects are asking for access to the same field. If they are
+ // and
+ // In the new style multiple aspects can share the same privileged accessors, so here we check if
+ // two aspects are asking for access to the same field. If they are then we don't add a duplicate
+ // accessor.
+ for (ConcreteTypeMunger mungerToAdd : xmembers.getTypeMungers()) {
+ ResolvedTypeMunger resolvedMungerToAdd = mungerToAdd.getMunger();
+ if (isNewStylePrivilegedAccessMunger(resolvedMungerToAdd)) {
+ String newFieldName = resolvedMungerToAdd.getSignature().getName();
+ boolean alreadyExists = false;
+ for (ConcreteTypeMunger existingMunger : ret) {
+ ResolvedTypeMunger existing = existingMunger.getMunger();
+ if (isNewStylePrivilegedAccessMunger(existing)) {
+ String existingFieldName = existing.getSignature().getName();
+ if (existingFieldName.equals(newFieldName)
+ && existing.getSignature().getDeclaringType().equals(
+ resolvedMungerToAdd.getSignature().getDeclaringType())) {
+ alreadyExists = true;
+ break;
+ }
+ }
+ }
+ if (!alreadyExists) {
+ ret.add(mungerToAdd);
+ }
+ } else {
+ ret.add(mungerToAdd);
+ }
+ }
+ }
+ typeMungers = ret;
+ }
+ return typeMungers;
+ }
+
+ /**
+ * Retrieve a subset of all known mungers, those of a specific kind.
+ *
+ * @param kind the kind of munger requested
+ * @return a list of those mungers (list is empty if none found)
+ */
+ public List<ConcreteTypeMunger> getTypeMungersOfKind(ResolvedTypeMunger.Kind kind) {
+ List<ConcreteTypeMunger> collected = null;
+ for (ConcreteTypeMunger typeMunger : typeMungers) {
+ if (typeMunger.getMunger() != null && typeMunger.getMunger().getKind() == kind) {
+ if (collected == null) {
+ collected = new ArrayList<ConcreteTypeMunger>();
+ }
+ collected.add(typeMunger);
+ }
+ }
+ if (collected == null) {
+ return Collections.emptyList();
+ } else {
+ return collected;
+ }
+ }
+
+ /**
+ * Determine if the type munger is: (1) for privileged access (2) for a normally non visible field (3) is from an aspect wanting
+ * 'old style' (ie. long) accessor names
+ */
+ private boolean isNewStylePrivilegedAccessMunger(ResolvedTypeMunger typeMunger) {
+ boolean b = (typeMunger != null && typeMunger.getKind() == ResolvedTypeMunger.PrivilegedAccess && typeMunger.getSignature()
+ .getKind() == Member.FIELD);
+ if (!b) {
+ return b;
+ }
+ PrivilegedAccessMunger privAccessMunger = (PrivilegedAccessMunger) typeMunger;
+ return privAccessMunger.shortSyntax;
+ }
+
+ public List<ConcreteTypeMunger> getLateTypeMungers() {
+ if (lateTypeMungers == null) {
+ List<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getLateTypeMungers());
+ }
+ lateTypeMungers = ret;
+ }
+ return lateTypeMungers;
+ }
+
+ public List<DeclareSoft> getDeclareSofts() {
+ if (declareSofts == null) {
+ Set<DeclareSoft> ret = new HashSet<DeclareSoft>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getDeclareSofts());
+ }
+ declareSofts = new ArrayList<DeclareSoft>();
+ declareSofts.addAll(ret);
+ }
+ return declareSofts;
+ }
+
+ public List<DeclareParents> getDeclareParents() {
+ if (declareParents == null) {
+ Set<DeclareParents> ret = new HashSet<DeclareParents>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getDeclareParents());
+ }
+ declareParents = new ArrayList<DeclareParents>();
+ declareParents.addAll(ret);
+ }
+ return declareParents;
+ }
+
+ /**
+ * @return an amalgamation of the declare @type statements.
+ */
+ public List<DeclareAnnotation> getDeclareAnnotationOnTypes() {
+ if (declareAnnotationOnTypes == null) {
+ Set<DeclareAnnotation> ret = new LinkedHashSet<DeclareAnnotation>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getDeclareAnnotationOnTypes());
+ }
+ declareAnnotationOnTypes = new ArrayList<DeclareAnnotation>();
+ declareAnnotationOnTypes.addAll(ret);
+ }
+ return declareAnnotationOnTypes;
+ }
+
+ /**
+ * @return an amalgamation of the declare @field statements.
+ */
+ public List<DeclareAnnotation> getDeclareAnnotationOnFields() {
+ if (declareAnnotationOnFields == null) {
+ Set<DeclareAnnotation> ret = new LinkedHashSet<DeclareAnnotation>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getDeclareAnnotationOnFields());
+ }
+ declareAnnotationOnFields = new ArrayList<DeclareAnnotation>();
+ declareAnnotationOnFields.addAll(ret);
+ }
+ return declareAnnotationOnFields;
+ }
+
+ /**
+ * @return an amalgamation of the declare @method/@constructor statements.
+ */
+ public List<DeclareAnnotation> getDeclareAnnotationOnMethods() {
+ if (declareAnnotationOnMethods == null) {
+ Set<DeclareAnnotation> ret = new LinkedHashSet<DeclareAnnotation>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getDeclareAnnotationOnMethods());
+ }
+ declareAnnotationOnMethods = new ArrayList<DeclareAnnotation>();
+ declareAnnotationOnMethods.addAll(ret);
+ // world.sortDeclareAnnotations(declareAnnotationOnMethods);
+ }
+ return declareAnnotationOnMethods;
+ }
+
+ /**
+ * Return an amalgamation of the declare type eow statements
+ */
+ public List<DeclareTypeErrorOrWarning> getDeclareTypeEows() {
+ if (declareTypeEows == null) {
+ Set<DeclareTypeErrorOrWarning> ret = new HashSet<DeclareTypeErrorOrWarning>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getDeclareTypeErrorOrWarning());
+ }
+ declareTypeEows = new ArrayList<DeclareTypeErrorOrWarning>();
+ declareTypeEows.addAll(ret);
+ }
+ return declareTypeEows;
+ }
+
+ public List<Declare> getDeclareDominates() {
+ if (declareDominates == null) {
+ List<Declare> ret = new ArrayList<Declare>();
+ for (Iterator<CrosscuttingMembers> i = members.values().iterator(); i.hasNext();) {
+ ret.addAll(i.next().getDeclareDominates());
+ }
+ declareDominates = ret;
+ }
+ return declareDominates;
+ }
+
+ public ResolvedType findAspectDeclaringParents(DeclareParents p) {
+ Set<ResolvedType> keys = this.members.keySet();
+ for (Iterator<ResolvedType> iter = keys.iterator(); iter.hasNext();) {
+ ResolvedType element = iter.next();
+ for (Iterator i = members.get(element).getDeclareParents().iterator(); i.hasNext();) {
+ DeclareParents dp = (DeclareParents) i.next();
+ if (dp.equals(p)) {
+ return element;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void reset() {
+ verificationList = null;
+ changedSinceLastReset = false;
+ }
+
+ public boolean hasChangedSinceLastReset() {
+ return changedSinceLastReset;
+ }
+
+ /**
+ * Record something that needs verifying when we believe the type system is complete. Used for things that can't be verified as
+ * we go along - for example some recursive type variable references (pr133307)
+ */
+ public void recordNecessaryCheck(IVerificationRequired verification) {
+ if (verificationList == null) {
+ verificationList = new ArrayList<IVerificationRequired>();
+ }
+ verificationList.add(verification);
+ }
+
+ /**
+ * Called when type bindings are complete - calls all registered verification objects in turn.
+ */
+ public void verify() {
+ if (verificationList == null) {
+ return;
+ }
+ for (Iterator<IVerificationRequired> iter = verificationList.iterator(); iter.hasNext();) {
+ IVerificationRequired element = iter.next();
+ element.verify();
+ }
+ verificationList = null;
+ }
+
+ public int serializationVersion = 1;
+
+ public void write(CompressingDataOutputStream stream) throws IOException {
+ // stream.writeInt(serializationVersion);
+ stream.writeInt(shadowMungers.size());
+ for (Iterator iterator = shadowMungers.iterator(); iterator.hasNext();) {
+ ShadowMunger shadowMunger = (ShadowMunger) iterator.next();
+ shadowMunger.write(stream);
+ }
+ // // private List /* ShadowMunger */shadowMungers = null;
+ // // private List typeMungers = null;
+ // // private List lateTypeMungers = null;
+ // // private List declareSofts = null;
+ // // private List declareParents = null;
+ // // private List declareAnnotationOnTypes = null;
+ // // private List declareAnnotationOnFields = null;
+ // // private List declareAnnotationOnMethods = null; // includes constructors
+ // // private List declareDominates = null;
+ // // private boolean changedSinceLastReset = false;
+ //
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CustomMungerFactory.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CustomMungerFactory.java
new file mode 100644
index 000000000..91bcbdf6b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/CustomMungerFactory.java
@@ -0,0 +1,52 @@
+/* *******************************************************************
+ * Copyright (c) 2007 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Linton Ye https://bugs.eclipse.org/bugs/show_bug.cgi?id=193065
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.util.Collection;
+
+/**
+ * <p>
+ * This interface is introduced to support tools like PointcutDoctor.
+ * </p>
+ * <p>
+ * A CustomMungerFactory is used to create ShadowMungers and/or ConcreteTypeMungers so that an extender can extract extra
+ * information during the weaving process.
+ * </p>
+ * <p>
+ * A CustomMungerFactory is assigned to a weaver through its AjCompiler in extenders' code, and gets invoked by the weaver right
+ * before the weaving starts. The custom shadow/type mungers being created will be added into the shadow/type munger list in the
+ * weaver and participate the weaving process. For example, the match method of each custom shadow munger will be called against
+ * each shadow.
+ * </p>
+ *
+ * @author lintonye
+ *
+ */
+public interface CustomMungerFactory {
+
+ /**
+ * @param aspectType
+ * @return a Collection&lt;ShadowMunger&gt; of custom shadow mungers for the given aspect
+ */
+ public Collection<ShadowMunger> createCustomShadowMungers(ResolvedType aspectType);
+
+ /**
+ * @param aspectType
+ * @return a Collection&lt;ConcreteTypeMunger&gt; of custom type mungers for the given aspect
+ */
+ public Collection<ConcreteTypeMunger> createCustomTypeMungers(ResolvedType aspectType);
+
+ public Collection<ShadowMunger> getAllCreatedCustomShadowMungers();
+
+ public Collection<ConcreteTypeMunger> getAllCreatedCustomTypeMungers();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Dump.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Dump.java
new file mode 100644
index 000000000..103e9fec2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Dump.java
@@ -0,0 +1,523 @@
+/* *******************************************************************
+ * Copyright (c) 2004,2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster, IBM
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHolder;
+import org.aspectj.bridge.Version;
+import org.aspectj.weaver.tools.Trace;
+import org.aspectj.weaver.tools.TraceFactory;
+import org.aspectj.weaver.tools.Traceable;
+
+/**
+ * @author Matthew Webster
+ */
+public class Dump {
+
+ public final static String DUMP_CONDITION_PROPERTY = "org.aspectj.weaver.Dump.condition";
+ public final static String DUMP_DIRECTORY_PROPERTY = "org.aspectj.dump.directory";
+
+ /* Format for unique filename based on date & time */
+ private static final String FILENAME_PREFIX = "ajcore";
+ // private static final DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+ // private static final DateFormat timeFormat = new SimpleDateFormat("HHmmss.SSS");
+ private static final String FILENAME_SUFFIX = "txt";
+
+ public static final String UNKNOWN_FILENAME = "Unknown";
+ public static final String DUMP_EXCLUDED = "Excluded";
+ public static final String NULL_OR_EMPTY = "Empty";
+
+ private static Class<?> exceptionClass;
+ private static IMessage.Kind conditionKind = IMessage.ABORT;
+ private static File directory = new File(".");
+
+ private String reason;
+ private String fileName;
+ private PrintStream print;
+
+ private static String[] savedCommandLine;
+ private static List<String> savedFullClasspath;
+ private static IMessageHolder savedMessageHolder;
+
+ // private static Map<INode, WeakReference<INode>> nodes = Collections
+ // .synchronizedMap(new WeakHashMap<INode, WeakReference<INode>>());
+ private static String lastDumpFileName = UNKNOWN_FILENAME;
+
+ private static boolean preserveOnNextReset = false;
+
+ private static Trace trace = TraceFactory.getTraceFactory().getTrace(Dump.class);
+
+ /**
+ * for testing only, so that we can verify dump contents after compilation has completely finished
+ */
+ public static void preserveOnNextReset() {
+ preserveOnNextReset = true;
+ }
+
+ public static void reset() {
+ if (preserveOnNextReset) {
+ preserveOnNextReset = false;
+ return;
+ } else {
+ // nodes.clear();
+ savedMessageHolder = null;
+ }
+ }
+
+ /*
+ * Dump methods
+ */
+ public static String dump(String reason) {
+ String fileName = UNKNOWN_FILENAME;
+ Dump dump = null;
+ try {
+ dump = new Dump(reason);
+ fileName = dump.getFileName();
+ dump.dumpDefault();
+ } finally {
+ if (dump != null) {
+ dump.close();
+ }
+ }
+ return fileName;
+ }
+
+ public static String dumpWithException(Throwable th) {
+ return dumpWithException(savedMessageHolder, th);
+ }
+
+ public static String dumpWithException(IMessageHolder messageHolder, Throwable th) {
+ if (!getDumpOnException()) {
+ return null;
+ }
+ if (trace.isTraceEnabled()) {
+ trace.enter("dumpWithException", null, new Object[] { messageHolder, th });
+ }
+
+ String fileName = UNKNOWN_FILENAME;
+ Dump dump = null;
+ try {
+ dump = new Dump(th.getClass().getName());
+ fileName = dump.getFileName();
+ dump.dumpException(messageHolder, th);
+ } finally {
+ if (dump != null) {
+ dump.close();
+ }
+ }
+
+ if (trace.isTraceEnabled()) {
+ trace.exit("dumpWithException", fileName);
+ }
+ return fileName;
+ }
+
+ public static String dumpOnExit() {
+ return dumpOnExit(savedMessageHolder, false);
+ }
+
+ public static String dumpOnExit(IMessageHolder messageHolder, boolean reset) {
+ if (!getDumpOnException()) {
+ return null;
+ }
+ if (trace.isTraceEnabled()) {
+ trace.enter("dumpOnExit", null, messageHolder);
+ }
+ String fileName = UNKNOWN_FILENAME;
+
+ if (!shouldDumpOnExit(messageHolder)) {
+ fileName = DUMP_EXCLUDED;
+ } else {
+ Dump dump = null;
+ try {
+ dump = new Dump(conditionKind.toString());
+ fileName = dump.getFileName();
+ dump.dumpDefault(messageHolder);
+ } finally {
+ if (dump != null) {
+ dump.close();
+ }
+ }
+ }
+
+ if (reset) {
+ messageHolder.clearMessages();
+ }
+
+ if (trace.isTraceEnabled()) {
+ trace.exit("dumpOnExit", fileName);
+ }
+ return fileName;
+ }
+
+ private static boolean shouldDumpOnExit(IMessageHolder messageHolder) {
+ if (trace.isTraceEnabled()) {
+ trace.enter("shouldDumpOnExit", null, messageHolder);
+ }
+ if (trace.isTraceEnabled()) {
+ trace.event("shouldDumpOnExit", null, conditionKind);
+ }
+ boolean result = (messageHolder == null) || messageHolder.hasAnyMessage(conditionKind, true);
+
+ if (trace.isTraceEnabled()) {
+ trace.exit("shouldDumpOnExit", result);
+ }
+ return result;
+ }
+
+ /*
+ * Dump configuration
+ */
+ public static void setDumpOnException(boolean b) {
+ if (b) {
+ exceptionClass = java.lang.Throwable.class;
+ } else {
+ exceptionClass = null;
+ }
+ }
+
+ public static boolean setDumpDirectory(String directoryName) {
+ if (trace.isTraceEnabled()) {
+ trace.enter("setDumpDirectory", null, directoryName);
+ }
+ boolean success = false;
+
+ File newDirectory = new File(directoryName);
+ if (newDirectory.exists()) {
+ directory = newDirectory;
+ success = true;
+ }
+
+ if (trace.isTraceEnabled()) {
+ trace.exit("setDumpDirectory", success);
+ }
+ return success;
+
+ }
+
+ public static boolean getDumpOnException() {
+ return (exceptionClass != null);
+ }
+
+ public static boolean setDumpOnExit(IMessage.Kind condition) {
+ if (trace.isTraceEnabled()) {
+ trace.event("setDumpOnExit", null, condition);
+ }
+
+ conditionKind = condition;
+ return true;
+ }
+
+ public static boolean setDumpOnExit(String condition) {
+ for (IMessage.Kind kind : IMessage.KINDS) {
+ if (kind.toString().equals(condition)) {
+ return setDumpOnExit(kind);
+ }
+ }
+ return false;
+ }
+
+ public static IMessage.Kind getDumpOnExit() {
+ return conditionKind;
+ }
+
+ public static String getLastDumpFileName() {
+ return lastDumpFileName;
+ }
+
+ public static void saveCommandLine(String[] args) {
+ savedCommandLine = new String[args.length];
+ System.arraycopy(args, 0, savedCommandLine, 0, args.length);
+ }
+
+ public static void saveFullClasspath(List<String> list) {
+ savedFullClasspath = list;
+ }
+
+ public static void saveMessageHolder(IMessageHolder holder) {
+ savedMessageHolder = holder;
+ }
+
+ // public static void registerNode(Class<?> module, INode newNode) {
+ // if (trace.isTraceEnabled()) {
+ // trace.enter("registerNode", null, new Object[] { module, newNode });
+ // }
+ //
+ // // TODO surely this should preserve the module???? it never has....
+ // nodes.put(newNode, new WeakReference<INode>(newNode));
+ //
+ // if (trace.isTraceEnabled()) {
+ // trace.exit("registerNode", nodes.size());
+ // }
+ // }
+
+ private Dump(String reason) {
+ if (trace.isTraceEnabled()) {
+ trace.enter("<init>", this, reason);
+ }
+
+ this.reason = reason;
+
+ openDump();
+ dumpAspectJProperties();
+ dumpDumpConfiguration();
+
+ if (trace.isTraceEnabled()) {
+ trace.exit("<init>", this);
+ }
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ private void dumpDefault() {
+ dumpDefault(savedMessageHolder);
+ }
+
+ private void dumpDefault(IMessageHolder holder) {
+ dumpSytemProperties();
+ dumpCommandLine();
+ dumpFullClasspath();
+ dumpCompilerMessages(holder);
+
+ // dumpNodes();
+ }
+
+ // private void dumpNodes() {
+ //
+ // IVisitor dumpVisitor = new IVisitor() {
+ //
+ // public void visitObject(Object obj) {
+ // println(formatObj(obj));
+ // }
+ //
+ // public void visitList(List list) {
+ // println(list);
+ // }
+ // };
+ //
+ // Set<INode> keys = nodes.keySet();
+ // for (INode dumpNode : keys) {
+ // println("---- " + formatObj(dumpNode) + " ----");
+ // try {
+ // dumpNode.accept(dumpVisitor);
+ // } catch (Exception ex) {
+ // trace.error(formatObj(dumpNode).toString(), ex);
+ // }
+ // }
+ // }
+
+ private void dumpException(IMessageHolder messageHolder, Throwable th) {
+ println("---- Exception Information ---");
+ println(th);
+ dumpDefault(messageHolder);
+ }
+
+ private void dumpAspectJProperties() {
+ println("---- AspectJ Properties ---");
+ println("AspectJ Compiler " + Version.text + " built on " + Version.time_text);
+ }
+
+ private void dumpDumpConfiguration() {
+ println("---- Dump Properties ---");
+ println("Dump file: " + fileName);
+ println("Dump reason: " + reason);
+ println("Dump on exception: " + (exceptionClass != null));
+ println("Dump at exit condition: " + conditionKind);
+ }
+
+ private void dumpFullClasspath() {
+ println("---- Full Classpath ---");
+ if (savedFullClasspath != null && savedFullClasspath.size() > 0) {
+ for (String fileName : savedFullClasspath) {
+ File file = new File(fileName);
+ println(file);
+ }
+ } else {
+ println(NULL_OR_EMPTY);
+ }
+ }
+
+ private void dumpSytemProperties() {
+ println("---- System Properties ---");
+ Properties props = System.getProperties();
+ println(props);
+ }
+
+ private void dumpCommandLine() {
+ println("---- Command Line ---");
+ println(savedCommandLine);
+ }
+
+ private void dumpCompilerMessages(IMessageHolder messageHolder) {
+ println("---- Compiler Messages ---");
+ if (messageHolder != null) {
+ for (Iterator<IMessage> i = messageHolder.getUnmodifiableListView().iterator(); i.hasNext();) {
+ IMessage message = i.next();
+ println(message.toString());
+ }
+ } else {
+ println(NULL_OR_EMPTY);
+ }
+ }
+
+ /*
+ * Dump output
+ */
+ private void openDump() {
+ if (print != null) {
+ return;
+ }
+
+ Date now = new Date();
+ fileName = FILENAME_PREFIX + "." + new SimpleDateFormat("yyyyMMdd").format(now) + "."
+ + new SimpleDateFormat("HHmmss.SSS").format(now) + "." + FILENAME_SUFFIX;
+ try {
+ File file = new File(directory, fileName);
+ print = new PrintStream(new FileOutputStream(file), true);
+ trace.info("Dumping to " + file.getAbsolutePath());
+ } catch (Exception ex) {
+ print = System.err;
+ trace.info("Dumping to stderr");
+ fileName = UNKNOWN_FILENAME;
+ }
+
+ lastDumpFileName = fileName;
+ }
+
+ public void close() {
+ print.close();
+ }
+
+ private void println(Object obj) {
+ print.println(obj);
+ }
+
+ private void println(Object[] array) {
+ if (array == null) {
+ println(NULL_OR_EMPTY);
+ return;
+ }
+
+ for (int i = 0; i < array.length; i++) {
+ print.println(array[i]);
+ }
+ }
+
+ private void println(Properties props) {
+ Iterator iter = props.keySet().iterator();
+ while (iter.hasNext()) {
+ String key = (String) iter.next();
+ String value = props.getProperty(key);
+ print.println(key + "=" + value);
+ }
+ }
+
+ private void println(Throwable th) {
+ th.printStackTrace(print);
+ }
+
+ private void println(File file) {
+ print.print(file.getAbsolutePath());
+ if (!file.exists()) {
+ println("(missing)");
+ } else if (file.isDirectory()) {
+ int count = file.listFiles().length;
+ println("(" + count + " entries)");
+ } else {
+ println("(" + file.length() + " bytes)");
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private void println(List list) {
+ if (list == null || list.isEmpty()) {
+ println(NULL_OR_EMPTY);
+ } else {
+ for (Iterator i = list.iterator(); i.hasNext();) {
+ Object o = i.next();
+ if (o instanceof Exception) {
+ println((Exception) o);
+ } else {
+ println(o.toString());
+ }
+ }
+ }
+ }
+
+ private static Object formatObj(Object obj) {
+
+ /* These classes have a safe implementation of toString() */
+ if (obj == null || obj instanceof String || obj instanceof Number || obj instanceof Boolean || obj instanceof Exception
+ || obj instanceof Character || obj instanceof Class || obj instanceof File || obj instanceof StringBuffer
+ || obj instanceof URL) {
+ return obj;
+ } else {
+ try {
+
+ /* Classes can provide an alternative implementation of toString() */
+ if (obj instanceof Traceable) {
+ Traceable t = (Traceable) obj;
+ return t.toTraceString();
+ } else {
+ return obj.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(obj));
+ }
+
+ /* Object.hashCode() can be override and may thow an exception */
+ } catch (Exception ex) {
+ return obj.getClass().getName() + "@FFFFFFFF";
+ }
+ }
+ }
+
+ static {
+ String exceptionName = System.getProperty("org.aspectj.weaver.Dump.exception", "true");
+ if (!exceptionName.equals("false")) {
+ setDumpOnException(true);
+ }
+
+ String conditionName = System.getProperty(DUMP_CONDITION_PROPERTY);
+ if (conditionName != null) {
+ setDumpOnExit(conditionName);
+ }
+
+ String directoryName = System.getProperty(DUMP_DIRECTORY_PROPERTY);
+ if (directoryName != null) {
+ setDumpDirectory(directoryName);
+ }
+ }
+
+ public interface INode {
+
+ public void accept(IVisitor visior);
+
+ }
+
+ public interface IVisitor {
+
+ public void visitObject(Object s);
+
+ public void visitList(List list);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/EnumAnnotationValue.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/EnumAnnotationValue.java
new file mode 100644
index 000000000..f15968b8d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/EnumAnnotationValue.java
@@ -0,0 +1,41 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+public class EnumAnnotationValue extends AnnotationValue {
+
+ private String typeSignature;
+ private String value;
+
+ public EnumAnnotationValue(String typeSignature, String value) {
+ super(AnnotationValue.ENUM_CONSTANT);
+ this.typeSignature = typeSignature;
+ this.value = value;
+ }
+
+ public String getType() {
+ return typeSignature;
+ }
+
+ public String stringify() {
+ return typeSignature+value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String toString() {
+ return "E(" + typeSignature + " " + value + ")";
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ExposeTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ExposeTypeMunger.java
new file mode 100644
index 000000000..f5b842011
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ExposeTypeMunger.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * Copyright (c) 2007 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement, IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Special kind of privileged access munger which exposes a type to be public.
+ */
+public class ExposeTypeMunger extends PrivilegedAccessMunger {
+
+ public ExposeTypeMunger(UnresolvedType typeToExpose) {
+ super(new ResolvedMemberImpl(Member.STATIC_INITIALIZATION, typeToExpose, 0, UnresolvedType.VOID, "<clinit>",
+ UnresolvedType.NONE), false);
+ }
+
+ public String toString() {
+ return "ExposeTypeMunger(" + getSignature().getDeclaringType().getName() + ")";
+ }
+
+ public String getExposedTypeSignature() {
+ return getSignature().getDeclaringType().getSignature();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/GeneratedReferenceTypeDelegate.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/GeneratedReferenceTypeDelegate.java
new file mode 100644
index 000000000..5d08467d0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/GeneratedReferenceTypeDelegate.java
@@ -0,0 +1,155 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Collection;
+
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.PerClause;
+
+/**
+ * A delegate that can sit in the ReferenceType instance created for an aspect generated from aop.xml. Only answers the minimal set
+ * of information required as the type is processed.
+ *
+ * @author Andy Clement
+ */
+public class GeneratedReferenceTypeDelegate extends AbstractReferenceTypeDelegate {
+
+ private ResolvedType superclass;
+
+ public GeneratedReferenceTypeDelegate(ReferenceType backing) {
+ super(backing, false);
+ }
+
+ public boolean isAspect() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isAnnotationStyleAspect() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isInterface() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isEnum() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isAnnotation() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isAnnotationWithRuntimeRetention() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isAnonymous() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isNested() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public ResolvedType getOuterClass() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public String getRetentionPolicy() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean canAnnotationTargetType() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public AnnotationTargetKind[] getAnnotationTargetKinds() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean isGeneric() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public String getDeclaredGenericSignature() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public AnnotationAJ[] getAnnotations() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public boolean hasAnnotations() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public ResolvedType[] getAnnotationTypes() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public ResolvedMember[] getDeclaredFields() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public ResolvedType[] getDeclaredInterfaces() {
+ return ResolvedType.NONE;
+ }
+
+ public ResolvedMember[] getDeclaredMethods() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public ResolvedMember[] getDeclaredPointcuts() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public PerClause getPerClause() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public Collection<Declare> getDeclares() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public Collection<ConcreteTypeMunger> getTypeMungers() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public Collection<ResolvedMember> getPrivilegedAccesses() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public int getModifiers() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public void setSuperclass(ResolvedType superclass) {
+ this.superclass = superclass;
+ }
+
+ public ResolvedType getSuperclass() {
+ return this.superclass;
+ }
+
+ public WeaverStateInfo getWeaverState() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+ public TypeVariable[] getTypeVariables() {
+ throw new UnsupportedOperationException("Not supported for GeneratedReferenceTypeDelegate");
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IClassWeaver.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IClassWeaver.java
new file mode 100644
index 000000000..ad65eedf9
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IClassWeaver.java
@@ -0,0 +1,28 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+/**
+ * An IClassWeaver is initialized with a class (a type, really, but let's ignore that for now) and a world, and has one method that
+ * actually weaves the contents of the world into the class implementation.
+ */
+
+public interface IClassWeaver {
+
+ /**
+ * perform the weaving.
+ *
+ * @return <code>true</code> if the class is changed by the weaving, <code>false</code> otherwise.
+ */
+ boolean weave();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ICrossReferenceHandler.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ICrossReferenceHandler.java
new file mode 100644
index 000000000..e38338ae1
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ICrossReferenceHandler.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver;
+
+import org.aspectj.bridge.ISourceLocation;
+
+/**
+ * Clients can pass a single cross-reference handler to the weaver on construction of a BcelWorld. Any cross-references detected
+ * during munging will be notified to the handler.
+ */
+public interface ICrossReferenceHandler {
+
+ void addCrossReference(ISourceLocation from, ISourceLocation to, String kind, boolean runtimeTest);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IEclipseSourceContext.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IEclipseSourceContext.java
new file mode 100644
index 000000000..d691c503d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IEclipseSourceContext.java
@@ -0,0 +1,15 @@
+/********************************************************************
+ * Copyright (c) 2006 Contributors. All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: IBM Corporation - initial API and implementation
+ * Helen Hawkins - iniital version
+ *******************************************************************/
+package org.aspectj.weaver;
+
+public interface IEclipseSourceContext extends ISourceContext {
+ public void removeUnnecessaryProblems(Member method, int problemLineNumber);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasPosition.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasPosition.java
new file mode 100644
index 000000000..8efb55828
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasPosition.java
@@ -0,0 +1,32 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+public interface IHasPosition {
+ /**
+ * The starting index of this location in the character stream.
+ */
+ int getStart();
+
+ /**
+ * The ending index of this location in the character stream
+ *
+ * This points to the last character in this token.
+ *
+ * If a location truly had no contents, then start == end + 1. We don't recommend this.
+ */
+ int getEnd();
+ //
+ // String getFileName();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasSourceLocation.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasSourceLocation.java
new file mode 100644
index 000000000..5b011f246
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IHasSourceLocation.java
@@ -0,0 +1,21 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import org.aspectj.bridge.ISourceLocation;
+
+public interface IHasSourceLocation extends IHasPosition {
+ ISourceContext getSourceContext();
+
+ ISourceLocation getSourceLocation();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ISourceContext.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ISourceContext.java
new file mode 100644
index 000000000..0f2f0aba1
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ISourceContext.java
@@ -0,0 +1,25 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import org.aspectj.bridge.ISourceLocation;
+
+public interface ISourceContext {
+ public ISourceLocation makeSourceLocation(IHasPosition position);
+
+ public ISourceLocation makeSourceLocation(int line, int offset);
+
+ public int getOffset();
+
+ public void tidy();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IUnwovenClassFile.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IUnwovenClassFile.java
new file mode 100644
index 000000000..85ab7a16d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IUnwovenClassFile.java
@@ -0,0 +1,27 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * History: 246125
+ *
+ * @author Andy Clement
+ */
+public interface IUnwovenClassFile {
+
+ String getFilename();
+
+ String getClassName();
+
+ byte[] getBytes();
+
+ char[] getClassNameAsChars();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeaveRequestor.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeaveRequestor.java
new file mode 100644
index 000000000..60037c2e6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeaveRequestor.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * @author colyer
+ *
+ * This interface is implemented by clients driving weaving through the IClassFileProvider interface. It is used by the
+ * weaver to return woven class file results back to the client. The client can correlate weave results with inputs since it
+ * knows the last UnwovenClassFile returned by its iterator.
+ */
+public interface IWeaveRequestor {
+
+ /*
+ * A class file resulting from a weave (yes, even though the type name says "unwoven"...).
+ */
+ void acceptResult(IUnwovenClassFile result);
+
+ // various notifications to the requestor about our progress...
+ void processingReweavableState();
+
+ void addingTypeMungers();
+
+ void weavingAspects();
+
+ void weavingClasses();
+
+ void weaveCompleted();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeavingSupport.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeavingSupport.java
new file mode 100644
index 000000000..3f259c66c
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IWeavingSupport.java
@@ -0,0 +1,45 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import org.aspectj.weaver.ast.Var;
+import org.aspectj.weaver.patterns.PerClause;
+import org.aspectj.weaver.patterns.Pointcut;
+
+/**
+ * Encapsulates operations that a world will need to support if it is actually going to modify bytecode rather than just match
+ * against it. {@see BcelWeavingSupport}
+ *
+ * @author Andy Clement
+ */
+public interface IWeavingSupport {
+
+ public Advice createAdviceMunger(AjAttribute.AdviceAttribute attribute, Pointcut pointcut, Member signature,
+ ResolvedType concreteAspect);
+
+ public abstract ConcreteTypeMunger makeCflowStackFieldAdder(ResolvedMember cflowField);
+
+ public abstract ConcreteTypeMunger makeCflowCounterFieldAdder(ResolvedMember cflowField);
+
+ /**
+ * Register a munger for perclause @AJ aspect so that we add aspectOf(..) to them as needed
+ *
+ * @see org.aspectj.weaver.bcel.BcelWorld#makePerClauseAspect(ResolvedType, org.aspectj.weaver.patterns.PerClause.Kind)
+ */
+ public abstract ConcreteTypeMunger makePerClauseAspect(ResolvedType aspect, PerClause.Kind kind);
+
+ public abstract ConcreteTypeMunger concreteTypeMunger(ResolvedTypeMunger munger, ResolvedType aspectType);
+
+ public ConcreteTypeMunger createAccessForInlineMunger(ResolvedType inAspect);
+
+ public Var makeCflowAccessVar(ResolvedType formalType, Member cflowField, int arrayIndex);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IntMap.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IntMap.java
new file mode 100644
index 000000000..c0af738ba
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/IntMap.java
@@ -0,0 +1,150 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class IntMap {
+ // public static final IntMap EMPTY = new IntMap(0) {
+ // public boolean directlyInAdvice() { return true; }
+ // public ShadowMunger getEnclosingAdvice() { return null; } //XXX possible
+ // };
+
+ // XXX begin hack to avoid a signature refactoring in Pointcut
+ private ResolvedType concreteAspect;
+ private ShadowMunger enclosingAdvice;
+ private List<ResolvedPointcutDefinition> enclosingDefinition = new ArrayList<ResolvedPointcutDefinition>();
+
+ public void pushEnclosingDefinition(ResolvedPointcutDefinition def) {
+ enclosingDefinition.add(def);
+ }
+
+ public void popEnclosingDefinitition() {
+ enclosingDefinition.remove(enclosingDefinition.size() - 1);
+ }
+
+ public ResolvedPointcutDefinition peekEnclosingDefinition() {
+ if (enclosingDefinition.size() == 0) {
+ return null;
+ }
+ return enclosingDefinition.get(enclosingDefinition.size() - 1);
+ }
+
+ public boolean directlyInAdvice() {
+ return enclosingDefinition.isEmpty();
+ }
+
+ public ShadowMunger getEnclosingAdvice() {
+ return enclosingAdvice;
+ }
+
+ public void setEnclosingAdvice(ShadowMunger advice) {
+ this.enclosingAdvice = advice;
+ }
+
+ public Member getAdviceSignature() {
+ if (enclosingAdvice instanceof Advice) {
+ return ((Advice) enclosingAdvice).getSignature();
+ } else {
+ return null;
+ }
+ }
+
+ public ResolvedType getConcreteAspect() {
+ return concreteAspect;
+ }
+
+ public void setConcreteAspect(ResolvedType concreteAspect) {
+ this.concreteAspect = concreteAspect;
+ }
+
+ public void copyContext(IntMap bindings) {
+ this.enclosingAdvice = bindings.enclosingAdvice;
+ this.enclosingDefinition = bindings.enclosingDefinition;
+ this.concreteAspect = bindings.concreteAspect;
+ }
+
+ // XXX end hack to avoid a signature refactoring in Pointcut
+
+ private static final int MISSING = -1;
+
+ private int[] map;
+
+ private IntMap(int[] map) {
+ this.map = map;
+ }
+
+ public IntMap() {
+ map = new int[0];
+ }
+
+ public IntMap(int initialCapacity) {
+ map = new int[initialCapacity];
+ for (int i = 0; i < initialCapacity; i++) {
+ map[i] = MISSING;
+ }
+ }
+
+ public void put(int key, int val) {
+ /* assert (val >= 0 && key >= 0) */
+ if (key >= map.length) {
+ int[] tmp = new int[key * 2 + 1]; // ??? better expansion function
+ System.arraycopy(map, 0, tmp, 0, map.length);
+ for (int i = map.length, len = tmp.length; i < len; i++) {
+ tmp[i] = MISSING;
+ }
+ map = tmp;
+ }
+ map[key] = val;
+ }
+
+ public int get(int key) {
+ return map[key];
+ }
+
+ public boolean hasKey(int key) {
+ return (key < map.length && map[key] != MISSING);
+ }
+
+ // ---- factory methods
+
+ public static IntMap idMap(int size) {
+ int[] map = new int[size];
+ for (int i = 0; i < size; i++) {
+ map[i] = i;
+ }
+ return new IntMap(map);
+ }
+
+ // ---- from object
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("[");
+ boolean seenFirst = false;
+ for (int i = 0, len = map.length; i < len; i++) {
+ if (map[i] != MISSING) {
+ if (seenFirst) {
+ buf.append(", ");
+ }
+ seenFirst = true;
+ buf.append(i);
+ buf.append(" -> ");
+ buf.append(map[i]);
+ }
+ }
+ buf.append("]");
+ return buf.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Iterators.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Iterators.java
new file mode 100644
index 000000000..1a2e82006
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Iterators.java
@@ -0,0 +1,359 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+public final class Iterators {
+
+ /**
+ * Private constructor, nobody should ever make one of these
+ */
+ private Iterators() {
+ }
+
+ /**
+ * A getter represents a mapping function from Object to Iterator
+ */
+ public interface Getter<A, B> {
+ Iterator<B> get(A target);
+ }
+
+ /**
+ * A filter represents a mapping function from Iterator to Iterator
+ */
+ public interface Filter<T> {
+ Iterator<T> filter(Iterator<T> in);
+ }
+
+ /**
+ * Create a new filter F that, when wrapped around another iterator I, creates a new iterator I' that will return only those
+ * values of I that have not yet been returned by I', discarding duplicates.
+ */
+ public static <T> Filter<T> dupFilter() {
+ return new Filter<T>() {
+ final Set<T> seen = new HashSet<T>(); // should have weak ptrs?
+
+ public Iterator<T> filter(final Iterator<T> in) {
+ return new Iterator<T>() {
+ boolean fresh = false;
+ T peek;
+
+ public boolean hasNext() {
+ if (fresh) {
+ return true;
+ }
+ while (true) {
+ if (!in.hasNext()) {
+ return false;
+ }
+ peek = in.next();
+ if (!seen.contains(peek)) {
+ fresh = true;
+ return true;
+ } else {
+ peek = null; // garbage collection
+ }
+ }
+ }
+
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ T ret = peek;
+ seen.add(peek);
+ peek = null;
+ fresh = false;
+ return ret;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Creates an iterator that will return the elements of a specified array, in order. Like Arrays.asList(o).iterator(), without
+ * all that pesky safety.
+ */
+
+ public static <T> Iterator<T> array(final T[] o) {
+ return new Iterator<T>() {
+ int i = 0;
+ int len = (o == null) ? 0 : o.length;
+
+ public boolean hasNext() {
+ return i < len;
+ }
+
+ public T next() {
+ if (i < len) {
+ return o[i++];
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public static class ResolvedTypeArrayIterator implements Iterator<ResolvedType> {
+ private ResolvedType[] array;
+ private int index;
+ private int len;
+ private boolean wantGenerics;
+ private List<String> alreadySeen; // type signatures
+
+ public ResolvedTypeArrayIterator(ResolvedType[] array, List<String> alreadySeen, boolean wantGenerics) {
+ assert array != null;
+ this.array = array;
+ this.wantGenerics = wantGenerics;
+ this.len = array.length;
+ this.index = 0;
+ this.alreadySeen = alreadySeen;
+ moveToNextNewOne();
+ }
+
+ private void moveToNextNewOne() {
+ while (index < len) {
+ ResolvedType interfaceType = array[index];
+ if (!wantGenerics && interfaceType.isParameterizedOrGenericType()) {
+ interfaceType = interfaceType.getRawType();
+ }
+ String signature = interfaceType.getSignature();
+ if (!alreadySeen.contains(signature)) {
+ break;
+ }
+ index++;
+ }
+ }
+
+ public boolean hasNext() {
+ return index < len;
+ }
+
+ public ResolvedType next() {
+ if (index < len) {
+ ResolvedType oo = array[index++];
+ if (!wantGenerics && (oo.isParameterizedType() || oo.isGenericType())) {
+ oo = oo.getRawType();
+ }
+ alreadySeen.add(oo.getSignature());
+ moveToNextNewOne();
+ return oo;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static Iterator<ResolvedType> array(final ResolvedType[] o, final boolean genericsAware) {
+ return new Iterator<ResolvedType>() {
+ int i = 0;
+ int len = (o == null) ? 0 : o.length;
+
+ public boolean hasNext() {
+ return i < len;
+ }
+
+ public ResolvedType next() {
+ if (i < len) {
+ ResolvedType oo = o[i++];
+ if (!genericsAware && (oo.isParameterizedType() || oo.isGenericType())) {
+ return oo.getRawType();
+ }
+ return oo;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * creates an iterator I based on a base iterator A and a getter G. I returns, in order, forall (i in A), G(i).
+ */
+ public static <A, B> Iterator<B> mapOver(final Iterator<A> a, final Getter<A, B> g) {
+ return new Iterator<B>() {
+ Iterator<B> delegate = new Iterator<B>() {
+ public boolean hasNext() {
+ if (!a.hasNext()) {
+ return false;
+ }
+ A o = a.next();
+ delegate = append1(g.get(o), this);
+ return delegate.hasNext();
+ }
+
+ public B next() {
+ if (!hasNext()) {
+ throw new UnsupportedOperationException();
+ }
+ return delegate.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ public B next() {
+ return delegate.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * creates an iterator I based on a base iterator A and a getter G. I returns, in order, forall (i in I) i :: forall (i' in
+ * g(i)) recur(i', g)
+ */
+ public static <A> Iterator<A> recur(final A a, final Getter<A, A> g) {
+ return new Iterator<A>() {
+ Iterator<A> delegate = one(a);
+
+ public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ public A next() {
+ A next = delegate.next();
+ delegate = append(g.get(next), delegate);
+ return next;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * creates an iterator I based on base iterators A and B. Returns the elements returned by A followed by those returned by B. If
+ * B is empty, simply returns A, and if A is empty, simply returns B. Do NOT USE if b.hasNext() is not idempotent.
+ */
+ public static <T> Iterator<T> append(final Iterator<T> a, final Iterator<T> b) {
+ if (!b.hasNext()) {
+ return a;
+ }
+ return append1(a, b);
+ }
+
+ /**
+ * creates an iterator I based on base iterators A and B. Returns the elements returned by A followed by those returned by B. If
+ * A is empty, simply returns B. Guaranteed not to call B.hasNext() until A is empty.
+ */
+ public static <T> Iterator<T> append1(final Iterator<T> a, final Iterator<T> b) {
+ if (!a.hasNext()) {
+ return b;
+ }
+ return new Iterator<T>() {
+ public boolean hasNext() {
+ return a.hasNext() || b.hasNext();
+ }
+
+ public T next() {
+ if (a.hasNext()) {
+ return a.next();
+ }
+ if (b.hasNext()) {
+ return b.next();
+ }
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * creates an iterator I based on a base iterator A and an object O. Returns the elements returned by A, followed by O.
+ */
+ public static <T> Iterator<T> snoc(final Iterator<T> first, final T last) {
+ return new Iterator<T>() {
+ T last1 = last;
+
+ public boolean hasNext() {
+ return first.hasNext() || last1 != null;
+ }
+
+ public T next() {
+ if (first.hasNext()) {
+ return first.next();
+ } else if (last1 == null) {
+ throw new NoSuchElementException();
+ }
+ T ret = last1;
+ last1 = null;
+ return ret;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * creates an iterator I based on an object O. Returns O, once.
+ */
+ public static <T> Iterator<T> one(final T it) {
+ return new Iterator<T>() {
+ boolean avail = true;
+
+ public boolean hasNext() {
+ return avail;
+ }
+
+ public T next() {
+ if (!avail) {
+ throw new NoSuchElementException();
+ }
+ avail = false;
+ return it;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignature.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignature.java
new file mode 100644
index 000000000..57171dd13
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignature.java
@@ -0,0 +1,378 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.AjAttribute.EffectiveSignatureAttribute;
+
+/**
+ * @author colyer Instances of this class are created by ResolvedMember.getSignatures() when collating all of the signatures for a
+ * member. We need to create entries in the set for the "gaps" in the hierarchy. For example:
+ *
+ * class A { void foo(); }
+ *
+ * class B extends A {}
+ *
+ * Join Point : call(* B.foo())
+ *
+ * has signatures:
+ *
+ * B.foo() AND A.foo() B.foo() will be created as a ResolvedMemberWithSubstituteDeclaringType
+ *
+ * Oh for a JDK 1.4 dynamic proxy.... we have to run on 1.3 :(
+ */
+public class JoinPointSignature implements ResolvedMember {
+
+ public static final JoinPointSignature[] EMPTY_ARRAY = new JoinPointSignature[0];
+
+ private ResolvedMember realMember;
+ private ResolvedType substituteDeclaringType;
+
+ public JoinPointSignature(ResolvedMember backing, ResolvedType aType) {
+ this.realMember = backing;
+ this.substituteDeclaringType = aType;
+ }
+
+ public UnresolvedType getDeclaringType() {
+ return substituteDeclaringType;
+ }
+
+ public int getModifiers(World world) {
+ return realMember.getModifiers(world);
+ }
+
+ public int getModifiers() {
+ return realMember.getModifiers();
+ }
+
+ public UnresolvedType[] getExceptions(World world) {
+ return realMember.getExceptions(world);
+ }
+
+ public UnresolvedType[] getExceptions() {
+ return realMember.getExceptions();
+ }
+
+ public ShadowMunger getAssociatedShadowMunger() {
+ return realMember.getAssociatedShadowMunger();
+ }
+
+ public boolean isAjSynthetic() {
+ return realMember.isAjSynthetic();
+ }
+
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ return realMember.hasAnnotation(ofType);
+ }
+
+ public ResolvedType[] getAnnotationTypes() {
+ return realMember.getAnnotationTypes();
+ }
+
+ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
+ return realMember.getAnnotationOfType(ofType);
+ }
+
+ public void setAnnotationTypes(ResolvedType[] annotationtypes) {
+ realMember.setAnnotationTypes(annotationtypes);
+ }
+
+ public void setAnnotations(AnnotationAJ[] annotations) {
+ realMember.setAnnotations(annotations);
+ }
+
+ public void addAnnotation(AnnotationAJ annotation) {
+ realMember.addAnnotation(annotation);
+ }
+
+ public boolean isBridgeMethod() {
+ return realMember.isBridgeMethod();
+ }
+
+ public boolean isVarargsMethod() {
+ return realMember.isVarargsMethod();
+ }
+
+ public boolean isSynthetic() {
+ return realMember.isSynthetic();
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ realMember.write(s);
+ }
+
+ public ISourceContext getSourceContext(World world) {
+ return realMember.getSourceContext(world);
+ }
+
+ public String[] getParameterNames() {
+ return realMember.getParameterNames();
+ }
+
+ public void setParameterNames(String[] names) {
+ realMember.setParameterNames(names);
+ }
+
+ public String[] getParameterNames(World world) {
+ return realMember.getParameterNames(world);
+ }
+
+ public EffectiveSignatureAttribute getEffectiveSignature() {
+ return realMember.getEffectiveSignature();
+ }
+
+ public ISourceLocation getSourceLocation() {
+ return realMember.getSourceLocation();
+ }
+
+ public int getEnd() {
+ return realMember.getEnd();
+ }
+
+ public ISourceContext getSourceContext() {
+ return realMember.getSourceContext();
+ }
+
+ public int getStart() {
+ return realMember.getStart();
+ }
+
+ public void setPosition(int sourceStart, int sourceEnd) {
+ realMember.setPosition(sourceStart, sourceEnd);
+ }
+
+ public void setSourceContext(ISourceContext sourceContext) {
+ realMember.setSourceContext(sourceContext);
+ }
+
+ public boolean isAbstract() {
+ return realMember.isAbstract();
+ }
+
+ public boolean isPublic() {
+ return realMember.isPublic();
+ }
+
+ public boolean isDefault() {
+ return realMember.isDefault();
+ }
+
+ public boolean isVisible(ResolvedType fromType) {
+ return realMember.isVisible(fromType);
+ }
+
+ public void setCheckedExceptions(UnresolvedType[] checkedExceptions) {
+ realMember.setCheckedExceptions(checkedExceptions);
+ }
+
+ public void setAnnotatedElsewhere(boolean b) {
+ realMember.setAnnotatedElsewhere(b);
+ }
+
+ public boolean isAnnotatedElsewhere() {
+ return realMember.isAnnotatedElsewhere();
+ }
+
+ public UnresolvedType getGenericReturnType() {
+ return realMember.getGenericReturnType();
+ }
+
+ public UnresolvedType[] getGenericParameterTypes() {
+ return realMember.getGenericParameterTypes();
+ }
+
+ public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
+ boolean isParameterized) {
+ return realMember.parameterizedWith(typeParameters, newDeclaringType, isParameterized);
+ }
+
+ public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
+ boolean isParameterized, List<String> aliases) {
+ return realMember.parameterizedWith(typeParameters, newDeclaringType, isParameterized, aliases);
+ }
+
+ public void setTypeVariables(TypeVariable[] types) {
+ realMember.setTypeVariables(types);
+ }
+
+ public TypeVariable[] getTypeVariables() {
+ return realMember.getTypeVariables();
+ }
+
+ public TypeVariable getTypeVariableNamed(String name) {
+ return realMember.getTypeVariableNamed(name);
+ }
+
+ public boolean matches(ResolvedMember aCandidateMatch, boolean ignoreGenerics) {
+ return realMember.matches(aCandidateMatch, ignoreGenerics);
+ }
+
+ public ResolvedMember resolve(World world) {
+ return realMember.resolve(world);
+ }
+
+ public int compareTo(Member other) {
+ return realMember.compareTo(other);
+ }
+
+ public MemberKind getKind() {
+ return realMember.getKind();
+ }
+
+ public UnresolvedType getReturnType() {
+ return realMember.getReturnType();
+ }
+
+ public UnresolvedType getType() {
+ return realMember.getType();
+ }
+
+ public String getName() {
+ return realMember.getName();
+ }
+
+ public UnresolvedType[] getParameterTypes() {
+ return realMember.getParameterTypes();
+ }
+
+ public AnnotationAJ[][] getParameterAnnotations() {
+ return realMember.getParameterAnnotations();
+ }
+
+ public ResolvedType[][] getParameterAnnotationTypes() {
+ return realMember.getParameterAnnotationTypes();
+ }
+
+ public String getSignature() {
+ return realMember.getSignature();
+ }
+
+ public int getArity() {
+ return realMember.getArity();
+ }
+
+ public String getParameterSignature() {
+ return realMember.getParameterSignature();
+ }
+
+ public boolean isCompatibleWith(Member am) {
+ return realMember.isCompatibleWith(am);
+ }
+
+ public boolean canBeParameterized() {
+ return realMember.canBeParameterized();
+ }
+
+ public AnnotationAJ[] getAnnotations() {
+ return realMember.getAnnotations();
+ }
+
+ public Collection<ResolvedType> getDeclaringTypes(World world) {
+ throw new UnsupportedOperationException("Adrian doesn't think you should be calling this...");
+ }
+
+ public JoinPointSignatureIterator getJoinPointSignatures(World world) {
+ return realMember.getJoinPointSignatures(world);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(getReturnType().getName());
+ buf.append(' ');
+ buf.append(getDeclaringType().getName());
+ buf.append('.');
+ buf.append(getName());
+ if (getKind() != FIELD) {
+ buf.append("(");
+ UnresolvedType[] parameterTypes = getParameterTypes();
+ if (parameterTypes.length != 0) {
+ buf.append(parameterTypes[0]);
+ for (int i = 1, len = parameterTypes.length; i < len; i++) {
+ buf.append(", ");
+ buf.append(parameterTypes[i].getName());
+ }
+ }
+ buf.append(")");
+ }
+ return buf.toString();
+ }
+
+ public String toGenericString() {
+ return realMember.toGenericString();
+ }
+
+ public String toDebugString() {
+ return realMember.toDebugString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof JoinPointSignature)) {
+ return false;
+ }
+ JoinPointSignature other = (JoinPointSignature) obj;
+ if (!realMember.equals(other.realMember)) {
+ return false;
+ }
+ if (!substituteDeclaringType.equals(other.substituteDeclaringType)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return 17 + (37 * realMember.hashCode()) + (37 * substituteDeclaringType.hashCode());
+ }
+
+ public boolean hasBackingGenericMember() {
+ return realMember.hasBackingGenericMember();
+ }
+
+ public ResolvedMember getBackingGenericMember() {
+ return realMember.getBackingGenericMember();
+ }
+
+ public void evictWeavingState() {
+ realMember.evictWeavingState();
+ }
+
+ public ResolvedMember parameterizedWith(Map m, World w) {
+ return realMember.parameterizedWith(m, w);
+ }
+
+ public String getAnnotationDefaultValue() {
+ return realMember.getAnnotationDefaultValue();
+ }
+
+ public String getParameterSignatureErased() {
+ return realMember.getParameterSignatureErased();
+ }
+
+ public String getSignatureErased() {
+ return realMember.getSignatureErased();
+ }
+
+ public boolean isDefaultConstructor() {
+ return realMember.isDefaultConstructor();
+ }
+
+ public boolean equalsApartFromDeclaringType(Object other) {
+ return realMember.equalsApartFromDeclaringType(other);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignatureIterator.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignatureIterator.java
new file mode 100644
index 000000000..50332c1c0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/JoinPointSignatureIterator.java
@@ -0,0 +1,281 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * Iterates over the signatures of a join point, calculating new signatures lazily to minimize processing and to avoid unneccessary
+ * "can't find type" errors. Iterator can be cached and reused by calling the "reset" method between iterations.
+ */
+public class JoinPointSignatureIterator implements Iterator<JoinPointSignature> {
+
+ ResolvedType firstDefiningType;
+
+ private Member signaturesOfMember;
+ private ResolvedMember firstDefiningMember;
+ private World world;
+ private List<JoinPointSignature> discoveredSignatures = new ArrayList<JoinPointSignature>();
+ private List<JoinPointSignature> additionalSignatures = Collections.emptyList();
+ private Iterator<JoinPointSignature> discoveredSignaturesIterator = null;
+ private Iterator<ResolvedType> superTypeIterator = null;
+ private boolean isProxy = false;
+ private Set<ResolvedType> visitedSuperTypes = new HashSet<ResolvedType>();
+ private List<SearchPair> yetToBeProcessedSuperMembers = null;
+
+ private boolean iteratingOverDiscoveredSignatures = true;
+ private boolean couldBeFurtherAsYetUndiscoveredSignatures = true;
+ private final static UnresolvedType jlrProxy = UnresolvedType.forSignature("Ljava/lang/reflect/Proxy;");
+
+ public JoinPointSignatureIterator(Member joinPointSignature, World world) {
+ this.signaturesOfMember = joinPointSignature;
+ this.world = world;
+ addSignaturesUpToFirstDefiningMember();
+ if (!shouldWalkUpHierarchy()) {
+ couldBeFurtherAsYetUndiscoveredSignatures = false;
+ }
+ }
+
+ public void reset() {
+ discoveredSignaturesIterator = discoveredSignatures.iterator();
+ additionalSignatures.clear();
+ iteratingOverDiscoveredSignatures = true;
+ }
+
+ public boolean hasNext() {
+ if (iteratingOverDiscoveredSignatures && discoveredSignaturesIterator.hasNext()) {
+ return true;
+ } else if (couldBeFurtherAsYetUndiscoveredSignatures) {
+ if (additionalSignatures.size() > 0) {
+ return true;
+ } else {
+ return findSignaturesFromSupertypes();
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public JoinPointSignature next() {
+ if (iteratingOverDiscoveredSignatures && discoveredSignaturesIterator.hasNext()) {
+ return discoveredSignaturesIterator.next();
+ } else {
+ if (additionalSignatures.size() > 0) {
+ return additionalSignatures.remove(0);
+ }
+ }
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("can't remove from JoinPointSignatureIterator");
+ }
+
+ /**
+ * Walk up the hierarchy creating one member for each type up to and including the first defining type.
+ */
+ private void addSignaturesUpToFirstDefiningMember() {
+ ResolvedType originalDeclaringType = signaturesOfMember.getDeclaringType().resolve(world);
+ ResolvedType superType = originalDeclaringType.getSuperclass();
+ if (superType != null && superType.equals(jlrProxy)) {
+ // Proxy types are generated without any regard to generics (pr268419) and so the member walking
+ // should also ignore them
+ isProxy = true;
+ }
+
+ // is it the array constructor join point?
+ if (world.isJoinpointArrayConstructionEnabled() && originalDeclaringType.isArray()) {
+ Member m = signaturesOfMember;
+ ResolvedMember rm = new ResolvedMemberImpl(m.getKind(), m.getDeclaringType(), m.getModifiers(), m.getReturnType(), m
+ .getName(), m.getParameterTypes());
+ discoveredSignatures.add(new JoinPointSignature(rm, originalDeclaringType));
+ couldBeFurtherAsYetUndiscoveredSignatures = false;
+ return;
+ }
+
+ firstDefiningMember = (signaturesOfMember instanceof ResolvedMember ?
+ (ResolvedMember) signaturesOfMember: signaturesOfMember.resolve(world));
+
+ if (firstDefiningMember == null) {
+ couldBeFurtherAsYetUndiscoveredSignatures = false;
+ return;
+ }
+
+ // declaringType can be unresolved if we matched a synthetic member generated by Aj...
+ // should be fixed elsewhere but add this resolve call on the end for now so that we can
+ // focus on one problem at a time...
+ firstDefiningType = firstDefiningMember.getDeclaringType().resolve(world);
+ if (firstDefiningType != originalDeclaringType) {
+ if (signaturesOfMember.getKind() == Member.CONSTRUCTOR) {
+ return;
+ }
+ }
+
+ if (originalDeclaringType == firstDefiningType) {
+ // a common case
+ discoveredSignatures.add(new JoinPointSignature(firstDefiningMember, originalDeclaringType));
+ } else {
+ List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
+ accumulateTypesInBetween(originalDeclaringType, firstDefiningType, declaringTypes);
+ for (ResolvedType declaringType : declaringTypes) {
+ discoveredSignatures.add(new JoinPointSignature(firstDefiningMember, declaringType));
+ }
+ }
+ }
+
+ /**
+ * Build a list containing every type between subtype and supertype, inclusively.
+ */
+ private void accumulateTypesInBetween(ResolvedType subType, ResolvedType superType, List<ResolvedType> types) {
+ types.add(subType);
+ if (subType == superType) {
+ return;
+ } else {
+ for (Iterator<ResolvedType> iter = subType.getDirectSupertypes(); iter.hasNext();) {
+ ResolvedType parent = iter.next();
+ if (superType.isAssignableFrom(parent, true)) {
+ accumulateTypesInBetween(parent, superType, types);
+ }
+ }
+ }
+ }
+
+ private boolean shouldWalkUpHierarchy() {
+ if (signaturesOfMember.getKind() == Member.CONSTRUCTOR) {
+ return false;
+ }
+ if (signaturesOfMember.getKind() == Member.FIELD) {
+ return false;
+ }
+ if (Modifier.isStatic(signaturesOfMember.getModifiers())) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean findSignaturesFromSupertypes() {
+ iteratingOverDiscoveredSignatures = false;
+ if (superTypeIterator == null) {
+ superTypeIterator = firstDefiningType.getDirectSupertypes();
+ }
+ if (superTypeIterator.hasNext()) {
+ ResolvedType superType = superTypeIterator.next();
+ if (isProxy && (superType.isGenericType() || superType.isParameterizedType())) {
+ superType = superType.getRawType();
+ }
+ if (visitedSuperTypes.contains(superType)) {
+ return findSignaturesFromSupertypes();
+ } else {
+ // we haven't looked in this type yet
+ visitedSuperTypes.add(superType);
+ if (superType.isMissing()) {
+ // issue a warning, stop looking for join point signatures in this line
+ warnOnMissingType(superType);
+ return findSignaturesFromSupertypes();
+ }
+ ResolvedMemberImpl foundMember = (ResolvedMemberImpl) superType.lookupResolvedMember(firstDefiningMember, true,
+ isProxy);
+ if (foundMember != null && isVisibleTo(firstDefiningMember, foundMember)) {
+ List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
+ // declaring type can be unresolved if the member can from an ITD...
+ ResolvedType resolvedDeclaringType = foundMember.getDeclaringType().resolve(world);
+ accumulateTypesInBetween(superType, resolvedDeclaringType, declaringTypes);
+ for (ResolvedType declaringType : declaringTypes) {
+ JoinPointSignature member = null;
+ if (isProxy) {
+ if (declaringType.isGenericType() || declaringType.isParameterizedType()) {
+ declaringType = declaringType.getRawType();
+ }
+ }
+ member = new JoinPointSignature(foundMember, declaringType);
+ discoveredSignatures.add(member); // for next time we are reset
+ if (additionalSignatures == Collections.EMPTY_LIST) {
+ additionalSignatures = new ArrayList<JoinPointSignature>();
+ }
+ additionalSignatures.add(member); // for this time
+ }
+ // if this was a parameterized type, look in the generic type that backs it too
+ if (!isProxy && superType.isParameterizedType() && (foundMember.backingGenericMember != null)) {
+ JoinPointSignature member = new JoinPointSignature(foundMember.backingGenericMember,
+ foundMember.declaringType.resolve(world));
+ discoveredSignatures.add(member); // for next time we are reset
+ if (additionalSignatures == Collections.EMPTY_LIST) {
+ additionalSignatures = new ArrayList<JoinPointSignature>();
+ }
+ additionalSignatures.add(member); // for this time
+ }
+ if (yetToBeProcessedSuperMembers == null) {
+ yetToBeProcessedSuperMembers = new ArrayList<SearchPair>();
+ }
+ yetToBeProcessedSuperMembers.add(new SearchPair(foundMember, superType));
+ return true;
+ } else {
+ return findSignaturesFromSupertypes();
+ }
+ }
+ }
+ if (yetToBeProcessedSuperMembers != null && !yetToBeProcessedSuperMembers.isEmpty()) {
+ SearchPair nextUp = yetToBeProcessedSuperMembers.remove(0);
+ firstDefiningType = nextUp.type;
+ firstDefiningMember = nextUp.member;
+ superTypeIterator = null;
+ return findSignaturesFromSupertypes();
+ }
+ couldBeFurtherAsYetUndiscoveredSignatures = false;
+ return false;
+ }
+
+ /**
+ * Returns true if the parent member is visible to the child member In the same declaring type this is always true, otherwise if
+ * parent is private it is false.
+ *
+ * @param childMember
+ * @param parentMember
+ * @return
+ */
+ private boolean isVisibleTo(ResolvedMember childMember, ResolvedMember parentMember) {
+ if (childMember.getDeclaringType().equals(parentMember.getDeclaringType())) {
+ return true;
+ }
+ if (Modifier.isPrivate(parentMember.getModifiers())) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private void warnOnMissingType(ResolvedType missing) {
+ if (missing instanceof MissingResolvedTypeWithKnownSignature) {
+ // which it should be...
+ MissingResolvedTypeWithKnownSignature mrt = (MissingResolvedTypeWithKnownSignature) missing;
+ mrt.raiseWarningOnJoinPointSignature(signaturesOfMember.toString());
+ }
+ }
+
+ private static class SearchPair {
+ public ResolvedMember member;
+ public ResolvedType type;
+
+ public SearchPair(ResolvedMember member, ResolvedType type) {
+ this.member = member;
+ this.type = type;
+ }
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Lint.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Lint.java
new file mode 100644
index 000000000..aab34b8f6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Lint.java
@@ -0,0 +1,355 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.weaver.tools.Trace;
+import org.aspectj.weaver.tools.TraceFactory;
+
+public class Lint {
+ Map<String, Lint.Kind> kinds = new HashMap<String, Lint.Kind>();
+ /* private */World world;
+
+ public final Kind invalidAbsoluteTypeName = new Kind("invalidAbsoluteTypeName", "no match for this type name: {0}");
+
+ public final Kind invalidWildcardTypeName = new Kind("invalidWildcardTypeName", "no match for this type pattern: {0}");
+
+ public final Kind unresolvableMember = new Kind("unresolvableMember", "can not resolve this member: {0}");
+
+ public final Kind typeNotExposedToWeaver = new Kind("typeNotExposedToWeaver",
+ "this affected type is not exposed to the weaver: {0}");
+
+ public final Kind shadowNotInStructure = new Kind("shadowNotInStructure",
+ "the shadow for this join point is not exposed in the structure model: {0}");
+
+ public final Kind unmatchedSuperTypeInCall = new Kind("unmatchedSuperTypeInCall",
+ "does not match because declaring type is {0}, if match desired use target({1})");
+
+ public final Kind unmatchedTargetKind = new Kind("unmatchedTargetKind", "does not match because annotation {0} has @Target{1}");
+
+ public final Kind canNotImplementLazyTjp = new Kind("canNotImplementLazyTjp",
+ "can not implement lazyTjp on this joinpoint {0} because around advice is used");
+
+ public final Kind multipleAdviceStoppingLazyTjp = new Kind("multipleAdviceStoppingLazyTjp",
+ "can not implement lazyTjp at joinpoint {0} because of advice conflicts, see secondary locations to find conflicting advice");
+
+ public final Kind needsSerialVersionUIDField = new Kind("needsSerialVersionUIDField",
+ "serialVersionUID of type {0} needs to be set because of {1}");
+
+ public final Kind serialVersionUIDBroken = new Kind("brokeSerialVersionCompatibility",
+ "serialVersionUID of type {0} is broken because of added field {1}");
+
+ public final Kind noInterfaceCtorJoinpoint = new Kind("noInterfaceCtorJoinpoint",
+ "no interface constructor-execution join point - use {0}+ for implementing classes");
+
+ public final Kind noJoinpointsForBridgeMethods = new Kind(
+ "noJoinpointsForBridgeMethods",
+ "pointcut did not match on the method call to a bridge method. Bridge methods are generated by the compiler and have no join points");
+
+ public final Kind enumAsTargetForDecpIgnored = new Kind("enumAsTargetForDecpIgnored",
+ "enum type {0} matches a declare parents type pattern but is being ignored");
+
+ public final Kind annotationAsTargetForDecpIgnored = new Kind("annotationAsTargetForDecpIgnored",
+ "annotation type {0} matches a declare parents type pattern but is being ignored");
+
+ public final Kind cantMatchArrayTypeOnVarargs = new Kind("cantMatchArrayTypeOnVarargs",
+ "an array type as the last parameter in a signature does not match on the varargs declared method: {0}");
+
+ public final Kind adviceDidNotMatch = new Kind("adviceDidNotMatch", "advice defined in {0} has not been applied");
+
+ public final Kind invalidTargetForAnnotation = new Kind("invalidTargetForAnnotation",
+ "{0} is not a valid target for annotation {1}, this annotation can only be applied to {2}");
+
+ public final Kind elementAlreadyAnnotated = new Kind("elementAlreadyAnnotated",
+ "{0} - already has an annotation of type {1}, cannot add a second instance");
+
+ public final Kind runtimeExceptionNotSoftened = new Kind("runtimeExceptionNotSoftened",
+ "{0} will not be softened as it is already a RuntimeException");
+
+ public final Kind uncheckedArgument = new Kind("uncheckedArgument",
+ "unchecked match of {0} with {1} when argument is an instance of {2} at join point {3}");
+
+ public final Kind uncheckedAdviceConversion = new Kind("uncheckedAdviceConversion",
+ "unchecked conversion when advice applied at shadow {0}, expected {1} but advice uses {2}");
+
+ public final Kind noGuardForLazyTjp = new Kind("noGuardForLazyTjp",
+ "can not build thisJoinPoint lazily for this advice since it has no suitable guard");
+
+ public final Kind noExplicitConstructorCall = new Kind("noExplicitConstructorCall",
+ "inter-type constructor does not contain explicit constructor call: field initializers in the target type will not be executed");
+
+ public final Kind aspectExcludedByConfiguration = new Kind("aspectExcludedByConfiguration",
+ "aspect {0} exluded for class loader {1}");
+
+ public final Kind unorderedAdviceAtShadow = new Kind("unorderedAdviceAtShadow",
+ "at this shadow {0} no precedence is specified between advice applying from aspect {1} and aspect {2}");
+
+ public final Kind swallowedExceptionInCatchBlock = new Kind("swallowedExceptionInCatchBlock",
+ "exception swallowed in catch block");
+
+ public final Kind calculatingSerialVersionUID = new Kind("calculatingSerialVersionUID",
+ "calculated SerialVersionUID for type {0} to be {1}");
+
+ public final Kind nonReweavableTypeEncountered = new Kind("nonReweavableTypeEncountered",
+ "class {0} is already woven and has not been built in reweavable mode");
+
+ // there are a lot of messages in the cant find type family - I'm defining an umbrella lint warning that
+ // allows a user to control their severity (for e.g. ltw or binary weaving)
+ public final Kind cantFindType = new Kind("cantFindType", "{0}");
+
+ public final Kind cantFindTypeAffectingJoinPointMatch = new Kind("cantFindTypeAffectingJPMatch", "{0}");
+
+ public final Kind advisingSynchronizedMethods = new Kind("advisingSynchronizedMethods",
+ "advice matching the synchronized method shadow ''{0}'' will be executed outside the lock rather than inside (compiler limitation)");
+
+ public final Kind mustWeaveXmlDefinedAspects = new Kind(
+ "mustWeaveXmlDefinedAspects",
+ "XML Defined aspects must be woven in cases where cflow pointcuts are involved. Currently the include/exclude patterns exclude ''{0}''");
+
+ public final Kind cannotAdviseJoinpointInInterfaceWithAroundAdvice = new Kind(
+ "cannotAdviseJoinpointInInterfaceWithAroundAdvice",
+ "The joinpoint ''{0}'' cannot be advised and is being skipped as the compiler implementation will lead to creation of methods with bodies in an interface (compiler limitation)");
+
+ /**
+ * Indicates an aspect could not be found when attempting reweaving.
+ */
+ public final Kind missingAspectForReweaving = new Kind("missingAspectForReweaving",
+ "aspect {0} cannot be found when reweaving {1}");
+
+ private static Trace trace = TraceFactory.getTraceFactory().getTrace(Lint.class);
+
+ public Lint(World world) {
+ if (trace.isTraceEnabled()) {
+ trace.enter("<init>", this, world);
+ }
+ this.world = world;
+ if (trace.isTraceEnabled()) {
+ trace.exit("<init>");
+ }
+ }
+
+ public void setAll(String messageKind) {
+ if (trace.isTraceEnabled()) {
+ trace.enter("setAll", this, messageKind);
+ }
+ setAll(getMessageKind(messageKind));
+ if (trace.isTraceEnabled()) {
+ trace.exit("setAll");
+ }
+ }
+
+ private void setAll(IMessage.Kind messageKind) {
+ for (Kind kind : kinds.values()) {
+ kind.setKind(messageKind);
+ }
+ }
+
+ public void setFromMap(Map<String,String> lintOptionsMap) {
+ for (String key: lintOptionsMap.keySet()) {
+ String value = lintOptionsMap.get(key);
+ Kind kind = kinds.get(key);
+ if (kind == null) {
+ MessageUtil.error(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINT_KEY_ERROR, key));
+ } else {
+ kind.setKind(getMessageKind(value));
+ }
+ }
+ }
+
+ public void setFromProperties(File file) {
+ if (trace.isTraceEnabled()) {
+ trace.enter("setFromProperties", this, file);
+ }
+ InputStream s = null;
+ try {
+ s = new FileInputStream(file);
+ setFromProperties(s);
+ } catch (IOException ioe) {
+ MessageUtil.error(world.getMessageHandler(),
+ WeaverMessages.format(WeaverMessages.XLINT_LOAD_ERROR, file.getPath(), ioe.getMessage()));
+ } finally {
+ if (s != null) {
+ try {
+ s.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ if (trace.isTraceEnabled()) {
+ trace.exit("setFromProperties");
+ }
+ }
+
+ public void loadDefaultProperties() {
+ InputStream s = getClass().getResourceAsStream("XlintDefault.properties");
+ if (s == null) {
+ MessageUtil.warn(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINTDEFAULT_LOAD_ERROR));
+ return;
+ }
+ try {
+ setFromProperties(s);
+ } catch (IOException ioe) {
+ MessageUtil.error(world.getMessageHandler(),
+ WeaverMessages.format(WeaverMessages.XLINTDEFAULT_LOAD_PROBLEM, ioe.getMessage()));
+ } finally {
+ try {
+ s.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ }
+
+ private void setFromProperties(InputStream s) throws IOException {
+ Properties p = new Properties();
+ p.load(s);
+ setFromProperties(p);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void setFromProperties(Properties properties) {
+ for (Iterator i = properties.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ Kind kind = kinds.get(entry.getKey());
+ if (kind == null) {
+ MessageUtil.error(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINT_KEY_ERROR, entry.getKey()));
+ } else {
+ kind.setKind(getMessageKind((String) entry.getValue()));
+ }
+ }
+ }
+
+ public Collection<Kind> allKinds() {
+ return kinds.values();
+ }
+
+ public Kind getLintKind(String name) {
+ return kinds.get(name);
+ }
+
+ // temporarily suppress the given lint messages
+ public void suppressKinds(Collection<Kind> lintKind) {
+ if (lintKind.isEmpty()) {
+ return;
+ }
+ for (Kind k : lintKind) {
+ k.setSuppressed(true);
+ }
+ }
+
+ // remove any suppression of lint warnings in place
+ public void clearAllSuppressions() {
+ for (Kind k : kinds.values()) {
+ k.setSuppressed(false);
+ }
+ }
+
+ public void clearSuppressions(Collection<Lint.Kind> lintKinds) {
+ for (Kind k : lintKinds) {
+ k.setSuppressed(false);
+ }
+ }
+
+ private IMessage.Kind getMessageKind(String v) {
+ if (v.equals("ignore")) {
+ return null;
+ } else if (v.equals("warning")) {
+ return IMessage.WARNING;
+ } else if (v.equals("error")) {
+ return IMessage.ERROR;
+ }
+
+ MessageUtil.error(world.getMessageHandler(), WeaverMessages.format(WeaverMessages.XLINT_VALUE_ERROR, v));
+ return null;
+ }
+
+ public Kind fromKey(String lintkey) {
+ return kinds.get(lintkey);
+ }
+
+ public class Kind {
+ private final String name;
+ private final String message;
+ private IMessage.Kind kind = IMessage.WARNING;
+ private boolean isSupressed = false; // by SuppressAjWarnings
+
+ public Kind(String name, String message) {
+ this.name = name;
+ this.message = message;
+ kinds.put(this.name, this);
+ }
+
+ public void setSuppressed(boolean shouldBeSuppressed) {
+ this.isSupressed = shouldBeSuppressed;
+ }
+
+ public boolean isEnabled() {
+ return (kind != null) && !isSupressed();
+ }
+
+ private boolean isSupressed() {
+ // can't suppress errors!
+ return isSupressed && (kind != IMessage.ERROR);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public IMessage.Kind getKind() {
+ return kind;
+ }
+
+ public void setKind(IMessage.Kind kind) {
+ this.kind = kind;
+ }
+
+ public void signal(String info, ISourceLocation location) {
+ if (kind == null) {
+ return;
+ }
+
+ String text = MessageFormat.format(message, new Object[] { info });
+ text += " [Xlint:" + name + "]";
+ world.getMessageHandler().handleMessage(new LintMessage(text, kind, location, null, getLintKind(name)));
+ }
+
+ public void signal(String[] infos, ISourceLocation location, ISourceLocation[] extraLocations) {
+ if (kind == null) {
+ return;
+ }
+
+ String text = MessageFormat.format(message, (Object[]) infos);
+ text += " [Xlint:" + name + "]";
+ world.getMessageHandler().handleMessage(new LintMessage(text, kind, location, extraLocations, getLintKind(name)));
+ }
+
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/LintMessage.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/LintMessage.java
new file mode 100644
index 000000000..f54e20e7d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/LintMessage.java
@@ -0,0 +1,44 @@
+/* *******************************************************************
+ * Copyright (c) 2002-2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * AndyClement extracted as self contained type from Lint type (4-Aug-06)
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+
+public class LintMessage extends Message {
+
+ // private Lint.Kind lintKind;
+ private String lintKind;
+
+ public LintMessage(String message, IMessage.Kind messageKind, ISourceLocation location, ISourceLocation[] extraLocations,
+ Lint.Kind lintKind) {
+ super(message, "", messageKind, location, null, extraLocations);
+ this.lintKind = lintKind.getName();
+ }
+
+ public LintMessage(String message, String extraDetails, org.aspectj.weaver.Lint.Kind kind2, Kind kind,
+ ISourceLocation sourceLocation, Throwable object, ISourceLocation[] seeAlsoLocations, boolean declared, int id,
+ int sourceStart, int sourceEnd) {
+ super(message, extraDetails, kind, sourceLocation, object, seeAlsoLocations, declared, id, sourceStart, sourceEnd);
+ this.lintKind = kind2.getName();
+ }
+
+ /**
+ * @return Returns the Lint kind of this message
+ */
+ public String getLintKind() {
+ return lintKind;
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Member.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Member.java
new file mode 100644
index 000000000..8134e8df2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Member.java
@@ -0,0 +1,93 @@
+/* *******************************************************************
+ * Copyright (c) 2002-2010
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Collection;
+
+/**
+ * Abstract representation of a member (field/constructor/method) within a type.
+ *
+ * @author PARC
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public interface Member extends Comparable<Member> {
+
+ public static final Member[] NONE = new Member[0];
+
+ public static final MemberKind METHOD = new MemberKind("METHOD", 1);
+ public static final MemberKind FIELD = new MemberKind("FIELD", 2);
+ public static final MemberKind CONSTRUCTOR = new MemberKind("CONSTRUCTOR", 3);
+ public static final MemberKind STATIC_INITIALIZATION = new MemberKind("STATIC_INITIALIZATION", 4);
+ public static final MemberKind POINTCUT = new MemberKind("POINTCUT", 5);
+ public static final MemberKind ADVICE = new MemberKind("ADVICE", 6);
+ public static final MemberKind HANDLER = new MemberKind("HANDLER", 7);
+ public static final MemberKind MONITORENTER = new MemberKind("MONITORENTER", 8);
+ public static final MemberKind MONITOREXIT = new MemberKind("MONITOREXIT", 9);
+
+ public static final AnnotationAJ[][] NO_PARAMETER_ANNOTATIONXS = new AnnotationAJ[][] {};
+ public static final ResolvedType[][] NO_PARAMETER_ANNOTATION_TYPES = new ResolvedType[][] {};
+
+ /**
+ * @return the kind of member from those listed as MemberKind instances
+ */
+ public MemberKind getKind();
+
+ public String getName();
+
+ public UnresolvedType getDeclaringType();
+
+ public UnresolvedType[] getParameterTypes();
+
+ public UnresolvedType[] getGenericParameterTypes();
+
+ public UnresolvedType getType();
+
+ public UnresolvedType getReturnType();
+
+ public UnresolvedType getGenericReturnType();
+
+ /**
+ * Return full signature, including return type, e.g. "()LFastCar;". For a signature without the return type, use
+ * getParameterSignature() - it is important to choose the right one in the face of covariance.
+ */
+ public String getSignature();
+
+ public JoinPointSignatureIterator getJoinPointSignatures(World world);
+
+ public int getArity();
+
+ /**
+ * Return signature without return type, e.g. "()" for a signature *with* the return type, use getSignature() - it is important
+ * to choose the right one in the face of covariance.
+ */
+ public String getParameterSignature();
+
+ public int getModifiers(World world);
+
+ public int getModifiers();
+
+ /**
+ * Returns true iff the member is generic (NOT parameterized)
+ */
+ public boolean canBeParameterized();
+
+ public AnnotationAJ[] getAnnotations();
+
+ public Collection<ResolvedType> getDeclaringTypes(World world);
+
+ public String[] getParameterNames(World world);
+
+ public UnresolvedType[] getExceptions(World world);
+
+ public ResolvedMember resolve(World world);
+
+ public int compareTo(Member other);
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberImpl.java
new file mode 100644
index 000000000..fbf497ed2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberImpl.java
@@ -0,0 +1,542 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+public class MemberImpl implements Member {
+
+ protected MemberKind kind;
+ protected int modifiers;
+ protected String name;
+ protected UnresolvedType declaringType;
+ protected UnresolvedType returnType;
+ protected UnresolvedType[] parameterTypes;
+ private final String erasedSignature; // eg. (Ljava/util/Set;V)Ljava/lang/String;
+ private String paramSignature; // eg. (Ljava/util/Set<Ljava/lang/String;>;V) // no return type
+
+ // OPTIMIZE move out of the member!
+ private boolean reportedCantFindDeclaringType = false;
+ private boolean reportedUnresolvableMember = false;
+
+ /**
+ * All the signatures that a join point with this member as its signature has.
+ */
+ private JoinPointSignatureIterator joinPointSignatures = null;
+
+ /**
+ * Construct a MemberImpl using an erased signature for the parameters and return type (member method/ctor) or type (member
+ * field)
+ */
+ public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name, String erasedSignature) {
+ this.kind = kind;
+ this.declaringType = declaringType;
+ this.modifiers = modifiers;
+ this.name = name;
+ this.erasedSignature = erasedSignature;
+ if (kind == FIELD) {
+ this.returnType = UnresolvedType.forSignature(erasedSignature);
+ this.parameterTypes = UnresolvedType.NONE;
+ } else {
+ Object[] returnAndParams = signatureToTypes(erasedSignature);
+ this.returnType = (UnresolvedType) returnAndParams[0];
+ this.parameterTypes = (UnresolvedType[]) returnAndParams[1];
+ }
+ }
+
+ /**
+ * Construct a MemberImpl using real type information for the parameters and return type (member method/ctor) or type (member
+ * field)
+ */
+ public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
+ UnresolvedType[] parameterTypes) {
+ this.kind = kind;
+ this.declaringType = declaringType;
+ this.modifiers = modifiers;
+ this.returnType = returnType;
+ this.name = name;
+ this.parameterTypes = parameterTypes;
+ if (kind == FIELD) {
+ this.erasedSignature = returnType.getErasureSignature();
+ } else {
+ this.erasedSignature = typesToSignature(returnType, parameterTypes, true);
+
+ // Check parameter recovery by collapsing types to the string then rebuilding them from that
+ // this will check we are capable of having WeakRefs to the parameter types
+ // String nonErasedSignature = getParameterSignature()+getReturnType().getSignature();
+ // Object[] returnAndParams = signatureToTypes(nonErasedSignature);
+ // UnresolvedType[] recoveredParams = (UnresolvedType[]) returnAndParams[1];
+ // for (int jj=0;jj<parameterTypes.length;jj++) {
+ // if (!parameterTypes[jj].getSignature().equals(recoveredParams[jj].getSignature())) {
+ // throw new
+ // RuntimeException(parameterTypes[jj].getSignature()+" != "+recoveredParams[jj].getSignature()+" "+paramSignature);
+ // }
+ // }
+ }
+
+ }
+
+ public ResolvedMember resolve(World world) {
+ return world.resolve(this);
+ }
+
+ // ---- utility methods
+
+ /**
+ * Build a signature based on the return type and parameter types. For example: "(Ljava/util/Set<Ljava/lang/String;>;)V" or
+ * "(Ljava/util/Set;)V". The latter form shows what happens when the generics are erased
+ */
+ public static String typesToSignature(UnresolvedType returnType, UnresolvedType[] paramTypes, boolean eraseGenerics) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("(");
+ for (UnresolvedType paramType : paramTypes) {
+ if (eraseGenerics) {
+ buf.append(paramType.getErasureSignature());
+ } else {
+ buf.append(paramType.getSignature());
+ }
+ }
+ buf.append(")");
+ if (eraseGenerics) {
+ buf.append(returnType.getErasureSignature());
+ } else {
+ buf.append(returnType.getSignature());
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns "(<signaturesOfParamTypes>,...)" - unlike the other typesToSignature that also includes the return type, this one
+ * just deals with the parameter types.
+ */
+ public static String typesToSignature(UnresolvedType[] paramTypes) {
+ StringBuffer buf = new StringBuffer();
+ buf.append("(");
+ for (int i = 0; i < paramTypes.length; i++) {
+ buf.append(paramTypes[i].getSignature());
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ /**
+ * returns an Object[] pair of UnresolvedType, UnresolvedType[] representing return type, argument types parsed from the JVM
+ * bytecode signature of a method. Yes, this should actually return a nice statically-typed pair object, but we don't have one
+ * of those.
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * UnresolvedType.signatureToTypes(&quot;()[Z&quot;)[0].equals(Type.forSignature(&quot;[Z&quot;))
+ * UnresolvedType.signatureToTypes(&quot;(JJ)I&quot;)[1]
+ * .equals(UnresolvedType.forSignatures(new String[] {&quot;J&quot;, &quot;J&quot;}))
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @param erasedSignature the JVM bytecode method signature string we want to break apart
+ * @return a pair of UnresolvedType, UnresolvedType[] representing the return types and parameter types.
+ */
+ private static Object[] signatureToTypes(String sig) {
+ boolean hasParameters = sig.charAt(1) != ')';
+ if (hasParameters) {
+ List<UnresolvedType> l = new ArrayList<UnresolvedType>();
+ int i = 1;
+ boolean hasAnyAnglies = sig.indexOf('<') != -1;
+ while (true) {
+ char c = sig.charAt(i);
+ if (c == ')') {
+ break; // break out when the hit the ')'
+ }
+ int start = i;
+ while (c == '[') {
+ c = sig.charAt(++i);
+ }
+ if (c == 'L' || c == 'P') {
+ int nextSemicolon = sig.indexOf(';', start);
+ int firstAngly = (hasAnyAnglies ? sig.indexOf('<', start) : -1);
+ if (!hasAnyAnglies || firstAngly == -1 || firstAngly > nextSemicolon) {
+ i = nextSemicolon + 1;
+ l.add(UnresolvedType.forSignature(sig.substring(start, i)));
+ } else {
+ // generics generics generics
+ // Have to skip to the *correct* ';'
+ boolean endOfSigReached = false;
+ int posn = firstAngly;
+ int genericDepth = 0;
+ while (!endOfSigReached) {
+ switch (sig.charAt(posn)) {
+ case '<':
+ genericDepth++;
+ break;
+ case '>':
+ genericDepth--;
+ break;
+ case ';':
+ if (genericDepth == 0) {
+ endOfSigReached = true;
+ }
+ break;
+ default:
+ }
+ posn++;
+ }
+ // posn now points to the correct nextSemicolon :)
+ i = posn;
+ l.add(UnresolvedType.forSignature(sig.substring(start, i)));
+ }
+ } else if (c == 'T') { // assumed 'reference' to a type
+ // variable, so just "Tname;"
+ int nextSemicolon = sig.indexOf(';', start);
+ String nextbit = sig.substring(start, nextSemicolon + 1);
+ l.add(UnresolvedType.forSignature(nextbit));
+ i = nextSemicolon + 1;
+ } else {
+ i++;
+ l.add(UnresolvedType.forSignature(sig.substring(start, i)));
+ }
+ }
+ UnresolvedType[] paramTypes = l.toArray(new UnresolvedType[l.size()]);
+ UnresolvedType returnType = UnresolvedType.forSignature(sig.substring(i + 1, sig.length()));
+ return new Object[] { returnType, paramTypes };
+ } else {
+ UnresolvedType returnType = UnresolvedType.forSignature(sig.substring(2));
+ return new Object[] { returnType, UnresolvedType.NONE };
+ }
+ }
+
+ // ---- factory methods
+ public static MemberImpl field(String declaring, int mods, String name, String signature) {
+ return field(declaring, mods, UnresolvedType.forSignature(signature), name);
+ }
+
+ // OPTIMIZE do we need to call this? unless necessary the signatureToTypes()
+ // call smacks of laziness on the behalf of the caller of this method
+ public static MemberImpl method(UnresolvedType declaring, int mods, String name, String signature) {
+ Object[] pair = signatureToTypes(signature);
+ return method(declaring, mods, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]);
+ }
+
+ public static MemberImpl monitorEnter() {
+ return new MemberImpl(MONITORENTER, UnresolvedType.OBJECT, Modifier.STATIC, UnresolvedType.VOID, "<lock>",
+ UnresolvedType.ARRAY_WITH_JUST_OBJECT);
+ }
+
+ public static MemberImpl monitorExit() {
+ return new MemberImpl(MONITOREXIT, UnresolvedType.OBJECT, Modifier.STATIC, UnresolvedType.VOID, "<unlock>",
+ UnresolvedType.ARRAY_WITH_JUST_OBJECT);
+ }
+
+ public static Member pointcut(UnresolvedType declaring, String name, String signature) {
+ Object[] pair = signatureToTypes(signature);
+ return pointcut(declaring, 0, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]);
+ }
+
+ private static MemberImpl field(String declaring, int mods, UnresolvedType ty, String name) {
+ return new MemberImpl(FIELD, UnresolvedType.forName(declaring), mods, ty, name, UnresolvedType.NONE);
+ }
+
+ public static MemberImpl method(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
+ return new MemberImpl(
+ // ??? this calls <clinit> a method
+ name.equals("<init>") ? CONSTRUCTOR : METHOD, declTy, mods, rTy, name, paramTys);
+ }
+
+ private static Member pointcut(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
+ return new MemberImpl(POINTCUT, declTy, mods, rTy, name, paramTys);
+ }
+
+ public static ResolvedMemberImpl makeExceptionHandlerSignature(UnresolvedType inType, UnresolvedType catchType) {
+ return new ResolvedMemberImpl(HANDLER, inType, Modifier.STATIC, "<catch>", "(" + catchType.getSignature() + ")V");
+ }
+
+ @Override
+ public final boolean equals(Object other) {
+ if (!(other instanceof Member)) {
+ return false;
+ }
+ Member o = (Member) other;
+ return (getKind() == o.getKind() && getName().equals(o.getName()) && getSignature().equals(o.getSignature()) && getDeclaringType()
+ .equals(o.getDeclaringType()));
+ }
+
+ /**
+ * @return true if this member equals the one supplied in every respect other than the declaring type
+ */
+ public final boolean equalsApartFromDeclaringType(Object other) {
+ if (!(other instanceof Member)) {
+ return false;
+ }
+ Member o = (Member) other;
+ return (getKind() == o.getKind() && getName().equals(o.getName()) && getSignature().equals(o.getSignature()));
+ }
+
+ /**
+ * Equality is checked based on the underlying signature, so the hash code of a member is based on its kind, name, signature,
+ * and declaring type. The algorithm for this was taken from page 38 of effective java.
+ */
+ private volatile int hashCode = 0;
+
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + getKind().hashCode();
+ result = 37 * result + getName().hashCode();
+ result = 37 * result + getSignature().hashCode();
+ result = 37 * result + getDeclaringType().hashCode();
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ public int compareTo(Member other) {
+ Member o = other;
+ int i = getName().compareTo(o.getName());
+ if (i != 0) {
+ return i;
+ }
+ return getSignature().compareTo(o.getSignature());
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(returnType.getName());
+ buf.append(' ');
+ if (declaringType == null) {
+ buf.append("<NULL>");
+ } else {
+ buf.append(declaringType.getName());
+ }
+ buf.append('.');
+ buf.append(name);
+ if (kind != FIELD) {
+ buf.append("(");
+ if (parameterTypes.length != 0) {
+ buf.append(parameterTypes[0]);
+ for (int i = 1, len = parameterTypes.length; i < len; i++) {
+ buf.append(", ");
+ buf.append(parameterTypes[i].getName());
+ }
+ }
+ buf.append(")");
+ }
+ return buf.toString();
+ }
+
+ public MemberKind getKind() {
+ return kind;
+ }
+
+ public UnresolvedType getDeclaringType() {
+ return declaringType;
+ }
+
+ public UnresolvedType getReturnType() {
+ return returnType;
+ }
+
+ public UnresolvedType getGenericReturnType() {
+ return getReturnType();
+ }
+
+ public UnresolvedType[] getGenericParameterTypes() {
+ return getParameterTypes();
+ }
+
+ public final UnresolvedType getType() {
+ return returnType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public UnresolvedType[] getParameterTypes() {
+ return parameterTypes;
+ }
+
+ public String getSignature() {
+ return erasedSignature;
+ }
+
+ public int getArity() {
+ return parameterTypes.length;
+ }
+
+ public String getParameterSignature() {
+ if (paramSignature == null) {
+ StringBuilder sb = new StringBuilder("(");
+ for (UnresolvedType parameterType : parameterTypes) {
+ sb.append(parameterType.getSignature());
+ }
+ paramSignature = sb.append(")").toString();
+ }
+ return paramSignature;
+ }
+
+ // OPTIMIZE see next line. Why the hell are they in here if we only know it
+ // once resolution has occurred...
+ // ---- things we know only with resolution
+
+ public int getModifiers(World world) {
+ ResolvedMember resolved = resolve(world);
+ if (resolved == null) {
+ reportDidntFindMember(world);
+ return 0;
+ }
+ return resolved.getModifiers();
+ }
+
+ public UnresolvedType[] getExceptions(World world) {
+ ResolvedMember resolved = resolve(world);
+ if (resolved == null) {
+ reportDidntFindMember(world);
+ return UnresolvedType.NONE;
+ }
+ return resolved.getExceptions();
+ }
+
+ public final boolean isStatic() {
+ return Modifier.isStatic(modifiers);
+ }
+
+ public final boolean isInterface() {
+ return Modifier.isInterface(modifiers);
+ }
+
+ public final boolean isPrivate() {
+ return Modifier.isPrivate(modifiers);
+ }
+
+ public boolean canBeParameterized() {
+ return false;
+ }
+
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ public AnnotationAJ[] getAnnotations() {
+ throw new UnsupportedOperationException("You should resolve this member '" + this
+ + "' and call getAnnotations() on the result...");
+ }
+
+ // ---- fields 'n' stuff
+
+ public Collection<ResolvedType> getDeclaringTypes(World world) {
+ ResolvedType myType = getDeclaringType().resolve(world);
+ Collection<ResolvedType> ret = new HashSet<ResolvedType>();
+ if (kind == CONSTRUCTOR) {
+ // this is wrong if the member doesn't exist, but that doesn't
+ // matter
+ ret.add(myType);
+ } else if (Modifier.isStatic(modifiers) || kind == FIELD) {
+ walkUpStatic(ret, myType);
+ } else {
+ walkUp(ret, myType);
+ }
+
+ return ret;
+ }
+
+ private boolean walkUp(Collection<ResolvedType> acc, ResolvedType curr) {
+ if (acc.contains(curr)) {
+ return true;
+ }
+
+ boolean b = false;
+ for (Iterator<ResolvedType> i = curr.getDirectSupertypes(); i.hasNext();) {
+ b |= walkUp(acc, i.next());
+ }
+
+ if (!b && curr.isParameterizedType()) {
+ b = walkUp(acc, curr.getGenericType());
+ }
+
+ if (!b) {
+ b = curr.lookupMemberNoSupers(this) != null;
+ }
+ if (b) {
+ acc.add(curr);
+ }
+ return b;
+ }
+
+ private boolean walkUpStatic(Collection<ResolvedType> acc, ResolvedType curr) {
+ if (curr.lookupMemberNoSupers(this) != null) {
+ acc.add(curr);
+ return true;
+ } else {
+ boolean b = false;
+ for (Iterator<ResolvedType> i = curr.getDirectSupertypes(); i.hasNext();) {
+ b |= walkUpStatic(acc, i.next());
+ }
+ if (!b && curr.isParameterizedType()) {
+ b = walkUpStatic(acc, curr.getGenericType());
+ }
+ if (b) {
+ acc.add(curr);
+ }
+ return b;
+ }
+ }
+
+ public String[] getParameterNames(World world) {
+ ResolvedMember resolved = resolve(world);
+ if (resolved == null) {
+ reportDidntFindMember(world);
+ return null;
+ }
+ return resolved.getParameterNames();
+ }
+
+ /**
+ * All the signatures that a join point with this member as its signature has.
+ */
+ public JoinPointSignatureIterator getJoinPointSignatures(World inAWorld) {
+ if (joinPointSignatures == null) {
+ joinPointSignatures = new JoinPointSignatureIterator(this, inAWorld);
+ }
+ joinPointSignatures.reset();
+ return joinPointSignatures;
+ }
+
+ /**
+ * Raises an [Xlint:cantFindType] message if the declaring type cannot be found or an [Xlint:unresolvableMember] message if the
+ * type can be found (bug 149908)
+ */
+ private void reportDidntFindMember(World world) {
+ if (reportedCantFindDeclaringType || reportedUnresolvableMember) {
+ return;
+ }
+ ResolvedType rType = getDeclaringType().resolve(world);
+ if (rType.isMissing()) {
+ world.getLint().cantFindType.signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE, rType.getName()), null);
+ reportedCantFindDeclaringType = true;
+ } else {
+ world.getLint().unresolvableMember.signal(getName(), null);
+ reportedUnresolvableMember = true;
+ }
+ }
+
+ public void wipeJoinpointSignatures() {
+ joinPointSignatures = null;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberKind.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberKind.java
new file mode 100644
index 000000000..f1d5dfa0f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberKind.java
@@ -0,0 +1,48 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.aspectj.util.TypeSafeEnum;
+
+public class MemberKind extends TypeSafeEnum {
+ public MemberKind(String name, int key) {
+ super(name, key);
+ }
+
+ public static MemberKind read(DataInputStream s) throws IOException {
+ int key = s.readByte();
+ switch (key) {
+ case 1:
+ return Member.METHOD;
+ case 2:
+ return Member.FIELD;
+ case 3:
+ return Member.CONSTRUCTOR;
+ case 4:
+ return Member.STATIC_INITIALIZATION;
+ case 5:
+ return Member.POINTCUT;
+ case 6:
+ return Member.ADVICE;
+ case 7:
+ return Member.HANDLER;
+ case 8:
+ return Member.MONITORENTER;
+ case 9:
+ return Member.MONITOREXIT;
+ }
+ throw new BCException("Unexpected memberkind, should be (1-9) but was " + key);
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberUtils.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberUtils.java
new file mode 100644
index 000000000..201eb758f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MemberUtils.java
@@ -0,0 +1,25 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement, SpringSource
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Common utility methods for members.
+ *
+ * @author Andy Clement
+ */
+public class MemberUtils {
+
+ public static boolean isConstructor(ResolvedMember member) {
+ return member.getName().equals("<init>");
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MethodDelegateTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MethodDelegateTypeMunger.java
new file mode 100644
index 000000000..79eab7d4d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MethodDelegateTypeMunger.java
@@ -0,0 +1,298 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Vasseur initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+import org.aspectj.weaver.patterns.TypePattern;
+
+/**
+ * Type munger for annotation style ITD declare parents. with an interface AND an implementation. Given the aspect that has a field
+ * public static Interface fieldI = ... // impl. we will weave in the Interface' methods and delegate to the aspect public static
+ * field fieldI
+ *
+ * Note: this munger DOES NOT handles the interface addition to the target classes - a regular Parent kinded munger must be added in
+ * coordination.
+ */
+public class MethodDelegateTypeMunger extends ResolvedTypeMunger {
+
+ private final UnresolvedType aspect;
+
+ private UnresolvedType fieldType;
+
+ /**
+ * The mixin implementation (which should have a no-argument constructor)
+ */
+ private final String implClassName;
+
+ /**
+ * Type pattern this munger applies to
+ */
+ private final TypePattern typePattern;
+
+ /**
+ * When created to represent a mixed in method for @DeclareMixin, these hold the signature of the factory method
+ */
+ private String factoryMethodName;
+ private String factoryMethodSignature;
+
+ private int bitflags;
+ private static final int REPLACING_EXISTING_METHOD = 0x001;
+
+ /**
+ * Construct a new type munger for @AspectJ ITD
+ *
+ * @param signature
+ * @param aspect
+ * @param implClassName
+ * @param typePattern
+ */
+ public MethodDelegateTypeMunger(ResolvedMember signature, UnresolvedType aspect, String implClassName, TypePattern typePattern) {
+ super(MethodDelegate2, signature);
+ this.aspect = aspect;
+ this.typePattern = typePattern;
+ this.implClassName = implClassName;
+ factoryMethodName = "";
+ factoryMethodSignature = "";
+ }
+
+ public MethodDelegateTypeMunger(ResolvedMember signature, UnresolvedType aspect, String implClassName, TypePattern typePattern,
+ String factoryMethodName, String factoryMethodSignature) {
+ super(MethodDelegate2, signature);
+ this.aspect = aspect;
+ this.typePattern = typePattern;
+ this.implClassName = implClassName;
+ this.factoryMethodName = factoryMethodName;
+ this.factoryMethodSignature = factoryMethodSignature;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof MethodDelegateTypeMunger)) {
+ return false;
+ }
+ MethodDelegateTypeMunger o = (MethodDelegateTypeMunger) other;
+ return ((o.aspect == null) ? (aspect == null) : aspect.equals(o.aspect))
+ && ((o.typePattern == null) ? (typePattern == null) : typePattern.equals(o.typePattern))
+ && ((o.implClassName == null) ? (implClassName == null) : implClassName.equals(o.implClassName))
+ && ((o.fieldType == null ? (fieldType == null) : fieldType.equals(o.fieldType)))
+ && ((o.factoryMethodName == null) ? (factoryMethodName == null) : factoryMethodName.equals(o.factoryMethodName))
+ && ((o.factoryMethodSignature == null) ? (factoryMethodSignature == null) : factoryMethodSignature
+ .equals(o.factoryMethodSignature)) && o.bitflags == bitflags;
+ }
+
+ private volatile int hashCode = 0;
+
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + ((aspect == null) ? 0 : aspect.hashCode());
+ result = 37 * result + ((typePattern == null) ? 0 : typePattern.hashCode());
+ result = 37 * result + ((implClassName == null) ? 0 : implClassName.hashCode());
+ result = 37 * result + ((fieldType == null) ? 0 : fieldType.hashCode());
+ result = 37 * result + ((factoryMethodName == null) ? 0 : factoryMethodName.hashCode());
+ result = 37 * result + ((factoryMethodSignature == null) ? 0 : factoryMethodSignature.hashCode());
+ result = 37 * result + bitflags;
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ public ResolvedMember getDelegate(ResolvedType targetType) {
+ return AjcMemberMaker.itdAtDeclareParentsField(targetType, fieldType, aspect);
+ }
+
+ public ResolvedMember getDelegateFactoryMethod(World w) {
+ ResolvedType aspectType = w.resolve(aspect);
+ ResolvedMember[] methods = aspectType.getDeclaredMethods();
+ for (int i = 0; i < methods.length; i++) {
+ ResolvedMember rm = methods[i];
+ if (rm.getName().equals(factoryMethodName) && rm.getSignature().equals(factoryMethodSignature)) {
+ return rm;
+ }
+ }
+ return null;
+ }
+
+ public String getImplClassName() {
+ return implClassName;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ signature.write(s);
+ aspect.write(s);
+ s.writeUTF(implClassName);
+ typePattern.write(s);
+ fieldType.write(s);
+ s.writeUTF(factoryMethodName);
+ s.writeUTF(factoryMethodSignature);
+ s.writeInt(bitflags);
+ }
+
+ public static ResolvedTypeMunger readMethod(VersionedDataInputStream s, ISourceContext context, boolean isEnhanced)
+ throws IOException {
+ ResolvedMemberImpl signature = ResolvedMemberImpl.readResolvedMember(s, context);
+ UnresolvedType aspect = UnresolvedType.read(s);
+ String implClassName = s.readUTF();
+ TypePattern tp = TypePattern.read(s, context);
+ MethodDelegateTypeMunger typeMunger = new MethodDelegateTypeMunger(signature, aspect, implClassName, tp);
+ UnresolvedType fieldType = null;
+ if (isEnhanced) {
+ fieldType = UnresolvedType.read(s);
+ } else {
+ // a guess... that will work in a lot of cases
+ fieldType = signature.getDeclaringType();
+ }
+ typeMunger.setFieldType(fieldType);
+ if (isEnhanced) {
+ typeMunger.factoryMethodName = s.readUTF();
+ typeMunger.factoryMethodSignature = s.readUTF();
+ typeMunger.bitflags = s.readInt();
+ }
+ return typeMunger;
+ }
+
+ /**
+ * Match based on given type pattern, only classes can be matched
+ *
+ * @param matchType
+ * @param aspectType
+ * @return true if match
+ */
+ public boolean matches(ResolvedType matchType, ResolvedType aspectType) {
+ // match only on class
+ if (matchType.isEnum() || matchType.isInterface() || matchType.isAnnotation()) {
+ return false;
+ }
+
+ return typePattern.matchesStatically(matchType);
+ }
+
+ /**
+ * Needed for reweavable
+ *
+ * @return true
+ */
+ public boolean changesPublicSignature() {
+ return true;
+ }
+
+ public static class FieldHostTypeMunger extends ResolvedTypeMunger {
+
+ private final UnresolvedType aspect;
+
+ /**
+ * Type pattern this munger applies to
+ */
+ private final TypePattern typePattern;
+
+ /**
+ * Construct a new type munger for @AspectJ ITD
+ *
+ * @param field
+ * @param aspect
+ * @param typePattern
+ */
+ public FieldHostTypeMunger(ResolvedMember field, UnresolvedType aspect, TypePattern typePattern) {
+ super(FieldHost, field);
+ this.aspect = aspect;
+ this.typePattern = typePattern;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof FieldHostTypeMunger)) {
+ return false;
+ }
+ FieldHostTypeMunger o = (FieldHostTypeMunger) other;
+ return ((o.aspect == null) ? (aspect == null) : aspect.equals(o.aspect))
+ && ((o.typePattern == null) ? (typePattern == null) : typePattern.equals(o.typePattern));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + ((aspect == null) ? 0 : aspect.hashCode());
+ result = 37 * result + ((typePattern == null) ? 0 : typePattern.hashCode());
+ return result;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ signature.write(s);
+ aspect.write(s);
+ typePattern.write(s);
+ }
+
+ public static ResolvedTypeMunger readFieldHost(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ResolvedMemberImpl signature = ResolvedMemberImpl.readResolvedMember(s, context);
+ UnresolvedType aspect = UnresolvedType.read(s);
+ TypePattern tp = TypePattern.read(s, context);
+ return new FieldHostTypeMunger(signature, aspect, tp);
+ }
+
+ /**
+ * Match based on given type pattern, only classes can be matched
+ *
+ * @param matchType
+ * @param aspectType
+ * @return true if match
+ */
+ public boolean matches(ResolvedType matchType, ResolvedType aspectType) {
+ // match only on class
+ if (matchType.isEnum() || matchType.isInterface() || matchType.isAnnotation()) {
+ return false;
+ }
+
+ return typePattern.matchesStatically(matchType);
+ }
+
+ public boolean changesPublicSignature() {
+ return false;
+ }
+
+ public boolean existsToSupportShadowMunging() {
+ return true;
+ }
+ }
+
+ public void setFieldType(UnresolvedType fieldType) {
+ this.fieldType = fieldType;
+ }
+
+ public boolean specifiesDelegateFactoryMethod() {
+ return factoryMethodName != null && factoryMethodName.length() != 0;
+ }
+
+ public String getFactoryMethodName() {
+ return factoryMethodName;
+ }
+
+ public String getFactoryMethodSignature() {
+ return factoryMethodSignature;
+ }
+
+ public UnresolvedType getAspect() {
+ return aspect;
+ }
+
+ public boolean existsToSupportShadowMunging() {
+ return true;
+ }
+
+ public void tagAsReplacingExistingMethod() {
+ bitflags |= REPLACING_EXISTING_METHOD;
+ }
+
+ public boolean isReplacingExistingMethod() {
+ return (bitflags & REPLACING_EXISTING_METHOD) != 0;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MissingResolvedTypeWithKnownSignature.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MissingResolvedTypeWithKnownSignature.java
new file mode 100644
index 000000000..da61ffd8b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/MissingResolvedTypeWithKnownSignature.java
@@ -0,0 +1,253 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.context.CompilationAndWeavingContext;
+
+/**
+ * When we try to resolve a type in the world that we require to be present, and then fail to find it, we return an instance of this
+ * class. This class defers the production of the "can't find type error" until the first time that someone asks a question that
+ * can't be answered solely from the signature. This enables the weaver to be more tolerant of missing types.
+ *
+ */
+public class MissingResolvedTypeWithKnownSignature extends ResolvedType {
+
+ private static ResolvedMember[] NO_MEMBERS = new ResolvedMember[0];
+ private static ResolvedType[] NO_TYPES = new ResolvedType[0];
+ private boolean issuedCantFindTypeError = false;
+ private boolean issuedJoinPointWarning = false;
+ private boolean issuedMissingInterfaceWarning = false;
+
+ /**
+ * @param signature
+ * @param world
+ */
+ public MissingResolvedTypeWithKnownSignature(String signature, World world) {
+ super(signature, world);
+ }
+
+ @Override
+ public boolean isMissing() {
+ return true;
+ }
+
+ /**
+ * @param signature
+ * @param signatureErasure
+ * @param world
+ */
+ public MissingResolvedTypeWithKnownSignature(String signature, String signatureErasure, World world) {
+ super(signature, signatureErasure, world);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ResolvedType#getDeclaredFields()
+ */
+ @Override
+ public ResolvedMember[] getDeclaredFields() {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_FIELDS);
+ return NO_MEMBERS;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ResolvedType#getDeclaredMethods()
+ */
+ @Override
+ public ResolvedMember[] getDeclaredMethods() {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_METHODS);
+ return NO_MEMBERS;
+ }
+
+ @Override
+ public AnnotationAJ[] getAnnotations() {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_ANNOTATION);
+ return AnnotationAJ.EMPTY_ARRAY;
+ }
+
+ @Override
+ public ResolvedType[] getDeclaredInterfaces() {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_INTERFACES);
+ return NO_TYPES;
+ }
+
+ @Override
+ public ResolvedMember[] getDeclaredPointcuts() {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_POINTCUTS);
+ return NO_MEMBERS;
+ }
+
+ @Override
+ public ResolvedType getSuperclass() {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_SUPERCLASS);
+ return ResolvedType.MISSING;
+ }
+
+ @Override
+ public int getModifiers() {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_MODIFIERS);
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ResolvedType#getSourceContext()
+ */
+ @Override
+ public ISourceContext getSourceContext() {
+ return new ISourceContext() {
+
+ @Override
+ public ISourceLocation makeSourceLocation(IHasPosition position) {
+ return null;
+ }
+
+ @Override
+ public ISourceLocation makeSourceLocation(int line, int offset) {
+ return null;
+ }
+
+ @Override
+ public int getOffset() {
+ return 0;
+ }
+
+ @Override
+ public void tidy() {
+ }
+
+ };
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ResolvedType#isAssignableFrom(org.aspectj.weaver.ResolvedType)
+ */
+ @Override
+ public boolean isAssignableFrom(ResolvedType other) {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_ASSIGNABLE, other.getName());
+ return false;
+ }
+
+ @Override
+ public boolean isAssignableFrom(ResolvedType other, boolean allowMissing) {
+ if (allowMissing) {
+ return false;
+ } else {
+ return isAssignableFrom(other);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ResolvedType#isCoerceableFrom(org.aspectj.weaver.ResolvedType)
+ */
+ @Override
+ public boolean isCoerceableFrom(ResolvedType other) {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_COERCEABLE, other.getName());
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.AnnotatedElement#hasAnnotation(org.aspectj.weaver.UnresolvedType)
+ */
+ @Override
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ raiseCantFindType(WeaverMessages.CANT_FIND_TYPE_ANNOTATION);
+ return false;
+ }
+
+ @Override
+ public List getInterTypeMungers() {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public List getInterTypeMungersIncludingSupers() {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public List getInterTypeParentMungers() {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public List getInterTypeParentMungersIncludingSupers() {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ protected void collectInterTypeMungers(List collector) {
+ return;
+ }
+
+ public void raiseWarningOnJoinPointSignature(String signature) {
+ if (issuedJoinPointWarning) {
+ return;
+ }
+ String message = WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_JOINPOINT, getName(), signature);
+ message += "\n" + CompilationAndWeavingContext.getCurrentContext();
+ world.getLint().cantFindTypeAffectingJoinPointMatch.signal(message, null);
+ // MessageUtil.warn(world.getMessageHandler(),message);
+ issuedJoinPointWarning = true;
+ }
+
+ public void raiseWarningOnMissingInterfaceWhilstFindingMethods() {
+ if (issuedMissingInterfaceWarning) {
+ return;
+ }
+ String message = WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_INTERFACE_METHODS, getName(), signature);
+ message += "\n" + CompilationAndWeavingContext.getCurrentContext();
+ world.getLint().cantFindTypeAffectingJoinPointMatch.signal(message, null);
+ // MessageUtil.warn(world.getMessageHandler(),message);
+ issuedMissingInterfaceWarning = true;
+ }
+
+ private void raiseCantFindType(String key) {
+ if (!world.getLint().cantFindType.isEnabled()) {
+ return;
+ }
+ if (issuedCantFindTypeError) {
+ return;
+ }
+ String message = WeaverMessages.format(key, getName());
+ message += "\n" + CompilationAndWeavingContext.getCurrentContext();
+ world.getLint().cantFindType.signal(message, null);
+ // MessageUtil.error(world.getMessageHandler(),message);
+ issuedCantFindTypeError = true;
+ }
+
+ private void raiseCantFindType(String key, String insert) {
+ if (issuedCantFindTypeError) {
+ return;
+ }
+ String message = WeaverMessages.format(key, getName(), insert);
+ message += "\n" + CompilationAndWeavingContext.getCurrentContext();
+ world.getLint().cantFindType.signal(message, null);
+ // MessageUtil.error(world.getMessageHandler(),message);
+ issuedCantFindTypeError = true;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NameMangler.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NameMangler.java
new file mode 100644
index 000000000..f9162684a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NameMangler.java
@@ -0,0 +1,357 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.lang.reflect.Modifier;
+
+public class NameMangler {
+
+ // public static final char[] AJC_DOLLAR_PREFIX = { 'a', 'j', 'c', '$' };
+ // public static final char[] CLINIT = { '<', 'c', 'l', 'i', 'n', 'i', 't', '>' };
+ public static final String PREFIX = "ajc$";
+ public static final char[] PREFIX_CHARS = "ajc$".toCharArray();
+ // public static final char[] INIT = { '<', 'i', 'n', 'i', 't', '>' };
+ public static final String ITD_PREFIX = PREFIX + "interType$";
+ // public static final char[] METHOD_ASPECTOF = {'a', 's', 'p','e','c','t','O','f'};
+ // public static final char[] METHOD_HASASPECT = { 'h', 'a', 's', 'A', 's', 'p', 'e', 'c', 't' };
+ // public static final char[] STATIC_INITIALIZER = { '<', 'c', 'l', 'i', 'n', 'i', 't', '>' };
+
+ public static final String CFLOW_STACK_TYPE = "org.aspectj.runtime.internal.CFlowStack";
+ public static final String CFLOW_COUNTER_TYPE = "org.aspectj.runtime.internal.CFlowCounter";
+
+ public static final UnresolvedType CFLOW_STACK_UNRESOLVEDTYPE = UnresolvedType
+ .forSignature("Lorg/aspectj/runtime/internal/CFlowStack;");
+
+ public static final UnresolvedType CFLOW_COUNTER_UNRESOLVEDTYPE = UnresolvedType
+ .forSignature("Lorg/aspectj/runtime/internal/CFlowCounter;");
+
+ public static final String SOFT_EXCEPTION_TYPE = "org.aspectj.lang.SoftException";
+
+ public static final String PERSINGLETON_FIELD_NAME = PREFIX + "perSingletonInstance";
+ public static final String PERCFLOW_FIELD_NAME = PREFIX + "perCflowStack";
+ // public static final String PERTHIS_FIELD_NAME = PREFIX + "perSingletonInstance";
+
+ // -----
+ public static final String PERCFLOW_PUSH_METHOD = PREFIX + "perCflowPush";
+
+ public static final String PEROBJECT_BIND_METHOD = PREFIX + "perObjectBind";
+
+ // PTWIMPL Method and field names
+ public static final String PERTYPEWITHIN_GETINSTANCE_METHOD = PREFIX + "getInstance";
+ public static final String PERTYPEWITHIN_CREATEASPECTINSTANCE_METHOD = PREFIX + "createAspectInstance";
+ public static final String PERTYPEWITHIN_WITHINTYPEFIELD = PREFIX + "withinType";
+ public static final String PERTYPEWITHIN_GETWITHINTYPENAME_METHOD = "getWithinTypeName";
+
+ public static final String AJC_PRE_CLINIT_NAME = PREFIX + "preClinit";
+
+ public static final String AJC_POST_CLINIT_NAME = PREFIX + "postClinit";
+
+ public static final String INITFAILURECAUSE_FIELD_NAME = PREFIX + "initFailureCause";
+
+ public static final String ANNOTATION_CACHE_FIELD_NAME = PREFIX + "anno$";
+
+ public static boolean isSyntheticMethod(String methodName, boolean declaredInAspect) {
+ if (methodName.startsWith(PREFIX)) {
+ // it's synthetic unless it is an advice method
+ if (methodName.startsWith("ajc$before") || methodName.startsWith("ajc$after")) {
+ return false;
+ } else if (methodName.startsWith("ajc$around")) {
+ // around advice method is not synthetic, but generated proceed is...
+ return (methodName.endsWith("proceed"));
+ } else if (methodName.startsWith("ajc$interMethod$")) {
+ return false; // body of an itd-m
+ }
+ return true;
+ } else if (methodName.indexOf("_aroundBody") != -1) {
+ return true;
+ }
+ // these aren't the droids you're looking for...move along...... pr148727
+ // else if (declaredInAspect) {
+ // if (methodName.equals("aspectOf") || methodName.equals("hasAspect")) {
+ // return true;
+ // }
+ // }
+ return false;
+ }
+
+ public static String perObjectInterfaceGet(UnresolvedType aspectType) {
+ return makeName(aspectType.getNameAsIdentifier(), "perObjectGet");
+ }
+
+ public static String perObjectInterfaceSet(UnresolvedType aspectType) {
+ return makeName(aspectType.getNameAsIdentifier(), "perObjectSet");
+ }
+
+ public static String perObjectInterfaceField(UnresolvedType aspectType) {
+ return makeName(aspectType.getNameAsIdentifier(), "perObjectField");
+ }
+
+ // PTWIMPL method names that must include aspect type
+ public static String perTypeWithinFieldForTarget(UnresolvedType aspectType) {
+ return makeName(aspectType.getNameAsIdentifier(), "ptwAspectInstance");
+ }
+
+ public static String perTypeWithinLocalAspectOf(UnresolvedType aspectType) {
+ return makeName(aspectType.getNameAsIdentifier(), "localAspectOf");
+ }
+
+ public static String itdAtDeclareParentsField(UnresolvedType aspectType, UnresolvedType itdType) {
+ return makeName("instance", aspectType.getNameAsIdentifier(), itdType.getNameAsIdentifier());
+ }
+
+ public static String privilegedAccessMethodForMethod(String name, UnresolvedType objectType, UnresolvedType aspectType) {
+ return makeName("privMethod", aspectType.getNameAsIdentifier(), objectType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * Create the old style (<1.6.9) format getter name which includes the aspect requesting access and the type containing the
+ * field in the name of the type. At 1.6.9 and above the name is simply ajc$get$<fieldname>
+ */
+ public static String privilegedAccessMethodForFieldGet(String name, UnresolvedType objectType, UnresolvedType aspectType) {
+ StringBuilder nameBuilder = new StringBuilder();
+ nameBuilder.append(makeName("privFieldGet", aspectType.getNameAsIdentifier(), objectType.getNameAsIdentifier(), name));
+ return nameBuilder.toString();
+ }
+
+ /**
+ * Create the old style (<1.6.9) format setter name which includes the aspect requesting access and the type containing the
+ * field in the name of the type. At 1.6.9 and above the name is simply ajc$set$<fieldname>
+ */
+ public static String privilegedAccessMethodForFieldSet(String name, UnresolvedType objectType, UnresolvedType aspectType) {
+ return makeName("privFieldSet", aspectType.getNameAsIdentifier(), objectType.getNameAsIdentifier(), name);
+ }
+
+ public static String inlineAccessMethodForMethod(String name, UnresolvedType objectType, UnresolvedType aspectType) {
+ return makeName("inlineAccessMethod", aspectType.getNameAsIdentifier(), objectType.getNameAsIdentifier(), name);
+ }
+
+ public static String inlineAccessMethodForFieldGet(String name, UnresolvedType objectType, UnresolvedType aspectType) {
+ return makeName("inlineAccessFieldGet", aspectType.getNameAsIdentifier(), objectType.getNameAsIdentifier(), name);
+ }
+
+ public static String inlineAccessMethodForFieldSet(String name, UnresolvedType objectType, UnresolvedType aspectType) {
+ return makeName("inlineAccessFieldSet", aspectType.getNameAsIdentifier(), objectType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * The name of methods corresponding to advice declarations Of the form:
+ * "ajc$[AdviceKind]$[AspectName]$[NumberOfAdviceInAspect]$[PointcutHash]"
+ */
+ public static String adviceName(String nameAsIdentifier, AdviceKind kind, int adviceSeqNumber, int pcdHash) {
+ String newname = makeName(kind.getName(), nameAsIdentifier, Integer.toString(adviceSeqNumber), Integer.toHexString(pcdHash));
+ return newname;
+ }
+
+ /**
+ * This field goes on top-most implementers of the interface the field is declared onto
+ */
+ public static String interFieldInterfaceField(UnresolvedType aspectType, UnresolvedType interfaceType, String name) {
+ return makeName("interField", aspectType.getNameAsIdentifier(), interfaceType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * This instance method goes on the interface the field is declared onto as well as its top-most implementors
+ */
+ public static String interFieldInterfaceSetter(UnresolvedType aspectType, UnresolvedType interfaceType, String name) {
+ return makeName("interFieldSet", aspectType.getNameAsIdentifier(), interfaceType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * This instance method goes on the interface the field is declared onto as well as its top-most implementors
+ */
+ public static String interFieldInterfaceGetter(UnresolvedType aspectType, UnresolvedType interfaceType, String name) {
+ return makeName("interFieldGet", aspectType.getNameAsIdentifier(), interfaceType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * This static method goes on the aspect that declares the inter-type field
+ */
+ public static String interFieldSetDispatcher(UnresolvedType aspectType, UnresolvedType onType, String name) {
+ return makeName("interFieldSetDispatch", aspectType.getNameAsIdentifier(), onType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * This static method goes on the aspect that declares the inter-type field
+ */
+ public static String interFieldGetDispatcher(UnresolvedType aspectType, UnresolvedType onType, String name) {
+ return makeName("interFieldGetDispatch", aspectType.getNameAsIdentifier(), onType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * This field goes on the class the field is declared onto
+ */
+ public static String interFieldClassField(int modifiers, UnresolvedType aspectType, UnresolvedType classType, String name) {
+ // return name;
+ if (Modifier.isPublic(modifiers)) {
+ return name;
+ }
+ // // ??? might want to handle case where aspect and class are in same package similar to public
+ return makeName("interField", makeVisibilityName(modifiers, aspectType), name);
+ }
+
+ // /**
+ // * This static method goes on the aspect that declares the inter-type field
+ // */
+ // public static String classFieldSetDispatcher(UnresolvedType aspectType, UnresolvedType classType, String name) {
+ // return makeName("interFieldSetDispatch", aspectType.getNameAsIdentifier(),
+ // classType.getNameAsIdentifier(), name);
+ // }
+ //
+ // /**
+ // * This static method goes on the aspect that declares the inter-type field
+ // */
+ // public static String classFieldGetDispatcher(UnresolvedType aspectType, UnresolvedType classType, String name)
+ // {
+ // return makeName(
+ // "interFieldGetDispatch",
+ // aspectType.getNameAsIdentifier(),
+ // classType.getNameAsIdentifier(),
+ // name);
+ // }
+
+ /**
+ * This static void method goes on the aspect that declares the inter-type field and is called from the appropriate place
+ * (target's initializer, or clinit, or topmost implementer's inits), to initialize the field;
+ */
+
+ public static String interFieldInitializer(UnresolvedType aspectType, UnresolvedType classType, String name) {
+ return makeName("interFieldInit", aspectType.getNameAsIdentifier(), classType.getNameAsIdentifier(), name);
+ }
+
+ // ----
+
+ /**
+ * This method goes on the target type of the inter-type method. (and possibly the topmost-implemeters, if the target type is an
+ * interface)
+ */
+ public static String interMethod(int modifiers, UnresolvedType aspectType, UnresolvedType classType, String name) {
+ if (Modifier.isPublic(modifiers)) {
+ return name;
+ }
+ // ??? might want to handle case where aspect and class are in same package similar to public
+ return makeName("interMethodDispatch2", makeVisibilityName(modifiers, aspectType), name);
+ }
+
+ /**
+ * This static method goes on the declaring aspect of the inter-type method.
+ */
+ public static String interMethodDispatcher(UnresolvedType aspectType, UnresolvedType classType, String name) {
+ return makeName("interMethodDispatch1", aspectType.getNameAsIdentifier(), classType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * This static method goes on the declaring aspect of the inter-type method.
+ */
+ public static String interMethodBody(UnresolvedType aspectType, UnresolvedType classType, String name) {
+ return makeName("interMethod", aspectType.getNameAsIdentifier(), classType.getNameAsIdentifier(), name);
+ }
+
+ // ----
+
+ /**
+ * This static method goes on the declaring aspect of the inter-type constructor.
+ */
+ public static String preIntroducedConstructor(UnresolvedType aspectType, UnresolvedType targetType) {
+ return makeName("preInterConstructor", aspectType.getNameAsIdentifier(), targetType.getNameAsIdentifier());
+ }
+
+ /**
+ * This static method goes on the declaring aspect of the inter-type constructor.
+ */
+ public static String postIntroducedConstructor(UnresolvedType aspectType, UnresolvedType targetType) {
+ return makeName("postInterConstructor", aspectType.getNameAsIdentifier(), targetType.getNameAsIdentifier());
+ }
+
+ // ----
+
+ /**
+ * This static method goes on the target class of the inter-type method.
+ */
+ public static String superDispatchMethod(UnresolvedType classType, String name) {
+ return makeName("superDispatch", classType.getNameAsIdentifier(), name);
+ }
+
+ /**
+ * This static method goes on the target class of the inter-type method.
+ */
+ public static String protectedDispatchMethod(UnresolvedType classType, String name) {
+ return makeName("protectedDispatch", classType.getNameAsIdentifier(), name);
+ }
+
+ // ----
+
+ private static String makeVisibilityName(int modifiers, UnresolvedType aspectType) {
+ if (Modifier.isPrivate(modifiers)) {
+ return aspectType.getOutermostType().getNameAsIdentifier();
+ } else if (Modifier.isProtected(modifiers)) {
+ throw new RuntimeException("protected inter-types not allowed");
+ } else if (Modifier.isPublic(modifiers)) {
+ return "";
+ } else {
+ return aspectType.getPackageNameAsIdentifier();
+ }
+ }
+
+ private static String makeName(String s1, String s2) {
+ return "ajc$" + s1 + "$" + s2;
+ }
+
+ public static String makeName(String s1, String s2, String s3) {
+ return "ajc$" + s1 + "$" + s2 + "$" + s3;
+ }
+
+ public static String makeName(String s1, String s2, String s3, String s4) {
+ return "ajc$" + s1 + "$" + s2 + "$" + s3 + "$" + s4;
+ }
+
+ public static String cflowStack(CrosscuttingMembers xcut) {
+ return makeName("cflowStack", Integer.toHexString(xcut.getCflowEntries().size()));
+ }
+
+ public static String cflowCounter(CrosscuttingMembers xcut) {
+ return makeName("cflowCounter", Integer.toHexString(xcut.getCflowEntries().size()));
+ }
+
+ public static String makeClosureClassName(UnresolvedType enclosingType, String suffix) {
+ return enclosingType.getName() + "$AjcClosure" + suffix;
+ }
+
+ public static String aroundShadowMethodName(Member shadowSig, String suffixTag) {
+ StringBuffer ret = new StringBuffer();
+ ret.append(getExtractableName(shadowSig)).append("_aroundBody").append(suffixTag);
+ return ret.toString();
+ }
+
+ public static String aroundAdviceMethodName(Member shadowSig, String suffixTag) {
+ StringBuffer ret = new StringBuffer();
+ ret.append(getExtractableName(shadowSig)).append("_aroundBody").append(suffixTag).append("$advice");
+ return ret.toString();
+ }
+
+ public static String getExtractableName(Member shadowSignature) {
+ String name = shadowSignature.getName();
+ MemberKind kind = shadowSignature.getKind();
+ if (kind == Member.CONSTRUCTOR) {
+ return "init$";
+ } else if (kind == Member.STATIC_INITIALIZATION) {
+ return "clinit$";
+ } else {
+ return name;
+ }
+ }
+
+ public static String proceedMethodName(String adviceMethodName) {
+ return adviceMethodName + "proceed";
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewConstructorTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewConstructorTypeMunger.java
new file mode 100644
index 000000000..d7d1ba18d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewConstructorTypeMunger.java
@@ -0,0 +1,163 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+
+public class NewConstructorTypeMunger extends ResolvedTypeMunger {
+ private ResolvedMember syntheticConstructor;
+ private ResolvedMember explicitConstructor;
+
+ public NewConstructorTypeMunger(ResolvedMember signature, ResolvedMember syntheticConstructor,
+ ResolvedMember explicitConstructor, Set superMethodsCalled, List typeVariableAliases) {
+ super(Constructor, signature);
+ this.syntheticConstructor = syntheticConstructor;
+ this.typeVariableAliases = typeVariableAliases;
+ this.explicitConstructor = explicitConstructor;
+ this.setSuperMethodsCalled(superMethodsCalled);
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof NewConstructorTypeMunger)) {
+ return false;
+ }
+ NewConstructorTypeMunger o = (NewConstructorTypeMunger) other;
+ return ((syntheticConstructor == null) ? (o.syntheticConstructor == null) : syntheticConstructor
+ .equals(o.syntheticConstructor))
+ & ((explicitConstructor == null) ? (o.explicitConstructor == null) : explicitConstructor
+ .equals(o.explicitConstructor));
+ }
+
+ // pr262218 - equivalence ignores the explicit constructor since that won't have yet been set for an EclipseTypeMunger
+ public boolean equivalentTo(Object other) {
+ if (!(other instanceof NewConstructorTypeMunger)) {
+ return false;
+ }
+ NewConstructorTypeMunger o = (NewConstructorTypeMunger) other;
+ return ((syntheticConstructor == null) ? (o.syntheticConstructor == null) : syntheticConstructor
+ .equals(o.syntheticConstructor));
+ }
+
+ private volatile int hashCode = 0;
+
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + ((syntheticConstructor == null) ? 0 : syntheticConstructor.hashCode());
+ result = 37 * result + ((explicitConstructor == null) ? 0 : explicitConstructor.hashCode());
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ // doesnt seem required....
+ // public ResolvedMember getDispatchMethod(UnresolvedType aspectType) {
+ // return AjcMemberMaker.interMethodBody(signature, aspectType);
+ // }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ signature.write(s);
+ syntheticConstructor.write(s);
+ explicitConstructor.write(s);
+ writeSuperMethodsCalled(s);
+ writeSourceLocation(s);
+ writeOutTypeAliases(s);
+ }
+
+ public static ResolvedTypeMunger readConstructor(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ISourceLocation sloc = null;
+ ResolvedMember sig = ResolvedMemberImpl.readResolvedMember(s, context);
+ ResolvedMember syntheticCtor = ResolvedMemberImpl.readResolvedMember(s, context);
+ ResolvedMember explicitCtor = ResolvedMemberImpl.readResolvedMember(s, context);
+ Set superMethodsCalled = readSuperMethodsCalled(s);
+ sloc = readSourceLocation(s);
+ List typeVarAliases = readInTypeAliases(s);
+ ResolvedTypeMunger munger = new NewConstructorTypeMunger(sig, syntheticCtor, explicitCtor, superMethodsCalled,
+ typeVarAliases);
+ if (sloc != null) {
+ munger.setSourceLocation(sloc);
+ }
+ return munger;
+ }
+
+ public ResolvedMember getExplicitConstructor() {
+ return explicitConstructor;
+ }
+
+ public ResolvedMember getSyntheticConstructor() {
+ return syntheticConstructor;
+ }
+
+ public void setExplicitConstructor(ResolvedMember explicitConstructor) {
+ this.explicitConstructor = explicitConstructor;
+ // reset hashCode so that its recalculated with new value
+ hashCode = 0;
+ }
+
+ @Override
+ public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedType aspectType) {
+ ResolvedMember ret = getSyntheticConstructor();
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ return super.getMatchingSyntheticMember(member, aspectType);
+ }
+
+ public void check(World world) {
+ if (getSignature().getDeclaringType().resolve(world).isAspect()) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ITD_CONS_ON_ASPECT), getSignature()
+ .getSourceLocation(), null);
+ }
+ }
+
+ /**
+ * see ResolvedTypeMunger.parameterizedFor(ResolvedType)
+ */
+ @Override
+ public ResolvedTypeMunger parameterizedFor(ResolvedType target) {
+ ResolvedType genericType = target;
+ if (target.isRawType() || target.isParameterizedType()) {
+ genericType = genericType.getGenericType();
+ }
+ ResolvedMember parameterizedSignature = null;
+ // If we are parameterizing it for a generic type, we just need to 'swap the letters' from the ones used
+ // in the original ITD declaration to the ones used in the actual target type declaration.
+ if (target.isGenericType()) {
+ TypeVariable vars[] = target.getTypeVariables();
+ UnresolvedTypeVariableReferenceType[] varRefs = new UnresolvedTypeVariableReferenceType[vars.length];
+ for (int i = 0; i < vars.length; i++) {
+ varRefs[i] = new UnresolvedTypeVariableReferenceType(vars[i]);
+ }
+ parameterizedSignature = getSignature().parameterizedWith(varRefs, genericType, true, typeVariableAliases);
+ } else {
+ // For raw and 'normal' parameterized targets (e.g. Interface, Interface<String>)
+ parameterizedSignature = getSignature().parameterizedWith(target.getTypeParameters(), genericType,
+ target.isParameterizedType(), typeVariableAliases);
+ }
+ NewConstructorTypeMunger nctm = new NewConstructorTypeMunger(parameterizedSignature, syntheticConstructor,
+ explicitConstructor, getSuperMethodsCalled(), typeVariableAliases);
+ nctm.setSourceLocation(getSourceLocation());
+ return nctm;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewFieldTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewFieldTypeMunger.java
new file mode 100644
index 000000000..ed8afc1e0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewFieldTypeMunger.java
@@ -0,0 +1,160 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+
+/**
+ * Code that created version one style ITD type mungers will be using direct field access from the dispatchers
+ *
+ * @author Andy
+ *
+ */
+public class NewFieldTypeMunger extends ResolvedTypeMunger {
+
+ public static final int VersionOne = 1;
+ public static final int VersionTwo = 2; // new style ITDs
+
+ public int version = VersionOne;
+
+ public NewFieldTypeMunger(ResolvedMember signature, Set superMethodsCalled, List typeVariableAliases) {
+ super(Field, signature);
+ this.version = VersionTwo;
+ this.typeVariableAliases = typeVariableAliases;
+ signature.setAnnotatedElsewhere(true);
+ this.setSuperMethodsCalled(superMethodsCalled);
+ }
+
+ public ResolvedMember getInitMethod(UnresolvedType aspectType) {
+ return AjcMemberMaker.interFieldInitializer(signature, aspectType);
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ signature.write(s);
+ writeSuperMethodsCalled(s);
+ writeSourceLocation(s);
+ writeOutTypeAliases(s);
+ s.writeInt(version);
+ }
+
+ public static ResolvedTypeMunger readField(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ISourceLocation sloc = null;
+ ResolvedMember fieldSignature = ResolvedMemberImpl.readResolvedMember(s, context);
+ Set superMethodsCalled = readSuperMethodsCalled(s);
+ sloc = readSourceLocation(s);
+ List aliases = readInTypeAliases(s);
+ NewFieldTypeMunger munger = new NewFieldTypeMunger(fieldSignature, superMethodsCalled, aliases);
+ if (sloc != null) {
+ munger.setSourceLocation(sloc);
+ }
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
+ // there is a version int
+ munger.version = s.readInt();
+ } else {
+ munger.version = VersionOne;
+ }
+ return munger;
+ }
+
+ public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedType aspectType) {
+ // ??? might give a field where a method is expected
+ ResolvedType onType = aspectType.getWorld().resolve(getSignature().getDeclaringType());
+ if (onType.isRawType()) {
+ onType = onType.getGenericType();
+ }
+
+ ResolvedMember ret = AjcMemberMaker.interFieldGetDispatcher(getSignature(), aspectType);
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ ret = AjcMemberMaker.interFieldSetDispatcher(getSignature(), aspectType);
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ ret = AjcMemberMaker.interFieldInterfaceGetter(getSignature(), onType, aspectType);
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ ret = AjcMemberMaker.interFieldInterfaceSetter(getSignature(), onType, aspectType);
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ return super.getMatchingSyntheticMember(member, aspectType);
+ }
+
+ /**
+ * see ResolvedTypeMunger.parameterizedFor(ResolvedType)
+ */
+ public ResolvedTypeMunger parameterizedFor(ResolvedType target) {
+ ResolvedType genericType = target;
+ if (target.isRawType() || target.isParameterizedType()) {
+ genericType = genericType.getGenericType();
+ }
+ ResolvedMember parameterizedSignature = null;
+ // If we are parameterizing it for a generic type, we just need to 'swap the letters' from the ones used
+ // in the original ITD declaration to the ones used in the actual target type declaration.
+ if (target.isGenericType()) {
+ TypeVariable vars[] = target.getTypeVariables();
+ UnresolvedTypeVariableReferenceType[] varRefs = new UnresolvedTypeVariableReferenceType[vars.length];
+ for (int i = 0; i < vars.length; i++) {
+ varRefs[i] = new UnresolvedTypeVariableReferenceType(vars[i]);
+ }
+ parameterizedSignature = getSignature().parameterizedWith(varRefs, genericType, true, typeVariableAliases);
+ } else {
+ // For raw and 'normal' parameterized targets (e.g. Interface, Interface<String>)
+ parameterizedSignature = getSignature().parameterizedWith(target.getTypeParameters(), genericType,
+ target.isParameterizedType(), typeVariableAliases);
+ }
+ NewFieldTypeMunger nftm = new NewFieldTypeMunger(parameterizedSignature, getSuperMethodsCalled(), typeVariableAliases);
+ nftm.setDeclaredSignature(getSignature());
+ nftm.setSourceLocation(getSourceLocation());
+ return nftm;
+ }
+
+ public ResolvedTypeMunger parameterizeWith(Map<String, UnresolvedType> m, World w) {
+ ResolvedMember parameterizedSignature = getSignature().parameterizedWith(m, w);
+ NewFieldTypeMunger nftm = new NewFieldTypeMunger(parameterizedSignature, getSuperMethodsCalled(), typeVariableAliases);
+ nftm.setDeclaredSignature(getSignature());
+ nftm.setSourceLocation(getSourceLocation());
+ return nftm;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof NewFieldTypeMunger)) {
+ return false;
+ }
+ NewFieldTypeMunger o = (NewFieldTypeMunger) other;
+ return ((kind == null) ? (o.kind == null) : kind.equals(o.kind))
+ && ((signature == null) ? (o.signature == null) : signature.equals(o.signature))
+ && ((declaredSignature == null) ? (o.declaredSignature == null) : declaredSignature.equals(o.declaredSignature))
+ && ((typeVariableAliases == null) ? (o.typeVariableAliases == null) : typeVariableAliases
+ .equals(o.typeVariableAliases));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + ((signature == null) ? 0 : signature.hashCode());
+ result = 37 * result + ((declaredSignature == null) ? 0 : declaredSignature.hashCode());
+ result = 37 * result + ((typeVariableAliases == null) ? 0 : typeVariableAliases.hashCode());
+ return result;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMemberClassTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMemberClassTypeMunger.java
new file mode 100644
index 000000000..c086c2c86
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMemberClassTypeMunger.java
@@ -0,0 +1,90 @@
+/* *******************************************************************
+ * Copyright (c) 2010 SpringSource, Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.aspectj.bridge.ISourceLocation;
+
+/**
+ * Weaver representation of an intertype declared member class. The munger captures the name of the type being declared and the
+ * target.
+ *
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public class NewMemberClassTypeMunger extends ResolvedTypeMunger {
+
+ private UnresolvedType targetType;
+ private String memberTypeName; // short (last part of) name
+ private int version = 1; // 1.6.9m2
+
+ public NewMemberClassTypeMunger(UnresolvedType targetType, String memberTypeName) {
+ super(ResolvedTypeMunger.InnerClass, null);
+ this.targetType = targetType;
+ this.memberTypeName = memberTypeName;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream stream) throws IOException {
+ kind.write(stream);
+ stream.writeInt(version);
+ targetType.write(stream);
+ stream.writeUTF(memberTypeName);
+ writeSourceLocation(stream);
+ writeOutTypeAliases(stream);
+ }
+
+ public static ResolvedTypeMunger readInnerClass(VersionedDataInputStream stream, ISourceContext context) throws IOException {
+ /* int version = */stream.readInt();
+ UnresolvedType targetType = UnresolvedType.read(stream);
+ String memberTypeName = stream.readUTF();
+ ISourceLocation sourceLocation = readSourceLocation(stream);
+ List<String> typeVarAliases = readInTypeAliases(stream);
+
+ NewMemberClassTypeMunger newInstance = new NewMemberClassTypeMunger(targetType, memberTypeName);
+ newInstance.setTypeVariableAliases(typeVarAliases);
+ newInstance.setSourceLocation(sourceLocation);
+ return newInstance;
+ }
+
+ public UnresolvedType getTargetType() {
+ return targetType;
+ }
+
+ public UnresolvedType getDeclaringType() {
+ return targetType;
+ }
+
+ public String getMemberTypeName() {
+ return memberTypeName;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + memberTypeName.hashCode();
+ result = 37 * result + targetType.hashCode();
+ result = 37 * result + ((typeVariableAliases == null) ? 0 : typeVariableAliases.hashCode());
+ return result;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof NewMemberClassTypeMunger)) {
+ return false;
+ }
+ NewMemberClassTypeMunger o = (NewMemberClassTypeMunger) other;
+ return ((kind == null) ? (o.kind == null) : kind.equals(o.kind))
+ && memberTypeName.equals(o.memberTypeName)
+ && targetType.equals(o.targetType)
+ && ((typeVariableAliases == null) ? (o.typeVariableAliases == null) : typeVariableAliases
+ .equals(o.typeVariableAliases));
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMethodTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMethodTypeMunger.java
new file mode 100644
index 000000000..a6e0ffce7
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewMethodTypeMunger.java
@@ -0,0 +1,149 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.ISourceLocation;
+
+public class NewMethodTypeMunger extends ResolvedTypeMunger {
+
+ public NewMethodTypeMunger(ResolvedMember signature, Set superMethodsCalled, List typeVariableAliases) {
+ super(Method, signature);
+ this.typeVariableAliases = typeVariableAliases;
+ this.setSuperMethodsCalled(superMethodsCalled);
+ }
+
+ public ResolvedMember getInterMethodBody(UnresolvedType aspectType) {
+ return AjcMemberMaker.interMethodBody(signature, aspectType);
+ }
+
+ /**
+ * If the munger has a declared signature
+ */
+ public ResolvedMember getDeclaredInterMethodBody(UnresolvedType aspectType, World w) {
+ if (declaredSignature != null) {
+ ResolvedMember rm = declaredSignature.parameterizedWith(null, signature.getDeclaringType().resolve(w), false,
+ getTypeVariableAliases());
+ return AjcMemberMaker.interMethodBody(rm, aspectType);
+ } else {
+ return AjcMemberMaker.interMethodBody(signature, aspectType);
+ }
+ }
+
+ // public ResolvedMember getInterMethodDispatcher(UnresolvedType aspectType) {
+ // return AjcMemberMaker.interMethodDispatcher(signature, aspectType);
+ // }
+
+ public ResolvedMember getDeclaredInterMethodDispatcher(UnresolvedType aspectType, World w) {
+ if (declaredSignature != null) {
+ ResolvedMember rm = declaredSignature.parameterizedWith(null, signature.getDeclaringType().resolve(w), false,
+ getTypeVariableAliases());
+ return AjcMemberMaker.interMethodDispatcher(rm, aspectType);
+ } else {
+ return AjcMemberMaker.interMethodDispatcher(signature, aspectType);
+ }
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ signature.write(s);
+ writeSuperMethodsCalled(s);
+ writeSourceLocation(s);
+ writeOutTypeAliases(s);
+ }
+
+ public static ResolvedTypeMunger readMethod(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ISourceLocation sloc = null;
+ ResolvedMemberImpl rmImpl = ResolvedMemberImpl.readResolvedMember(s, context);
+ Set<ResolvedMember> superMethodsCalled = readSuperMethodsCalled(s);
+ sloc = readSourceLocation(s);
+ List<String> typeVarAliases = readInTypeAliases(s);
+
+ ResolvedTypeMunger munger = new NewMethodTypeMunger(rmImpl, superMethodsCalled, typeVarAliases);
+ if (sloc != null) {
+ munger.setSourceLocation(sloc);
+ }
+ return munger;
+ }
+
+ public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedType aspectType) {
+ ResolvedMember ret = AjcMemberMaker.interMethodDispatcher(getSignature(), aspectType);
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ return super.getMatchingSyntheticMember(member, aspectType);
+ }
+
+ /**
+ * see ResolvedTypeMunger.parameterizedFor(ResolvedType)
+ */
+ public ResolvedTypeMunger parameterizedFor(ResolvedType target) {
+ ResolvedType genericType = target;
+ if (target.isRawType() || target.isParameterizedType()) {
+ genericType = genericType.getGenericType();
+ }
+ ResolvedMember parameterizedSignature = null;
+ // If we are parameterizing it for a generic type, we just need to 'swap the letters' from the ones used
+ // in the original ITD declaration to the ones used in the actual target type declaration.
+ if (target.isGenericType()) {
+ TypeVariable vars[] = target.getTypeVariables();
+ UnresolvedTypeVariableReferenceType[] varRefs = new UnresolvedTypeVariableReferenceType[vars.length];
+ for (int i = 0; i < vars.length; i++) {
+ varRefs[i] = new UnresolvedTypeVariableReferenceType(vars[i]);
+ }
+ parameterizedSignature = getSignature().parameterizedWith(varRefs, genericType, true, typeVariableAliases);
+ } else {
+ // For raw and 'normal' parameterized targets (e.g. Interface, Interface<String>)
+ parameterizedSignature = getSignature().parameterizedWith(target.getTypeParameters(), genericType,
+ target.isParameterizedType(), typeVariableAliases);
+ }
+ NewMethodTypeMunger nmtm = new NewMethodTypeMunger(parameterizedSignature, getSuperMethodsCalled(), typeVariableAliases);
+ nmtm.setDeclaredSignature(getSignature());
+ nmtm.setSourceLocation(getSourceLocation());
+ return nmtm;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof NewMethodTypeMunger)) {
+ return false;
+ }
+ NewMethodTypeMunger o = (NewMethodTypeMunger) other;
+ return ((kind == null) ? (o.kind == null) : kind.equals(o.kind))
+ && ((signature == null) ? (o.signature == null) : signature.equals(o.signature))
+ && ((declaredSignature == null) ? (o.declaredSignature == null) : declaredSignature.equals(o.declaredSignature))
+ && ((typeVariableAliases == null) ? (o.typeVariableAliases == null) : typeVariableAliases
+ .equals(o.typeVariableAliases));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + ((signature == null) ? 0 : signature.hashCode());
+ result = 37 * result + ((declaredSignature == null) ? 0 : declaredSignature.hashCode());
+ result = 37 * result + ((typeVariableAliases == null) ? 0 : typeVariableAliases.hashCode());
+ return result;
+ }
+
+ public ResolvedTypeMunger parameterizeWith(Map<String, UnresolvedType> m, World w) {
+ ResolvedMember parameterizedSignature = getSignature().parameterizedWith(m, w);
+ NewMethodTypeMunger nmtm = new NewMethodTypeMunger(parameterizedSignature, getSuperMethodsCalled(), typeVariableAliases);
+ nmtm.setDeclaredSignature(getSignature());
+ nmtm.setSourceLocation(getSourceLocation());
+ return nmtm;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewParentTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewParentTypeMunger.java
new file mode 100644
index 000000000..cb3110073
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/NewParentTypeMunger.java
@@ -0,0 +1,68 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+public class NewParentTypeMunger extends ResolvedTypeMunger {
+ ResolvedType newParent;
+ ResolvedType declaringType;
+ private boolean isMixin;
+
+ public NewParentTypeMunger(ResolvedType newParent, ResolvedType declaringType) {
+ super(Parent, null);
+ this.newParent = newParent;
+ this.declaringType = declaringType;
+ this.isMixin = false;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public ResolvedType getNewParent() {
+ return newParent;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof NewParentTypeMunger)) {
+ return false;
+ }
+ NewParentTypeMunger o = (NewParentTypeMunger) other;
+ return newParent.equals(o.newParent) && isMixin == o.isMixin;
+ }
+
+ private volatile int hashCode = 0;
+
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + newParent.hashCode();
+ result = 37 * result + (isMixin ? 0 : 1);
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ public ResolvedType getDeclaringType() {
+ return declaringType;
+ }
+
+ public void setIsMixin(boolean b) {
+ isMixin = true;
+ }
+
+ public boolean isMixin() {
+ return isMixin;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerObjectInterfaceTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerObjectInterfaceTypeMunger.java
new file mode 100644
index 000000000..ce4348241
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerObjectInterfaceTypeMunger.java
@@ -0,0 +1,96 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Alexandre Vasseur rearchitected for #75442 finer grained matching
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+import org.aspectj.weaver.patterns.PerFromSuper;
+import org.aspectj.weaver.patterns.PerObject;
+import org.aspectj.weaver.patterns.PerThisOrTargetPointcutVisitor;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+
+public class PerObjectInterfaceTypeMunger extends ResolvedTypeMunger {
+
+ private final UnresolvedType interfaceType;
+ private final Pointcut testPointcut;
+ private TypePattern lazyTestTypePattern;
+
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof PerObjectInterfaceTypeMunger)) {
+ return false;
+ }
+ PerObjectInterfaceTypeMunger o = (PerObjectInterfaceTypeMunger) other;
+ return ((testPointcut == null) ? (o.testPointcut == null) : testPointcut.equals(o.testPointcut))
+ && ((lazyTestTypePattern == null) ? (o.lazyTestTypePattern == null) : lazyTestTypePattern
+ .equals(o.lazyTestTypePattern));
+ }
+
+ private volatile int hashCode = 0;
+
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + ((testPointcut == null) ? 0 : testPointcut.hashCode());
+ result = 37 * result + ((lazyTestTypePattern == null) ? 0 : lazyTestTypePattern.hashCode());
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ public PerObjectInterfaceTypeMunger(UnresolvedType aspectType, Pointcut testPointcut) {
+ super(PerObjectInterface, null);
+ this.testPointcut = testPointcut;
+ this.interfaceType = AjcMemberMaker.perObjectInterfaceType(aspectType);
+ }
+
+ private TypePattern getTestTypePattern(ResolvedType aspectType) {
+ if (lazyTestTypePattern == null) {
+ final boolean isPerThis;
+ if (aspectType.getPerClause() instanceof PerFromSuper) {
+ PerFromSuper ps = (PerFromSuper) aspectType.getPerClause();
+ isPerThis = ((PerObject) ps.lookupConcretePerClause(aspectType)).isThis();
+ } else {
+ isPerThis = ((PerObject) aspectType.getPerClause()).isThis();
+ }
+ PerThisOrTargetPointcutVisitor v = new PerThisOrTargetPointcutVisitor(!isPerThis, aspectType);
+ lazyTestTypePattern = v.getPerTypePointcut(testPointcut);
+ // reset hashCode so that its recalculated with the new lazyTestTypePattern
+ hashCode = 0;
+ }
+ return lazyTestTypePattern;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new RuntimeException("shouldn't be serialized");
+ }
+
+ public UnresolvedType getInterfaceType() {
+ return interfaceType;
+ }
+
+ public Pointcut getTestPointcut() {
+ return testPointcut;
+ }
+
+ public boolean matches(ResolvedType matchType, ResolvedType aspectType) {
+ if (matchType.isInterface()) {
+ return false;
+ }
+ return getTestTypePattern(aspectType).matchesStatically(matchType);
+ }
+
+ public boolean isLateMunger() {
+ return true;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerTypeWithinTargetTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerTypeWithinTargetTypeMunger.java
new file mode 100644
index 000000000..ad549417a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PerTypeWithinTargetTypeMunger.java
@@ -0,0 +1,86 @@
+/* *******************************************************************
+ * Copyright (c) 2005 IBM, Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.patterns.PerTypeWithin;
+import org.aspectj.weaver.patterns.Pointcut;
+
+// PTWIMPL Target type munger adds the localAspectOf() method
+public class PerTypeWithinTargetTypeMunger extends ResolvedTypeMunger {
+ private UnresolvedType aspectType;
+ private PerTypeWithin testPointcut;
+
+ public PerTypeWithinTargetTypeMunger(UnresolvedType aspectType, PerTypeWithin testPointcut) {
+ super(PerTypeWithinInterface, null);
+ this.aspectType = aspectType;
+ this.testPointcut = testPointcut;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof PerTypeWithinTargetTypeMunger)) {
+ return false;
+ }
+ PerTypeWithinTargetTypeMunger o = (PerTypeWithinTargetTypeMunger) other;
+ return ((o.testPointcut == null) ? (testPointcut == null) : testPointcut.equals(o.testPointcut))
+ && ((o.aspectType == null) ? (aspectType == null) : aspectType.equals(o.aspectType));
+ }
+
+ private volatile int hashCode = 0;
+
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37 * result + ((testPointcut == null) ? 0 : testPointcut.hashCode());
+ result = 37 * result + ((aspectType == null) ? 0 : aspectType.hashCode());
+ hashCode = result;
+ }
+ return hashCode;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new RuntimeException("shouldn't be serialized");
+ }
+
+ public UnresolvedType getAspectType() {
+ return aspectType;
+ }
+
+ public Pointcut getTestPointcut() {
+ return testPointcut;
+ }
+
+ // This is a lexical within() so if you say PerTypeWithin(Test) and matchType is an
+ // inner type (e.g. Test$NestedType) then it should match successfully
+ // Does not match if the target is an interface
+ @Override
+ public boolean matches(ResolvedType matchType, ResolvedType aspectType) {
+ return isWithinType(matchType).alwaysTrue() && !matchType.isInterface() && (matchType.canBeSeenBy(aspectType) || aspectType.isPrivilegedAspect());
+ }
+
+ private FuzzyBoolean isWithinType(ResolvedType type) {
+ while (type != null) {
+ if (testPointcut.getTypePattern().matchesStatically(type)) {
+ return FuzzyBoolean.YES;
+ }
+ type = type.getDeclaringType();
+ }
+ return FuzzyBoolean.NO;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PersistenceSupport.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PersistenceSupport.java
new file mode 100644
index 000000000..d98c7678d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PersistenceSupport.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * Copyright (c) 2009 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/**
+ * @author Andy Clement
+ */
+public class PersistenceSupport {
+
+ public static void write(CompressingDataOutputStream stream, ISourceContext sourceContext) throws IOException {
+ throw new IllegalStateException();
+ }
+
+ public static void write(CompressingDataOutputStream stream, Serializable serializableObject) throws IOException {
+ ObjectOutputStream oos = new ObjectOutputStream(stream);
+ oos.writeObject(serializableObject);
+ oos.flush();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PoliceExtensionUse.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PoliceExtensionUse.java
new file mode 100644
index 000000000..e35a9b8a3
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PoliceExtensionUse.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
+import org.aspectj.weaver.patterns.AndPointcut;
+import org.aspectj.weaver.patterns.KindedPointcut;
+import org.aspectj.weaver.patterns.NotPointcut;
+import org.aspectj.weaver.patterns.OrPointcut;
+import org.aspectj.weaver.patterns.Pointcut;
+
+/**
+ * Walks a pointcut and determines if the synchronization related designators have been used: lock() or unlock()
+ */
+public class PoliceExtensionUse extends AbstractPatternNodeVisitor {
+
+ private boolean synchronizationDesignatorEncountered;
+ private World world;
+ private Pointcut p;
+
+ public PoliceExtensionUse(World w, Pointcut p) {
+ this.world = w;
+ this.p = p;
+ this.synchronizationDesignatorEncountered = false;
+ }
+
+ public boolean synchronizationDesignatorEncountered() {
+ return synchronizationDesignatorEncountered;
+ }
+
+ public Object visit(KindedPointcut node, Object data) {
+ if (world == null)
+ return super.visit(node, data); // error scenario can sometimes lead to this LazyClassGen.toLongString()
+ if (node.getKind() == Shadow.SynchronizationLock || node.getKind() == Shadow.SynchronizationUnlock)
+ synchronizationDesignatorEncountered = true;
+ // Check it!
+ if (!world.isJoinpointSynchronizationEnabled()) {
+ if (node.getKind() == Shadow.SynchronizationLock) {
+ IMessage m = MessageUtil.warn(
+ "lock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization", p
+ .getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ } else if (node.getKind() == Shadow.SynchronizationUnlock) {
+ IMessage m = MessageUtil.warn(
+ "unlock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization", p
+ .getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ }
+ }
+ return super.visit(node, data);
+ }
+
+ public Object visit(AndPointcut node, Object data) {
+ node.getLeft().accept(this, data);
+ node.getRight().accept(this, data);
+ return node;
+ }
+
+ public Object visit(NotPointcut node, Object data) {
+ node.getNegatedPointcut().accept(this, data);
+ return node;
+ }
+
+ public Object visit(OrPointcut node, Object data) {
+ node.getLeft().accept(this, data);
+ node.getRight().accept(this, data);
+ return node;
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Position.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Position.java
new file mode 100644
index 000000000..af9f38328
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Position.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+public class Position implements IHasPosition {
+ private int start, end;
+
+ public Position(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PrivilegedAccessMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PrivilegedAccessMunger.java
new file mode 100644
index 000000000..3acbf9b4b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/PrivilegedAccessMunger.java
@@ -0,0 +1,94 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+/**
+ * A privileged access munger is for handling privileged access to a member. It determines the names of the getter/setter that will
+ * be used to access a private field in some type, or the special method that provides access to a private method.
+ *
+ * There are two syntax styles for field access, the older style was in use up to AspectJ 1.6.9 and involves long named getters and
+ * setters which include the requesting aspect and the target type. The short style syntax is use from AspectJ 1.6.9 onwards is
+ * simply 'ajc$get$<fieldname>' and 'ajc$set$<fieldname>' - as the requesting aspect isn't included in the name they can be shared
+ * across aspects.
+ */
+public class PrivilegedAccessMunger extends ResolvedTypeMunger {
+
+ public boolean shortSyntax = false;
+
+ public PrivilegedAccessMunger(ResolvedMember member, boolean shortSyntax) {
+ super(PrivilegedAccess, member);
+ this.shortSyntax = shortSyntax;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new RuntimeException("should not be serialized");
+ }
+
+ public ResolvedMember getMember() {
+ return getSignature();
+ }
+
+ @Override
+ public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedType aspectType) {
+ ResolvedMember ret;
+ // assert if shortSyntax then aspectType.getCompilerVersion()>=169
+ if (getSignature().getKind() == Member.FIELD) {
+ ret = AjcMemberMaker.privilegedAccessMethodForFieldGet(aspectType, getSignature(), shortSyntax);
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ ret = AjcMemberMaker.privilegedAccessMethodForFieldSet(aspectType, getSignature(), shortSyntax);
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ } else {
+ // System.err.println("sig: " + getSignature());
+ ret = AjcMemberMaker.privilegedAccessMethodForMethod(aspectType, getSignature());
+ if (ResolvedType.matches(ret, member)) {
+ return getSignature();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof PrivilegedAccessMunger)) {
+ return false;
+ }
+ PrivilegedAccessMunger o = (PrivilegedAccessMunger) other;
+ return kind.equals(o.kind)
+ && ((o.signature == null) ? (signature == null) : signature.equals(o.signature))
+ && ((o.declaredSignature == null) ? (declaredSignature == null) : declaredSignature.equals(o.declaredSignature))
+ && ((o.typeVariableAliases == null) ? (typeVariableAliases == null) : typeVariableAliases
+ .equals(o.typeVariableAliases));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + ((signature == null) ? 0 : signature.hashCode());
+ result = 37 * result + ((declaredSignature == null) ? 0 : declaredSignature.hashCode());
+ result = 37 * result + ((typeVariableAliases == null) ? 0 : typeVariableAliases.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean existsToSupportShadowMunging() {
+ return true;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceType.java
new file mode 100644
index 000000000..7dc162a16
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceType.java
@@ -0,0 +1,1280 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Andy Clement - June 2005 - separated out from ResolvedType
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.World.TypeMap;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.PerClause;
+
+/**
+ * A reference type represents some 'real' type, not a primitive, not an array -
+ * but a real type, for example java.util.List. Each ReferenceType has a
+ * delegate that is the underlying artifact - either an eclipse artifact or a
+ * bcel artifact. If the type represents a raw type (i.e. there is a generic
+ * form) then the genericType field is set to point to the generic type. If it
+ * is for a parameterized type then the generic type is also set to point to the
+ * generic form.
+ */
+public class ReferenceType extends ResolvedType {
+
+ public static final ReferenceType[] EMPTY_ARRAY = new ReferenceType[0];
+
+ /**
+ * For generic types, this list holds references to all the derived raw and
+ * parameterized versions. We need this so that if the generic delegate is
+ * swapped during incremental compilation, the delegate of the derivatives
+ * is swapped also.
+ */
+ private final List<WeakReference<ReferenceType>> derivativeTypes = new ArrayList<WeakReference<ReferenceType>>();
+
+ /**
+ * For parameterized types (or the raw type) - this field points to the
+ * actual reference type from which they are derived.
+ */
+ ReferenceType genericType = null;
+
+ ReferenceType rawType = null; // generic types have a pointer back to their
+ // raw variant (prevents GC of the raw from
+ // the typemap!)
+
+ ReferenceTypeDelegate delegate = null;
+ int startPos = 0;
+ int endPos = 0;
+
+ // cached values for members
+ ResolvedMember[] parameterizedMethods = null;
+ ResolvedMember[] parameterizedFields = null;
+ ResolvedMember[] parameterizedPointcuts = null;
+ WeakReference<ResolvedType[]> parameterizedInterfaces = new WeakReference<ResolvedType[]>(
+ null);
+ Collection<Declare> parameterizedDeclares = null;
+ // Collection parameterizedTypeMungers = null;
+
+ // During matching it can be necessary to temporary mark types as annotated.
+ // For example
+ // a declare @type may trigger a separate declare parents to match, and so
+ // the annotation
+ // is temporarily held against the referencetype, the annotation will be
+ // properly
+ // added to the class during weaving.
+ private ResolvedType[] annotationTypes = null;
+ private AnnotationAJ[] annotations = null;
+
+ // Similarly these are temporary replacements and additions for the
+ // superclass and
+ // superinterfaces
+ private ResolvedType newSuperclass;
+ private ResolvedType[] newInterfaces;
+
+ public ReferenceType(String signature, World world) {
+ super(signature, world);
+ }
+
+ public ReferenceType(String signature, String signatureErasure, World world) {
+ super(signature, signatureErasure, world);
+ }
+
+ public static ReferenceType fromTypeX(UnresolvedType tx, World world) {
+ ReferenceType rt = new ReferenceType(tx.getErasureSignature(), world);
+ rt.typeKind = tx.typeKind;
+ return rt;
+ }
+
+ /**
+ * Constructor used when creating a parameterized type.
+ */
+ public ReferenceType(ResolvedType theGenericType,
+ ResolvedType[] theParameters, World aWorld) {
+ super(makeParameterizedSignature(theGenericType, theParameters),
+ theGenericType.signatureErasure, aWorld);
+ ReferenceType genericReferenceType = (ReferenceType) theGenericType;
+ this.typeParameters = theParameters;
+ this.genericType = genericReferenceType;
+ this.typeKind = TypeKind.PARAMETERIZED;
+ this.delegate = genericReferenceType.getDelegate();
+ genericReferenceType.addDependentType(this);
+ }
+
+ synchronized void addDependentType(ReferenceType dependent) {
+ // checkDuplicates(dependent);
+ synchronized (derivativeTypes) {
+ this.derivativeTypes
+ .add(new WeakReference<ReferenceType>(dependent));
+ }
+ }
+
+ public void checkDuplicates(ReferenceType newRt) {
+ synchronized (derivativeTypes) {
+ List<WeakReference<ReferenceType>> forRemoval = new ArrayList<WeakReference<ReferenceType>>();
+ for (WeakReference<ReferenceType> derivativeTypeReference : derivativeTypes) {
+ ReferenceType derivativeType = derivativeTypeReference.get();
+ if (derivativeType == null) {
+ forRemoval.add(derivativeTypeReference);
+ } else {
+ if (derivativeType.getTypekind() != newRt.getTypekind()) {
+ continue; // cannot be this one
+ }
+ if (equal2(newRt.getTypeParameters(),
+ derivativeType.getTypeParameters())) {
+ if (TypeMap.useExpendableMap) {
+ throw new IllegalStateException();
+ }
+ }
+ }
+ }
+ derivativeTypes.removeAll(forRemoval);
+ }
+ }
+
+ private boolean equal2(UnresolvedType[] typeParameters,
+ UnresolvedType[] resolvedParameters) {
+ if (typeParameters.length != resolvedParameters.length) {
+ return false;
+ }
+ int len = typeParameters.length;
+ for (int p = 0; p < len; p++) {
+ if (!typeParameters[p].equals(resolvedParameters[p])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String getSignatureForAttribute() {
+ if (genericType == null || typeParameters == null) {
+ return getSignature();
+ }
+ return makeDeclaredSignature(genericType, typeParameters);
+ }
+
+ /**
+ * Create a reference type for a generic type
+ */
+ public ReferenceType(UnresolvedType genericType, World world) {
+ super(genericType.getSignature(), world);
+ typeKind = TypeKind.GENERIC;
+ this.typeVariables = genericType.typeVariables;
+ }
+
+ @Override
+ public boolean isClass() {
+ return getDelegate().isClass();
+ }
+
+ @Override
+ public int getCompilerVersion() {
+ return getDelegate().getCompilerVersion();
+ }
+
+ @Override
+ public boolean isGenericType() {
+ return !isParameterizedType() && !isRawType()
+ && getDelegate().isGeneric();
+ }
+
+ public String getGenericSignature() {
+ String sig = getDelegate().getDeclaredGenericSignature();
+ return (sig == null) ? "" : sig;
+ }
+
+ @Override
+ public AnnotationAJ[] getAnnotations() {
+ return getDelegate().getAnnotations();
+ }
+
+ @Override
+ public boolean hasAnnotations() {
+ return getDelegate().hasAnnotations();
+ }
+
+ @Override
+ public void addAnnotation(AnnotationAJ annotationX) {
+ if (annotations == null) {
+ annotations = new AnnotationAJ[] { annotationX };
+ } else {
+ AnnotationAJ[] newAnnotations = new AnnotationAJ[annotations.length + 1];
+ System.arraycopy(annotations, 0, newAnnotations, 1,
+ annotations.length);
+ newAnnotations[0] = annotationX;
+ annotations = newAnnotations;
+ }
+ addAnnotationType(annotationX.getType());
+ }
+
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ boolean onDelegate = getDelegate().hasAnnotation(ofType);
+ if (onDelegate) {
+ return true;
+ }
+ if (annotationTypes != null) {
+ for (int i = 0; i < annotationTypes.length; i++) {
+ if (annotationTypes[i].equals(ofType)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void addAnnotationType(ResolvedType ofType) {
+ if (annotationTypes == null) {
+ annotationTypes = new ResolvedType[1];
+ annotationTypes[0] = ofType;
+ } else {
+ ResolvedType[] newAnnotationTypes = new ResolvedType[annotationTypes.length + 1];
+ System.arraycopy(annotationTypes, 0, newAnnotationTypes, 1,
+ annotationTypes.length);
+ newAnnotationTypes[0] = ofType;
+ annotationTypes = newAnnotationTypes;
+ }
+ }
+
+ @Override
+ public ResolvedType[] getAnnotationTypes() {
+ if (getDelegate() == null) {
+ throw new BCException("Unexpected null delegate for type "
+ + this.getName());
+ }
+ if (annotationTypes == null) {
+ // there are no extras:
+ return getDelegate().getAnnotationTypes();
+ } else {
+ ResolvedType[] delegateAnnotationTypes = getDelegate()
+ .getAnnotationTypes();
+ ResolvedType[] result = new ResolvedType[annotationTypes.length
+ + delegateAnnotationTypes.length];
+ System.arraycopy(delegateAnnotationTypes, 0, result, 0,
+ delegateAnnotationTypes.length);
+ System.arraycopy(annotationTypes, 0, result,
+ delegateAnnotationTypes.length, annotationTypes.length);
+ return result;
+ }
+ }
+
+ @Override
+ public String getNameAsIdentifier() {
+ return getRawName().replace('.', '_');
+ }
+
+ @Override
+ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
+ AnnotationAJ[] axs = getDelegate().getAnnotations();
+ if (axs != null) {
+ for (int i = 0; i < axs.length; i++) {
+ if (axs[i].getTypeSignature().equals(ofType.getSignature())) {
+ return axs[i];
+ }
+ }
+ }
+ if (annotations != null) {
+ String searchSig = ofType.getSignature();
+ for (int i = 0; i < annotations.length; i++) {
+ if (annotations[i].getTypeSignature().equals(searchSig)) {
+ return annotations[i];
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isAspect() {
+ return getDelegate().isAspect();
+ }
+
+ @Override
+ public boolean isAnnotationStyleAspect() {
+ return getDelegate().isAnnotationStyleAspect();
+ }
+
+ @Override
+ public boolean isEnum() {
+ return getDelegate().isEnum();
+ }
+
+ @Override
+ public boolean isAnnotation() {
+ return getDelegate().isAnnotation();
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ return getDelegate().isAnonymous();
+ }
+
+ @Override
+ public boolean isNested() {
+ return getDelegate().isNested();
+ }
+
+ public ResolvedType getOuterClass() {
+ return getDelegate().getOuterClass();
+ }
+
+ public String getRetentionPolicy() {
+ return getDelegate().getRetentionPolicy();
+ }
+
+ @Override
+ public boolean isAnnotationWithRuntimeRetention() {
+ return getDelegate().isAnnotationWithRuntimeRetention();
+ }
+
+ @Override
+ public boolean canAnnotationTargetType() {
+ return getDelegate().canAnnotationTargetType();
+ }
+
+ @Override
+ public AnnotationTargetKind[] getAnnotationTargetKinds() {
+ return getDelegate().getAnnotationTargetKinds();
+ }
+
+ // true iff the statement "this = (ThisType) other" would compile
+ @Override
+ public boolean isCoerceableFrom(ResolvedType o) {
+ ResolvedType other = o.resolve(world);
+
+ if (this.isAssignableFrom(other) || other.isAssignableFrom(this)) {
+ return true;
+ }
+
+ if (this.isParameterizedType() && other.isParameterizedType()) {
+ return isCoerceableFromParameterizedType(other);
+ }
+
+ if (this.isParameterizedType() && other.isRawType()) {
+ return ((ReferenceType) this.getRawType()).isCoerceableFrom(other
+ .getGenericType());
+ }
+
+ if (this.isRawType() && other.isParameterizedType()) {
+ return this.getGenericType().isCoerceableFrom((other.getRawType()));
+ }
+
+ if (!this.isInterface() && !other.isInterface()) {
+ return false;
+ }
+ if (this.isFinal() || other.isFinal()) {
+ return false;
+ }
+
+ // 20170927: What is the block of code for? It mentions jls5.5 which isn't on this topic (old version of jls?)
+ // Some possible references: http://docs.oracle.com/javase/specs/jls/se9/jls9.pdf 5.1.6 (narrowing reference conversion)
+ // On Java 9 the test GenericsTests.testAfterReturningWithWildcardVar will fail because this code below
+ // used to find Set and List were the same, but now finds they are not. (so it doesn't put out the unchecked
+ // conversion message). However the code "List l = (List)someSet;" still compiles on 9 - so is this code bogus?
+
+ // ??? needs to be Methods, not just declared methods? JLS 5.5 unclear
+ ResolvedMember[] a = getDeclaredMethods();
+ ResolvedMember[] b = other.getDeclaredMethods();
+ for (int ai = 0, alen = a.length; ai < alen; ai++) {
+ for (int bi = 0, blen = b.length; bi < blen; bi++) {
+ if (!b[bi].isCompatibleWith(a[ai])) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private final boolean isCoerceableFromParameterizedType(ResolvedType other) {
+ if (!other.isParameterizedType()) {
+ return false;
+ }
+ ResolvedType myRawType = getRawType();
+ ResolvedType theirRawType = other.getRawType();
+ if (myRawType == theirRawType
+ || myRawType.isCoerceableFrom(theirRawType)) {
+ if (getTypeParameters().length == other.getTypeParameters().length) {
+ // there's a chance it can be done
+ ResolvedType[] myTypeParameters = getResolvedTypeParameters();
+ ResolvedType[] theirTypeParameters = other
+ .getResolvedTypeParameters();
+ for (int i = 0; i < myTypeParameters.length; i++) {
+ if (myTypeParameters[i] != theirTypeParameters[i]) {
+ // thin ice now... but List<String> may still be
+ // coerceable from e.g. List<T>
+ if (myTypeParameters[i].isGenericWildcard()) {
+ BoundedReferenceType wildcard = (BoundedReferenceType) myTypeParameters[i];
+ if (!wildcard
+ .canBeCoercedTo(theirTypeParameters[i])) {
+ return false;
+ }
+ } else if (myTypeParameters[i]
+ .isTypeVariableReference()) {
+ TypeVariableReferenceType tvrt = (TypeVariableReferenceType) myTypeParameters[i];
+ TypeVariable tv = tvrt.getTypeVariable();
+ tv.resolve(world);
+ if (!tv.canBeBoundTo(theirTypeParameters[i])) {
+ return false;
+ }
+ } else if (theirTypeParameters[i]
+ .isTypeVariableReference()) {
+ TypeVariableReferenceType tvrt = (TypeVariableReferenceType) theirTypeParameters[i];
+ TypeVariable tv = tvrt.getTypeVariable();
+ tv.resolve(world);
+ if (!tv.canBeBoundTo(myTypeParameters[i])) {
+ return false;
+ }
+ } else if (theirTypeParameters[i].isGenericWildcard()) {
+ BoundedReferenceType wildcard = (BoundedReferenceType) theirTypeParameters[i];
+ if (!wildcard.canBeCoercedTo(myTypeParameters[i])) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ // } else {
+ // // we do this walk for situations like the following:
+ // // Base<T>, Sub<S,T> extends Base<S>
+ // // is Sub<Y,Z> coerceable from Base<X> ???
+ // for (Iterator i = getDirectSupertypes(); i.hasNext();) {
+ // ReferenceType parent = (ReferenceType) i.next();
+ // if (parent.isCoerceableFromParameterizedType(other))
+ // return true;
+ // }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isAssignableFrom(ResolvedType other) {
+ return isAssignableFrom(other, false);
+ }
+
+ // TODO rewrite this method - it is a terrible mess
+
+ // true iff the statement "this = other" would compile.
+ @Override
+ public boolean isAssignableFrom(ResolvedType other, boolean allowMissing) {
+ if (other.isPrimitiveType()) {
+ if (!world.isInJava5Mode()) {
+ return false;
+ }
+ if (ResolvedType.validBoxing.contains(this.getSignature()
+ + other.getSignature())) {
+ return true;
+ }
+ }
+ if (this == other) {
+ return true;
+ }
+
+ if (this.getSignature().equals("Ljava/lang/Object;")) {
+ return true;
+ }
+
+ if (!isTypeVariableReference()
+ && other.getSignature().equals("Ljava/lang/Object;")) {
+ return false;
+ }
+
+ boolean thisRaw = this.isRawType();
+ if (thisRaw && other.isParameterizedOrGenericType()) {
+ return isAssignableFrom(other.getRawType());
+ }
+
+ boolean thisGeneric = this.isGenericType();
+ if (thisGeneric && other.isParameterizedOrRawType()) {
+ return isAssignableFrom(other.getGenericType());
+ }
+
+ if (this.isParameterizedType()) {
+ // look at wildcards...
+ if (((ReferenceType) this.getRawType()).isAssignableFrom(other)) {
+ boolean wildcardsAllTheWay = true;
+ ResolvedType[] myParameters = this.getResolvedTypeParameters();
+ for (int i = 0; i < myParameters.length; i++) {
+ if (!myParameters[i].isGenericWildcard()) {
+ wildcardsAllTheWay = false;
+ } else {
+ BoundedReferenceType boundedRT = (BoundedReferenceType) myParameters[i];
+ if (boundedRT.isExtends() || boundedRT.isSuper()) {
+ wildcardsAllTheWay = false;
+ }
+ }
+ }
+ if (wildcardsAllTheWay && !other.isParameterizedType()) {
+ return true;
+ }
+ // we have to match by parameters one at a time
+ ResolvedType[] theirParameters = other
+ .getResolvedTypeParameters();
+ boolean parametersAssignable = true;
+ if (myParameters.length == theirParameters.length) {
+ for (int i = 0; i < myParameters.length
+ && parametersAssignable; i++) {
+ if (myParameters[i] == theirParameters[i]) {
+ continue;
+ }
+ // dont do this: pr253109
+ // if
+ // (myParameters[i].isAssignableFrom(theirParameters[i],
+ // allowMissing)) {
+ // continue;
+ // }
+ ResolvedType mp = myParameters[i];
+ ResolvedType tp = theirParameters[i];
+ if (mp.isParameterizedType()
+ && tp.isParameterizedType()) {
+ if (mp.getGenericType().equals(tp.getGenericType())) {
+ UnresolvedType[] mtps = mp.getTypeParameters();
+ UnresolvedType[] ttps = tp.getTypeParameters();
+ for (int ii = 0; ii < mtps.length; ii++) {
+ if (mtps[ii].isTypeVariableReference()
+ && ttps[ii]
+ .isTypeVariableReference()) {
+ TypeVariable mtv = ((TypeVariableReferenceType) mtps[ii])
+ .getTypeVariable();
+ boolean b = mtv
+ .canBeBoundTo((ResolvedType) ttps[ii]);
+ if (!b) {// TODO incomplete testing here
+ // I think
+ parametersAssignable = false;
+ break;
+ }
+ } else {
+ parametersAssignable = false;
+ break;
+ }
+ }
+ continue;
+ } else {
+ parametersAssignable = false;
+ break;
+ }
+ }
+ if (myParameters[i].isTypeVariableReference()
+ && theirParameters[i].isTypeVariableReference()) {
+ TypeVariable myTV = ((TypeVariableReferenceType) myParameters[i])
+ .getTypeVariable();
+ // TypeVariable theirTV =
+ // ((TypeVariableReferenceType)
+ // theirParameters[i]).getTypeVariable();
+ boolean b = myTV.canBeBoundTo(theirParameters[i]);
+ if (!b) {// TODO incomplete testing here I think
+ parametersAssignable = false;
+ break;
+ } else {
+ continue;
+ }
+ }
+ if (!myParameters[i].isGenericWildcard()) {
+ parametersAssignable = false;
+ break;
+ } else {
+ BoundedReferenceType wildcardType = (BoundedReferenceType) myParameters[i];
+ if (!wildcardType.alwaysMatches(theirParameters[i])) {
+ parametersAssignable = false;
+ break;
+ }
+ }
+ }
+ } else {
+ parametersAssignable = false;
+ }
+ if (parametersAssignable) {
+ return true;
+ }
+ }
+ }
+
+ // eg this=T other=Ljava/lang/Object;
+ if (isTypeVariableReference() && !other.isTypeVariableReference()) {
+ TypeVariable aVar = ((TypeVariableReference) this)
+ .getTypeVariable();
+ return aVar.resolve(world).canBeBoundTo(other);
+ }
+
+ if (other.isTypeVariableReference()) {
+ TypeVariableReferenceType otherType = (TypeVariableReferenceType) other;
+ if (this instanceof TypeVariableReference) {
+ return ((TypeVariableReference) this)
+ .getTypeVariable()
+ .resolve(world)
+ .canBeBoundTo(
+ otherType.getTypeVariable().getFirstBound()
+ .resolve(world));// pr171952
+ // return
+ // ((TypeVariableReference)this).getTypeVariable()==otherType
+ // .getTypeVariable();
+ } else {
+ // FIXME asc should this say canBeBoundTo??
+ return this.isAssignableFrom(otherType.getTypeVariable()
+ .getFirstBound().resolve(world));
+ }
+ }
+
+ if (allowMissing && other.isMissing()) {
+ return false;
+ }
+
+ ResolvedType[] interfaces = other.getDeclaredInterfaces();
+ for (ResolvedType intface : interfaces) {
+ boolean b;
+ if (thisRaw && intface.isParameterizedOrGenericType()) {
+ b = this.isAssignableFrom(intface.getRawType(), allowMissing);
+ } else {
+ b = this.isAssignableFrom(intface, allowMissing);
+ }
+ if (b) {
+ return true;
+ }
+ }
+ ResolvedType superclass = other.getSuperclass();
+ if (superclass != null) {
+ boolean b;
+ if (thisRaw && superclass.isParameterizedOrGenericType()) {
+ b = this.isAssignableFrom(superclass.getRawType(), allowMissing);
+ } else {
+ b = this.isAssignableFrom(superclass, allowMissing);
+ }
+ if (b) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public ISourceContext getSourceContext() {
+ return getDelegate().getSourceContext();
+ }
+
+ @Override
+ public ISourceLocation getSourceLocation() {
+ ISourceContext isc = getDelegate().getSourceContext();
+ return isc.makeSourceLocation(new Position(startPos, endPos));
+ }
+
+ @Override
+ public boolean isExposedToWeaver() {
+ return (getDelegate() == null) || delegate.isExposedToWeaver();
+ }
+
+ @Override
+ public WeaverStateInfo getWeaverState() {
+ return getDelegate().getWeaverState();
+ }
+
+ @Override
+ public ResolvedMember[] getDeclaredFields() {
+ if (parameterizedFields != null) {
+ return parameterizedFields;
+ }
+ if (isParameterizedType() || isRawType()) {
+ ResolvedMember[] delegateFields = getDelegate().getDeclaredFields();
+ parameterizedFields = new ResolvedMember[delegateFields.length];
+ for (int i = 0; i < delegateFields.length; i++) {
+ parameterizedFields[i] = delegateFields[i].parameterizedWith(
+ getTypesForMemberParameterization(), this,
+ isParameterizedType());
+ }
+ return parameterizedFields;
+ } else {
+ return getDelegate().getDeclaredFields();
+ }
+ }
+
+ /**
+ * Find out from the generic signature the true signature of any interfaces
+ * I implement. If I am parameterized, these may then need to be
+ * parameterized before returning.
+ */
+ @Override
+ public ResolvedType[] getDeclaredInterfaces() {
+ ResolvedType[] interfaces = parameterizedInterfaces.get();
+ if (interfaces != null) {
+ return interfaces;
+ }
+ ResolvedType[] delegateInterfaces = getDelegate()
+ .getDeclaredInterfaces();
+ if (isRawType()) {
+ if (newInterfaces != null) {// debug 375777
+ throw new IllegalStateException(
+ "The raw type should never be accumulating new interfaces, they should be on the generic type. Type is "
+ + this.getName());
+ }
+ ResolvedType[] newInterfacesFromGenericType = genericType.newInterfaces;
+ if (newInterfacesFromGenericType != null) {
+ ResolvedType[] extraInterfaces = new ResolvedType[delegateInterfaces.length
+ + newInterfacesFromGenericType.length];
+ System.arraycopy(delegateInterfaces, 0, extraInterfaces, 0,
+ delegateInterfaces.length);
+ System.arraycopy(newInterfacesFromGenericType, 0,
+ extraInterfaces, delegateInterfaces.length,
+ newInterfacesFromGenericType.length);
+ delegateInterfaces = extraInterfaces;
+ }
+ } else if (newInterfaces != null) {
+ // OPTIMIZE does this part of the method trigger often?
+ ResolvedType[] extraInterfaces = new ResolvedType[delegateInterfaces.length
+ + newInterfaces.length];
+ System.arraycopy(delegateInterfaces, 0, extraInterfaces, 0,
+ delegateInterfaces.length);
+ System.arraycopy(newInterfaces, 0, extraInterfaces,
+ delegateInterfaces.length, newInterfaces.length);
+
+ delegateInterfaces = extraInterfaces;
+ }
+ if (isParameterizedType()) {
+ // UnresolvedType[] paramTypes =
+ // getTypesForMemberParameterization();
+ interfaces = new ResolvedType[delegateInterfaces.length];
+ for (int i = 0; i < delegateInterfaces.length; i++) {
+ // We may have to sub/super set the set of parametertypes if the
+ // implemented interface
+ // needs more or less than this type does. (pr124803/pr125080)
+
+ if (delegateInterfaces[i].isParameterizedType()) {
+ interfaces[i] = delegateInterfaces[i].parameterize(
+ getMemberParameterizationMap()).resolve(world);
+ } else {
+ interfaces[i] = delegateInterfaces[i];
+ }
+ }
+ parameterizedInterfaces = new WeakReference<ResolvedType[]>(
+ interfaces);
+ return interfaces;
+ } else if (isRawType()) {
+ UnresolvedType[] paramTypes = getTypesForMemberParameterization();
+ interfaces = new ResolvedType[delegateInterfaces.length];
+ for (int i = 0, max = interfaces.length; i < max; i++) {
+ interfaces[i] = delegateInterfaces[i];
+ if (interfaces[i].isGenericType()) {
+ // a generic supertype of a raw type is replaced by its raw
+ // equivalent
+ interfaces[i] = interfaces[i].getRawType().resolve(
+ getWorld());
+ } else if (interfaces[i].isParameterizedType()) {
+ // a parameterized supertype collapses any type vars to
+ // their upper bounds
+ UnresolvedType[] toUseForParameterization = determineThoseTypesToUse(
+ interfaces[i], paramTypes);
+ interfaces[i] = interfaces[i]
+ .parameterizedWith(toUseForParameterization);
+ }
+ }
+ parameterizedInterfaces = new WeakReference<ResolvedType[]>(
+ interfaces);
+ return interfaces;
+ }
+ if (getDelegate().isCacheable()) {
+ parameterizedInterfaces = new WeakReference<ResolvedType[]>(
+ delegateInterfaces);
+ }
+ return delegateInterfaces;
+ }
+
+ /**
+ * It is possible this type has multiple type variables but the interface we
+ * are about to parameterize only uses a subset - this method determines the
+ * subset to use by looking at the type variable names used. For example:
+ * <code>
+ * class Foo<T extends String,E extends Number> implements SuperInterface<T> {}
+ * </code> where <code>
+ * interface SuperInterface<Z> {}
+ * </code> In that example, a use of the 'Foo' raw type should know that it
+ * implements the SuperInterface<String>.
+ */
+ private UnresolvedType[] determineThoseTypesToUse(
+ ResolvedType parameterizedInterface, UnresolvedType[] paramTypes) {
+ // What are the type parameters for the supertype?
+ UnresolvedType[] tParms = parameterizedInterface.getTypeParameters();
+ UnresolvedType[] retVal = new UnresolvedType[tParms.length];
+
+ // Go through the supertypes type parameters, if any of them is a type
+ // variable, use the
+ // real type variable on the declaring type.
+
+ // it is possibly overkill to look up the type variable - ideally the
+ // entry in the type parameter list for the
+ // interface should be the a ref to the type variable in the current
+ // type ... but I'm not 100% confident right now.
+ for (int i = 0; i < tParms.length; i++) {
+ UnresolvedType tParm = tParms[i];
+ if (tParm.isTypeVariableReference()) {
+ TypeVariableReference tvrt = (TypeVariableReference) tParm;
+ TypeVariable tv = tvrt.getTypeVariable();
+ int rank = getRank(tv.getName());
+ // -1 probably means it is a reference to a type variable on the
+ // outer generic type (see pr129566)
+ if (rank != -1) {
+ retVal[i] = paramTypes[rank];
+ } else {
+ retVal[i] = tParms[i];
+ }
+ } else {
+ retVal[i] = tParms[i];
+ }
+
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns the position within the set of type variables for this type for
+ * the specified type variable name. Returns -1 if there is no type variable
+ * with the specified name.
+ */
+ private int getRank(String tvname) {
+ TypeVariable[] thisTypesTVars = getGenericType().getTypeVariables();
+ for (int i = 0; i < thisTypesTVars.length; i++) {
+ TypeVariable tv = thisTypesTVars[i];
+ if (tv.getName().equals(tvname)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public ResolvedMember[] getDeclaredMethods() {
+ if (parameterizedMethods != null) {
+ return parameterizedMethods;
+ }
+ if (isParameterizedType() || isRawType()) {
+ ResolvedMember[] delegateMethods = getDelegate()
+ .getDeclaredMethods();
+ UnresolvedType[] parameters = getTypesForMemberParameterization();
+ parameterizedMethods = new ResolvedMember[delegateMethods.length];
+ for (int i = 0; i < delegateMethods.length; i++) {
+ parameterizedMethods[i] = delegateMethods[i].parameterizedWith(
+ parameters, this, isParameterizedType());
+ }
+ return parameterizedMethods;
+ } else {
+ return getDelegate().getDeclaredMethods();
+ }
+ }
+
+ @Override
+ public ResolvedMember[] getDeclaredPointcuts() {
+ if (parameterizedPointcuts != null) {
+ return parameterizedPointcuts;
+ }
+ if (isParameterizedType()) {
+ ResolvedMember[] delegatePointcuts = getDelegate()
+ .getDeclaredPointcuts();
+ parameterizedPointcuts = new ResolvedMember[delegatePointcuts.length];
+ for (int i = 0; i < delegatePointcuts.length; i++) {
+ parameterizedPointcuts[i] = delegatePointcuts[i]
+ .parameterizedWith(getTypesForMemberParameterization(),
+ this, isParameterizedType());
+ }
+ return parameterizedPointcuts;
+ } else {
+ return getDelegate().getDeclaredPointcuts();
+ }
+ }
+
+ private UnresolvedType[] getTypesForMemberParameterization() {
+ UnresolvedType[] parameters = null;
+ if (isParameterizedType()) {
+ parameters = getTypeParameters();
+ } else if (isRawType()) {
+ // raw type, use upper bounds of type variables on generic type
+ TypeVariable[] tvs = getGenericType().getTypeVariables();
+ parameters = new UnresolvedType[tvs.length];
+ for (int i = 0; i < tvs.length; i++) {
+ parameters[i] = tvs[i].getFirstBound();
+ }
+ }
+ return parameters;
+ }
+
+ @Override
+ public TypeVariable[] getTypeVariables() {
+ if (typeVariables == null) {
+ typeVariables = getDelegate().getTypeVariables();
+ for (int i = 0; i < this.typeVariables.length; i++) {
+ typeVariables[i].resolve(world);
+ }
+ }
+ return typeVariables;
+ }
+
+ @Override
+ public PerClause getPerClause() {
+ PerClause pclause = getDelegate().getPerClause();
+ if (pclause != null && isParameterizedType()) { // could cache the
+ // result here...
+ Map<String, UnresolvedType> parameterizationMap = getAjMemberParameterizationMap();
+ pclause = (PerClause) pclause.parameterizeWith(parameterizationMap,
+ world);
+ }
+ return pclause;
+ }
+
+ @Override
+ public Collection<Declare> getDeclares() {
+ if (parameterizedDeclares != null) {
+ return parameterizedDeclares;
+ }
+ Collection<Declare> declares = null;
+ if (ajMembersNeedParameterization()) {
+ Collection<Declare> genericDeclares = getDelegate().getDeclares();
+ parameterizedDeclares = new ArrayList<Declare>();
+ Map<String, UnresolvedType> parameterizationMap = getAjMemberParameterizationMap();
+ for (Declare declareStatement : genericDeclares) {
+ parameterizedDeclares.add(declareStatement.parameterizeWith(
+ parameterizationMap, world));
+ }
+ declares = parameterizedDeclares;
+ } else {
+ declares = getDelegate().getDeclares();
+ }
+ for (Declare d : declares) {
+ d.setDeclaringType(this);
+ }
+ return declares;
+ }
+
+ @Override
+ public Collection<ConcreteTypeMunger> getTypeMungers() {
+ return getDelegate().getTypeMungers();
+ }
+
+ @Override
+ public Collection<ResolvedMember> getPrivilegedAccesses() {
+ return getDelegate().getPrivilegedAccesses();
+ }
+
+ @Override
+ public int getModifiers() {
+ return getDelegate().getModifiers();
+ }
+
+ WeakReference<ResolvedType> superclassReference = new WeakReference<ResolvedType>(
+ null);
+
+ @Override
+ public ResolvedType getSuperclass() {
+ ResolvedType ret = null;// superclassReference.get();
+ // if (ret != null) {
+ // return ret;
+ // }
+ if (newSuperclass != null) {
+ if (this.isParameterizedType()
+ && newSuperclass.isParameterizedType()) {
+ return newSuperclass.parameterize(
+ getMemberParameterizationMap()).resolve(getWorld());
+ }
+ if (getDelegate().isCacheable()) {
+ superclassReference = new WeakReference<ResolvedType>(ret);
+ }
+ return newSuperclass;
+ }
+ try {
+ world.setTypeVariableLookupScope(this);
+ ret = getDelegate().getSuperclass();
+ } finally {
+ world.setTypeVariableLookupScope(null);
+ }
+ if (this.isParameterizedType() && ret.isParameterizedType()) {
+ ret = ret.parameterize(getMemberParameterizationMap()).resolve(
+ getWorld());
+ }
+ if (getDelegate().isCacheable()) {
+ superclassReference = new WeakReference<ResolvedType>(ret);
+ }
+ return ret;
+ }
+
+ public ReferenceTypeDelegate getDelegate() {
+ return delegate;
+ }
+
+ public void setDelegate(ReferenceTypeDelegate delegate) {
+ // Don't copy from BcelObjectType to EclipseSourceType - the context may
+ // be tidied (result null'd) after previous weaving
+ if (this.delegate != null
+ && this.delegate.copySourceContext()
+ && this.delegate.getSourceContext() != SourceContextImpl.UNKNOWN_SOURCE_CONTEXT) {
+ ((AbstractReferenceTypeDelegate) delegate)
+ .setSourceContext(this.delegate.getSourceContext());
+ }
+ this.delegate = delegate;
+ synchronized (derivativeTypes) {
+ List<WeakReference<ReferenceType>> forRemoval = new ArrayList<WeakReference<ReferenceType>>();
+ for (WeakReference<ReferenceType> derivativeRef : derivativeTypes) {
+ ReferenceType derivative = derivativeRef.get();
+ if (derivative != null) {
+ derivative.setDelegate(delegate);
+ } else {
+ forRemoval.add(derivativeRef);
+ }
+ }
+ derivativeTypes.removeAll(forRemoval);
+ }
+
+ // If we are raw, we have a generic type - we should ensure it uses the
+ // same delegate
+ if (isRawType() && getGenericType() != null) {
+ ReferenceType genType = (ReferenceType) getGenericType();
+ if (genType.getDelegate() != delegate) { // avoids circular updates
+ genType.setDelegate(delegate);
+ }
+ }
+ clearParameterizationCaches();
+ ensureConsistent();
+ }
+
+ private void clearParameterizationCaches() {
+ parameterizedFields = null;
+ parameterizedInterfaces.clear();
+ parameterizedMethods = null;
+ parameterizedPointcuts = null;
+ superclassReference = new WeakReference<ResolvedType>(null);
+ }
+
+ public int getEndPos() {
+ return endPos;
+ }
+
+ public int getStartPos() {
+ return startPos;
+ }
+
+ public void setEndPos(int endPos) {
+ this.endPos = endPos;
+ }
+
+ public void setStartPos(int startPos) {
+ this.startPos = startPos;
+ }
+
+ @Override
+ public boolean doesNotExposeShadowMungers() {
+ return getDelegate().doesNotExposeShadowMungers();
+ }
+
+ public String getDeclaredGenericSignature() {
+ return getDelegate().getDeclaredGenericSignature();
+ }
+
+ public void setGenericType(ReferenceType rt) {
+ genericType = rt;
+ // Should we 'promote' this reference type from simple to raw?
+ // makes sense if someone is specifying that it has a generic form
+ if (typeKind == TypeKind.SIMPLE) {
+ typeKind = TypeKind.RAW;
+ signatureErasure = signature;
+ if (newInterfaces != null) { // debug 375777
+ throw new IllegalStateException(
+ "Simple type promoted to raw, but simple type had new interfaces/superclass. Type is "
+ + this.getName());
+ }
+ }
+ if (typeKind == TypeKind.RAW) {
+ genericType.addDependentType(this);
+ }
+ if (isRawType()) {
+ genericType.rawType = this;
+ }
+ if (this.isRawType() && rt.isRawType()) {
+ new RuntimeException(
+ "PR341926 diagnostics: Incorrect setup for a generic type, raw type should not point to raw: "
+ + this.getName()).printStackTrace();
+ }
+ }
+
+ public void demoteToSimpleType() {
+ genericType = null;
+ typeKind = TypeKind.SIMPLE;
+ signatureErasure = null;
+ }
+
+ @Override
+ public ReferenceType getGenericType() {
+ if (isGenericType()) {
+ return this;
+ }
+ return genericType;
+ }
+
+ /**
+ * a parameterized signature starts with a "P" in place of the "L", see the
+ * comment on signatures in UnresolvedType.
+ *
+ * @param aGenericType
+ * @param someParameters
+ * @return
+ */
+ private static String makeParameterizedSignature(ResolvedType aGenericType,
+ ResolvedType[] someParameters) {
+ String rawSignature = aGenericType.getErasureSignature();
+ StringBuffer ret = new StringBuffer();
+ ret.append(PARAMETERIZED_TYPE_IDENTIFIER);
+ ret.append(rawSignature.substring(1, rawSignature.length() - 1));
+ ret.append("<");
+ for (int i = 0; i < someParameters.length; i++) {
+ ret.append(someParameters[i].getSignature());
+ }
+ ret.append(">;");
+ return ret.toString();
+ }
+
+ private static String makeDeclaredSignature(ResolvedType aGenericType,
+ UnresolvedType[] someParameters) {
+ StringBuffer ret = new StringBuffer();
+ String rawSig = aGenericType.getErasureSignature();
+ ret.append(rawSig.substring(0, rawSig.length() - 1));
+ ret.append("<");
+ for (int i = 0; i < someParameters.length; i++) {
+ if (someParameters[i] instanceof ReferenceType) {
+ ret.append(((ReferenceType) someParameters[i])
+ .getSignatureForAttribute());
+ } else if (someParameters[i] instanceof Primitive) {
+ ret.append(((Primitive) someParameters[i])
+ .getSignatureForAttribute());
+ } else {
+ throw new IllegalStateException(
+ "DebugFor325731: expected a ReferenceType or Primitive but was "
+ + someParameters[i] + " of type "
+ + someParameters[i].getClass().getName());
+ }
+ }
+ ret.append(">;");
+ return ret.toString();
+ }
+
+ @Override
+ public void ensureConsistent() {
+ annotations = null;
+ annotationTypes = null;
+ newSuperclass = null;
+ bits = 0; // clears the hierarchy complete tag (amongst other things)
+ newInterfaces = null;
+ typeVariables = null;
+ parameterizedInterfaces.clear();
+ superclassReference = new WeakReference<ResolvedType>(null);
+ if (getDelegate() != null) {
+ delegate.ensureConsistent();
+ }
+ if (isParameterizedOrRawType()) {
+ ReferenceType genericType = getGenericType();
+ if (genericType != null) {
+ genericType.ensureConsistent();
+ }
+ }
+ }
+
+ @Override
+ public void addParent(ResolvedType newParent) {
+ if (this.isRawType()) {
+ throw new IllegalStateException(
+ "The raw type should never be accumulating new interfaces, they should be on the generic type. Type is "
+ + this.getName());
+ }
+ if (newParent.isClass()) {
+ newSuperclass = newParent;
+ superclassReference = new WeakReference<ResolvedType>(null);
+ } else {
+ if (newInterfaces == null) {
+ newInterfaces = new ResolvedType[1];
+ newInterfaces[0] = newParent;
+ } else {
+ ResolvedType[] existing = getDelegate().getDeclaredInterfaces();
+ if (existing != null) {
+ for (int i = 0; i < existing.length; i++) {
+ if (existing[i].equals(newParent)) {
+ return; // already has this interface
+ }
+ }
+ }
+ ResolvedType[] newNewInterfaces = new ResolvedType[newInterfaces.length + 1];
+ System.arraycopy(newInterfaces, 0, newNewInterfaces, 1,
+ newInterfaces.length);
+ newNewInterfaces[0] = newParent;
+ newInterfaces = newNewInterfaces;
+ }
+ if (this.isGenericType()) {
+ synchronized (derivativeTypes) {
+ for (WeakReference<ReferenceType> derivativeTypeRef : derivativeTypes) {
+ ReferenceType derivativeType = derivativeTypeRef.get();
+ if (derivativeType != null) {
+ derivativeType.parameterizedInterfaces.clear();
+ }
+ }
+ }
+ }
+ parameterizedInterfaces.clear();
+ }
+ }
+
+ private boolean equal(UnresolvedType[] typeParameters,
+ ResolvedType[] resolvedParameters) {
+ if (typeParameters.length != resolvedParameters.length) {
+ return false;
+ }
+ int len = typeParameters.length;
+ for (int p = 0; p < len; p++) {
+ if (!typeParameters[p].equals(resolvedParameters[p])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Look for a derivative type with the specified type parameters. This can
+ * avoid creating an unnecessary new (duplicate) with the same information
+ * in it. This method also cleans up any reference entries that have been
+ * null'd by a GC.
+ *
+ * @param typeParameters
+ * the type parameters to use when searching for the derivative
+ * type.
+ * @return an existing derivative type or null if there isn't one
+ */
+ public ReferenceType findDerivativeType(ResolvedType[] typeParameters) {
+ synchronized (derivativeTypes) {
+ List<WeakReference<ReferenceType>> forRemoval = new ArrayList<WeakReference<ReferenceType>>();
+ for (WeakReference<ReferenceType> derivativeTypeRef : derivativeTypes) {
+ ReferenceType derivativeType = derivativeTypeRef.get();
+ if (derivativeType == null) {
+ forRemoval.add(derivativeTypeRef);
+ } else {
+ if (derivativeType.isRawType()) {
+ continue;
+ }
+ if (equal(derivativeType.typeParameters, typeParameters)) {
+ return derivativeType; // this escape route wont remove
+ // the empty refs
+ }
+ }
+ }
+ derivativeTypes.removeAll(forRemoval);
+ }
+ return null;
+ }
+
+ public boolean hasNewInterfaces() {
+ return newInterfaces != null;
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceTypeDelegate.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceTypeDelegate.java
new file mode 100644
index 000000000..e07c032e6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ReferenceTypeDelegate.java
@@ -0,0 +1,148 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Andy Clement - June 2005 - separated out from ResolvedType
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Collection;
+
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.PerClause;
+
+/**
+ * Abstraction over a type - a reference type is Object or a descendant of Object, other types (int/etc) are considered primitive
+ * types. Abstract implementation provided by AbstractReferenceTypeDelegate.
+ */
+
+public interface ReferenceTypeDelegate {
+
+ public boolean isAspect();
+
+ /**
+ * @return true if the type is an annotation style aspect (a type marked @Aspect)
+ */
+ public boolean isAnnotationStyleAspect();
+
+ public boolean isInterface();
+
+ public boolean isEnum();
+
+ public boolean isAnnotation();
+
+ public String getRetentionPolicy();
+
+ /**
+ * @return true if this annotation type can be on a regular type (ie. it doesn't specify anything or it specifies TYPE)
+ */
+ public boolean canAnnotationTargetType();
+
+ /**
+ * @return all the possible targets that this annotation can be placed upon
+ */
+ public AnnotationTargetKind[] getAnnotationTargetKinds();
+
+ /**
+ * @return true if this annotation type has a retention policy of RUNTIME
+ */
+ public boolean isAnnotationWithRuntimeRetention();
+
+ public boolean isClass();
+
+ public boolean isGeneric();
+
+ public boolean isAnonymous();
+
+ /**
+ * @return true if this class is nested (this includes: member classes, local classes, anonymous classes)
+ */
+ public boolean isNested();
+
+ public boolean hasAnnotation(UnresolvedType ofType);
+
+ public AnnotationAJ[] getAnnotations();
+
+ public ResolvedType[] getAnnotationTypes();
+
+ public ResolvedMember[] getDeclaredFields();
+
+ public ResolvedType[] getDeclaredInterfaces();
+
+ public ResolvedMember[] getDeclaredMethods();
+
+ public ResolvedMember[] getDeclaredPointcuts();
+
+ public TypeVariable[] getTypeVariables();
+
+ public int getModifiers();
+
+ // aspect declaration related members
+ /**
+ * @return for an aspect declaration, return the
+ */
+ public PerClause getPerClause();
+
+ public Collection<Declare> getDeclares();
+
+ public Collection<ConcreteTypeMunger> getTypeMungers();
+
+ public Collection<ResolvedMember> getPrivilegedAccesses();
+
+ // end of aspect declaration related members
+
+ public ResolvedType getSuperclass();
+
+ public WeaverStateInfo getWeaverState();
+
+ public ReferenceType getResolvedTypeX();
+
+ // needs renaming isWeavable or removing from here
+ public boolean isExposedToWeaver();
+
+ public boolean doesNotExposeShadowMungers();
+
+ public ISourceContext getSourceContext();
+
+ public String getSourcefilename();
+
+ public String getDeclaredGenericSignature();
+
+ public ResolvedType getOuterClass();
+
+ public boolean copySourceContext();
+
+ /**
+ * TODO Caching of methods besides getDeclaredInterfaces() may also be dependent on this flag - which?
+ *
+ * @return true if something the result of getDeclaredInterfaces() can be cached by the caller
+ */
+ public boolean isCacheable();
+
+ /**
+ * If known, return the compiler/weaver version used to build this delegate. Default is the most recent level as specified in
+ * {@link WeaverVersionInfo}.
+ *
+ * @return the major version
+ */
+ public int getCompilerVersion();
+
+ /**
+ * Implementations need to clear state
+ */
+ public void ensureConsistent();
+
+ public boolean isWeavable();
+
+ public boolean hasBeenWoven();
+
+ public boolean hasAnnotations();
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvableTypeList.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvableTypeList.java
new file mode 100644
index 000000000..34e17b44a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvableTypeList.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2009 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Carries an array of unresolved types - will resolve them on demand. Can be used where currently the entire array gets resolved
+ * and a ResolvedType array is passed on. Depending on the situation there may not be a need to resolve all the entries so this can
+ * perform better. Note: the array elements are resolved in place, so the caller should not be surprised if elements and resolved
+ * after the type list has been used.
+ *
+ * @author Andy Clement
+ */
+public class ResolvableTypeList {
+
+ public int length;
+ private World world;
+ private UnresolvedType[] types;
+
+ public ResolvableTypeList(World world, UnresolvedType[] unresolvedTypes) {
+ length = unresolvedTypes.length;
+ types = unresolvedTypes;
+ this.world = world;
+ }
+
+ public ResolvedType getResolved(int nameIndex) {
+ UnresolvedType ut = types[nameIndex];
+ if (!(ut instanceof ResolvedType)) {
+ types[nameIndex] = world.resolve(ut);
+ return (ResolvedType) types[nameIndex];
+ } else {
+ return (ResolvedType) ut;
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMember.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMember.java
new file mode 100644
index 000000000..0b5def29a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMember.java
@@ -0,0 +1,158 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 2005 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * AMC extracted as interface
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+
+public interface ResolvedMember extends Member, AnnotatedElement, TypeVariableDeclaringElement {
+
+ public static final ResolvedMember[] NONE = new ResolvedMember[0];
+
+ public int getModifiers(World world);
+
+ public int getModifiers();
+
+ public UnresolvedType[] getExceptions(World world);
+
+ public UnresolvedType[] getExceptions();
+
+ public ShadowMunger getAssociatedShadowMunger();
+
+ public boolean isAjSynthetic();
+
+ public boolean isCompatibleWith(Member am);
+
+ public boolean hasAnnotation(UnresolvedType ofType);
+
+ public AnnotationAJ[] getAnnotations();
+
+ public ResolvedType[] getAnnotationTypes();
+
+ public void setAnnotationTypes(ResolvedType[] annotationtypes);
+
+ public void addAnnotation(AnnotationAJ annotation);
+
+ public boolean isBridgeMethod();
+
+ public boolean isVarargsMethod();
+
+ public boolean isSynthetic();
+
+ public void write(CompressingDataOutputStream s) throws IOException;
+
+ public ISourceContext getSourceContext(World world);
+
+ public String[] getParameterNames();
+
+ public void setParameterNames(String[] names);
+
+ public AnnotationAJ[][] getParameterAnnotations();
+
+ public ResolvedType[][] getParameterAnnotationTypes();
+
+ public String getAnnotationDefaultValue();
+
+ public String getParameterSignatureErased();
+
+ public String getSignatureErased();
+
+ public String[] getParameterNames(World world);
+
+ public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature();
+
+ public ISourceLocation getSourceLocation();
+
+ public int getStart();
+
+ public int getEnd();
+
+ public ISourceContext getSourceContext();
+
+ public void setPosition(int sourceStart, int sourceEnd);
+
+ public void setSourceContext(ISourceContext sourceContext);
+
+ public boolean isAbstract();
+
+ public boolean isPublic();
+
+ public boolean isDefault();
+
+ public boolean isVisible(ResolvedType fromType);
+
+ public void setCheckedExceptions(UnresolvedType[] checkedExceptions);
+
+ public void setAnnotatedElsewhere(boolean b);
+
+ public boolean isAnnotatedElsewhere();
+
+ // like toString but include generic signature info
+ public String toGenericString();
+
+ public String toDebugString();
+
+ public boolean hasBackingGenericMember();
+
+ public ResolvedMember getBackingGenericMember();
+
+ /**
+ * Get the UnresolvedType for the return type, taking generic signature into account
+ */
+ public UnresolvedType getGenericReturnType();
+
+ /**
+ * Get the TypeXs of the parameter types, taking generic signature into account
+ */
+ public UnresolvedType[] getGenericParameterTypes();
+
+ public boolean equalsApartFromDeclaringType(Object other);
+
+ // return a resolved member in which all type variables in the signature of
+ // this member have been replaced with the given bindings. the isParameterized flag tells us whether we are creating a raw type
+ // version or not
+ // if isParameterized List<T> will turn into List<String> (for example),
+ // but if !isParameterized List<T> will turn into List.
+ public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
+ boolean isParameterized);
+
+ // this variant allows for aliases for type variables (i.e. allowing them to
+ // have another name)
+ // this is used for processing ITDs that share type variables with their
+ // target generic type
+ public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
+ boolean isParameterized, List<String> aliases);
+
+ public void setTypeVariables(TypeVariable[] types);
+
+ public TypeVariable[] getTypeVariables();
+
+ /**
+ * Returns true if this member matches the other. The matching takes into account name and parameter types only. When comparing
+ * parameter types, we allow any type variable to match any other type variable regardless of bounds.
+ */
+ public boolean matches(ResolvedMember aCandidateMatch, boolean ignoreGenerics);
+
+ public void evictWeavingState();
+
+ public ResolvedMember parameterizedWith(Map<String, UnresolvedType> m, World w);
+
+ public boolean isDefaultConstructor();
+
+ public void setAnnotations(AnnotationAJ[] annotations);
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMemberImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMemberImpl.java
new file mode 100644
index 000000000..cfd0508c4
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedMemberImpl.java
@@ -0,0 +1,1266 @@
+/* *******************************************************************
+ * Copyright (c) 2002-2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.ISourceLocation;
+
+/**
+ * Represent a resolved member. Components of it are expected to exist. This member will correspond to a real member *unless* it is
+ * being used to represent the effect of an ITD.
+ *
+ * @author PARC
+ * @author Andy Clement
+ */
+public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, ResolvedMember {
+
+ private String[] parameterNames = null;
+ private boolean isResolved = false;
+ protected UnresolvedType[] checkedExceptions = UnresolvedType.NONE;
+
+ /**
+ * if this member is a parameterized version of a member in a generic type, then this field holds a reference to the member we
+ * parameterize.
+ */
+ protected ResolvedMember backingGenericMember = null;
+
+ protected AnnotationAJ[] annotations = null;
+ protected ResolvedType[] annotationTypes = null;
+ protected AnnotationAJ[][] parameterAnnotations = null;
+ protected ResolvedType[][] parameterAnnotationTypes = null;
+
+ // Some members are 'created' to represent other things (for example ITDs).
+ // These members have their annotations stored elsewhere, and this flag indicates
+ // that is the case. It is up to the caller to work out where that is!
+ // Once determined the caller may choose to stash the annotations in this
+ // member...
+ private boolean isAnnotatedElsewhere = false;
+ private boolean isAjSynthetic = false;
+
+ // generic methods have type variables
+ protected TypeVariable[] typeVariables;
+
+ // these three fields hold the source location of this member
+ protected int start, end;
+ protected ISourceContext sourceContext = null;
+
+ // XXX deprecate this in favor of the constructor below
+ public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
+ UnresolvedType[] parameterTypes) {
+ super(kind, declaringType, modifiers, returnType, name, parameterTypes);
+ }
+
+ public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
+ UnresolvedType[] parameterTypes, UnresolvedType[] checkedExceptions) {
+ super(kind, declaringType, modifiers, returnType, name, parameterTypes);
+ this.checkedExceptions = checkedExceptions;
+ }
+
+ public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
+ UnresolvedType[] parameterTypes, UnresolvedType[] checkedExceptions, ResolvedMember backingGenericMember) {
+ this(kind, declaringType, modifiers, returnType, name, parameterTypes, checkedExceptions);
+ this.backingGenericMember = backingGenericMember;
+ this.isAjSynthetic = backingGenericMember.isAjSynthetic();
+ }
+
+ public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name, String signature) {
+ super(kind, declaringType, modifiers, name, signature);
+ }
+
+ /**
+ * Compute the full set of signatures for a member. This walks up the hierarchy giving the ResolvedMember in each defining type
+ * in the hierarchy. A shadowMember can be created with a target type (declaring type) that does not actually define the member.
+ * This is ok as long as the member is inherited in the declaring type. Each declaring type in the line to the actual declaring
+ * type is added as an additional signature. For example:
+ *
+ * class A { void foo(); } class B extends A {}
+ *
+ * shadowMember : void B.foo()
+ *
+ * gives { void B.foo(), void A.foo() }
+ *
+ * @param joinPointSignature
+ * @param inAWorld
+ */
+ public static JoinPointSignature[] getJoinPointSignatures(Member joinPointSignature, World inAWorld) {
+
+ // Walk up hierarchy creating one member for each type up to and
+ // including the
+ // first defining type
+ ResolvedType originalDeclaringType = joinPointSignature.getDeclaringType().resolve(inAWorld);
+ ResolvedMemberImpl firstDefiningMember = (ResolvedMemberImpl) joinPointSignature.resolve(inAWorld);
+ if (firstDefiningMember == null) {
+ return JoinPointSignature.EMPTY_ARRAY;
+ }
+ // declaringType can be unresolved if we matched a synthetic member
+ // generated by Aj...
+ // should be fixed elsewhere but add this resolve call on the end for
+ // now so that we can
+ // focus on one problem at a time...
+ ResolvedType firstDefiningType = firstDefiningMember.getDeclaringType().resolve(inAWorld);
+ if (firstDefiningType != originalDeclaringType) {
+ if (joinPointSignature.getKind() == Member.CONSTRUCTOR) {
+ return JoinPointSignature.EMPTY_ARRAY;
+ }
+ // else if (shadowMember.isStatic()) {
+ // return new ResolvedMember[] {firstDefiningMember};
+ // }
+ }
+
+ List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
+ accumulateTypesInBetween(originalDeclaringType, firstDefiningType, declaringTypes);
+ Set<ResolvedMember> memberSignatures = new HashSet<ResolvedMember>();
+ for (ResolvedType declaringType : declaringTypes) {
+ memberSignatures.add(new JoinPointSignature(firstDefiningMember, declaringType));
+ }
+
+ if (shouldWalkUpHierarchyFor(firstDefiningMember)) {
+ // now walk up the hierarchy from the firstDefiningMember and
+ // include the signature for
+ // every type between the firstDefiningMember and the root defining
+ // member.
+ Iterator<ResolvedType> superTypeIterator = firstDefiningType.getDirectSupertypes();
+ List<ResolvedType> typesAlreadyVisited = new ArrayList<ResolvedType>();
+ accumulateMembersMatching(firstDefiningMember, superTypeIterator, typesAlreadyVisited, memberSignatures, false);
+ }
+
+ JoinPointSignature[] ret = new JoinPointSignature[memberSignatures.size()];
+ memberSignatures.toArray(ret);
+ return ret;
+ }
+
+ private static boolean shouldWalkUpHierarchyFor(Member aMember) {
+ if (aMember.getKind() == Member.CONSTRUCTOR) {
+ return false;
+ }
+ if (aMember.getKind() == Member.FIELD) {
+ return false;
+ }
+ if (Modifier.isStatic(aMember.getModifiers())) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Build a list containing every type between subtype and supertype, inclusively.
+ */
+ private static void accumulateTypesInBetween(ResolvedType subType, ResolvedType superType, List<ResolvedType> types) {
+ types.add(subType);
+ if (subType == superType) {
+ return;
+ } else {
+ for (Iterator<ResolvedType> iter = subType.getDirectSupertypes(); iter.hasNext();) {
+ ResolvedType parent = iter.next();
+ if (superType.isAssignableFrom(parent)) {
+ accumulateTypesInBetween(parent, superType, types);
+ }
+ }
+ }
+ }
+
+ /**
+ * We have a resolved member, possibly with type parameter references as parameters or return type. We need to find all its
+ * ancestor members. When doing this, a type parameter matches regardless of bounds (bounds can be narrowed down the hierarchy).
+ */
+ private static void accumulateMembersMatching(ResolvedMemberImpl memberToMatch, Iterator<ResolvedType> typesToLookIn,
+ List<ResolvedType> typesAlreadyVisited, Set<ResolvedMember> foundMembers, boolean ignoreGenerics) {
+ while (typesToLookIn.hasNext()) {
+ ResolvedType toLookIn = typesToLookIn.next();
+ if (!typesAlreadyVisited.contains(toLookIn)) {
+ typesAlreadyVisited.add(toLookIn);
+ ResolvedMemberImpl foundMember = (ResolvedMemberImpl) toLookIn.lookupResolvedMember(memberToMatch, true,
+ ignoreGenerics);
+ if (foundMember != null && isVisibleTo(memberToMatch, foundMember)) {
+ List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
+ // declaring type can be unresolved if the member can from
+ // an ITD...
+ ResolvedType resolvedDeclaringType = foundMember.getDeclaringType().resolve(toLookIn.getWorld());
+ accumulateTypesInBetween(toLookIn, resolvedDeclaringType, declaringTypes);
+ for (ResolvedType declaringType : declaringTypes) {
+ // typesAlreadyVisited.add(declaringType);
+ foundMembers.add(new JoinPointSignature(foundMember, declaringType));
+ }
+ if (!ignoreGenerics && toLookIn.isParameterizedType() && (foundMember.backingGenericMember != null)) {
+ foundMembers.add(new JoinPointSignature(foundMember.backingGenericMember, foundMember.declaringType
+ .resolve(toLookIn.getWorld())));
+ }
+ accumulateMembersMatching(foundMember, toLookIn.getDirectSupertypes(), typesAlreadyVisited, foundMembers,
+ ignoreGenerics);
+ // if this was a parameterized type, look in the generic
+ // type that backs it too
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns true if the parent member is visible to the child member In the same declaring type this is always true, otherwise if
+ * parent is private it is false.
+ *
+ * @param childMember
+ * @param parentMember
+ * @return
+ */
+ private static boolean isVisibleTo(ResolvedMember childMember, ResolvedMember parentMember) {
+ if (childMember.getDeclaringType().equals(parentMember.getDeclaringType())) {
+ return true;
+ }
+ if (Modifier.isPrivate(parentMember.getModifiers())) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ // ----
+
+ @Override
+ public final int getModifiers(World world) {
+ return modifiers;
+ }
+
+ @Override
+ public final int getModifiers() {
+ return modifiers;
+ }
+
+ // ----
+
+ @Override
+ public final UnresolvedType[] getExceptions(World world) {
+ return getExceptions();
+ }
+
+ public UnresolvedType[] getExceptions() {
+ return checkedExceptions;
+ }
+
+ public ShadowMunger getAssociatedShadowMunger() {
+ return null;
+ }
+
+ // ??? true or false?
+ public boolean isAjSynthetic() {
+ return isAjSynthetic;
+ }
+
+ protected void setAjSynthetic(boolean b) {
+ isAjSynthetic = b;
+ }
+
+ public boolean hasAnnotations() {
+ return (annotationTypes != null);
+ }
+
+ /**
+ * Check if this member has an annotation of the specified type. If the member has a backing generic member then this member
+ * represents a parameterization of a member in a generic type and the annotations available on the backing generic member
+ * should be used.
+ *
+ * @param ofType the type of the annotation being searched for
+ * @return true if the annotation is found on this member or its backing generic member
+ */
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ // The ctors don't allow annotations to be specified ... yet - but
+ // that doesn't mean it is an error to call this method.
+ // Normally the weaver will be working with subtypes of
+ // this type - BcelField/BcelMethod
+ if (backingGenericMember != null) {
+ if (annotationTypes != null) {
+ throw new BCException("Unexpectedly found a backing generic member and a local set of annotations");
+ }
+ return backingGenericMember.hasAnnotation(ofType);
+ }
+ if (annotationTypes != null) {
+ for (int i = 0, max = annotationTypes.length; i < max; i++) {
+ if (annotationTypes[i].equals(ofType)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public ResolvedType[] getAnnotationTypes() {
+ // The ctors don't allow annotations to be specified ... yet - but
+ // that doesn't mean it is an error to call this method.
+ // Normally the weaver will be working with subtypes of
+ // this type - BcelField/BcelMethod
+ if (backingGenericMember != null) {
+ if (annotationTypes != null) {
+ throw new BCException("Unexpectedly found a backing generic member and a local set of annotations");
+ }
+ return backingGenericMember.getAnnotationTypes();
+ }
+ return annotationTypes;
+ }
+
+ public String getAnnotationDefaultValue() {
+ throw new UnsupportedOperationException(
+ "You should resolve this member and call getAnnotationDefaultValue() on the result...");
+ }
+
+ @Override
+ public AnnotationAJ[] getAnnotations() {
+ if (backingGenericMember != null) {
+ return backingGenericMember.getAnnotations();
+ }
+ if (annotations!=null) {
+ return annotations;
+ }
+ return super.getAnnotations();
+ }
+
+ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
+ if (annotations!=null) {
+ // this means they have been set (we are likely a placeholder for an ITD, so a fake member)
+ for (AnnotationAJ annotation: annotations) {
+ if (annotation.getType().equals(ofType)) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+ throw new UnsupportedOperationException("You should resolve this member and call getAnnotationOfType() on the result...");
+ }
+
+ public void setAnnotations(AnnotationAJ[] annotations) {
+ this.annotations = annotations;
+ }
+
+ public void setAnnotationTypes(ResolvedType[] annotationTypes) {
+ this.annotationTypes = annotationTypes;
+ }
+
+ public ResolvedType[][] getParameterAnnotationTypes() {
+ return parameterAnnotationTypes;
+ }
+
+ public AnnotationAJ[][] getParameterAnnotations() {
+ if (backingGenericMember != null) {
+ return backingGenericMember.getParameterAnnotations();
+ }
+ throw new BCException("Cannot return parameter annotations for a " + this.getClass().getName() + " member");
+ // return super.getParameterAnnotations();
+ }
+
+ public void addAnnotation(AnnotationAJ annotation) {
+ if (annotationTypes == null) {
+ annotationTypes = new ResolvedType[1];
+ annotationTypes[0] = annotation.getType();
+ annotations = new AnnotationAJ[1];
+ annotations[0] = annotation;
+ } else {
+ int len = annotations.length;
+ AnnotationAJ[] ret = new AnnotationAJ[len + 1];
+ System.arraycopy(annotations, 0, ret, 0, len);
+ ret[len] = annotation;
+ annotations = ret;
+
+ ResolvedType[] newAnnotationTypes = new ResolvedType[len + 1];
+ System.arraycopy(annotationTypes, 0, newAnnotationTypes, 0, len);
+ newAnnotationTypes[len] = annotation.getType();
+ annotationTypes = newAnnotationTypes;
+ }
+ }
+
+ public boolean isBridgeMethod() {
+ return (modifiers & Constants.ACC_BRIDGE) != 0 && getKind().equals(METHOD);
+ }
+
+ public boolean isVarargsMethod() {
+ return (modifiers & Constants.ACC_VARARGS) != 0;
+ }
+
+ public void setVarargsMethod() {
+ modifiers = modifiers | Constants.ACC_VARARGS;
+ }
+
+ public boolean isSynthetic() {
+ // See Bcelmethod.isSynthetic() which takes account of preJava5
+ // Synthetic modifier
+ return (modifiers & 4096) != 0; // do we know better?
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ getKind().write(s);
+ s.writeBoolean(s.canCompress()); // boolean indicates if parts of this are compressed references
+
+ // write out the signature of the declaring type of this member
+ if (s.canCompress()) {
+ s.writeCompressedSignature(getDeclaringType().getSignature());
+ } else {
+ getDeclaringType().write(s);
+ }
+
+ // write out the modifiers
+ s.writeInt(modifiers);
+
+ // write out the name and the signature of this member
+ if (s.canCompress()) {
+ s.writeCompressedName(getName());
+ s.writeCompressedSignature(getSignature());
+ } else {
+ s.writeUTF(getName());
+ s.writeUTF(getSignature());
+ }
+
+ // write out the array clauses
+ UnresolvedType.writeArray(getExceptions(), s);
+
+ s.writeInt(getStart());
+ s.writeInt(getEnd());
+ s.writeBoolean(isVarargsMethod());
+
+ // Write out any type variables...
+ if (typeVariables == null) {
+ s.writeByte(0);
+ } else {
+ s.writeByte(typeVariables.length);
+ for (int i = 0; i < typeVariables.length; i++) {
+ typeVariables[i].write(s);
+ }
+ }
+ String gsig = getGenericSignature();
+
+ // change this to a byte: 255=false 0>254 means true and encodes the number of parameters
+ if (getSignature().equals(gsig)) {
+ s.writeByte(0xff);
+ } else {
+ s.writeByte(parameterTypes.length);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (s.canCompress()) {
+ s.writeCompressedSignature(parameterTypes[i].getSignature());
+ } else {
+ UnresolvedType array_element = parameterTypes[i];
+ array_element.write(s);
+ }
+ }
+ if (s.canCompress()) {
+ s.writeCompressedSignature(returnType.getSignature());
+ } else {
+ returnType.write(s);
+ }
+ }
+ }
+
+ /**
+ * Return the member generic signature that would be suitable for inclusion in a class file Signature attribute. For: <T>
+ * List<String> getThem(T t) {} we would create: <T:Ljava/lang/Object;>(TT;)Ljava/util/List<Ljava/lang/String;>;;
+ *
+ * @return the generic signature for the member that could be inserted into a class file
+ */
+ public String getSignatureForAttribute() {
+ StringBuffer sb = new StringBuffer();
+ if (typeVariables != null) {
+ sb.append("<");
+ for (int i = 0; i < typeVariables.length; i++) {
+ sb.append(typeVariables[i].getSignatureForAttribute()); // need
+ // a
+ // 'getSignatureForAttribute()'
+ }
+ sb.append(">");
+ }
+ sb.append("(");
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ResolvedType ptype = (ResolvedType) parameterTypes[i];
+ sb.append(ptype.getSignatureForAttribute());
+ }
+ sb.append(")");
+ sb.append(((ResolvedType) returnType).getSignatureForAttribute());
+ return sb.toString();
+ }
+
+ public String getGenericSignature() {
+ StringBuffer sb = new StringBuffer();
+ if (typeVariables != null) {
+ sb.append("<");
+ for (int i = 0; i < typeVariables.length; i++) {
+ sb.append(typeVariables[i].getSignature());
+ }
+ sb.append(">");
+ }
+ sb.append("(");
+ for (int i = 0; i < parameterTypes.length; i++) {
+ UnresolvedType ptype = parameterTypes[i];
+ sb.append(ptype.getSignature());
+ }
+ sb.append(")");
+ sb.append(returnType.getSignature());
+ return sb.toString();
+ }
+
+ public static void writeArray(ResolvedMember[] members, CompressingDataOutputStream s) throws IOException {
+ s.writeInt(members.length);
+ for (int i = 0, len = members.length; i < len; i++) {
+ members[i].write(s);
+ }
+ }
+
+ public static ResolvedMemberImpl readResolvedMember(VersionedDataInputStream s, ISourceContext sourceContext)
+ throws IOException {
+
+ MemberKind mk = MemberKind.read(s);
+ boolean compressed = (s.isAtLeast169() ? s.readBoolean() : false);
+ UnresolvedType declaringType = compressed ? UnresolvedType.forSignature(s.readUtf8(s.readShort())) : UnresolvedType.read(s);
+ int modifiers = s.readInt();
+ String name = compressed ? s.readUtf8(s.readShort()) : s.readUTF();
+ String signature = compressed ? s.readUtf8(s.readShort()) : s.readUTF();
+ ResolvedMemberImpl m = new ResolvedMemberImpl(mk, declaringType, modifiers, name, signature);
+ m.checkedExceptions = UnresolvedType.readArray(s);
+
+ m.start = s.readInt();
+ m.end = s.readInt();
+ m.sourceContext = sourceContext;
+
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150M4) {
+ boolean isvarargs = s.readBoolean();
+ if (isvarargs) {
+ m.setVarargsMethod();
+ }
+ }
+
+ int tvcount = s.isAtLeast169() ? s.readByte() : s.readInt();
+ if (tvcount != 0) {
+ m.typeVariables = new TypeVariable[tvcount];
+ for (int i = 0; i < tvcount; i++) {
+ m.typeVariables[i] = TypeVariable.read(s);
+ m.typeVariables[i].setDeclaringElement(m);
+ m.typeVariables[i].setRank(i);
+ }
+ }
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150M4) {
+ int pcount = -1;
+ boolean hasAGenericSignature = false;
+ if (s.isAtLeast169()) {
+ pcount = s.readByte();
+ hasAGenericSignature = (pcount >= 0 && pcount < 255);
+ } else {
+ hasAGenericSignature = s.readBoolean();
+ }
+ if (hasAGenericSignature) {
+ int ps = (s.isAtLeast169() ? pcount : s.readInt());
+ UnresolvedType[] params = new UnresolvedType[ps];
+ for (int i = 0; i < params.length; i++) {
+ if (compressed) {
+ params[i] = TypeFactory.createTypeFromSignature(s.readSignature());
+ } else {
+ params[i] = TypeFactory.createTypeFromSignature(s.readUTF());
+ }
+ }
+ UnresolvedType rt = compressed ? TypeFactory.createTypeFromSignature(s.readSignature()) : TypeFactory
+ .createTypeFromSignature(s.readUTF());
+ m.parameterTypes = params;
+ m.returnType = rt;
+ }
+ }
+ }
+ return m;
+ }
+
+ public static ResolvedMember[] readResolvedMemberArray(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ int len = s.readInt();
+ ResolvedMember[] members = new ResolvedMember[len];
+ for (int i = 0; i < len; i++) {
+ members[i] = ResolvedMemberImpl.readResolvedMember(s, context);
+ }
+ return members;
+ }
+
+ // OPTIMIZE dont like how resolve(world) on ResolvedMemberImpl does
+ // something different to world.resolve(member)
+ @Override
+ public ResolvedMember resolve(World world) {
+ if (isResolved) {
+ return this;
+ }
+ // make sure all the pieces of a resolvedmember really are resolved
+ try {
+ if (typeVariables != null && typeVariables.length > 0) {
+ for (int i = 0; i < typeVariables.length; i++) {
+ typeVariables[i] = typeVariables[i].resolve(world);
+ }
+ }
+ world.setTypeVariableLookupScope(this);
+ // if (annotationTypes != null) {
+ // Set<ResolvedType> r = new HashSet<ResolvedType>();
+ // for (UnresolvedType element : annotationTypes) {
+ // // for (Iterator iter = annotationTypes.iterator(); iter.hasNext();) {
+ // // UnresolvedType element = (UnresolvedType) iter.next();
+ // r.add(world.resolve(element));
+ // }
+ // annotationTypes = r;
+ // }
+ declaringType = declaringType.resolve(world);
+ if (declaringType.isRawType()) {
+ declaringType = ((ReferenceType) declaringType).getGenericType();
+ }
+
+ if (parameterTypes != null && parameterTypes.length > 0) {
+ for (int i = 0; i < parameterTypes.length; i++) {
+ parameterTypes[i] = parameterTypes[i].resolve(world);
+ }
+ }
+
+ returnType = returnType.resolve(world);
+
+ } finally {
+ world.setTypeVariableLookupScope(null);
+ }
+ isResolved = true;
+ return this;
+ }
+
+ public ISourceContext getSourceContext(World world) {
+ return getDeclaringType().resolve(world).getSourceContext();
+ }
+
+ public String[] getParameterNames() {
+ return parameterNames;
+ }
+
+ public final void setParameterNames(String[] pnames) {
+ parameterNames = pnames;
+ }
+
+ @Override
+ public final String[] getParameterNames(World world) {
+ return getParameterNames();
+ }
+
+ public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() {
+ return null;
+ }
+
+ public ISourceLocation getSourceLocation() {
+ // System.out.println("get context: " + this + " is " + sourceContext);
+ if (getSourceContext() == null) {
+ // System.err.println("no context: " + this);
+ return null;
+ }
+ return getSourceContext().makeSourceLocation(this);
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public ISourceContext getSourceContext() {
+ return sourceContext;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public void setPosition(int sourceStart, int sourceEnd) {
+ this.start = sourceStart;
+ this.end = sourceEnd;
+ }
+
+ public void setDeclaringType(ReferenceType rt) {
+ declaringType = rt;
+ }
+
+ public void setSourceContext(ISourceContext sourceContext) {
+ this.sourceContext = sourceContext;
+ }
+
+ public boolean isAbstract() {
+ return Modifier.isAbstract(modifiers);
+ }
+
+ public boolean isPublic() {
+ return Modifier.isPublic(modifiers);
+ }
+
+ public boolean isDefault() {
+ int mods = getModifiers();
+ return !(Modifier.isPublic(mods) || Modifier.isProtected(mods) || Modifier.isPrivate(mods));
+ }
+
+ public boolean isVisible(ResolvedType fromType) {
+ UnresolvedType declaringType = getDeclaringType();
+ ResolvedType type = null;
+ if (fromType.equals(declaringType)) {
+ type = fromType;
+ } else {
+ World world = fromType.getWorld();
+ type = declaringType.resolve(world);
+ }
+ return ResolvedType.isVisible(getModifiers(), type, fromType);
+ }
+
+ public void setCheckedExceptions(UnresolvedType[] checkedExceptions) {
+ this.checkedExceptions = checkedExceptions;
+ }
+
+ public void setAnnotatedElsewhere(boolean b) {
+ isAnnotatedElsewhere = b;
+ }
+
+ public boolean isAnnotatedElsewhere() {
+ return isAnnotatedElsewhere;
+ }
+
+ /**
+ * Get the UnresolvedType for the return type, taking generic signature into account
+ */
+ @Override
+ public UnresolvedType getGenericReturnType() {
+ return getReturnType();
+ }
+
+ /**
+ * Get the TypeXs of the parameter types, taking generic signature into account
+ */
+ @Override
+ public UnresolvedType[] getGenericParameterTypes() {
+ return getParameterTypes();
+ }
+
+ public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
+ boolean isParameterized) {
+ return parameterizedWith(typeParameters, newDeclaringType, isParameterized, null);
+ }
+
+ /**
+ * Return a resolvedmember in which all the type variables in the signature have been replaced with the given bindings. The
+ * 'isParameterized' flag tells us whether we are creating a raw type version or not. if (isParameterized) then List<T> will
+ * turn into List<String> (for example) - if (!isParameterized) then List<T> will turn into List.
+ */
+ public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
+ boolean isParameterized, List<String> aliases) {
+ // PR308773
+ // this check had problems for the inner type of a generic type because the inner type can be represented
+ // by a 'simple type' if it is only sharing type variables with the outer and has none of its own. To avoid the
+ // check going bang in this case we check for $ (crap...) - we can't check the outer because the declaring type
+ // is considered unresolved...
+ if (// isParameterized && <-- might need this bit...
+ !getDeclaringType().isGenericType() && getDeclaringType().getName().indexOf("$") == -1) {
+ throw new IllegalStateException("Can't ask to parameterize a member of non-generic type: " + getDeclaringType()
+ + " kind(" + getDeclaringType().typeKind + ")");
+ }
+ TypeVariable[] typeVariables = getDeclaringType().getTypeVariables();
+ if (isParameterized && (typeVariables.length != typeParameters.length)) {
+ throw new IllegalStateException("Wrong number of type parameters supplied");
+ }
+ Map<String, UnresolvedType> typeMap = new HashMap<String, UnresolvedType>();
+ boolean typeParametersSupplied = typeParameters != null && typeParameters.length > 0;
+ if (typeVariables != null) {
+ // If no 'replacements' were supplied in the typeParameters array
+ // then collapse
+ // type variables to their first bound.
+ for (int i = 0; i < typeVariables.length; i++) {
+ UnresolvedType ut = (!typeParametersSupplied ? typeVariables[i].getFirstBound() : typeParameters[i]);
+ typeMap.put(typeVariables[i].getName(), ut);
+ }
+ }
+ // For ITDs on generic types that use type variables from the target type, the aliases
+ // record the alternative names used throughout the ITD expression that must map to
+ // the same value as the type variables real name.
+ if (aliases != null) {
+ int posn = 0;
+ for (String typeVariableAlias : aliases) {
+ typeMap.put(typeVariableAlias, (!typeParametersSupplied ? typeVariables[posn].getFirstBound()
+ : typeParameters[posn]));
+ posn++;
+ }
+ }
+
+ UnresolvedType parameterizedReturnType = parameterize(getGenericReturnType(), typeMap, isParameterized,
+ newDeclaringType.getWorld());
+ UnresolvedType[] parameterizedParameterTypes = new UnresolvedType[getGenericParameterTypes().length];
+ UnresolvedType[] genericParameterTypes = getGenericParameterTypes();
+ for (int i = 0; i < parameterizedParameterTypes.length; i++) {
+ parameterizedParameterTypes[i] = parameterize(genericParameterTypes[i], typeMap, isParameterized,
+ newDeclaringType.getWorld());
+ }
+ ResolvedMemberImpl ret = new ResolvedMemberImpl(getKind(), newDeclaringType, getModifiers(), parameterizedReturnType,
+ getName(), parameterizedParameterTypes, getExceptions(), this);
+ ret.setTypeVariables(getTypeVariables());
+ ret.setSourceContext(getSourceContext());
+ ret.setPosition(getStart(), getEnd());
+ ret.setParameterNames(getParameterNames());
+ return ret;
+ }
+
+ /**
+ * Replace occurrences of type variables in the signature with values contained in the map. The map is of the form
+ * A=String,B=Integer and so a signature List<A> Foo.m(B i) {} would become List<String> Foo.m(Integer i) {}
+ */
+ public ResolvedMember parameterizedWith(Map<String, UnresolvedType> m, World w) {
+ // if (//isParameterized && <-- might need this bit...
+ // !getDeclaringType().isGenericType()) {
+ // throw new IllegalStateException(
+ // "Can't ask to parameterize a member of non-generic type: "
+ // +getDeclaringType()+" kind("+
+ // getDeclaringType().typeKind+")");
+ // }
+ declaringType = declaringType.resolve(w);
+ if (declaringType.isRawType()) {
+ declaringType = ((ResolvedType) declaringType).getGenericType();
+ // TypeVariable[] typeVariables = getDeclaringType().getTypeVariables();
+ // if (isParameterized && (typeVariables.length !=
+ // typeParameters.length)) {
+ // throw new
+ // IllegalStateException("Wrong number of type parameters supplied");
+ // }
+ // Map typeMap = new HashMap();
+ // boolean typeParametersSupplied = typeParameters!=null &&
+ // typeParameters.length>0;
+ // if (typeVariables!=null) {
+ // // If no 'replacements' were supplied in the typeParameters array
+ // then collapse
+ // // type variables to their first bound.
+ // for (int i = 0; i < typeVariables.length; i++) {
+ // UnresolvedType ut =
+ // (!typeParametersSupplied?typeVariables[i].getFirstBound
+ // ():typeParameters[i]);
+ // typeMap.put(typeVariables[i].getName(),ut);
+ // }
+ // }
+ // // For ITDs on generic types that use type variables from the target
+ // type, the aliases
+ // // record the alternative names used throughout the ITD expression
+ // that must map to
+ // // the same value as the type variables real name.
+ // if (aliases!=null) {
+ // int posn = 0;
+ // for (Iterator iter = aliases.iterator(); iter.hasNext();) {
+ // String typeVariableAlias = (String) iter.next();
+ // typeMap.put(typeVariableAlias,(!typeParametersSupplied?typeVariables[
+ // posn].getFirstBound():typeParameters[posn]));
+ // posn++;
+ // }
+ // }
+ }
+
+ UnresolvedType parameterizedReturnType = parameterize(getGenericReturnType(), m, true, w);
+ UnresolvedType[] parameterizedParameterTypes = new UnresolvedType[getGenericParameterTypes().length];
+ UnresolvedType[] genericParameterTypes = getGenericParameterTypes();
+ for (int i = 0; i < parameterizedParameterTypes.length; i++) {
+ parameterizedParameterTypes[i] = parameterize(genericParameterTypes[i], m, true, w);
+ }
+ ResolvedMemberImpl ret = new ResolvedMemberImpl(getKind(), declaringType, getModifiers(), parameterizedReturnType,
+ getName(), parameterizedParameterTypes, getExceptions(), this);
+ ret.setTypeVariables(getTypeVariables());
+ ret.setSourceContext(getSourceContext());
+ ret.setPosition(getStart(), getEnd());
+ ret.setParameterNames(getParameterNames());
+ return ret;
+ }
+
+ public void setTypeVariables(TypeVariable[] tvars) {
+ typeVariables = tvars;
+ }
+
+ public TypeVariable[] getTypeVariables() {
+ return typeVariables;
+ }
+
+ protected UnresolvedType parameterize(UnresolvedType aType, Map<String, UnresolvedType> typeVariableMap,
+ boolean inParameterizedType, World w) {
+ if (aType instanceof TypeVariableReference) {
+ String variableName = ((TypeVariableReference) aType).getTypeVariable().getName();
+ if (!typeVariableMap.containsKey(variableName)) {
+ return aType; // if the type variable comes from the method (and
+ // not the type) thats OK
+ }
+ return typeVariableMap.get(variableName);
+ } else if (aType.isParameterizedType()) {
+ if (inParameterizedType) {
+ if (w != null) {
+ aType = aType.resolve(w);
+ } else {
+ UnresolvedType dType = getDeclaringType();
+ aType = aType.resolve(((ResolvedType) dType).getWorld());
+ }
+ return aType.parameterize(typeVariableMap);
+ } else {
+ return aType.getRawType();
+ }
+ } else if (aType.isArray()) {
+ // The component type might be a type variable (pr150095)
+ int dims = 1;
+ String sig = aType.getSignature();
+ // while (sig.charAt(dims) == '[')
+ // dims++;
+ UnresolvedType arrayType = null;
+ UnresolvedType componentSig = UnresolvedType.forSignature(sig.substring(dims));
+ UnresolvedType parameterizedComponentSig = parameterize(componentSig, typeVariableMap, inParameterizedType, w);
+ if (parameterizedComponentSig.isTypeVariableReference()
+ && parameterizedComponentSig instanceof UnresolvedTypeVariableReferenceType
+ && typeVariableMap.containsKey(((UnresolvedTypeVariableReferenceType) parameterizedComponentSig)
+ .getTypeVariable().getName())) { // pr250632
+ // TODO ASC bah, this code is rubbish - i should fix it properly
+ StringBuffer newsig = new StringBuffer();
+ newsig.append("[T");
+ newsig.append(((UnresolvedTypeVariableReferenceType) parameterizedComponentSig).getTypeVariable().getName());
+ newsig.append(";");
+ arrayType = UnresolvedType.forSignature(newsig.toString());
+ } else {
+ arrayType = ResolvedType.makeArray(parameterizedComponentSig, dims);
+ }
+ return arrayType;
+ }
+ return aType;
+ }
+
+ /**
+ * If this member is defined by a parameterized super-type, return the erasure of that member. For example: interface I<T> { T
+ * foo(T aTea); } class C implements I<String> { String foo(String aString) { return "something"; } } The resolved member for
+ * C.foo has signature String foo(String). The erasure of that member is Object foo(Object) -- use upper bound of type variable.
+ * A type is a supertype of itself.
+ */
+ // public ResolvedMember getErasure() {
+ // if (calculatedMyErasure) return myErasure;
+ // calculatedMyErasure = true;
+ // ResolvedType resolvedDeclaringType = (ResolvedType) getDeclaringType();
+ // // this next test is fast, and the result is cached.
+ // if (!resolvedDeclaringType.hasParameterizedSuperType()) {
+ // return null;
+ // } else {
+ // // we have one or more parameterized super types.
+ // // this member may be defined by one of them... we need to find out.
+ // Collection declaringTypes =
+ // this.getDeclaringTypes(resolvedDeclaringType.getWorld());
+ // for (Iterator iter = declaringTypes.iterator(); iter.hasNext();) {
+ // ResolvedType aDeclaringType = (ResolvedType) iter.next();
+ // if (aDeclaringType.isParameterizedType()) {
+ // // we've found the (a?) parameterized type that defines this member.
+ // // now get the erasure of it
+ // ResolvedMemberImpl matchingMember = (ResolvedMemberImpl)
+ // aDeclaringType.lookupMemberNoSupers(this);
+ // if (matchingMember != null && matchingMember.backingGenericMember !=
+ // null) {
+ // myErasure = matchingMember.backingGenericMember;
+ // return myErasure;
+ // }
+ // }
+ // }
+ // }
+ // return null;
+ // }
+ //
+ // private ResolvedMember myErasure = null;
+ // private boolean calculatedMyErasure = false;
+ public boolean hasBackingGenericMember() {
+ return backingGenericMember != null;
+ }
+
+ public ResolvedMember getBackingGenericMember() {
+ return backingGenericMember;
+ }
+
+ /**
+ * For ITDs, we use the default factory methods to build a resolved member, then alter a couple of characteristics using this
+ * method - this is safe.
+ */
+ public void resetName(String newName) {
+ this.name = newName;
+ }
+
+ public void resetKind(MemberKind newKind) {
+ this.kind = newKind;
+ }
+
+ public void resetModifiers(int newModifiers) {
+ this.modifiers = newModifiers;
+ }
+
+ public void resetReturnTypeToObjectArray() {
+ returnType = UnresolvedType.OBJECTARRAY;
+ }
+
+ /**
+ * Returns true if this member matches the other. The matching takes into account name and parameter types only. When comparing
+ * parameter types, we allow any type variable to match any other type variable regardless of bounds.
+ */
+ public boolean matches(ResolvedMember aCandidateMatch, boolean ignoreGenerics) {
+ ResolvedMemberImpl candidateMatchImpl = (ResolvedMemberImpl) aCandidateMatch;
+ if (!getName().equals(aCandidateMatch.getName())) {
+ return false;
+ }
+ UnresolvedType[] parameterTypes = getGenericParameterTypes();
+ UnresolvedType[] candidateParameterTypes = aCandidateMatch.getGenericParameterTypes();
+ if (parameterTypes.length != candidateParameterTypes.length) {
+ return false;
+ }
+ boolean b = false;
+ /*
+ * if (ignoreGenerics) { String myParameterSignature = getParameterSigWithBoundsRemoved(); String
+ * candidateParameterSignature = candidateMatchImpl.getParameterSigWithBoundsRemoved(); if
+ * (myParameterSignature.equals(candidateParameterSignature)) { b = true; } else { myParameterSignature =
+ * (hasBackingGenericMember() ? backingGenericMember.getParameterSignatureErased() : getParameterSignatureErased());
+ * candidateParameterSignature = (candidateMatchImpl.hasBackingGenericMember() ? candidateMatchImpl.backingGenericMember
+ * .getParameterSignatureErased() : candidateMatchImpl.getParameterSignatureErased()); // System.out.println("my psig = " +
+ * myParameterSignature); // System.out.println("can psig = " + candidateParameterSignature); b =
+ * myParameterSignature.equals(candidateParameterSignature); } } else {
+ */
+ String myParameterSignature = getParameterSigWithBoundsRemoved();
+ String candidateParameterSignature = candidateMatchImpl.getParameterSigWithBoundsRemoved();
+ if (myParameterSignature.equals(candidateParameterSignature)) {
+ b = true;
+ } else {
+ // try erasure
+ myParameterSignature = getParameterSignatureErased();
+ candidateParameterSignature = candidateMatchImpl.getParameterSignatureErased();
+ // myParameterSignature = (hasBackingGenericMember() ? backingGenericMember.getParameterSignatureErased()
+ // : getParameterSignatureErased());
+ // candidateParameterSignature = (candidateMatchImpl.hasBackingGenericMember() ?
+ // candidateMatchImpl.backingGenericMember
+ // .getParameterSignatureErased() : candidateMatchImpl.getParameterSignatureErased());
+ // System.out.println("my psig = " + myParameterSignature);
+ // System.out.println("can psig = " + candidateParameterSignature);
+ b = myParameterSignature.equals(candidateParameterSignature);
+ // }
+ }
+ // System.out.println("Checking param signatures: " + b);
+ return b;
+ }
+
+ /**
+ * converts e.g. <T extends Number>.... List<T> to just Ljava/util/List<T;>; whereas the full signature would be
+ * Ljava/util/List<T:Ljava/lang/Number;>;
+ */
+ private String myParameterSignatureWithBoundsRemoved = null;
+ /**
+ * converts e.g. <T extends Number>.... List<T> to just Ljava/util/List;
+ */
+ private String myParameterSignatureErasure = null;
+
+ // does NOT produce a meaningful java signature, but does give a unique
+ // string suitable for
+ // comparison.
+ private String getParameterSigWithBoundsRemoved() {
+ if (myParameterSignatureWithBoundsRemoved != null) {
+ return myParameterSignatureWithBoundsRemoved;
+ }
+ StringBuffer sig = new StringBuffer();
+ UnresolvedType[] myParameterTypes = getGenericParameterTypes();
+ for (int i = 0; i < myParameterTypes.length; i++) {
+ appendSigWithTypeVarBoundsRemoved(myParameterTypes[i], sig, new HashSet<UnresolvedType>());
+ }
+ myParameterSignatureWithBoundsRemoved = sig.toString();
+ return myParameterSignatureWithBoundsRemoved;
+ }
+
+ /**
+ * Return the erased form of the signature with bounds collapsed for type variables, etc. Does not include the return type, @see
+ * getParam
+ */
+ public String getParameterSignatureErased() {
+ if (myParameterSignatureErasure == null) {
+ StringBuilder sig = new StringBuilder();
+ for (UnresolvedType parameter : getParameterTypes()) {
+ sig.append(parameter.getErasureSignature());
+ }
+ myParameterSignatureErasure = sig.toString();
+ }
+ return myParameterSignatureErasure;
+ }
+
+ public String getSignatureErased() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("(");
+ sb.append(getParameterSignatureErased());
+ sb.append(")");
+ sb.append(getReturnType().getErasureSignature());
+ return sb.toString();
+ }
+
+ // does NOT produce a meaningful java signature, but does give a unique
+ // string suitable for
+ // comparison.
+ public static void appendSigWithTypeVarBoundsRemoved(UnresolvedType aType, StringBuffer toBuffer,
+ Set<UnresolvedType> alreadyUsedTypeVars) {
+ if (aType.isTypeVariableReference()) {
+ TypeVariableReferenceType typeVariableRT = (TypeVariableReferenceType) aType;
+ // pr204505
+ if (alreadyUsedTypeVars.contains(aType)) {
+ toBuffer.append("...");
+ } else {
+ alreadyUsedTypeVars.add(aType);
+ appendSigWithTypeVarBoundsRemoved(typeVariableRT.getTypeVariable().getFirstBound(), toBuffer, alreadyUsedTypeVars);
+ }
+ // toBuffer.append("T;");
+ } else if (aType.isParameterizedType()) {
+ toBuffer.append(aType.getRawType().getSignature());
+ toBuffer.append("<");
+ for (int i = 0; i < aType.getTypeParameters().length; i++) {
+ appendSigWithTypeVarBoundsRemoved(aType.getTypeParameters()[i], toBuffer, alreadyUsedTypeVars);
+ }
+ toBuffer.append(">;");
+ } else {
+ toBuffer.append(aType.getSignature());
+ }
+ }
+
+ /**
+ * Useful for writing tests, returns *everything* we know about this member.
+ */
+ public String toDebugString() {
+ StringBuffer r = new StringBuffer();
+
+ // modifiers
+ int mods = modifiers;
+ if ((mods & 4096) > 0) {
+ mods = mods - 4096; // remove synthetic (added in the ASM case but
+ }
+ // not in the BCEL case...)
+ if ((mods & 512) > 0) {
+ mods = mods - 512; // remove interface (added in the BCEL case but
+ }
+ // not in the ASM case...)
+ if ((mods & 131072) > 0) {
+ mods = mods - 131072; // remove deprecated (added in the ASM case
+ }
+ // but not in the BCEL case...)
+ String modsStr = Modifier.toString(mods);
+ if (modsStr.length() != 0) {
+ r.append(modsStr).append("(" + mods + ")").append(" ");
+ }
+
+ // type variables
+ if (typeVariables != null && typeVariables.length > 0) {
+ r.append("<");
+ for (int i = 0; i < typeVariables.length; i++) {
+ if (i > 0) {
+ r.append(",");
+ }
+ TypeVariable t = typeVariables[i];
+ r.append(t.toDebugString());
+ }
+ r.append("> ");
+ }
+
+ // 'declaring' type
+ r.append(getGenericReturnType().toDebugString());
+ r.append(' ');
+
+ // name
+ r.append(declaringType.getName());
+ r.append('.');
+ r.append(name);
+
+ // parameter signature if a method
+ if (kind != FIELD) {
+ r.append("(");
+ UnresolvedType[] params = getGenericParameterTypes();
+ boolean parameterNamesExist = showParameterNames && parameterNames != null && parameterNames.length == params.length;
+ if (params.length != 0) {
+ for (int i = 0, len = params.length; i < len; i++) {
+ if (i > 0) {
+ r.append(", ");
+ }
+ r.append(params[i].toDebugString());
+ if (parameterNamesExist) {
+ r.append(" ").append(parameterNames[i]);
+ }
+ }
+ }
+ r.append(")");
+ }
+ return r.toString();
+ }
+
+ // SECRETAPI - controlling whether parameter names come out in the debug
+ // string (for testing purposes)
+ public static boolean showParameterNames = true;
+
+ public String toGenericString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(getGenericReturnType().getSimpleName());
+ buf.append(' ');
+ buf.append(declaringType.getName());
+ buf.append('.');
+ buf.append(name);
+ if (kind != FIELD) {
+ buf.append("(");
+ UnresolvedType[] params = getGenericParameterTypes();
+ if (params.length != 0) {
+ buf.append(params[0].getSimpleName());
+ for (int i = 1, len = params.length; i < len; i++) {
+ buf.append(", ");
+ buf.append(params[i].getSimpleName());
+ }
+ }
+ buf.append(")");
+ }
+ return buf.toString();
+ }
+
+ public boolean isCompatibleWith(Member am) {
+ if (kind != METHOD || am.getKind() != METHOD) {
+ return true;
+ }
+ if (!name.equals(am.getName())) {
+ return true;
+ }
+ if (!equalTypes(getParameterTypes(), am.getParameterTypes())) {
+ return true;
+ }
+ return getReturnType().equals(am.getReturnType());
+ }
+
+ private static boolean equalTypes(UnresolvedType[] a, UnresolvedType[] b) {
+ int len = a.length;
+ if (len != b.length) {
+ return false;
+ }
+ for (int i = 0; i < len; i++) {
+ if (!a[i].equals(b[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public TypeVariable getTypeVariableNamed(String name) {
+ // Check locally...
+ if (typeVariables != null) {
+ for (int i = 0; i < typeVariables.length; i++) {
+ if (typeVariables[i].getName().equals(name)) {
+ return typeVariables[i];
+ }
+ }
+ }
+ // check the declaring type!
+ return declaringType.getTypeVariableNamed(name);
+
+ // Do generic aspects with ITDs that share type variables with the
+ // aspect and the target type and have their own tvars cause
+ // this to be messier?
+ }
+
+ public void evictWeavingState() {
+ }
+
+
+ public boolean isEquivalentTo(Object other) {
+ return this.equals(other);
+ }
+
+ public boolean isDefaultConstructor() {
+ return false;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedPointcutDefinition.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedPointcutDefinition.java
new file mode 100644
index 000000000..500b30cd0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedPointcutDefinition.java
@@ -0,0 +1,142 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.aspectj.weaver.patterns.Pointcut;
+
+public class ResolvedPointcutDefinition extends ResolvedMemberImpl {
+ private Pointcut pointcut;
+
+ public ResolvedPointcutDefinition(UnresolvedType declaringType, int modifiers, String name, UnresolvedType[] parameterTypes,
+ Pointcut pointcut) {
+ this(declaringType, modifiers, name, parameterTypes, UnresolvedType.VOID, pointcut);
+ }
+
+ /**
+ * An instance which can be given a specific returnType, used f.e. in if() pointcut for @AJ
+ *
+ * @param declaringType
+ * @param modifiers
+ * @param name
+ * @param parameterTypes
+ * @param returnType
+ * @param pointcut
+ */
+ public ResolvedPointcutDefinition(UnresolvedType declaringType, int modifiers, String name, UnresolvedType[] parameterTypes,
+ UnresolvedType returnType, Pointcut pointcut) {
+ super(POINTCUT, declaringType, modifiers, returnType, name, parameterTypes);
+ this.pointcut = pointcut;
+ // XXXpointcut.assertState(Pointcut.RESOLVED);
+ checkedExceptions = UnresolvedType.NONE;
+ }
+
+ // ----
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ getDeclaringType().write(s);
+ s.writeInt(getModifiers());
+ s.writeUTF(getName());
+ UnresolvedType.writeArray(getParameterTypes(), s);
+ pointcut.write(s);
+ }
+
+ public static ResolvedPointcutDefinition read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ResolvedPointcutDefinition rpd = new ResolvedPointcutDefinition(UnresolvedType.read(s), s.readInt(), s.readUTF(),
+ UnresolvedType.readArray(s), Pointcut.read(s, context));
+ rpd.setSourceContext(context); // whilst we have a source context, let's remember it
+ return rpd;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("pointcut ");
+ buf.append((getDeclaringType() == null ? "<nullDeclaringType>" : getDeclaringType().getName()));
+ buf.append(".");
+ buf.append(getName());
+ buf.append("(");
+ for (int i = 0; i < getParameterTypes().length; i++) {
+ if (i > 0) {
+ buf.append(", ");
+ }
+ buf.append(getParameterTypes()[i].toString());
+ }
+ buf.append(")");
+ // buf.append(pointcut);
+
+ return buf.toString();
+ }
+
+ public Pointcut getPointcut() {
+ return pointcut;
+ }
+
+ @Override
+ public boolean isAjSynthetic() {
+ return true;
+ }
+
+ /**
+ * Called when asking a parameterized super-aspect for its pointcuts.
+ */
+ @Override
+ public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
+ boolean isParameterized) {
+ TypeVariable[] typeVariables = getDeclaringType().resolve(newDeclaringType.getWorld()).getTypeVariables();
+ if (isParameterized && (typeVariables.length != typeParameters.length)) {
+ throw new IllegalStateException("Wrong number of type parameters supplied");
+ }
+ Map typeMap = new HashMap();
+ boolean typeParametersSupplied = typeParameters != null && typeParameters.length > 0;
+ if (typeVariables != null) {
+ // If no 'replacements' were supplied in the typeParameters array then collapse
+ // type variables to their first bound.
+ for (int i = 0; i < typeVariables.length; i++) {
+ UnresolvedType ut = (!typeParametersSupplied ? typeVariables[i].getFirstBound() : typeParameters[i]);
+ typeMap.put(typeVariables[i].getName(), ut);
+ }
+ }
+ UnresolvedType parameterizedReturnType = parameterize(getGenericReturnType(), typeMap, isParameterized,
+ newDeclaringType.getWorld());
+ UnresolvedType[] parameterizedParameterTypes = new UnresolvedType[getGenericParameterTypes().length];
+ for (int i = 0; i < parameterizedParameterTypes.length; i++) {
+ parameterizedParameterTypes[i] = parameterize(getGenericParameterTypes()[i], typeMap, isParameterized,
+ newDeclaringType.getWorld());
+ }
+ ResolvedPointcutDefinition ret = new ResolvedPointcutDefinition(newDeclaringType, getModifiers(), getName(),
+ parameterizedParameterTypes, parameterizedReturnType, pointcut.parameterizeWith(typeMap,
+ newDeclaringType.getWorld()));
+ ret.setTypeVariables(getTypeVariables());
+ ret.setSourceContext(getSourceContext());
+ ret.setPosition(getStart(), getEnd());
+ ret.setParameterNames(getParameterNames());
+ return ret;
+ // return this;
+ }
+
+ // for testing
+ public static final ResolvedPointcutDefinition DUMMY = new ResolvedPointcutDefinition(UnresolvedType.OBJECT, 0, "missing",
+ UnresolvedType.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED));
+
+ public static final ResolvedPointcutDefinition[] NO_POINTCUTS = new ResolvedPointcutDefinition[] {};
+
+ public void setPointcut(Pointcut pointcut) {
+ this.pointcut = pointcut;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedType.java
new file mode 100644
index 000000000..98400ebdc
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedType.java
@@ -0,0 +1,2933 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Alexandre Vasseur @AspectJ ITDs
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.Iterators.Getter;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.PerClause;
+
+public abstract class ResolvedType extends UnresolvedType implements AnnotatedElement {
+
+ public static final ResolvedType[] EMPTY_RESOLVED_TYPE_ARRAY = new ResolvedType[0];
+ public static final String PARAMETERIZED_TYPE_IDENTIFIER = "P";
+
+ // Set temporarily during a type pattern match call - this currently used to hold the
+ // annotations that may be attached to a type when it used as a parameter
+ public ResolvedType[] temporaryAnnotationTypes;
+ private ResolvedType[] resolvedTypeParams;
+ private String binaryPath;
+
+ protected World world;
+
+ protected int bits;
+
+ private static int AnnotationBitsInitialized = 0x0001;
+ private static int AnnotationMarkedInherited = 0x0002;
+ private static int MungersAnalyzed = 0x0004;
+ private static int HasParentMunger = 0x0008;
+ private static int TypeHierarchyCompleteBit = 0x0010;
+ private static int GroovyObjectInitialized = 0x0020;
+ private static int IsGroovyObject = 0x0040;
+ private static int IsPrivilegedBitInitialized = 0x0080;
+ private static int IsPrivilegedAspect = 0x0100;
+
+ protected ResolvedType(String signature, World world) {
+ super(signature);
+ this.world = world;
+ }
+
+ protected ResolvedType(String signature, String signatureErasure, World world) {
+ super(signature, signatureErasure);
+ this.world = world;
+ }
+
+ @Override
+ public int getSize() {
+ return 1;
+ }
+
+ /**
+ * Returns an iterator through ResolvedType objects representing all the direct supertypes of this type. That is, through the
+ * superclass, if any, and all declared interfaces.
+ */
+ public final Iterator<ResolvedType> getDirectSupertypes() {
+ Iterator<ResolvedType> interfacesIterator = Iterators.array(getDeclaredInterfaces());
+ ResolvedType superclass = getSuperclass();
+ if (superclass == null) {
+ return interfacesIterator;
+ } else {
+ return Iterators.snoc(interfacesIterator, superclass);
+ }
+ }
+
+ public abstract ResolvedMember[] getDeclaredFields();
+
+ public abstract ResolvedMember[] getDeclaredMethods();
+
+ public abstract ResolvedType[] getDeclaredInterfaces();
+
+ public abstract ResolvedMember[] getDeclaredPointcuts();
+
+ public boolean isCacheable() {
+ return true;
+ }
+
+ /**
+ * @return the superclass of this type, or null (if this represents a jlObject, primitive, or void)
+ */
+ public abstract ResolvedType getSuperclass();
+
+ public abstract int getModifiers();
+
+ public boolean canBeSeenBy(ResolvedType from) {
+ int targetMods = getModifiers();
+ if (Modifier.isPublic(targetMods)) {
+ return true;
+ }
+ if (Modifier.isPrivate(targetMods)) {
+ return false;
+ }
+ // isProtected() or isDefault()
+ return getPackageName().equals(from.getPackageName());
+ }
+
+ // return true if this resolved type couldn't be found (but we know it's name maybe)
+ public boolean isMissing() {
+ return false;
+ }
+
+ // FIXME asc I wonder if in some circumstances MissingWithKnownSignature
+ // should not be considered
+ // 'really' missing as some code can continue based solely on the signature
+ public static boolean isMissing(UnresolvedType unresolved) {
+ if (unresolved instanceof ResolvedType) {
+ ResolvedType resolved = (ResolvedType) unresolved;
+ return resolved.isMissing();
+ } else {
+ return (unresolved == MISSING);
+ }
+ }
+
+ @Override
+ public ResolvedType[] getAnnotationTypes() {
+ return EMPTY_RESOLVED_TYPE_ARRAY;
+ }
+
+ @Override
+ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
+ return null;
+ }
+
+ // public final UnresolvedType getSuperclass(World world) {
+ // return getSuperclass();
+ // }
+
+ // This set contains pairs of types whose signatures are concatenated
+ // together, this means with a fast lookup we can tell if two types
+ // are equivalent.
+ protected static Set<String> validBoxing = new HashSet<String>();
+
+ static {
+ validBoxing.add("Ljava/lang/Byte;B");
+ validBoxing.add("Ljava/lang/Character;C");
+ validBoxing.add("Ljava/lang/Double;D");
+ validBoxing.add("Ljava/lang/Float;F");
+ validBoxing.add("Ljava/lang/Integer;I");
+ validBoxing.add("Ljava/lang/Long;J");
+ validBoxing.add("Ljava/lang/Short;S");
+ validBoxing.add("Ljava/lang/Boolean;Z");
+ validBoxing.add("BLjava/lang/Byte;");
+ validBoxing.add("CLjava/lang/Character;");
+ validBoxing.add("DLjava/lang/Double;");
+ validBoxing.add("FLjava/lang/Float;");
+ validBoxing.add("ILjava/lang/Integer;");
+ validBoxing.add("JLjava/lang/Long;");
+ validBoxing.add("SLjava/lang/Short;");
+ validBoxing.add("ZLjava/lang/Boolean;");
+ }
+
+ // utilities
+ public ResolvedType getResolvedComponentType() {
+ return null;
+ }
+
+ public World getWorld() {
+ return world;
+ }
+
+ // ---- things from object
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ResolvedType) {
+ return this == other;
+ } else {
+ return super.equals(other);
+ }
+ }
+
+ // ---- difficult things
+
+ /**
+ * returns an iterator through all of the fields of this type, in order for checking from JVM spec 2ed 5.4.3.2. This means that
+ * the order is
+ * <p/>
+ * <ul>
+ * <li>fields from current class</li>
+ * <li>recur into direct superinterfaces</li>
+ * <li>recur into superclass</li>
+ * </ul>
+ * <p/>
+ * We keep a hashSet of interfaces that we've visited so we don't spiral out into 2^n land.
+ */
+ public Iterator<ResolvedMember> getFields() {
+ final Iterators.Filter<ResolvedType> dupFilter = Iterators.dupFilter();
+ Iterators.Getter<ResolvedType, ResolvedType> typeGetter = new Iterators.Getter<ResolvedType, ResolvedType>() {
+ @Override
+ public Iterator<ResolvedType> get(ResolvedType o) {
+ return dupFilter.filter(o.getDirectSupertypes());
+ }
+ };
+ return Iterators.mapOver(Iterators.recur(this, typeGetter), FieldGetterInstance);
+ }
+
+ /**
+ * returns an iterator through all of the methods of this type, in order for checking from JVM spec 2ed 5.4.3.3. This means that
+ * the order is
+ * <p/>
+ * <ul>
+ * <li>methods from current class</li>
+ * <li>recur into superclass, all the way up, not touching interfaces</li>
+ * <li>recur into all superinterfaces, in some unspecified order (but those 'closest' to this type are first)</li>
+ * </ul>
+ * <p/>
+ *
+ * @param wantGenerics is true if the caller would like all generics information, otherwise those methods are collapsed to their
+ * erasure
+ */
+ public Iterator<ResolvedMember> getMethods(boolean wantGenerics, boolean wantDeclaredParents) {
+ return Iterators.mapOver(getHierarchy(wantGenerics, wantDeclaredParents), MethodGetterInstance);
+ }
+
+ public Iterator<ResolvedMember> getMethodsIncludingIntertypeDeclarations(boolean wantGenerics, boolean wantDeclaredParents) {
+ return Iterators.mapOver(getHierarchy(wantGenerics, wantDeclaredParents), MethodGetterWithItdsInstance);
+ }
+
+ /**
+ * An Iterators.Getter that returns an iterator over all methods declared on some resolved type.
+ */
+ private static class MethodGetter implements Iterators.Getter<ResolvedType, ResolvedMember> {
+ @Override
+ public Iterator<ResolvedMember> get(ResolvedType type) {
+ return Iterators.array(type.getDeclaredMethods());
+ }
+ }
+
+ /**
+ * An Iterators.Getter that returns an iterator over all pointcuts declared on some resolved type.
+ */
+ private static class PointcutGetter implements Iterators.Getter<ResolvedType, ResolvedMember> {
+ @Override
+ public Iterator<ResolvedMember> get(ResolvedType o) {
+ return Iterators.array(o.getDeclaredPointcuts());
+ }
+ }
+
+ // OPTIMIZE could cache the result of discovering ITDs
+
+ // Getter that returns all declared methods for a type through an iterator - including intertype declarations
+ private static class MethodGetterIncludingItds implements Iterators.Getter<ResolvedType, ResolvedMember> {
+ @Override
+ public Iterator<ResolvedMember> get(ResolvedType type) {
+ ResolvedMember[] methods = type.getDeclaredMethods();
+ if (type.interTypeMungers != null) {
+ int additional = 0;
+ for (ConcreteTypeMunger typeTransformer : type.interTypeMungers) {
+ ResolvedMember rm = typeTransformer.getSignature();
+ // BUG won't this include fields? When we are looking for methods
+ if (rm != null) { // new parent type munger can have null signature
+ additional++;
+ }
+ }
+ if (additional > 0) {
+ ResolvedMember[] methods2 = new ResolvedMember[methods.length + additional];
+ System.arraycopy(methods, 0, methods2, 0, methods.length);
+ additional = methods.length;
+ for (ConcreteTypeMunger typeTransformer : type.interTypeMungers) {
+ ResolvedMember rm = typeTransformer.getSignature();
+ if (rm != null) { // new parent type munger can have null signature
+ methods2[additional++] = typeTransformer.getSignature();
+ }
+ }
+ methods = methods2;
+ }
+ }
+ return Iterators.array(methods);
+ }
+ }
+
+ /**
+ * An Iterators.Getter that returns an iterator over all fields declared on some resolved type.
+ */
+ private static class FieldGetter implements Iterators.Getter<ResolvedType, ResolvedMember> {
+ @Override
+ public Iterator<ResolvedMember> get(ResolvedType type) {
+ return Iterators.array(type.getDeclaredFields());
+ }
+ }
+
+ private final static MethodGetter MethodGetterInstance = new MethodGetter();
+ private final static MethodGetterIncludingItds MethodGetterWithItdsInstance = new MethodGetterIncludingItds();
+ private final static PointcutGetter PointcutGetterInstance = new PointcutGetter();
+ private final static FieldGetter FieldGetterInstance = new FieldGetter();
+
+ /**
+ * Return an iterator over the types in this types hierarchy - starting with this type first, then all superclasses up to Object
+ * and then all interfaces (starting with those 'nearest' this type).
+ *
+ * @param wantGenerics true if the caller wants full generic information
+ * @param wantDeclaredParents true if the caller even wants those parents introduced via declare parents
+ * @return an iterator over all types in the hierarchy of this type
+ */
+ public Iterator<ResolvedType> getHierarchy() {
+ return getHierarchy(false, false);
+ }
+
+ public Iterator<ResolvedType> getHierarchy(final boolean wantGenerics, final boolean wantDeclaredParents) {
+
+ final Iterators.Getter<ResolvedType, ResolvedType> interfaceGetter = new Iterators.Getter<ResolvedType, ResolvedType>() {
+ List<String> alreadySeen = new ArrayList<String>(); // Strings are signatures (ResolvedType.getSignature())
+
+ @Override
+ public Iterator<ResolvedType> get(ResolvedType type) {
+ ResolvedType[] interfaces = type.getDeclaredInterfaces();
+
+ // remove interfaces introduced by declare parents
+ // relatively expensive but hopefully uncommon
+ if (!wantDeclaredParents && type.hasNewParentMungers()) {
+ // Throw away interfaces from that array if they were decp'd onto here
+ List<Integer> forRemoval = new ArrayList<Integer>();
+ for (ConcreteTypeMunger munger : type.interTypeMungers) {
+ if (munger.getMunger() != null) {
+ ResolvedTypeMunger m = munger.getMunger();
+ if (m.getKind() == ResolvedTypeMunger.Parent) {
+ ResolvedType newType = ((NewParentTypeMunger) m).getNewParent();
+ if (!wantGenerics && newType.isParameterizedOrGenericType()) {
+ newType = newType.getRawType();
+ }
+ for (int ii = 0; ii < interfaces.length; ii++) {
+ ResolvedType iface = interfaces[ii];
+ if (!wantGenerics && iface.isParameterizedOrGenericType()) {
+ iface = iface.getRawType();
+ }
+ if (newType.getSignature().equals(iface.getSignature())) { // pr171953
+ forRemoval.add(ii);
+ }
+ }
+ }
+ }
+ }
+ // Found some to remove from those we are going to iterate over
+ if (forRemoval.size() > 0) {
+ ResolvedType[] interfaces2 = new ResolvedType[interfaces.length - forRemoval.size()];
+ int p = 0;
+ for (int ii = 0; ii < interfaces.length; ii++) {
+ if (!forRemoval.contains(ii)) {
+ interfaces2[p++] = interfaces[ii];
+ }
+ }
+ interfaces = interfaces2;
+ }
+ }
+ return new Iterators.ResolvedTypeArrayIterator(interfaces, alreadySeen, wantGenerics);
+ }
+ };
+
+ // If this type is an interface, there are only interfaces to walk
+ if (this.isInterface()) {
+ return new SuperInterfaceWalker(interfaceGetter, this);
+ } else {
+ SuperInterfaceWalker superInterfaceWalker = new SuperInterfaceWalker(interfaceGetter);
+ Iterator<ResolvedType> superClassesIterator = new SuperClassWalker(this, superInterfaceWalker, wantGenerics);
+ // append() will check if the second iterator is empty before appending - but the types which the superInterfaceWalker
+ // needs to visit are only accumulated whilst the superClassesIterator is in progress
+ return Iterators.append1(superClassesIterator, superInterfaceWalker);
+ }
+ }
+
+ /**
+ * Return a list of methods, first those declared on this class, then those declared on the superclass (recurse) and then those
+ * declared on the superinterfaces. This is expensive - use the getMethods() method if you can!
+ */
+ public List<ResolvedMember> getMethodsWithoutIterator(boolean includeITDs, boolean allowMissing, boolean genericsAware) {
+ List<ResolvedMember> methods = new ArrayList<ResolvedMember>();
+ Set<String> knowninterfaces = new HashSet<String>();
+ addAndRecurse(knowninterfaces, methods, this, includeITDs, allowMissing, genericsAware);
+ return methods;
+ }
+
+ /**
+ * Return a list of the types in the hierarchy of this type, starting with this type. The order in the list is the superclasses
+ * followed by the super interfaces.
+ *
+ * @param genericsAware should the list include parameterized/generic types (if not, they will be collapsed to raw)?
+ * @return list of resolvedtypes in this types hierarchy, including this type first
+ */
+ public List<ResolvedType> getHierarchyWithoutIterator(boolean includeITDs, boolean allowMissing, boolean genericsAware) {
+ List<ResolvedType> types = new ArrayList<ResolvedType>();
+ Set<String> visited = new HashSet<String>();
+ recurseHierarchy(visited, types, this, includeITDs, allowMissing, genericsAware);
+ return types;
+ }
+
+ private void addAndRecurse(Set<String> knowninterfaces, List<ResolvedMember> collector, ResolvedType resolvedType,
+ boolean includeITDs, boolean allowMissing, boolean genericsAware) {
+ // Add the methods declared on this type
+ collector.addAll(Arrays.asList(resolvedType.getDeclaredMethods()));
+ // now add all the inter-typed members too
+ if (includeITDs && resolvedType.interTypeMungers != null) {
+ for (ConcreteTypeMunger typeTransformer : interTypeMungers) {
+ ResolvedMember rm = typeTransformer.getSignature();
+ if (rm != null) { // new parent type munger can have null signature
+ collector.add(typeTransformer.getSignature());
+ }
+ }
+ }
+ // BUG? interface type superclass is Object - is that correct?
+ if (!resolvedType.isInterface() && !resolvedType.equals(ResolvedType.OBJECT)) {
+ ResolvedType superType = resolvedType.getSuperclass();
+ if (superType != null && !superType.isMissing()) {
+ if (!genericsAware && superType.isParameterizedOrGenericType()) {
+ superType = superType.getRawType();
+ }
+ // Recurse if we are not at the top
+ addAndRecurse(knowninterfaces, collector, superType, includeITDs, allowMissing, genericsAware);
+ }
+ }
+ // Go through the interfaces on the way back down
+ ResolvedType[] interfaces = resolvedType.getDeclaredInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ ResolvedType iface = interfaces[i];
+ if (!genericsAware && iface.isParameterizedOrGenericType()) {
+ iface = iface.getRawType();
+ }
+ // we need to know if it is an interface from Parent kind munger
+ // as those are used for @AJ ITD and we precisely want to skip those
+ boolean shouldSkip = false;
+ for (int j = 0; j < resolvedType.interTypeMungers.size(); j++) {
+ ConcreteTypeMunger munger = resolvedType.interTypeMungers.get(j);
+ if (munger.getMunger() != null && munger.getMunger().getKind() == ResolvedTypeMunger.Parent
+ && ((NewParentTypeMunger) munger.getMunger()).getNewParent().equals(iface) // pr171953
+ ) {
+ shouldSkip = true;
+ break;
+ }
+ }
+
+ // Do not do interfaces more than once
+ if (!shouldSkip && !knowninterfaces.contains(iface.getSignature())) {
+ knowninterfaces.add(iface.getSignature());
+ if (allowMissing && iface.isMissing()) {
+ if (iface instanceof MissingResolvedTypeWithKnownSignature) {
+ ((MissingResolvedTypeWithKnownSignature) iface).raiseWarningOnMissingInterfaceWhilstFindingMethods();
+ }
+ } else {
+ addAndRecurse(knowninterfaces, collector, iface, includeITDs, allowMissing, genericsAware);
+ }
+ }
+ }
+ }
+
+ /**
+ * Recurse up a type hierarchy, first the superclasses then the super interfaces.
+ */
+ private void recurseHierarchy(Set<String> knowninterfaces, List<ResolvedType> collector, ResolvedType resolvedType,
+ boolean includeITDs, boolean allowMissing, boolean genericsAware) {
+ collector.add(resolvedType);
+ if (!resolvedType.isInterface() && !resolvedType.equals(ResolvedType.OBJECT)) {
+ ResolvedType superType = resolvedType.getSuperclass();
+ if (superType != null && !superType.isMissing()) {
+ if (!genericsAware && (superType.isParameterizedType() || superType.isGenericType())) {
+ superType = superType.getRawType();
+ }
+ // Recurse if we are not at the top
+ recurseHierarchy(knowninterfaces, collector, superType, includeITDs, allowMissing, genericsAware);
+ }
+ }
+ // Go through the interfaces on the way back down
+ ResolvedType[] interfaces = resolvedType.getDeclaredInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ ResolvedType iface = interfaces[i];
+ if (!genericsAware && (iface.isParameterizedType() || iface.isGenericType())) {
+ iface = iface.getRawType();
+ }
+ // we need to know if it is an interface from Parent kind munger
+ // as those are used for @AJ ITD and we precisely want to skip those
+ boolean shouldSkip = false;
+ for (int j = 0; j < resolvedType.interTypeMungers.size(); j++) {
+ ConcreteTypeMunger munger = resolvedType.interTypeMungers.get(j);
+ if (munger.getMunger() != null && munger.getMunger().getKind() == ResolvedTypeMunger.Parent
+ && ((NewParentTypeMunger) munger.getMunger()).getNewParent().equals(iface) // pr171953
+ ) {
+ shouldSkip = true;
+ break;
+ }
+ }
+
+ // Do not do interfaces more than once
+ if (!shouldSkip && !knowninterfaces.contains(iface.getSignature())) {
+ knowninterfaces.add(iface.getSignature());
+ if (allowMissing && iface.isMissing()) {
+ if (iface instanceof MissingResolvedTypeWithKnownSignature) {
+ ((MissingResolvedTypeWithKnownSignature) iface).raiseWarningOnMissingInterfaceWhilstFindingMethods();
+ }
+ } else {
+ recurseHierarchy(knowninterfaces, collector, iface, includeITDs, allowMissing, genericsAware);
+ }
+ }
+ }
+ }
+
+ public ResolvedType[] getResolvedTypeParameters() {
+ if (resolvedTypeParams == null) {
+ resolvedTypeParams = world.resolve(typeParameters);
+ }
+ return resolvedTypeParams;
+ }
+
+ /**
+ * described in JVM spec 2ed 5.4.3.2
+ */
+ public ResolvedMember lookupField(Member field) {
+ Iterator<ResolvedMember> i = getFields();
+ while (i.hasNext()) {
+ ResolvedMember resolvedMember = i.next();
+ if (matches(resolvedMember, field)) {
+ return resolvedMember;
+ }
+ if (resolvedMember.hasBackingGenericMember() && field.getName().equals(resolvedMember.getName())) {
+ // might be worth checking the member behind the parameterized member (see pr137496)
+ if (matches(resolvedMember.getBackingGenericMember(), field)) {
+ return resolvedMember;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * described in JVM spec 2ed 5.4.3.3. Doesnt check ITDs.
+ *
+ * <p>
+ * Check the current type for the method. If it is not found, check the super class and any super interfaces. Taking care not to
+ * process interfaces multiple times.
+ */
+ public ResolvedMember lookupMethod(Member m) {
+ List<ResolvedType> typesTolookat = new ArrayList<ResolvedType>();
+ typesTolookat.add(this);
+ int pos = 0;
+ while (pos < typesTolookat.size()) {
+ ResolvedType type = typesTolookat.get(pos++);
+ if (!type.isMissing()) {
+ ResolvedMember[] methods = type.getDeclaredMethods();
+ if (methods != null) {
+ for (int i = 0; i < methods.length; i++) {
+ ResolvedMember method = methods[i];
+ if (matches(method, m)) {
+ return method;
+ }
+ // might be worth checking the method behind the parameterized method (137496)
+ if (method.hasBackingGenericMember() && m.getName().equals(method.getName())) {
+ if (matches(method.getBackingGenericMember(), m)) {
+ return method;
+ }
+ }
+ }
+ }
+ }
+ // Queue the superclass:
+ ResolvedType superclass = type.getSuperclass();
+ if (superclass != null) {
+ typesTolookat.add(superclass);
+ }
+ // Queue any interfaces not already checked:
+ ResolvedType[] superinterfaces = type.getDeclaredInterfaces();
+ if (superinterfaces != null) {
+ for (int i = 0; i < superinterfaces.length; i++) {
+ ResolvedType interf = superinterfaces[i];
+ if (!typesTolookat.contains(interf)) {
+ typesTolookat.add(interf);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param member the member to lookup in intertype declarations affecting this type
+ * @return the real signature defined by any matching intertype declaration, otherwise null
+ */
+ public ResolvedMember lookupMethodInITDs(Member member) {
+ for (ConcreteTypeMunger typeTransformer : interTypeMungers) {
+ if (matches(typeTransformer.getSignature(), member)) {
+ return typeTransformer.getSignature();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * return null if not found
+ */
+ private ResolvedMember lookupMember(Member m, ResolvedMember[] a) {
+ for (int i = 0; i < a.length; i++) {
+ ResolvedMember f = a[i];
+ if (matches(f, m)) {
+ return f;
+ }
+ }
+ return null;
+ }
+
+ // Bug (1) Do callers expect ITDs to be involved in the lookup? or do they do their own walk over ITDs?
+ /**
+ * Looks for the first member in the hierarchy matching aMember. This method differs from lookupMember(Member) in that it takes
+ * into account parameters which are type variables - which clearly an unresolved Member cannot do since it does not know
+ * anything about type variables.
+ */
+ public ResolvedMember lookupResolvedMember(ResolvedMember aMember, boolean allowMissing, boolean eraseGenerics) {
+ Iterator<ResolvedMember> toSearch = null;
+ ResolvedMember found = null;
+ if ((aMember.getKind() == Member.METHOD) || (aMember.getKind() == Member.CONSTRUCTOR)) {
+ // toSearch = getMethodsWithoutIterator(true, allowMissing, !eraseGenerics).iterator();
+ toSearch = getMethodsIncludingIntertypeDeclarations(!eraseGenerics, true);
+ } else if (aMember.getKind()==Member.ADVICE) {
+ return null;
+ } else {
+ assert aMember.getKind() == Member.FIELD;
+ toSearch = getFields();
+ }
+ while (toSearch.hasNext()) {
+ ResolvedMember candidate = toSearch.next();
+ if (eraseGenerics) {
+ if (candidate.hasBackingGenericMember()) {
+ candidate = candidate.getBackingGenericMember();
+ }
+ }
+ // OPTIMIZE speed up matches? optimize order of checks
+ if (candidate.matches(aMember, eraseGenerics)) {
+ found = candidate;
+ break;
+ }
+ }
+
+ return found;
+ }
+
+ public static boolean matches(Member m1, Member m2) {
+ if (m1 == null) {
+ return m2 == null;
+ }
+ if (m2 == null) {
+ return false;
+ }
+
+ // Check the names
+ boolean equalNames = m1.getName().equals(m2.getName());
+ if (!equalNames) {
+ return false;
+ }
+
+ // Check the signatures
+ boolean equalSignatures = m1.getSignature().equals(m2.getSignature());
+ if (equalSignatures) {
+ return true;
+ }
+
+ // If they aren't the same, we need to allow for covariance ... where
+ // one sig might be ()LCar; and
+ // the subsig might be ()LFastCar; - where FastCar is a subclass of Car
+ boolean equalCovariantSignatures = m1.getParameterSignature().equals(m2.getParameterSignature());
+ if (equalCovariantSignatures) {
+ return true;
+ }
+
+ return false;
+ }
+ public static boolean conflictingSignature(Member m1, Member m2) {
+ return conflictingSignature(m1,m2,true);
+ }
+
+ /**
+ * Do the two members conflict? Due to the change in 1.7.1, field itds on interfaces now act like 'default' fields - so types implementing
+ * those fields get the field if they don't have it already, otherwise they keep what they have. The conflict detection below had to be
+ * altered. Previously (<1.7.1) it is not a conflict if the declaring types are different. With v2itds it may still be a conflict if the
+ * declaring types are different.
+ */
+ public static boolean conflictingSignature(Member m1, Member m2, boolean v2itds) {
+ if (m1 == null || m2 == null) {
+ return false;
+ }
+ if (!m1.getName().equals(m2.getName())) {
+ return false;
+ }
+ if (m1.getKind() != m2.getKind()) {
+ return false;
+ }
+ if (m1.getKind() == Member.FIELD) {
+ if (v2itds) {
+ if (m1.getDeclaringType().equals(m2.getDeclaringType())) {
+ return true;
+ }
+ } else {
+ return m1.getDeclaringType().equals(m2.getDeclaringType());
+ }
+ } else if (m1.getKind() == Member.POINTCUT) {
+ return true;
+ }
+
+ UnresolvedType[] p1 = m1.getGenericParameterTypes();
+ UnresolvedType[] p2 = m2.getGenericParameterTypes();
+ if (p1 == null) {
+ p1 = m1.getParameterTypes();
+ }
+ if (p2 == null) {
+ p2 = m2.getParameterTypes();
+ }
+ int n = p1.length;
+ if (n != p2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < n; i++) {
+ if (!p1[i].equals(p2[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * returns an iterator through all of the pointcuts of this type, in order for checking from JVM spec 2ed 5.4.3.2 (as for
+ * fields). This means that the order is
+ * <p/>
+ * <ul>
+ * <li>pointcuts from current class</li>
+ * <li>recur into direct superinterfaces</li>
+ * <li>recur into superclass</li>
+ * </ul>
+ * <p/>
+ * We keep a hashSet of interfaces that we've visited so we don't spiral out into 2^n land.
+ */
+ public Iterator<ResolvedMember> getPointcuts() {
+ final Iterators.Filter<ResolvedType> dupFilter = Iterators.dupFilter();
+ // same order as fields
+ Iterators.Getter<ResolvedType, ResolvedType> typeGetter = new Iterators.Getter<ResolvedType, ResolvedType>() {
+ @Override
+ public Iterator<ResolvedType> get(ResolvedType o) {
+ return dupFilter.filter(o.getDirectSupertypes());
+ }
+ };
+ return Iterators.mapOver(Iterators.recur(this, typeGetter), PointcutGetterInstance);
+ }
+
+ public ResolvedPointcutDefinition findPointcut(String name) {
+ for (Iterator<ResolvedMember> i = getPointcuts(); i.hasNext();) {
+ ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next();
+ // the ResolvedPointcutDefinition can be null if there are other problems that prevented its resolution
+ if (f != null && name.equals(f.getName())) {
+ return f;
+ }
+ }
+ // pr120521
+ if (!getOutermostType().equals(this)) {
+ ResolvedType outerType = getOutermostType().resolve(world);
+ ResolvedPointcutDefinition rpd = outerType.findPointcut(name);
+ return rpd;
+ }
+ return null; // should we throw an exception here?
+ }
+
+ // all about collecting CrosscuttingMembers
+
+ // ??? collecting data-structure, shouldn't really be a field
+ public CrosscuttingMembers crosscuttingMembers;
+
+ public CrosscuttingMembers collectCrosscuttingMembers(boolean shouldConcretizeIfNeeded) {
+ crosscuttingMembers = new CrosscuttingMembers(this, shouldConcretizeIfNeeded);
+ if (getPerClause() == null) {
+ return crosscuttingMembers;
+ }
+ crosscuttingMembers.setPerClause(getPerClause());
+ crosscuttingMembers.addShadowMungers(collectShadowMungers());
+ // GENERICITDFIX
+ // crosscuttingMembers.addTypeMungers(collectTypeMungers());
+ crosscuttingMembers.addTypeMungers(getTypeMungers());
+ // FIXME AV - skip but needed ?? or ??
+ // crosscuttingMembers.addLateTypeMungers(getLateTypeMungers());
+ crosscuttingMembers.addDeclares(collectDeclares(!this.doesNotExposeShadowMungers()));
+ crosscuttingMembers.addPrivilegedAccesses(getPrivilegedAccesses());
+
+ // System.err.println("collected cc members: " + this + ", " +
+ // collectDeclares());
+ return crosscuttingMembers;
+ }
+
+ public final List<Declare> collectDeclares(boolean includeAdviceLike) {
+ if (!this.isAspect()) {
+ return Collections.emptyList();
+ }
+
+ List<Declare> ret = new ArrayList<Declare>();
+ // if (this.isAbstract()) {
+ // for (Iterator i = getDeclares().iterator(); i.hasNext();) {
+ // Declare dec = (Declare) i.next();
+ // if (!dec.isAdviceLike()) ret.add(dec);
+ // }
+ //
+ // if (!includeAdviceLike) return ret;
+
+ if (!this.isAbstract()) {
+ // ret.addAll(getDeclares());
+ final Iterators.Filter<ResolvedType> dupFilter = Iterators.dupFilter();
+ Iterators.Getter<ResolvedType, ResolvedType> typeGetter = new Iterators.Getter<ResolvedType, ResolvedType>() {
+ @Override
+ public Iterator<ResolvedType> get(ResolvedType o) {
+ return dupFilter.filter((o).getDirectSupertypes());
+ }
+ };
+ Iterator<ResolvedType> typeIterator = Iterators.recur(this, typeGetter);
+
+ while (typeIterator.hasNext()) {
+ ResolvedType ty = typeIterator.next();
+ // System.out.println("super: " + ty + ", " + );
+ for (Iterator<Declare> i = ty.getDeclares().iterator(); i.hasNext();) {
+ Declare dec = i.next();
+ if (dec.isAdviceLike()) {
+ if (includeAdviceLike) {
+ ret.add(dec);
+ }
+ } else {
+ ret.add(dec);
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private final List<ShadowMunger> collectShadowMungers() {
+ if (!this.isAspect() || this.isAbstract() || this.doesNotExposeShadowMungers()) {
+ return Collections.emptyList();
+ }
+
+ List<ShadowMunger> acc = new ArrayList<ShadowMunger>();
+ final Iterators.Filter<ResolvedType> dupFilter = Iterators.dupFilter();
+ Iterators.Getter<ResolvedType, ResolvedType> typeGetter = new Iterators.Getter<ResolvedType, ResolvedType>() {
+ @Override
+ public Iterator<ResolvedType> get(ResolvedType o) {
+ return dupFilter.filter((o).getDirectSupertypes());
+ }
+ };
+ Iterator<ResolvedType> typeIterator = Iterators.recur(this, typeGetter);
+
+ while (typeIterator.hasNext()) {
+ ResolvedType ty = typeIterator.next();
+ acc.addAll(ty.getDeclaredShadowMungers());
+ }
+
+ return acc;
+ }
+
+ public void addParent(ResolvedType newParent) {
+ // Nothing to do for anything except a ReferenceType
+ }
+
+ protected boolean doesNotExposeShadowMungers() {
+ return false;
+ }
+
+ public PerClause getPerClause() {
+ return null;
+ }
+
+ public Collection<Declare> getDeclares() {
+ return Collections.emptyList();
+ }
+
+ public Collection<ConcreteTypeMunger> getTypeMungers() {
+ return Collections.emptyList();
+ }
+
+ public Collection<ResolvedMember> getPrivilegedAccesses() {
+ return Collections.emptyList();
+ }
+
+ // ---- useful things
+
+ public final boolean isInterface() {
+ return Modifier.isInterface(getModifiers());
+ }
+
+ public final boolean isAbstract() {
+ return Modifier.isAbstract(getModifiers());
+ }
+
+ public boolean isClass() {
+ return false;
+ }
+
+ public boolean isAspect() {
+ return false;
+ }
+
+ public boolean isAnnotationStyleAspect() {
+ return false;
+ }
+
+ /**
+ * Note: Only overridden by Name subtype.
+ */
+ public boolean isEnum() {
+ return false;
+ }
+
+ /**
+ * Note: Only overridden by Name subtype.
+ */
+ public boolean isAnnotation() {
+ return false;
+ }
+
+ public boolean isAnonymous() {
+ return false;
+ }
+
+ public boolean isNested() {
+ return false;
+ }
+
+ public ResolvedType getOuterClass() {
+ return null;
+ }
+
+ public void addAnnotation(AnnotationAJ annotationX) {
+ throw new RuntimeException("ResolvedType.addAnnotation() should never be called");
+ }
+
+ public AnnotationAJ[] getAnnotations() {
+ throw new RuntimeException("ResolvedType.getAnnotations() should never be called");
+ }
+
+ public boolean hasAnnotations() {
+ throw new RuntimeException("ResolvedType.getAnnotations() should never be called");
+ }
+
+
+ /**
+ * Note: Only overridden by ReferenceType subtype
+ */
+ public boolean canAnnotationTargetType() {
+ return false;
+ }
+
+ /**
+ * Note: Only overridden by ReferenceType subtype
+ */
+ public AnnotationTargetKind[] getAnnotationTargetKinds() {
+ return null;
+ }
+
+ /**
+ * Note: Only overridden by Name subtype.
+ */
+ public boolean isAnnotationWithRuntimeRetention() {
+ return false;
+ }
+
+ public boolean isSynthetic() {
+ return signature.indexOf("$ajc") != -1;
+ }
+
+ public final boolean isFinal() {
+ return Modifier.isFinal(getModifiers());
+ }
+
+ protected Map<String, UnresolvedType> getMemberParameterizationMap() {
+ if (!isParameterizedType()) {
+ return Collections.emptyMap();
+ }
+ TypeVariable[] tvs = getGenericType().getTypeVariables();
+ Map<String, UnresolvedType> parameterizationMap = new HashMap<String, UnresolvedType>();
+ if (tvs.length != typeParameters.length) {
+ world.getMessageHandler()
+ .handleMessage(
+ new Message("Mismatch when building parameterization map. For type '" + this.signature +
+ "' expecting "+tvs.length+":["+toString(tvs)+"] type parameters but found "+typeParameters.length+
+ ":["+toString(typeParameters)+"]", "",
+ IMessage.ERROR, getSourceLocation(), null,
+ new ISourceLocation[] { getSourceLocation() }));
+ } else {
+ for (int i = 0; i < tvs.length; i++) {
+ parameterizationMap.put(tvs[i].getName(), typeParameters[i]);
+ }
+ }
+ return parameterizationMap;
+ }
+
+ private String toString(UnresolvedType[] typeParameters) {
+ StringBuilder s = new StringBuilder();
+ for (UnresolvedType tv: typeParameters) {
+ s.append(tv.getSignature()).append(" ");
+ }
+ return s.toString().trim();
+ }
+
+ private String toString(TypeVariable[] tvs) {
+ StringBuilder s = new StringBuilder();
+ for (TypeVariable tv: tvs) {
+ s.append(tv.getName()).append(" ");
+ }
+ return s.toString().trim();
+ }
+
+ public List<ShadowMunger> getDeclaredAdvice() {
+ List<ShadowMunger> l = new ArrayList<ShadowMunger>();
+ ResolvedMember[] methods = getDeclaredMethods();
+ if (isParameterizedType()) {
+ methods = getGenericType().getDeclaredMethods();
+ }
+ Map<String, UnresolvedType> typeVariableMap = getAjMemberParameterizationMap();
+ for (int i = 0, len = methods.length; i < len; i++) {
+ ShadowMunger munger = methods[i].getAssociatedShadowMunger();
+ if (munger != null) {
+ if (ajMembersNeedParameterization()) {
+ // munger.setPointcut(munger.getPointcut().parameterizeWith(
+ // typeVariableMap));
+ munger = munger.parameterizeWith(this, typeVariableMap);
+ if (munger instanceof Advice) {
+ Advice advice = (Advice) munger;
+ // update to use the parameterized signature...
+ UnresolvedType[] ptypes = methods[i].getGenericParameterTypes();
+ UnresolvedType[] newPTypes = new UnresolvedType[ptypes.length];
+ for (int j = 0; j < ptypes.length; j++) {
+ if (ptypes[j] instanceof TypeVariableReferenceType) {
+ TypeVariableReferenceType tvrt = (TypeVariableReferenceType) ptypes[j];
+ if (typeVariableMap.containsKey(tvrt.getTypeVariable().getName())) {
+ newPTypes[j] = typeVariableMap.get(tvrt.getTypeVariable().getName());
+ } else {
+ newPTypes[j] = ptypes[j];
+ }
+ } else {
+ newPTypes[j] = ptypes[j];
+ }
+ }
+ advice.setBindingParameterTypes(newPTypes);
+ }
+ }
+ munger.setDeclaringType(this);
+ l.add(munger);
+ }
+ }
+ return l;
+ }
+
+ public List<ShadowMunger> getDeclaredShadowMungers() {
+ return getDeclaredAdvice();
+ }
+
+ // ---- only for testing!
+
+ public ResolvedMember[] getDeclaredJavaFields() {
+ return filterInJavaVisible(getDeclaredFields());
+ }
+
+ public ResolvedMember[] getDeclaredJavaMethods() {
+ return filterInJavaVisible(getDeclaredMethods());
+ }
+
+ private ResolvedMember[] filterInJavaVisible(ResolvedMember[] ms) {
+ List<ResolvedMember> l = new ArrayList<ResolvedMember>();
+ for (int i = 0, len = ms.length; i < len; i++) {
+ if (!ms[i].isAjSynthetic() && ms[i].getAssociatedShadowMunger() == null) {
+ l.add(ms[i]);
+ }
+ }
+ return l.toArray(new ResolvedMember[l.size()]);
+ }
+
+ public abstract ISourceContext getSourceContext();
+
+ // ---- fields
+
+ public static final ResolvedType[] NONE = new ResolvedType[0];
+ public static final ResolvedType[] EMPTY_ARRAY = NONE;
+
+ public static final Missing MISSING = new Missing();
+
+ // ---- types
+ public static ResolvedType makeArray(ResolvedType type, int dim) {
+ if (dim == 0) {
+ return type;
+ }
+ ResolvedType array = new ArrayReferenceType("[" + type.getSignature(), "[" + type.getErasureSignature(), type.getWorld(),
+ type);
+ return makeArray(array, dim - 1);
+ }
+
+ static class Primitive extends ResolvedType {
+ private final int size;
+ private final int index;
+
+ Primitive(String signature, int size, int index) {
+ super(signature, null);
+ this.size = size;
+ this.index = index;
+ this.typeKind = TypeKind.PRIMITIVE;
+ }
+
+ @Override
+ public final int getSize() {
+ return size;
+ }
+
+ @Override
+ public final int getModifiers() {
+ return Modifier.PUBLIC | Modifier.FINAL;
+ }
+
+ @Override
+ public final boolean isPrimitiveType() {
+ return true;
+ }
+
+ @Override
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ return false;
+ }
+
+ @Override
+ public final boolean isAssignableFrom(ResolvedType other) {
+ if (!other.isPrimitiveType()) {
+ if (!world.isInJava5Mode()) {
+ return false;
+ }
+ return validBoxing.contains(this.getSignature() + other.getSignature());
+ }
+ return assignTable[((Primitive) other).index][index];
+ }
+
+ @Override
+ public final boolean isAssignableFrom(ResolvedType other, boolean allowMissing) {
+ return isAssignableFrom(other);
+ }
+
+ @Override
+ public final boolean isCoerceableFrom(ResolvedType other) {
+ if (this == other) {
+ return true;
+ }
+ if (!other.isPrimitiveType()) {
+ return false;
+ }
+ if (index > 6 || ((Primitive) other).index > 6) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public ResolvedType resolve(World world) {
+ if (this.world != world) {
+ throw new IllegalStateException();
+ }
+ this.world = world;
+ return super.resolve(world);
+ }
+
+ @Override
+ public final boolean needsNoConversionFrom(ResolvedType other) {
+ if (!other.isPrimitiveType()) {
+ return false;
+ }
+ return noConvertTable[((Primitive) other).index][index];
+ }
+
+ private static final boolean[][] assignTable = {// to: B C D F I J S V Z
+ // from
+ { true, true, true, true, true, true, true, false, false }, // B
+ { false, true, true, true, true, true, false, false, false }, // C
+ { false, false, true, false, false, false, false, false, false }, // D
+ { false, false, true, true, false, false, false, false, false }, // F
+ { false, false, true, true, true, true, false, false, false }, // I
+ { false, false, true, true, false, true, false, false, false }, // J
+ { false, false, true, true, true, true, true, false, false }, // S
+ { false, false, false, false, false, false, false, true, false }, // V
+ { false, false, false, false, false, false, false, false, true }, // Z
+ };
+ private static final boolean[][] noConvertTable = {// to: B C D F I J S
+ // V Z from
+ { true, true, false, false, true, false, true, false, false }, // B
+ { false, true, false, false, true, false, false, false, false }, // C
+ { false, false, true, false, false, false, false, false, false }, // D
+ { false, false, false, true, false, false, false, false, false }, // F
+ { false, false, false, false, true, false, false, false, false }, // I
+ { false, false, false, false, false, true, false, false, false }, // J
+ { false, false, false, false, true, false, true, false, false }, // S
+ { false, false, false, false, false, false, false, true, false }, // V
+ { false, false, false, false, false, false, false, false, true }, // Z
+ };
+
+ // ----
+
+ @Override
+ public final ResolvedMember[] getDeclaredFields() {
+ return ResolvedMember.NONE;
+ }
+
+ @Override
+ public final ResolvedMember[] getDeclaredMethods() {
+ return ResolvedMember.NONE;
+ }
+
+ @Override
+ public final ResolvedType[] getDeclaredInterfaces() {
+ return ResolvedType.NONE;
+ }
+
+ @Override
+ public final ResolvedMember[] getDeclaredPointcuts() {
+ return ResolvedMember.NONE;
+ }
+
+ @Override
+ public final ResolvedType getSuperclass() {
+ return null;
+ }
+
+ @Override
+ public ISourceContext getSourceContext() {
+ return null;
+ }
+
+ }
+
+ static class Missing extends ResolvedType {
+ Missing() {
+ super(MISSING_NAME, null);
+ }
+
+ // public final String toString() {
+ // return "<missing>";
+ // }
+ @Override
+ public final String getName() {
+ return MISSING_NAME;
+ }
+
+ @Override
+ public final boolean isMissing() {
+ return true;
+ }
+
+ @Override
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ return false;
+ }
+
+ @Override
+ public final ResolvedMember[] getDeclaredFields() {
+ return ResolvedMember.NONE;
+ }
+
+ @Override
+ public final ResolvedMember[] getDeclaredMethods() {
+ return ResolvedMember.NONE;
+ }
+
+ @Override
+ public final ResolvedType[] getDeclaredInterfaces() {
+ return ResolvedType.NONE;
+ }
+
+ @Override
+ public final ResolvedMember[] getDeclaredPointcuts() {
+ return ResolvedMember.NONE;
+ }
+
+ @Override
+ public final ResolvedType getSuperclass() {
+ return null;
+ }
+
+ @Override
+ public final int getModifiers() {
+ return 0;
+ }
+
+ @Override
+ public final boolean isAssignableFrom(ResolvedType other) {
+ return false;
+ }
+
+ @Override
+ public final boolean isAssignableFrom(ResolvedType other, boolean allowMissing) {
+ return false;
+ }
+
+ @Override
+ public final boolean isCoerceableFrom(ResolvedType other) {
+ return false;
+ }
+
+ @Override
+ public boolean needsNoConversionFrom(ResolvedType other) {
+ return false;
+ }
+
+ @Override
+ public ISourceContext getSourceContext() {
+ return null;
+ }
+
+ }
+
+ /**
+ * Look up a member, takes into account any ITDs on this type. return null if not found
+ */
+ public ResolvedMember lookupMemberNoSupers(Member member) {
+ ResolvedMember ret = lookupDirectlyDeclaredMemberNoSupers(member);
+ if (ret == null && interTypeMungers != null) {
+ for (ConcreteTypeMunger tm : interTypeMungers) {
+ if (matches(tm.getSignature(), member)) {
+ return tm.getSignature();
+ }
+ }
+ }
+ return ret;
+ }
+
+ public ResolvedMember lookupMemberWithSupersAndITDs(Member member) {
+ ResolvedMember ret = lookupMemberNoSupers(member);
+ if (ret != null) {
+ return ret;
+ }
+
+ ResolvedType supert = getSuperclass();
+ while (ret == null && supert != null) {
+ ret = supert.lookupMemberNoSupers(member);
+ if (ret == null) {
+ supert = supert.getSuperclass();
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * as lookupMemberNoSupers, but does not include ITDs
+ *
+ * @param member
+ * @return
+ */
+ public ResolvedMember lookupDirectlyDeclaredMemberNoSupers(Member member) {
+ ResolvedMember ret;
+ if (member.getKind() == Member.FIELD) {
+ ret = lookupMember(member, getDeclaredFields());
+ } else {
+ // assert member.getKind() == Member.METHOD || member.getKind() ==
+ // Member.CONSTRUCTOR
+ ret = lookupMember(member, getDeclaredMethods());
+ }
+ return ret;
+ }
+
+ /**
+ * This lookup has specialized behaviour - a null result tells the EclipseTypeMunger that it should make a default
+ * implementation of a method on this type.
+ *
+ * @param member
+ * @return
+ */
+ public ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member) {
+ return lookupMemberIncludingITDsOnInterfaces(member, this);
+ }
+
+ private ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member, ResolvedType onType) {
+ ResolvedMember ret = onType.lookupMemberNoSupers(member);
+ if (ret != null) {
+ return ret;
+ } else {
+ ResolvedType superType = onType.getSuperclass();
+ if (superType != null) {
+ ret = lookupMemberIncludingITDsOnInterfaces(member, superType);
+ }
+ if (ret == null) {
+ // try interfaces then, but only ITDs now...
+ ResolvedType[] superInterfaces = onType.getDeclaredInterfaces();
+ for (int i = 0; i < superInterfaces.length; i++) {
+ ret = superInterfaces[i].lookupMethodInITDs(member);
+ if (ret != null) {
+ return ret;
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ protected List<ConcreteTypeMunger> interTypeMungers = new ArrayList<ConcreteTypeMunger>();
+
+ public List<ConcreteTypeMunger> getInterTypeMungers() {
+ return interTypeMungers;
+ }
+
+ public List<ConcreteTypeMunger> getInterTypeParentMungers() {
+ List<ConcreteTypeMunger> l = new ArrayList<ConcreteTypeMunger>();
+ for (ConcreteTypeMunger element : interTypeMungers) {
+ if (element.getMunger() instanceof NewParentTypeMunger) {
+ l.add(element);
+ }
+ }
+ return l;
+ }
+
+ /**
+ * ??? This method is O(N*M) where N = number of methods and M is number of inter-type declarations in my super
+ */
+ public List<ConcreteTypeMunger> getInterTypeMungersIncludingSupers() {
+ ArrayList<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
+ collectInterTypeMungers(ret);
+ return ret;
+ }
+
+ public List<ConcreteTypeMunger> getInterTypeParentMungersIncludingSupers() {
+ ArrayList<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
+ collectInterTypeParentMungers(ret);
+ return ret;
+ }
+
+ private void collectInterTypeParentMungers(List<ConcreteTypeMunger> collector) {
+ for (Iterator<ResolvedType> iter = getDirectSupertypes(); iter.hasNext();) {
+ ResolvedType superType = iter.next();
+ superType.collectInterTypeParentMungers(collector);
+ }
+ collector.addAll(getInterTypeParentMungers());
+ }
+
+ protected void collectInterTypeMungers(List<ConcreteTypeMunger> collector) {
+ for (Iterator<ResolvedType> iter = getDirectSupertypes(); iter.hasNext();) {
+ ResolvedType superType = iter.next();
+ if (superType == null) {
+ throw new BCException("UnexpectedProblem: a supertype in the hierarchy for " + this.getName() + " is null");
+ }
+ superType.collectInterTypeMungers(collector);
+ }
+
+ outer: for (Iterator<ConcreteTypeMunger> iter1 = collector.iterator(); iter1.hasNext();) {
+ ConcreteTypeMunger superMunger = iter1.next();
+ if (superMunger.getSignature() == null) {
+ continue;
+ }
+
+ if (!superMunger.getSignature().isAbstract()) {
+ continue;
+ }
+
+ for (ConcreteTypeMunger myMunger : getInterTypeMungers()) {
+ if (conflictingSignature(myMunger.getSignature(), superMunger.getSignature())) {
+ iter1.remove();
+ continue outer;
+ }
+ }
+
+ if (!superMunger.getSignature().isPublic()) {
+ continue;
+ }
+
+ for (Iterator<ResolvedMember> iter = getMethods(true, true); iter.hasNext();) {
+ ResolvedMember method = iter.next();
+ if (conflictingSignature(method, superMunger.getSignature())) {
+ iter1.remove();
+ continue outer;
+ }
+ }
+ }
+
+ collector.addAll(getInterTypeMungers());
+ }
+
+ /**
+ * Check: 1) That we don't have any abstract type mungers unless this type is abstract. 2) That an abstract ITDM on an interface
+ * is declared public. (Compiler limitation) (PR70794)
+ */
+ public void checkInterTypeMungers() {
+ if (isAbstract()) {
+ return;
+ }
+
+ boolean itdProblem = false;
+
+ for (ConcreteTypeMunger munger : getInterTypeMungersIncludingSupers()) {
+ itdProblem = checkAbstractDeclaration(munger) || itdProblem; // Rule 2
+ }
+
+ if (itdProblem) {
+ return; // If the rules above are broken, return right now
+ }
+
+ for (ConcreteTypeMunger munger : getInterTypeMungersIncludingSupers()) {
+ if (munger.getSignature() != null && munger.getSignature().isAbstract() && munger.getMunger().getKind()!=ResolvedTypeMunger.PrivilegedAccess) { // Rule 1
+ if (munger.getMunger().getKind() == ResolvedTypeMunger.MethodDelegate2) {
+ // ignore for @AJ ITD as munger.getSignature() is the
+ // interface method hence abstract
+ } else {
+ world.getMessageHandler()
+ .handleMessage(
+ new Message("must implement abstract inter-type declaration: " + munger.getSignature(), "",
+ IMessage.ERROR, getSourceLocation(), null,
+ new ISourceLocation[] { getMungerLocation(munger) }));
+ }
+ }
+ }
+ }
+
+ /**
+ * See PR70794. This method checks that if an abstract inter-type method declaration is made on an interface then it must also
+ * be public. This is a compiler limitation that could be made to work in the future (if someone provides a worthwhile usecase)
+ *
+ * @return indicates if the munger failed the check
+ */
+ private boolean checkAbstractDeclaration(ConcreteTypeMunger munger) {
+ if (munger.getMunger() != null && (munger.getMunger() instanceof NewMethodTypeMunger)) {
+ ResolvedMember itdMember = munger.getSignature();
+ ResolvedType onType = itdMember.getDeclaringType().resolve(world);
+ if (onType.isInterface() && itdMember.isAbstract() && !itdMember.isPublic()) {
+ world.getMessageHandler().handleMessage(
+ new Message(WeaverMessages.format(WeaverMessages.ITD_ABSTRACT_MUST_BE_PUBLIC_ON_INTERFACE,
+ munger.getSignature(), onType), "", Message.ERROR, getSourceLocation(), null,
+ new ISourceLocation[] { getMungerLocation(munger) }));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get a source location for the munger. Until intertype mungers remember where they came from, the source location for the
+ * munger itself is null. In these cases use the source location for the aspect containing the ITD.
+ */
+ private ISourceLocation getMungerLocation(ConcreteTypeMunger munger) {
+ ISourceLocation sloc = munger.getSourceLocation();
+ if (sloc == null) {
+ sloc = munger.getAspectType().getSourceLocation();
+ }
+ return sloc;
+ }
+
+ /**
+ * Returns a ResolvedType object representing the declaring type of this type, or null if this type does not represent a
+ * non-package-level-type.
+ * <p/>
+ * <strong>Warning</strong>: This is guaranteed to work for all member types. For anonymous/local types, the only guarantee is
+ * given in JLS 13.1, where it guarantees that if you call getDeclaringType() repeatedly, you will eventually get the top-level
+ * class, but it does not say anything about classes in between.
+ *
+ * @return the declaring type, or null if it is not an nested type.
+ */
+ public ResolvedType getDeclaringType() {
+ if (isArray()) {
+ return null;
+ }
+ if (isNested() || isAnonymous()) {
+ return getOuterClass();
+ }
+ return null;
+ }
+
+ public static boolean isVisible(int modifiers, ResolvedType targetType, ResolvedType fromType) {
+ // System.err.println("mod: " + modifiers + ", " + targetType + " and "
+ // + fromType);
+
+ if (Modifier.isPublic(modifiers)) {
+ return true;
+ } else if (Modifier.isPrivate(modifiers)) {
+ return targetType.getOutermostType().equals(fromType.getOutermostType());
+ } else if (Modifier.isProtected(modifiers)) {
+ return samePackage(targetType, fromType) || targetType.isAssignableFrom(fromType);
+ } else { // package-visible
+ return samePackage(targetType, fromType);
+ }
+ }
+
+ private static boolean samePackage(ResolvedType targetType, ResolvedType fromType) {
+ String p1 = targetType.getPackageName();
+ String p2 = fromType.getPackageName();
+ if (p1 == null) {
+ return p2 == null;
+ }
+ if (p2 == null) {
+ return false;
+ }
+ return p1.equals(p2);
+ }
+
+ /**
+ * Checks if the generic type for 'this' and the generic type for 'other' are the same - it can be passed raw or parameterized
+ * versions and will just compare the underlying generic type.
+ */
+ private boolean genericTypeEquals(ResolvedType other) {
+ ResolvedType rt = other;
+ if (rt.isParameterizedType() || rt.isRawType()) {
+ rt.getGenericType();
+ }
+ if (((isParameterizedType() || isRawType()) && getGenericType().equals(rt)) || (this.equals(other))) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Look up the actual occurence of a particular type in the hierarchy for 'this' type. The input is going to be a generic type,
+ * and the caller wants to know if it was used in its RAW or a PARAMETERIZED form in this hierarchy.
+ *
+ * returns null if it can't be found.
+ */
+ public ResolvedType discoverActualOccurrenceOfTypeInHierarchy(ResolvedType lookingFor) {
+ if (!lookingFor.isGenericType()) {
+ throw new BCException("assertion failed: method should only be called with generic type, but " + lookingFor + " is "
+ + lookingFor.typeKind);
+ }
+
+ if (this.equals(ResolvedType.OBJECT)) {
+ return null;
+ }
+
+ if (genericTypeEquals(lookingFor)) {
+ return this;
+ }
+
+ ResolvedType superT = getSuperclass();
+ if (superT.genericTypeEquals(lookingFor)) {
+ return superT;
+ }
+
+ ResolvedType[] superIs = getDeclaredInterfaces();
+ for (int i = 0; i < superIs.length; i++) {
+ ResolvedType superI = superIs[i];
+ if (superI.genericTypeEquals(lookingFor)) {
+ return superI;
+ }
+ ResolvedType checkTheSuperI = superI.discoverActualOccurrenceOfTypeInHierarchy(lookingFor);
+ if (checkTheSuperI != null) {
+ return checkTheSuperI;
+ }
+ }
+ return superT.discoverActualOccurrenceOfTypeInHierarchy(lookingFor);
+ }
+
+ /**
+ * Called for all type mungers but only does something if they share type variables with a generic type which they target. When
+ * this happens this routine will check for the target type in the target hierarchy and 'bind' any type parameters as
+ * appropriate. For example, for the ITD "List<T> I<T>.x" against a type like this: "class A implements I<String>" this routine
+ * will return a parameterized form of the ITD "List<String> I.x"
+ */
+ public ConcreteTypeMunger fillInAnyTypeParameters(ConcreteTypeMunger munger) {
+ boolean debug = false;
+ ResolvedMember member = munger.getSignature();
+ if (munger.isTargetTypeParameterized()) {
+ if (debug) {
+ System.err.println("Processing attempted parameterization of " + munger + " targetting type " + this);
+ }
+ if (debug) {
+ System.err.println(" This type is " + this + " (" + typeKind + ")");
+ }
+ // need to tailor this munger instance for the particular target...
+ if (debug) {
+ System.err.println(" Signature that needs parameterizing: " + member);
+ }
+ // Retrieve the generic type
+ ResolvedType onTypeResolved = world.resolve(member.getDeclaringType());
+ ResolvedType onType = onTypeResolved.getGenericType();
+ if (onType == null) {
+ // The target is not generic
+ getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error("The target type for the intertype declaration is not generic",
+ munger.getSourceLocation()));
+ return munger;
+ }
+ member.resolve(world); // Ensure all parts of the member are resolved
+ if (debug) {
+ System.err.println(" Actual target ontype: " + onType + " (" + onType.typeKind + ")");
+ }
+ // quickly find the targettype in the type hierarchy for this type
+ // (it will be either RAW or PARAMETERIZED)
+ ResolvedType actualTarget = discoverActualOccurrenceOfTypeInHierarchy(onType);
+ if (actualTarget == null) {
+ throw new BCException("assertion failed: asked " + this + " for occurrence of " + onType + " in its hierarchy??");
+ }
+
+ // only bind the tvars if its a parameterized type or the raw type
+ // (in which case they collapse to bounds) - don't do it
+ // for generic types ;)
+ if (!actualTarget.isGenericType()) {
+ if (debug) {
+ System.err.println("Occurrence in " + this + " is actually " + actualTarget + " (" + actualTarget.typeKind
+ + ")");
+ // parameterize the signature
+ // ResolvedMember newOne =
+ // member.parameterizedWith(actualTarget.getTypeParameters(),
+ // onType,actualTarget.isParameterizedType());
+ }
+ }
+ // if (!actualTarget.isRawType())
+ munger = munger.parameterizedFor(actualTarget);
+ if (debug) {
+ System.err.println("New sig: " + munger.getSignature());
+ }
+
+ if (debug) {
+ System.err.println("=====================================");
+ }
+ }
+ return munger;
+ }
+
+ /**
+ * Add an intertype munger to this type. isDuringCompilation tells us if we should be checking for an error scenario where two
+ * ITD fields are trying to use the same name. When this happens during compilation one of them is altered to get mangled name
+ * but when it happens during weaving it is too late and we need to put out an error asking them to recompile.
+ */
+ public void addInterTypeMunger(ConcreteTypeMunger munger, boolean isDuringCompilation) {
+ ResolvedMember sig = munger.getSignature();
+ bits = (bits & ~MungersAnalyzed); // clear the bit - as the mungers have changed
+ if (sig == null || munger.getMunger() == null || munger.getMunger().getKind() == ResolvedTypeMunger.PrivilegedAccess) {
+ interTypeMungers.add(munger);
+ return;
+ }
+
+ // ConcreteTypeMunger originalMunger = munger;
+ // we will use the 'parameterized' ITD for all the comparisons but we
+ // say the original
+ // one passed in actually matched as it will be added to the intertype
+ // member finder
+ // for the target type. It is possible we only want to do this if a
+ // generic type
+ // is discovered and the tvar is collapsed to a bound?
+ munger = fillInAnyTypeParameters(munger);
+ sig = munger.getSignature(); // possibly changed when type parms filled in
+
+ if (sig.getKind() == Member.METHOD) {
+ // OPTIMIZE can this be sped up?
+ if (clashesWithExistingMember(munger, getMethods(true, false))) { // ITDs checked below
+ return;
+ }
+ if (this.isInterface()) {
+ // OPTIMIZE this set of methods are always the same - must we keep creating them as a list?
+ if (clashesWithExistingMember(munger, Arrays.asList(world.getCoreType(OBJECT).getDeclaredMethods()).iterator())) {
+ return;
+ }
+ }
+ } else if (sig.getKind() == Member.FIELD) {
+ if (clashesWithExistingMember(munger, Arrays.asList(getDeclaredFields()).iterator())) {
+ return;
+ }
+ // Cannot cope with two version '2' style mungers for the same field on the same type
+ // Must error and request the user recompile at least one aspect with the
+ // -Xset:itdStyle=1 option
+ if (!isDuringCompilation) {
+ ResolvedTypeMunger thisRealMunger = munger.getMunger();
+ if (thisRealMunger instanceof NewFieldTypeMunger) {
+ NewFieldTypeMunger newFieldTypeMunger = (NewFieldTypeMunger) thisRealMunger;
+ if (newFieldTypeMunger.version == NewFieldTypeMunger.VersionTwo) {
+ String thisRealMungerSignatureName = newFieldTypeMunger.getSignature().getName();
+ for (ConcreteTypeMunger typeMunger : interTypeMungers) {
+ if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
+ if (typeMunger.getSignature().getKind() == Member.FIELD) {
+ NewFieldTypeMunger existing = (NewFieldTypeMunger) typeMunger.getMunger();
+ if (existing.getSignature().getName().equals(thisRealMungerSignatureName)
+ && existing.version == NewFieldTypeMunger.VersionTwo
+ // this check ensures no problem for a clash with an ITD on an interface
+ && existing.getSignature().getDeclaringType()
+ .equals(newFieldTypeMunger.getSignature().getDeclaringType())) {
+
+ // report error on the aspect
+ StringBuffer sb = new StringBuffer();
+ sb.append("Cannot handle two aspects both attempting to use new style ITDs for the same named field ");
+ sb.append("on the same target type. Please recompile at least one aspect with '-Xset:itdVersion=1'.");
+ sb.append(" Aspects involved: " + munger.getAspectType().getName() + " and "
+ + typeMunger.getAspectType().getName() + ".");
+ sb.append(" Field is named '" + existing.getSignature().getName() + "'");
+ getWorld().getMessageHandler().handleMessage(
+ new Message(sb.toString(), getSourceLocation(), true));
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ if (clashesWithExistingMember(munger, Arrays.asList(getDeclaredMethods()).iterator())) {
+ return;
+ }
+ }
+
+ boolean needsAdding =true;
+ boolean needsToBeAddedEarlier =false;
+ // now compare to existingMungers
+ for (Iterator<ConcreteTypeMunger> i = interTypeMungers.iterator(); i.hasNext();) {
+ ConcreteTypeMunger existingMunger = i.next();
+ boolean v2itds = munger.getSignature().getKind()== Member.FIELD && (munger.getMunger() instanceof NewFieldTypeMunger) && ((NewFieldTypeMunger)munger.getMunger()).version==NewFieldTypeMunger.VersionTwo;
+
+ if (conflictingSignature(existingMunger.getSignature(), munger.getSignature(),v2itds)) {
+ // System.err.println("match " + munger + " with " + existingMunger);
+ if (isVisible(munger.getSignature().getModifiers(), munger.getAspectType(), existingMunger.getAspectType())) {
+ // System.err.println(" is visible");
+ int c = compareMemberPrecedence(sig, existingMunger.getSignature());
+ if (c == 0) {
+ c = getWorld().compareByPrecedenceAndHierarchy(munger.getAspectType(), existingMunger.getAspectType());
+ }
+ // System.err.println(" compare: " + c);
+ if (c < 0) {
+ // the existing munger dominates the new munger
+ checkLegalOverride(munger.getSignature(), existingMunger.getSignature(), 0x11, null);
+ needsAdding = false;
+ if (munger.getSignature().getKind()== Member.FIELD && munger.getSignature().getDeclaringType().resolve(world).isInterface() && ((NewFieldTypeMunger)munger.getMunger()).version==NewFieldTypeMunger.VersionTwo) {
+ // still need to add it
+ needsAdding=true;
+ }
+ break;
+ } else if (c > 0) {
+ // the new munger dominates the existing one
+ checkLegalOverride(existingMunger.getSignature(), munger.getSignature(), 0x11, null);
+// i.remove();
+ if (existingMunger.getSignature().getKind()==Member.FIELD &&
+ existingMunger.getSignature().getDeclaringType().resolve(world).isInterface()
+ && ((NewFieldTypeMunger)existingMunger.getMunger()).version==NewFieldTypeMunger.VersionTwo) {
+ needsToBeAddedEarlier=true;
+ } else {
+ i.remove();
+ }
+ break;
+ } else {
+ interTypeConflictError(munger, existingMunger);
+ interTypeConflictError(existingMunger, munger);
+ return;
+ }
+ }
+ }
+ }
+ // System.err.println("adding: " + munger + " to " + this);
+ // we are adding the parameterized form of the ITD to the list of
+ // mungers. Within it, the munger knows the original declared
+ // signature for the ITD so it can be retrieved.
+ if (needsAdding) {
+ if (!needsToBeAddedEarlier) {
+ interTypeMungers.add(munger);
+ } else {
+ interTypeMungers.add(0,munger);
+ }
+ }
+ }
+
+ /**
+ * Compare the type transformer with the existing members. A clash may not be an error (the ITD may be the 'default
+ * implementation') so returning false is not always a sign of an error.
+ *
+ * @return true if there is a clash
+ */
+ private boolean clashesWithExistingMember(ConcreteTypeMunger typeTransformer, Iterator<ResolvedMember> existingMembers) {
+ ResolvedMember typeTransformerSignature = typeTransformer.getSignature();
+
+ // ResolvedType declaringAspectType = munger.getAspectType();
+ // if (declaringAspectType.isRawType()) declaringAspectType =
+ // declaringAspectType.getGenericType();
+ // if (declaringAspectType.isGenericType()) {
+ //
+ // ResolvedType genericOnType =
+ // getWorld().resolve(sig.getDeclaringType()).getGenericType();
+ // ConcreteTypeMunger ctm =
+ // munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy
+ // (genericOnType));
+ // sig = ctm.getSignature(); // possible sig change when type
+ // }
+ // if (munger.getMunger().hasTypeVariableAliases()) {
+ // ResolvedType genericOnType =
+ // getWorld().resolve(sig.getDeclaringType()).getGenericType();
+ // ConcreteTypeMunger ctm =
+ // munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy(
+ // genericOnType));
+ // sig = ctm.getSignature(); // possible sig change when type parameters
+ // filled in
+ // }
+ ResolvedTypeMunger rtm = typeTransformer.getMunger();
+ boolean v2itds = true;
+ if (rtm instanceof NewFieldTypeMunger && ((NewFieldTypeMunger)rtm).version==NewFieldTypeMunger.VersionOne) {
+ v2itds = false;
+ }
+ while (existingMembers.hasNext()) {
+ ResolvedMember existingMember = existingMembers.next();
+ // don't worry about clashing with bridge methods
+ if (existingMember.isBridgeMethod()) {
+ continue;
+ }
+ if (conflictingSignature(existingMember, typeTransformerSignature,v2itds)) {
+ // System.err.println("conflict: existingMember=" +
+ // existingMember + " typeMunger=" + munger);
+ // System.err.println(munger.getSourceLocation() + ", " +
+ // munger.getSignature() + ", " +
+ // munger.getSignature().getSourceLocation());
+
+ if (isVisible(existingMember.getModifiers(), this, typeTransformer.getAspectType())) {
+ int c = compareMemberPrecedence(typeTransformerSignature, existingMember);
+ // System.err.println(" c: " + c);
+ if (c < 0) {
+ ResolvedType typeTransformerTargetType = typeTransformerSignature.getDeclaringType().resolve(world);
+ if (typeTransformerTargetType.isInterface()) {
+ ResolvedType existingMemberType = existingMember.getDeclaringType().resolve(world);
+ if ((rtm instanceof NewMethodTypeMunger) && !typeTransformerTargetType.equals(existingMemberType)) {
+ // Might be pr404601. ITD is on an interface with a different visibility to the real member
+ if (Modifier.isPrivate(typeTransformerSignature.getModifiers()) &&
+ Modifier.isPublic(existingMember.getModifiers())) {
+ world.getMessageHandler().handleMessage(new Message("private intertype declaration '"+typeTransformerSignature.toString()+"' clashes with public member '"+existingMember.toString()+"'",existingMember.getSourceLocation(),true));
+ }
+ }
+ }
+ // existingMember dominates munger
+ checkLegalOverride(typeTransformerSignature, existingMember, 0x10, typeTransformer.getAspectType());
+ return true;
+ } else if (c > 0) {
+ // munger dominates existingMember
+ checkLegalOverride(existingMember, typeTransformerSignature, 0x01, typeTransformer.getAspectType());
+ // interTypeMungers.add(munger);
+ // ??? might need list of these overridden abstracts
+ continue;
+ } else {
+ // bridge methods can differ solely in return type.
+ // FIXME this whole method seems very hokey - unaware of covariance/varargs/bridging - it
+ // could do with a rewrite !
+ boolean sameReturnTypes = (existingMember.getReturnType().equals(typeTransformerSignature.getReturnType()));
+ if (sameReturnTypes) {
+ // pr206732 - if the existingMember is due to a
+ // previous application of this same ITD (which can
+ // happen if this is a binary type being brought in
+ // from the aspectpath). The 'better' fix is
+ // to recognize it is from the aspectpath at a
+ // higher level and dont do this, but that is rather
+ // more work.
+ boolean isDuplicateOfPreviousITD = false;
+ ResolvedType declaringRt = existingMember.getDeclaringType().resolve(world);
+ WeaverStateInfo wsi = declaringRt.getWeaverState();
+ if (wsi != null) {
+ List<ConcreteTypeMunger> mungersAffectingThisType = wsi.getTypeMungers(declaringRt);
+ if (mungersAffectingThisType != null) {
+ for (Iterator<ConcreteTypeMunger> iterator = mungersAffectingThisType.iterator(); iterator
+ .hasNext() && !isDuplicateOfPreviousITD;) {
+ ConcreteTypeMunger ctMunger = iterator.next();
+ // relatively crude check - is the ITD
+ // for the same as the existingmember
+ // and does it come
+ // from the same aspect
+ if (ctMunger.getSignature().equals(existingMember)
+ && ctMunger.aspectType.equals(typeTransformer.getAspectType())) {
+ isDuplicateOfPreviousITD = true;
+ }
+ }
+ }
+ }
+ if (!isDuplicateOfPreviousITD) {
+ // b275032 - this is OK if it is the default ctor and that default ctor was generated
+ // at compile time, otherwise we cannot overwrite it
+ if (!(typeTransformerSignature.getName().equals("<init>") && existingMember.isDefaultConstructor())) {
+ String aspectName = typeTransformer.getAspectType().getName();
+ ISourceLocation typeTransformerLocation = typeTransformer.getSourceLocation();
+ ISourceLocation existingMemberLocation = existingMember.getSourceLocation();
+ String msg = WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT, aspectName,
+ existingMember);
+
+ // this isn't quite right really... as I think the errors should only be recorded against
+ // what is currently being processed or they may get lost or reported twice
+
+ // report error on the aspect
+ getWorld().getMessageHandler().handleMessage(new Message(msg, typeTransformerLocation, true));
+
+ // report error on the affected type, if we can
+ if (existingMemberLocation != null) {
+ getWorld().getMessageHandler()
+ .handleMessage(new Message(msg, existingMemberLocation, true));
+ }
+ return true; // clash - so ignore this itd
+ }
+ }
+ }
+ }
+ } else if (isDuplicateMemberWithinTargetType(existingMember, this, typeTransformerSignature)) {
+ getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT, typeTransformer
+ .getAspectType().getName(), existingMember), typeTransformer.getSourceLocation()));
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // we know that the member signature matches, but that the member in the
+ // target type is not visible to the aspect.
+ // this may still be disallowed if it would result in two members within the
+ // same declaring type with the same
+ // signature AND more than one of them is concrete AND they are both visible
+ // within the target type.
+ private boolean isDuplicateMemberWithinTargetType(ResolvedMember existingMember, ResolvedType targetType,
+ ResolvedMember itdMember) {
+ if ((existingMember.isAbstract() || itdMember.isAbstract())) {
+ return false;
+ }
+ UnresolvedType declaringType = existingMember.getDeclaringType();
+ if (!targetType.equals(declaringType)) {
+ return false;
+ }
+ // now have to test that itdMember is visible from targetType
+ if (Modifier.isPrivate(itdMember.getModifiers())) {
+ return false;
+ }
+ if (itdMember.isPublic()) {
+ return true;
+ }
+ // must be in same package to be visible then...
+ if (!targetType.getPackageName().equals(itdMember.getDeclaringType().getPackageName())) {
+ return false;
+ }
+
+ // trying to put two members with the same signature into the exact same
+ // type..., and both visible in that type.
+ return true;
+ }
+
+ /**
+ * @param transformerPosition which parameter is the type transformer (0x10 for first, 0x01 for second, 0x11 for both, 0x00 for
+ * neither)
+ * @param aspectType the declaring type of aspect defining the *first* type transformer
+ * @return true if the override is legal note: calling showMessage with two locations issues TWO messages, not ONE message with
+ * an additional source location.
+ */
+ public boolean checkLegalOverride(ResolvedMember parent, ResolvedMember child, int transformerPosition, ResolvedType aspectType) {
+ // System.err.println("check: " + child.getDeclaringType() + " overrides " + parent.getDeclaringType());
+ if (Modifier.isFinal(parent.getModifiers())) {
+ // If the ITD matching is occurring due to pulling in a BinaryTypeBinding then this check can incorrectly
+ // signal an error because the ITD transformer being examined here will exactly match the member it added
+ // during the first round of compilation. This situation can only occur if the ITD is on an interface whilst
+ // the class is the top most implementor. If the ITD is on the same type that received it during compilation,
+ // this method won't be called as the previous check for precedence level will return 0.
+
+ if (transformerPosition == 0x10 && aspectType != null) {
+ ResolvedType nonItdDeclaringType = child.getDeclaringType().resolve(world);
+ WeaverStateInfo wsi = nonItdDeclaringType.getWeaverState();
+ if (wsi != null) {
+ List<ConcreteTypeMunger> transformersOnThisType = wsi.getTypeMungers(nonItdDeclaringType);
+ if (transformersOnThisType != null) {
+ for (ConcreteTypeMunger transformer : transformersOnThisType) {
+ // relatively crude check - is the ITD for the same as the existingmember
+ // and does it come from the same aspect
+ if (transformer.aspectType.equals(aspectType)) {
+ if (parent.equalsApartFromDeclaringType(transformer.getSignature())) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ world.showMessage(Message.ERROR, WeaverMessages.format(WeaverMessages.CANT_OVERRIDE_FINAL_MEMBER, parent),
+ child.getSourceLocation(), null);
+ return false;
+ }
+
+ boolean incompatibleReturnTypes = false;
+ // In 1.5 mode, allow for covariance on return type
+ if (world.isInJava5Mode() && parent.getKind() == Member.METHOD) {
+
+ // Look at the generic types when doing this comparison
+ ResolvedType rtParentReturnType = parent.resolve(world).getGenericReturnType().resolve(world);
+ ResolvedType rtChildReturnType = child.resolve(world).getGenericReturnType().resolve(world);
+ incompatibleReturnTypes = !rtParentReturnType.isAssignableFrom(rtChildReturnType);
+ // For debug, uncomment this bit and we'll repeat the check - stick
+ // a breakpoint on the call
+ // if (incompatibleReturnTypes) {
+ // incompatibleReturnTypes =
+ // !rtParentReturnType.isAssignableFrom(rtChildReturnType);
+ // }
+ } else {
+ ResolvedType rtParentReturnType = parent.resolve(world).getGenericReturnType().resolve(world);
+ ResolvedType rtChildReturnType = child.resolve(world).getGenericReturnType().resolve(world);
+
+ incompatibleReturnTypes = !rtParentReturnType.equals(rtChildReturnType);
+ }
+
+ if (incompatibleReturnTypes) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ITD_RETURN_TYPE_MISMATCH, parent, child),
+ child.getSourceLocation(), parent.getSourceLocation());
+ return false;
+ }
+ if (parent.getKind() == Member.POINTCUT) {
+ UnresolvedType[] pTypes = parent.getParameterTypes();
+ UnresolvedType[] cTypes = child.getParameterTypes();
+ if (!Arrays.equals(pTypes, cTypes)) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ITD_PARAM_TYPE_MISMATCH, parent, child),
+ child.getSourceLocation(), parent.getSourceLocation());
+ return false;
+ }
+ }
+ // System.err.println("check: " + child.getModifiers() +
+ // " more visible " + parent.getModifiers());
+ if (isMoreVisible(parent.getModifiers(), child.getModifiers())) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ITD_VISIBILITY_REDUCTION, parent, child),
+ child.getSourceLocation(), parent.getSourceLocation());
+ return false;
+ }
+
+ // check declared exceptions
+ ResolvedType[] childExceptions = world.resolve(child.getExceptions());
+ ResolvedType[] parentExceptions = world.resolve(parent.getExceptions());
+ ResolvedType runtimeException = world.resolve("java.lang.RuntimeException");
+ ResolvedType error = world.resolve("java.lang.Error");
+
+ outer: for (int i = 0, leni = childExceptions.length; i < leni; i++) {
+ // System.err.println("checking: " + childExceptions[i]);
+ if (runtimeException.isAssignableFrom(childExceptions[i])) {
+ continue;
+ }
+ if (error.isAssignableFrom(childExceptions[i])) {
+ continue;
+ }
+
+ for (int j = 0, lenj = parentExceptions.length; j < lenj; j++) {
+ if (parentExceptions[j].isAssignableFrom(childExceptions[i])) {
+ continue outer;
+ }
+ }
+
+ // this message is now better handled my MethodVerifier in JDT core.
+ // world.showMessage(IMessage.ERROR,
+ // WeaverMessages.format(WeaverMessages.ITD_DOESNT_THROW,
+ // childExceptions[i].getName()),
+ // child.getSourceLocation(), null);
+
+ return false;
+ }
+ boolean parentStatic = Modifier.isStatic(parent.getModifiers());
+ boolean childStatic = Modifier.isStatic(child.getModifiers());
+ if (parentStatic && !childStatic) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ITD_OVERRIDDEN_STATIC, child, parent),
+ child.getSourceLocation(), null);
+ return false;
+ } else if (childStatic && !parentStatic) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ITD_OVERIDDING_STATIC, child, parent),
+ child.getSourceLocation(), null);
+ return false;
+ }
+ return true;
+
+ }
+
+ private int compareMemberPrecedence(ResolvedMember m1, ResolvedMember m2) {
+ // if (!m1.getReturnType().equals(m2.getReturnType())) return 0;
+
+ // need to allow for the special case of 'clone' - which is like
+ // abstract but is
+ // not marked abstract. The code below this next line seems to make
+ // assumptions
+ // about what will have gotten through the compiler based on the normal
+ // java rules. clone goes against these...
+ if (Modifier.isProtected(m2.getModifiers()) && m2.getName().charAt(0) == 'c') {
+ UnresolvedType declaring = m2.getDeclaringType();
+ if (declaring != null) {
+ if (declaring.getName().equals("java.lang.Object") && m2.getName().equals("clone")) {
+ return +1;
+ }
+ }
+ }
+
+ if (Modifier.isAbstract(m1.getModifiers())) {
+ return -1;
+ }
+ if (Modifier.isAbstract(m2.getModifiers())) {
+ return +1;
+ }
+
+ if (m1.getDeclaringType().equals(m2.getDeclaringType())) {
+ return 0;
+ }
+
+ ResolvedType t1 = m1.getDeclaringType().resolve(world);
+ ResolvedType t2 = m2.getDeclaringType().resolve(world);
+ if (t1.isAssignableFrom(t2)) {
+ return -1;
+ }
+ if (t2.isAssignableFrom(t1)) {
+ return +1;
+ }
+ return 0;
+ }
+
+ public static boolean isMoreVisible(int m1, int m2) {
+ if (Modifier.isPrivate(m1)) {
+ return false;
+ }
+ if (isPackage(m1)) {
+ return Modifier.isPrivate(m2);
+ }
+ if (Modifier.isProtected(m1)) {
+ return /* private package */(Modifier.isPrivate(m2) || isPackage(m2));
+ }
+ if (Modifier.isPublic(m1)) {
+ return /* private package protected */!Modifier.isPublic(m2);
+ }
+ throw new RuntimeException("bad modifier: " + m1);
+ }
+
+ private static boolean isPackage(int i) {
+ return (0 == (i & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED)));
+ }
+
+ private void interTypeConflictError(ConcreteTypeMunger m1, ConcreteTypeMunger m2) {
+ // XXX this works only if we ignore separate compilation issues
+ // XXX dual errors possible if (this instanceof BcelObjectType) return;
+ /*
+ * if (m1.getMunger().getKind() == ResolvedTypeMunger.Field && m2.getMunger().getKind() == ResolvedTypeMunger.Field) { // if
+ * *exactly* the same, it's ok return true; }
+ */
+ // System.err.println("conflict at " + m2.getSourceLocation());
+ getWorld().showMessage(
+ IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.ITD_CONFLICT, m1.getAspectType().getName(), m2.getSignature(), m2
+ .getAspectType().getName()), m2.getSourceLocation(), getSourceLocation());
+ // return false;
+ }
+
+ public ResolvedMember lookupSyntheticMember(Member member) {
+ // ??? horribly inefficient
+ // for (Iterator i =
+ // System.err.println("lookup " + member + " in " + interTypeMungers);
+ for (ConcreteTypeMunger m : interTypeMungers) {
+ ResolvedMember ret = m.getMatchingSyntheticMember(member);
+ if (ret != null) {
+ // System.err.println(" found: " + ret);
+ return ret;
+ }
+ }
+
+ // Handling members for the new array join point
+ if (world.isJoinpointArrayConstructionEnabled() && this.isArray()) {
+ if (member.getKind() == Member.CONSTRUCTOR) {
+ ResolvedMemberImpl ret = new ResolvedMemberImpl(Member.CONSTRUCTOR, this, Modifier.PUBLIC, UnresolvedType.VOID,
+ "<init>", world.resolve(member.getParameterTypes()));
+ // Give the parameters names - they are going to be the dimensions uses to build the array (dim0 > dimN)
+ int count = ret.getParameterTypes().length;
+ String[] paramNames = new String[count];
+ for (int i = 0; i < count; i++) {
+ paramNames[i] = new StringBuffer("dim").append(i).toString();
+ }
+ ret.setParameterNames(paramNames);
+ return ret;
+ }
+ }
+
+ // if (this.getSuperclass() != ResolvedType.OBJECT &&
+ // this.getSuperclass() != null) {
+ // return getSuperclass().lookupSyntheticMember(member);
+ // }
+
+ return null;
+ }
+
+ static class SuperClassWalker implements Iterator<ResolvedType> {
+
+ private ResolvedType curr;
+ private SuperInterfaceWalker iwalker;
+ private boolean wantGenerics;
+
+ public SuperClassWalker(ResolvedType type, SuperInterfaceWalker iwalker, boolean genericsAware) {
+ this.curr = type;
+ this.iwalker = iwalker;
+ this.wantGenerics = genericsAware;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return curr != null;
+ }
+
+ @Override
+ public ResolvedType next() {
+ ResolvedType ret = curr;
+ if (!wantGenerics && ret.isParameterizedOrGenericType()) {
+ ret = ret.getRawType();
+ }
+ iwalker.push(ret); // tell the interface walker about another class whose interfaces need visiting
+ curr = curr.getSuperclass();
+ return ret;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ static class SuperInterfaceWalker implements Iterator<ResolvedType> {
+
+ private Getter<ResolvedType, ResolvedType> ifaceGetter;
+ Iterator<ResolvedType> delegate = null;
+ public Queue<ResolvedType> toPersue = new LinkedList<ResolvedType>();
+ public Set<ResolvedType> visited = new HashSet<ResolvedType>();
+
+ SuperInterfaceWalker(Iterators.Getter<ResolvedType, ResolvedType> ifaceGetter) {
+ this.ifaceGetter = ifaceGetter;
+ }
+
+ SuperInterfaceWalker(Iterators.Getter<ResolvedType, ResolvedType> ifaceGetter, ResolvedType interfaceType) {
+ this.ifaceGetter = ifaceGetter;
+ this.delegate = Iterators.one(interfaceType);
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (delegate == null || !delegate.hasNext()) {
+ // either we set it up or we have run out, is there anything else to look at?
+ if (toPersue.isEmpty()) {
+ return false;
+ }
+ do {
+ ResolvedType next = toPersue.remove();
+ visited.add(next);
+ delegate = ifaceGetter.get(next); // retrieve interfaces from a class or another interface
+ } while (!delegate.hasNext() && !toPersue.isEmpty());
+ }
+ return delegate.hasNext();
+ }
+
+ public void push(ResolvedType ret) {
+ toPersue.add(ret);
+ }
+
+ @Override
+ public ResolvedType next() {
+ ResolvedType next = delegate.next();
+ // BUG should check for generics and erase?
+ // if (!visited.contains(next)) {
+ // visited.add(next);
+ if (visited.add(next)) {
+ toPersue.add(next); // pushes on interfaces already visited?
+ }
+ return next;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public void clearInterTypeMungers() {
+ if (isRawType()) {
+ ResolvedType genericType = getGenericType();
+ if (genericType.isRawType()) { // ERROR SITUATION: PR341926
+ // For some reason the raw type is pointing to another raw form (possibly itself)
+ System.err.println("DebugFor341926: Type " + this.getName() + " has an incorrect generic form");
+ } else {
+ genericType.clearInterTypeMungers();
+ }
+ }
+ // interTypeMungers.clear();
+ // BUG? Why can't this be clear() instead: 293620 c6
+ interTypeMungers = new ArrayList<ConcreteTypeMunger>();
+ }
+
+ public boolean isTopmostImplementor(ResolvedType interfaceType) {
+ boolean b = true;
+ if (isInterface()) {
+ b = false;
+ } else if (!interfaceType.isAssignableFrom(this, true)) {
+ b = false;
+ } else {
+ ResolvedType superclass = this.getSuperclass();
+ if (superclass.isMissing()) {
+ b = true; // we don't know anything about supertype, and it can't be exposed to weaver
+ } else if (interfaceType.isAssignableFrom(superclass, true)) { // check that I'm truly the topmost implementor
+ b = false;
+ }
+ }
+ // System.out.println("is " + getName() + " topmostimplementor of " + interfaceType + "? " + b);
+ return b;
+ }
+
+ public ResolvedType getTopmostImplementor(ResolvedType interfaceType) {
+ if (isInterface()) {
+ return null;
+ }
+ if (!interfaceType.isAssignableFrom(this)) {
+ return null;
+ }
+ // Check if my super class is an implementor?
+ ResolvedType higherType = this.getSuperclass().getTopmostImplementor(interfaceType);
+ if (higherType != null) {
+ return higherType;
+ }
+ return this;
+ }
+
+ public List<ResolvedMember> getExposedPointcuts() {
+ List<ResolvedMember> ret = new ArrayList<ResolvedMember>();
+ if (getSuperclass() != null) {
+ ret.addAll(getSuperclass().getExposedPointcuts());
+ }
+
+ for (ResolvedType type : getDeclaredInterfaces()) {
+ addPointcutsResolvingConflicts(ret, Arrays.asList(type.getDeclaredPointcuts()), false);
+ }
+
+ addPointcutsResolvingConflicts(ret, Arrays.asList(getDeclaredPointcuts()), true);
+
+ for (ResolvedMember member : ret) {
+ ResolvedPointcutDefinition inherited = (ResolvedPointcutDefinition) member;
+ if (inherited != null && inherited.isAbstract()) {
+ if (!this.isAbstract()) {
+ getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.POINCUT_NOT_CONCRETE, inherited, this.getName()),
+ inherited.getSourceLocation(), this.getSourceLocation());
+ }
+ }
+ }
+ return ret;
+ }
+
+ private void addPointcutsResolvingConflicts(List<ResolvedMember> acc, List<ResolvedMember> added, boolean isOverriding) {
+ for (Iterator<ResolvedMember> i = added.iterator(); i.hasNext();) {
+ ResolvedPointcutDefinition toAdd = (ResolvedPointcutDefinition) i.next();
+ for (Iterator<ResolvedMember> j = acc.iterator(); j.hasNext();) {
+ ResolvedPointcutDefinition existing = (ResolvedPointcutDefinition) j.next();
+ if (toAdd == null || existing == null || existing == toAdd) {
+ continue;
+ }
+ UnresolvedType pointcutDeclaringTypeUT = existing.getDeclaringType();
+ if (pointcutDeclaringTypeUT != null) {
+ ResolvedType pointcutDeclaringType = pointcutDeclaringTypeUT.resolve(getWorld());
+ if (!isVisible(existing.getModifiers(), pointcutDeclaringType, this)) {
+ // if they intended to override it but it is not visible,
+ // give them a nicer message
+ if (existing.isAbstract() && conflictingSignature(existing, toAdd)) {
+ getWorld().showMessage(
+ IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.POINTCUT_NOT_VISIBLE, existing.getDeclaringType()
+ .getName() + "." + existing.getName() + "()", this.getName()),
+ toAdd.getSourceLocation(), null);
+ j.remove();
+ }
+ continue;
+ }
+ }
+ if (conflictingSignature(existing, toAdd)) {
+ if (isOverriding) {
+ checkLegalOverride(existing, toAdd, 0x00, null);
+ j.remove();
+ } else {
+ getWorld().showMessage(
+ IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.CONFLICTING_INHERITED_POINTCUTS,
+ this.getName() + toAdd.getSignature()), existing.getSourceLocation(),
+ toAdd.getSourceLocation());
+ j.remove();
+ }
+ }
+ }
+ acc.add(toAdd);
+ }
+ }
+
+ public ISourceLocation getSourceLocation() {
+ return null;
+ }
+
+ public boolean isExposedToWeaver() {
+ return false;
+ }
+
+ public WeaverStateInfo getWeaverState() {
+ return null;
+ }
+
+ /**
+ * Overridden by ReferenceType to return a sensible answer for parameterized and raw types.
+ *
+ * @return
+ */
+ public ReferenceType getGenericType() {
+ // if (!(isParameterizedType() || isRawType()))
+ // throw new BCException("The type " + getBaseName() + " is not parameterized or raw - it has no generic type");
+ return null;
+ }
+
+ @Override
+ public ResolvedType getRawType() {
+ return super.getRawType().resolve(world);
+ }
+
+ public ResolvedType parameterizedWith(UnresolvedType[] typeParameters) {
+ if (!(isGenericType() || isParameterizedType())) {
+ return this;
+ }
+ return TypeFactory.createParameterizedType(this.getGenericType(), typeParameters, getWorld());
+ }
+
+ /**
+ * Iff I am a parameterized type, and any of my parameters are type variable references (or nested parameterized types),
+ * return a version with those type parameters replaced in accordance with the passed bindings.
+ */
+ @Override
+ public UnresolvedType parameterize(Map<String, UnresolvedType> typeBindings) {
+ if (!isParameterizedType()) {
+ // throw new IllegalStateException("Can't parameterize a type that is not a parameterized type");
+ return this;
+ }
+ boolean workToDo = false;
+ for (int i = 0; i < typeParameters.length; i++) {
+ if (typeParameters[i].isTypeVariableReference() || (typeParameters[i] instanceof BoundedReferenceType) || typeParameters[i].isParameterizedType()) {
+ workToDo = true;
+ }
+ }
+ if (!workToDo) {
+ return this;
+ } else {
+ UnresolvedType[] newTypeParams = new UnresolvedType[typeParameters.length];
+ for (int i = 0; i < newTypeParams.length; i++) {
+ newTypeParams[i] = typeParameters[i];
+ if (newTypeParams[i].isTypeVariableReference()) {
+ TypeVariableReferenceType tvrt = (TypeVariableReferenceType) newTypeParams[i];
+ UnresolvedType binding = typeBindings.get(tvrt.getTypeVariable().getName());
+ if (binding != null) {
+ newTypeParams[i] = binding;
+ }
+ } else if (newTypeParams[i] instanceof BoundedReferenceType) {
+ BoundedReferenceType brType = (BoundedReferenceType) newTypeParams[i];
+ newTypeParams[i] = brType.parameterize(typeBindings);
+ // brType.parameterize(typeBindings)
+ } else if (newTypeParams[i].isParameterizedType()) {
+ newTypeParams[i] = newTypeParams[i].parameterize(typeBindings);
+ }
+ }
+ return TypeFactory.createParameterizedType(getGenericType(), newTypeParams, getWorld());
+ }
+ }
+
+ // public boolean hasParameterizedSuperType() {
+ // getParameterizedSuperTypes();
+ // return parameterizedSuperTypes.length > 0;
+ // }
+
+ // public boolean hasGenericSuperType() {
+ // ResolvedType[] superTypes = getDeclaredInterfaces();
+ // for (int i = 0; i < superTypes.length; i++) {
+ // if (superTypes[i].isGenericType())
+ // return true;
+ // }
+ // return false;
+ // }
+
+ // private ResolvedType[] parameterizedSuperTypes = null;
+
+ /**
+ * Similar to the above method, but accumulates the super types
+ *
+ * @return
+ */
+ // public ResolvedType[] getParameterizedSuperTypes() {
+ // if (parameterizedSuperTypes != null)
+ // return parameterizedSuperTypes;
+ // List accumulatedTypes = new ArrayList();
+ // accumulateParameterizedSuperTypes(this, accumulatedTypes);
+ // ResolvedType[] ret = new ResolvedType[accumulatedTypes.size()];
+ // parameterizedSuperTypes = (ResolvedType[]) accumulatedTypes.toArray(ret);
+ // return parameterizedSuperTypes;
+ // }
+ // private void accumulateParameterizedSuperTypes(ResolvedType forType, List
+ // parameterizedTypeList) {
+ // if (forType.isParameterizedType()) {
+ // parameterizedTypeList.add(forType);
+ // }
+ // if (forType.getSuperclass() != null) {
+ // accumulateParameterizedSuperTypes(forType.getSuperclass(),
+ // parameterizedTypeList);
+ // }
+ // ResolvedType[] interfaces = forType.getDeclaredInterfaces();
+ // for (int i = 0; i < interfaces.length; i++) {
+ // accumulateParameterizedSuperTypes(interfaces[i], parameterizedTypeList);
+ // }
+ // }
+ /**
+ * @return true if assignable to java.lang.Exception
+ */
+ public boolean isException() {
+ return (world.getCoreType(UnresolvedType.JL_EXCEPTION).isAssignableFrom(this));
+ }
+
+ /**
+ * @return true if it is an exception and it is a checked one, false otherwise.
+ */
+ public boolean isCheckedException() {
+ if (!isException()) {
+ return false;
+ }
+ if (world.getCoreType(UnresolvedType.RUNTIME_EXCEPTION).isAssignableFrom(this)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Determines if variables of this type could be assigned values of another with lots of help. java.lang.Object is convertable
+ * from all types. A primitive type is convertable from X iff it's assignable from X. A reference type is convertable from X iff
+ * it's coerceable from X. In other words, X isConvertableFrom Y iff the compiler thinks that _some_ value of Y could be
+ * assignable to a variable of type X without loss of precision.
+ *
+ * @param other the other type
+ * @param world the {@link World} in which the possible assignment should be checked.
+ * @return true iff variables of this type could be assigned values of other with possible conversion
+ */
+ public final boolean isConvertableFrom(ResolvedType other) {
+
+ // // version from TypeX
+ // if (this.equals(OBJECT)) return true;
+ // if (this.isPrimitiveType() || other.isPrimitiveType()) return
+ // this.isAssignableFrom(other);
+ // return this.isCoerceableFrom(other);
+ //
+
+ // version from ResolvedTypeX
+ if (this.equals(OBJECT)) {
+ return true;
+ }
+ if (world.isInJava5Mode()) {
+ if (this.isPrimitiveType() ^ other.isPrimitiveType()) { // If one is
+ // primitive
+ // and the
+ // other
+ // isnt
+ if (validBoxing.contains(this.getSignature() + other.getSignature())) {
+ return true;
+ }
+ }
+ }
+ if (this.isPrimitiveType() || other.isPrimitiveType()) {
+ return this.isAssignableFrom(other);
+ }
+ return this.isCoerceableFrom(other);
+ }
+
+ /**
+ * Determines if the variables of this type could be assigned values of another type without casting. This still allows for
+ * assignment conversion as per JLS 2ed 5.2. For object types, this means supertypeOrEqual(THIS, OTHER).
+ *
+ * @param other the other type
+ * @param world the {@link World} in which the possible assignment should be checked.
+ * @return true iff variables of this type could be assigned values of other without casting
+ * @throws NullPointerException if other is null
+ */
+ public abstract boolean isAssignableFrom(ResolvedType other);
+
+ public abstract boolean isAssignableFrom(ResolvedType other, boolean allowMissing);
+
+ /**
+ * Determines if values of another type could possibly be cast to this type. The rules followed are from JLS 2ed 5.5,
+ * "Casting Conversion".
+ * <p/>
+ * <p>
+ * This method should be commutative, i.e., for all UnresolvedType a, b and all World w:
+ * <p/>
+ * <blockquote>
+ *
+ * <pre>
+ * a.isCoerceableFrom(b, w) == b.isCoerceableFrom(a, w)
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @param other the other type
+ * @param world the {@link World} in which the possible coersion should be checked.
+ * @return true iff values of other could possibly be cast to this type.
+ * @throws NullPointerException if other is null.
+ */
+ public abstract boolean isCoerceableFrom(ResolvedType other);
+
+ public boolean needsNoConversionFrom(ResolvedType o) {
+ return isAssignableFrom(o);
+ }
+
+ public String getSignatureForAttribute() {
+ return signature; // Assume if this is being called that it is for a
+ // simple type (eg. void, int, etc)
+ }
+
+ private FuzzyBoolean parameterizedWithTypeVariable = FuzzyBoolean.MAYBE;
+
+ /**
+ * return true if the parameterization of this type includes a member type variable. Member type variables occur in generic
+ * methods/ctors.
+ */
+ public boolean isParameterizedWithTypeVariable() {
+ // MAYBE means we haven't worked it out yet...
+ if (parameterizedWithTypeVariable == FuzzyBoolean.MAYBE) {
+
+ // if there are no type parameters then we cant be...
+ if (typeParameters == null || typeParameters.length == 0) {
+ parameterizedWithTypeVariable = FuzzyBoolean.NO;
+ return false;
+ }
+
+ for (int i = 0; i < typeParameters.length; i++) {
+ ResolvedType aType = (ResolvedType) typeParameters[i];
+ if (aType.isTypeVariableReference()
+ // Changed according to the problems covered in bug 222648
+ // Don't care what kind of type variable - the fact that there
+ // is one
+ // at all means we can't risk caching it against we get confused
+ // later
+ // by another variation of the parameterization that just
+ // happens to
+ // use the same type variable name
+
+ // assume the worst - if its definetly not a type declared one,
+ // it could be anything
+ // && ((TypeVariableReference)aType).getTypeVariable().
+ // getDeclaringElementKind()!=TypeVariable.TYPE
+ ) {
+ parameterizedWithTypeVariable = FuzzyBoolean.YES;
+ return true;
+ }
+ if (aType.isParameterizedType()) {
+ boolean b = aType.isParameterizedWithTypeVariable();
+ if (b) {
+ parameterizedWithTypeVariable = FuzzyBoolean.YES;
+ return true;
+ }
+ }
+ if (aType.isGenericWildcard()) {
+ BoundedReferenceType boundedRT = (BoundedReferenceType) aType;
+ if (boundedRT.isExtends()) {
+ boolean b = false;
+ UnresolvedType upperBound = boundedRT.getUpperBound();
+ if (upperBound.isParameterizedType()) {
+ b = ((ResolvedType) upperBound).isParameterizedWithTypeVariable();
+ } else if (upperBound.isTypeVariableReference()
+ && ((TypeVariableReference) upperBound).getTypeVariable().getDeclaringElementKind() == TypeVariable.METHOD) {
+ b = true;
+ }
+ if (b) {
+ parameterizedWithTypeVariable = FuzzyBoolean.YES;
+ return true;
+ }
+ // FIXME asc need to check additional interface bounds
+ }
+ if (boundedRT.isSuper()) {
+ boolean b = false;
+ UnresolvedType lowerBound = boundedRT.getLowerBound();
+ if (lowerBound.isParameterizedType()) {
+ b = ((ResolvedType) lowerBound).isParameterizedWithTypeVariable();
+ } else if (lowerBound.isTypeVariableReference()
+ && ((TypeVariableReference) lowerBound).getTypeVariable().getDeclaringElementKind() == TypeVariable.METHOD) {
+ b = true;
+ }
+ if (b) {
+ parameterizedWithTypeVariable = FuzzyBoolean.YES;
+ return true;
+ }
+ }
+ }
+ }
+ parameterizedWithTypeVariable = FuzzyBoolean.NO;
+ }
+ return parameterizedWithTypeVariable.alwaysTrue();
+ }
+
+ protected boolean ajMembersNeedParameterization() {
+ if (isParameterizedType()) {
+ return true;
+ }
+ ResolvedType superclass = getSuperclass();
+ if (superclass != null && !superclass.isMissing()) {
+ return superclass.ajMembersNeedParameterization();
+ }
+ return false;
+ }
+
+ protected Map<String, UnresolvedType> getAjMemberParameterizationMap() {
+ Map<String, UnresolvedType> myMap = getMemberParameterizationMap();
+ if (myMap.isEmpty()) {
+ // might extend a parameterized aspect that we also need to
+ // consider...
+ if (getSuperclass() != null) {
+ return getSuperclass().getAjMemberParameterizationMap();
+ }
+ }
+ return myMap;
+ }
+
+ public void setBinaryPath(String binaryPath) {
+ this.binaryPath = binaryPath;
+ }
+
+ /**
+ * Returns the path to the jar or class file from which this binary aspect came or null if not a binary aspect
+ */
+ public String getBinaryPath() {
+ return binaryPath;
+ }
+
+ /**
+ * Undo any temporary modifications to the type (for example it may be holding annotations temporarily whilst some matching is
+ * occurring - These annotations will be added properly during weaving but sometimes for type completion they need to be held
+ * here for a while).
+ */
+ public void ensureConsistent() {
+ // Nothing to do for anything except a ReferenceType
+ }
+
+ /**
+ * For an annotation type, this will return if it is marked with @Inherited
+ */
+ public boolean isInheritedAnnotation() {
+ ensureAnnotationBitsInitialized();
+ return (bits & AnnotationMarkedInherited) != 0;
+ }
+
+ /*
+ * Setup the bitflags if they have not already been done.
+ */
+ private void ensureAnnotationBitsInitialized() {
+ if ((bits & AnnotationBitsInitialized) == 0) {
+ bits |= AnnotationBitsInitialized;
+ // Is it marked @Inherited?
+ if (hasAnnotation(UnresolvedType.AT_INHERITED)) {
+ bits |= AnnotationMarkedInherited;
+ }
+ }
+ }
+
+ private boolean hasNewParentMungers() {
+ if ((bits & MungersAnalyzed) == 0) {
+ bits |= MungersAnalyzed;
+ for (ConcreteTypeMunger munger : interTypeMungers) {
+ ResolvedTypeMunger resolvedTypeMunger = munger.getMunger();
+ if (resolvedTypeMunger != null && resolvedTypeMunger.getKind() == ResolvedTypeMunger.Parent) {
+ bits |= HasParentMunger;
+ }
+ }
+ }
+ return (bits & HasParentMunger) != 0;
+ }
+
+ public void tagAsTypeHierarchyComplete() {
+ if (isParameterizedOrRawType()) {
+ ReferenceType genericType = this.getGenericType();
+ genericType.tagAsTypeHierarchyComplete();
+ return;
+ }
+ bits |= TypeHierarchyCompleteBit;
+ }
+
+ public boolean isTypeHierarchyComplete() {
+ if (isParameterizedOrRawType()) {
+ return this.getGenericType().isTypeHierarchyComplete();
+ }
+ return (bits & TypeHierarchyCompleteBit) != 0;
+ }
+
+ /**
+ * return the weaver version used to build this type - defaults to the most recent version unless discovered otherwise.
+ *
+ * @return the (major) version, {@link WeaverVersionInfo}
+ */
+ public int getCompilerVersion() {
+ return WeaverVersionInfo.getCurrentWeaverMajorVersion();
+ }
+
+ public boolean isPrimitiveArray() {
+ return false;
+ }
+
+ public boolean isGroovyObject() {
+ if ((bits & GroovyObjectInitialized) == 0) {
+ ResolvedType[] intfaces = getDeclaredInterfaces();
+ boolean done = false;
+ // TODO do we need to walk more of these? (i.e. the interfaces interfaces and supertypes supertype). Check what groovy
+ // does in the case where a hierarchy is involved and there are types in between GroovyObject/GroovyObjectSupport and
+ // the type
+ if (intfaces != null) {
+ for (ResolvedType intface : intfaces) {
+ if (intface.getName().equals("groovy.lang.GroovyObject")) {
+ bits |= IsGroovyObject;
+ done = true;
+ break;
+ }
+ }
+ }
+ if (!done) {
+ // take a look at the supertype
+ if (getSuperclass().getName().equals("groovy.lang.GroovyObjectSupport")) {
+ bits |= IsGroovyObject;
+ }
+ }
+ bits |= GroovyObjectInitialized;
+ }
+ return (bits & IsGroovyObject) != 0;
+ }
+
+ public boolean isPrivilegedAspect() {
+ if ((bits & IsPrivilegedBitInitialized) == 0) {
+ AnnotationAJ privilegedAnnotation = getAnnotationOfType(UnresolvedType.AJC_PRIVILEGED);
+ if (privilegedAnnotation != null) {
+ bits |= IsPrivilegedAspect;
+ }
+ // TODO do we need to reset this bit if the annotations are set again ?
+ bits |= IsPrivilegedBitInitialized;
+ }
+ return (bits & IsPrivilegedAspect) != 0;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedTypeMunger.java
new file mode 100644
index 000000000..2ba3cbc36
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ResolvedTypeMunger.java
@@ -0,0 +1,499 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Alexandre Vasseur @AspectJ ITDs
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.SourceLocation;
+import org.aspectj.util.TypeSafeEnum;
+
+/**
+ * This is an abstraction over method/field introduction. It might not have the chops to handle other inter-type declarations. This
+ * is the thing that is used on the eclipse side and serialized into a ConcreteTypeMunger.
+ */
+public abstract class ResolvedTypeMunger {
+
+ protected Kind kind;
+ protected ResolvedMember signature;
+
+ /**
+ * The declared signature is filled in when a type munger is parameterized for application to a particular type. It represents
+ * the signature originally declared in the source file.
+ */
+ protected ResolvedMember declaredSignature;
+
+ // This list records the occurences (in order) of any names specified in the <>
+ // for a target type for the ITD. So for example, for List<C,B,A> this list
+ // will be C,B,A - the list is used later to map other occurrences of C,B,A
+ // across the intertype declaration to the right type variables in the generic
+ // type upon which the itd is being made.
+ // might need serializing the class file for binary weaving.
+ protected List<String> typeVariableAliases;
+
+ private Set<ResolvedMember> superMethodsCalled = Collections.emptySet();
+
+ private ISourceLocation location;
+
+ private ResolvedType onType = null;
+
+ public ResolvedTypeMunger(Kind kind, ResolvedMember signature) {
+ this.kind = kind;
+ this.signature = signature;
+ UnresolvedType declaringType = signature != null ? signature.getDeclaringType() : null;
+ if (declaringType != null) {
+ if (declaringType.isRawType()) {
+ throw new IllegalStateException("Use generic type, not raw type");
+ }
+ if (declaringType.isParameterizedType()) {
+ throw new IllegalStateException("Use generic type, not parameterized type");
+ }
+ }
+ // boolean aChangeOccurred = false;
+ //
+ // UnresolvedType rt = signature.getReturnType();
+ // if (rt.isParameterizedType() || rt.isGenericType()) {rt = rt.getRawType();aChangeOccurred=true;}
+ // UnresolvedType[] pt = signature.getParameterTypes();
+ // for (int i = 0; i < pt.length; i++) {
+ // if (pt[i].isParameterizedType() || pt[i].isGenericType()) { pt[i] = pt[i].getRawType();aChangeOccurred=true;}
+ // }
+ // if (aChangeOccurred) {
+ // this.signature = new
+ // ResolvedMemberImpl(signature.getKind(),signature.getDeclaringType(),signature.getModifiers(),rt,signature
+ // .getName(),pt,signature.getExceptions());
+ // }
+ }
+
+ public void setSourceLocation(ISourceLocation isl) {
+ location = isl;
+ }
+
+ public ISourceLocation getSourceLocation() {
+ return location;
+ }
+
+ // ----
+
+ // fromType is guaranteed to be a non-abstract aspect
+ // public ConcreteTypeMunger concretize(World world, ResolvedType aspectType) {
+ //
+ // ConcreteTypeMunger munger = world.concreteTypeMunger(this, aspectType);
+ // return munger;
+ // }
+
+ public boolean matches(ResolvedType matchType, ResolvedType aspectType) {
+ if (onType == null) {
+ onType = matchType.getWorld().resolve(getDeclaringType());
+ if (onType.isRawType()) {
+ onType = onType.getGenericType();
+ }
+ }
+ // System.err.println("matching: " + this + " to " + matchType + " onType = " + onType);
+ if (matchType.equals(onType)) {
+ if (!onType.isExposedToWeaver()) {
+ // if the onType is an interface, and it already has the member we are about
+ // to munge, then this is ok...
+ boolean ok = (onType.isInterface() && (onType.lookupMemberWithSupersAndITDs(getSignature()) != null));
+
+ if (!ok && onType.getWeaverState() == null) {
+ if (matchType.getWorld().getLint().typeNotExposedToWeaver.isEnabled()) {
+ matchType.getWorld().getLint().typeNotExposedToWeaver.signal(matchType.getName(), signature
+ .getSourceLocation());
+ }
+ }
+ }
+ return true;
+ }
+ // System.err.println("NO MATCH DIRECT");
+
+ if (onType.isInterface()) {
+ return matchType.isTopmostImplementor(onType);
+ } else {
+ return false;
+ }
+ }
+
+ // ----
+
+ @Override
+ public String toString() {
+ return "ResolvedTypeMunger(" + getKind() + ", " + getSignature() + ")";
+ // .superMethodsCalled + ")";
+ }
+
+ // ----
+
+ public static ResolvedTypeMunger read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ Kind kind = Kind.read(s);
+ if (kind == Field) {
+ return NewFieldTypeMunger.readField(s, context);
+ } else if (kind == Method) {
+ return NewMethodTypeMunger.readMethod(s, context);
+ } else if (kind == Constructor) {
+ return NewConstructorTypeMunger.readConstructor(s, context);
+ } else if (kind == MethodDelegate) {
+ return MethodDelegateTypeMunger.readMethod(s, context, false);
+ } else if (kind == FieldHost) {
+ return MethodDelegateTypeMunger.FieldHostTypeMunger.readFieldHost(s, context);
+ } else if (kind == MethodDelegate2) {
+ return MethodDelegateTypeMunger.readMethod(s, context, true);
+ } else if (kind == InnerClass) {
+ return NewMemberClassTypeMunger.readInnerClass(s, context);
+ } else {
+ throw new RuntimeException("unimplemented");
+ }
+ }
+
+ protected static Set<ResolvedMember> readSuperMethodsCalled(VersionedDataInputStream s) throws IOException {
+ Set<ResolvedMember> ret = new HashSet<ResolvedMember>();
+ int n = -1;
+ if (s.isAtLeast169()) {
+ n = s.readByte();
+ } else {
+ n = s.readInt();
+ }
+ if (n < 0) {
+ throw new BCException("Problem deserializing type munger");
+ }
+ for (int i = 0; i < n; i++) {
+ ret.add(ResolvedMemberImpl.readResolvedMember(s, null));
+ }
+ return ret;
+ }
+
+ protected final void writeSuperMethodsCalled(CompressingDataOutputStream s) throws IOException {
+ if (superMethodsCalled == null || superMethodsCalled.size() == 0) {
+ s.writeByte(0);
+ return;
+ }
+ List<ResolvedMember> ret = new ArrayList<ResolvedMember>(superMethodsCalled);
+ Collections.sort(ret);
+ int n = ret.size();
+ s.writeByte(n);
+ for (ResolvedMember m : ret) {
+ m.write(s);
+ }
+ }
+
+ protected static ISourceLocation readSourceLocation(VersionedDataInputStream s) throws IOException {
+ // Location persistence for type mungers was added after 1.2.1 was shipped...
+ if (s.getMajorVersion() < AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+ return null;
+ }
+ SourceLocation ret = null;
+ ObjectInputStream ois = null;
+ try {
+ // This logic copes with the location missing from the attribute - an EOFException will
+ // occur on the next line and we ignore it.
+ byte b = 0;
+ // if we aren't on 1.6.9 or we are on 1.6.9 but not compressed, then read as object stream
+ if (!s.isAtLeast169() || (b = s.readByte()) == 0) {
+ ois = new ObjectInputStream(s);
+ boolean validLocation = (Boolean) ois.readObject();
+ if (validLocation) {
+ File f = (File) ois.readObject();
+ Integer ii = (Integer) ois.readObject();
+ Integer offset = (Integer) ois.readObject();
+ ret = new SourceLocation(f, ii.intValue());
+ ret.setOffset(offset.intValue());
+ }
+ } else {
+ boolean validLocation = b == 2;
+ if (validLocation) {
+ String path = s.readUtf8(s.readShort());
+ File f = new File(path);
+ ret = new SourceLocation(f, s.readInt());
+ int offset = s.readInt();
+ ret.setOffset(offset);
+ }
+ }
+
+ } catch (EOFException eof) {
+ return null; // This exception occurs if processing an 'old style' file where the
+ // type munger attributes don't include the source location.
+ } catch (IOException ioe) {
+ // Something went wrong, maybe this is an 'old style' file that doesnt attach locations to mungers?
+ // (but I thought that was just an EOFException?)
+ ioe.printStackTrace();
+ return null;
+ } catch (ClassNotFoundException e) {
+ } finally {
+ if (ois != null) {
+ ois.close();
+ }
+ }
+ return ret;
+ }
+
+ protected final void writeSourceLocation(CompressingDataOutputStream s) throws IOException {
+ if (s.canCompress()) {
+ s.writeByte(1 + (location == null ? 0 : 1)); // 1==compressed no location 2==compressed with location
+ if (location != null) {
+ s.writeCompressedPath(location.getSourceFile().getPath());
+ s.writeInt(location.getLine());
+ s.writeInt(location.getOffset());
+ }
+ } else {
+ s.writeByte(0);
+ ObjectOutputStream oos = new ObjectOutputStream(s);
+ oos.writeObject(new Boolean(location != null));
+ if (location != null) {
+ oos.writeObject(location.getSourceFile());
+ oos.writeObject(new Integer(location.getLine()));
+ oos.writeObject(new Integer(location.getOffset()));
+ }
+ oos.flush();
+ oos.close();
+ }
+ }
+
+ public abstract void write(CompressingDataOutputStream s) throws IOException;
+
+ public Kind getKind() {
+ return kind;
+ }
+
+ public static class Kind extends TypeSafeEnum {
+ /* private */Kind(String name, int key) {
+ super(name, key);
+ }
+
+ public static Kind read(DataInputStream s) throws IOException {
+ int key = s.readByte();
+ switch (key) {
+ case 1:
+ return Field;
+ case 2:
+ return Method;
+ case 5:
+ return Constructor;
+ case 9:
+ return MethodDelegate;
+ case 10:
+ return FieldHost;
+ case 11:
+ return MethodDelegate2;
+ case 12:
+ return InnerClass;
+ }
+ throw new BCException("bad kind: " + key);
+ }
+
+ @Override
+ public String toString() {
+ // we want MethodDelegate to appear as Method in WeaveInfo messages
+ // TODO we may want something for fieldhost ?
+ if (getName().startsWith(MethodDelegate.getName())) {// startsWith will cover MethodDelegate2 as well
+ return Method.toString();
+ } else {
+ return super.toString();
+ }
+ }
+ }
+
+ // ---- fields
+
+ public static final Kind Field = new Kind("Field", 1);
+ public static final Kind Method = new Kind("Method", 2);
+ public static final Kind Constructor = new Kind("Constructor", 5);
+ // not serialized, only created during concretization of aspects
+ public static final Kind PerObjectInterface = new Kind("PerObjectInterface", 3);
+ public static final Kind PrivilegedAccess = new Kind("PrivilegedAccess", 4);
+ public static final Kind Parent = new Kind("Parent", 6);
+ // PTWIMPL not serialized, used during concretization of aspects
+ public static final Kind PerTypeWithinInterface = new Kind("PerTypeWithinInterface", 7);
+ public static final Kind AnnotationOnType = new Kind("AnnotationOnType", 8); // not serialized
+ public static final Kind MethodDelegate = new Kind("MethodDelegate", 9);// serialized, @AJ ITDs
+ public static final Kind FieldHost = new Kind("FieldHost", 10);// serialized, @AJ ITDs
+ public static final Kind MethodDelegate2 = new Kind("MethodDelegate2", 11);// serialized, @AJ ITDs
+ public static final Kind InnerClass = new Kind("InnerClass", 12);
+
+ public static final String SUPER_DISPATCH_NAME = "superDispatch";
+
+ public void setSuperMethodsCalled(Set<ResolvedMember> c) {
+ this.superMethodsCalled = c;
+ }
+
+ public Set<ResolvedMember> getSuperMethodsCalled() {
+ return superMethodsCalled;
+ }
+
+ public ResolvedMember getSignature() {
+ return signature;
+ }
+
+ // ----
+
+ public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedType aspectType) {
+ if ((getSignature() != null) && getSignature().isPublic() && member.equals(getSignature())) {
+ return getSignature();
+ }
+
+ return null;
+ }
+
+ public boolean changesPublicSignature() {
+ return kind == Field || kind == Method || kind == Constructor;
+ }
+
+ public boolean needsAccessToTopmostImplementor() {
+ if (kind == Field) {
+ return true;
+ } else if (kind == Method) {
+ return !signature.isAbstract();
+ } else {
+ return false;
+ }
+ }
+
+ protected static List<String> readInTypeAliases(VersionedDataInputStream s) throws IOException {
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+ int count = -1;
+ if (s.isAtLeast169()) {
+ count = s.readByte();
+ } else {
+ count = s.readInt();
+ }
+ if (count != 0) {
+ List<String> aliases = new ArrayList<String>();
+ for (int i = 0; i < count; i++) {
+ aliases.add(s.readUTF());
+ }
+ return aliases;
+ }
+ }
+ return null;
+ }
+
+ protected final void writeOutTypeAliases(DataOutputStream s) throws IOException {
+ // Write any type variable aliases
+ if (typeVariableAliases == null || typeVariableAliases.size() == 0) {
+ s.writeByte(0);
+ } else {
+ s.writeByte(typeVariableAliases.size());
+ for (String element : typeVariableAliases) {
+ s.writeUTF(element);
+ }
+ }
+ }
+
+ public List<String> getTypeVariableAliases() {
+ return typeVariableAliases;
+ }
+
+ protected void setTypeVariableAliases(List<String> typeVariableAliases) {
+ this.typeVariableAliases = typeVariableAliases;
+ }
+
+ public boolean hasTypeVariableAliases() {
+ return (typeVariableAliases != null && typeVariableAliases.size() > 0);
+ }
+
+ /**
+ * return true if type variables are specified with the target type for this ITD. e.g. this would return true:
+ * "int I<A,B>.m() { return 42; }"
+ */
+ public boolean sharesTypeVariablesWithGenericType() {
+ return (typeVariableAliases != null && typeVariableAliases.size() > 0);
+ }
+
+ /**
+ * Parameterizes a resolved type munger for a particular usage of its target type (this is used when the target type is generic
+ * and the ITD shares type variables with the target) see ConcreteTypeMunger.parameterizedFor
+ */
+ public ResolvedTypeMunger parameterizedFor(ResolvedType target) {
+ throw new BCException("Dont call parameterizedFor on a type munger of this kind: " + this.getClass());
+ }
+
+ // ResolvedType genericType = target;
+ // if (target.isRawType() || target.isParameterizedType()) genericType = genericType.getGenericType();
+ // ResolvedMember parameterizedSignature = null;
+ // // If we are parameterizing it for a generic type, we just need to 'swap the letters' from the ones used
+ // // in the original ITD declaration to the ones used in the actual target type declaration.
+ // if (target.isGenericType()) {
+ // TypeVariable vars[] = target.getTypeVariables();
+ // UnresolvedTypeVariableReferenceType[] varRefs = new UnresolvedTypeVariableReferenceType[vars.length];
+ // for (int i = 0; i < vars.length; i++) {
+ // varRefs[i] = new UnresolvedTypeVariableReferenceType(vars[i]);
+ // }
+ // parameterizedSignature = getSignature().parameterizedWith(varRefs,genericType,true,typeVariableAliases);
+ // } else {
+ // // For raw and 'normal' parameterized targets (e.g. Interface, Interface<String>)
+ // parameterizedSignature =
+ // getSignature().parameterizedWith(target.getTypeParameters(),genericType,target.isParameterizedType(),typeVariableAliases);
+ // }
+ // return new NewMethodTypeMunger(parameterizedSignature,getSuperMethodsCalled(),typeVariableAliases);
+ // }
+ // /**
+ // * see ResolvedTypeMunger.parameterizedFor(ResolvedType)
+ // */
+ // public ResolvedTypeMunger parameterizedFor(ResolvedType target) {
+ // ResolvedType genericType = target;
+ // if (target.isRawType() || target.isParameterizedType()) genericType = genericType.getGenericType();
+ // ResolvedMember parameterizedSignature =
+ // getSignature().parameterizedWith(target.getTypeParameters(),genericType,target.isParameterizedType(),typeVariableAliases);
+ // return new NewFieldTypeMunger(parameterizedSignature,getSuperMethodsCalled(),typeVariableAliases);
+ // }
+
+ public void setDeclaredSignature(ResolvedMember rm) {
+ declaredSignature = rm;
+ }
+
+ public ResolvedMember getDeclaredSignature() {
+ return declaredSignature;
+ }
+
+ /**
+ * A late munger has to be done after shadow munging since which shadows are matched can affect the operation of the late
+ * munger. e.g. perobjectinterfacemunger
+ */
+ public boolean isLateMunger() {
+ return false;
+ }
+
+ /**
+ * Some type mungers are created purely to help with the implementation of shadow mungers. For example to support the cflow()
+ * pointcut we create a new cflow field in the aspect, and that is added via a BcelCflowCounterFieldAdder.
+ *
+ * During compilation we need to compare sets of type mungers, and if some only come into existence after the 'shadowy' type
+ * things have been processed, we need to ignore them during the comparison.
+ *
+ * Returning true from this method indicates the type munger exists to support 'shadowy' stuff - and so can be ignored in some
+ * comparison.
+ */
+ public boolean existsToSupportShadowMunging() {
+ return false;
+ }
+
+ public ResolvedTypeMunger parameterizeWith(Map<String, UnresolvedType> m, World w) {
+ throw new BCException("Dont call parameterizeWith() on a type munger of this kind: " + this.getClass());
+ }
+
+ public UnresolvedType getDeclaringType() {
+ return getSignature().getDeclaringType();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/RuntimeVersion.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/RuntimeVersion.java
new file mode 100644
index 000000000..0cf90a9a2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/RuntimeVersion.java
@@ -0,0 +1,47 @@
+/* *******************************************************************
+ * Copyright (c) 2018 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Captures important runtime versions. Typically new versions are added here if something
+ * changes in the runtime and the code generation may be able to do something different
+ * (more optimal) for a later runtime.
+ *
+ * @author Andy Clement
+ */
+public enum RuntimeVersion {
+
+ V1_2("1.2"), V1_5("1.5"), V1_6_10("1.6.10"), V1_9("1.9");
+
+ private String[] aliases = null;
+
+ RuntimeVersion(String... aliases) {
+ this.aliases = aliases;
+ }
+
+ public static RuntimeVersion getVersionFor(String version) {
+ for (RuntimeVersion candidateVersion: values()) {
+ if (candidateVersion.name().equals(version)) {
+ return candidateVersion;
+ }
+ if (candidateVersion.aliases != null) {
+ for (String alias: candidateVersion.aliases) {
+ if (alias.equals(version)) {
+ return candidateVersion;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public boolean isThisVersionOrLater(RuntimeVersion version) {
+ return this.compareTo(version) >= 0;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Shadow.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Shadow.java
new file mode 100644
index 000000000..587d19c15
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Shadow.java
@@ -0,0 +1,687 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.PartialOrder;
+import org.aspectj.util.TypeSafeEnum;
+import org.aspectj.weaver.ast.Var;
+
+/*
+ * The superclass of anything representing a the shadow of a join point. A shadow represents
+ * some bit of code, and encompasses both entry and exit from that code. All shadows have a kind
+ * and a signature.
+ */
+
+public abstract class Shadow {
+
+ // every Shadow has a unique id, doesn't matter if it wraps...
+ private static int nextShadowID = 100; // easier to spot than zero. // OPTIMIZE is this a bug? static?
+
+ private final Kind kind;
+ private final Member signature;
+ private Member matchingSignature;
+ private ResolvedMember resolvedSignature;
+ protected final Shadow enclosingShadow;
+ protected List<ShadowMunger> mungers = Collections.emptyList();
+
+ public int shadowId = nextShadowID++; // every time we build a shadow, it gets a new id
+
+ // ----
+ protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
+ this.kind = kind;
+ this.signature = signature;
+ this.enclosingShadow = enclosingShadow;
+ }
+
+ // ----
+
+ public abstract World getIWorld();
+
+ public List<ShadowMunger> getMungers() {
+ return mungers;
+ }
+
+ /**
+ * could this(*) pcd ever match
+ */
+ public final boolean hasThis() {
+ if (getKind().neverHasThis()) {
+ return false;
+ } else if (getKind().isEnclosingKind()) {
+ return !Modifier.isStatic(getSignature().getModifiers());
+ } else if (enclosingShadow == null) {
+ return false;
+ } else {
+ return enclosingShadow.hasThis();
+ }
+ }
+
+ /**
+ * the type of the this object here
+ *
+ * @throws IllegalStateException if there is no this here
+ */
+ public final UnresolvedType getThisType() {
+ if (!hasThis()) {
+ throw new IllegalStateException("no this");
+ }
+ if (getKind().isEnclosingKind()) {
+ return getSignature().getDeclaringType();
+ } else {
+ return enclosingShadow.getThisType();
+ }
+ }
+
+ /**
+ * a var referencing this
+ *
+ * @throws IllegalStateException if there is no target here
+ */
+ public abstract Var getThisVar();
+
+ /**
+ * could target(*) pcd ever match
+ */
+ public final boolean hasTarget() {
+ if (getKind().neverHasTarget()) {
+ return false;
+ } else if (getKind().isTargetSameAsThis()) {
+ return hasThis();
+ } else {
+ return !Modifier.isStatic(getSignature().getModifiers());
+ }
+ }
+
+ /**
+ * the type of the target object here
+ *
+ * @throws IllegalStateException if there is no target here
+ */
+ public final UnresolvedType getTargetType() {
+ if (!hasTarget()) {
+ throw new IllegalStateException("no target");
+ }
+ return getSignature().getDeclaringType();
+ }
+
+ /**
+ * a var referencing the target
+ *
+ * @throws IllegalStateException if there is no target here
+ */
+ public abstract Var getTargetVar();
+
+ public UnresolvedType[] getArgTypes() {
+ if (getKind() == FieldSet) {
+ return new UnresolvedType[] { getSignature().getReturnType() };
+ }
+ return getSignature().getParameterTypes();
+ }
+
+ public boolean isShadowForArrayConstructionJoinpoint() {
+ return (getKind() == ConstructorCall && signature.getDeclaringType().isArray());
+ }
+
+ public boolean isShadowForMonitor() {
+ return (getKind() == SynchronizationLock || getKind() == SynchronizationUnlock);
+ }
+
+ // will return the right length array of ints depending on how many dimensions the array has
+ public ResolvedType[] getArgumentTypesForArrayConstructionShadow() {
+ String s = signature.getDeclaringType().getSignature();
+ int pos = s.indexOf("[");
+ int dims = 1;
+ while (pos < s.length()) {
+ pos++;
+ if (pos < s.length()) {
+ dims += (s.charAt(pos) == '[' ? 1 : 0);
+ }
+ }
+ ResolvedType intType = UnresolvedType.INT.resolve(this.getIWorld());
+ if (dims == 1) {
+ return new ResolvedType[] { intType };
+ }
+ ResolvedType[] someInts = new ResolvedType[dims];
+ for (int i = 0; i < dims; i++) {
+ someInts[i] = intType;
+ }
+ return someInts;
+ }
+
+ public UnresolvedType[] getGenericArgTypes() {
+ if (isShadowForArrayConstructionJoinpoint()) {
+ return getArgumentTypesForArrayConstructionShadow();
+ }
+ if (isShadowForMonitor()) {
+ return UnresolvedType.ARRAY_WITH_JUST_OBJECT;
+ }
+ if (getKind() == FieldSet) {
+ return new UnresolvedType[] { getResolvedSignature().getGenericReturnType() };
+ }
+ return getResolvedSignature().getGenericParameterTypes();
+ }
+
+ public UnresolvedType getArgType(int arg) {
+ if (getKind() == FieldSet) {
+ return getSignature().getReturnType();
+ }
+ return getSignature().getParameterTypes()[arg];
+ }
+
+ public int getArgCount() {
+ if (getKind() == FieldSet) {
+ return 1;
+ }
+ return getSignature().getParameterTypes().length;
+ }
+
+ // /**
+ // * Return name of the argument at position 'i' at this shadow. This does not make sense for all shadows - but can be useful in
+ // * the case of, for example, method-execution.
+ // *
+ // * @return null if it cannot be determined
+ // */
+ // public String getArgName(int i, World w) {
+ // String[] names = getSignature().getParameterNames(w);
+ // if (names == null || i >= names.length)
+ // return null;
+ // return names[i];
+ // }
+
+ public abstract UnresolvedType getEnclosingType();
+
+ public abstract Var getArgVar(int i);
+
+ public abstract Var getThisJoinPointVar();
+
+ public abstract Var getThisJoinPointStaticPartVar();
+
+ public abstract Var getThisEnclosingJoinPointStaticPartVar();
+
+ public abstract Var getThisAspectInstanceVar(ResolvedType aspectType);
+
+ // annotation variables
+ public abstract Var getKindedAnnotationVar(UnresolvedType forAnnotationType);
+
+ public abstract Var getWithinAnnotationVar(UnresolvedType forAnnotationType);
+
+ public abstract Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType);
+
+ public abstract Var getThisAnnotationVar(UnresolvedType forAnnotationType);
+
+ public abstract Var getTargetAnnotationVar(UnresolvedType forAnnotationType);
+
+ public abstract Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType);
+
+ public abstract Member getEnclosingCodeSignature();
+
+ /**
+ * returns the kind of shadow this is, representing what happens under this shadow
+ */
+ public Kind getKind() {
+ return kind;
+ }
+
+ /**
+ * returns the signature of the thing under this shadow
+ */
+ public Member getSignature() {
+ return signature;
+ }
+
+ /**
+ * returns the signature of the thing under this shadow, with any synthetic arguments removed
+ */
+ public Member getMatchingSignature() {
+ return matchingSignature != null ? matchingSignature : signature;
+ }
+
+ public void setMatchingSignature(Member member) {
+ this.matchingSignature = member;
+ }
+
+ /**
+ * returns the resolved signature of the thing under this shadow
+ *
+ */
+ public ResolvedMember getResolvedSignature() {
+ if (resolvedSignature == null) {
+ resolvedSignature = signature.resolve(getIWorld());
+ }
+ return resolvedSignature;
+ }
+
+ public UnresolvedType getReturnType() {
+ if (kind == ConstructorCall) {
+ return getSignature().getDeclaringType();
+ } else if (kind == FieldSet) {
+ return UnresolvedType.VOID;
+ } else if (kind == SynchronizationLock || kind == SynchronizationUnlock) {
+ return UnresolvedType.VOID;
+ }
+ return getResolvedSignature().getGenericReturnType();
+ }
+
+ public static String METHOD_EXECUTION = "method-execution";
+ public static String METHOD_CALL = "method-call";
+ public static String CONSTRUCTOR_EXECUTION = "constructor-execution";
+ public static String CONSTRUCTOR_CALL = "constructor-call";
+ public static String FIELD_GET = "field-get";
+ public static String FIELD_SET = "field-set";
+ public static String STATICINITIALIZATION = "staticinitialization";
+ public static String PREINITIALIZATION = "preinitialization";
+ public static String INITIALIZATION = "initialization";
+ public static String EXCEPTION_HANDLER = "exception-handler";
+ public static String SYNCHRONIZATION_LOCK = "lock";
+ public static String SYNCHRONIZATION_UNLOCK = "unlock";
+ public static String ADVICE_EXECUTION = "adviceexecution";
+
+ /**
+ * These names are the ones that will be returned by thisJoinPoint.getKind() Those need to be documented somewhere
+ */
+ public static final Kind MethodCall = new Kind(METHOD_CALL, 1, true);
+ public static final Kind ConstructorCall = new Kind(CONSTRUCTOR_CALL, 2, true);
+ public static final Kind MethodExecution = new Kind(METHOD_EXECUTION, 3, false);
+ public static final Kind ConstructorExecution = new Kind(CONSTRUCTOR_EXECUTION, 4, false);
+ public static final Kind FieldGet = new Kind(FIELD_GET, 5, true);
+ public static final Kind FieldSet = new Kind(FIELD_SET, 6, true);
+ public static final Kind StaticInitialization = new Kind(STATICINITIALIZATION, 7, false);
+ public static final Kind PreInitialization = new Kind(PREINITIALIZATION, 8, false);
+ public static final Kind AdviceExecution = new Kind(ADVICE_EXECUTION, 9, false);
+ public static final Kind Initialization = new Kind(INITIALIZATION, 10, false);
+ public static final Kind ExceptionHandler = new Kind(EXCEPTION_HANDLER, 11, true);
+ public static final Kind SynchronizationLock = new Kind(SYNCHRONIZATION_LOCK, 12, true);
+ public static final Kind SynchronizationUnlock = new Kind(SYNCHRONIZATION_UNLOCK, 13, true);
+
+ // Bits here are 1<<(Kind.getKey()) - and unfortunately keys didn't start at zero so bits here start at 2
+ public static final int MethodCallBit = 0x002;
+ public static final int ConstructorCallBit = 0x004;
+ public static final int MethodExecutionBit = 0x008;
+ public static final int ConstructorExecutionBit = 0x010;
+ public static final int FieldGetBit = 0x020;
+ public static final int FieldSetBit = 0x040;
+ public static final int StaticInitializationBit = 0x080;
+ public static final int PreInitializationBit = 0x100;
+ public static final int AdviceExecutionBit = 0x200;
+ public static final int InitializationBit = 0x400;
+ public static final int ExceptionHandlerBit = 0x800;
+ public static final int SynchronizationLockBit = 0x1000;
+ public static final int SynchronizationUnlockBit = 0x2000;
+
+ public static final int MAX_SHADOW_KIND = 13;
+ public static final Kind[] SHADOW_KINDS = new Kind[] { MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
+ FieldGet, FieldSet, StaticInitialization, PreInitialization, AdviceExecution, Initialization, ExceptionHandler,
+ SynchronizationLock, SynchronizationUnlock };
+
+ public static final int ALL_SHADOW_KINDS_BITS;
+ public static final int NO_SHADOW_KINDS_BITS;
+
+ static {
+ ALL_SHADOW_KINDS_BITS = 0x3ffe;
+ NO_SHADOW_KINDS_BITS = 0x0000;
+ }
+
+ /**
+ * Return count of how many bits set in the supplied parameter.
+ */
+ public static int howMany(int i) {
+ int count = 0;
+ for (int j = 0; j < SHADOW_KINDS.length; j++) {
+ if ((i & SHADOW_KINDS[j].bit) != 0) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * A type-safe enum representing the kind of shadows
+ */
+ public static final class Kind extends TypeSafeEnum {
+ // private boolean argsOnStack; //XXX unused
+
+ public int bit;
+
+ public Kind(String name, int key, boolean argsOnStack) {
+ super(name, key);
+ bit = 1 << key;
+ // this.argsOnStack = argsOnStack;
+ }
+
+ public String toLegalJavaIdentifier() {
+ return getName().replace('-', '_');
+ }
+
+ public boolean argsOnStack() {
+ return !isTargetSameAsThis();
+ }
+
+ // false for handlers
+ public boolean allowsExtraction() {
+ return true;
+ }
+
+ public boolean isSet(int i) {
+ return (i & bit) != 0;
+ }
+
+ // XXX revisit along with removal of priorities
+ public boolean hasHighPriorityExceptions() {
+ return !isTargetSameAsThis();
+ }
+
+ private final static int hasReturnValueFlag = MethodCallBit | ConstructorCallBit | MethodExecutionBit | FieldGetBit
+ | AdviceExecutionBit;
+
+ /**
+ * These shadow kinds have return values that can be bound in after returning(Dooberry doo) advice.
+ *
+ * @return
+ */
+ public boolean hasReturnValue() {
+ return (bit & hasReturnValueFlag) != 0;
+ }
+
+ private final static int isEnclosingKindFlag = MethodExecutionBit | ConstructorExecutionBit | AdviceExecutionBit
+ | StaticInitializationBit | InitializationBit;
+
+ /**
+ * These are all the shadows that contains other shadows within them and are often directly associated with methods.
+ */
+ public boolean isEnclosingKind() {
+ return (bit & isEnclosingKindFlag) != 0;
+ }
+
+ private final static int isTargetSameAsThisFlag = MethodExecutionBit | ConstructorExecutionBit | StaticInitializationBit
+ | PreInitializationBit | AdviceExecutionBit | InitializationBit;
+
+ public boolean isTargetSameAsThis() {
+ return (bit & isTargetSameAsThisFlag) != 0;
+ }
+
+ private final static int neverHasTargetFlag = ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit
+ | StaticInitializationBit | SynchronizationLockBit | SynchronizationUnlockBit;
+
+ public boolean neverHasTarget() {
+ return (bit & neverHasTargetFlag) != 0;
+ }
+
+ private final static int neverHasThisFlag = PreInitializationBit | StaticInitializationBit;
+
+ public boolean neverHasThis() {
+ return (bit & neverHasThisFlag) != 0;
+ }
+
+ public String getSimpleName() {
+ int dash = getName().lastIndexOf('-');
+ if (dash == -1) {
+ return getName();
+ } else {
+ return getName().substring(dash + 1);
+ }
+ }
+
+ public static Kind read(DataInputStream s) throws IOException {
+ int key = s.readByte();
+ switch (key) {
+ case 1:
+ return MethodCall;
+ case 2:
+ return ConstructorCall;
+ case 3:
+ return MethodExecution;
+ case 4:
+ return ConstructorExecution;
+ case 5:
+ return FieldGet;
+ case 6:
+ return FieldSet;
+ case 7:
+ return StaticInitialization;
+ case 8:
+ return PreInitialization;
+ case 9:
+ return AdviceExecution;
+ case 10:
+ return Initialization;
+ case 11:
+ return ExceptionHandler;
+ case 12:
+ return SynchronizationLock;
+ case 13:
+ return SynchronizationUnlock;
+ }
+ throw new BCException("unknown kind: " + key);
+ }
+ }
+
+ /**
+ * Only does the check if the munger requires it (@AJ aspects don't)
+ *
+ * @param munger
+ * @return
+ */
+ protected boolean checkMunger(ShadowMunger munger) {
+ if (munger.mustCheckExceptions()) {
+ for (Iterator<ResolvedType> i = munger.getThrownExceptions().iterator(); i.hasNext();) {
+ if (!checkCanThrow(munger, i.next())) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ protected boolean checkCanThrow(ShadowMunger munger, ResolvedType resolvedTypeX) {
+ if (getKind() == ExceptionHandler) {
+ // XXX much too lenient rules here, need to walk up exception handlers
+ return true;
+ }
+
+ if (!isDeclaredException(resolvedTypeX, getSignature())) {
+ getIWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_THROW_CHECKED, resolvedTypeX, this), // from
+ // advice
+ // in
+ // \
+ // '"
+ // +
+ // munger
+ // .
+ // +
+ // "\'"
+ // ,
+ getSourceLocation(), munger.getSourceLocation());
+ }
+
+ return true;
+ }
+
+ private boolean isDeclaredException(ResolvedType resolvedTypeX, Member member) {
+ ResolvedType[] excs = getIWorld().resolve(member.getExceptions(getIWorld()));
+ for (int i = 0, len = excs.length; i < len; i++) {
+ if (excs[i].isAssignableFrom(resolvedTypeX)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void addMunger(ShadowMunger munger) {
+ if (checkMunger(munger)) {
+ if (mungers == Collections.EMPTY_LIST) {
+ mungers = new ArrayList<ShadowMunger>();
+ }
+ this.mungers.add(munger);
+ }
+ }
+
+ public final void implement() {
+ sortMungers();
+ if (mungers == null) {
+ return;
+ }
+ prepareForMungers();
+ implementMungers();
+ }
+
+ private void sortMungers() {
+
+ List sorted = PartialOrder.sort(mungers);
+
+ // Bunch of code to work out whether to report xlints for advice that isn't ordered at this Joinpoint
+ possiblyReportUnorderedAdvice(sorted);
+
+ if (sorted == null) {
+ // this means that we have circular dependencies
+ for (ShadowMunger m : mungers) {
+ getIWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.CIRCULAR_DEPENDENCY, this), m.getSourceLocation()));
+ }
+ }
+ mungers = sorted;
+ }
+
+ // not quite optimal... but the xlint is ignore by default
+ private void possiblyReportUnorderedAdvice(List sorted) {
+ if (sorted != null && getIWorld().getLint().unorderedAdviceAtShadow.isEnabled() && mungers.size() > 1) {
+
+ // Stores a set of strings of the form 'aspect1:aspect2' which indicates there is no
+ // precedence specified between the two aspects at this shadow.
+ Set<String> clashingAspects = new HashSet<String>();
+ int max = mungers.size();
+
+ // Compare every pair of advice mungers
+ for (int i = max - 1; i >= 0; i--) {
+ for (int j = 0; j < i; j++) {
+ Object a = mungers.get(i);
+ Object b = mungers.get(j);
+
+ // Make sure they are the right type
+ if (a instanceof Advice && b instanceof Advice) {
+ Advice adviceA = (Advice) a;
+ Advice adviceB = (Advice) b;
+ if (!adviceA.concreteAspect.equals(adviceB.concreteAspect)) {
+ AdviceKind adviceKindA = adviceA.getKind();
+ AdviceKind adviceKindB = adviceB.getKind();
+
+ // make sure they are the nice ones (<6) and not any synthetic advice ones we
+ // create to support other features of the language.
+ if (adviceKindA.getKey() < (byte) 6 && adviceKindB.getKey() < (byte) 6
+ && adviceKindA.getPrecedence() == adviceKindB.getPrecedence()) {
+
+ // Ask the world if it knows about precedence between these
+ Integer order = getIWorld().getPrecedenceIfAny(adviceA.concreteAspect, adviceB.concreteAspect);
+
+ if (order != null && order.equals(new Integer(0))) {
+ String key = adviceA.getDeclaringAspect() + ":" + adviceB.getDeclaringAspect();
+ String possibleExistingKey = adviceB.getDeclaringAspect() + ":" + adviceA.getDeclaringAspect();
+ if (!clashingAspects.contains(possibleExistingKey)) {
+ clashingAspects.add(key);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ for (Iterator<String> iter = clashingAspects.iterator(); iter.hasNext();) {
+ String element = iter.next();
+ String aspect1 = element.substring(0, element.indexOf(":"));
+ String aspect2 = element.substring(element.indexOf(":") + 1);
+ getIWorld().getLint().unorderedAdviceAtShadow.signal(new String[] { this.toString(), aspect1, aspect2 },
+ this.getSourceLocation(), null);
+ }
+ }
+ }
+
+ /**
+ * Prepare the shadow for implementation. After this is done, the shadow should be in such a position that each munger simply
+ * needs to be implemented.
+ */
+ protected void prepareForMungers() {
+ throw new RuntimeException("Generic shadows cannot be prepared");
+ }
+
+ /** Actually implement the (non-empty) mungers associated with this shadow */
+ private void implementMungers() {
+ World world = getIWorld();
+ for (ShadowMunger munger : mungers) {
+ if (munger.implementOn(this)) {
+ world.reportMatch(munger, this);
+ }
+ }
+ }
+
+ public abstract ISourceLocation getSourceLocation();
+
+ // ---- utility
+
+ public String toString() {
+ return getKind() + "(" + getSignature() + ")"; // + getSourceLines();
+ }
+
+ public String toResolvedString(World world) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getKind());
+ sb.append("(");
+ Member m = getSignature();
+ if (m == null) {
+ sb.append("<<missing signature>>");
+ } else {
+ ResolvedMember rm = world.resolve(m);
+ if (rm == null) {
+ sb.append("<<unresolvableMember:").append(m).append(">>");
+ } else {
+ String genString = rm.toGenericString();
+ if (genString == null) {
+ sb.append("<<unableToGetGenericStringFor:").append(rm).append(">>");
+ } else {
+ sb.append(genString);
+ }
+
+ }
+ }
+ sb.append(")");
+ return sb.toString();
+ // was: return getKind() + "(" + world.resolve(getSignature()).toGenericString() + ")";
+ }
+
+ /**
+ * Convert a bit array for the shadow kinds into a set of them... should only be used for testing - mainline code should do bit
+ * manipulation!
+ */
+ public static Set<Kind> toSet(int i) {
+ Set<Kind> results = new HashSet<Kind>();
+ for (int j = 0; j < Shadow.SHADOW_KINDS.length; j++) {
+ Kind k = Shadow.SHADOW_KINDS[j];
+ if (k.isSet(i)) {
+ results.add(k);
+ }
+ }
+ return results;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ShadowMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ShadowMunger.java
new file mode 100644
index 000000000..c07d7e8e7
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ShadowMunger.java
@@ -0,0 +1,307 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.bridge.SourceLocation;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.util.PartialOrder;
+import org.aspectj.weaver.patterns.PerClause;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+
+/**
+ * For every shadow munger, nothing can be done with it until it is concretized. Then...
+ *
+ * (Then we call fast match.)
+ *
+ * For every shadow munger, for every shadow, first match is called, then (if match returned true) the shadow munger is specialized
+ * for the shadow, which may modify state. Then implement is called.
+ */
+public abstract class ShadowMunger implements PartialOrder.PartialComparable, IHasPosition {
+
+ public static final ShadowMunger[] NONE = new ShadowMunger[0];
+
+ private static int VERSION_1 = 1; // ShadowMunger version for serialization
+
+ protected static final int ShadowMungerAdvice = 1;
+ protected static final int ShadowMungerDeow = 2;
+
+ public String handle = null;
+
+ private int shadowMungerKind;
+
+ protected int start, end;
+ protected ISourceContext sourceContext;
+ private ISourceLocation sourceLocation;
+ private ISourceLocation binarySourceLocation;
+ private File binaryFile;
+ private ResolvedType declaringType;
+ private boolean isBinary;
+ private boolean checkedIsBinary;
+
+ protected Pointcut pointcut;
+
+ protected ShadowMunger() {
+ }
+
+ public ShadowMunger(Pointcut pointcut, int start, int end, ISourceContext sourceContext, int shadowMungerKind) {
+ this.shadowMungerKind = shadowMungerKind;
+ this.pointcut = pointcut;
+ this.start = start;
+ this.end = end;
+ this.sourceContext = sourceContext;
+ }
+
+ /**
+ * All overriding methods should call super
+ */
+ public boolean match(Shadow shadow, World world) {
+ if (world.isXmlConfigured() && world.isAspectIncluded(declaringType)) {
+ TypePattern scoped = world.getAspectScope(declaringType);
+ if (scoped != null) {
+ // Check the 'cached' exclusion map
+ Set<ResolvedType> excludedTypes = world.getExclusionMap().get(declaringType);
+ ResolvedType type = shadow.getEnclosingType().resolve(world);
+ if (excludedTypes != null && excludedTypes.contains(type)) {
+ return false;
+ }
+ boolean b = scoped.matches(type, TypePattern.STATIC).alwaysTrue();
+ if (!b) {
+ if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
+ world.getMessageHandler().handleMessage(
+ MessageUtil.info("Type '" + type.getName() + "' not woven by aspect '" + declaringType.getName()
+ + "' due to scope exclusion in XML definition"));
+ }
+ if (excludedTypes == null) {
+ excludedTypes = new HashSet<ResolvedType>();
+ excludedTypes.add(type);
+ world.getExclusionMap().put(declaringType, excludedTypes);
+ } else {
+ excludedTypes.add(type);
+ }
+ return false;
+ }
+ }
+ }
+ if (world.areInfoMessagesEnabled() && world.isTimingEnabled()) {
+ long starttime = System.nanoTime();
+ FuzzyBoolean isMatch = pointcut.match(shadow);
+ long endtime = System.nanoTime();
+ world.record(pointcut, endtime - starttime);
+ return isMatch.maybeTrue();
+ } else {
+ FuzzyBoolean isMatch = pointcut.match(shadow);
+ return isMatch.maybeTrue();
+ }
+ }
+
+ public int fallbackCompareTo(Object other) {
+ return toString().compareTo(toString());
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public ISourceLocation getSourceLocation() {
+ if (sourceLocation == null) {
+ if (sourceContext != null) {
+ sourceLocation = sourceContext.makeSourceLocation(this);
+ }
+ }
+ if (isBinary()) {
+ if (binarySourceLocation == null) {
+ binarySourceLocation = getBinarySourceLocation(sourceLocation);
+ }
+ return binarySourceLocation;
+ }
+ return sourceLocation;
+ }
+
+ public Pointcut getPointcut() {
+ return pointcut;
+ }
+
+ // pointcut may be updated during rewriting...
+ public void setPointcut(Pointcut pointcut) {
+ this.pointcut = pointcut;
+ }
+
+ /**
+ * Invoked when the shadow munger of a resolved type are processed.
+ *
+ * @param aType
+ */
+ public void setDeclaringType(ResolvedType aType) {
+ declaringType = aType;
+ }
+
+ public ResolvedType getDeclaringType() {
+ return declaringType;
+ }
+
+ public abstract ResolvedType getConcreteAspect();
+
+ /**
+ * Returns the binarySourceLocation for the given sourcelocation. This isn't cached because it's used when faulting in the
+ * binary nodes and is called with ISourceLocations for all advice, pointcuts and deows contained within the
+ * resolvedDeclaringAspect.
+ */
+ public ISourceLocation getBinarySourceLocation(ISourceLocation sl) {
+ if (sl == null) {
+ return null;
+ }
+ String sourceFileName = null;
+ if (getDeclaringType() instanceof ReferenceType) {
+ String s = ((ReferenceType) getDeclaringType()).getDelegate().getSourcefilename();
+ int i = s.lastIndexOf('/');
+ if (i != -1) {
+ sourceFileName = s.substring(i + 1);
+ } else {
+ sourceFileName = s;
+ }
+ }
+ ISourceLocation sLoc = new SourceLocation(getBinaryFile(), sl.getLine(), sl.getEndLine(),
+ ((sl.getColumn() == 0) ? ISourceLocation.NO_COLUMN : sl.getColumn()), sl.getContext(), sourceFileName);
+ return sLoc;
+ }
+
+ /**
+ * Returns the File with pathname to the class file, for example either:<br>
+ * C:\temp \ajcSandbox\workspace\ajcTest16957.tmp\simple.jar!pkg\BinaryAspect.class if the class file is in a jar file, or <br>
+ * C:\temp\ajcSandbox\workspace\ajcTest16957.tmp!pkg\BinaryAspect.class if the class file is in a directory
+ */
+ private File getBinaryFile() {
+ if (binaryFile == null) {
+ String binaryPath = getDeclaringType().getBinaryPath();
+ if (binaryPath == null) {
+ // Looks like an aspect that has been picked up from the classpath (likely an abstract one
+ // being extended). As it didn't come in via inpath or aspectpath the binarypath has not
+ // yet been constructed.
+
+ // We can't discover where the file came from now, that info has been lost. So just
+ // use "classpath" for now - until we discover we need to get this right.
+
+ binaryPath = "classpath";
+ getDeclaringType().setBinaryPath(binaryPath);
+ // ReferenceTypeDelegate delegate = ((ReferenceType) getDeclaringType()).getDelegate();
+ // if (delegate instanceof BcelObjectType) {
+ // grab javaclass... but it doesnt know the originating file
+ // }
+ }
+ if (binaryPath.indexOf("!") == -1) {
+ File f = getDeclaringType().getSourceLocation().getSourceFile();
+ // Replace the source file suffix with .class
+ int i = f.getPath().lastIndexOf('.');
+ String path = null;
+ if (i != -1) {
+ path = f.getPath().substring(0, i) + ".class";
+ } else {
+ path = f.getPath() + ".class";
+ }
+ binaryFile = new File(binaryPath + "!" + path);
+ } else {
+ binaryFile = new File(binaryPath);
+ }
+ }
+ return binaryFile;
+ }
+
+ /**
+ * Returns whether or not this shadow munger came from a binary aspect - keep a record of whether or not we've checked if we're
+ * binary otherwise we keep calculating the same thing many times
+ */
+ public boolean isBinary() {
+ if (!checkedIsBinary) {
+ ResolvedType rt = getDeclaringType();
+ if (rt != null) {
+ isBinary = ((rt.getBinaryPath() == null) ? false : true);
+ }
+ checkedIsBinary = true;
+ }
+ return isBinary;
+ }
+
+ public abstract ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause);
+
+ public abstract void specializeOn(Shadow shadow);
+
+ /**
+ * Implement this munger at the specified shadow, returning a boolean to indicate success.
+ *
+ * @param shadow the shadow where this munger should be applied
+ * @return true if the implement was successful
+ */
+ public abstract boolean implementOn(Shadow shadow);
+
+ public abstract ShadowMunger parameterizeWith(ResolvedType declaringType, Map<String, UnresolvedType> typeVariableMap);
+
+ /**
+ * @return a Collection of ResolvedTypes for all checked exceptions that might be thrown by this munger
+ */
+ public abstract Collection<ResolvedType> getThrownExceptions();
+
+ /**
+ * Does the munger have to check that its exception are accepted by the shadow ? It is not the case for annotation style around
+ * advice, for example: that can throw Throwable, even if the advised method does not throw any exceptions.
+ *
+ * @return true if munger has to check that its exceptions can be thrown based on the shadow
+ */
+ public abstract boolean mustCheckExceptions();
+
+ public void write(CompressingDataOutputStream stream) throws IOException {
+ stream.writeInt(VERSION_1);
+ stream.writeInt(shadowMungerKind); // determines real subclass
+ stream.writeInt(start);
+ stream.writeInt(end);
+ PersistenceSupport.write(stream, sourceContext);
+ PersistenceSupport.write(stream, sourceLocation);
+ PersistenceSupport.write(stream, binarySourceLocation);
+ PersistenceSupport.write(stream, binaryFile);
+ declaringType.write(stream);
+ stream.writeBoolean(isBinary);
+ stream.writeBoolean(checkedIsBinary);
+ pointcut.write(stream);
+ }
+
+ //
+ // public static ShadowMunger read(VersionedDataInputStream stream, World world) throws IOException {
+ // stream.readInt();
+ // int kind = stream.readInt();
+ // ShadowMunger newShadowMunger = null;
+ // switch (kind) {
+ // case ShadowMungerAdvice:
+ // // world.getWeavingSupport().createAdviceMunger(attribute, pointcut, signature)
+ // case ShadowMungerDeow:
+ // newShadowMunger = Checker.read(stream, world);
+ // default:
+ // throw new IllegalStateException("Unexpected type of shadow munger found on deserialization: " + kind);
+ // }
+ // newShadowMunger.binaryFile = null;
+ // }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SignatureUtils.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SignatureUtils.java
new file mode 100644
index 000000000..d32f7d99f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SignatureUtils.java
@@ -0,0 +1,240 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ *
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - refactored out of MemberImpl
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.lang.reflect.Modifier;
+
+public class SignatureUtils {
+
+ public static String getSignatureString(Member m, World world) {
+ MemberKind kind = m.getKind();
+ if (kind == Member.METHOD) {
+ return getMethodSignatureString(m, world);
+ } else if (kind == Member.CONSTRUCTOR) {
+ return getConstructorSignatureString(m, world);
+ } else if (kind == Member.FIELD) {
+ return getFieldSignatureString(m, world);
+ } else if (kind == Member.HANDLER) {
+ return getHandlerSignatureString(m, world);
+ } else if (kind == Member.STATIC_INITIALIZATION) {
+ return getStaticInitializationSignatureString(m, world);
+ } else if (kind == Member.ADVICE) {
+ return getAdviceSignatureString(m, world);
+ } else if (kind == Member.MONITORENTER || kind == Member.MONITOREXIT) {
+ return getMonitorSignatureString(m, world);
+ } else {
+ throw new BCException("Do not know the signature string for MemberKind " + kind);
+ }
+ }
+
+ public static String getSignatureMakerName(Member m) {
+ MemberKind kind = m.getKind();
+ if (kind == Member.METHOD) {
+ return "makeMethodSig";
+ } else if (kind == Member.CONSTRUCTOR) {
+ return "makeConstructorSig";
+ } else if (kind == Member.FIELD) {
+ return "makeFieldSig";
+ } else if (kind == Member.HANDLER) {
+ return "makeCatchClauseSig";
+ } else if (kind == Member.STATIC_INITIALIZATION) {
+ return "makeInitializerSig";
+ } else if (kind == Member.ADVICE) {
+ return "makeAdviceSig";
+ } else if (kind == Member.MONITORENTER) {
+ return "makeLockSig";
+ } else if (kind == Member.MONITOREXIT) {
+ return "makeUnlockSig";
+ } else {
+ throw new BCException("Do not know the signature maker name for MemberKind " + kind);
+ }
+ }
+
+ public static String getSignatureType(Member m) {
+ MemberKind kind = m.getKind();
+ if (m.getName().equals("<clinit>") && kind != Member.STATIC_INITIALIZATION)
+ throw new BCException();
+ // if (m.getName().equals("<clinit>")) return "org.aspectj.lang.reflect.InitializerSignature";
+
+ if (kind == Member.METHOD) {
+ return "org.aspectj.lang.reflect.MethodSignature";
+ } else if (kind == Member.CONSTRUCTOR) {
+ return "org.aspectj.lang.reflect.ConstructorSignature";
+ } else if (kind == Member.FIELD) {
+ return "org.aspectj.lang.reflect.FieldSignature";
+ } else if (kind == Member.HANDLER) {
+ return "org.aspectj.lang.reflect.CatchClauseSignature";
+ } else if (kind == Member.STATIC_INITIALIZATION) {
+ return "org.aspectj.lang.reflect.InitializerSignature";
+ } else if (kind == Member.ADVICE) {
+ return "org.aspectj.lang.reflect.AdviceSignature";
+ } else if (kind == Member.MONITORENTER) {
+ return "org.aspectj.lang.reflect.LockSignature";
+ } else if (kind == Member.MONITOREXIT) {
+ return "org.aspectj.lang.reflect.UnlockSignature";
+ } else {
+ throw new BCException("Do not know the signature type for MemberKind " + kind);
+ }
+ }
+
+ // ---
+
+ private static String getHandlerSignatureString(Member m, World world) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(makeString(0));
+ buf.append('-');
+ // buf.append(getName());
+ buf.append('-');
+ buf.append(makeString(m.getDeclaringType()));
+ buf.append('-');
+ buf.append(makeString(m.getParameterTypes()[0]));
+ buf.append('-');
+ String pName = "<missing>";
+ String[] names = m.getParameterNames(world);
+ if (names != null)
+ pName = names[0];
+ buf.append(pName);
+ buf.append('-');
+ return buf.toString();
+ }
+
+ private static String getStaticInitializationSignatureString(Member m, World world) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(makeString(m.getModifiers(world)));
+ buf.append('-');
+ // buf.append(getName());
+ buf.append('-');
+ buf.append(makeString(m.getDeclaringType()));
+ buf.append('-');
+ return buf.toString();
+ }
+
+ protected static String getAdviceSignatureString(Member m, World world) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(makeString(m.getModifiers(world)));
+ buf.append('-');
+ buf.append(m.getName());
+ buf.append('-');
+ buf.append(makeString(m.getDeclaringType()));
+ buf.append('-');
+ buf.append(makeString(m.getParameterTypes()));
+ buf.append('-');
+ buf.append(makeString(m.getParameterNames(world)));
+ buf.append('-');
+ buf.append(makeString(m.getExceptions(world)));
+ buf.append('-');
+ buf.append(makeString(m.getReturnType()));
+ buf.append('-');
+ return buf.toString();
+ }
+
+ protected static String getMethodSignatureString(Member m, World world) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(makeString(m.getModifiers(world)));
+ buf.append('-');
+ buf.append(m.getName());
+ buf.append('-');
+ buf.append(makeString(m.getDeclaringType()));
+ buf.append('-');
+ buf.append(makeString(m.getParameterTypes()));
+ buf.append('-');
+ buf.append(makeString(m.getParameterNames(world)));
+ buf.append('-');
+ buf.append(makeString(m.getExceptions(world)));
+ buf.append('-');
+ buf.append(makeString(m.getReturnType()));
+ buf.append('-');
+ return buf.toString();
+ }
+
+ protected static String getMonitorSignatureString(Member m, World world) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(makeString(Modifier.STATIC)); // modifiers
+ buf.append('-');
+ buf.append(m.getName()); // name
+ buf.append('-');
+ buf.append(makeString(m.getDeclaringType())); // Declaring Type
+ buf.append('-');
+ buf.append(makeString(m.getParameterTypes()[0])); // Parameter Types
+ buf.append('-');
+ buf.append(""); // Parameter names
+ buf.append('-');
+ return buf.toString();
+ }
+
+ protected static String getConstructorSignatureString(Member m, World world) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(makeString(m.getModifiers(world)));
+ buf.append('-');
+ buf.append('-');
+ buf.append(makeString(m.getDeclaringType()));
+ buf.append('-');
+ buf.append(makeString(m.getParameterTypes()));
+ buf.append('-');
+ buf.append(makeString(m.getParameterNames(world)));
+ buf.append('-');
+ buf.append(makeString(m.getExceptions(world)));
+ buf.append('-');
+ return buf.toString();
+ }
+
+ protected static String getFieldSignatureString(Member m, World world) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(makeString(m.getModifiers(world)));
+ buf.append('-');
+ buf.append(m.getName());
+ buf.append('-');
+ buf.append(makeString(m.getDeclaringType()));
+ buf.append('-');
+ buf.append(makeString(m.getReturnType()));
+ buf.append('-');
+ return buf.toString();
+ }
+
+ protected static String makeString(int i) {
+ return Integer.toString(i, 16);
+ }
+
+ protected static String makeString(UnresolvedType t) {
+ // this is the inverse of the odd behavior for Class.forName w/ arrays
+ if (t.isArray()) {
+ // this behavior matches the string used by the eclipse compiler for Foo.class literals
+ return t.getSignature().replace('/', '.');
+ } else {
+ return t.getName();
+ }
+ }
+
+ protected static String makeString(UnresolvedType[] types) {
+ if (types == null)
+ return "";
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0, len = types.length; i < len; i++) {
+ buf.append(makeString(types[i]));
+ buf.append(':');
+ }
+ return buf.toString();
+ }
+
+ protected static String makeString(String[] names) {
+ if (names == null)
+ return "";
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0, len = names.length; i < len; i++) {
+ buf.append(names[i]);
+ buf.append(':');
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SimpleAnnotationValue.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SimpleAnnotationValue.java
new file mode 100644
index 000000000..312f7726b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SimpleAnnotationValue.java
@@ -0,0 +1,110 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+public class SimpleAnnotationValue extends AnnotationValue {
+
+ public SimpleAnnotationValue(int kind) {
+ super(kind);
+ }
+
+ public SimpleAnnotationValue(int kind, Object value) {
+ super(kind);
+ switch (kind) {
+ case AnnotationValue.PRIMITIVE_BYTE:
+ theByte = ((Byte) value).byteValue();
+ break;
+ case AnnotationValue.PRIMITIVE_CHAR:
+ theChar = ((Character) value).charValue();
+ break;
+ case AnnotationValue.PRIMITIVE_INT:
+ theInt = ((Integer) value).intValue();
+ break;
+ case AnnotationValue.STRING:
+ theString = (String) value;
+ break;
+ case AnnotationValue.PRIMITIVE_DOUBLE:
+ theDouble = ((Double) value).doubleValue();
+ break;
+ case AnnotationValue.PRIMITIVE_FLOAT:
+ theFloat = ((Float) value).floatValue();
+ break;
+ case AnnotationValue.PRIMITIVE_LONG:
+ theLong = ((Long) value).longValue();
+ break;
+ case AnnotationValue.PRIMITIVE_SHORT:
+ theShort = ((Short) value).shortValue();
+ break;
+ case AnnotationValue.PRIMITIVE_BOOLEAN:
+ theBoolean = ((Boolean) value).booleanValue();
+ break;
+ default:
+ throw new BCException("Not implemented for this kind: " + whatKindIsThis(kind));
+ }
+ }
+
+ private byte theByte;
+ private char theChar;
+ private int theInt;
+ private String theString;
+ private double theDouble;
+ private float theFloat;
+ private long theLong;
+ private short theShort;
+ private boolean theBoolean;
+
+ public void setValueString(String s) {
+ theString = s;
+ }
+
+ public void setValueByte(byte b) {
+ theByte = b;
+ }
+
+ public void setValueChar(char c) {
+ theChar = c;
+ }
+
+ public void setValueInt(int i) {
+ theInt = i;
+ }
+
+ public String stringify() {
+ switch (valueKind) {
+ case 'B': // byte
+ return Byte.toString(theByte);
+ case 'C': // char
+ return new Character(theChar).toString();
+ case 'D': // double
+ return Double.toString(theDouble);
+ case 'F': // float
+ return Float.toString(theFloat);
+ case 'I': // int
+ return Integer.toString(theInt);
+ case 'J': // long
+ return Long.toString(theLong);
+ case 'S': // short
+ return Short.toString(theShort);
+ case 'Z': // boolean
+ return new Boolean(theBoolean).toString();
+ case 's': // String
+ return theString;
+ default:
+ throw new BCException("Do not understand this kind: " + valueKind);
+ }
+ }
+
+ public String toString() {
+ return stringify();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SourceContextImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SourceContextImpl.java
new file mode 100644
index 000000000..2ae91c649
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/SourceContextImpl.java
@@ -0,0 +1,98 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.SourceLocation;
+
+public class SourceContextImpl implements ISourceContext {
+
+ private int[] lineBreaks;
+ String sourceFilename;
+
+ public SourceContextImpl(AbstractReferenceTypeDelegate delegate) {
+ sourceFilename = delegate.getSourcefilename();
+ }
+
+ public void configureFromAttribute(String name, int[] linebreaks) {
+ this.sourceFilename = name;
+ this.lineBreaks = linebreaks;
+ }
+
+ public void setSourceFileName(String name) {
+ sourceFilename = name;
+ }
+
+ private File getSourceFile() {
+ return new File(sourceFilename);
+ }
+
+ public void tidy() {
+ }
+
+ public int getOffset() {
+ return 0;
+ }
+
+ public ISourceLocation makeSourceLocation(IHasPosition position) {
+ if (lineBreaks != null) {
+ int line = Arrays.binarySearch(lineBreaks, position.getStart());
+ if (line < 0) {
+ line = -line;
+ }
+ return new SourceLocation(getSourceFile(), line); // ??? have more info
+ } else {
+ return new SourceLocation(getSourceFile(), 0);
+ }
+ }
+
+ public ISourceLocation makeSourceLocation(int line, int offset) {
+ if (line < 0) {
+ line = 0;
+ }
+ SourceLocation sl = new SourceLocation(getSourceFile(), line);
+ if (offset > 0) {
+ sl.setOffset(offset);
+ } else {
+ if (lineBreaks != null) {
+ int likelyOffset = 0;
+ if (line > 0 && line < lineBreaks.length) {
+ // 1st char of given line is next char after previous end of line
+ likelyOffset = lineBreaks[line - 1] + 1;
+ }
+ sl.setOffset(likelyOffset);
+ }
+ }
+ return sl;
+ }
+
+ public final static ISourceContext UNKNOWN_SOURCE_CONTEXT = new ISourceContext() {
+ public ISourceLocation makeSourceLocation(IHasPosition position) {
+ return null;
+ }
+
+ public ISourceLocation makeSourceLocation(int line, int offset) {
+ return null;
+ }
+
+ public int getOffset() {
+ return 0;
+ }
+
+ public void tidy() {
+ }
+ };
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/StandardAnnotation.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/StandardAnnotation.java
new file mode 100644
index 000000000..475b0977f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/StandardAnnotation.java
@@ -0,0 +1,157 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This type represents the weavers abstraction of an annotation - it is not tied to any underlying BCI toolkit. The weaver actualy
+ * handles these through AnnotationX wrapper objects - until we start transforming the BCEL annotations into this form (expensive)
+ * or offer a clever visitor mechanism over the BCEL annotation stuff that builds these annotation types directly.
+ *
+ * @author AndyClement
+ */
+public class StandardAnnotation extends AbstractAnnotationAJ {
+
+ private final boolean isRuntimeVisible;
+
+ private List<AnnotationNameValuePair> nvPairs = null;
+
+ public StandardAnnotation(ResolvedType type, boolean isRuntimeVisible) {
+ super(type);
+ this.isRuntimeVisible = isRuntimeVisible;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isRuntimeVisible() {
+ return isRuntimeVisible;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String stringify() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("@").append(type.getClassName());
+ if (hasNameValuePairs()) {
+ sb.append("(");
+ for (AnnotationNameValuePair nvPair : nvPairs) {
+ sb.append(nvPair.stringify());
+ }
+ sb.append(")");
+ }
+ return sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Anno[" + getTypeSignature() + " " + (isRuntimeVisible ? "rVis" : "rInvis"));
+ if (nvPairs != null) {
+ sb.append(" ");
+ for (Iterator<AnnotationNameValuePair> iter = nvPairs.iterator(); iter.hasNext();) {
+ AnnotationNameValuePair element = iter.next();
+ sb.append(element.toString());
+ if (iter.hasNext()) {
+ sb.append(",");
+ }
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNamedValue(String n) {
+ if (nvPairs == null) {
+ return false;
+ }
+ for (int i = 0; i < nvPairs.size(); i++) {
+ AnnotationNameValuePair pair = nvPairs.get(i);
+ if (pair.getName().equals(n)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNameValuePair(String n, String v) {
+ if (nvPairs == null) {
+ return false;
+ }
+ for (int i = 0; i < nvPairs.size(); i++) {
+ AnnotationNameValuePair pair = nvPairs.get(i);
+ if (pair.getName().equals(n)) {
+ if (pair.getValue().stringify().equals(v)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<String> getTargets() {
+ if (!type.equals(UnresolvedType.AT_TARGET)) {
+ return Collections.emptySet();
+ }
+ AnnotationNameValuePair nvp = nvPairs.get(0);
+ ArrayAnnotationValue aav = (ArrayAnnotationValue) nvp.getValue();
+ AnnotationValue[] avs = aav.getValues();
+ Set<String> targets = new HashSet<String>();
+ for (int i = 0; i < avs.length; i++) {
+ EnumAnnotationValue value = (EnumAnnotationValue)avs[i];
+ targets.add(value.getValue());
+ }
+ return targets;
+ }
+
+ public List<AnnotationNameValuePair> getNameValuePairs() {
+ return nvPairs;
+ }
+
+ public boolean hasNameValuePairs() {
+ return nvPairs != null && nvPairs.size() != 0;
+ }
+
+ public void addNameValuePair(AnnotationNameValuePair pair) {
+ if (nvPairs == null) {
+ nvPairs = new ArrayList<AnnotationNameValuePair>();
+ }
+ nvPairs.add(pair);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getStringFormOfValue(String name) {
+ if (hasNameValuePairs()) {
+ for (AnnotationNameValuePair nvPair : nvPairs) {
+ if (nvPair.getName().equals(name)) {
+ return nvPair.getValue().stringify();
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/StaticJoinPointFactory.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/StaticJoinPointFactory.java
new file mode 100644
index 000000000..591e6c470
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/StaticJoinPointFactory.java
@@ -0,0 +1,54 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+public class StaticJoinPointFactory {
+ // int usedKeys;
+ //
+ // List/*String*/ strings = new ArrayList();
+ // Map/*String,Integer*/ keysForStrings = new HashMap();
+ //
+ // public StaticJoinPointFactory() {
+ // super();
+ // }
+ //
+ // static char[] encoding = new char[] {
+ // '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//10
+ // 'a', 'b', 'z', //36
+ // 'A', 'B', 'Z', //62
+ // '%', '$', //64
+ // };
+ //
+ // static int TWO_WORDS = 64*64-1;
+ // static int WORD_MASK = 63;
+ //
+ // public void write(String s, StringBuffer result) {
+ // int i = getIndex(s);
+ // encode(i, result);
+ // }
+ //
+ // void encode(int i, StringBuffer result) {
+ // if (i > TWO_WORDS) {
+ // throw new RuntimeException("unimplemented");
+ // } else {
+ // result.append( encoding[(i >> 6) & WORD_MASK] );
+ // result.append( encoding[i & WORD_MASK] );
+ // }
+ // }
+ //
+ // public String read(StringReader reader) {
+ // int i = reader.read();
+ //
+ // }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TemporaryTypeMunger.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TemporaryTypeMunger.java
new file mode 100644
index 000000000..0e0a89fce
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TemporaryTypeMunger.java
@@ -0,0 +1,37 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Map;
+
+/**
+ * Some methods need a temporary type munger (because ConcreteTypeMunger is abstract - dont ask...).
+ *
+ * TODO ought to remove the need for this or at least sort out the two methods that are in it, they look weird...
+ *
+ * @author AndyClement
+ */
+public class TemporaryTypeMunger extends ConcreteTypeMunger {
+
+ public TemporaryTypeMunger(ResolvedTypeMunger munger, ResolvedType aspectType) {
+ super(munger, aspectType);
+ }
+
+ @Override
+ public ConcreteTypeMunger parameterizeWith(Map parameterizationMap, World world) {
+ throw new UnsupportedOperationException("Cannot be called on a TemporaryTypeMunger");
+ }
+
+ @Override
+ public ConcreteTypeMunger parameterizedFor(ResolvedType targetType) {
+ throw new UnsupportedOperationException("Cannot be called on a TemporaryTypeMunger");
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeFactory.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeFactory.java
new file mode 100644
index 000000000..e565e5bc8
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeFactory.java
@@ -0,0 +1,377 @@
+/* *******************************************************************
+ * Copyright (c) 2005-2010 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class TypeFactory {
+
+ /**
+ * Create a parameterized version of a generic type.
+ *
+ * @param aGenericType
+ * @param someTypeParameters note, in the case of an inner type of a parameterized type, this parameter may legitimately be null
+ * @param inAWorld
+ * @return
+ */
+ public static ReferenceType createParameterizedType(ResolvedType aBaseType, UnresolvedType[] someTypeParameters, World inAWorld) {
+ ResolvedType baseType = aBaseType;
+ if (!aBaseType.isGenericType()) {
+ if (someTypeParameters != null && someTypeParameters.length > 0) {
+ if (!aBaseType.isRawType()) {
+ throw new IllegalStateException("Expecting raw type, but " + aBaseType+" is of type "+aBaseType.getTypekind());
+ }
+ baseType = baseType.getGenericType();
+ if (baseType == null) {
+ throw new IllegalStateException("Raw type does not have generic type set");
+ }
+ } // else if someTypeParameters is null, then the base type is allowed to be non-generic, it's an inner
+ }
+ ResolvedType[] resolvedParameters = inAWorld.resolve(someTypeParameters);
+
+ ReferenceType existingType = ((ReferenceType)baseType).findDerivativeType(resolvedParameters);
+
+ ReferenceType pType = null;
+
+ if (existingType!=null) {
+ pType = existingType;
+ } else {
+ pType =new ReferenceType(baseType, resolvedParameters, inAWorld);
+ }
+ // pType.setSourceContext(aBaseType.getSourceContext());
+ return (ReferenceType) pType.resolve(inAWorld);
+ }
+
+ /**
+ * Create an *unresolved* parameterized version of a generic type.
+ */
+ public static UnresolvedType createUnresolvedParameterizedType(String sig, String erasuresig, UnresolvedType[] arguments) {
+ return new UnresolvedType(sig, erasuresig, arguments);
+ }
+
+ // public static ReferenceType createRawType(
+ // ResolvedType aBaseType,
+ // World inAWorld
+ // ) {
+ // if (aBaseType.isRawType()) return (ReferenceType) aBaseType;
+ // if (!aBaseType.isGenericType()) {
+ // if (!aBaseType.isRawType()) throw new IllegalStateException("Expecting generic type");
+ // }
+ // ReferenceType rType = new ReferenceType(aBaseType,inAWorld);
+ // //rType.setSourceContext(aBaseType.getSourceContext());
+ // return (ReferenceType) rType.resolve(inAWorld);
+ // }
+
+ /**
+ * Creates a sensible unresolvedtype from some signature, for example: signature = LIGuard<TT;>; bound = toString=IGuard<T>
+ * sig=PIGuard<TT;>; sigErasure=LIGuard; kind=parameterized
+ */
+ static UnresolvedType convertSigToType(String aSignature) {
+ UnresolvedType bound = null;
+ int startOfParams = aSignature.indexOf('<');
+ if (startOfParams == -1) {
+ bound = UnresolvedType.forSignature(aSignature);
+ } else {
+ int endOfParams = aSignature.lastIndexOf('>');
+ String signatureErasure = "L" + aSignature.substring(1, startOfParams) + ";";
+ UnresolvedType[] typeParams = createTypeParams(aSignature.substring(startOfParams + 1, endOfParams));
+ bound = new UnresolvedType("P" + aSignature.substring(1), signatureErasure, typeParams);
+ }
+ return bound;
+ }
+
+ /**
+ * Used by UnresolvedType.read, creates a type from a full signature.
+ */
+ public static UnresolvedType createTypeFromSignature(String signature) {
+ // if (signature.equals(ResolvedType.MISSING_NAME)) {
+ // return ResolvedType.MISSING;
+ // }
+
+ char firstChar = signature.charAt(0);
+ if (firstChar == 'P') {
+ // parameterized type, calculate signature erasure and type parameters
+ // (see pr122458) It is possible for a parameterized type to have *no* type parameters visible in its signature.
+ // This happens for an inner type of a parameterized type which simply inherits the type parameters
+ // of its parent. In this case it is parameterized but theres no < in the signature.
+ int startOfParams = signature.indexOf('<');
+
+ if (startOfParams == -1) {
+ // Should be an inner type of a parameterized type - could assert there is a '$' in the signature....
+ String signatureErasure = "L" + signature.substring(1);
+ return new UnresolvedType(signature, signatureErasure, UnresolvedType.NONE);
+ } else {
+ int endOfParams = locateMatchingEndAngleBracket(signature, startOfParams);
+ StringBuffer erasureSig = new StringBuffer(signature);
+ erasureSig.setCharAt(0, 'L');
+ while (startOfParams != -1) {
+ erasureSig.delete(startOfParams, endOfParams + 1);
+ startOfParams = locateFirstBracket(erasureSig);
+ if (startOfParams != -1) {
+ endOfParams = locateMatchingEndAngleBracket(erasureSig, startOfParams);
+ }
+ }
+
+ String signatureErasure = erasureSig.toString();// "L" + erasureSig.substring(1);
+
+ // the type parameters of interest are only those that apply to the 'last type' in the signature
+ // if the signature is 'PMyInterface<String>$MyOtherType;' then there are none...
+ String lastType = null;
+ int nestedTypePosition = signature.indexOf("$", endOfParams); // don't look for $ INSIDE the parameters
+ if (nestedTypePosition != -1) {
+ lastType = signature.substring(nestedTypePosition + 1);
+ } else {
+ lastType = new String(signature);
+ }
+ startOfParams = lastType.indexOf("<");
+ UnresolvedType[] typeParams = UnresolvedType.NONE;
+ if (startOfParams != -1) {
+ endOfParams = locateMatchingEndAngleBracket(lastType, startOfParams);
+ typeParams = createTypeParams(lastType.substring(startOfParams + 1, endOfParams));
+ }
+ StringBuilder s = new StringBuilder();
+ int firstAngleBracket = signature.indexOf('<');
+ s.append("P").append(signature.substring(1, firstAngleBracket));
+ s.append('<');
+ for (UnresolvedType typeParameter : typeParams) {
+ s.append(typeParameter.getSignature());
+ }
+ s.append(">;");
+ signature = s.toString();// 'P' + signature.substring(1);
+ return new UnresolvedType(signature, signatureErasure, typeParams);
+ }
+ // can't replace above with convertSigToType - leads to stackoverflow
+ } else if ((firstChar == '?' || firstChar == '*') && signature.length()==1) {
+ return WildcardedUnresolvedType.QUESTIONMARK;
+ } else if (firstChar == '+') {
+ // ? extends ...
+ UnresolvedType upperBound = convertSigToType(signature.substring(1));
+ WildcardedUnresolvedType wildcardedUT = new WildcardedUnresolvedType(signature, upperBound, null);
+ return wildcardedUT;
+ } else if (firstChar == '-') {
+ // ? super ...
+ UnresolvedType lowerBound = convertSigToType(signature.substring(1));
+ WildcardedUnresolvedType wildcardedUT = new WildcardedUnresolvedType(signature, null, lowerBound);
+ return wildcardedUT;
+ } else if (firstChar == 'T') {
+ String typeVariableName = signature.substring(1);
+ if (typeVariableName.endsWith(";")) {
+ typeVariableName = typeVariableName.substring(0, typeVariableName.length() - 1);
+ }
+ return new UnresolvedTypeVariableReferenceType(new TypeVariable(typeVariableName));
+ } else if (firstChar == '[') {
+ int dims = 0;
+ while (signature.charAt(dims) == '[') {
+ dims++;
+ }
+ UnresolvedType componentType = createTypeFromSignature(signature.substring(dims));
+ return new UnresolvedType(signature, signature.substring(0, dims) + componentType.getErasureSignature());
+ } else if (signature.length() == 1) { // could be a primitive
+ switch (firstChar) {
+
+ case 'V':
+ return UnresolvedType.VOID;
+ case 'Z':
+ return UnresolvedType.BOOLEAN;
+ case 'B':
+ return UnresolvedType.BYTE;
+ case 'C':
+ return UnresolvedType.CHAR;
+ case 'D':
+ return UnresolvedType.DOUBLE;
+ case 'F':
+ return UnresolvedType.FLOAT;
+ case 'I':
+ return UnresolvedType.INT;
+ case 'J':
+ return UnresolvedType.LONG;
+ case 'S':
+ return UnresolvedType.SHORT;
+ }
+ } else if (firstChar == '@') {
+ // missing type
+ return ResolvedType.MISSING;
+ } else if (firstChar == 'L') {
+ // only an issue if there is also an angle bracket
+ int leftAngleBracket = signature.indexOf('<');
+
+ if (leftAngleBracket == -1) {
+ return new UnresolvedType(signature);
+ } else {
+ int endOfParams = locateMatchingEndAngleBracket(signature, leftAngleBracket);
+ StringBuffer erasureSig = new StringBuffer(signature);
+ erasureSig.setCharAt(0, 'L');
+ while (leftAngleBracket != -1) {
+ erasureSig.delete(leftAngleBracket, endOfParams + 1);
+ leftAngleBracket = locateFirstBracket(erasureSig);
+ if (leftAngleBracket != -1) {
+ endOfParams = locateMatchingEndAngleBracket(erasureSig, leftAngleBracket);
+ }
+ }
+
+ String signatureErasure = erasureSig.toString();
+
+ // TODO should consider all the intermediate parameterizations as well!
+ // the type parameters of interest are only those that apply to the 'last type' in the signature
+ // if the signature is 'PMyInterface<String>$MyOtherType;' then there are none...
+ String lastType = null;
+ int nestedTypePosition = signature.indexOf("$", endOfParams); // don't look for $ INSIDE the parameters
+ if (nestedTypePosition != -1) {
+ lastType = signature.substring(nestedTypePosition + 1);
+ } else {
+ lastType = new String(signature);
+ }
+ leftAngleBracket = lastType.indexOf("<");
+ UnresolvedType[] typeParams = UnresolvedType.NONE;
+ if (leftAngleBracket != -1) {
+ endOfParams = locateMatchingEndAngleBracket(lastType, leftAngleBracket);
+ typeParams = createTypeParams(lastType.substring(leftAngleBracket + 1, endOfParams));
+ }
+ StringBuilder s = new StringBuilder();
+ int firstAngleBracket = signature.indexOf('<');
+ s.append("P").append(signature.substring(1, firstAngleBracket));
+ s.append('<');
+ for (UnresolvedType typeParameter : typeParams) {
+ s.append(typeParameter.getSignature());
+ }
+ s.append(">;");
+ signature = s.toString();// 'P' + signature.substring(1);
+ return new UnresolvedType(signature, signatureErasure, typeParams);
+ }
+
+ }
+ return new UnresolvedType(signature);
+ }
+
+ private static int locateMatchingEndAngleBracket(CharSequence signature, int startOfParams) {
+ if (startOfParams == -1) {
+ return -1;
+ }
+ int count = 1;
+ int idx = startOfParams;
+ int max = signature.length();
+ while (idx < max) {
+ char ch = signature.charAt(++idx);
+ if (ch == '<') {
+ count++;
+ } else if (ch == '>') {
+ if (count == 1) {
+ break;
+ }
+ count--;
+ }
+ }
+ return idx;
+ }
+
+ private static int locateFirstBracket(StringBuffer signature) {
+ int idx = 0;
+ int max = signature.length();
+ while (idx < max) {
+ if (signature.charAt(idx) == '<') {
+ return idx;
+ }
+ idx++;
+ }
+ return -1;
+ }
+
+ private static UnresolvedType[] createTypeParams(String typeParameterSpecification) {
+ String remainingToProcess = typeParameterSpecification;
+ List<UnresolvedType> types = new ArrayList<UnresolvedType>();
+ while (remainingToProcess.length() != 0) {
+ int endOfSig = 0;
+ int anglies = 0;
+ boolean hadAnglies = false;
+ boolean sigFound = false; // OPTIMIZE can this be done better?
+ for (endOfSig = 0; (endOfSig < remainingToProcess.length()) && !sigFound; endOfSig++) {
+ char thisChar = remainingToProcess.charAt(endOfSig);
+ switch (thisChar) {
+ case '<':
+ anglies++;
+ hadAnglies = true;
+ break;
+ case '>':
+ anglies--;
+ break;
+ case '*':
+ if (anglies==0) {
+ int nextCharPos = endOfSig+1;
+ if (nextCharPos>=remainingToProcess.length()) {
+ sigFound=true;
+ } else {
+ char nextChar = remainingToProcess.charAt(nextCharPos);
+ if (!(nextChar=='+' || nextChar=='-')) {
+ // dont need to set endOfSig as the loop will increment
+ // it to the right place before it exits
+ sigFound=true;
+ }
+ }
+ }
+ break;
+ case '[':
+ if (anglies == 0) {
+ // the next char might be a [ or a primitive type ref (BCDFIJSZ)
+ int nextChar = endOfSig + 1;
+ while (remainingToProcess.charAt(nextChar) == '[') {
+ nextChar++;
+ }
+ if ("BCDFIJSZ".indexOf(remainingToProcess.charAt(nextChar)) != -1) {
+ // it is something like [I or [[S
+ sigFound = true;
+ endOfSig = nextChar;
+ break;
+ }
+ }
+ break;
+ case ';':
+ if (anglies == 0) {
+ sigFound = true;
+ break;
+ }
+ }
+ }
+ String forProcessing = remainingToProcess.substring(0, endOfSig);
+ if (hadAnglies && forProcessing.charAt(0) == 'L') {
+ forProcessing = "P" + forProcessing.substring(1);
+ }
+ types.add(createTypeFromSignature(forProcessing));
+ remainingToProcess = remainingToProcess.substring(endOfSig);
+ }
+ UnresolvedType[] typeParams = new UnresolvedType[types.size()];
+ types.toArray(typeParams);
+ return typeParams;
+ }
+
+ // OPTIMIZE improve all this signature processing stuff, use char arrays, etc
+
+ /**
+ * Create a signature then delegate to the other factory method. Same input/output: baseTypeSignature="LSomeType;" arguments[0]=
+ * something with sig "Pcom/Foo<Ljava/lang/String;>;" signature created = "PSomeType<Pcom/Foo<Ljava/lang/String;>;>;"
+ */
+ public static UnresolvedType createUnresolvedParameterizedType(String baseTypeSignature, UnresolvedType[] arguments) {
+ StringBuffer parameterizedSig = new StringBuffer();
+ parameterizedSig.append(ResolvedType.PARAMETERIZED_TYPE_IDENTIFIER);
+ parameterizedSig.append(baseTypeSignature.substring(1, baseTypeSignature.length() - 1));
+ if (arguments.length > 0) {
+ parameterizedSig.append("<");
+ for (int i = 0; i < arguments.length; i++) {
+ parameterizedSig.append(arguments[i].getSignature());
+ }
+ parameterizedSig.append(">");
+ }
+ parameterizedSig.append(";");
+ return createUnresolvedParameterizedType(parameterizedSig.toString(), baseTypeSignature, arguments);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariable.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariable.java
new file mode 100644
index 000000000..d67bbd8dc
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariable.java
@@ -0,0 +1,371 @@
+/* *******************************************************************
+ * Copyright (c) 2005-2010 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.io.IOException;
+
+/**
+ * Represents a type variable with possible bounds.
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class TypeVariable {
+
+ public static final TypeVariable[] NONE = new TypeVariable[0];
+
+ // the name of the type variable as recorded in the generic signature
+ private String name;
+ // index
+ private int rank;
+ // computed as required: either ==superclass or ==superInterfaces[0] or is OBJECT
+ private UnresolvedType firstbound;
+ // the upper bound of the type variable. From the extends clause, eg. T extends Number
+ private UnresolvedType superclass;
+ // any additional upper (interface) bounds. from the extends clause, e.g. T extends Number & Comparable
+ private UnresolvedType[] superInterfaces = UnresolvedType.NONE;
+ // It would be nice to push this field onto the TypeVariableDeclaringElement
+ // interface (a getKind()) but at the moment we don't always guarantee
+ // to set the declaring element (eclipse seems to utilise the knowledge of
+ // what declared the type variable, but we dont yet...)
+ public static final int UNKNOWN = -1;
+ public static final int METHOD = 1;
+ public static final int TYPE = 2;
+ // What kind of element declared this type variable?
+ private int declaringElementKind = UNKNOWN;
+ private TypeVariableDeclaringElement declaringElement;
+ // whether or not the bounds of this type variable have been resolved
+ public boolean isResolved = false;
+ // Is this type variable in the process of being resolved (allows for something self-referential like Enum)
+ private boolean beingResolved = false;
+
+ /**
+ * Constructor for an unbound type variable, eg. 'T'
+ */
+ public TypeVariable(String name) {
+ this.name = name;
+ }
+
+ public TypeVariable(String name, UnresolvedType anUpperBound) {
+ this(name);
+ this.superclass = anUpperBound;
+ }
+
+ public TypeVariable(String name, UnresolvedType anUpperBound, UnresolvedType[] superInterfaces) {
+ this(name, anUpperBound);
+ this.superInterfaces = superInterfaces;
+ }
+
+ /**
+ * @return the first bound, either the superclass or if non is specified the first interface or if non are specified then OBJECT
+ */
+ public UnresolvedType getFirstBound() {
+ if (firstbound != null) {
+ return firstbound;
+ }
+ if (superclass == null || superclass.getSignature().equals("Ljava/lang/Object;")) {
+ if (superInterfaces.length > 0) {
+ firstbound = superInterfaces[0];
+ } else {
+ firstbound = UnresolvedType.OBJECT;
+ }
+ } else {
+ firstbound = superclass;
+ }
+ return firstbound;
+ }
+
+ public UnresolvedType getUpperBound() {
+ return superclass;
+ }
+
+ public UnresolvedType[] getSuperInterfaces() {
+ return superInterfaces;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * resolve all the bounds of this type variable
+ */
+ public TypeVariable resolve(World world) {
+ if (isResolved) {
+ return this;
+ }
+ if (beingResolved) {
+ return this;
+ }
+ beingResolved = true;
+
+ TypeVariable resolvedTVar = null;
+
+ if (declaringElement != null) {
+ // resolve by finding the real type var that we refer to...
+ if (declaringElementKind == TYPE) {
+ UnresolvedType declaring = (UnresolvedType) declaringElement;
+ ReferenceType rd = (ReferenceType) declaring.resolve(world);
+ TypeVariable[] tVars = rd.getTypeVariables();
+ for (int i = 0; i < tVars.length; i++) {
+ if (tVars[i].getName().equals(getName())) {
+ resolvedTVar = tVars[i];
+ break;
+ }
+ }
+ } else {
+ // look for type variable on method...
+ ResolvedMember declaring = (ResolvedMember) declaringElement;
+ TypeVariable[] tvrts = declaring.getTypeVariables();
+ for (int i = 0; i < tvrts.length; i++) {
+ if (tvrts[i].getName().equals(getName())) {
+ resolvedTVar = tvrts[i];
+ // if (tvrts[i].isTypeVariableReference()) {
+ // TypeVariableReferenceType tvrt = (TypeVariableReferenceType) tvrts[i].resolve(inSomeWorld);
+ // TypeVariable tv = tvrt.getTypeVariable();
+ // if (tv.getName().equals(getName())) resolvedTVar = tv;
+ // }
+ }
+ }
+ }
+
+ if (resolvedTVar == null) {
+ throw new IllegalStateException();
+ // well, this is bad... we didn't find the type variable on the member
+ // could be a separate compilation issue...
+ // should issue message, this is a workaround to get us going...
+ // resolvedTVar = this;
+ }
+ } else {
+ resolvedTVar = this;
+ }
+
+ superclass = resolvedTVar.superclass;
+ superInterfaces = resolvedTVar.superInterfaces;
+
+ if (superclass != null) {
+ ResolvedType rt = superclass.resolve(world);
+// if (!superclass.isTypeVariableReference() && rt.isInterface()) {
+// throw new IllegalStateException("Why is the type an interface? " + rt);
+// }
+ superclass = rt;
+ }
+ firstbound = getFirstBound().resolve(world);
+
+ for (int i = 0; i < superInterfaces.length; i++) {
+ superInterfaces[i] = superInterfaces[i].resolve(world);
+ }
+ isResolved = true;
+ beingResolved = false;
+ return this;
+ }
+
+ /**
+ * answer true if the given type satisfies all of the bound constraints of this type variable. If type variable has not been
+ * resolved then throws IllegalStateException
+ */
+ public boolean canBeBoundTo(ResolvedType candidate) {
+ if (!isResolved) {
+ throw new IllegalStateException("Can't answer binding questions prior to resolving");
+ }
+
+ // wildcard can accept any binding
+ if (candidate.isGenericWildcard()) {
+ return true;
+ }
+
+ // otherwise can be bound iff...
+
+ // candidate is a subtype of upperBound
+ if (superclass != null && !isASubtypeOf(superclass, candidate)) {
+ return false;
+ }
+ // candidate is a subtype of all superInterfaces
+ for (int i = 0; i < superInterfaces.length; i++) {
+ if (!isASubtypeOf(superInterfaces[i], candidate)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isASubtypeOf(UnresolvedType candidateSuperType, UnresolvedType candidateSubType) {
+ ResolvedType superType = (ResolvedType) candidateSuperType;
+ ResolvedType subType = (ResolvedType) candidateSubType;
+ return superType.isAssignableFrom(subType);
+ }
+
+ // only used when resolving
+ public void setUpperBound(UnresolvedType superclass) {
+ // if (isResolved) {
+ // throw new IllegalStateException("Why set this late?");
+ // }
+ this.firstbound = null;
+ this.superclass = superclass;
+ }
+
+ // only used when resolving
+ public void setAdditionalInterfaceBounds(UnresolvedType[] superInterfaces) {
+ // if (isResolved) {
+ // throw new IllegalStateException("Why set this late?");
+ // }
+ this.firstbound = null;
+ this.superInterfaces = superInterfaces;
+ }
+
+ public String toDebugString() {
+ return getDisplayName();
+ }
+
+ public String getDisplayName() {
+ StringBuffer ret = new StringBuffer();
+ ret.append(name);
+ if (!getFirstBound().getName().equals("java.lang.Object")) {
+ ret.append(" extends ");
+ ret.append(getFirstBound().getName());
+ if (superInterfaces != null) {
+ for (int i = 0; i < superInterfaces.length; i++) {
+ if (!getFirstBound().equals(superInterfaces[i])) {
+ ret.append(" & ");
+ ret.append(superInterfaces[i].getName());
+ }
+ }
+ }
+ }
+ return ret.toString();
+ }
+
+ @Override
+ public String toString() {
+ return "TypeVar " + getDisplayName();
+ }
+
+ /**
+ * Return complete signature, e.g. "T extends Number" would return "T:Ljava/lang/Number;" note: MAY INCLUDE P types if bounds
+ * are parameterized types
+ */
+ public String getSignature() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(name);
+ sb.append(":");
+ if (superInterfaces.length == 0 || !superclass.getSignature().equals(UnresolvedType.OBJECT.getSignature())) {
+ sb.append(superclass.getSignature());
+ }
+ if (superInterfaces.length != 0) {
+ for (int i = 0; i < superInterfaces.length; i++) {
+ sb.append(":");
+ UnresolvedType iBound = superInterfaces[i];
+ sb.append(iBound.getSignature());
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @return signature for inclusion in an attribute, there must be no 'P' in it signatures
+ */
+ public String getSignatureForAttribute() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(name);
+ sb.append(":");
+ if (superInterfaces.length == 0 || !superclass.getSignature().equals(UnresolvedType.OBJECT.getSignature())) {
+ sb.append(((ReferenceType)superclass).getSignatureForAttribute());
+ }
+ if (superInterfaces.length != 0) {
+ for (int i = 0; i < superInterfaces.length; i++) {
+ sb.append(":");
+ ResolvedType iBound = (ResolvedType) superInterfaces[i];
+ sb.append(iBound.getSignatureForAttribute());
+ }
+ }
+ return sb.toString();
+ }
+
+ public void setRank(int rank) {
+ this.rank = rank;
+ }
+
+ public int getRank() {
+ return rank;
+ }
+
+ public void setDeclaringElement(TypeVariableDeclaringElement element) {
+ this.declaringElement = element;
+ if (element instanceof UnresolvedType) {
+ this.declaringElementKind = TYPE;
+ } else {
+ this.declaringElementKind = METHOD;
+ }
+ }
+
+ public TypeVariableDeclaringElement getDeclaringElement() {
+ return declaringElement;
+ }
+
+ public void setDeclaringElementKind(int kind) {
+ this.declaringElementKind = kind;
+ }
+
+ public int getDeclaringElementKind() {
+ // if (declaringElementKind==UNKNOWN) throw new RuntimeException("Dont know declarer of this tvar : "+this);
+ return declaringElementKind;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ // name, upperbound, additionalInterfaceBounds, lowerbound
+ s.writeUTF(name);
+ superclass.write(s);
+ if (superInterfaces.length == 0) {
+ s.writeInt(0);
+ } else {
+ s.writeInt(superInterfaces.length);
+ for (int i = 0; i < superInterfaces.length; i++) {
+ UnresolvedType ibound = superInterfaces[i];
+ ibound.write(s);
+ }
+ }
+ }
+
+ public static TypeVariable read(VersionedDataInputStream s) throws IOException {
+
+ // if (s.getMajorVersion()>=AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+
+ String name = s.readUTF();
+ UnresolvedType ubound = UnresolvedType.read(s);
+ int iboundcount = s.readInt();
+ UnresolvedType[] ibounds = UnresolvedType.NONE;
+ if (iboundcount > 0) {
+ ibounds = new UnresolvedType[iboundcount];
+ for (int i = 0; i < iboundcount; i++) {
+ ibounds[i] = UnresolvedType.read(s);
+ }
+ }
+
+ TypeVariable newVariable = new TypeVariable(name, ubound, ibounds);
+ return newVariable;
+ }
+
+ public String getGenericSignature() {
+ return "T" + name + ";";
+ }
+
+ public String getErasureSignature() {
+ return getFirstBound().getErasureSignature();
+ }
+
+ public UnresolvedType getSuperclass() {
+ return superclass;
+ }
+
+ public void setSuperclass(UnresolvedType superclass) {
+ this.firstbound = null;
+ this.superclass = superclass;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableDeclaringElement.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableDeclaringElement.java
new file mode 100644
index 000000000..ae41fd09c
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableDeclaringElement.java
@@ -0,0 +1,21 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement Initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+/**
+ * Tag interface - methods and types can be declaring elements for type variables. See the TypeVariable class which holds onto the
+ * declaring element
+ */
+public interface TypeVariableDeclaringElement {
+ public TypeVariable getTypeVariableNamed(String name);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReference.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReference.java
new file mode 100644
index 000000000..138fbced7
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReference.java
@@ -0,0 +1,22 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Implemented by Types that represent references to type variables
+ *
+ */
+public interface TypeVariableReference {
+
+ TypeVariable getTypeVariable();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReferenceType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReferenceType.java
new file mode 100644
index 000000000..1e867ab5e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/TypeVariableReferenceType.java
@@ -0,0 +1,154 @@
+/* *******************************************************************
+ * Copyright (c) 2005-2012 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.util.Map;
+
+/**
+ * ReferenceType pointing to a type variable. The delegate for this reference type is the upperbound on the type variable (so
+ * Object if not otherwise specified).
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class TypeVariableReferenceType extends ReferenceType implements TypeVariableReference {
+
+ private TypeVariable typeVariable;
+
+ public TypeVariableReferenceType(TypeVariable typeVariable, World world) {
+ super(typeVariable.getGenericSignature(), typeVariable.getErasureSignature(), world);
+ this.typeVariable = typeVariable;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof TypeVariableReferenceType) {
+ return typeVariable==((TypeVariableReferenceType)other).typeVariable;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return typeVariable.hashCode();
+ }
+
+ /**
+ * For a TypeVariableReferenceType the delegate is the delegate for the first bound.
+ */
+ @Override
+ public ReferenceTypeDelegate getDelegate() {
+ if (this.delegate == null) {
+ ResolvedType resolvedFirstBound = typeVariable.getFirstBound().resolve(world);
+ BoundedReferenceTypeDelegate brtd = null;
+ if (resolvedFirstBound.isMissing()) {
+ brtd = new BoundedReferenceTypeDelegate((ReferenceType) world.resolve(UnresolvedType.OBJECT));
+ setDelegate(brtd); // set now because getSourceLocation() below will cause a recursive step to discover the delegate
+ world.getLint().cantFindType.signal(
+ "Unable to find type for generic bound. Missing type is " + resolvedFirstBound.getName(),
+ getSourceLocation());
+ } else {
+ brtd = new BoundedReferenceTypeDelegate((ReferenceType) resolvedFirstBound);
+ setDelegate(brtd);
+ }
+
+ }
+ return this.delegate;
+ }
+
+ @Override
+ public UnresolvedType parameterize(Map<String, UnresolvedType> typeBindings) {
+ UnresolvedType ut = typeBindings.get(getName());
+ if (ut != null) {
+ return world.resolve(ut);
+ }
+ return this;
+ }
+
+ public TypeVariable getTypeVariable() {
+ return typeVariable;
+ }
+
+ @Override
+ public boolean isTypeVariableReference() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return typeVariable.getName();
+ }
+
+ @Override
+ public boolean isGenericWildcard() {
+ return false;
+ }
+
+ @Override
+ public boolean isAnnotation() {
+ ReferenceType upper = (ReferenceType) typeVariable.getUpperBound();
+ if (upper.isAnnotation()) {
+ return true;
+ }
+ World world = upper.getWorld();
+ typeVariable.resolve(world);
+ ResolvedType annotationType = ResolvedType.ANNOTATION.resolve(world);
+ UnresolvedType[] ifBounds = typeVariable.getSuperInterfaces();// AdditionalBounds();
+ for (int i = 0; i < ifBounds.length; i++) {
+ if (((ReferenceType) ifBounds[i]).isAnnotation()) {
+ return true;
+ }
+ if (ifBounds[i].equals(annotationType)) {
+ return true; // annotation itself does not have the annotation flag set in Java!
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return the signature for a *REFERENCE* to a type variable, which is simply: Tname; there is no bounds info included, that is
+ * in the signature of the type variable itself
+ */
+ @Override
+ public String getSignature() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("T");
+ sb.append(typeVariable.getName());
+ sb.append(";");
+ return sb.toString();
+ }
+
+ /**
+ * @return the name of the type variable
+ */
+ public String getTypeVariableName() {
+ return typeVariable.getName();
+ }
+
+ public ReferenceType getUpperBound() {
+ return (ReferenceType) typeVariable.resolve(world).getUpperBound();
+ }
+
+ /**
+ * resolve the type variable we are managing and then return this object. 'this' is already a ResolvedType but the type variable
+ * may transition from a not-resolved to a resolved state.
+ */
+ public ResolvedType resolve(World world) {
+ typeVariable.resolve(world);
+ return this;
+ }
+
+ /**
+ * @return true if the type variable this reference is managing is resolved
+ */
+ public boolean isTypeVariableResolved() {
+ return typeVariable.isResolved;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedType.java
new file mode 100644
index 000000000..d8d46176d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedType.java
@@ -0,0 +1,968 @@
+/* *******************************************************************
+ * Copyright (c) 2002,2005 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Andy Clement start of generics upgrade...
+ * Adrian Colyer - overhaul
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.GenericSignature;
+import org.aspectj.util.GenericSignature.ClassSignature;
+import org.aspectj.util.GenericSignatureParser;
+import org.aspectj.weaver.tools.Traceable;
+
+/**
+ * A UnresolvedType represents a type to the weaver. UnresolvedTypes are resolved in some World (a type repository). When a
+ * UnresolvedType is resolved it turns into a ResolvedType which may be a primitive type, or a ReferenceType. ReferenceTypes may
+ * refer to simple, generic, parameterized or type-variable based reference types. A ReferenceType is backed by a delegate that
+ * provides information about the type based on some repository (for example an Eclipse based delegate, a bytecode based delegate or
+ * a reflection based delegate).
+ * <p>
+ * Every UnresolvedType has a signature, the unique key for the type in the world.
+ */
+public class UnresolvedType implements Traceable, TypeVariableDeclaringElement {
+
+ // common type structures
+ public static final UnresolvedType[] NONE = new UnresolvedType[0];
+ public static final UnresolvedType OBJECT = forSignature("Ljava/lang/Object;");
+ public static final UnresolvedType OBJECTARRAY = forSignature("[Ljava/lang/Object;");
+ public static final UnresolvedType CLONEABLE = forSignature("Ljava/lang/Cloneable;");
+ public static final UnresolvedType SERIALIZABLE = forSignature("Ljava/io/Serializable;");
+ public static final UnresolvedType THROWABLE = forSignature("Ljava/lang/Throwable;");
+ public static final UnresolvedType RUNTIME_EXCEPTION = forSignature("Ljava/lang/RuntimeException;");
+ public static final UnresolvedType ERROR = forSignature("Ljava/lang/Error;");
+ public static final UnresolvedType AT_INHERITED = forSignature("Ljava/lang/annotation/Inherited;");
+ public static final UnresolvedType AT_RETENTION = forSignature("Ljava/lang/annotation/Retention;");
+ public static final UnresolvedType ENUM = forSignature("Ljava/lang/Enum;");
+ public static final UnresolvedType ANNOTATION = forSignature("Ljava/lang/annotation/Annotation;");
+ public static final UnresolvedType JL_CLASS = forSignature("Ljava/lang/Class;");
+ public static final UnresolvedType JAVA_LANG_CLASS_ARRAY = forSignature("[Ljava/lang/Class;");
+ public static final UnresolvedType JL_STRING = forSignature("Ljava/lang/String;");
+ public static final UnresolvedType JL_EXCEPTION = forSignature("Ljava/lang/Exception;");
+ public static final UnresolvedType JAVA_LANG_REFLECT_METHOD = forSignature("Ljava/lang/reflect/Method;");
+ public static final UnresolvedType JAVA_LANG_REFLECT_FIELD = forSignature("Ljava/lang/reflect/Field;");
+ public static final UnresolvedType JAVA_LANG_REFLECT_CONSTRUCTOR = forSignature("Ljava/lang/reflect/Constructor;");
+ public static final UnresolvedType JAVA_LANG_ANNOTATION = forSignature("Ljava/lang/annotation/Annotation;");
+ public static final UnresolvedType SUPPRESS_AJ_WARNINGS = forSignature("Lorg/aspectj/lang/annotation/SuppressAjWarnings;");
+ public static final UnresolvedType AT_TARGET = forSignature("Ljava/lang/annotation/Target;");
+ public static final UnresolvedType SOMETHING = new UnresolvedType("?");
+ public static final UnresolvedType[] ARRAY_WITH_JUST_OBJECT = new UnresolvedType[] { OBJECT };
+ public static final UnresolvedType JOINPOINT_STATICPART = forSignature("Lorg/aspectj/lang/JoinPoint$StaticPart;");
+ public static final UnresolvedType JOINPOINT_ENCLOSINGSTATICPART = forSignature("Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;");
+ public static final UnresolvedType AJC_PRIVILEGED = forSignature("Lorg/aspectj/internal/lang/annotation/ajcPrivileged;");
+
+ public static final UnresolvedType BOOLEAN = forPrimitiveType("Z");
+ public static final UnresolvedType BYTE = forPrimitiveType("B");
+ public static final UnresolvedType CHAR = forPrimitiveType("C");
+ public static final UnresolvedType DOUBLE = forPrimitiveType("D");
+ public static final UnresolvedType FLOAT = forPrimitiveType("F");
+ public static final UnresolvedType INT = forPrimitiveType("I");
+ public static final UnresolvedType LONG = forPrimitiveType("J");
+ public static final UnresolvedType SHORT = forPrimitiveType("S");
+ public static final UnresolvedType VOID = forPrimitiveType("V");
+
+ // A type is considered missing if we have a signature for it but cannot find the delegate
+ public static final String MISSING_NAME = "@missing@";
+
+ // OPTIMIZE I dont think you can ask something unresolved what kind of type it is, how can it always know? Push down into
+ // resolvedtype that will force references to resolvedtypes to be correct rather than relying on unresolvedtypes to answer
+ // questions
+ protected TypeKind typeKind = TypeKind.SIMPLE; // what kind of type am I?
+
+ protected String signature;
+
+ /**
+ * The erasure of the signature. Contains only the Java signature of the type with all supertype, superinterface, type variable,
+ * and parameter information removed.
+ */
+ protected String signatureErasure;
+
+ /**
+ * Calculated on first request - the package name (java.lang for type java.lang.String)
+ */
+ private String packageName;
+
+ /**
+ * Calculated on first request - the class name (String for type java.lang.String)
+ */
+ private String className;
+
+ /**
+ * Iff isParameterized(), then these are the type parameters
+ */
+ protected UnresolvedType[] typeParameters;
+
+ /**
+ * Iff isGeneric(), then these are the type variables declared on the type Iff isParameterized(), then these are the type
+ * variables bound as parameters in the type
+ */
+ // OPTIMIZE should be no state in here that will damage whether equals() is correct...
+ protected TypeVariable[] typeVariables;
+
+ public boolean isPrimitiveType() {
+ return typeKind == TypeKind.PRIMITIVE;
+ }
+
+ public boolean isVoid() {
+ // OPTIMIZE promote to bitflag?
+ return signature.equals("V");
+ }
+
+ public boolean isSimpleType() {
+ return typeKind == TypeKind.SIMPLE;
+ }
+
+ public boolean isRawType() {
+ return typeKind == TypeKind.RAW;
+ }
+
+ public boolean isGenericType() {
+ return typeKind == TypeKind.GENERIC;
+ }
+
+ public boolean isParameterizedType() {
+ return typeKind == TypeKind.PARAMETERIZED;
+ }
+
+ public boolean isParameterizedOrGenericType() {
+ return typeKind == TypeKind.GENERIC || typeKind == TypeKind.PARAMETERIZED;
+ }
+
+ public boolean isParameterizedOrRawType() {
+ return typeKind == TypeKind.PARAMETERIZED || typeKind == TypeKind.RAW;
+ }
+
+ public boolean isTypeVariableReference() {
+ return typeKind == TypeKind.TYPE_VARIABLE;
+ }
+
+ public boolean isGenericWildcard() {
+ return typeKind == TypeKind.WILDCARD;
+ }
+
+ public TypeKind getTypekind() {
+ return typeKind;
+ }
+
+ // for any reference type, we can get some extra information...
+ public final boolean isArray() {
+ return signature.length() > 0 && signature.charAt(0) == '[';
+ }
+
+ /**
+ * Equality is checked based on the underlying signature.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof UnresolvedType)) {
+ return false;
+ }
+ return signature.equals(((UnresolvedType) other).signature);
+ }
+
+ /**
+ * Equality is checked based on the underlying signature, so the hash code of a particular type is the hash code of its
+ * signature string.
+ */
+ @Override
+ public int hashCode() {
+ return signature.hashCode();
+ }
+
+ protected UnresolvedType(String signature) {
+ this.signature = signature;
+ this.signatureErasure = signature;
+ }
+
+ protected UnresolvedType(String signature, String signatureErasure) {
+ this.signature = signature;
+ this.signatureErasure = signatureErasure;
+ }
+
+ // called from TypeFactory
+ public UnresolvedType(String signature, String signatureErasure, UnresolvedType[] typeParams) {
+ this.signature = signature;
+ this.signatureErasure = signatureErasure;
+ this.typeParameters = typeParams;
+ if (typeParams != null) {
+ this.typeKind = TypeKind.PARAMETERIZED;
+ }
+ }
+
+ // The operations supported by an UnresolvedType are those that do not require a world
+
+ /**
+ * This is the size of this type as used in JVM.
+ */
+ public int getSize() {
+ return size;
+ }
+
+ private int size = 1;
+
+ /**
+ * NOTE: Use forSignature() if you can, it'll be cheaper ! Constructs a UnresolvedType for a java language type name. For
+ * example:
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * UnresolvedType.forName(&quot;java.lang.Thread[]&quot;)
+ * UnresolvedType.forName(&quot;int&quot;)
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * Types may equivalently be produced by this or by {@link #forSignature(String)}.
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * UnresolvedType.forName(&quot;java.lang.Thread[]&quot;).equals(Type.forSignature(&quot;[Ljava/lang/Thread;&quot;)
+ * UnresolvedType.forName(&quot;int&quot;).equals(Type.forSignature(&quot;I&quot;))
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @param name the java language type name in question.
+ * @return a type object representing that java language type.
+ */
+ // OPTIMIZE change users of this to use forSignature, especially for simple cases
+ public static UnresolvedType forName(String name) {
+ return forSignature(nameToSignature(name));
+ }
+
+ /**
+ * Constructs a UnresolvedType for each java language type name in an incoming array.
+ *
+ * @param names an array of java language type names.
+ * @return an array of UnresolvedType objects.
+ * @see #forName(String)
+ */
+ public static UnresolvedType[] forNames(String[] names) {
+ UnresolvedType[] ret = new UnresolvedType[names.length];
+ for (int i = 0, len = names.length; i < len; i++) {
+ ret[i] = UnresolvedType.forName(names[i]);
+ }
+ return ret;
+ }
+
+ public static UnresolvedType forGenericType(String name, TypeVariable[] tvbs, String genericSig) {
+ String sig = nameToSignature(name);
+ UnresolvedType ret = UnresolvedType.forSignature(sig);
+ ret.typeKind = TypeKind.GENERIC;
+ ret.typeVariables = tvbs;
+ ret.signatureErasure = sig;
+ return ret;
+ }
+
+ public static UnresolvedType forGenericTypeSignature(String sig, String declaredGenericSig) {
+ UnresolvedType ret = UnresolvedType.forSignature(sig);
+ ret.typeKind = TypeKind.GENERIC;
+
+ ClassSignature csig = new GenericSignatureParser().parseAsClassSignature(declaredGenericSig);
+
+ GenericSignature.FormalTypeParameter[] ftps = csig.formalTypeParameters;
+ ret.typeVariables = new TypeVariable[ftps.length];
+ for (int i = 0; i < ftps.length; i++) {
+ GenericSignature.FormalTypeParameter parameter = ftps[i];
+ if (parameter.classBound instanceof GenericSignature.ClassTypeSignature) {
+ GenericSignature.ClassTypeSignature cts = (GenericSignature.ClassTypeSignature) parameter.classBound;
+ ret.typeVariables[i] = new TypeVariable(ftps[i].identifier, UnresolvedType.forSignature(cts.outerType.identifier
+ + ";"));
+ } else if (parameter.classBound instanceof GenericSignature.TypeVariableSignature) {
+ GenericSignature.TypeVariableSignature tvs = (GenericSignature.TypeVariableSignature) parameter.classBound;
+ UnresolvedTypeVariableReferenceType utvrt = new UnresolvedTypeVariableReferenceType(new TypeVariable(
+ tvs.typeVariableName));
+ ret.typeVariables[i] = new TypeVariable(ftps[i].identifier, utvrt);
+ } else {
+ throw new BCException(
+ "UnresolvedType.forGenericTypeSignature(): Do not know how to process type variable bound of type '"
+ + parameter.classBound.getClass() + "'. Full signature is '" + sig + "'");
+ }
+ }
+ ret.signatureErasure = sig;
+ ret.signature = ret.signatureErasure;
+ return ret;
+ }
+
+ public static UnresolvedType forGenericTypeVariables(String sig, TypeVariable[] tVars) {
+ UnresolvedType ret = UnresolvedType.forSignature(sig);
+ ret.typeKind = TypeKind.GENERIC;
+ ret.typeVariables = tVars;
+ ret.signatureErasure = sig;
+ ret.signature = ret.signatureErasure;
+ return ret;
+ }
+
+ public static UnresolvedType forRawTypeName(String name) {
+ UnresolvedType ret = UnresolvedType.forName(name);
+ ret.typeKind = TypeKind.RAW;
+ return ret;
+ }
+
+ public static UnresolvedType forPrimitiveType(String signature) {
+ UnresolvedType ret = new UnresolvedType(signature);
+ ret.typeKind = TypeKind.PRIMITIVE;
+ if (signature.equals("J") || signature.equals("D")) {
+ ret.size = 2;
+ } else if (signature.equals("V")) {
+ ret.size = 0;
+ }
+ return ret;
+ }
+
+ /**
+ * Creates a new type array with a fresh type appended to the end.
+ *
+ * @param types the left hand side of the new array
+ * @param end the right hand side of the new array
+ */
+ public static UnresolvedType[] add(UnresolvedType[] types, UnresolvedType end) {
+ int len = types.length;
+ UnresolvedType[] ret = new UnresolvedType[len + 1];
+ System.arraycopy(types, 0, ret, 0, len);
+ ret[len] = end;
+ return ret;
+ }
+
+ /**
+ * Creates a new type array with a fresh type inserted at the beginning.
+ *
+ *
+ * @param start the left hand side of the new array
+ * @param types the right hand side of the new array
+ */
+ public static UnresolvedType[] insert(UnresolvedType start, UnresolvedType[] types) {
+ int len = types.length;
+ UnresolvedType[] ret = new UnresolvedType[len + 1];
+ ret[0] = start;
+ System.arraycopy(types, 0, ret, 1, len);
+ return ret;
+ }
+
+ /**
+ * Constructs a Type for a JVM bytecode signature string. For example:
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * UnresolvedType.forSignature(&quot;[Ljava/lang/Thread;&quot;)
+ * UnresolvedType.forSignature(&quot;I&quot;);
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * Types may equivalently be produced by this or by {@link #forName(String)}. This method should not be passed P signatures.
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * UnresolvedType.forName(&quot;java.lang.Thread[]&quot;).equals(Type.forSignature(&quot;[Ljava/lang/Thread;&quot;)
+ * UnresolvedType.forName(&quot;int&quot;).equals(Type.forSignature(&quot;I&quot;))
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @param signature the JVM bytecode signature string for the desired type.
+ * @return a type object represnting that JVM bytecode signature.
+ */
+ public static UnresolvedType forSignature(String signature) {
+ assert !(signature.startsWith("L") && signature.indexOf("<") != -1);
+ switch (signature.charAt(0)) {
+ case 'B':
+ return UnresolvedType.BYTE;
+ case 'C':
+ return UnresolvedType.CHAR;
+ case 'D':
+ return UnresolvedType.DOUBLE;
+ case 'F':
+ return UnresolvedType.FLOAT;
+ case 'I':
+ return UnresolvedType.INT;
+ case 'J':
+ return UnresolvedType.LONG;
+ case 'L':
+ return TypeFactory.createTypeFromSignature(signature);
+ case 'P':
+ return TypeFactory.createTypeFromSignature(signature);
+ case 'S':
+ return UnresolvedType.SHORT;
+ case 'V':
+ return UnresolvedType.VOID;
+ case 'Z':
+ return UnresolvedType.BOOLEAN;
+ case '[':
+ return TypeFactory.createTypeFromSignature(signature);
+ case '+':
+ return TypeFactory.createTypeFromSignature(signature);
+ case '-':
+ return TypeFactory.createTypeFromSignature(signature);
+ case '?':
+ return TypeFactory.createTypeFromSignature(signature);
+ case 'T':
+ return TypeFactory.createTypeFromSignature(signature);
+ default:
+ throw new BCException("Bad type signature " + signature);
+ }
+ }
+
+ /**
+ * Constructs a UnresolvedType for each JVM bytecode type signature in an incoming array.
+ *
+ * @param names an array of JVM bytecode type signatures
+ * @return an array of UnresolvedType objects.
+ * @see #forSignature(String)
+ */
+ public static UnresolvedType[] forSignatures(String[] sigs) {
+ UnresolvedType[] ret = new UnresolvedType[sigs.length];
+ for (int i = 0, len = sigs.length; i < len; i++) {
+ ret[i] = UnresolvedType.forSignature(sigs[i]);
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the name of this type in java language form (e.g. java.lang.Thread or boolean[]). This produces a more aesthetically
+ * pleasing string than {@link java.lang.Class#getName()}.
+ *
+ * @return the java language name of this type.
+ */
+ public String getName() {
+ return signatureToName(signature);
+ }
+
+ public String getSimpleName() {
+ String name = getRawName();
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot != -1) {
+ name = name.substring(lastDot + 1);
+ }
+ if (isParameterizedType()) {
+ StringBuffer sb = new StringBuffer(name);
+ sb.append("<");
+ for (int i = 0; i < (typeParameters.length - 1); i++) {
+ sb.append(typeParameters[i].getSimpleName());
+ sb.append(",");
+ }
+ sb.append(typeParameters[typeParameters.length - 1].getSimpleName());
+ sb.append(">");
+ name = sb.toString();
+ }
+ return name;
+ }
+
+ public String getRawName() {
+ return signatureToName((signatureErasure == null ? signature : signatureErasure));
+ }
+
+ public String getBaseName() {
+ String name = getName();
+ if (isParameterizedType() || isGenericType()) {
+ if (typeParameters == null) {
+ return name;
+ } else {
+ return name.substring(0, name.indexOf("<"));
+ }
+ } else {
+ return name;
+ }
+ }
+
+ public String getSimpleBaseName() {
+ String name = getBaseName();
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot != -1) {
+ name = name.substring(lastDot + 1);
+ }
+ return name;
+ }
+
+ /**
+ * Returns an array of strings representing the java langauge names of an array of types.
+ *
+ * @param types an array of UnresolvedType objects
+ * @return an array of Strings fo the java language names of types.
+ * @see #getName()
+ */
+ public static String[] getNames(UnresolvedType[] types) {
+ String[] ret = new String[types.length];
+ for (int i = 0, len = types.length; i < len; i++) {
+ ret[i] = types[i].getName();
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the name of this type in JVM signature form. For all UnresolvedType t:
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * UnresolvedType.forSignature(t.getSignature()).equals(t)
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * and for all String s where s is a lexically valid JVM type signature string:
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * UnresolvedType.forSignature(s).getSignature().equals(s)
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @return the java JVM signature string for this type.
+ */
+ public String getSignature() {
+ return signature;
+ }
+
+ /**
+ * For parameterized types, return the signature for the raw type
+ */
+ public String getErasureSignature() {
+ if (signatureErasure == null) {
+ return signature;
+ }
+ return signatureErasure;
+ }
+
+ private boolean needsModifiableDelegate = false;
+
+ public boolean needsModifiableDelegate() {
+ return needsModifiableDelegate;
+ }
+
+ public void setNeedsModifiableDelegate(boolean b) {
+ this.needsModifiableDelegate = b;
+ }
+
+ public UnresolvedType getRawType() {
+ return UnresolvedType.forSignature(getErasureSignature());
+ }
+
+ /**
+ * Returns a UnresolvedType object representing the effective outermost enclosing type for a name type. For all other types,
+ * this will return the type itself.
+ *
+ * The only guarantee is given in JLS 13.1 where code generated according to those rules will have type names that can be split
+ * apart in this way.
+ *
+ * @return the outermost enclosing UnresolvedType object or this.
+ */
+ public UnresolvedType getOutermostType() {
+ if (isArray() || isPrimitiveType()) {
+ return this;
+ }
+ String sig = getErasureSignature();
+ int dollar = sig.indexOf('$');
+ if (dollar != -1) {
+ return UnresolvedType.forSignature(sig.substring(0, dollar) + ';');
+ } else {
+ return this;
+ }
+ }
+
+ /**
+ * Returns a UnresolvedType object representing the component type of this array, or null if this type does not represent an
+ * array type.
+ *
+ * @return the component UnresolvedType object, or null.
+ */
+ public UnresolvedType getComponentType() {
+ if (isArray()) {
+ return forSignature(signature.substring(1));
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a java language string representation of this type.
+ */
+ @Override
+ public String toString() {
+ return getName(); // + " - " + getKind();
+ }
+
+ public String toDebugString() {
+ return getName();
+ }
+
+ // ---- requires worlds
+
+ /**
+ * Returns a resolved version of this type according to a particular world.
+ *
+ * @param world the {@link World} within which to resolve.
+ * @return a resolved type representing this type in the appropriate world.
+ */
+ public ResolvedType resolve(World world) {
+ return world.resolve(this);
+ }
+
+ // ---- helpers
+
+ private static String signatureToName(String signature) {
+ switch (signature.charAt(0)) {
+ case 'B':
+ return "byte";
+ case 'C':
+ return "char";
+ case 'D':
+ return "double";
+ case 'F':
+ return "float";
+ case 'I':
+ return "int";
+ case 'J':
+ return "long";
+ case 'L':
+ String name = signature.substring(1, signature.length() - 1).replace('/', '.');
+ return name;
+ case 'T':
+ StringBuffer nameBuff2 = new StringBuffer();
+ int colon = signature.indexOf(";");
+ String tvarName = signature.substring(1, colon);
+ nameBuff2.append(tvarName);
+ return nameBuff2.toString();
+ case 'P': // it's one of our parameterized type sigs
+ StringBuffer nameBuff = new StringBuffer();
+ // signature for parameterized types is e.g.
+ // List<String> -> Ljava/util/List<Ljava/lang/String;>;
+ // Map<String,List<Integer>> -> Ljava/util/Map<java/lang/String;Ljava/util/List<Ljava/lang/Integer;>;>;
+ int paramNestLevel = 0;
+ for (int i = 1; i < signature.length(); i++) {
+ char c = signature.charAt(i);
+ switch (c) {
+ case '/':
+ nameBuff.append('.');
+ break;
+ case '<':
+ nameBuff.append("<");
+ paramNestLevel++;
+ StringBuffer innerBuff = new StringBuffer();
+ while (paramNestLevel > 0) {
+ c = signature.charAt(++i);
+ if (c == '<') {
+ paramNestLevel++;
+ }
+ if (c == '>') {
+ paramNestLevel--;
+ }
+ if (paramNestLevel > 0) {
+ innerBuff.append(c);
+ }
+ if (c == ';' && paramNestLevel == 1) {
+ nameBuff.append(signatureToName(innerBuff.toString()));
+ if (signature.charAt(i + 1) != '>') {
+ nameBuff.append(',');
+ }
+ innerBuff = new StringBuffer();
+ }
+ }
+ nameBuff.append(">");
+ break;
+ case ';':
+ break;
+ default:
+ nameBuff.append(c);
+ }
+ }
+ return nameBuff.toString();
+ case 'S':
+ return "short";
+ case 'V':
+ return "void";
+ case 'Z':
+ return "boolean";
+ case '[':
+ return signatureToName(signature.substring(1, signature.length())) + "[]";
+ // case '<':
+ // // its a generic!
+ // if (signature.charAt(1)=='>') return signatureToName(signature.substring(2));
+ case '+':
+ return "? extends " + signatureToName(signature.substring(1, signature.length()));
+ case '-':
+ return "? super " + signatureToName(signature.substring(1, signature.length()));
+ case '*':
+ return "?";
+ default:
+ throw new BCException("Bad type signature: " + signature);
+ }
+ }
+
+ private static String nameToSignature(String name) {
+ int len = name.length();
+ if (len < 8) {
+ if (name.equals("int")) {
+ return "I";
+ }
+ if (name.equals("void")) {
+ return "V";
+ }
+ if (name.equals("long")) {
+ return "J";
+ }
+ if (name.equals("boolean")) {
+ return "Z";
+ }
+ if (name.equals("double")) {
+ return "D";
+ }
+ if (name.equals("float")) {
+ return "F";
+ }
+ if (name.equals("byte")) {
+ return "B";
+ }
+ if (name.equals("short")) {
+ return "S";
+ }
+ if (name.equals("char")) {
+ return "C";
+ }
+ if (name.equals("?")) {
+ return name;
+ }
+ }
+ if (len == 0) {
+ throw new BCException("Bad type name: " + name);
+ }
+ if (name.endsWith("[]")) {
+ return "[" + nameToSignature(name.substring(0, name.length() - 2));
+ }
+
+ // Sometimes the 'name' for an array is of the form: [Ljava.lang.String;
+ if (name.charAt(0)=='[') {
+ return name.replace('.','/');
+ }
+
+ if (name.indexOf("<") == -1) {
+ // not parameterized
+ return new StringBuilder("L").append(name.replace('.', '/')).append(';').toString();
+ } else {
+ StringBuffer nameBuff = new StringBuffer();
+ int nestLevel = 0;
+ nameBuff.append("P");
+ for (int i = 0; i < len; i++) {
+ char c = name.charAt(i);
+ switch (c) {
+ case '.':
+ nameBuff.append('/');
+ break;
+ case '<':
+ nameBuff.append("<");
+ nestLevel++;
+ StringBuffer innerBuff = new StringBuffer();
+ while (nestLevel > 0) {
+ c = name.charAt(++i);
+ if (c == '<') {
+ nestLevel++;
+ } else if (c == '>') {
+ nestLevel--;
+ }
+ if (c == ',' && nestLevel == 1) {
+ nameBuff.append(nameToSignature(innerBuff.toString()));
+ innerBuff = new StringBuffer();
+ } else {
+ if (nestLevel > 0) {
+ innerBuff.append(c);
+ }
+ }
+ }
+ nameBuff.append(nameToSignature(innerBuff.toString()));
+ nameBuff.append('>');
+ break;
+// case '>':
+// throw new IllegalStateException("Should by matched by <");
+// case ',':
+// throw new IllegalStateException("Should only happen inside <...>");
+ default:
+ nameBuff.append(c);
+ }
+ }
+ nameBuff.append(";");
+ return nameBuff.toString();
+ }
+ }
+
+ /**
+ * Write out an UnresolvedType - the signature should be enough.
+ */
+ public final void write(CompressingDataOutputStream s) throws IOException {
+ s.writeUTF(getSignature());
+ }
+
+ /**
+ * Read in an UnresolvedType - just read the signature and rebuild the UnresolvedType.
+ */
+ public static UnresolvedType read(DataInputStream s) throws IOException {
+ String sig = s.readUTF();
+ if (sig.equals(MISSING_NAME)) {
+ return ResolvedType.MISSING;
+ } else {
+ // TODO isn't it a shame to build these (this method is expensive) and then chuck them away on resolution?
+ // TODO review callers and see if they are immediately resolving it, maybe we can do something more optimal if they are
+ return UnresolvedType.forSignature(sig);
+ }
+ }
+
+ public String getNameAsIdentifier() {
+ return getName().replace('.', '_');
+ }
+
+ public String getPackageNameAsIdentifier() {
+ String name = getName();
+ int index = name.lastIndexOf('.');
+ if (index == -1) {
+ return "";
+ } else {
+ return name.substring(0, index).replace('.', '_');
+ }
+ }
+
+ public UnresolvedType[] getTypeParameters() {
+ return typeParameters == null ? UnresolvedType.NONE : typeParameters;
+ }
+
+ public TypeVariable[] getTypeVariables() {
+ return typeVariables;
+ }
+
+ public static class TypeKind {
+ // Note: It is not sufficient to say that a parameterized type with no type parameters in fact
+ // represents a raw type - a parameterized type with no type parameters can represent
+ // an inner type of a parameterized type that specifies no type parameters of its own.
+ public final static TypeKind PRIMITIVE = new TypeKind("primitive");
+ public final static TypeKind SIMPLE = new TypeKind("simple"); // a type with NO type parameters/vars
+ public final static TypeKind RAW = new TypeKind("raw"); // the erasure of a generic type
+ public final static TypeKind GENERIC = new TypeKind("generic"); // a generic type
+ public final static TypeKind PARAMETERIZED = new TypeKind("parameterized"); // a parameterized type
+ public final static TypeKind TYPE_VARIABLE = new TypeKind("type_variable"); // a type variable
+ public final static TypeKind WILDCARD = new TypeKind("wildcard"); // a generic wildcard type
+
+ @Override
+ public String toString() {
+ return type;
+ }
+
+ private TypeKind(String type) {
+ this.type = type;
+ }
+
+ private final String type;
+ }
+
+ @Override
+ public TypeVariable getTypeVariableNamed(String name) {
+ TypeVariable[] vars = getTypeVariables();
+ if (vars == null || vars.length == 0) {
+ return null;
+ }
+ for (int i = 0; i < vars.length; i++) {
+ TypeVariable aVar = vars[i];
+ if (aVar.getName().equals(name)) {
+ return aVar;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toTraceString() {
+ return getClass().getName() + "[" + getName() + "]";
+ }
+
+ /**
+ * Return a version of this parameterized type in which any type parameters that are type variable references are replaced by
+ * their matching type variable binding.
+ */
+ // OPTIMIZE methods like this just allow callers to be lazy and not ensure they are working with the right (resolved) subtype
+ public UnresolvedType parameterize(Map<String, UnresolvedType> typeBindings) {
+ throw new UnsupportedOperationException("unable to parameterize unresolved type: " + signature);
+ }
+
+ /**
+ * @return the class name (does not include the package name)
+ */
+ public String getClassName() {
+ if (className == null) {
+ String name = getName();
+ if (name.indexOf("<") != -1) {
+ name = name.substring(0, name.indexOf("<"));
+ }
+ int index = name.lastIndexOf('.');
+ if (index == -1) {
+ className = name;
+ } else {
+ className = name.substring(index + 1);
+ }
+ }
+ return className;
+ }
+
+ /**
+ * @return the package name (no class name included)
+ */
+ public String getPackageName() {
+ if (packageName == null) {
+ String name = getName();
+ int angly = name.indexOf('<');
+ if (angly != -1) {
+ name = name.substring(0, angly);
+ }
+ int index = name.lastIndexOf('.');
+ if (index == -1) {
+ packageName = "";
+ } else {
+ packageName = name.substring(0, index);
+ }
+ }
+ return packageName;
+ }
+
+ public static void writeArray(UnresolvedType[] types, CompressingDataOutputStream stream) throws IOException {
+ int len = types.length;
+ stream.writeShort(len);
+ for (UnresolvedType type : types) {
+ type.write(stream);
+ }
+ }
+
+ public static UnresolvedType[] readArray(DataInputStream s) throws IOException {
+ int len = s.readShort();
+ if (len == 0) {
+ return UnresolvedType.NONE;
+ }
+ UnresolvedType[] types = new UnresolvedType[len];
+ for (int i = 0; i < len; i++) {
+ types[i] = UnresolvedType.read(s);
+ }
+ return types;
+ }
+
+ public static UnresolvedType makeArray(UnresolvedType base, int dims) {
+ StringBuffer sig = new StringBuffer();
+ for (int i = 0; i < dims; i++) {
+ sig.append("[");
+ }
+ sig.append(base.getSignature());
+ return UnresolvedType.forSignature(sig.toString());
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java
new file mode 100644
index 000000000..fbeb47164
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java
@@ -0,0 +1,90 @@
+/* *******************************************************************
+ * Copyright (c) 2005-2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class UnresolvedTypeVariableReferenceType extends UnresolvedType implements TypeVariableReference {
+
+ private TypeVariable typeVariable;
+
+ // constructor used as place-holder when dealing with circular refs such as Enum
+ public UnresolvedTypeVariableReferenceType() {
+ super("Ljava/lang/Object;");
+ }
+
+ public UnresolvedTypeVariableReferenceType(TypeVariable aTypeVariable) {
+ super("T" + aTypeVariable.getName() + ";", aTypeVariable.getFirstBound().getErasureSignature());//aTypeVariable.getFirstBound().getSignature());
+ this.typeVariable = aTypeVariable;
+ }
+
+ // only used when resolving circular refs...
+ public void setTypeVariable(TypeVariable aTypeVariable) {
+ this.signature = "T" + aTypeVariable.getName() + ";"; // aTypeVariable.getUpperBound().getSignature();
+ this.signatureErasure = aTypeVariable.getFirstBound().getErasureSignature();
+ this.typeVariable = aTypeVariable;
+ this.typeKind = TypeKind.TYPE_VARIABLE;
+ }
+
+ @Override
+ public ResolvedType resolve(World world) {
+ TypeVariableDeclaringElement typeVariableScope = world.getTypeVariableLookupScope();
+ TypeVariable resolvedTypeVariable = null;
+ TypeVariableReferenceType tvrt = null;
+ if (typeVariableScope == null) {
+ // throw new BCException("There is no scope in which to lookup type variables!");
+ // FIXME asc correct thing to do is go bang, but to limp along, lets cope with the scope missing
+ resolvedTypeVariable = typeVariable.resolve(world);
+ tvrt = new TypeVariableReferenceType(resolvedTypeVariable, world);
+ } else {
+ boolean foundOK = false;
+ resolvedTypeVariable = typeVariableScope.getTypeVariableNamed(typeVariable.getName());
+ // FIXME asc remove this when the shared type var stuff is sorted
+ if (resolvedTypeVariable == null) {
+ resolvedTypeVariable = typeVariable.resolve(world);
+ } else {
+ foundOK = true;
+ }
+ tvrt = new TypeVariableReferenceType(resolvedTypeVariable, world);
+ }
+
+ return tvrt;
+ }
+
+ @Override
+ public boolean isTypeVariableReference() {
+ return true;
+ }
+
+ public TypeVariable getTypeVariable() {
+ return typeVariable;
+ }
+
+ @Override
+ public String toString() {
+ if (typeVariable == null) {
+ return "<type variable not set!>";
+ } else {
+ return "T" + typeVariable.getName() + ";";
+ }
+ }
+
+ @Override
+ public String toDebugString() {
+ return typeVariable.getName();
+ }
+
+ @Override
+ public String getErasureSignature() {
+ return typeVariable.getFirstBound().getSignature();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Utils.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Utils.java
new file mode 100644
index 000000000..8053af0c0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/Utils.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ *
+ * @author Andy Clement
+ */
+public class Utils {
+
+ /**
+ * Check if the annotations contain a SuppressAjWarnings annotation and if that annotation specifies that the given lint message
+ * (identified by its key) should be ignored.
+ *
+ */
+ public static boolean isSuppressing(AnnotationAJ[] anns, String lintkey) {
+ if (anns == null) {
+ return false;
+ }
+ // Go through the annotation types on the advice
+ for (int i = 0; i < anns.length; i++) {
+ if (UnresolvedType.SUPPRESS_AJ_WARNINGS.getSignature().equals(anns[i].getTypeSignature())) {
+ // Two possibilities:
+ // 1. there are no values specified (i.e. @SuppressAjWarnings)
+ // 2. there are values specified (i.e. @SuppressAjWarnings("A") or @SuppressAjWarnings({"A","B"})
+ String value = anns[i].getStringFormOfValue("value");
+ // Slightly lazy, just doing a string indexof
+ if (value == null || value.indexOf(lintkey) != -1) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/VersionedDataInputStream.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/VersionedDataInputStream.java
new file mode 100644
index 000000000..38b2081b0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/VersionedDataInputStream.java
@@ -0,0 +1,87 @@
+/* *******************************************************************
+ * Copyright (c) 2005-2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement (IBM, SpringSource)
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+
+/**
+ * Lightweight subclass of DataInputStream that knows what version of the weaver was used to construct the data in it. The input
+ * stream has a constant pool reader attached which enables it to decode constant pool references found within the data being read.
+ *
+ * @author Andy Clement
+ */
+public class VersionedDataInputStream extends DataInputStream {
+
+ private WeaverVersionInfo version = new WeaverVersionInfo();// assume we are the latest unless something tells us otherwise...
+
+ private ConstantPoolReader constantPoolReader;
+
+ public VersionedDataInputStream(InputStream is, ConstantPoolReader constantPoolReader) {
+ super(is);
+ this.constantPoolReader = constantPoolReader;
+ }
+
+ public int getMajorVersion() {
+ return version.getMajorVersion();
+ }
+
+ public int getMinorVersion() {
+ return version.getMinorVersion();
+ }
+
+ public long getBuildstamp() {
+ return version.getBuildstamp();
+ }
+
+ public void setVersion(WeaverVersionInfo version) {
+ this.version = version;
+ }
+
+ public String readUtf8(int cpIndex) {
+ if (constantPoolReader == null) {
+ throw new IllegalStateException();
+ }
+ if (cpIndex < 0) {
+ throw new IllegalStateException(cpIndex + "");
+ }
+ return constantPoolReader.readUtf8(cpIndex);
+ }
+
+ public boolean canDecompress() {
+ return constantPoolReader != null;
+ }
+
+ public boolean isAtLeast169() {
+ return getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_AJ169;
+ }
+
+ public String readPath() throws IOException {
+ return readUtf8(readShort());
+ }
+
+ public String readSignature() throws IOException {
+ return readUtf8(readShort());
+ }
+
+ public UnresolvedType readSignatureAsUnresolvedType() throws IOException {
+ return UnresolvedType.forSignature(readUtf8(readShort()));
+ }
+
+ public String toString() {
+ return "VersionedDataInputStream: version=" + version + " constantPoolReader?" + (constantPoolReader != null);
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeakClassLoaderReference.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeakClassLoaderReference.java
new file mode 100644
index 000000000..ddca93202
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeakClassLoaderReference.java
@@ -0,0 +1,69 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Wraps a reference to a classloader inside a WeakReference. This should be used where we do not want the existence of a
+ * classloader reference to prevent garbage collection of that classloader (and possibly an associated weaver instance in the case
+ * of load time weaving).
+ * <p>
+ * In more detail:<br>
+ * When load time weaving, the class Aj maintains a WeakHashMap from the classloader instance to a weaver instance. The aim is that
+ * the weaver is around as long as the classloader is and should the classloader be dereferenced then the weaver can also be garbage
+ * collected. The problem is that if there are many references to the classloader from within the weaver, these are considered hard
+ * references and cause the classloader to be long lived - even if the user of the classloader has dereferenced it in their code.
+ * The solution is that the weaver should use instances of WeakClassLoaderReference objects - so that when the users hard reference
+ * to the classloader goes, nothing in the weaver will cause it to hang around. There is a big assertion here that the
+ * WeakClassLoaderReference instances will not 'lose' their ClassLoader references until the top level ClassLoader reference is
+ * null'd. This means there is no need to check for the null case on get() in this WeakReference logic below, because we shouldn't
+ * be using this weaver if its associated ClassLoader has been collected. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=210470
+ *
+ *
+ * @author Andy Clement, Abraham Nevado
+ */
+public class WeakClassLoaderReference{
+
+ protected final int hashcode;
+
+ private final WeakReference loaderRef;
+
+ public WeakClassLoaderReference(ClassLoader loader) {
+ loaderRef = new WeakReference(loader);
+ if(loader == null){
+ // Bug: 363962
+ // Check that ClassLoader is not null, for instance when loaded from BootStrapClassLoader
+ hashcode = System.identityHashCode(this);
+ }else{
+ hashcode = loader.hashCode() * 37;
+ }
+ }
+
+ public ClassLoader getClassLoader() {
+ ClassLoader instance = (ClassLoader) loaderRef.get();
+ // Assert instance!=null
+ return instance;
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof WeakClassLoaderReference))
+ return false;
+ WeakClassLoaderReference other = (WeakClassLoaderReference) obj;
+ return (other.hashcode == hashcode);
+ }
+
+ public int hashCode() {
+ return hashcode;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverMessages.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverMessages.java
new file mode 100644
index 000000000..5a64a77e8
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverMessages.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2004-2019 Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.aspectj.weaver;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * @author Andy Clement
+ * @author IBM
+ */
+public class WeaverMessages {
+
+ private static ResourceBundle bundle = ResourceBundle.getBundle("org.aspectj.weaver.weaver-messages");
+
+ public static final String ARGS_IN_DECLARE = "argsInDeclare";
+ public static final String CFLOW_IN_DECLARE = "cflowInDeclare";
+ public static final String IF_IN_DECLARE = "ifInDeclare";
+ public static final String THIS_OR_TARGET_IN_DECLARE = "thisOrTargetInDeclare";
+ public static final String ABSTRACT_POINTCUT = "abstractPointcut";
+ public static final String POINCUT_NOT_CONCRETE = "abstractPointcutNotMadeConcrete";
+ public static final String POINTCUT_NOT_VISIBLE = "pointcutNotVisible";
+ public static final String CONFLICTING_INHERITED_POINTCUTS = "conflictingInheritedPointcuts";
+ public static final String CIRCULAR_POINTCUT = "circularPointcutDeclaration";
+ public static final String CANT_FIND_POINTCUT = "cantFindPointcut";
+ public static final String EXACT_TYPE_PATTERN_REQD = "exactTypePatternRequired";
+ public static final String CANT_BIND_TYPE = "cantBindType";
+ public static final String WILDCARD_NOT_ALLOWED = "wildcardTypePatternNotAllowed";
+ public static final String FIELDS_CANT_HAVE_VOID_TYPE = "fieldCantBeVoid";
+ public static final String NO_NEWARRAY_JOINPOINTS_BY_DEFAULT = "noNewArrayJoinpointsByDefault";
+ public static final String UNSUPPORTED_POINTCUT_PRIMITIVE = "unsupportedPointcutPrimitive";
+ public static final String MISSING_TYPE_PREVENTS_MATCH = "missingTypePreventsMatch";
+
+ public static final String DECP_OBJECT = "decpObject";
+ public static final String CANT_EXTEND_SELF = "cantExtendSelf";
+ public static final String INTERFACE_CANT_EXTEND_CLASS = "interfaceExtendClass";
+ public static final String DECP_HIERARCHY_ERROR = "decpHierarchy";
+
+ public static final String MULTIPLE_MATCHES_IN_PRECEDENCE = "multipleMatchesInPrecedence";
+ public static final String TWO_STARS_IN_PRECEDENCE = "circularityInPrecedenceStar";
+ public static final String CLASSES_IN_PRECEDENCE = "nonAspectTypesInPrecedence";
+ public static final String TWO_PATTERN_MATCHES_IN_PRECEDENCE = "circularityInPrecedenceTwo";
+
+ public static final String NOT_THROWABLE = "notThrowable";
+
+ public static final String ITD_CONS_ON_ASPECT = "itdConsOnAspect";
+ public static final String ITD_RETURN_TYPE_MISMATCH = "returnTypeMismatch";
+ public static final String ITD_PARAM_TYPE_MISMATCH = "paramTypeMismatch";
+ public static final String ITD_VISIBILITY_REDUCTION = "visibilityReduction";
+ public static final String ITD_DOESNT_THROW = "doesntThrow";
+ public static final String ITD_OVERRIDDEN_STATIC = "overriddenStatic";
+ public static final String ITD_OVERIDDING_STATIC = "overridingStatic";
+ public static final String ITD_CONFLICT = "itdConflict";
+ public static final String ITD_MEMBER_CONFLICT = "itdMemberConflict";
+ public static final String ITD_NON_EXPOSED_IMPLEMENTOR = "itdNonExposedImplementor";
+ public static final String ITD_ABSTRACT_MUST_BE_PUBLIC_ON_INTERFACE = "itdAbstractMustBePublicOnInterface";
+ public static final String CANT_OVERRIDE_FINAL_MEMBER = "cantOverrideFinalMember";
+
+ public static final String NON_VOID_RETURN = "nonVoidReturn";
+ public static final String INCOMPATIBLE_RETURN_TYPE = "incompatibleReturnType";
+ public static final String CANT_THROW_CHECKED = "cantThrowChecked";
+ public static final String CIRCULAR_DEPENDENCY = "circularDependency";
+
+ public static final String MISSING_PER_CLAUSE = "missingPerClause";
+ public static final String WRONG_PER_CLAUSE = "wrongPerClause";
+
+ public static final String ALREADY_WOVEN = "alreadyWoven";
+ public static final String REWEAVABLE_MODE = "reweavableMode";
+ public static final String PROCESSING_REWEAVABLE = "processingReweavable";
+ public static final String MISSING_REWEAVABLE_TYPE = "missingReweavableType";
+ public static final String VERIFIED_REWEAVABLE_TYPE = "verifiedReweavableType";
+ public static final String ASPECT_NEEDED = "aspectNeeded";
+ public static final String REWEAVABLE_ASPECT_NOT_REGISTERED = "reweavableAspectNotRegistered";
+
+ public static final String CANT_FIND_TYPE = "cantFindType";
+ public static final String CANT_FIND_CORE_TYPE = "cantFindCoreType";
+ public static final String CANT_FIND_TYPE_WITHINPCD = "cantFindTypeWithinpcd";
+ public static final String CANT_FIND_TYPE_DURING_AROUND_WEAVE = "cftDuringAroundWeave";
+ public static final String CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT = "cftDuringAroundWeavePreinit";
+ public static final String CANT_FIND_TYPE_EXCEPTION_TYPE = "cftExceptionType";
+ public static final String CANT_FIND_TYPE_ARG_TYPE = "cftArgType";
+ public static final String CANT_FIND_PARENT_TYPE = "cantFindParentType";
+ public static final String CANT_FIND_PARENT_TYPE_NO_SUB = "cantFindParentTypeNoSub";
+ public static final String CANT_FIND_TYPE_FIELDS = "cantFindTypeFields";
+ public static final String CANT_FIND_TYPE_SUPERCLASS = "cantFindTypeSuperclass";
+ public static final String CANT_FIND_TYPE_INTERFACES = "cantFindTypeInterfaces";
+ public static final String CANT_FIND_TYPE_METHODS = "cantFindTypeMethods";
+ public static final String CANT_FIND_TYPE_POINTCUTS = "cantFindTypePointcuts";
+ public static final String CANT_FIND_TYPE_MODIFIERS = "cantFindTypeModifiers";
+ public static final String CANT_FIND_TYPE_ANNOTATION = "cantFindTypeAnnotation";
+ public static final String CANT_FIND_TYPE_ASSIGNABLE = "cantFindTypeAssignable";
+ public static final String CANT_FIND_TYPE_COERCEABLE = "cantFindTypeCoerceable";
+ public static final String CANT_FIND_TYPE_JOINPOINT = "cantFindTypeJoinPoint";
+ public static final String CANT_FIND_TYPE_INTERFACE_METHODS = "cantFindTypeInterfaceMethods";
+
+ public static final String DECP_BINARY_LIMITATION = "decpBinaryLimitation";
+ public static final String OVERWRITE_JSR45 = "overwriteJSR45";
+ public static final String IF_IN_PERCLAUSE = "ifInPerClause";
+ public static final String IF_LEXICALLY_IN_CFLOW = "ifLexicallyInCflow";
+ public static final String ONLY_BEFORE_ON_HANDLER = "onlyBeforeOnHandler";
+ public static final String NO_AROUND_ON_SYNCHRONIZATION = "noAroundOnSynchronization";
+ public static final String AROUND_ON_PREINIT = "aroundOnPreInit";
+ public static final String AROUND_ON_INIT = "aroundOnInit";
+ public static final String AROUND_ON_INTERFACE_STATICINIT = "aroundOnInterfaceStaticInit";
+
+ public static final String PROBLEM_GENERATING_METHOD = "problemGeneratingMethod";
+ public static final String CLASS_TOO_BIG = "classTooBig";
+
+ public static final String ZIPFILE_ENTRY_MISSING = "zipfileEntryMissing";
+ public static final String ZIPFILE_ENTRY_INVALID = "zipfileEntryInvalid";
+ public static final String DIRECTORY_ENTRY_MISSING = "directoryEntryMissing";
+ public static final String OUTJAR_IN_INPUT_PATH = "outjarInInputPath";
+
+ public static final String XLINT_LOAD_ERROR = "problemLoadingXLint";
+ public static final String XLINTDEFAULT_LOAD_ERROR = "unableToLoadXLintDefault";
+ public static final String XLINTDEFAULT_LOAD_PROBLEM = "errorLoadingXLintDefault";
+ public static final String XLINT_KEY_ERROR = "invalidXLintKey";
+ public static final String XLINT_VALUE_ERROR = "invalidXLintMessageKind";
+
+ public static final String UNBOUND_FORMAL = "unboundFormalInPC";
+ public static final String AMBIGUOUS_BINDING = "ambiguousBindingInPC";
+ public static final String AMBIGUOUS_BINDING_IN_OR = "ambiguousBindingInOrPC";
+ public static final String NEGATION_DOESNT_ALLOW_BINDING = "negationDoesntAllowBinding";
+
+ // Java5 messages
+ public static final String ITDC_ON_ENUM_NOT_ALLOWED = "itdcOnEnumNotAllowed";
+ public static final String ITDM_ON_ENUM_NOT_ALLOWED = "itdmOnEnumNotAllowed";
+ public static final String ITDF_ON_ENUM_NOT_ALLOWED = "itdfOnEnumNotAllowed";
+ public static final String CANT_DECP_ON_ENUM_TO_IMPL_INTERFACE = "cantDecpOnEnumToImplInterface";
+ public static final String CANT_DECP_ON_ENUM_TO_EXTEND_CLASS = "cantDecpOnEnumToExtendClass";
+ public static final String CANT_DECP_TO_MAKE_ENUM_SUPERTYPE = "cantDecpToMakeEnumSupertype";
+ public static final String ITDC_ON_ANNOTATION_NOT_ALLOWED = "itdcOnAnnotationNotAllowed";
+ public static final String ITDM_ON_ANNOTATION_NOT_ALLOWED = "itdmOnAnnotationNotAllowed";
+ public static final String ITDF_ON_ANNOTATION_NOT_ALLOWED = "itdfOnAnnotationNotAllowed";
+ public static final String CANT_DECP_ON_ANNOTATION_TO_IMPL_INTERFACE = "cantDecpOnAnnotationToImplInterface";
+ public static final String CANT_DECP_ON_ANNOTATION_TO_EXTEND_CLASS = "cantDecpOnAnnotationToExtendClass";
+ public static final String CANT_DECP_TO_MAKE_ANNOTATION_SUPERTYPE = "cantDecpToMakeAnnotationSupertype";
+ public static final String REFERENCE_TO_NON_ANNOTATION_TYPE = "referenceToNonAnnotationType";
+ public static final String BINDING_NON_RUNTIME_RETENTION_ANNOTATION = "bindingNonRuntimeRetentionAnnotation";
+
+ public static final String UNSUPPORTED_ANNOTATION_VALUE_TYPE = "unsupportedAnnotationValueType";
+
+ public static final String INCORRECT_TARGET_FOR_DECLARE_ANNOTATION = "incorrectTargetForDeclareAnnotation";
+ public static final String NO_MATCH_BECAUSE_SOURCE_RETENTION = "noMatchBecauseSourceRetention";
+
+ // Annotation Value messages
+ public static final String INVALID_ANNOTATION_VALUE = "invalidAnnotationValue";
+ public static final String UNKNOWN_ANNOTATION_VALUE = "unknownAnnotationValue";
+
+ // < Java5 messages
+ public static final String ATANNOTATION_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "atannotationNeedsJava5";
+ public static final String ATWITHIN_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "atwithinNeedsJava5";
+ public static final String ATWITHINCODE_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "atwithincodeNeedsJava5";
+ public static final String ATTHIS_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "atthisNeedsJava5";
+ public static final String ATTARGET_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "attargetNeedsJava5";
+ public static final String ATARGS_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "atargsNeedsJava5";
+ public static final String DECLARE_ATTYPE_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "declareAtTypeNeedsJava5";
+ public static final String DECLARE_ATMETHOD_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "declareAtMethodNeedsJava5";
+ public static final String DECLARE_ATFIELD_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "declareAtFieldNeedsJava5";
+ public static final String DECLARE_ATCONS_ONLY_SUPPORTED_AT_JAVA5_LEVEL = "declareAtConsNeedsJava5";
+ public static final String ANNOTATIONS_NEED_JAVA5 = "annotationsRequireJava5";
+
+ // Generics
+ public static final String CANT_DECP_MULTIPLE_PARAMETERIZATIONS = "cantDecpMultipleParameterizations";
+ public static final String HANDLER_PCD_DOESNT_SUPPORT_PARAMETERS = "noParameterizedTypePatternInHandler";
+ public static final String INCORRECT_NUMBER_OF_TYPE_ARGUMENTS = "incorrectNumberOfTypeArguments";
+ public static final String VIOLATES_TYPE_VARIABLE_BOUNDS = "violatesTypeVariableBounds";
+ public static final String NO_STATIC_INIT_JPS_FOR_PARAMETERIZED_TYPES = "noStaticInitJPsForParameterizedTypes";
+ public static final String NOT_A_GENERIC_TYPE = "notAGenericType";
+ public static final String WITHIN_PCD_DOESNT_SUPPORT_PARAMETERS = "noParameterizedTypePatternInWithin";
+ public static final String THIS_AND_TARGET_DONT_SUPPORT_PARAMETERS = "noParameterizedTypesInThisAndTarget";
+ public static final String GET_AND_SET_DONT_SUPPORT_DEC_TYPE_PARAMETERS = "noParameterizedTypesInGetAndSet";
+ public static final String NO_INIT_JPS_FOR_PARAMETERIZED_TYPES = "noInitJPsForParameterizedTypes";
+ public static final String NO_GENERIC_THROWABLES = "noGenericThrowables";
+ public static final String WITHINCODE_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES = "noParameterizedDeclaringTypesWithinCode";
+ public static final String EXECUTION_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES = "noParameterizedDeclaringTypesInExecution";
+ public static final String CALL_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES = "noParameterizedDeclaringTypesInCall";
+ public static final String CANT_REFERENCE_POINTCUT_IN_RAW_TYPE = "noRawTypePointcutReferences";
+
+ public static final String HAS_MEMBER_NOT_ENABLED = "hasMemberNotEnabled";
+
+ public static final String MUST_KEEP_OVERWEAVING_ONCE_START = "mustKeepOverweavingOnceStart";
+
+ // @AspectJ
+ public static final String RETURNING_FORMAL_NOT_DECLARED_IN_ADVICE = "returningFormalNotDeclaredInAdvice";
+ public static final String THROWN_FORMAL_NOT_DECLARED_IN_ADVICE = "thrownFormalNotDeclaredInAdvice";
+
+ public static String format(String key) {
+ return bundle.getString(key);
+ }
+
+ public static String format(String key, Object insert) {
+ return MessageFormat.format(bundle.getString(key), new Object[] { insert });
+ }
+
+ public static String format(String key, Object insert1, Object insert2) {
+ return MessageFormat.format(bundle.getString(key), new Object[] { insert1, insert2 });
+ }
+
+ public static String format(String key, Object insert1, Object insert2, Object insert3) {
+ return MessageFormat.format(bundle.getString(key), new Object[] { insert1, insert2, insert3 });
+ }
+
+ public static String format(String key, Object insert1, Object insert2, Object insert3, Object insert4) {
+ return MessageFormat.format(bundle.getString(key), new Object[] { insert1, insert2, insert3, insert4 });
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverStateInfo.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverStateInfo.java
new file mode 100644
index 000000000..f0dcbf270
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WeaverStateInfo.java
@@ -0,0 +1,581 @@
+/* *******************************************************************
+ * Copyright (c) 2002-2019 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+
+/**
+ * WeaverStateInfo represents how a type was processed. It is used by the weaver to determine how a type was previously treated and
+ * whether reweaving is allowed. The format in the data stream is:
+ *
+ * Byte: Kind. UNTOUCHED|WOVEN|EXTENDED - If extended it can have two extra bits set 'REWEAVABLE' and 'REWEAVABLE_COMPRESSION_BIT'
+ * Short: typeMungerCount - how many type mungers have affected this type <UnresolvedType & ResolvedTypeMunger>: The type mungers
+ * themselves If we are reweavable then we also have: Short: Number of aspects that touched this type in some way when it was
+ * previously woven <String> The fully qualified name of each type Int: Length of class file data (i.e. the unwovenclassfile)
+ * Byte[]: The class file data, compressed if REWEAVABLE_COMPRESSION_BIT set.
+ *
+ * @author Andy Clement
+ */
+public class WeaverStateInfo {
+ private List<Entry> typeMungers;
+ private boolean oldStyle;
+
+ private boolean reweavable;
+ private boolean reweavableCompressedMode; // If true, unwovenClassFile is uncompressed on read
+ private boolean reweavableDiffMode; // if true, unwovenClassFile is written and read as a diff
+
+ // These must exist in the world for reweaving to be valid.
+ // It is a set of signatures 'La/b/c/D;'
+ private Set<String> aspectsAffectingType;
+
+ private byte[] unwovenClassFile; // Original 'untouched' class file
+ private static boolean reweavableDefault = true; // ajh02: changed from false;
+ private static boolean reweavableCompressedModeDefault = false;
+ private static boolean reweavableDiffModeDefault = true;
+
+ // when serializing the WeaverStateInfo we come to adding the reweavable data,
+ // we'd like to add a diff of the unwovenClassFile and the wovenClassFile,
+ // but we don't have the wovenClassFile yet as we're still in the process of making it.
+ // so we put this key there instead as a stub.
+ // Then when the wovenClassFile has been made, replaceKeyWithDiff is called.
+ private static byte[] key = { -51, 34, 105, 56, -34, 65, 45, 78, -26, 125, 114, 97, 98, 1, -1, -42 };
+ private boolean unwovenClassFileIsADiff = false;
+
+ int compressionEnabled = 0; // 0=dont know, 1=no, 2=yes
+
+ private void checkCompressionEnabled() {
+ if (compressionEnabled == 0) {
+ // work it out!
+ compressionEnabled = 1;
+ try {
+ String value = System.getProperty("aspectj.compression.weaverstateinfo", "false");
+ if (value.equalsIgnoreCase("true")) {
+ System.out.println("ASPECTJ: aspectj.compression.weaverstateinfo=true: compressing weaverstateinfo");
+ compressionEnabled = 2;
+ }
+ } catch (Throwable t) {
+ // nop
+ }
+ }
+ }
+
+ private WeaverStateInfo() {
+ // this(new ArrayList(), false,reweavableDefault,reweavableCompressedModeDefault,reweavableDiffModeDefault);
+ }
+
+ public WeaverStateInfo(boolean reweavable) {
+ this(new ArrayList<Entry>(), false, reweavable, reweavableCompressedModeDefault, reweavableDiffModeDefault);
+ }
+
+ private WeaverStateInfo(List<Entry> typeMungers, boolean oldStyle, boolean reweavableMode, boolean reweavableCompressedMode,
+ boolean reweavableDiffMode) {
+ this.typeMungers = typeMungers;
+ this.oldStyle = oldStyle;
+ this.reweavable = reweavableMode;
+ this.reweavableCompressedMode = reweavableCompressedMode;
+ this.reweavableDiffMode = reweavableMode ? reweavableDiffMode : false;
+ this.aspectsAffectingType = new HashSet<String>();
+ this.unwovenClassFile = null;
+ }
+
+ public static void setReweavableModeDefaults(boolean mode, boolean compress, boolean diff) {
+ reweavableDefault = mode;
+ reweavableCompressedModeDefault = compress;
+ reweavableDiffModeDefault = diff;
+ }
+
+ private static final int UNTOUCHED = 0, WOVEN = 2, EXTENDED = 3;
+
+ // Use 'bits' for these capabilities - only valid in EXTENDED mode
+ private static final byte REWEAVABLE_BIT = 1 << 4;
+ private static final byte REWEAVABLE_COMPRESSION_BIT = 1 << 5;
+ private static final byte REWEAVABLE_DIFF_BIT = 1 << 6;
+
+ /** See comments on write() */
+ public static final WeaverStateInfo read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte b = s.readByte();
+
+ boolean isReweavable = ((b & REWEAVABLE_BIT) != 0);
+ if (isReweavable) {
+ b = (byte) (b - REWEAVABLE_BIT);
+ }
+
+ boolean isReweavableCompressed = ((b & REWEAVABLE_COMPRESSION_BIT) != 0);
+ if (isReweavableCompressed) {
+ b = (byte) (b - REWEAVABLE_COMPRESSION_BIT);
+ }
+
+ boolean isReweavableDiff = ((b & REWEAVABLE_DIFF_BIT) != 0);
+ if (isReweavableDiff) {
+ b = (byte) (b - REWEAVABLE_DIFF_BIT);
+ }
+
+ switch (b) {
+ case UNTOUCHED:
+ throw new RuntimeException("unexpected UNWOVEN");
+ case WOVEN:
+ return new WeaverStateInfo(Collections.<Entry>emptyList(), true, isReweavable, isReweavableCompressed, isReweavableDiff);
+ case EXTENDED:
+ boolean isCompressed = false;
+ if (s.isAtLeast169()) {
+ isCompressed = s.readBoolean();
+ }
+
+ int n = s.readShort();
+ List<Entry> l = new ArrayList<Entry>();
+ for (int i = 0; i < n; i++) {
+ // conditional on version
+ UnresolvedType aspectType = null;
+ if (isCompressed) {
+ int cpIndex = s.readShort();
+ String signature = s.readUtf8(cpIndex);
+ if (signature.charAt(0) == '@') { // '@missing@'
+ aspectType = ResolvedType.MISSING;
+ } else {
+ aspectType = UnresolvedType.forSignature(signature);
+ }
+ } else {
+ aspectType = UnresolvedType.read(s);
+ }
+ ResolvedTypeMunger typeMunger = ResolvedTypeMunger.read(s, context);
+ l.add(new Entry(aspectType, typeMunger));
+ }
+ WeaverStateInfo wsi = new WeaverStateInfo(l, false, isReweavable, isReweavableCompressed, isReweavableDiff);
+ readAnyReweavableData(wsi, s, isCompressed);
+ return wsi;
+ }
+ throw new RuntimeException("bad WeaverState.Kind: " + b + ". File was :"
+ + (context == null ? "unknown" : context.makeSourceLocation(0, 0).toString()));
+ }
+
+ private static class Entry {
+ public UnresolvedType aspectType;
+ public ResolvedTypeMunger typeMunger;
+
+ public Entry(UnresolvedType aspectType, ResolvedTypeMunger typeMunger) {
+ this.aspectType = aspectType;
+ this.typeMunger = typeMunger;
+ }
+
+ public String toString() {
+ return "<" + aspectType + ", " + typeMunger + ">";
+ }
+ }
+
+ /**
+ * Serialize the WeaverStateInfo. Various bits are set within the 'kind' flag to indicate the structure of the attribute. In
+ * reweavable diff mode a 'marker' is inserted at the start of the attribute to indicate where the final calculated diff should
+ * be inserted. When the key is replaced with the diff, the 'kind' byte moves to the front of the attribute - thats why in the
+ * read logic you'll see it expecting the kind as the first byte.
+ */
+ public void write(CompressingDataOutputStream s) throws IOException {
+ checkCompressionEnabled();
+ if (oldStyle || reweavableCompressedMode) {
+ throw new RuntimeException("shouldn't be writing this");
+ }
+
+ byte weaverStateInfoKind = EXTENDED;
+ if (reweavable) {
+ weaverStateInfoKind |= REWEAVABLE_BIT;
+ }
+
+ if (reweavableDiffMode) {
+ s.write(key); // put key in so we can replace it with the diff later
+ weaverStateInfoKind |= REWEAVABLE_DIFF_BIT;
+ }
+
+ s.writeByte(weaverStateInfoKind);
+
+ // Tag whether the remainder of the data is subject to cp compression
+ try {
+ s.compressionEnabled = compressionEnabled == 2;
+ s.writeBoolean(s.canCompress());
+
+ int n = typeMungers.size();
+ s.writeShort(n);
+ for (Entry e : typeMungers) {
+ if (s.canCompress()) {
+ s.writeCompressedSignature(e.aspectType.getSignature());
+ } else {
+ e.aspectType.write(s);
+ }
+ e.typeMunger.write(s);
+ }
+ writeAnyReweavableData(this, s, s.canCompress());
+ } finally {
+ s.compressionEnabled = true;
+ }
+ }
+
+ private final static byte[] NO_BYTES = new byte[0];
+
+ /**
+ * If the weaver is ever invoked in over weaving mode, we should
+ * not include the key when writing out, it won't be replaced later.
+ * If we turn off the reweaving flag that unfortunately removes
+ * the 'what aspects have been woven into this type' list which we
+ * want to keep as it helps overweaving avoid weaving an aspect in
+ * twice.
+ */
+ public void markOverweavingInUse() {
+ reweavableDiffMode = false;
+ unwovenClassFile = NO_BYTES;
+ }
+
+ public void addConcreteMunger(ConcreteTypeMunger munger) {
+ typeMungers.add(new Entry(munger.getAspectType(), munger.getMunger()));
+ }
+
+ public String toString() {
+ return "WeaverStateInfo(aspectsAffectingType=" + aspectsAffectingType + "," + typeMungers + ", " + oldStyle + ")";
+ }
+
+ public List<ConcreteTypeMunger> getTypeMungers(ResolvedType onType) {
+ World world = onType.getWorld();
+ List<ConcreteTypeMunger> ret = new ArrayList<ConcreteTypeMunger>();
+ for (Entry entry : typeMungers) {
+ ResolvedType aspectType = world.resolve(entry.aspectType, true);
+ if (aspectType.isMissing()) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ASPECT_NEEDED, entry.aspectType, onType),
+ onType.getSourceLocation(), null);
+ continue;
+ }
+
+ ret.add(new TemporaryTypeMunger(entry.typeMunger, aspectType));
+ }
+ return ret;
+ }
+
+ public boolean isOldStyle() {
+ return oldStyle;
+ }
+
+ public byte[] getUnwovenClassFileData() {
+ return unwovenClassFile;
+ }
+
+ public byte[] getUnwovenClassFileData(byte wovenClassFile[]) {
+ if (unwovenClassFileIsADiff) {
+ unwovenClassFile = applyDiff(wovenClassFile, unwovenClassFile);
+ unwovenClassFileIsADiff = false;
+ }
+ return unwovenClassFile;
+ }
+
+ public void setUnwovenClassFileData(byte[] data) {
+ unwovenClassFile = data;
+ }
+
+ public boolean isReweavable() {
+ return reweavable;
+ }
+
+ public void setReweavable(boolean rw) {
+ reweavable = rw;
+ }
+
+ public void addAspectsAffectingType(Collection<String> aspects) {
+ aspectsAffectingType.addAll(aspects);
+ }
+
+ public void addAspectAffectingType(String aspectSignature) {
+ aspectsAffectingType.add(aspectSignature);
+ }
+
+ public Set<String> getAspectsAffectingType() {
+ return this.aspectsAffectingType;
+ }
+
+ private static void readAnyReweavableData(WeaverStateInfo wsi, VersionedDataInputStream s, boolean compressed)
+ throws IOException {
+ if (wsi.isReweavable()) {
+ // Load list of aspects that need to exist in the world for reweaving to be 'legal'
+ int numberAspectsAffectingType = s.readShort();
+ for (int i = 0; i < numberAspectsAffectingType; i++) {
+ String str = null;
+ if (compressed) {
+ str = s.readSignature();
+ } else {
+ str = s.readUTF();
+ // Prior to 1.6.9 we were writing out names (com.foo.Bar) rather than signatures (Lcom/foo/Bar;)
+ // From 1.6.9 onwards we write out signatures (pr319431)
+ if (s.getMajorVersion() < WeaverVersionInfo.WEAVER_VERSION_AJ169) {
+ // It is a name, make it a signature
+ StringBuilder sb = new StringBuilder();
+ sb.append("L").append(str.replace('.', '/')).append(";");
+ str = sb.toString();
+ }
+ }
+ wsi.addAspectAffectingType(str);
+ }
+
+ int unwovenClassFileSize = s.readInt();
+ byte[] classData = null;
+ // the unwovenClassFile may have been compressed:
+ if (wsi.reweavableCompressedMode) {
+ classData = new byte[unwovenClassFileSize];
+ ZipInputStream zis = new ZipInputStream(s);
+ ZipEntry zen = zis.getNextEntry();
+ int current = 0;
+ int bytesToGo = unwovenClassFileSize;
+ while (bytesToGo > 0) {
+ int amount = zis.read(classData, current, bytesToGo);
+ current += amount;
+ bytesToGo -= amount;
+ }
+ zis.closeEntry();
+ if (bytesToGo != 0) {
+ throw new IOException("ERROR whilst reading compressed reweavable data, expected " + unwovenClassFileSize
+ + " bytes, only found " + current);
+ }
+ } else {
+ classData = new byte[unwovenClassFileSize];
+ if (unwovenClassFileSize != 0) {
+ int bytesread = s.read(classData);
+ if (bytesread != unwovenClassFileSize) {
+ throw new IOException("ERROR whilst reading reweavable data, expected " + unwovenClassFileSize
+ + " bytes, only found " + bytesread);
+ }
+ }
+ }
+
+ // if it was diffMode we'll have to remember to apply the diff if someone
+ // asks for the unwovenClassFile
+ wsi.unwovenClassFileIsADiff = wsi.reweavableDiffMode;
+ wsi.setUnwovenClassFileData(classData);
+ }
+ }
+
+ /**
+ * Here is the cleverness for reweavable diff mode. The class file on disk contains, inside the weaverstateinfo attribute, a
+ * diff that can be applied to 'itself' to recover the original class - which can then be rewoven.
+ */
+ public byte[] replaceKeyWithDiff(byte wovenClassFile[]) {
+ // we couldn't have made the diff earlier
+ // as we didn't have the wovenClassFile
+ // so we left a key there as a marker to come back to
+
+ if (reweavableDiffMode) {
+ ByteArrayOutputStream arrayStream = new ByteArrayOutputStream();
+ DataOutputStream s = new DataOutputStream(arrayStream);
+
+ int endOfKey = findEndOfKey(wovenClassFile);
+ int startOfKey = endOfKey - key.length;
+ // the length of the wsi attribute is written infront of it in the classFile,
+ // swapping the diff for the key will probably change the length of the wsi,
+ // so we'll have to fiddle with the four 'int length' bytes
+ int oldLengthLocation = startOfKey - 4;
+ int oldLength = readInt(wovenClassFile, oldLengthLocation);
+ wovenClassFile = deleteInArray(wovenClassFile, startOfKey, endOfKey); // delete the key
+
+ byte[] wovenClassFileUpToWSI = new byte[oldLengthLocation];
+ System.arraycopy(wovenClassFile, 0, wovenClassFileUpToWSI, 0, oldLengthLocation);
+
+ byte[] diff = generateDiff(wovenClassFileUpToWSI, unwovenClassFile);
+ try { // put the length of the diff infront of the diff
+ s.writeInt(diff.length);
+ s.write(diff);
+ } catch (IOException e) {
+ }
+ diff = arrayStream.toByteArray();
+ // we have to swap the oldLength for the new one,
+ // and add the diff, using the oldLength to work out where it should go :)
+
+ int newLength = oldLength - key.length + diff.length;
+ byte newLengthBytes[] = serializeInt(newLength);
+
+ // swap in the serialized newLength for the oldOne:
+ wovenClassFile[oldLengthLocation] = newLengthBytes[0];
+ wovenClassFile[oldLengthLocation + 1] = newLengthBytes[1];
+ wovenClassFile[oldLengthLocation + 2] = newLengthBytes[2];
+ wovenClassFile[oldLengthLocation + 3] = newLengthBytes[3];
+
+ // add the diff
+ wovenClassFile = insertArray(diff, wovenClassFile, oldLengthLocation + 4 + oldLength - key.length);
+ }
+ return wovenClassFile;
+ }
+
+ private static final int findEndOfKey(byte[] wovenClassFile) {
+ // looks through the classfile backwards (as the attributes are all near the end)
+ for (int i = wovenClassFile.length - 1; i > 0; i--) {
+ if (endOfKeyHere(wovenClassFile, i)) {
+ return i + 1;
+ }
+ }
+ throw new RuntimeException("key not found in wovenClassFile"); // should never happen
+ }
+
+ private static final boolean endOfKeyHere(byte lookIn[], int i) {
+ for (int j = 0; j < key.length; j++) {
+ if (key[key.length - 1 - j] != lookIn[i - j]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static final byte[] insertArray(byte toInsert[], byte original[], int offset) {
+ byte result[] = new byte[original.length + toInsert.length];
+ System.arraycopy(original, 0, result, 0, offset);
+ System.arraycopy(toInsert, 0, result, offset, toInsert.length);
+ System.arraycopy(original, offset, result, offset + toInsert.length, original.length - offset);
+ return result;
+ }
+
+ private static final int readInt(byte[] a, int offset) {
+ ByteArrayInputStream b = new ByteArrayInputStream(a, offset, 4);
+ DataInputStream d = new DataInputStream(b);
+ int length = -1;
+ try {
+ length = d.readInt();
+ } catch (IOException e) {
+ throw (new RuntimeException("readInt called with a bad array or offset")); // should never happen
+ }
+ return length;
+ }
+
+ private static final byte[] deleteInArray(byte a[], int start, int end) {
+ int lengthToDelete = end - start;
+ byte result[] = new byte[a.length - lengthToDelete]; // make a new array
+ System.arraycopy(a, 0, result, 0, start); // copy in the bit before the deleted bit
+ System.arraycopy(a, end, result, start, a.length - end); // copy in the bit after the deleted bit
+ return result;
+ }
+
+ // ajh02: a quick note about the diff format...
+ //
+ // classfiles consist of:
+ // 8 bytes: magic number and minor and major versions,
+ // 2 bytes: its constant pool count
+ // n bytes: the rest of the class file
+ //
+ // weaving a classfile never changes the classfile's first 8 bytes,
+ // and after the constant pool count there's usually a run of bytes that weaving didn't change
+ // hereafter referred to as the run
+ //
+ // so the diff consists of:
+ // 2 bytes: its constant pool count
+ // 4 bytes: length of the run
+ // n bytes: the rest of the unwovenClassFile
+
+ byte[] generateDiff(byte[] wovenClassFile, byte[] unWovenClassFile) {
+
+ // find how long the run is
+ int lookingAt = 10;
+ int shorterLength = (wovenClassFile.length < unWovenClassFile.length) ? wovenClassFile.length : unWovenClassFile.length;
+ while (lookingAt < shorterLength && (wovenClassFile[lookingAt] == unWovenClassFile[lookingAt])) {
+ lookingAt++;
+ }
+ int lengthInCommon = lookingAt - 10;
+ byte[] diff = new byte[unWovenClassFile.length - 4 - lengthInCommon];
+
+ // first 2 bytes of the diff are the constant pool count
+ diff[0] = unWovenClassFile[8];
+ diff[1] = unWovenClassFile[9];
+
+ // then 4 bytes saying how long the run is
+ byte[] lengthInCommonBytes = serializeInt(lengthInCommon);
+ diff[2] = lengthInCommonBytes[0];
+ diff[3] = lengthInCommonBytes[1];
+ diff[4] = lengthInCommonBytes[2];
+ diff[5] = lengthInCommonBytes[3];
+
+ // then we just dump the rest of the unWovenClassFile verbatim
+ System.arraycopy(unWovenClassFile, 10 + lengthInCommon, diff, 6, diff.length - 6);
+
+ return diff;
+ }
+
+ byte[] applyDiff(byte[] wovenClassFile, byte[] diff) {
+
+ int lengthInCommon = readInt(diff, 2);
+ byte[] unWovenClassFile = new byte[4 + diff.length + lengthInCommon];
+
+ // copy the first 8 bytes from the wovenClassFile
+ System.arraycopy(wovenClassFile, 0, unWovenClassFile, 0, 8);
+
+ // copy the constant pool count from the diff
+ unWovenClassFile[8] = diff[0];
+ unWovenClassFile[9] = diff[1];
+
+ // copy the run from the wovenClassFile
+ System.arraycopy(wovenClassFile, 10, unWovenClassFile, 10, lengthInCommon);
+
+ // copy the stuff after the run from the diff
+ System.arraycopy(diff, 6, unWovenClassFile, 10 + lengthInCommon, diff.length - 6);
+
+ return unWovenClassFile;
+ }
+
+ private byte[] serializeInt(int i) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(4);
+ DataOutputStream dos = new DataOutputStream(bos);
+ try {
+ dos.writeInt(i);
+ } catch (IOException e) {
+ }
+ return bos.toByteArray();
+ }
+
+ private static void writeAnyReweavableData(WeaverStateInfo wsi, CompressingDataOutputStream s, boolean compress)
+ throws IOException {
+ if (wsi.isReweavable()) {
+ // Write out list of aspects that must exist next time we try and weave this class
+ s.writeShort(wsi.aspectsAffectingType.size());
+ for (String type : wsi.aspectsAffectingType) {
+ if (compress) {
+ s.writeCompressedSignature(type);
+ } else {
+ s.writeUTF(type);
+ }
+ }
+ byte[] data = wsi.unwovenClassFile;
+ // if we're not in diffMode, write the unwovenClassFile now,
+ // otherwise we'll insert it as a diff later
+ if (!wsi.reweavableDiffMode) {
+ s.writeInt(data.length);
+ s.write(wsi.unwovenClassFile);
+ }
+ }
+ }
+
+ /**
+ * @return true if the supplied aspect is already in the list of those affecting this type
+ */
+ public boolean isAspectAlreadyApplied(ResolvedType someAspect) {
+ String someAspectSignature = someAspect.getSignature();
+ for (String aspectSignature : aspectsAffectingType) {
+ if (aspectSignature.equals(someAspectSignature)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WildcardedUnresolvedType.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WildcardedUnresolvedType.java
new file mode 100644
index 000000000..d3e609e7f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/WildcardedUnresolvedType.java
@@ -0,0 +1,70 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver;
+
+/**
+ * Represents a wildcarded bound for a generic type, this can be unbounded '?' or bounded via extends '? extends Foo' or super '?
+ * super Foo'. The signature for a ? is in fact "*" and the erasure signature is the upper bound which defaults to java.lang.Object
+ * if nothing is specified. On resolution, this becomes a BoundedReferenceType
+ *
+ * @author Andy Clement
+ */
+public class WildcardedUnresolvedType extends UnresolvedType {
+
+ // TODO does not cope with extra bounds '? extends A & B & C'
+
+ public static final int UNBOUND = 0;
+ public static final int EXTENDS = 1;
+ public static final int SUPER = 2;
+
+ public static final WildcardedUnresolvedType QUESTIONMARK = new WildcardedUnresolvedType("*", UnresolvedType.OBJECT, null);
+
+ private int boundKind = UNBOUND; // UNBOUND, EXTENDS, SUPER
+
+ private UnresolvedType lowerBound;
+
+ private UnresolvedType upperBound;
+
+ public WildcardedUnresolvedType(String signature, UnresolvedType upperBound, UnresolvedType lowerBound) {
+ super(signature, (upperBound == null ? UnresolvedType.OBJECT.signature : upperBound.signatureErasure));
+ this.typeKind = TypeKind.WILDCARD;
+ this.upperBound = upperBound;
+ this.lowerBound = lowerBound;
+ if (signature.charAt(0) == '-') {
+ boundKind = SUPER;
+ }
+ if (signature.charAt(0) == '+') {
+ boundKind = EXTENDS;
+ }
+ }
+
+ public UnresolvedType getUpperBound() {
+ return upperBound;
+ }
+
+ public UnresolvedType getLowerBound() {
+ return lowerBound;
+ }
+
+ public boolean isExtends() {
+ return boundKind == EXTENDS;
+ }
+
+ public boolean isSuper() {
+ return boundKind == SUPER;
+ }
+
+ public boolean isUnbound() {
+ return boundKind == UNBOUND;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/World.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/World.java
new file mode 100644
index 000000000..644f232ac
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/World.java
@@ -0,0 +1,2029 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 2005 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Adrian Colyer, Andy Clement, overhaul for generics, Abraham Nevado
+ * ******************************************************************/
+
+package org.aspectj.weaver;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessage.Kind;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.bridge.context.PinpointingMessageHandler;
+import org.aspectj.util.IStructureModel;
+import org.aspectj.weaver.ResolvedType.Primitive;
+import org.aspectj.weaver.UnresolvedType.TypeKind;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.DeclareAnnotation;
+import org.aspectj.weaver.patterns.DeclareParents;
+import org.aspectj.weaver.patterns.DeclarePrecedence;
+import org.aspectj.weaver.patterns.DeclareSoft;
+import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+import org.aspectj.weaver.tools.PointcutDesignatorHandler;
+import org.aspectj.weaver.tools.Trace;
+import org.aspectj.weaver.tools.TraceFactory;
+
+/**
+ * A World is a collection of known types and crosscutting members.
+ */
+public abstract class World implements Dump.INode {
+
+ /** handler for any messages produced during resolution etc. */
+ private IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR;
+
+ /** handler for cross-reference information produced during the weaving process */
+ private ICrossReferenceHandler xrefHandler = null;
+
+ /** Currently 'active' scope in which to lookup (resolve) typevariable references */
+ private TypeVariableDeclaringElement typeVariableLookupScope;
+
+ /** The heart of the world, a map from type signatures to resolved types */
+ protected TypeMap typeMap = new TypeMap(this);
+
+ /** New pointcut designators this world supports */
+ private Set<PointcutDesignatorHandler> pointcutDesignators;
+
+ // see pr145963
+ /** Should we create the hierarchy for binary classes and aspects */
+ public static boolean createInjarHierarchy = true;
+
+ /** Calculator for working out aspect precedence */
+ private final AspectPrecedenceCalculator precedenceCalculator;
+
+ /** All of the type and shadow mungers known to us */
+ private final CrosscuttingMembersSet crosscuttingMembersSet = new CrosscuttingMembersSet(this);
+
+ /** The structure model for the compilation */
+ private IStructureModel model = null;
+
+ /** for processing Xlint messages */
+ private Lint lint = new Lint(this);
+
+ /** XnoInline option setting passed down to weaver */
+ private boolean XnoInline;
+
+ /** XlazyTjp option setting passed down to weaver */
+ private boolean XlazyTjp;
+
+ /** XhasMember option setting passed down to weaver */
+ private boolean XhasMember = false;
+
+ /** Xpinpoint controls whether we put out developer info showing the source of messages */
+ private boolean Xpinpoint = false;
+
+ /** When behaving in a Java 5 way autoboxing is considered */
+ private boolean behaveInJava5Way = false;
+
+ /** Should timing information be reported (as info messages)? */
+ private boolean timing = false;
+ private boolean timingPeriodically = true;
+
+ /** Determines if this world could be used for multiple compiles */
+ private boolean incrementalCompileCouldFollow = false;
+
+ /** The level of the aspectjrt.jar the code we generate needs to run on */
+ public static final RuntimeVersion RUNTIME_LEVEL_DEFAULT = RuntimeVersion.V1_5;
+ private RuntimeVersion targetAspectjRuntimeLevel = RUNTIME_LEVEL_DEFAULT;
+
+ /** Flags for the new joinpoints that are 'optional': -Xjoinpoints:arrayconstruction -Xjoinpoints:synchronization */
+ private boolean optionalJoinpoint_ArrayConstruction = false;
+ private boolean optionalJoinpoint_Synchronization = false;
+
+ private boolean addSerialVerUID = false;
+
+ private Properties extraConfiguration = null;
+ private boolean checkedAdvancedConfiguration = false;
+ private boolean synchronizationPointcutsInUse = false;
+ // Xset'table options
+ private boolean runMinimalMemory = false;
+ private boolean transientTjpFields = false;
+ private boolean runMinimalMemorySet = false;
+ private boolean shouldPipelineCompilation = true;
+ private boolean shouldGenerateStackMaps = false;
+ protected boolean bcelRepositoryCaching = xsetBCEL_REPOSITORY_CACHING_DEFAULT.equalsIgnoreCase("true");
+ private boolean fastMethodPacking = false;
+ private int itdVersion = 2; // defaults to 2nd generation itds
+
+ // Minimal Model controls whether model entities that are not involved in relationships are deleted post-build
+ private boolean minimalModel = true;
+ private boolean useFinal = true;
+ private boolean targettingRuntime1_6_10 = false;
+
+ private boolean completeBinaryTypes = false;
+ private boolean overWeaving = false;
+ private static boolean systemPropertyOverWeaving = false;
+ public boolean forDEBUG_structuralChangesCode = false;
+ public boolean forDEBUG_bridgingCode = false;
+ public boolean optimizedMatching = true;
+ public boolean generateNewLvts = true;
+ protected long timersPerJoinpoint = 25000;
+ protected long timersPerType = 250;
+
+ public int infoMessagesEnabled = 0; // 0=uninitialized, 1=no, 2=yes
+
+ private static Trace trace = TraceFactory.getTraceFactory().getTrace(World.class);
+
+ private boolean errorThreshold;
+ private boolean warningThreshold;
+
+ /**
+ * A list of RuntimeExceptions containing full stack information for every type we couldn't find.
+ */
+ private List<RuntimeException> dumpState_cantFindTypeExceptions = null;
+
+ static {
+ try {
+ String value = System.getProperty("aspectj.overweaving", "false");
+ if (value.equalsIgnoreCase("true")) {
+ System.out.println("ASPECTJ: aspectj.overweaving=true: overweaving switched ON");
+ systemPropertyOverWeaving = true;
+ }
+ } catch (Throwable t) {
+ System.err.println("ASPECTJ: Unable to read system properties");
+ t.printStackTrace();
+ }
+ }
+
+ public final Primitive BYTE = new Primitive("B", 1, 0);
+ public final Primitive CHAR = new Primitive("C", 1, 1);
+ public final Primitive DOUBLE = new Primitive("D", 2, 2);
+ public final Primitive FLOAT = new Primitive("F", 1, 3);
+ public final Primitive INT = new Primitive("I", 1, 4);
+ public final Primitive LONG = new Primitive("J", 2, 5);
+ public final Primitive SHORT = new Primitive("S", 1, 6);
+ public final Primitive BOOLEAN = new Primitive("Z", 1, 7);
+ public final Primitive VOID = new Primitive("V", 0, 8);
+
+ /**
+ * Insert the primitives
+ */
+ protected World() {
+ super();
+ // Dump.registerNode(this.getClass(), this);
+ typeMap.put("B", BYTE);
+ typeMap.put("S", SHORT);
+ typeMap.put("I", INT);
+ typeMap.put("J", LONG);
+ typeMap.put("F", FLOAT);
+ typeMap.put("D", DOUBLE);
+ typeMap.put("C", CHAR);
+ typeMap.put("Z", BOOLEAN);
+ typeMap.put("V", VOID);
+ precedenceCalculator = new AspectPrecedenceCalculator(this);
+ }
+
+ /**
+ * Dump processing when a fatal error occurs
+ */
+ @Override
+ public void accept(Dump.IVisitor visitor) {
+ // visitor.visitObject("Extra configuration:");
+ // visitor.visitList(extraConfiguration.);
+ visitor.visitObject("Shadow mungers:");
+ visitor.visitList(crosscuttingMembersSet.getShadowMungers());
+ visitor.visitObject("Type mungers:");
+ visitor.visitList(crosscuttingMembersSet.getTypeMungers());
+ visitor.visitObject("Late Type mungers:");
+ visitor.visitList(crosscuttingMembersSet.getLateTypeMungers());
+ if (dumpState_cantFindTypeExceptions != null) {
+ visitor.visitObject("Cant find type problems:");
+ visitor.visitList(dumpState_cantFindTypeExceptions);
+ dumpState_cantFindTypeExceptions = null;
+ }
+ }
+
+ // ==========================================================================
+ // T Y P E R E S O L U T I O N
+ // ==========================================================================
+
+ /**
+ * Resolve a type that we require to be present in the world
+ */
+ public ResolvedType resolve(UnresolvedType ty) {
+ return resolve(ty, false);
+ }
+
+ /**
+ * Attempt to resolve a type - the source location gives you some context in which resolution is taking place. In the case of an
+ * error where we can't find the type - we can then at least report why (source location) we were trying to resolve it.
+ */
+ public ResolvedType resolve(UnresolvedType ty, ISourceLocation isl) {
+ ResolvedType ret = resolve(ty, true);
+ if (ResolvedType.isMissing(ty)) {
+ // IMessage msg = null;
+ getLint().cantFindType.signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE, ty.getName()), isl);
+ // if (isl!=null) {
+ // msg = MessageUtil.error(WeaverMessages.format(WeaverMessages.
+ // CANT_FIND_TYPE,ty.getName()),isl);
+ // } else {
+ // msg = MessageUtil.error(WeaverMessages.format(WeaverMessages.
+ // CANT_FIND_TYPE,ty.getName()));
+ // }
+ // messageHandler.handleMessage(msg);
+ }
+ return ret;
+ }
+
+ /**
+ * Convenience method for resolving an array of unresolved types in one hit. Useful for e.g. resolving type parameters in
+ * signatures.
+ */
+ public ResolvedType[] resolve(UnresolvedType[] types) {
+ if (types == null) {
+ return ResolvedType.NONE;
+ }
+
+ ResolvedType[] ret = new ResolvedType[types.length];
+ for (int i = 0; i < types.length; i++) {
+ ret[i] = resolve(types[i]);
+ }
+ return ret;
+ }
+
+ /**
+ * Resolve a type. This the hub of type resolution. The resolved type is added to the type map by signature.
+ */
+ public ResolvedType resolve(UnresolvedType ty, boolean allowMissing) {
+
+ // special resolution processing for already resolved types.
+ if (ty instanceof ResolvedType) {
+ ResolvedType rty = (ResolvedType) ty;
+ rty = resolve(rty);
+ // A TypeVariableReferenceType may look like it is resolved (it extends ResolvedType) but the internal
+ // type variable may not yet have been resolved
+ if (!rty.isTypeVariableReference() || ((TypeVariableReferenceType) rty).isTypeVariableResolved()) {
+ return rty;
+ }
+ }
+
+ // dispatch back to the type variable reference to resolve its
+ // constituent parts don't do this for other unresolved types otherwise
+ // you'll end up in a
+ // loop
+ if (ty.isTypeVariableReference()) {
+ return ty.resolve(this);
+ }
+
+ // if we've already got a resolved type for the signature, just return
+ // it
+ // after updating the world
+ String signature = ty.getSignature();
+ ResolvedType ret = typeMap.get(signature);
+ if (ret != null) {
+ ret.world = this; // Set the world for the RTX
+ return ret;
+ } else if (signature.equals("?") || signature.equals("*")) {
+ // might be a problem here, not sure '?' should make it to here as a
+ // signature, the
+ // proper signature for wildcard '?' is '*'
+ // fault in generic wildcard, can't be done earlier because of init
+ // issues
+ // TODO ought to be shared single instance representing this
+ ResolvedType something = getWildcard();
+ typeMap.put("?", something);
+ return something;
+ }
+
+ // no existing resolved type, create one
+ synchronized (buildingTypeLock) {
+ if (ty.isArray()) {
+ ResolvedType componentType = resolve(ty.getComponentType(), allowMissing);
+ ret = new ArrayReferenceType(signature, "[" + componentType.getErasureSignature(), this, componentType);
+ } else {
+ ret = resolveToReferenceType(ty, allowMissing);
+ if (!allowMissing && ret.isMissing()) {
+ ret = handleRequiredMissingTypeDuringResolution(ty);
+ }
+ if (completeBinaryTypes) {
+ completeBinaryType(ret);
+ }
+ }
+ }
+
+ // Pulling in the type may have already put the right entry in the map
+ ResolvedType result = typeMap.get(signature);
+ if (result == null && !ret.isMissing()) {
+ ret = ensureRawTypeIfNecessary(ret);
+ typeMap.put(signature, ret);
+ return ret;
+ }
+ if (result == null) {
+ return ret;
+ } else {
+ return result;
+ }
+ }
+
+ private Object buildingTypeLock = new Object();
+
+ // Only need one representation of '?' in a world - can be shared
+ private BoundedReferenceType wildcard;
+
+ private BoundedReferenceType getWildcard() {
+ if (wildcard == null) {
+ wildcard = new BoundedReferenceType(this);
+ }
+ return wildcard;
+ }
+
+ /**
+ * Called when a type is resolved - enables its type hierarchy to be finished off before we proceed
+ */
+ protected void completeBinaryType(ResolvedType ret) {
+ }
+
+ /**
+ * Return true if the classloader relating to this world is definetly the one that will define the specified class. Return false
+ * otherwise or we don't know for certain.
+ */
+ public boolean isLocallyDefined(String classname) {
+ return false;
+ }
+
+ /**
+ * We tried to resolve a type and couldn't find it...
+ */
+ private ResolvedType handleRequiredMissingTypeDuringResolution(UnresolvedType ty) {
+ // defer the message until someone asks a question of the type that we
+ // can't answer
+ // just from the signature.
+ // MessageUtil.error(messageHandler,
+ // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE,ty.getName()));
+ if (dumpState_cantFindTypeExceptions == null) {
+ dumpState_cantFindTypeExceptions = new ArrayList<RuntimeException>();
+ }
+ if (dumpState_cantFindTypeExceptions.size() < 100) { // limit growth
+ dumpState_cantFindTypeExceptions.add(new RuntimeException("Can't find type " + ty.getName()));
+ }
+ return new MissingResolvedTypeWithKnownSignature(ty.getSignature(), this);
+ }
+
+ /**
+ * Some TypeFactory operations create resolved types directly, but these won't be in the typeMap - this resolution process puts
+ * them there. Resolved types are also told their world which is needed for the special autoboxing resolved types.
+ */
+ public ResolvedType resolve(ResolvedType ty) {
+ if (ty.isTypeVariableReference()) {
+ return ty; // until type variables have proper sigs...
+ }
+ ResolvedType resolved = typeMap.get(ty.getSignature());
+ if (resolved == null) {
+ resolved = ensureRawTypeIfNecessary(ty);
+ typeMap.put(ty.getSignature(), resolved);
+ resolved = ty;
+ }
+ resolved.world = this;
+ return resolved;
+ }
+
+ /**
+ * When the world is operating in 1.5 mode, the TypeMap should only contain RAW types and never directly generic types. The RAW
+ * type will contain a reference to the generic type.
+ *
+ * @param type a possibly generic type for which the raw needs creating as it is not currently in the world
+ * @return a type suitable for putting into the world
+ */
+ private ResolvedType ensureRawTypeIfNecessary(ResolvedType type) {
+ if (!isInJava5Mode() || type.isRawType()) {
+ return type;
+ }
+ // Key requirement here is if it is generic, create a RAW entry to be put in the map that points to it
+ if (type instanceof ReferenceType && ((ReferenceType) type).getDelegate() != null && type.isGenericType()) {
+ ReferenceType rawType = new ReferenceType(type.getSignature(), this);
+ rawType.typeKind = UnresolvedType.TypeKind.RAW;
+ ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
+ rawType.setDelegate(delegate);
+ rawType.setGenericType((ReferenceType) type);
+ return rawType;
+ }
+ // probably parameterized...
+ return type;
+ }
+
+ /**
+ * Convenience method for finding a type by name and resolving it in one step.
+ */
+ public ResolvedType resolve(String name) {
+ // trace.enter("resolve", this, new Object[] {name});
+ ResolvedType ret = resolve(UnresolvedType.forName(name));
+ // trace.exit("resolve", ret);
+ return ret;
+ }
+
+ public ReferenceType resolveToReferenceType(String name) {
+ return (ReferenceType) resolve(name);
+ }
+
+ public ResolvedType resolve(String name, boolean allowMissing) {
+ return resolve(UnresolvedType.forName(name), allowMissing);
+ }
+
+ /**
+ * Resolve to a ReferenceType - simple, raw, parameterized, or generic. Raw, parameterized, and generic versions of a type share
+ * a delegate.
+ */
+ private final ResolvedType resolveToReferenceType(UnresolvedType ty, boolean allowMissing) {
+ if (ty.isParameterizedType()) {
+ // ======= parameterized types ================
+ ResolvedType rt = resolveGenericTypeFor(ty, allowMissing);
+ if (rt.isMissing()) {
+ return rt;
+ }
+ ReferenceType genericType = (ReferenceType) rt;
+ ReferenceType parameterizedType = TypeFactory.createParameterizedType(genericType, ty.typeParameters, this);
+ return parameterizedType;
+
+ } else if (ty.isGenericType()) {
+ // ======= generic types ======================
+ ResolvedType rt = resolveGenericTypeFor(ty, false);
+ if (rt.isMissing()) {
+ return rt;
+ }
+ ReferenceType genericType = (ReferenceType) rt;
+ if (rt.isMissing()) {
+ return rt;
+ }
+ return genericType;
+
+ } else if (ty.isGenericWildcard()) {
+ // ======= generic wildcard types =============
+ return resolveGenericWildcardFor((WildcardedUnresolvedType) ty);
+ } else {
+ // ======= simple and raw types ===============
+ String erasedSignature = ty.getErasureSignature();
+ ReferenceType simpleOrRawType = new ReferenceType(erasedSignature, this);
+ if (ty.needsModifiableDelegate()) {
+ simpleOrRawType.setNeedsModifiableDelegate(true);
+ }
+ ReferenceTypeDelegate delegate = resolveDelegate(simpleOrRawType);
+
+ if (delegate == null) {
+ return new MissingResolvedTypeWithKnownSignature(ty.getSignature(), erasedSignature, this);
+ }
+
+ if (delegate.isGeneric() && behaveInJava5Way) {
+ // ======== raw type ===========
+ simpleOrRawType.typeKind = TypeKind.RAW;
+ if (simpleOrRawType.hasNewInterfaces()) { // debug 375777
+ throw new IllegalStateException(
+ "Simple type promoted forced to raw, but it had new interfaces/superclass. Type is "
+ + simpleOrRawType.getName());
+ }
+ ReferenceType genericType = makeGenericTypeFrom(delegate, simpleOrRawType);
+ simpleOrRawType.setDelegate(delegate);
+ genericType.setDelegate(delegate);
+ simpleOrRawType.setGenericType(genericType);
+ return simpleOrRawType;
+ } else {
+ // ======== simple type =========
+ simpleOrRawType.setDelegate(delegate);
+ return simpleOrRawType;
+ }
+ }
+ }
+
+ /**
+ * Attempt to resolve a type that should be a generic type.
+ */
+ public ResolvedType resolveGenericTypeFor(UnresolvedType anUnresolvedType, boolean allowMissing) {
+ // Look up the raw type by signature
+ String rawSignature = anUnresolvedType.getRawType().getSignature();
+ ResolvedType rawType = typeMap.get(rawSignature);
+ if (rawType == null) {
+ rawType = resolve(UnresolvedType.forSignature(rawSignature), allowMissing);
+ typeMap.put(rawSignature, rawType);
+ }
+ if (rawType.isMissing()) {
+ return rawType;
+ }
+
+ // Does the raw type know its generic form? (It will if we created the
+ // raw type from a source type, it won't if its been created just
+ // through
+ // being referenced, e.g. java.util.List
+ ResolvedType genericType = rawType.getGenericType();
+
+ // There is a special case to consider here (testGenericsBang_pr95993
+ // highlights it)
+ // You may have an unresolvedType for a parameterized type but it
+ // is backed by a simple type rather than a generic type. This occurs
+ // for
+ // inner types of generic types that inherit their enclosing types
+ // type variables.
+ if (rawType.isSimpleType() && (anUnresolvedType.typeParameters == null || anUnresolvedType.typeParameters.length == 0)) {
+ rawType.world = this;
+ return rawType;
+ }
+
+ if (genericType != null) {
+ genericType.world = this;
+ return genericType;
+ } else {
+ // Fault in the generic that underpins the raw type ;)
+ ReferenceTypeDelegate delegate = resolveDelegate((ReferenceType) rawType);
+ ReferenceType genericRefType = makeGenericTypeFrom(delegate, ((ReferenceType) rawType));
+ ((ReferenceType) rawType).setGenericType(genericRefType);
+ genericRefType.setDelegate(delegate);
+ ((ReferenceType) rawType).setDelegate(delegate);
+ return genericRefType;
+ }
+ }
+
+ private ReferenceType makeGenericTypeFrom(ReferenceTypeDelegate delegate, ReferenceType rawType) {
+ String genericSig = delegate.getDeclaredGenericSignature();
+ if (genericSig != null) {
+ return new ReferenceType(UnresolvedType.forGenericTypeSignature(rawType.getSignature(),
+ delegate.getDeclaredGenericSignature()), this);
+ } else {
+ return new ReferenceType(UnresolvedType.forGenericTypeVariables(rawType.getSignature(), delegate.getTypeVariables()),
+ this);
+ }
+ }
+
+ /**
+ * Go from an unresolved generic wildcard (represented by UnresolvedType) to a resolved version (BoundedReferenceType).
+ */
+ private ReferenceType resolveGenericWildcardFor(WildcardedUnresolvedType aType) {
+ BoundedReferenceType ret = null;
+ // FIXME asc doesnt take account of additional interface bounds (e.g. ? super R & Serializable - can you do that?)
+ if (aType.isExtends()) {
+ ResolvedType resolvedUpperBound = resolve(aType.getUpperBound());
+ if (resolvedUpperBound.isMissing()) {
+ return getWildcard();
+ }
+ ret = new BoundedReferenceType((ReferenceType)resolvedUpperBound, true, this);
+ } else if (aType.isSuper()) {
+ ResolvedType resolvedLowerBound = resolve(aType.getLowerBound());
+ if (resolvedLowerBound.isMissing()) {
+ return getWildcard();
+ }
+ ret = new BoundedReferenceType((ReferenceType)resolvedLowerBound, false, this);
+ } else {
+ // must be ? on its own!
+ ret = getWildcard();
+ }
+ return ret;
+ }
+
+ /**
+ * Find the ReferenceTypeDelegate behind this reference type so that it can fulfill its contract.
+ */
+ protected abstract ReferenceTypeDelegate resolveDelegate(ReferenceType ty);
+
+ /**
+ * Special resolution for "core" types like OBJECT. These are resolved just like any other type, but if they are not found it is
+ * more serious and we issue an error message immediately.
+ */
+ // OPTIMIZE streamline path for core types? They are just simple types,
+ // could look straight in the typemap?
+ public ResolvedType getCoreType(UnresolvedType tx) {
+ ResolvedType coreTy = resolve(tx, true);
+ if (coreTy.isMissing()) {
+ MessageUtil.error(messageHandler, WeaverMessages.format(WeaverMessages.CANT_FIND_CORE_TYPE, tx.getName()));
+ }
+ return coreTy;
+ }
+
+ /**
+ * Lookup a type by signature, if not found then build one and put it in the map.
+ */
+ public ReferenceType lookupOrCreateName(UnresolvedType ty) {
+ String signature = ty.getSignature();
+ ReferenceType ret = lookupBySignature(signature);
+ if (ret == null) {
+ ret = ReferenceType.fromTypeX(ty, this);
+ typeMap.put(signature, ret);
+ }
+ return ret;
+ }
+
+ /**
+ * Lookup a reference type in the world by its signature. Returns null if not found.
+ */
+ public ReferenceType lookupBySignature(String signature) {
+ return (ReferenceType) typeMap.get(signature);
+ }
+
+ // ==========================================================================
+ // ===
+ // T Y P E R E S O L U T I O N -- E N D
+ // ==========================================================================
+ // ===
+
+ /**
+ * Member resolution is achieved by resolving the declaring type and then looking up the member in the resolved declaring type.
+ */
+ public ResolvedMember resolve(Member member) {
+ ResolvedType declaring = member.getDeclaringType().resolve(this);
+ if (declaring.isRawType()) {
+ declaring = declaring.getGenericType();
+ }
+ ResolvedMember ret;
+ if (member.getKind() == Member.FIELD) {
+ ret = declaring.lookupField(member);
+ } else {
+ ret = declaring.lookupMethod(member);
+ }
+
+ if (ret != null) {
+ return ret;
+ }
+
+ return declaring.lookupSyntheticMember(member);
+ }
+
+ private boolean allLintIgnored = false;
+
+ public void setAllLintIgnored() {
+ allLintIgnored = true;
+ }
+
+ public boolean areAllLintIgnored() {
+ return allLintIgnored;
+ }
+
+ public abstract IWeavingSupport getWeavingSupport();
+
+ /**
+ * Create an advice shadow munger from the given advice attribute
+ */
+ // public abstract Advice createAdviceMunger(AjAttribute.AdviceAttribute
+ // attribute, Pointcut pointcut, Member signature);
+ /**
+ * Create an advice shadow munger for the given advice kind
+ */
+ public final Advice createAdviceMunger(AdviceKind kind, Pointcut p, Member signature, int extraParameterFlags,
+ IHasSourceLocation loc, ResolvedType declaringAspect) {
+ AjAttribute.AdviceAttribute attribute = new AjAttribute.AdviceAttribute(kind, p, extraParameterFlags, loc.getStart(),
+ loc.getEnd(), loc.getSourceContext());
+ return getWeavingSupport().createAdviceMunger(attribute, p, signature, declaringAspect);
+ }
+
+ /**
+ * Same signature as org.aspectj.util.PartialOrder.PartialComparable.compareTo
+ */
+ public int compareByPrecedence(ResolvedType aspect1, ResolvedType aspect2) {
+ return precedenceCalculator.compareByPrecedence(aspect1, aspect2);
+ }
+
+ public Integer getPrecedenceIfAny(ResolvedType aspect1, ResolvedType aspect2) {
+ return precedenceCalculator.getPrecedenceIfAny(aspect1, aspect2);
+ }
+
+ /**
+ * compares by precedence with the additional rule that a super-aspect is sorted before its sub-aspects
+ */
+ public int compareByPrecedenceAndHierarchy(ResolvedType aspect1, ResolvedType aspect2) {
+ return precedenceCalculator.compareByPrecedenceAndHierarchy(aspect1, aspect2);
+ }
+
+ // simple property getter and setters
+ // ===========================================================
+
+ /**
+ * Nobody should hold onto a copy of this message handler, or setMessageHandler won't work right.
+ */
+ public IMessageHandler getMessageHandler() {
+ return messageHandler;
+ }
+
+ public void setMessageHandler(IMessageHandler messageHandler) {
+ if (this.isInPinpointMode()) {
+ this.messageHandler = new PinpointingMessageHandler(messageHandler);
+ } else {
+ this.messageHandler = messageHandler;
+ }
+ }
+
+ /**
+ * convenenience method for creating and issuing messages via the message handler - if you supply two locations you will get two
+ * messages.
+ */
+ public void showMessage(Kind kind, String message, ISourceLocation loc1, ISourceLocation loc2) {
+ if (loc1 != null) {
+ messageHandler.handleMessage(new Message(message, kind, null, loc1));
+ if (loc2 != null) {
+ messageHandler.handleMessage(new Message(message, kind, null, loc2));
+ }
+ } else {
+ messageHandler.handleMessage(new Message(message, kind, null, loc2));
+ }
+ }
+
+ public void setCrossReferenceHandler(ICrossReferenceHandler xrefHandler) {
+ this.xrefHandler = xrefHandler;
+ }
+
+ /**
+ * Get the cross-reference handler for the world, may be null.
+ */
+ public ICrossReferenceHandler getCrossReferenceHandler() {
+ return xrefHandler;
+ }
+
+ public void setTypeVariableLookupScope(TypeVariableDeclaringElement scope) {
+ typeVariableLookupScope = scope;
+ }
+
+ public TypeVariableDeclaringElement getTypeVariableLookupScope() {
+ return typeVariableLookupScope;
+ }
+
+ public List<DeclareParents> getDeclareParents() {
+ return crosscuttingMembersSet.getDeclareParents();
+ }
+
+ public List<DeclareAnnotation> getDeclareAnnotationOnTypes() {
+ return crosscuttingMembersSet.getDeclareAnnotationOnTypes();
+ }
+
+ public List<DeclareAnnotation> getDeclareAnnotationOnFields() {
+ return crosscuttingMembersSet.getDeclareAnnotationOnFields();
+ }
+
+ public List<DeclareAnnotation> getDeclareAnnotationOnMethods() {
+ return crosscuttingMembersSet.getDeclareAnnotationOnMethods();
+ }
+
+ public List<DeclareTypeErrorOrWarning> getDeclareTypeEows() {
+ return crosscuttingMembersSet.getDeclareTypeEows();
+ }
+
+ public List<DeclareSoft> getDeclareSoft() {
+ return crosscuttingMembersSet.getDeclareSofts();
+ }
+
+ public CrosscuttingMembersSet getCrosscuttingMembersSet() {
+ return crosscuttingMembersSet;
+ }
+
+ public IStructureModel getModel() {
+ return model;
+ }
+
+ public void setModel(IStructureModel model) {
+ this.model = model;
+ }
+
+ public Lint getLint() {
+ return lint;
+ }
+
+ public void setLint(Lint lint) {
+ this.lint = lint;
+ }
+
+ public boolean isXnoInline() {
+ return XnoInline;
+ }
+
+ public void setXnoInline(boolean xnoInline) {
+ XnoInline = xnoInline;
+ }
+
+ public boolean isXlazyTjp() {
+ return XlazyTjp;
+ }
+
+ public void setXlazyTjp(boolean b) {
+ XlazyTjp = b;
+ }
+
+ public boolean isHasMemberSupportEnabled() {
+ return XhasMember;
+ }
+
+ public void setXHasMemberSupportEnabled(boolean b) {
+ XhasMember = b;
+ }
+
+ public boolean isInPinpointMode() {
+ return Xpinpoint;
+ }
+
+ public void setPinpointMode(boolean b) {
+ Xpinpoint = b;
+ }
+
+ public boolean useFinal() {
+ return useFinal;
+ }
+
+ public boolean isMinimalModel() {
+ ensureAdvancedConfigurationProcessed();
+ return minimalModel;
+ }
+
+ public boolean isTargettingRuntime1_6_10() {
+ ensureAdvancedConfigurationProcessed();
+ return targettingRuntime1_6_10;
+ }
+
+ public void setBehaveInJava5Way(boolean b) {
+ behaveInJava5Way = b;
+ }
+
+ /**
+ * Set the timing option (whether to collect timing info), this will also need INFO messages turned on for the message handler
+ * being used. The reportPeriodically flag should be set to false under AJDT so numbers just come out at the end.
+ */
+ public void setTiming(boolean timersOn, boolean reportPeriodically) {
+ timing = timersOn;
+ timingPeriodically = reportPeriodically;
+ }
+
+ /**
+ * Set the error and warning threashold which can be taken from CompilerOptions (see bug 129282)
+ *
+ * @param errorThreshold
+ * @param warningThreshold
+ */
+ public void setErrorAndWarningThreshold(boolean errorThreshold, boolean warningThreshold) {
+ this.errorThreshold = errorThreshold;
+ this.warningThreshold = warningThreshold;
+ }
+
+ /**
+ * @return true if ignoring the UnusedDeclaredThrownException and false if this compiler option is set to error or warning
+ */
+ public boolean isIgnoringUnusedDeclaredThrownException() {
+ // the 0x800000 is CompilerOptions.UnusedDeclaredThrownException
+ // which is ASTNode.bit24
+ return errorThreshold||warningThreshold;
+// if ((errorThreshold & 0x800000) != 0 || (warningThreshold & 0x800000) != 0) {
+// return false;
+// }
+// return true;
+ }
+
+ public void performExtraConfiguration(String config) {
+ if (config == null) {
+ return;
+ }
+ // Bunch of name value pairs to split
+ extraConfiguration = new Properties();
+ int pos = -1;
+ while ((pos = config.indexOf(",")) != -1) {
+ String nvpair = config.substring(0, pos);
+ int pos2 = nvpair.indexOf("=");
+ if (pos2 != -1) {
+ String n = nvpair.substring(0, pos2);
+ String v = nvpair.substring(pos2 + 1);
+ extraConfiguration.setProperty(n, v);
+ }
+ config = config.substring(pos + 1);
+ }
+ if (config.length() > 0) {
+ int pos2 = config.indexOf("=");
+ if (pos2 != -1) {
+ String n = config.substring(0, pos2);
+ String v = config.substring(pos2 + 1);
+ extraConfiguration.setProperty(n, v);
+ }
+ }
+ ensureAdvancedConfigurationProcessed();
+ }
+
+ public boolean areInfoMessagesEnabled() {
+ if (infoMessagesEnabled == 0) {
+ infoMessagesEnabled = (messageHandler.isIgnoring(IMessage.INFO) ? 1 : 2);
+ }
+ return infoMessagesEnabled == 2;
+ }
+
+ /**
+ * may return null
+ */
+ public Properties getExtraConfiguration() {
+ return extraConfiguration;
+ }
+
+ public final static String xsetAVOID_FINAL = "avoidFinal"; // default true
+
+ public final static String xsetWEAVE_JAVA_PACKAGES = "weaveJavaPackages"; // default
+ // false
+ // -
+ // controls
+ // LTW
+ public final static String xsetWEAVE_JAVAX_PACKAGES = "weaveJavaxPackages"; // default
+ // false
+ // -
+ // controls
+ // LTW
+ public final static String xsetCAPTURE_ALL_CONTEXT = "captureAllContext"; // default
+ // false
+ public final static String xsetRUN_MINIMAL_MEMORY = "runMinimalMemory"; // default
+ // true
+ public final static String xsetDEBUG_STRUCTURAL_CHANGES_CODE = "debugStructuralChangesCode"; // default
+ // false
+ public final static String xsetDEBUG_BRIDGING = "debugBridging"; // default
+ // false
+ public final static String xsetTRANSIENT_TJP_FIELDS = "makeTjpFieldsTransient"; // default false
+ public final static String xsetBCEL_REPOSITORY_CACHING = "bcelRepositoryCaching";
+ public final static String xsetPIPELINE_COMPILATION = "pipelineCompilation";
+ public final static String xsetGENERATE_STACKMAPS = "generateStackMaps";
+ public final static String xsetPIPELINE_COMPILATION_DEFAULT = "true";
+ public final static String xsetCOMPLETE_BINARY_TYPES = "completeBinaryTypes";
+ public final static String xsetCOMPLETE_BINARY_TYPES_DEFAULT = "false";
+ public final static String xsetTYPE_DEMOTION = "typeDemotion";
+ public final static String xsetTYPE_DEMOTION_DEBUG = "typeDemotionDebug";
+ public final static String xsetTYPE_REFS = "useWeakTypeRefs";
+ public final static String xsetBCEL_REPOSITORY_CACHING_DEFAULT = "true";
+ public final static String xsetFAST_PACK_METHODS = "fastPackMethods"; // default true
+ public final static String xsetOVERWEAVING = "overWeaving";
+ public final static String xsetOPTIMIZED_MATCHING = "optimizedMatching";
+ public final static String xsetTIMERS_PER_JOINPOINT = "timersPerJoinpoint";
+ public final static String xsetTIMERS_PER_FASTMATCH_CALL = "timersPerFastMatchCall";
+ public final static String xsetITD_VERSION = "itdVersion";
+ public final static String xsetITD_VERSION_ORIGINAL = "1";
+ public final static String xsetITD_VERSION_2NDGEN = "2";
+ public final static String xsetITD_VERSION_DEFAULT = xsetITD_VERSION_2NDGEN;
+ public final static String xsetMINIMAL_MODEL = "minimalModel";
+ public final static String xsetTARGETING_RUNTIME_1610 = "targetRuntime1_6_10";
+
+ // This option allows you to prevent AspectJ adding local variable tables - some tools (e.g. dex) may
+ // not like what gets created because even though it is valid, the bytecode they are processing has
+ // unexpected quirks that mean the table entries are violated in the code. See issue:
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=470658
+ public final static String xsetGENERATE_NEW_LVTS="generateNewLocalVariableTables";
+
+ public boolean isInJava5Mode() {
+ return behaveInJava5Way;
+ }
+
+ public boolean isTimingEnabled() {
+ return timing;
+ }
+
+ public void setTargetAspectjRuntimeLevel(String s) {
+ targetAspectjRuntimeLevel = RuntimeVersion.getVersionFor(s);
+ }
+
+ public void setOptionalJoinpoints(String jps) {
+ if (jps == null) {
+ return;
+ }
+ if (jps.indexOf("arrayconstruction") != -1) {
+ optionalJoinpoint_ArrayConstruction = true;
+ }
+ if (jps.indexOf("synchronization") != -1) {
+ optionalJoinpoint_Synchronization = true;
+ }
+ }
+
+ public boolean isJoinpointArrayConstructionEnabled() {
+ return optionalJoinpoint_ArrayConstruction;
+ }
+
+ public boolean isJoinpointSynchronizationEnabled() {
+ return optionalJoinpoint_Synchronization;
+ }
+
+ public RuntimeVersion getTargetAspectjRuntimeLevel() {
+ return targetAspectjRuntimeLevel;
+ }
+
+ // OPTIMIZE are users falling foul of not supplying -1.5 and so targetting the old runtime?
+ public boolean isTargettingAspectJRuntime12() {
+ boolean b = false; // pr116679
+ if (!isInJava5Mode()) {
+ b = true;
+ } else {
+ b = (getTargetAspectjRuntimeLevel() == RuntimeVersion.V1_2);
+ }
+ return b;
+ }
+
+ /*
+ * Map of types in the world, can have 'references' to expendable ones which can be garbage collected to recover memory. An
+ * expendable type is a reference type that is not exposed to the weaver (ie just pulled in for type resolution purposes).
+ * Generic types have their raw form added to the map, which has a pointer to the underlying generic.
+ */
+ public static class TypeMap {
+
+ // Strategy for entries in the expendable map
+ public final static int DONT_USE_REFS = 0; // Hang around forever
+ public final static int USE_WEAK_REFS = 1; // Collected asap
+ public final static int USE_SOFT_REFS = 2; // Collected when short on memory
+
+ public List<String> addedSinceLastDemote;
+ public List<String> writtenClasses;
+
+ private static boolean debug = false;
+ public static boolean useExpendableMap = true; // configurable for reliable testing
+ private boolean demotionSystemActive;
+ private boolean debugDemotion = false;
+
+ public int policy = USE_WEAK_REFS;
+
+ // Map of types that never get thrown away
+ final Map<String, ResolvedType> tMap = new HashMap<String, ResolvedType>();
+
+ // Map of types that may be ejected from the cache if we need space
+ final Map<String, Reference<ResolvedType>> expendableMap = Collections
+ .synchronizedMap(new WeakHashMap<String, Reference<ResolvedType>>());
+
+ private final World w;
+
+ // profiling tools...
+ private boolean memoryProfiling = false;
+ private int maxExpendableMapSize = -1;
+ private int collectedTypes = 0;
+ private final ReferenceQueue<ResolvedType> rq = new ReferenceQueue<ResolvedType>();
+
+ TypeMap(World w) {
+ // Demotion activated when switched on and loadtime weaving or in AJDT
+ demotionSystemActive = w.isDemotionActive() && (w.isLoadtimeWeaving() || w.couldIncrementalCompileFollow());
+ addedSinceLastDemote = new ArrayList<String>();
+ writtenClasses = new ArrayList<String>();
+ this.w = w;
+ memoryProfiling = false;// !w.getMessageHandler().isIgnoring(Message.
+ // INFO);
+ }
+
+ // For testing
+ public Map<String, Reference<ResolvedType>> getExpendableMap() {
+ return expendableMap;
+ }
+
+ // For testing
+ public Map<String, ResolvedType> getMainMap() {
+ return tMap;
+ }
+
+ public int demote() {
+ return demote(false);
+ }
+
+ /**
+ * Go through any types added during the previous file weave. If any are suitable for demotion, then put them in the
+ * expendable map where GC can claim them at some point later. Demotion means: the type is not an aspect, the type is not
+ * java.lang.Object, the type is not primitive and the type is not affected by type mungers in any way. Further refinements
+ * of these conditions may allow for more demotions.
+ *
+ * @return number of types demoted
+ */
+ public int demote(boolean atEndOfCompile) {
+ if (!demotionSystemActive) {
+ return 0;
+ }
+ if (debugDemotion) {
+ System.out.println("Demotion running " + addedSinceLastDemote);
+ }
+ boolean isLtw = w.isLoadtimeWeaving();
+ int demotionCounter = 0;
+ if (isLtw) {
+ // Loadtime weaving demotion strategy
+ for (String key : addedSinceLastDemote) {
+ ResolvedType type = tMap.get(key);
+ if (type != null && !type.isAspect() && !type.equals(UnresolvedType.OBJECT) && !type.isPrimitiveType()) {
+ List<ConcreteTypeMunger> typeMungers = type.getInterTypeMungers();
+ if (typeMungers == null || typeMungers.size() == 0) {
+ tMap.remove(key);
+ insertInExpendableMap(key, type);
+ demotionCounter++;
+ }
+ }
+ }
+ addedSinceLastDemote.clear();
+ } else {
+ // Compile time demotion strategy
+ List<String> forRemoval = new ArrayList<String>();
+ for (String key : addedSinceLastDemote) {
+ ResolvedType type = tMap.get(key);
+ if (type == null) {
+ // TODO not 100% sure why it is not there, where did it go?
+ forRemoval.add(key);
+ continue;
+ }
+ if (!writtenClasses.contains(type.getName())) { // COSTLY
+ continue;
+ }
+ if (type != null && !type.isAspect() && !type.equals(UnresolvedType.OBJECT) && !type.isPrimitiveType()) {
+ List<ConcreteTypeMunger> typeMungers = type.getInterTypeMungers();
+ if (typeMungers == null || typeMungers.size() == 0) {
+ /*
+ * if (type.isNested()) { try { ReferenceType rt = (ReferenceType) w.resolve(type.getOutermostType());
+ * if (!rt.isMissing()) { ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate(); boolean
+ * isWeavable = delegate == null ? false : delegate.isExposedToWeaver(); boolean hasBeenWoven = delegate
+ * == null ? false : delegate.hasBeenWoven(); if (isWeavable && !hasBeenWoven) { // skip demotion of
+ * this inner type for now continue; } } } catch (ClassCastException cce) { cce.printStackTrace();
+ * System.out.println("outer of " + key + " is not a reftype? " + type.getOutermostType()); // throw new
+ * IllegalStateException(cce); } }
+ */
+ ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
+ boolean isWeavable = delegate == null ? false : delegate.isExposedToWeaver();
+ boolean hasBeenWoven = delegate == null ? false : delegate.hasBeenWoven();
+ if (!isWeavable || hasBeenWoven) {
+ if (debugDemotion) {
+ System.out.println("Demoting " + key);
+ }
+ forRemoval.add(key);
+ tMap.remove(key);
+ insertInExpendableMap(key, type);
+ demotionCounter++;
+ }
+ } else {
+ // no need to try this again, it will never be demoted
+ writtenClasses.remove(type.getName());
+ forRemoval.add(key);
+ }
+ } else {
+ writtenClasses.remove(type.getName());
+ // no need to try this again, it will never be demoted
+ forRemoval.add(key);
+ }
+ }
+ addedSinceLastDemote.removeAll(forRemoval);
+ }
+ if (debugDemotion) {
+ System.out.println("Demoted " + demotionCounter + " types. Types remaining in fixed set #" + tMap.keySet().size()
+ + ". addedSinceLastDemote size is " + addedSinceLastDemote.size());
+ System.out.println("writtenClasses.size() = " + writtenClasses.size() + ": " + writtenClasses);
+ }
+ if (atEndOfCompile) {
+ if (debugDemotion) {
+ System.out.println("Clearing writtenClasses");
+ }
+ writtenClasses.clear();
+ }
+ return demotionCounter;
+ }
+
+ private void insertInExpendableMap(String key, ResolvedType type) {
+ if (useExpendableMap) {
+ if (!expendableMap.containsKey(key)) {
+ if (policy == USE_SOFT_REFS) {
+ expendableMap.put(key, new SoftReference<ResolvedType>(type));
+ } else {
+ expendableMap.put(key, new WeakReference<ResolvedType>(type));
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a new type into the map, the key is the type signature. Some types do *not* go in the map, these are ones involving
+ * *member* type variables. The reason is that when all you have is the signature which gives you a type variable name, you
+ * cannot guarantee you are using the type variable in the same way as someone previously working with a similarly named
+ * type variable. So, these do not go into the map: - TypeVariableReferenceType. - ParameterizedType where a member type
+ * variable is involved. - BoundedReferenceType when one of the bounds is a type variable.
+ *
+ * definition: "member type variables" - a tvar declared on a generic method/ctor as opposed to those you see declared on a
+ * generic type.
+ */
+ public ResolvedType put(String key, ResolvedType type) {
+ if (!type.isCacheable()) {
+ return type;
+ }
+ if (type.isParameterizedType() && type.isParameterizedWithTypeVariable()) {
+ if (debug) {
+ System.err
+ .println("Not putting a parameterized type that utilises member declared type variables into the typemap: key="
+ + key + " type=" + type);
+ }
+ return type;
+ }
+ if (type.isTypeVariableReference()) {
+ if (debug) {
+ System.err.println("Not putting a type variable reference type into the typemap: key=" + key + " type=" + type);
+ }
+ return type;
+ }
+ // this test should be improved - only avoid putting them in if one
+ // of the
+ // bounds is a member type variable
+ if (type instanceof BoundedReferenceType) {
+ if (debug) {
+ System.err.println("Not putting a bounded reference type into the typemap: key=" + key + " type=" + type);
+ }
+ return type;
+ }
+ if (type instanceof MissingResolvedTypeWithKnownSignature) {
+ if (debug) {
+ System.err.println("Not putting a missing type into the typemap: key=" + key + " type=" + type);
+ }
+ return type;
+ }
+
+ if ((type instanceof ReferenceType) && (((ReferenceType) type).getDelegate() == null) && w.isExpendable(type)) {
+ if (debug) {
+ System.err.println("Not putting expendable ref type with null delegate into typemap: key=" + key + " type="
+ + type);
+ }
+ return type;
+ }
+
+ // TODO should this be in as a permanent assertion?
+
+ if ((type instanceof ReferenceType) && type.getWorld().isInJava5Mode()
+ && (((ReferenceType) type).getDelegate() != null) && type.isGenericType()) {
+ throw new BCException("Attempt to add generic type to typemap " + type.toString() + " (should be raw)");
+ }
+
+
+ if (w.isExpendable(type)) {
+ if (useExpendableMap) {
+ // Dont use reference queue for tracking if not profiling...
+ if (policy == USE_WEAK_REFS) {
+ if (memoryProfiling) {
+ expendableMap.put(key, new WeakReference<ResolvedType>(type, rq));
+ } else {
+ expendableMap.put(key, new WeakReference<ResolvedType>(type));
+ }
+ } else if (policy == USE_SOFT_REFS) {
+ if (memoryProfiling) {
+ expendableMap.put(key, new SoftReference<ResolvedType>(type, rq));
+ } else {
+ expendableMap.put(key, new SoftReference<ResolvedType>(type));
+ }
+ // } else {
+ // expendableMap.put(key, type);
+ }
+ }
+ if (memoryProfiling && expendableMap.size() > maxExpendableMapSize) {
+ maxExpendableMapSize = expendableMap.size();
+ }
+ return type;
+ } else {
+ if (demotionSystemActive) {
+ // System.out.println("Added since last demote " + key);
+ addedSinceLastDemote.add(key);
+ }
+
+ return tMap.put(key, type);
+ }
+ }
+
+ public void report() {
+ if (!memoryProfiling) {
+ return;
+ }
+ checkq();
+ w.getMessageHandler().handleMessage(
+ MessageUtil.info("MEMORY: world expendable type map reached maximum size of #" + maxExpendableMapSize
+ + " entries"));
+ w.getMessageHandler().handleMessage(
+ MessageUtil.info("MEMORY: types collected through garbage collection #" + collectedTypes + " entries"));
+ }
+
+ public void checkq() {
+ if (!memoryProfiling) {
+ return;
+ }
+ Reference<? extends ResolvedType> r = null;
+ while ((r=rq.poll()) != null) {
+ collectedTypes++;
+ }
+ }
+
+ /**
+ * Lookup a type by its signature, always look in the real map before the expendable map
+ */
+ public ResolvedType get(String key) {
+ checkq();
+ ResolvedType ret = tMap.get(key);
+ if (ret == null) {
+ if (policy == USE_WEAK_REFS) {
+ WeakReference<ResolvedType> ref = (WeakReference<ResolvedType>) expendableMap.get(key);
+ if (ref != null) {
+ ret = ref.get();
+// if (ret==null) {
+// expendableMap.remove(key);
+// }
+ }
+ } else if (policy == USE_SOFT_REFS) {
+ SoftReference<ResolvedType> ref = (SoftReference<ResolvedType>) expendableMap.get(key);
+ if (ref != null) {
+ ret = ref.get();
+// if (ret==null) {
+// expendableMap.remove(key);
+// }
+ }
+ // } else {
+ // return (ResolvedType) expendableMap.get(key);
+ }
+ }
+ return ret;
+ }
+
+ /** Remove a type from the map */
+ public ResolvedType remove(String key) {
+ ResolvedType ret = tMap.remove(key);
+ if (ret == null) {
+ if (policy == USE_WEAK_REFS) {
+ WeakReference<ResolvedType> wref = (WeakReference<ResolvedType>) expendableMap.remove(key);
+ if (wref != null) {
+ ret = wref.get();
+ }
+ } else if (policy == USE_SOFT_REFS) {
+ SoftReference<ResolvedType> wref = (SoftReference<ResolvedType>) expendableMap.remove(key);
+ if (wref != null) {
+ ret = wref.get();
+ }
+ // } else {
+ // ret = (ResolvedType) expendableMap.remove(key);
+ }
+ }
+ return ret;
+ }
+
+ public void classWriteEvent(String classname) {
+ // that is a name com.Foo and not a signature Lcom/Foo; boooooooooo!
+ if (demotionSystemActive) {
+ writtenClasses.add(classname);
+ }
+ if (debugDemotion) {
+ System.out.println("Class write event for " + classname);
+ }
+ }
+
+ public void demote(ResolvedType type) {
+ String key = type.getSignature();
+ if (debugDemotion) {
+ addedSinceLastDemote.remove(key);
+ }
+ tMap.remove(key);
+ insertInExpendableMap(key, type);
+ }
+
+ // public ResolvedType[] getAllTypes() {
+ // List/* ResolvedType */results = new ArrayList();
+ //
+ // collectTypes(expendableMap, results);
+ // collectTypes(tMap, results);
+ // return (ResolvedType[]) results.toArray(new
+ // ResolvedType[results.size()]);
+ // }
+ //
+ // private void collectTypes(Map map, List/* ResolvedType */results) {
+ // for (Iterator iterator = map.keySet().iterator();
+ // iterator.hasNext();) {
+ // String key = (String) iterator.next();
+ // ResolvedType type = get(key);
+ // if (type != null)
+ // results.add(type);
+ // else
+ // System.err.println("null!:" + key);
+ // }
+ // }
+
+ }
+
+ /**
+ * This class is used to compute and store precedence relationships between aspects.
+ */
+ private static class AspectPrecedenceCalculator {
+
+ private final World world;
+ private final Map<PrecedenceCacheKey, Integer> cachedResults;
+
+ public AspectPrecedenceCalculator(World forSomeWorld) {
+ world = forSomeWorld;
+ cachedResults = new HashMap<PrecedenceCacheKey, Integer>();
+ }
+
+ /**
+ * Ask every declare precedence in the world to order the two aspects. If more than one declare precedence gives an
+ * ordering, and the orderings conflict, then that's an error.
+ */
+ public int compareByPrecedence(ResolvedType firstAspect, ResolvedType secondAspect) {
+ PrecedenceCacheKey key = new PrecedenceCacheKey(firstAspect, secondAspect);
+ if (cachedResults.containsKey(key)) {
+ return (cachedResults.get(key)).intValue();
+ } else {
+ int order = 0;
+ DeclarePrecedence orderer = null; // Records the declare
+ // precedence statement that
+ // gives the first ordering
+ for (Iterator<Declare> i = world.getCrosscuttingMembersSet().getDeclareDominates().iterator(); i.hasNext();) {
+ DeclarePrecedence d = (DeclarePrecedence) i.next();
+ int thisOrder = d.compare(firstAspect, secondAspect);
+ if (thisOrder != 0) {
+ if (orderer == null) {
+ orderer = d;
+ }
+ if (order != 0 && order != thisOrder) {
+ ISourceLocation[] isls = new ISourceLocation[2];
+ isls[0] = orderer.getSourceLocation();
+ isls[1] = d.getSourceLocation();
+ Message m = new Message("conflicting declare precedence orderings for aspects: "
+ + firstAspect.getName() + " and " + secondAspect.getName(), null, true, isls);
+ world.getMessageHandler().handleMessage(m);
+ } else {
+ order = thisOrder;
+ }
+ }
+ }
+ cachedResults.put(key, new Integer(order));
+ return order;
+ }
+ }
+
+ public Integer getPrecedenceIfAny(ResolvedType aspect1, ResolvedType aspect2) {
+ return cachedResults.get(new PrecedenceCacheKey(aspect1, aspect2));
+ }
+
+ public int compareByPrecedenceAndHierarchy(ResolvedType firstAspect, ResolvedType secondAspect) {
+ if (firstAspect.equals(secondAspect)) {
+ return 0;
+ }
+
+ int ret = compareByPrecedence(firstAspect, secondAspect);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (firstAspect.isAssignableFrom(secondAspect)) {
+ return -1;
+ } else if (secondAspect.isAssignableFrom(firstAspect)) {
+ return +1;
+ }
+
+ return 0;
+ }
+
+ private static class PrecedenceCacheKey {
+ public ResolvedType aspect1;
+ public ResolvedType aspect2;
+
+ public PrecedenceCacheKey(ResolvedType a1, ResolvedType a2) {
+ aspect1 = a1;
+ aspect2 = a2;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PrecedenceCacheKey)) {
+ return false;
+ }
+ PrecedenceCacheKey other = (PrecedenceCacheKey) obj;
+ return (aspect1 == other.aspect1 && aspect2 == other.aspect2);
+ }
+
+ @Override
+ public int hashCode() {
+ return aspect1.hashCode() + aspect2.hashCode();
+ }
+ }
+ }
+
+ public void validateType(UnresolvedType type) {
+ }
+
+ // --- with java5 we can get into a recursive mess if we aren't careful when
+ // resolving types (*cough* java.lang.Enum) ---
+
+ public boolean isDemotionActive() {
+ return true;
+ }
+
+ // --- this first map is for java15 delegates which may try and recursively
+ // access the same type variables.
+ // --- I would rather stash this against a reference type - but we don't
+ // guarantee referencetypes are unique for
+ // so we can't :(
+ private final Map<Class<?>, TypeVariable[]> workInProgress1 = new HashMap<Class<?>, TypeVariable[]>();
+
+ public TypeVariable[] getTypeVariablesCurrentlyBeingProcessed(Class<?> baseClass) {
+ return workInProgress1.get(baseClass);
+ }
+
+ public void recordTypeVariablesCurrentlyBeingProcessed(Class<?> baseClass, TypeVariable[] typeVariables) {
+ workInProgress1.put(baseClass, typeVariables);
+ }
+
+ public void forgetTypeVariablesCurrentlyBeingProcessed(Class<?> baseClass) {
+ workInProgress1.remove(baseClass);
+ }
+
+ public void setAddSerialVerUID(boolean b) {
+ addSerialVerUID = b;
+ }
+
+ public boolean isAddSerialVerUID() {
+ return addSerialVerUID;
+ }
+
+ /** be careful calling this - pr152257 */
+ public void flush() {
+ typeMap.expendableMap.clear();
+ }
+
+ public void ensureAdvancedConfigurationProcessed() {
+
+ // Check *once* whether the user has switched asm support off
+ if (!checkedAdvancedConfiguration) {
+ Properties p = getExtraConfiguration();
+ if (p != null) {
+
+ String s = p.getProperty(xsetBCEL_REPOSITORY_CACHING, xsetBCEL_REPOSITORY_CACHING_DEFAULT);
+ bcelRepositoryCaching = s.equalsIgnoreCase("true");
+ if (!bcelRepositoryCaching) {
+ getMessageHandler().handleMessage(
+ MessageUtil
+ .info("[bcelRepositoryCaching=false] AspectJ will not use a bcel cache for class information"));
+ }
+
+ // ITD Versions
+ // 1 is the first version in use up to AspectJ 1.6.8
+ // 2 is from 1.6.9 onwards
+ s = p.getProperty(xsetITD_VERSION, xsetITD_VERSION_DEFAULT);
+ if (s.equals(xsetITD_VERSION_ORIGINAL)) {
+ itdVersion = 1;
+ }
+
+ s = p.getProperty(xsetAVOID_FINAL, "false");
+ if (s.equalsIgnoreCase("true")) {
+ useFinal = false; // if avoidFinal=true, then set useFinal to false
+ }
+
+ s = p.getProperty(xsetMINIMAL_MODEL, "true");
+ if (s.equalsIgnoreCase("false")) {
+ minimalModel = false;
+ }
+
+ s = p.getProperty(xsetTARGETING_RUNTIME_1610, "false");
+ if (s.equalsIgnoreCase("true")) {
+ targettingRuntime1_6_10 = true;
+ }
+
+ s = p.getProperty(xsetFAST_PACK_METHODS, "true");
+ fastMethodPacking = s.equalsIgnoreCase("true");
+
+ s = p.getProperty(xsetPIPELINE_COMPILATION, xsetPIPELINE_COMPILATION_DEFAULT);
+ shouldPipelineCompilation = s.equalsIgnoreCase("true");
+
+ s = p.getProperty(xsetGENERATE_STACKMAPS, "false");
+ shouldGenerateStackMaps = s.equalsIgnoreCase("true");
+
+ s = p.getProperty(xsetCOMPLETE_BINARY_TYPES, xsetCOMPLETE_BINARY_TYPES_DEFAULT);
+ completeBinaryTypes = s.equalsIgnoreCase("true");
+ if (completeBinaryTypes) {
+ getMessageHandler().handleMessage(
+ MessageUtil.info("[completeBinaryTypes=true] Completion of binary types activated"));
+ }
+
+ s = p.getProperty(xsetTYPE_DEMOTION); // default is: ON
+ if (s != null) {
+ boolean b = typeMap.demotionSystemActive;
+ if (b && s.equalsIgnoreCase("false")) {
+ System.out.println("typeDemotion=false: type demotion switched OFF");
+ typeMap.demotionSystemActive = false;
+ } else if (!b && s.equalsIgnoreCase("true")) {
+ System.out.println("typeDemotion=true: type demotion switched ON");
+ typeMap.demotionSystemActive = true;
+ }
+ }
+
+ s = p.getProperty(xsetOVERWEAVING, "false");
+ if (s.equalsIgnoreCase("true")) {
+ overWeaving = true;
+ }
+
+ s = p.getProperty(xsetTYPE_DEMOTION_DEBUG, "false");
+ if (s.equalsIgnoreCase("true")) {
+ typeMap.debugDemotion = true;
+ }
+ s = p.getProperty(xsetTYPE_REFS, "true");
+ if (s.equalsIgnoreCase("false")) {
+ typeMap.policy = TypeMap.USE_SOFT_REFS;
+ }
+
+ runMinimalMemorySet = p.getProperty(xsetRUN_MINIMAL_MEMORY) != null;
+ s = p.getProperty(xsetRUN_MINIMAL_MEMORY, "false");
+ runMinimalMemory = s.equalsIgnoreCase("true");
+ // if (runMinimalMemory)
+ // getMessageHandler().handleMessage(MessageUtil.info(
+ // "[runMinimalMemory=true] Optimizing bcel processing (and cost of performance) to use less memory"
+ // ));
+
+ s = p.getProperty(xsetDEBUG_STRUCTURAL_CHANGES_CODE, "false");
+ forDEBUG_structuralChangesCode = s.equalsIgnoreCase("true");
+
+ s = p.getProperty(xsetTRANSIENT_TJP_FIELDS,"false");
+ transientTjpFields = s.equalsIgnoreCase("true");
+
+ s = p.getProperty(xsetDEBUG_BRIDGING, "false");
+ forDEBUG_bridgingCode = s.equalsIgnoreCase("true");
+
+ s = p.getProperty(xsetGENERATE_NEW_LVTS,"true");
+ generateNewLvts = s.equalsIgnoreCase("true");
+ if (!generateNewLvts) {
+ getMessageHandler().handleMessage(MessageUtil.info("[generateNewLvts=false] for methods without an incoming local variable table, do not generate one"));
+ }
+
+ s = p.getProperty(xsetOPTIMIZED_MATCHING, "true");
+ optimizedMatching = s.equalsIgnoreCase("true");
+ if (!optimizedMatching) {
+ getMessageHandler().handleMessage(MessageUtil.info("[optimizedMatching=false] optimized matching turned off"));
+ }
+
+ s = p.getProperty(xsetTIMERS_PER_JOINPOINT, "25000");
+ try {
+ timersPerJoinpoint = Integer.parseInt(s);
+ } catch (Exception e) {
+ getMessageHandler().handleMessage(MessageUtil.error("unable to process timersPerJoinpoint value of " + s));
+ timersPerJoinpoint = 25000;
+ }
+
+ s = p.getProperty(xsetTIMERS_PER_FASTMATCH_CALL, "250");
+ try {
+ timersPerType = Integer.parseInt(s);
+ } catch (Exception e) {
+ getMessageHandler().handleMessage(MessageUtil.error("unable to process timersPerType value of " + s));
+ timersPerType = 250;
+ }
+
+ }
+ try {
+ if (systemPropertyOverWeaving) {
+ overWeaving = true;
+ }
+ String value = null;
+ value = System.getProperty("aspectj.typeDemotion", "false");
+ if (value.equalsIgnoreCase("true")) {
+ System.out.println("ASPECTJ: aspectj.typeDemotion=true: type demotion switched ON");
+ typeMap.demotionSystemActive = true;
+ }
+ value = System.getProperty("aspectj.minimalModel", "false");
+ if (value.equalsIgnoreCase("true")) {
+ System.out.println("ASPECTJ: aspectj.minimalModel=true: minimal model switched ON");
+ minimalModel = true;
+ }
+ } catch (Throwable t) {
+ System.err.println("ASPECTJ: Unable to read system properties");
+ t.printStackTrace();
+ }
+ checkedAdvancedConfiguration = true;
+ }
+ }
+
+ public boolean isRunMinimalMemory() {
+ ensureAdvancedConfigurationProcessed();
+ return runMinimalMemory;
+ }
+
+ public boolean isTransientTjpFields() {
+ ensureAdvancedConfigurationProcessed();
+ return transientTjpFields;
+ }
+
+ public boolean isRunMinimalMemorySet() {
+ ensureAdvancedConfigurationProcessed();
+ return runMinimalMemorySet;
+ }
+
+ public boolean shouldFastPackMethods() {
+ ensureAdvancedConfigurationProcessed();
+ return fastMethodPacking;
+ }
+
+ public boolean shouldPipelineCompilation() {
+ ensureAdvancedConfigurationProcessed();
+ return shouldPipelineCompilation;
+ }
+
+ public boolean shouldGenerateStackMaps() {
+ ensureAdvancedConfigurationProcessed();
+ return shouldGenerateStackMaps;
+ }
+
+ public void setIncrementalCompileCouldFollow(boolean b) {
+ incrementalCompileCouldFollow = b;
+ }
+
+ public boolean couldIncrementalCompileFollow() {
+ return incrementalCompileCouldFollow;
+ }
+
+ public void setSynchronizationPointcutsInUse() {
+ if (trace.isTraceEnabled()) {
+ trace.enter("setSynchronizationPointcutsInUse", this);
+ }
+ synchronizationPointcutsInUse = true;
+ if (trace.isTraceEnabled()) {
+ trace.exit("setSynchronizationPointcutsInUse");
+ }
+ }
+
+ public boolean areSynchronizationPointcutsInUse() {
+ return synchronizationPointcutsInUse;
+ }
+
+ /**
+ * Register a new pointcut designator handler with the world - this can be used by any pointcut parsers attached to the world.
+ *
+ * @param designatorHandler handler for the new pointcut
+ */
+ public void registerPointcutHandler(PointcutDesignatorHandler designatorHandler) {
+ if (pointcutDesignators == null) {
+ pointcutDesignators = new HashSet<PointcutDesignatorHandler>();
+ }
+ pointcutDesignators.add(designatorHandler);
+ }
+
+ public Set<PointcutDesignatorHandler> getRegisteredPointcutHandlers() {
+ if (pointcutDesignators == null) {
+ return Collections.emptySet();
+ }
+ return pointcutDesignators;
+ }
+
+ public void reportMatch(ShadowMunger munger, Shadow shadow) {
+
+ }
+
+ public boolean isOverWeaving() {
+ return overWeaving;
+ }
+
+ public void reportCheckerMatch(Checker checker, Shadow shadow) {
+ }
+
+ /**
+ * @return true if this world has the activation and scope of application of the aspects controlled via aop.xml files
+ */
+ public boolean isXmlConfigured() {
+ return false;
+ }
+
+ public boolean isAspectIncluded(ResolvedType aspectType) {
+ return true;
+ }
+
+ /**
+ * Determine if the named aspect requires a particular type around in order to be useful. The type is named in the aop.xml file
+ * against the aspect.
+ *
+ * @return true if there is a type missing that this aspect really needed around
+ */
+ public boolean hasUnsatisfiedDependency(ResolvedType aspectType) {
+ return false;
+ }
+
+ public TypePattern getAspectScope(ResolvedType declaringType) {
+ return null;
+ }
+
+ public Map<String, ResolvedType> getFixed() {
+ return typeMap.tMap;
+ }
+
+ public Map<String, Reference<ResolvedType>> getExpendable() {
+ return typeMap.expendableMap;
+ }
+
+ /**
+ * Ask the type map to demote any types it can - we don't want them anchored forever.
+ */
+ public void demote() {
+ typeMap.demote();
+ }
+
+ // protected boolean isExpendable(ResolvedType type) {
+ // if (type.equals(UnresolvedType.OBJECT))
+ // return false;
+ // if (type == null)
+ // return false;
+ // boolean isExposed = type.isExposedToWeaver();
+ // boolean nullDele = (type instanceof ReferenceType) ? ((ReferenceType) type).getDelegate() != null : true;
+ // if (isExposed || !isExposed && nullDele)
+ // return false;
+ // return !type.isPrimitiveType();
+ // }
+
+ /**
+ * Reference types we don't intend to weave may be ejected from the cache if we need the space.
+ */
+ protected boolean isExpendable(ResolvedType type) {
+ return !type.equals(UnresolvedType.OBJECT) && !type.isExposedToWeaver() && !type.isPrimitiveType()
+ && !type.isPrimitiveArray();
+ }
+
+ // map from aspect > excluded types
+ // memory issue here?
+ private Map<ResolvedType, Set<ResolvedType>> exclusionMap = new HashMap<ResolvedType, Set<ResolvedType>>();
+
+ public Map<ResolvedType, Set<ResolvedType>> getExclusionMap() {
+ return exclusionMap;
+ }
+
+ private TimeCollector timeCollector = null;
+
+ /**
+ * Record the time spent matching a pointcut - this will accumulate over the lifetime of this world/weaver and be reported every
+ * 25000 join points.
+ */
+ public void record(Pointcut pointcut, long timetaken) {
+ if (timeCollector == null) {
+ ensureAdvancedConfigurationProcessed();
+ timeCollector = new TimeCollector(this);
+ }
+ timeCollector.record(pointcut, timetaken);
+ }
+
+ /**
+ * Record the time spent fastmatching a pointcut - this will accumulate over the lifetime of this world/weaver and be reported
+ * every 250 types.
+ */
+ public void recordFastMatch(Pointcut pointcut, long timetaken) {
+ if (timeCollector == null) {
+ ensureAdvancedConfigurationProcessed();
+ timeCollector = new TimeCollector(this);
+ }
+ timeCollector.recordFastMatch(pointcut, timetaken);
+ }
+
+ public void reportTimers() {
+ if (timeCollector != null && !timingPeriodically) {
+ timeCollector.report();
+ timeCollector = new TimeCollector(this);
+ }
+ }
+
+ private static class TimeCollector {
+ private World world;
+ long joinpointCount;
+ long typeCount;
+ long perJoinpointCount;
+ long perTypes;
+ Map<String, Long> joinpointsPerPointcut = new HashMap<String, Long>();
+ Map<String, Long> timePerPointcut = new HashMap<String, Long>();
+ Map<String, Long> fastMatchTimesPerPointcut = new HashMap<String, Long>();
+ Map<String, Long> fastMatchTypesPerPointcut = new HashMap<String, Long>();
+
+ TimeCollector(World world) {
+ this.perJoinpointCount = world.timersPerJoinpoint;
+ this.perTypes = world.timersPerType;
+ this.world = world;
+ this.joinpointCount = 0;
+ this.typeCount = 0;
+ this.joinpointsPerPointcut = new HashMap<String, Long>();
+ this.timePerPointcut = new HashMap<String, Long>();
+ }
+
+ public void report() {
+ long totalTime = 0L;
+ for (String p : joinpointsPerPointcut.keySet()) {
+ totalTime += timePerPointcut.get(p);
+ }
+ world.getMessageHandler().handleMessage(
+ MessageUtil.info("Pointcut matching cost (total=" + (totalTime / 1000000) + "ms for " + joinpointCount
+ + " joinpoint match calls):"));
+ for (String p : joinpointsPerPointcut.keySet()) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Time:" + (timePerPointcut.get(p) / 1000000) + "ms (jps:#" + joinpointsPerPointcut.get(p)
+ + ") matching against " + p);
+ world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
+ }
+ world.getMessageHandler().handleMessage(MessageUtil.info("---"));
+
+ totalTime = 0L;
+ for (String p : fastMatchTimesPerPointcut.keySet()) {
+ totalTime += fastMatchTimesPerPointcut.get(p);
+ }
+ world.getMessageHandler().handleMessage(
+ MessageUtil.info("Pointcut fast matching cost (total=" + (totalTime / 1000000) + "ms for " + typeCount
+ + " fast match calls):"));
+ for (String p : fastMatchTimesPerPointcut.keySet()) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Time:" + (fastMatchTimesPerPointcut.get(p) / 1000000) + "ms (types:#" + fastMatchTypesPerPointcut.get(p)
+ + ") fast matching against " + p);
+ world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
+ }
+ world.getMessageHandler().handleMessage(MessageUtil.info("---"));
+
+ }
+
+ void record(Pointcut pointcut, long timetakenInNs) {
+ joinpointCount++;
+ String pointcutText = pointcut.toString();
+ Long jpcounter = joinpointsPerPointcut.get(pointcutText);
+ if (jpcounter == null) {
+ jpcounter = 1L;
+ } else {
+ jpcounter++;
+ }
+ joinpointsPerPointcut.put(pointcutText, jpcounter);
+
+ Long time = timePerPointcut.get(pointcutText);
+ if (time == null) {
+ time = timetakenInNs;
+ } else {
+ time += timetakenInNs;
+ }
+ timePerPointcut.put(pointcutText, time);
+ if (world.timingPeriodically) {
+ if ((joinpointCount % perJoinpointCount) == 0) {
+ long totalTime = 0L;
+ for (String p : joinpointsPerPointcut.keySet()) {
+ totalTime += timePerPointcut.get(p);
+ }
+ world.getMessageHandler().handleMessage(
+ MessageUtil.info("Pointcut matching cost (total=" + (totalTime / 1000000) + "ms for " + joinpointCount
+ + " joinpoint match calls):"));
+ for (String p : joinpointsPerPointcut.keySet()) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Time:" + (timePerPointcut.get(p) / 1000000) + "ms (jps:#" + joinpointsPerPointcut.get(p)
+ + ") matching against " + p);
+ world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
+ }
+ world.getMessageHandler().handleMessage(MessageUtil.info("---"));
+ }
+ }
+ }
+
+ void recordFastMatch(Pointcut pointcut, long timetakenInNs) {
+ typeCount++;
+ String pointcutText = pointcut.toString();
+ Long typecounter = fastMatchTypesPerPointcut.get(pointcutText);
+ if (typecounter == null) {
+ typecounter = 1L;
+ } else {
+ typecounter++;
+ }
+ fastMatchTypesPerPointcut.put(pointcutText, typecounter);
+
+ Long time = fastMatchTimesPerPointcut.get(pointcutText);
+ if (time == null) {
+ time = timetakenInNs;
+ } else {
+ time += timetakenInNs;
+ }
+ fastMatchTimesPerPointcut.put(pointcutText, time);
+ if (world.timingPeriodically) {
+ if ((typeCount % perTypes) == 0) {
+ long totalTime = 0L;
+ for (String p : fastMatchTimesPerPointcut.keySet()) {
+ totalTime += fastMatchTimesPerPointcut.get(p);
+ }
+ world.getMessageHandler().handleMessage(
+ MessageUtil.info("Pointcut fast matching cost (total=" + (totalTime / 1000000) + "ms for " + typeCount
+ + " fast match calls):"));
+ for (String p : fastMatchTimesPerPointcut.keySet()) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Time:" + (fastMatchTimesPerPointcut.get(p) / 1000000) + "ms (types:#"
+ + fastMatchTypesPerPointcut.get(p) + ") fast matching against " + p);
+ world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
+ }
+ world.getMessageHandler().handleMessage(MessageUtil.info("---"));
+ }
+ }
+ }
+ }
+
+ public TypeMap getTypeMap() {
+ return typeMap;
+ }
+
+ public static void reset() {
+ // ResolvedType.resetPrimitives();
+ }
+
+ /**
+ * Returns the version of ITD that this world wants to create. The default is the new style (2) but in some cases where there
+ * might be a clash, the old style can be used. It is set through the option -Xset:itdVersion=1
+ *
+ * @return the ITD version this world wants to create - 1=oldstyle 2=new, transparent style
+ */
+ public int getItdVersion() {
+ return itdVersion;
+ }
+
+ // if not loadtime weaving then we are compile time weaving or post-compile time weaving
+ public abstract boolean isLoadtimeWeaving();
+
+ public void classWriteEvent(char[][] compoundName) {
+ // override if interested in write events
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/XlintDefault.properties b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/XlintDefault.properties
new file mode 100644
index 000000000..416fc2d55
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/XlintDefault.properties
@@ -0,0 +1,50 @@
+invalidAbsoluteTypeName = warning
+invalidWildcardTypeName = ignore
+
+unresolvableMember = warning
+
+typeNotExposedToWeaver = warning
+
+shadowNotInStructure = ignore
+
+unmatchedSuperTypeInCall = warning
+
+canNotImplementLazyTjp = ignore
+multipleAdviceStoppingLazyTjp=ignore
+noGuardForLazyTjp=ignore
+
+uncheckedAdviceConversion = warning
+
+needsSerialVersionUIDField = ignore
+brokeSerialVersionCompatibility = ignore
+
+noInterfaceCtorJoinpoint = warning
+
+noJoinpointsForBridgeMethods = warning
+cantMatchArrayTypeOnVarargs = ignore
+enumAsTargetForDecpIgnored = warning
+annotationAsTargetForDecpIgnored = warning
+adviceDidNotMatch = warning
+invalidTargetForAnnotation = warning
+elementAlreadyAnnotated = warning
+runtimeExceptionNotSoftened = warning
+uncheckedArgument = warning
+noExplicitConstructorCall = warning
+
+aspectExcludedByConfiguration = ignore
+
+unmatchedTargetKind = warning
+
+cantFindType = error
+cantFindTypeAffectingJPMatch = warning
+
+unorderedAdviceAtShadow=ignore
+swallowedExceptionInCatchBlock=ignore
+calculatingSerialVersionUID=ignore
+advisingSynchronizedMethods=warning
+mustWeaveXmlDefinedAspects=warning
+
+missingAspectForReweaving=error
+cannotAdviseJoinpointInInterfaceWithAroundAdvice=warning
+
+nonReweavableTypeEncountered=error \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ASTNode.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ASTNode.java
new file mode 100644
index 000000000..7e8b08347
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ASTNode.java
@@ -0,0 +1,22 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+public abstract class ASTNode {
+
+ public ASTNode() {
+ super();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/And.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/And.java
new file mode 100644
index 000000000..8679d48d0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/And.java
@@ -0,0 +1,51 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+
+public class And extends Test {
+ Test left, right;
+
+ public And(Test left, Test right) {
+ super();
+ this.left = left;
+ this.right = right;
+ }
+
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public String toString() {
+ return "(" + left + " && " + right + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof And) {
+ And o = (And) other;
+ return o.left.equals(left) && o.right.equals(right);
+ } else {
+ return false;
+ }
+ }
+
+ public Test getLeft() {
+ return left;
+ }
+
+ public Test getRight() {
+ return right;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Call.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Call.java
new file mode 100644
index 000000000..1a1b52abe
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Call.java
@@ -0,0 +1,41 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.Member;
+
+public class Call extends Test {
+ // assert m.return value is boolean
+ private final Member method;
+ private final Expr[] args;
+
+ public Call(Member m, Expr[] args) {
+ super();
+ this.method = m;
+ this.args = args;
+ }
+
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public Expr[] getArgs() {
+ return args;
+ }
+
+ public Member getMethod() {
+ return method;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/CallExpr.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/CallExpr.java
new file mode 100644
index 000000000..e8191a42e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/CallExpr.java
@@ -0,0 +1,48 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+
+public class CallExpr extends Expr {
+ // assert m.return value is boolean
+ private final Member method;
+ private final Expr[] args;
+ private final ResolvedType returnType; // yes, stored in method as well, but that one isn't resolved
+
+ public CallExpr(Member m, Expr[] args, ResolvedType returnType) {
+ super();
+ this.method = m;
+ this.args = args;
+ this.returnType = returnType;
+ }
+
+ public void accept(IExprVisitor v) {
+ v.visit(this);
+ }
+
+ public Expr[] getArgs() {
+ return args;
+ }
+
+ public Member getMethod() {
+ return method;
+ }
+
+ public ResolvedType getType() {
+ return returnType;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Expr.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Expr.java
new file mode 100644
index 000000000..1b22c8f42
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Expr.java
@@ -0,0 +1,34 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+
+public abstract class Expr extends ASTNode {
+
+ public Expr() {
+ super();
+ }
+
+ public static final Expr[] NONE = new Expr[0];
+
+ public abstract void accept(IExprVisitor v);
+
+ public abstract ResolvedType getType();
+
+ public static CallExpr makeCallExpr(Member member, Expr[] exprs, ResolvedType returnType) {
+ return new CallExpr(member, exprs, returnType);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGet.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGet.java
new file mode 100644
index 000000000..2e145e3c2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGet.java
@@ -0,0 +1,44 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+
+public class FieldGet extends Expr {
+ Member field;
+ ResolvedType resolvedType;
+
+ public FieldGet(Member field, ResolvedType resolvedType) {
+ super();
+ this.field = field;
+ this.resolvedType = resolvedType;
+ }
+
+ public ResolvedType getType() {
+ return resolvedType;
+ }
+
+ public String toString() {
+ return "(FieldGet " + field + ")";
+ }
+
+ public void accept(IExprVisitor v) {
+ v.visit(this);
+ }
+
+ public Member getField() {
+ return field;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGetCall.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGetCall.java
new file mode 100644
index 000000000..64aaf4b1a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/FieldGetCall.java
@@ -0,0 +1,47 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.Member;
+
+public class FieldGetCall extends Test {
+ // assert m.return value is boolean
+ private final Member field;
+ private final Member method;
+ private final Expr[] args;
+
+ public FieldGetCall(Member f, Member m, Expr[] args) {
+ super();
+ this.field = f;
+ this.method = m;
+ this.args = args;
+ }
+
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public Expr[] getArgs() {
+ return args;
+ }
+
+ public Member getMethod() {
+ return method;
+ }
+
+ public Member getField() {
+ return field;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/HasAnnotation.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/HasAnnotation.java
new file mode 100644
index 000000000..885e9d083
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/HasAnnotation.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+
+public class HasAnnotation extends Test {
+
+ private Var v;
+ private ResolvedType annType;
+
+ public HasAnnotation(Var v, ResolvedType annType) {
+ super();
+ this.v = v;
+ this.annType = annType;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.ast.Test#accept(org.aspectj.weaver.ast.ITestVisitor)
+ */
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public String toString() {
+ return "(" + v + " has annotation @" + annType + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof HasAnnotation) {
+ HasAnnotation o = (HasAnnotation) other;
+ return o.v.equals(v) && o.annType.equals(annType);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return v.hashCode()*37+annType.hashCode();
+ }
+
+ public Var getVar() {
+ return v;
+ }
+
+ public UnresolvedType getAnnotationType() {
+ return annType;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/IExprVisitor.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/IExprVisitor.java
new file mode 100644
index 000000000..89e0b3d74
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/IExprVisitor.java
@@ -0,0 +1,23 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.ast;
+
+public interface IExprVisitor {
+
+ void visit(Var i);
+
+ void visit(FieldGet fieldGet);
+
+ void visit(CallExpr callExpr);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ITestVisitor.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ITestVisitor.java
new file mode 100644
index 000000000..fc99272af
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/ITestVisitor.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
+
+
+public interface ITestVisitor {
+
+ void visit(And e);
+ void visit(Instanceof i);
+ void visit(Not not);
+ void visit(Or or);
+ void visit(Literal literal);
+ void visit(Call call);
+ void visit(FieldGetCall fieldGetCall);
+ void visit(HasAnnotation hasAnnotation);
+ void visit(MatchingContextBasedTest matchingContextTest);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Instanceof.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Instanceof.java
new file mode 100644
index 000000000..feec6a2be
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Instanceof.java
@@ -0,0 +1,56 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.UnresolvedType;
+
+public class Instanceof extends Test {
+ Var var;
+ UnresolvedType type;
+
+ public Instanceof(Var left, UnresolvedType right) {
+ super();
+ this.var = left;
+ this.type = right;
+ }
+
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public String toString() {
+ return "(" + var + " instanceof " + type + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof Instanceof) {
+ Instanceof o = (Instanceof) other;
+ return o.var.equals(var) && o.type.equals(type);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return var.hashCode()*37+type.hashCode();
+ }
+
+ public Var getVar() {
+ return var;
+ }
+
+ public UnresolvedType getType() {
+ return type;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Literal.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Literal.java
new file mode 100644
index 000000000..bb7968eb5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Literal.java
@@ -0,0 +1,39 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+
+public final class Literal extends Test {
+
+ boolean noTest;
+ boolean val;
+
+ private Literal(boolean val, boolean noTest) {
+ super();
+ this.val = val;
+ this.noTest = noTest;
+ }
+
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public static final Literal TRUE = new Literal(true, false);
+ public static final Literal FALSE = new Literal(false, false);
+// public static final Literal NO_TEST = new Literal(false, true);
+
+ public String toString() {
+ return noTest ? "NO_TEST" : val ? "TRUE" : "FALSE";
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Not.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Not.java
new file mode 100644
index 000000000..366a193a4
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Not.java
@@ -0,0 +1,49 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+
+public class Not extends Test {
+ Test test;
+
+ public Not(Test test) {
+ super();
+ this.test = test;
+ }
+
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public Test getBody() {
+ return test;
+ }
+
+ public String toString() {
+ return "!" + test;
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof Not) {
+ Not o = (Not) other;
+ return o.test.equals(test);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return test.hashCode();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Or.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Or.java
new file mode 100644
index 000000000..b3143df73
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Or.java
@@ -0,0 +1,56 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+public class Or extends Test {
+ Test left, right;
+
+ public Or(Test left, Test right) {
+ super();
+ this.left = left;
+ this.right = right;
+ }
+
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public String toString() {
+ return "(" + left + " || " + right + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof Or) {
+ Or o = (Or) other;
+ return o.left.equals(left) && o.right.equals(right);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ int result = 19;
+ result = 37*result + left.hashCode();
+ result = 37*result + right.hashCode();
+ return result;
+ }
+
+ public Test getLeft() {
+ return left;
+ }
+
+ public Test getRight() {
+ return right;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Test.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Test.java
new file mode 100644
index 000000000..8da7694e6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Test.java
@@ -0,0 +1,95 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+
+public abstract class Test extends ASTNode {
+
+ public Test() {
+ super();
+ }
+
+ public abstract void accept(ITestVisitor v);
+
+ public static Test makeAnd(Test a, Test b) {
+// if (a == Literal.NO_TEST) return b;
+// if (b == Literal.NO_TEST) return a;
+ if (a == Literal.TRUE) {
+ if (b == Literal.TRUE) {
+ return a;
+ } else {
+ return b;
+ }
+ } else if (b == Literal.TRUE) {
+ return a;
+ } else if (a == Literal.FALSE || b == Literal.FALSE) {
+ return Literal.FALSE;
+ } else {
+ return new And(a, b);
+ }
+ }
+
+ public static Test makeOr(Test a, Test b) {
+// if (a == Literal.NO_TEST) return a;
+// if (b == Literal.NO_TEST) return b;
+ if (a == Literal.FALSE) {
+ return b;
+ } else if (b == Literal.FALSE) {
+ return a;
+ } else if (a == Literal.TRUE || b == Literal.TRUE) {
+ return Literal.TRUE;
+ } else {
+ return new Or(a, b);
+ }
+ }
+
+ public static Test makeNot(Test a) {
+ if (a instanceof Not) {
+ return ((Not) a).getBody();
+ } else if (a == Literal.TRUE) {
+ return Literal.FALSE;
+ } else if (a == Literal.FALSE) {
+ return Literal.TRUE;
+// } else if (a == Literal.NO_TEST) {
+// return a;
+ } else {
+ return new Not(a);
+ }
+ }
+
+ // uses our special rules that anything matches object
+ public static Test makeInstanceof(Var v, ResolvedType ty) {
+ if (ty.equals(ResolvedType.OBJECT)) return Literal.TRUE;
+
+ Test e;
+ if (ty.isAssignableFrom(v.getType())) e = Literal.TRUE;
+ else if (! ty.isCoerceableFrom(v.getType())) e = Literal.FALSE;
+ else e = new Instanceof(v, ty);
+ return e;
+ }
+
+ public static Test makeHasAnnotation(Var v, ResolvedType annTy) {
+ return new HasAnnotation(v,annTy);
+ }
+
+ public static Test makeCall(Member m, Expr[] args) {
+ return new Call(m, args);
+ }
+ public static Test makeFieldGetCall(Member f, Member m, Expr[] args) {
+ return new FieldGetCall(f, m, args);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Var.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Var.java
new file mode 100644
index 000000000..77fddb557
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/ast/Var.java
@@ -0,0 +1,49 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.ast;
+
+import org.aspectj.weaver.ResolvedType;
+
+public class Var extends Expr {
+ public static final Var[] NONE = new Var[0];
+ ResolvedType variableType;
+
+ public Var(ResolvedType variableType) {
+ super();
+ this.variableType = variableType;
+ }
+
+ public ResolvedType getType() {
+ return variableType;
+ }
+
+ public String toString() {
+ return "(Var " + variableType + ")";
+ }
+
+ public void accept(IExprVisitor v) {
+ v.visit(this);
+ }
+
+ /**
+ * For an annotation this will return a variable that can access a specific field of the annotation (of the specified type) TODO
+ * what kind of behaviour happens for two annotation fields of the same type?
+ *
+ * @param formalType
+ * @param formalName
+ * @return
+ */
+ public Var getAccessorForValue(ResolvedType formalType, String formalName) {
+ throw new IllegalStateException("Only makes sense for annotation variables");
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/MatchingContextBasedTest.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/MatchingContextBasedTest.java
new file mode 100644
index 000000000..b5a78e0e6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/MatchingContextBasedTest.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.internal.tools;
+
+import org.aspectj.weaver.ast.ITestVisitor;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.tools.MatchingContext;
+import org.aspectj.weaver.tools.ContextBasedMatcher;
+
+/**
+ * Test that uses MatchingContext to match (or not)
+ *
+ */
+public class MatchingContextBasedTest extends Test {
+
+ private final ContextBasedMatcher matcher;
+
+ public MatchingContextBasedTest(ContextBasedMatcher pc) {
+ this.matcher = pc;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.ast.Test#accept(org.aspectj.weaver.ast.ITestVisitor)
+ */
+ public void accept(ITestVisitor v) {
+ v.visit(this);
+ }
+
+ public boolean matches(MatchingContext context) {
+ return this.matcher.matchesDynamically(context);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutDesignatorHandlerBasedPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutDesignatorHandlerBasedPointcut.java
new file mode 100644
index 000000000..e5672dede
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutDesignatorHandlerBasedPointcut.java
@@ -0,0 +1,187 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.internal.tools;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ReferenceTypeDelegate;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.patterns.Bindings;
+import org.aspectj.weaver.patterns.ExposedState;
+import org.aspectj.weaver.patterns.FastMatchInfo;
+import org.aspectj.weaver.patterns.IScope;
+import org.aspectj.weaver.patterns.PatternNodeVisitor;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate;
+import org.aspectj.weaver.reflect.ReflectionFastMatchInfo;
+import org.aspectj.weaver.reflect.ReflectionShadow;
+import org.aspectj.weaver.reflect.ReflectionWorld;
+import org.aspectj.weaver.tools.ContextBasedMatcher;
+import org.aspectj.weaver.tools.MatchingContext;
+
+/**
+ * Implementation of Pointcut that is backed by a user-extension pointcut designator handler.
+ *
+ */
+public class PointcutDesignatorHandlerBasedPointcut extends Pointcut {
+
+ private final ContextBasedMatcher matcher;
+ private final World world;
+
+ public PointcutDesignatorHandlerBasedPointcut(ContextBasedMatcher expr, World world) {
+ this.matcher = expr;
+ this.world = world;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#getPointcutKind()
+ */
+ public byte getPointcutKind() {
+ return Pointcut.USER_EXTENSION;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
+ */
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ if (info instanceof ReflectionFastMatchInfo) {
+ // Really need a reflectionworld here...
+ if (!(world instanceof ReflectionWorld)) {
+ throw new IllegalStateException("Can only match user-extension pcds with a ReflectionWorld");
+ }
+ Class<?> clazz = null;
+ try {
+ clazz = Class.forName(info.getType().getName(), false, ((ReflectionWorld) world).getClassLoader());
+ } catch (ClassNotFoundException cnfe) {
+ if (info.getType() instanceof ReferenceType) {
+ ReferenceTypeDelegate rtd = ((ReferenceType)info.getType()).getDelegate();
+ if (rtd instanceof ReflectionBasedReferenceTypeDelegate) {
+ clazz = ((ReflectionBasedReferenceTypeDelegate)rtd).getClazz();
+ }
+ }
+ }
+ if (clazz == null) {
+ return FuzzyBoolean.MAYBE;
+ }
+ return FuzzyBoolean.fromBoolean(this.matcher.couldMatchJoinPointsInType(clazz, ((ReflectionFastMatchInfo) info).getMatchingContext()));
+ }
+ throw new IllegalStateException("Can only match user-extension pcds against Reflection FastMatchInfo objects");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#couldMatchKinds()
+ */
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#matchInternal(org.aspectj.weaver.Shadow)
+ */
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ if (shadow instanceof ReflectionShadow) {
+ MatchingContext context = ((ReflectionShadow) shadow).getMatchingContext();
+ org.aspectj.weaver.tools.FuzzyBoolean match = this.matcher.matchesStatically(context);
+ if (match == org.aspectj.weaver.tools.FuzzyBoolean.MAYBE) {
+ return FuzzyBoolean.MAYBE;
+ } else if (match == org.aspectj.weaver.tools.FuzzyBoolean.YES) {
+ return FuzzyBoolean.YES;
+ } else if (match == org.aspectj.weaver.tools.FuzzyBoolean.NO) {
+ return FuzzyBoolean.NO;
+ }
+ }
+ throw new IllegalStateException("Can only match user-extension pcds against Reflection shadows (not BCEL)");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings)
+ */
+ protected void resolveBindings(IScope scope, Bindings bindings) {
+ // no-op
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.ResolvedType,
+ * org.aspectj.weaver.IntMap)
+ */
+ protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#findResidueInternal(org.aspectj.weaver.Shadow,
+ * org.aspectj.weaver.patterns.ExposedState)
+ */
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ if (!this.matcher.mayNeedDynamicTest()) {
+ return Literal.TRUE;
+ } else {
+ // could be more efficient here!
+ matchInternal(shadow);
+ return new MatchingContextBasedTest(this.matcher);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#parameterizeWith(java.util.Map)
+ */
+ public Pointcut parameterizeWith(Map typeVariableMap, World w) {
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
+ */
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new UnsupportedOperationException("can't write custom pointcut designator expressions to stream");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.PatternNode#accept(org.aspectj.weaver.patterns.PatternNodeVisitor, java.lang.Object)
+ */
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ // visitor.visit(this);
+ // no-op?
+ return data;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutExpressionImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutExpressionImpl.java
new file mode 100644
index 000000000..822c78d9a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/PointcutExpressionImpl.java
@@ -0,0 +1,442 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.internal.tools;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
+import org.aspectj.weaver.patterns.AnnotationPointcut;
+import org.aspectj.weaver.patterns.ArgsAnnotationPointcut;
+import org.aspectj.weaver.patterns.ArgsPointcut;
+import org.aspectj.weaver.patterns.CflowPointcut;
+import org.aspectj.weaver.patterns.ExposedState;
+import org.aspectj.weaver.patterns.IfPointcut;
+import org.aspectj.weaver.patterns.NotAnnotationTypePattern;
+import org.aspectj.weaver.patterns.NotPointcut;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
+import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
+import org.aspectj.weaver.patterns.WithinAnnotationPointcut;
+import org.aspectj.weaver.patterns.WithinCodeAnnotationPointcut;
+import org.aspectj.weaver.reflect.ReflectionFastMatchInfo;
+import org.aspectj.weaver.reflect.ReflectionShadow;
+import org.aspectj.weaver.reflect.ReflectionWorld;
+import org.aspectj.weaver.reflect.ShadowMatchImpl;
+import org.aspectj.weaver.tools.DefaultMatchingContext;
+import org.aspectj.weaver.tools.MatchingContext;
+import org.aspectj.weaver.tools.PointcutExpression;
+import org.aspectj.weaver.tools.PointcutParameter;
+import org.aspectj.weaver.tools.ShadowMatch;
+
+/**
+ * Map from weaver.tools interface to internal Pointcut implementation...
+ */
+public class PointcutExpressionImpl implements PointcutExpression {
+
+ private final static boolean MATCH_INFO = false;
+
+ private World world;
+ private Pointcut pointcut;
+ private String expression;
+ private PointcutParameter[] parameters;
+ private MatchingContext matchContext = new DefaultMatchingContext();
+
+ public PointcutExpressionImpl(Pointcut pointcut, String expression, PointcutParameter[] params, World inWorld) {
+ this.pointcut = pointcut;
+ this.expression = expression;
+ this.world = inWorld;
+ this.parameters = params;
+ if (this.parameters == null) {
+ this.parameters = new PointcutParameter[0];
+ }
+ }
+
+ public Pointcut getUnderlyingPointcut() {
+ return this.pointcut;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.tools.PointcutExpression#setMatchingContext(org.aspectj.weaver.tools.MatchingContext)
+ */
+ public void setMatchingContext(MatchingContext aMatchContext) {
+ this.matchContext = aMatchContext;
+ }
+
+ public boolean couldMatchJoinPointsInType(Class aClass) {
+ ResolvedType matchType = world.resolve(aClass.getName());
+ if (matchType.isMissing() && (world instanceof ReflectionWorld)) {
+ // Class is a generated class that cannot be 'looked up' via getResource.
+ // For example a proxy or lambda.
+ // Use the class itself in this case
+ matchType = ((ReflectionWorld)world).resolveUsingClass(aClass);
+ }
+ ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world);
+ boolean couldMatch = pointcut.fastMatch(info).maybeTrue();
+ if (MATCH_INFO) {
+ System.out.println("MATCHINFO: fast match for '" + this.expression + "' against '" + aClass.getName() + "': "
+ + couldMatch);
+ }
+ return couldMatch;
+ }
+
+ public boolean mayNeedDynamicTest() {
+ HasPossibleDynamicContentVisitor visitor = new HasPossibleDynamicContentVisitor();
+ pointcut.traverse(visitor, null);
+ return visitor.hasDynamicContent();
+ }
+
+ private ExposedState getExposedState() {
+ return new ExposedState(parameters.length);
+ }
+
+ public ShadowMatch matchesMethodExecution(Method aMethod) {
+ ShadowMatch match = matchesExecution(aMethod);
+ if (MATCH_INFO && match.maybeMatches()) {
+ System.out.println("MATCHINFO: method execution match on '" + aMethod + "' for '" + this.expression + "': "
+ + (match.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return match;
+ }
+
+ public ShadowMatch matchesConstructorExecution(Constructor aConstructor) {
+ ShadowMatch match = matchesExecution(aConstructor);
+ if (MATCH_INFO && match.maybeMatches()) {
+ System.out.println("MATCHINFO: constructor execution match on '" + aConstructor + "' for '" + this.expression + "': "
+ + (match.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return match;
+ }
+
+ private ShadowMatch matchesExecution(Member aMember) {
+ Shadow s = ReflectionShadow.makeExecutionShadow(world, aMember, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aMember);
+ sm.setWithinCode(null);
+ sm.setWithinType(aMember.getDeclaringClass());
+ return sm;
+ }
+
+ public ShadowMatch matchesStaticInitialization(Class aClass) {
+ Shadow s = ReflectionShadow.makeStaticInitializationShadow(world, aClass, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(null);
+ sm.setWithinCode(null);
+ sm.setWithinType(aClass);
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: static initialization match on '" + aClass.getName() + "' for '" + this.expression
+ + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesAdviceExecution(Method aMethod) {
+ Shadow s = ReflectionShadow.makeAdviceExecutionShadow(world, aMethod, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aMethod);
+ sm.setWithinCode(null);
+ sm.setWithinType(aMethod.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: advice execution match on '" + aMethod + "' for '" + this.expression + "': "
+ + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesInitialization(Constructor aConstructor) {
+ Shadow s = ReflectionShadow.makeInitializationShadow(world, aConstructor, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aConstructor);
+ sm.setWithinCode(null);
+ sm.setWithinType(aConstructor.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: initialization match on '" + aConstructor + "' for '" + this.expression + "': "
+ + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesPreInitialization(Constructor aConstructor) {
+ Shadow s = ReflectionShadow.makePreInitializationShadow(world, aConstructor, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aConstructor);
+ sm.setWithinCode(null);
+ sm.setWithinType(aConstructor.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: preinitialization match on '" + aConstructor + "' for '" + this.expression + "': "
+ + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesMethodCall(Method aMethod, Member withinCode) {
+ Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, withinCode, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aMethod);
+ sm.setWithinCode(withinCode);
+ sm.setWithinType(withinCode.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: method call match on '" + aMethod + "' withinCode='" + withinCode + "' for '"
+ + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesMethodCall(Method aMethod, Class callerType) {
+ Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, callerType, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aMethod);
+ sm.setWithinCode(null);
+ sm.setWithinType(callerType);
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: method call match on '" + aMethod + "' callerType='" + callerType.getName() + "' for '"
+ + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesConstructorCall(Constructor aConstructor, Class callerType) {
+ Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, callerType, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aConstructor);
+ sm.setWithinCode(null);
+ sm.setWithinType(callerType);
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: constructor call match on '" + aConstructor + "' callerType='" + callerType.getName()
+ + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesConstructorCall(Constructor aConstructor, Member withinCode) {
+ Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, withinCode, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aConstructor);
+ sm.setWithinCode(withinCode);
+ sm.setWithinType(withinCode.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: constructor call match on '" + aConstructor + "' withinCode='" + withinCode + "' for '"
+ + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesHandler(Class exceptionType, Class handlingType) {
+ Shadow s = ReflectionShadow.makeHandlerShadow(world, exceptionType, handlingType, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(null);
+ sm.setWithinCode(null);
+ sm.setWithinType(handlingType);
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: handler match on '" + exceptionType.getName() + "' handlingType='" + handlingType
+ + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesHandler(Class exceptionType, Member withinCode) {
+ Shadow s = ReflectionShadow.makeHandlerShadow(world, exceptionType, withinCode, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(null);
+ sm.setWithinCode(withinCode);
+ sm.setWithinType(withinCode.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: handler match on '" + exceptionType.getName() + "' withinCode='" + withinCode
+ + "' for '" + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesFieldGet(Field aField, Class withinType) {
+ Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinType, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aField);
+ sm.setWithinCode(null);
+ sm.setWithinType(withinType);
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: field get match on '" + aField + "' withinType='" + withinType.getName() + "' for '"
+ + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesFieldGet(Field aField, Member withinCode) {
+ Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinCode, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aField);
+ sm.setWithinCode(withinCode);
+ sm.setWithinType(withinCode.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: field get match on '" + aField + "' withinCode='" + withinCode + "' for '"
+ + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesFieldSet(Field aField, Class withinType) {
+ Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinType, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aField);
+ sm.setWithinCode(null);
+ sm.setWithinType(withinType);
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: field set match on '" + aField + "' withinType='" + withinType.getName() + "' for '"
+ + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ public ShadowMatch matchesFieldSet(Field aField, Member withinCode) {
+ Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinCode, this.matchContext);
+ ShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aField);
+ sm.setWithinCode(withinCode);
+ sm.setWithinType(withinCode.getDeclaringClass());
+ if (MATCH_INFO && sm.maybeMatches()) {
+ System.out.println("MATCHINFO: field set match on '" + aField + "' withinCode='" + withinCode + "' for '"
+ + this.expression + "': " + (sm.alwaysMatches() ? "YES" : "MAYBE"));
+ }
+ return sm;
+ }
+
+ private ShadowMatchImpl getShadowMatch(Shadow forShadow) {
+ org.aspectj.util.FuzzyBoolean match = pointcut.match(forShadow);
+ Test residueTest = Literal.TRUE;
+ ExposedState state = getExposedState();
+ if (match.maybeTrue()) {
+ residueTest = pointcut.findResidue(forShadow, state);
+ }
+ ShadowMatchImpl sm = new ShadowMatchImpl(match, residueTest, state, parameters);
+ sm.setMatchingContext(this.matchContext);
+ return sm;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.tools.PointcutExpression#getPointcutExpression()
+ */
+ public String getPointcutExpression() {
+ return expression;
+ }
+
+ private static class HasPossibleDynamicContentVisitor extends AbstractPatternNodeVisitor {
+ private boolean hasDynamicContent = false;
+
+ public boolean hasDynamicContent() {
+ return hasDynamicContent;
+ }
+
+ @Override
+ public Object visit(WithinAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(WithinCodeAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(AnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(ArgsAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(ArgsPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(CflowPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(IfPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(NotAnnotationTypePattern node, Object data) {
+ return node.getNegatedPattern().accept(this, data);
+ }
+
+ @Override
+ public Object visit(NotPointcut node, Object data) {
+ return node.getNegatedPointcut().accept(this, data);
+ }
+
+ @Override
+ public Object visit(ThisOrTargetAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(ThisOrTargetPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ }
+
+ public static class Handler implements Member {
+
+ private Class decClass;
+ private Class exType;
+
+ public Handler(Class decClass, Class exType) {
+ this.decClass = decClass;
+ this.exType = exType;
+ }
+
+ public int getModifiers() {
+ return 0;
+ }
+
+ public Class getDeclaringClass() {
+ return decClass;
+ }
+
+ public String getName() {
+ return null;
+ }
+
+ public Class getHandledExceptionType() {
+ return exType;
+ }
+
+ public boolean isSynthetic() {
+ return false;
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/StandardPointcutExpressionImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/StandardPointcutExpressionImpl.java
new file mode 100644
index 000000000..a767ed18b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/StandardPointcutExpressionImpl.java
@@ -0,0 +1,385 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.internal.tools;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
+import org.aspectj.weaver.patterns.AnnotationPointcut;
+import org.aspectj.weaver.patterns.ArgsAnnotationPointcut;
+import org.aspectj.weaver.patterns.ArgsPointcut;
+import org.aspectj.weaver.patterns.CflowPointcut;
+import org.aspectj.weaver.patterns.ExposedState;
+import org.aspectj.weaver.patterns.IfPointcut;
+import org.aspectj.weaver.patterns.NotAnnotationTypePattern;
+import org.aspectj.weaver.patterns.NotPointcut;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
+import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
+import org.aspectj.weaver.patterns.WithinAnnotationPointcut;
+import org.aspectj.weaver.patterns.WithinCodeAnnotationPointcut;
+import org.aspectj.weaver.reflect.ReflectionFastMatchInfo;
+import org.aspectj.weaver.reflect.StandardShadow;
+import org.aspectj.weaver.reflect.StandardShadowMatchImpl;
+import org.aspectj.weaver.tools.DefaultMatchingContext;
+import org.aspectj.weaver.tools.MatchingContext;
+import org.aspectj.weaver.tools.PointcutParameter;
+import org.aspectj.weaver.tools.ShadowMatch;
+import org.aspectj.weaver.tools.StandardPointcutExpression;
+
+/**
+ * Map from weaver.tools interface to internal Pointcut implementation...
+ */
+public class StandardPointcutExpressionImpl implements StandardPointcutExpression {
+
+ private World world;
+ private Pointcut pointcut;
+ private String expression;
+ private PointcutParameter[] parameters;
+ private MatchingContext matchContext = new DefaultMatchingContext();
+
+ public StandardPointcutExpressionImpl(Pointcut pointcut, String expression, PointcutParameter[] params, World inWorld) {
+ this.pointcut = pointcut;
+ this.expression = expression;
+ this.world = inWorld;
+ this.parameters = params;
+ if (this.parameters == null) {
+ this.parameters = new PointcutParameter[0];
+ }
+ }
+
+ public Pointcut getUnderlyingPointcut() {
+ return this.pointcut;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.tools.PointcutExpression#setMatchingContext(org.aspectj.weaver.tools.MatchingContext)
+ */
+ public void setMatchingContext(MatchingContext aMatchContext) {
+ this.matchContext = aMatchContext;
+ }
+
+ public boolean couldMatchJoinPointsInType(Class aClass) {
+ ResolvedType matchType = world.resolve(aClass.getName());
+ ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world);
+ return pointcut.fastMatch(info).maybeTrue();
+ }
+
+ public boolean mayNeedDynamicTest() {
+ HasPossibleDynamicContentVisitor visitor = new HasPossibleDynamicContentVisitor();
+ pointcut.traverse(visitor, null);
+ return visitor.hasDynamicContent();
+ }
+
+ private ExposedState getExposedState() {
+ return new ExposedState(parameters.length);
+ }
+
+ // public ShadowMatch matchesMethodExecution(Method aMethod) {
+ // return matchesExecution(aMethod);
+ // }
+
+ public ShadowMatch matchesMethodExecution(ResolvedMember aMethod) {
+ return matchesExecution(aMethod);
+ }
+
+ public ShadowMatch matchesConstructorExecution(Constructor aConstructor) {
+ return null;
+ // return matchesExecution(aConstructor);
+ }
+
+ // private ShadowMatch matchesExecution(Member aMember) {
+ // Shadow s = ReflectionShadow.makeExecutionShadow(world, aMember, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aMember);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(aMember.getDeclaringClass());
+ // return sm;
+ // }
+
+ private ShadowMatch matchesExecution(ResolvedMember aMember) {
+ Shadow s = StandardShadow.makeExecutionShadow(world, aMember, this.matchContext);
+ StandardShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aMember);
+ sm.setWithinCode(null);
+ sm.setWithinType((ResolvedType) aMember.getDeclaringType());
+ return sm;
+ }
+
+ // public ShadowMatch matchesStaticInitialization(Class aClass) {
+ // Shadow s = ReflectionShadow.makeStaticInitializationShadow(world, aClass, this.matchContext);
+ // StandardShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(null);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(aClass);
+ // return sm;
+ // }
+
+ public ShadowMatch matchesStaticInitialization(ResolvedType aType) {
+ Shadow s = StandardShadow.makeStaticInitializationShadow(world, aType, this.matchContext);
+ StandardShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(null);
+ sm.setWithinCode(null);
+ sm.setWithinType(aType);
+ return sm;
+ }
+
+ // public ShadowMatch matchesAdviceExecution(Method aMethod) {
+ // Shadow s = ReflectionShadow.makeAdviceExecutionShadow(world, aMethod, this.matchContext);
+ // StandardShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aMethod);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(aMethod.getDeclaringClass());
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesInitialization(Constructor aConstructor) {
+ // Shadow s = ReflectionShadow.makeInitializationShadow(world, aConstructor, this.matchContext);
+ // StandardShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aConstructor);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(aConstructor.getDeclaringClass());
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesPreInitialization(Constructor aConstructor) {
+ // Shadow s = ReflectionShadow.makePreInitializationShadow(world, aConstructor, this.matchContext);
+ // StandardShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aConstructor);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(aConstructor.getDeclaringClass());
+ // return sm;
+ // }
+ //
+ public ShadowMatch matchesMethodCall(ResolvedMember aMethod, ResolvedMember withinCode) {
+ Shadow s = StandardShadow.makeCallShadow(world, aMethod, withinCode, this.matchContext);
+ StandardShadowMatchImpl sm = getShadowMatch(s);
+ sm.setSubject(aMethod);
+ sm.setWithinCode(withinCode);
+ sm.setWithinType((ResolvedType) withinCode.getDeclaringType());
+ return sm;
+ }
+
+ //
+ // public ShadowMatch matchesMethodCall(Method aMethod, Class callerType) {
+ // Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, callerType, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aMethod);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(callerType);
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesConstructorCall(Constructor aConstructor, Class callerType) {
+ // Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, callerType, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aConstructor);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(callerType);
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesConstructorCall(Constructor aConstructor, Member withinCode) {
+ // Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, withinCode, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aConstructor);
+ // sm.setWithinCode(withinCode);
+ // sm.setWithinType(withinCode.getDeclaringClass());
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesHandler(Class exceptionType, Class handlingType) {
+ // Shadow s = ReflectionShadow.makeHandlerShadow(world, exceptionType, handlingType, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(null);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(handlingType);
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesHandler(Class exceptionType, Member withinCode) {
+ // Shadow s = ReflectionShadow.makeHandlerShadow(world, exceptionType, withinCode, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(null);
+ // sm.setWithinCode(withinCode);
+ // sm.setWithinType(withinCode.getDeclaringClass());
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesFieldGet(Field aField, Class withinType) {
+ // Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinType, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aField);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(withinType);
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesFieldGet(Field aField, Member withinCode) {
+ // Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinCode, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aField);
+ // sm.setWithinCode(withinCode);
+ // sm.setWithinType(withinCode.getDeclaringClass());
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesFieldSet(Field aField, Class withinType) {
+ // Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinType, this.matchContext);
+ // ShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aField);
+ // sm.setWithinCode(null);
+ // sm.setWithinType(withinType);
+ // return sm;
+ // }
+ //
+ // public ShadowMatch matchesFieldSet(Field aField, Member withinCode) {
+ // Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinCode, this.matchContext);
+ // StandardShadowMatchImpl sm = getShadowMatch(s);
+ // sm.setSubject(aField);
+ // sm.setWithinCode(withinCode);
+ // sm.setWithinType(withinCode.getDeclaringClass());
+ // return sm;
+ // }
+
+ private StandardShadowMatchImpl getShadowMatch(Shadow forShadow) {
+ org.aspectj.util.FuzzyBoolean match = pointcut.match(forShadow);
+ Test residueTest = Literal.TRUE;
+ ExposedState state = getExposedState();
+ if (match.maybeTrue()) {
+ residueTest = pointcut.findResidue(forShadow, state);
+ }
+ StandardShadowMatchImpl sm = new StandardShadowMatchImpl(match, residueTest, state, parameters);
+ sm.setMatchingContext(this.matchContext);
+ return sm;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.tools.PointcutExpression#getPointcutExpression()
+ */
+ public String getPointcutExpression() {
+ return expression;
+ }
+
+ private static class HasPossibleDynamicContentVisitor extends AbstractPatternNodeVisitor {
+ private boolean hasDynamicContent = false;
+
+ public boolean hasDynamicContent() {
+ return hasDynamicContent;
+ }
+
+ @Override
+ public Object visit(WithinAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(WithinCodeAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(AnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(ArgsAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(ArgsPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(CflowPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(IfPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(NotAnnotationTypePattern node, Object data) {
+ return node.getNegatedPattern().accept(this, data);
+ }
+
+ @Override
+ public Object visit(NotPointcut node, Object data) {
+ return node.getNegatedPointcut().accept(this, data);
+ }
+
+ @Override
+ public Object visit(ThisOrTargetAnnotationPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ @Override
+ public Object visit(ThisOrTargetPointcut node, Object data) {
+ hasDynamicContent = true;
+ return null;
+ }
+
+ }
+
+ public static class Handler implements Member {
+
+ private Class decClass;
+ private Class exType;
+
+ public Handler(Class decClass, Class exType) {
+ this.decClass = decClass;
+ this.exType = exType;
+ }
+
+ public int getModifiers() {
+ return 0;
+ }
+
+ public Class getDeclaringClass() {
+ return decClass;
+ }
+
+ public String getName() {
+ return null;
+ }
+
+ public Class getHandledExceptionType() {
+ return exType;
+ }
+
+ public boolean isSynthetic() {
+ return false;
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/TypePatternMatcherImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/TypePatternMatcherImpl.java
new file mode 100644
index 000000000..8ce4bceea
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/internal/tools/TypePatternMatcherImpl.java
@@ -0,0 +1,34 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.internal.tools;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.patterns.TypePattern;
+import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegateFactory;
+import org.aspectj.weaver.tools.TypePatternMatcher;
+
+public class TypePatternMatcherImpl implements TypePatternMatcher {
+
+ private final TypePattern pattern;
+ private final World world;
+
+ public TypePatternMatcherImpl(TypePattern pattern, World world) {
+ this.pattern = pattern;
+ this.world = world;
+ }
+
+ public boolean matches(Class aClass) {
+ ResolvedType rt =
+ ReflectionBasedReferenceTypeDelegateFactory.resolveTypeInWorld(aClass,world);
+ return pattern.matchesStatically(rt);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java
new file mode 100644
index 000000000..34efee3ee
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java
@@ -0,0 +1,253 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.patterns.Pointcut.MatchesNothingPointcut;
+
+/**
+ * @author colyer
+ *
+ */
+public abstract class AbstractPatternNodeVisitor implements PatternNodeVisitor {
+
+ public Object visit(AnyTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(NoTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(EllipsisTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(AnyWithAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(AnyAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(EllipsisAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(AndAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(AndPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(AndTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(AnnotationPatternList node, Object data) {
+ return node;
+ }
+
+ public Object visit(AnnotationPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(ArgsAnnotationPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(ArgsPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(BindingAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(BindingTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(CflowPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(ConcreteCflowPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(DeclareAnnotation node, Object data) {
+ return node;
+ }
+
+ public Object visit(DeclareErrorOrWarning node, Object data) {
+ return node;
+ }
+
+ public Object visit(DeclareParents node, Object data) {
+ return node;
+ }
+
+ public Object visit(DeclarePrecedence node, Object data) {
+ return node;
+ }
+
+ public Object visit(DeclareSoft node, Object data) {
+ return node;
+ }
+
+ public Object visit(ExactAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(ExactTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(HandlerPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(IfPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(KindedPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(ModifiersPattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(NamePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(NotAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(NotPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(NotTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(OrAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(OrPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(OrTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(PerCflow node, Object data) {
+ return node;
+ }
+
+ public Object visit(PerFromSuper node, Object data) {
+ return node;
+ }
+
+ public Object visit(PerObject node, Object data) {
+ return node;
+ }
+
+ public Object visit(PerSingleton node, Object data) {
+ return node;
+ }
+
+ public Object visit(PerTypeWithin node, Object data) {
+ return node;
+ }
+
+ public Object visit(PatternNode node, Object data) {
+ return node;
+ }
+
+ public Object visit(ReferencePointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(SignaturePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(ThisOrTargetAnnotationPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(ThisOrTargetPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(ThrowsPattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(TypePatternList node, Object data) {
+ return node;
+ }
+
+ public Object visit(WildAnnotationTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(WildTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(WithinAnnotationPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(WithinCodeAnnotationPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(WithinPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(WithincodePointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(MatchesNothingPointcut node, Object data) {
+ return node;
+ }
+
+ public Object visit(TypeVariablePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(TypeVariablePatternList node, Object data) {
+ return node;
+ }
+
+ public Object visit(HasMemberTypePattern node, Object data) {
+ return node;
+ }
+
+ public Object visit(TypeCategoryTypePattern node, Object data) {
+ return node;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractSignaturePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractSignaturePattern.java
new file mode 100644
index 000000000..cb87ee431
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AbstractSignaturePattern.java
@@ -0,0 +1,79 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.VersionedDataInputStream;
+
+/**
+ * Implements common functions to be used across ISignaturePatterns.
+ *
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public abstract class AbstractSignaturePattern implements ISignaturePattern {
+
+ protected void writePlaceholderLocation(CompressingDataOutputStream s) throws IOException {
+ s.writeInt(0);
+ s.writeInt(0);
+ }
+
+ public static ISignaturePattern readCompoundSignaturePattern(VersionedDataInputStream s, ISourceContext context)
+ throws IOException {
+ byte key = s.readByte();
+ switch (key) {
+ case PATTERN:
+ return SignaturePattern.read(s, context);
+ case AND:
+ return AndSignaturePattern.readAndSignaturePattern(s, context);
+ case OR:
+ return OrSignaturePattern.readOrSignaturePattern(s, context);
+ case NOT:
+ return NotSignaturePattern.readNotSignaturePattern(s, context);
+ default:
+ throw new BCException("unknown SignatureTypePattern kind: " + key);
+ }
+ }
+
+ public static void writeCompoundSignaturePattern(CompressingDataOutputStream s, ISignaturePattern sigPattern)
+ throws IOException {
+ if (sigPattern instanceof SignaturePattern) {
+ s.writeByte(PATTERN);
+ ((SignaturePattern) sigPattern).write(s);
+ } else if (sigPattern instanceof AndSignaturePattern) {
+ AndSignaturePattern andSignaturePattern = (AndSignaturePattern) sigPattern;
+ s.writeByte(AND);
+ writeCompoundSignaturePattern(s, andSignaturePattern.getLeft());
+ writeCompoundSignaturePattern(s, andSignaturePattern.getRight());
+ s.writeInt(0);
+ s.writeInt(0); // TODO positions not yet set properly
+ } else if (sigPattern instanceof OrSignaturePattern) {
+ OrSignaturePattern orSignaturePattern = (OrSignaturePattern) sigPattern;
+ s.writeByte(OR);
+ writeCompoundSignaturePattern(s, orSignaturePattern.getLeft());
+ writeCompoundSignaturePattern(s, orSignaturePattern.getRight());
+ s.writeInt(0);
+ s.writeInt(0); // TODO positions not yet set properly
+ } else {
+ // negated
+ NotSignaturePattern notSignaturePattern = (NotSignaturePattern) sigPattern;
+ s.writeByte(NOT);
+ writeCompoundSignaturePattern(s, notSignaturePattern.getNegated());
+ s.writeInt(0);
+ s.writeInt(0); // TODO positions not yet set properly
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndAnnotationTypePattern.java
new file mode 100644
index 000000000..c14f36025
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndAnnotationTypePattern.java
@@ -0,0 +1,142 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+
+/**
+ * @author colyer
+ *
+ * TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code
+ * Templates
+ */
+public class AndAnnotationTypePattern extends AnnotationTypePattern {
+
+ private AnnotationTypePattern left;
+ private AnnotationTypePattern right;
+
+ public AndAnnotationTypePattern(AnnotationTypePattern left, AnnotationTypePattern right) {
+ this.left = left;
+ this.right = right;
+ setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
+ }
+
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ return left.matches(annotated).and(right.matches(annotated));
+ }
+
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ return left.matches(annotated, parameterAnnotations).and(right.matches(annotated, parameterAnnotations));
+ }
+
+ public void resolve(World world) {
+ left.resolve(world);
+ right.resolve(world);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.AnnotationTypePattern#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings, boolean)
+ */
+ public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ left = left.resolveBindings(scope, bindings, allowBinding);
+ right = right.resolveBindings(scope, bindings, allowBinding);
+ return this;
+ }
+
+ public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ AnnotationTypePattern newLeft = left.parameterizeWith(typeVariableMap, w);
+ AnnotationTypePattern newRight = right.parameterizeWith(typeVariableMap, w);
+ AndAnnotationTypePattern ret = new AndAnnotationTypePattern(newLeft, newRight);
+ ret.copyLocationFrom(this);
+ if (this.isForParameterAnnotationMatch()) {
+ ret.setForParameterAnnotationMatch();
+ }
+ return ret;
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationTypePattern p = new AndAnnotationTypePattern(AnnotationTypePattern.read(s, context), AnnotationTypePattern.read(
+ s, context));
+ p.readLocation(context, s);
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) {
+ if (s.readBoolean()) {
+ p.setForParameterAnnotationMatch();
+ }
+ }
+ return p;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.AND);
+ left.write(s);
+ right.write(s);
+ writeLocation(s);
+ s.writeBoolean(isForParameterAnnotationMatch());
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AndAnnotationTypePattern)) {
+ return false;
+ }
+ AndAnnotationTypePattern other = (AndAnnotationTypePattern) obj;
+ return (left.equals(other.left) && right.equals(other.right) && left.isForParameterAnnotationMatch() == right
+ .isForParameterAnnotationMatch());
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = result * 37 + left.hashCode();
+ result = result * 37 + right.hashCode();
+ result = result * 37 + (isForParameterAnnotationMatch() ? 0 : 1);
+ return result;
+ }
+
+ public String toString() {
+ return left.toString() + " " + right.toString();
+ }
+
+ public AnnotationTypePattern getLeft() {
+ return left;
+ }
+
+ public AnnotationTypePattern getRight() {
+ return right;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ left.traverse(visitor, ret);
+ right.traverse(visitor, ret);
+ return ret;
+ }
+
+ public void setForParameterAnnotationMatch() {
+ left.setForParameterAnnotationMatch();
+ right.setForParameterAnnotationMatch();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndPointcut.java
new file mode 100644
index 000000000..20fc74734
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndPointcut.java
@@ -0,0 +1,138 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Test;
+
+public class AndPointcut extends Pointcut {
+ Pointcut left, right; // exposed for testing
+
+ private int couldMatchKinds;
+
+ public AndPointcut(Pointcut left, Pointcut right) {
+ super();
+ this.left = left;
+ this.right = right;
+ this.pointcutKind = AND;
+ setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
+ couldMatchKinds = left.couldMatchKinds() & right.couldMatchKinds();
+ }
+
+ public int couldMatchKinds() {
+ return couldMatchKinds;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ FuzzyBoolean leftMatch = left.fastMatch(type);
+ if (leftMatch.alwaysFalse()) {
+ return leftMatch;
+ }
+ return leftMatch.and(right.fastMatch(type));
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ FuzzyBoolean leftMatch = left.match(shadow);
+ if (leftMatch.alwaysFalse()) {
+ return leftMatch;
+ }
+ return leftMatch.and(right.match(shadow));
+ }
+
+ public String toString() {
+ return "(" + left.toString() + " && " + right.toString() + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof AndPointcut)) {
+ return false;
+ }
+ AndPointcut o = (AndPointcut) other;
+ return o.left.equals(left) && o.right.equals(right);
+ }
+
+ public int hashCode() {
+ int result = 19;
+ result = 37 * result + left.hashCode();
+ result = 37 * result + right.hashCode();
+ return result;
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ left.resolveBindings(scope, bindings);
+ right.resolveBindings(scope, bindings);
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.AND);
+ left.write(s);
+ right.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AndPointcut ret = new AndPointcut(Pointcut.read(s, context), Pointcut.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return Test.makeAnd(left.findResidue(shadow, state), right.findResidue(shadow, state));
+ }
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ AndPointcut ret = new AndPointcut(left.concretize(inAspect, declaringType, bindings), right.concretize(inAspect,
+ declaringType, bindings));
+ ret.copyLocationFrom(this);
+ ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
+ return ret;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ AndPointcut ret = new AndPointcut(left.parameterizeWith(typeVariableMap, w), right.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
+ return ret;
+ }
+
+ public Pointcut getLeft() {
+ return left;
+ }
+
+ public Pointcut getRight() {
+ return right;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ left.traverse(visitor, ret);
+ right.traverse(visitor, ret);
+ return ret;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndSignaturePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndSignaturePattern.java
new file mode 100644
index 000000000..c05995377
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndSignaturePattern.java
@@ -0,0 +1,104 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * Represents the AND of two other signature patterns.
+ *
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public class AndSignaturePattern extends AbstractSignaturePattern {
+
+ private ISignaturePattern leftSp;
+ private ISignaturePattern rightSp;
+ private List<ExactTypePattern> exactDeclaringTypes;
+
+ public AndSignaturePattern(ISignaturePattern leftSp, ISignaturePattern rightSp) {
+ this.leftSp = leftSp;
+ this.rightSp = rightSp;
+ }
+
+ public boolean couldEverMatch(ResolvedType type) {
+ return leftSp.couldEverMatch(type) || rightSp.couldEverMatch(type);
+ }
+
+ public List<ExactTypePattern> getExactDeclaringTypes() {
+ if (exactDeclaringTypes == null) {
+ exactDeclaringTypes = new ArrayList<ExactTypePattern>();
+ exactDeclaringTypes.addAll(leftSp.getExactDeclaringTypes());
+ exactDeclaringTypes.addAll(rightSp.getExactDeclaringTypes());
+ }
+ return exactDeclaringTypes;
+ }
+
+ public boolean isMatchOnAnyName() {
+ return leftSp.isMatchOnAnyName() || rightSp.isMatchOnAnyName();
+ }
+
+ public boolean isStarAnnotation() {
+ return leftSp.isStarAnnotation() || rightSp.isStarAnnotation();
+ }
+
+ public boolean matches(Member member, World world, boolean b) {
+ return (leftSp.matches(member, world, b)) && (rightSp.matches(member, world, b));
+ }
+
+ public ISignaturePattern parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World world) {
+ return new AndSignaturePattern(leftSp.parameterizeWith(typeVariableBindingMap, world), rightSp.parameterizeWith(
+ typeVariableBindingMap, world));
+ }
+
+ public ISignaturePattern resolveBindings(IScope scope, Bindings bindings) {
+ // Whilst the real SignaturePattern returns 'this' we are safe to return 'this' here rather than build a new
+ // AndSignaturePattern
+ leftSp.resolveBindings(scope, bindings);
+ rightSp.resolveBindings(scope, bindings);
+ return this;
+ }
+
+ public static ISignaturePattern readAndSignaturePattern(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AndSignaturePattern ret = new AndSignaturePattern(readCompoundSignaturePattern(s, context), readCompoundSignaturePattern(s,
+ context));
+ s.readInt();
+ s.readInt();
+ // ret.readLocation(context, s); // TODO output position currently useless so dont need to do this
+ return ret;
+ }
+
+ public ISignaturePattern getLeft() {
+ return leftSp;
+ }
+
+ public ISignaturePattern getRight() {
+ return rightSp;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(leftSp.toString()).append(" && ").append(rightSp.toString());
+ return sb.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndTypePattern.java
new file mode 100644
index 000000000..781a5881a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AndTypePattern.java
@@ -0,0 +1,198 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * left && right
+ *
+ * <p>
+ * any binding to formals is explicitly forbidden for any composite by the language
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public class AndTypePattern extends TypePattern {
+ private TypePattern left, right;
+
+ public AndTypePattern(TypePattern left, TypePattern right) {
+ super(false, false); // ?? we override all methods that care about includeSubtypes
+ this.left = left;
+ this.right = right;
+ setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
+ }
+
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ return true; // don't dive into ands yet....
+ }
+
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ return left.matchesInstanceof(type).and(right.matchesInstanceof(type));
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ // ??? if these had side-effects, this sort-circuit could be a mistake
+ return left.matchesExactly(type) && right.matchesExactly(type);
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ return left.matchesExactly(type, annotatedType) && right.matchesExactly(type, annotatedType);
+ }
+
+ @Override
+ public boolean matchesStatically(ResolvedType type) {
+ return left.matchesStatically(type) && right.matchesStatically(type);
+ }
+
+ @Override
+ public void setIsVarArgs(boolean isVarArgs) {
+ this.isVarArgs = isVarArgs;
+ left.setIsVarArgs(isVarArgs);
+ right.setIsVarArgs(isVarArgs);
+ }
+
+ @Override
+ public void setAnnotationTypePattern(AnnotationTypePattern annPatt) {
+ if (annPatt == AnnotationTypePattern.ANY) {
+ return;
+ }
+ if (left.annotationPattern == AnnotationTypePattern.ANY) {
+ left.setAnnotationTypePattern(annPatt);
+ } else {
+ left.setAnnotationTypePattern(new AndAnnotationTypePattern(left.annotationPattern, annPatt));
+ }
+ if (right.annotationPattern == AnnotationTypePattern.ANY) {
+ right.setAnnotationTypePattern(annPatt);
+ } else {
+ right.setAnnotationTypePattern(new AndAnnotationTypePattern(right.annotationPattern, annPatt));
+ }
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(TypePattern.AND);
+ left.write(s);
+ right.write(s);
+ writeLocation(s);
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AndTypePattern ret = new AndTypePattern(TypePattern.read(s, context), TypePattern.read(s, context));
+ ret.readLocation(context, s);
+ if (ret.left.isVarArgs && ret.right.isVarArgs) {
+ ret.isVarArgs = true;
+ }
+ return ret;
+ }
+
+ @Override
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ if (requireExactType) {
+ return notExactType(scope);
+ }
+ left = left.resolveBindings(scope, bindings, false, false);
+ right = right.resolveBindings(scope, bindings, false, false);
+ return this;
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ TypePattern newLeft = left.parameterizeWith(typeVariableMap, w);
+ TypePattern newRight = right.parameterizeWith(typeVariableMap, w);
+ AndTypePattern ret = new AndTypePattern(newLeft, newRight);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buff = new StringBuffer();
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append('(');
+ buff.append(annotationPattern.toString());
+ buff.append(' ');
+ }
+ buff.append('(');
+ buff.append(left.toString());
+ buff.append(" && ");
+ buff.append(right.toString());
+ buff.append(')');
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append(')');
+ }
+ return buff.toString();
+ }
+
+ public TypePattern getLeft() {
+ return left;
+ }
+
+ public TypePattern getRight() {
+ return right;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AndTypePattern)) {
+ return false;
+ }
+ AndTypePattern atp = (AndTypePattern) obj;
+ return left.equals(atp.left) && right.equals(atp.right);
+ }
+
+ @Override
+ public boolean isStarAnnotation() {
+ return left.isStarAnnotation() && right.isStarAnnotation();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ int ret = 17;
+ ret = ret + 37 * left.hashCode();
+ ret = ret + 37 * right.hashCode();
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ left.traverse(visitor, ret);
+ right.traverse(visitor, ret);
+ return ret;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPatternList.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPatternList.java
new file mode 100644
index 000000000..0b93b48d1
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPatternList.java
@@ -0,0 +1,215 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * @author Adrian Colyer
+ */
+public class AnnotationPatternList extends PatternNode {
+
+ private AnnotationTypePattern[] typePatterns;
+ int ellipsisCount = 0;
+
+ public static final AnnotationPatternList EMPTY = new AnnotationPatternList(new AnnotationTypePattern[] {});
+
+ public static final AnnotationPatternList ANY = new AnnotationPatternList(
+ new AnnotationTypePattern[] { AnnotationTypePattern.ELLIPSIS });
+
+ public AnnotationPatternList() {
+ typePatterns = new AnnotationTypePattern[0];
+ ellipsisCount = 0;
+ }
+
+ public AnnotationPatternList(AnnotationTypePattern[] arguments) {
+ this.typePatterns = arguments;
+ for (int i = 0; i < arguments.length; i++) {
+ if (arguments[i] == AnnotationTypePattern.ELLIPSIS) {
+ ellipsisCount++;
+ }
+ }
+ }
+
+ public AnnotationPatternList(List<AnnotationTypePattern> l) {
+ this((AnnotationTypePattern[]) l.toArray(new AnnotationTypePattern[l.size()]));
+ }
+
+ protected AnnotationTypePattern[] getAnnotationPatterns() {
+ return typePatterns;
+ }
+
+ public AnnotationPatternList parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ AnnotationTypePattern[] parameterizedPatterns = new AnnotationTypePattern[this.typePatterns.length];
+ for (int i = 0; i < parameterizedPatterns.length; i++) {
+ parameterizedPatterns[i] = this.typePatterns[i].parameterizeWith(typeVariableMap, w);
+ }
+ AnnotationPatternList ret = new AnnotationPatternList(parameterizedPatterns);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public void resolve(World inWorld) {
+ for (int i = 0; i < typePatterns.length; i++) {
+ typePatterns[i].resolve(inWorld);
+ }
+ }
+
+ public FuzzyBoolean matches(ResolvedType[] someArgs) {
+ // do some quick length tests first
+ int numArgsMatchedByEllipsis = (someArgs.length + ellipsisCount) - typePatterns.length;
+ if (numArgsMatchedByEllipsis < 0) {
+ return FuzzyBoolean.NO;
+ }
+ if ((numArgsMatchedByEllipsis > 0) && (ellipsisCount == 0)) {
+ return FuzzyBoolean.NO;
+ }
+ // now work through the args and the patterns, skipping at ellipsis
+ FuzzyBoolean ret = FuzzyBoolean.YES;
+ int argsIndex = 0;
+ for (int i = 0; i < typePatterns.length; i++) {
+ if (typePatterns[i] == AnnotationTypePattern.ELLIPSIS) {
+ // match ellipsisMatchCount args
+ argsIndex += numArgsMatchedByEllipsis;
+ } else if (typePatterns[i] == AnnotationTypePattern.ANY) {
+ argsIndex++;
+ } else {
+ // match the argument type at argsIndex with the ExactAnnotationTypePattern
+ // we know it is exact because nothing else is allowed in args
+ if (someArgs[argsIndex].isPrimitiveType()) {
+ return FuzzyBoolean.NO; // can never match
+ }
+ ExactAnnotationTypePattern ap = (ExactAnnotationTypePattern) typePatterns[i];
+ FuzzyBoolean matches = ap.matchesRuntimeType(someArgs[argsIndex]);
+ if (matches == FuzzyBoolean.NO) {
+ return FuzzyBoolean.MAYBE; // could still match at runtime
+ } else {
+ argsIndex++;
+ ret = ret.and(matches);
+ }
+ }
+ }
+ return ret;
+ }
+
+ public int size() {
+ return typePatterns.length;
+ }
+
+ public AnnotationTypePattern get(int index) {
+ return typePatterns[index];
+ }
+
+ public AnnotationPatternList resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ for (int i = 0; i < typePatterns.length; i++) {
+ AnnotationTypePattern p = typePatterns[i];
+ if (p != null) {
+ typePatterns[i] = typePatterns[i].resolveBindings(scope, bindings, allowBinding);
+ }
+ }
+ return this;
+ }
+
+ public AnnotationPatternList resolveReferences(IntMap bindings) {
+ int len = typePatterns.length;
+ AnnotationTypePattern[] ret = new AnnotationTypePattern[len];
+ for (int i = 0; i < len; i++) {
+ ret[i] = typePatterns[i].remapAdviceFormals(bindings);
+ }
+ return new AnnotationPatternList(ret);
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("(");
+ for (int i = 0, len = typePatterns.length; i < len; i++) {
+ AnnotationTypePattern type = typePatterns[i];
+ if (i > 0) {
+ buf.append(", ");
+ }
+ if (type == AnnotationTypePattern.ELLIPSIS) {
+ buf.append("..");
+ } else {
+ String annPatt = type.toString();
+ buf.append(annPatt.startsWith("@") ? annPatt.substring(1) : annPatt);
+ }
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof AnnotationPatternList)) {
+ return false;
+ }
+ AnnotationPatternList o = (AnnotationPatternList) other;
+ int len = o.typePatterns.length;
+ if (len != this.typePatterns.length) {
+ return false;
+ }
+ for (int i = 0; i < len; i++) {
+ if (!this.typePatterns[i].equals(o.typePatterns[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ int result = 41;
+ for (int i = 0, len = typePatterns.length; i < len; i++) {
+ result = 37 * result + typePatterns[i].hashCode();
+ }
+ return result;
+ }
+
+ public static AnnotationPatternList read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ short len = s.readShort();
+ AnnotationTypePattern[] arguments = new AnnotationTypePattern[len];
+ for (int i = 0; i < len; i++) {
+ arguments[i] = AnnotationTypePattern.read(s, context);
+ }
+ AnnotationPatternList ret = new AnnotationPatternList(arguments);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeShort(typePatterns.length);
+ for (int i = 0; i < typePatterns.length; i++) {
+ typePatterns[i].write(s);
+ }
+ writeLocation(s);
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ for (int i = 0; i < typePatterns.length; i++) {
+ typePatterns[i].traverse(visitor, ret);
+ }
+ return ret;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPointcut.java
new file mode 100644
index 000000000..e829d3772
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationPointcut.java
@@ -0,0 +1,339 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ConcreteTypeMunger;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.NameMangler;
+import org.aspectj.weaver.NewFieldTypeMunger;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * (at)Annotation((at)Foo) or (at)Annotation(foo)<br>
+ * <p>
+ * Matches any join point where the subject of the join point has an annotation matching the annotationTypePattern:
+ *
+ * <br>
+ * Join Point Kind - Subject <br>
+ * ================================ <br>
+ * method call - the target method <br>
+ * method execution - the method <br>
+ * constructor call - the constructor <br>
+ * constructor execution - the constructor <br>
+ * get - the target field <br>
+ * set - the target field <br>
+ * adviceexecution - the advice <br>
+ * initialization - the constructor <br>
+ * preinitialization - the constructor <br>
+ * staticinitialization - the type being initialized <br>
+ * handler - the declared type of the handled exception <br>
+ */
+public class AnnotationPointcut extends NameBindingPointcut {
+
+ private ExactAnnotationTypePattern annotationTypePattern;
+ private String declarationText;
+
+ public AnnotationPointcut(ExactAnnotationTypePattern type) {
+ super();
+ this.annotationTypePattern = type;
+ this.pointcutKind = Pointcut.ANNOTATION;
+ buildDeclarationText();
+ }
+
+ public AnnotationPointcut(ExactAnnotationTypePattern type, ShadowMunger munger) {
+ this(type);
+ buildDeclarationText();
+ }
+
+ public ExactAnnotationTypePattern getAnnotationTypePattern() {
+ return annotationTypePattern;
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ AnnotationPointcut ret = new AnnotationPointcut((ExactAnnotationTypePattern) annotationTypePattern.parameterizeWith(
+ typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
+ */
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ if (info.getKind() == Shadow.StaticInitialization) {
+ return annotationTypePattern.fastMatches(info.getType());
+ } else {
+ return FuzzyBoolean.MAYBE;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
+ */
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ AnnotatedElement toMatchAgainst = null;
+ Member member = shadow.getSignature();
+ ResolvedMember rMember = member.resolve(shadow.getIWorld());
+
+ if (rMember == null) {
+ if (member.getName().startsWith(NameMangler.PREFIX)) {
+ return FuzzyBoolean.NO;
+ }
+ shadow.getIWorld().getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
+ return FuzzyBoolean.NO;
+ }
+
+ Shadow.Kind kind = shadow.getKind();
+ if (kind == Shadow.StaticInitialization) {
+ toMatchAgainst = rMember.getDeclaringType().resolve(shadow.getIWorld());
+ } else if ((kind == Shadow.ExceptionHandler)) {
+ toMatchAgainst = rMember.getParameterTypes()[0].resolve(shadow.getIWorld());
+ } else {
+ toMatchAgainst = rMember;
+ // FIXME asc I'd like to get rid of this bit of logic altogether, shame ITD fields don't have an effective sig attribute
+ // FIXME asc perf cache the result of discovering the member that contains the real annotations
+ if (rMember.isAnnotatedElsewhere()) {
+ if (kind == Shadow.FieldGet || kind == Shadow.FieldSet) {
+ // FIXME asc should include supers with getInterTypeMungersIncludingSupers ?
+ List mungers = rMember.getDeclaringType().resolve(shadow.getIWorld()).getInterTypeMungers();
+ for (Iterator iter = mungers.iterator(); iter.hasNext();) {
+ ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) iter.next();
+ if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
+ ResolvedMember fakerm = typeMunger.getSignature();
+ if (fakerm.equals(member)) {
+ ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
+ ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
+ toMatchAgainst = rmm;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ annotationTypePattern.resolve(shadow.getIWorld());
+ return annotationTypePattern.matches(toMatchAgainst);
+ }
+
+ private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
+ ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
+ for (int i = 0; i < decMethods.length; i++) {
+ ResolvedMember member = decMethods[i];
+ if (member.equals(ajcMethod)) {
+ return member;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings)
+ */
+ @Override
+ protected void resolveBindings(IScope scope, Bindings bindings) {
+ if (!scope.getWorld().isInJava5Mode()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ATANNOTATION_ONLY_SUPPORTED_AT_JAVA5_LEVEL),
+ getSourceLocation()));
+ return;
+ }
+ annotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern.resolveBindings(scope, bindings, true);
+ // must be either a Var, or an annotation type pattern
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
+ */
+ @Override
+ protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ ExactAnnotationTypePattern newType = (ExactAnnotationTypePattern) annotationTypePattern.remapAdviceFormals(bindings);
+ Pointcut ret = new AnnotationPointcut(newType, bindings.getEnclosingAdvice());
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ if (annotationTypePattern instanceof BindingAnnotationFieldTypePattern) {
+ if (shadow.getKind() != Shadow.MethodExecution) {
+ shadow.getIWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil
+ .error("Annotation field binding is only supported at method-execution join points (compiler limitation)",
+ getSourceLocation()));
+ return Literal.TRUE; // exit quickly, error will prevent weaving
+ }
+ BindingAnnotationFieldTypePattern btp = (BindingAnnotationFieldTypePattern) annotationTypePattern;
+ ResolvedType formalType = btp.getFormalType().resolve(shadow.getIWorld());
+ UnresolvedType annoType = btp.getAnnotationType();
+ // TODO 2 need to sort out appropriate creation of the AnnotationAccessFieldVar - what happens for
+ // reflective (ReflectionShadow) access to types?
+ Var var = shadow.getKindedAnnotationVar(annoType);
+ if (var == null) {
+ throw new BCException("Unexpected problem locating annotation at join point '" + shadow + "'");
+ }
+ state.set(btp.getFormalIndex(), var.getAccessorForValue(formalType, btp.formalName));
+ } else if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) annotationTypePattern;
+ UnresolvedType annotationType = btp.getAnnotationType();
+ Var var = shadow.getKindedAnnotationVar(annotationType);
+
+ // At this point, var *could* be null. The only reason this could happen (if we aren't failing...)
+ // is if another binding annotation designator elsewhere in the pointcut is going to expose the annotation
+ // eg. (execution(* a*(..)) && @annotation(foo)) || (execution(* b*(..)) && @this(foo))
+ // where sometimes @annotation will be providing the value, and sometimes
+ // @this will be providing the value (see pr138223)
+
+ // If we are here for other indecipherable reasons (it's not the case above...) then
+ // you might want to uncomment this next bit of code to collect the diagnostics
+ // if (var == null) throw new BCException("Impossible! annotation=["+annotationType+
+ // "] shadow=["+shadow+" at "+shadow.getSourceLocation()+
+ // "] pointcut is at ["+getSourceLocation()+"]");
+ if (var == null) {
+ if (matchInternal(shadow).alwaysTrue()) {
+ return Literal.TRUE;
+ } else {
+ return Literal.FALSE;
+ }
+ }
+ state.set(btp.getFormalIndex(), var);
+ }
+
+ if (matchInternal(shadow).alwaysTrue()) {
+ return Literal.TRUE;
+ } else {
+ return Literal.FALSE;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ @Override
+ public List<BindingPattern> getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingPattern) { // BindingAnnotationTypePattern) {
+ List<BindingPattern> l = new ArrayList<BindingPattern>();
+ l.add((BindingPattern)annotationTypePattern);
+ return l;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ @Override
+ public List<BindingTypePattern> getBindingTypePatterns() {
+ return Collections.emptyList();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
+ */
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.ANNOTATION);
+ annotationTypePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationTypePattern type = AnnotationTypePattern.read(s, context);
+ AnnotationPointcut ret = new AnnotationPointcut((ExactAnnotationTypePattern) type);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof AnnotationPointcut)) {
+ return false;
+ }
+ AnnotationPointcut o = (AnnotationPointcut) other;
+ return o.annotationTypePattern.equals(this.annotationTypePattern);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + annotationTypePattern.hashCode();
+ return result;
+ }
+
+ public void buildDeclarationText() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("@annotation(");
+ String annPatt = annotationTypePattern.toString();
+ buf.append(annPatt.startsWith("@") ? annPatt.substring(1) : annPatt);
+ buf.append(")");
+ this.declarationText = buf.toString();
+ }
+
+ @Override
+ public String toString() {
+ return this.declarationText;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationTypePattern.java
new file mode 100644
index 000000000..82fb33854
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnnotationTypePattern.java
@@ -0,0 +1,158 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public abstract class AnnotationTypePattern extends PatternNode {
+
+ public static final AnnotationTypePattern ANY = new AnyAnnotationTypePattern();
+ public static final AnnotationTypePattern ELLIPSIS = new EllipsisAnnotationTypePattern();
+ public static final AnnotationTypePattern[] NONE = new AnnotationTypePattern[0];
+ private boolean isForParameterAnnotationMatch;
+
+ /**
+ * TODO: write, read, equals & hashCode both in annotation hierarchy and in altered TypePattern hierarchy
+ */
+ protected AnnotationTypePattern() {
+ super();
+ }
+
+ public abstract FuzzyBoolean matches(AnnotatedElement annotated);
+
+ public abstract FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations);
+
+ public FuzzyBoolean fastMatches(AnnotatedElement annotated) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ public AnnotationTypePattern remapAdviceFormals(IntMap bindings) {
+ return this;
+ }
+
+ public abstract void resolve(World world);
+
+ public abstract AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w);
+
+ public boolean isAny() {
+ return false;
+ }
+
+ /**
+ * This can modify in place, or return a new TypePattern if the type changes.
+ */
+ public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ return this;
+ }
+
+ public static final byte EXACT = 1;
+ public static final byte BINDING = 2;
+ public static final byte NOT = 3;
+ public static final byte OR = 4;
+ public static final byte AND = 5;
+ public static final byte ELLIPSIS_KEY = 6;
+ public static final byte ANY_KEY = 7;
+ public static final byte WILD = 8;
+ public static final byte EXACTFIELD = 9;
+ public static final byte BINDINGFIELD = 10;
+ public static final byte BINDINGFIELD2 = 11;
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte key = s.readByte();
+ switch (key) {
+ case EXACT:
+ return ExactAnnotationTypePattern.read(s, context);
+ case BINDING:
+ return BindingAnnotationTypePattern.read(s, context);
+ case NOT:
+ return NotAnnotationTypePattern.read(s, context);
+ case OR:
+ return OrAnnotationTypePattern.read(s, context);
+ case AND:
+ return AndAnnotationTypePattern.read(s, context);
+ case WILD:
+ return WildAnnotationTypePattern.read(s, context);
+ case EXACTFIELD:
+ return ExactAnnotationFieldTypePattern.read(s, context);
+ case BINDINGFIELD:
+ return BindingAnnotationFieldTypePattern.read(s, context);
+ case BINDINGFIELD2:
+ return BindingAnnotationFieldTypePattern.read2(s, context);
+ case ELLIPSIS_KEY:
+ return ELLIPSIS;
+ case ANY_KEY:
+ return ANY;
+ }
+ throw new BCException("unknown TypePattern kind: " + key);
+ }
+
+ public void setForParameterAnnotationMatch() {
+ isForParameterAnnotationMatch = true;
+ }
+
+ public boolean isForParameterAnnotationMatch() {
+ return isForParameterAnnotationMatch;
+ }
+
+}
+
+class EllipsisAnnotationTypePattern extends AnnotationTypePattern {
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.ELLIPSIS_KEY);
+ }
+
+ @Override
+ public void resolve(World world) {
+ }
+
+ @Override
+ public String toString() {
+ return "..";
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public AnnotationTypePattern parameterizeWith(Map arg0, World w) {
+ return this;
+ }
+
+ @Override
+ public void setForParameterAnnotationMatch() {
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyAnnotationTypePattern.java
new file mode 100644
index 000000000..769424311
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyAnnotationTypePattern.java
@@ -0,0 +1,74 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors
+ * Andy Clement - extracted from AnnotationTypePattern
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+public class AnyAnnotationTypePattern extends AnnotationTypePattern {
+
+ @Override
+ public FuzzyBoolean fastMatches(AnnotatedElement annotated) {
+ return FuzzyBoolean.YES;
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ return FuzzyBoolean.YES;
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ return FuzzyBoolean.YES;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.ANY_KEY);
+ }
+
+ @Override
+ public void resolve(World world) {
+ }
+
+ @Override
+ public String toString() {
+ return "@ANY";
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public boolean isAny() {
+ return true;
+ }
+
+ @Override
+ public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> arg0, World w) {
+ return this;
+ }
+
+ @Override
+ public void setForParameterAnnotationMatch() {
+
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyTypePattern.java
new file mode 100644
index 000000000..db9ba5130
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyTypePattern.java
@@ -0,0 +1,113 @@
+/* *******************************************************************
+ * Copyright (c) 2002, 2010 Palo Alto Research Center, Incorporated (PARC) and others.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+public class AnyTypePattern extends TypePattern {
+
+ /**
+ * Constructor for EllipsisTypePattern.
+ *
+ * @param includeSubtypes
+ */
+ public AnyTypePattern() {
+ super(false, false, new TypePatternList());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
+ */
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ return true;
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType)
+ */
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ return true;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ return true;
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType)
+ */
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ return FuzzyBoolean.YES;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(ANY_KEY);
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matches(IType, MatchKind)
+ */
+ // public FuzzyBoolean matches(IType type, MatchKind kind) {
+ // return FuzzyBoolean.YES;
+ // }
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesSubtypes(IType)
+ */
+ @Override
+ protected boolean matchesSubtypes(ResolvedType type) {
+ return true;
+ }
+
+ @Override
+ public boolean isStar() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "*";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof AnyTypePattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return 37;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> arg0, World w) {
+ return this;
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyWithAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyWithAnnotationTypePattern.java
new file mode 100644
index 000000000..8306ff6d0
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/AnyWithAnnotationTypePattern.java
@@ -0,0 +1,143 @@
+/* *******************************************************************
+ * Copyright (c) 2002, 2010 Palo Alto Research Center, Incorporated (PARC) and others.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+
+/**
+ * This type represents a type pattern of '*' but with an annotation specified, e.g. '@Color *'
+ */
+public class AnyWithAnnotationTypePattern extends TypePattern {
+
+ public AnyWithAnnotationTypePattern(AnnotationTypePattern atp) {
+ super(false, false);
+ annotationPattern = atp;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ return true;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ annotationPattern.resolve(type.getWorld());
+ boolean b = false;
+ if (type.temporaryAnnotationTypes != null) {
+ b = annotationPattern.matches(type, type.temporaryAnnotationTypes).alwaysTrue();
+ } else {
+ b = annotationPattern.matches(type).alwaysTrue();
+ }
+ return b;
+ }
+
+ @Override
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ if (requireExactType) {
+ scope.getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
+ return NO;
+ }
+ return super.resolveBindings(scope, bindings, allowBinding, requireExactType);
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ annotationPattern.resolve(type.getWorld());
+ return annotationPattern.matches(annotatedType).alwaysTrue();
+ }
+
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ if (Modifier.isFinal(type.getModifiers())) {
+ return FuzzyBoolean.fromBoolean(matchesExactly(type));
+ }
+ return FuzzyBoolean.MAYBE;
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(this.annotationPattern.parameterizeWith(
+ typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(TypePattern.ANY_WITH_ANNO);
+ annotationPattern.write(s);
+ writeLocation(s);
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext c) throws IOException {
+ AnnotationTypePattern annPatt = AnnotationTypePattern.read(s, c);
+ AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(annPatt);
+ ret.readLocation(c, s);
+ return ret;
+ }
+
+ // public FuzzyBoolean matches(IType type, MatchKind kind) {
+ // return FuzzyBoolean.YES;
+ // }
+
+ @Override
+ protected boolean matchesSubtypes(ResolvedType type) {
+ return true;
+ }
+
+ @Override
+ public boolean isStar() {
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + annotationPattern + " *)";
+ }
+
+ public AnnotationTypePattern getAnnotationTypePattern() {
+ return annotationPattern;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AnyWithAnnotationTypePattern)) {
+ return false;
+ }
+ AnyWithAnnotationTypePattern awatp = (AnyWithAnnotationTypePattern) obj;
+ return (annotationPattern.equals(awatp.annotationPattern));
+ }
+
+ @Override
+ public int hashCode() {
+ return annotationPattern.hashCode();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java
new file mode 100644
index 000000000..db612b8cd
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsAnnotationPointcut.java
@@ -0,0 +1,250 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * @author colyer
+ *
+ * TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code
+ * Templates
+ */
+public class ArgsAnnotationPointcut extends NameBindingPointcut {
+
+ private AnnotationPatternList arguments;
+ private String declarationText;
+
+ /**
+ *
+ */
+ public ArgsAnnotationPointcut(AnnotationPatternList arguments) {
+ super();
+ this.arguments = arguments;
+ this.pointcutKind = ATARGS;
+ buildDeclarationText();
+ }
+
+ public AnnotationPatternList getArguments() {
+ return arguments;
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS; // empty args() matches jps with no args
+ }
+
+ public Pointcut parameterizeWith(Map typeVariableMap, World w) {
+ ArgsAnnotationPointcut ret = new ArgsAnnotationPointcut(arguments.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
+ */
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
+ */
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ arguments.resolve(shadow.getIWorld());
+ FuzzyBoolean ret = arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()));
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings)
+ */
+ protected void resolveBindings(IScope scope, Bindings bindings) {
+ if (!scope.getWorld().isInJava5Mode()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ATARGS_ONLY_SUPPORTED_AT_JAVA5_LEVEL),
+ getSourceLocation()));
+ return;
+ }
+ arguments.resolveBindings(scope, bindings, true);
+ if (arguments.ellipsisCount > 1) {
+ scope.message(IMessage.ERROR, this, "uses more than one .. in args (compiler limitation)");
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
+ */
+ protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ // Enforce rule about which designators are supported in declare
+ inAspect.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ARGS_IN_DECLARE),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+ AnnotationPatternList list = arguments.resolveReferences(bindings);
+ Pointcut ret = new ArgsAnnotationPointcut(list);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
+ */
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ int len = shadow.getArgCount();
+
+ // do some quick length tests first
+ int numArgsMatchedByEllipsis = (len + arguments.ellipsisCount) - arguments.size();
+ if (numArgsMatchedByEllipsis < 0) {
+ return Literal.FALSE; // should never happen
+ }
+ if ((numArgsMatchedByEllipsis > 0) && (arguments.ellipsisCount == 0)) {
+ return Literal.FALSE; // should never happen
+ }
+ // now work through the args and the patterns, skipping at ellipsis
+ Test ret = Literal.TRUE;
+ int argsIndex = 0;
+ for (int i = 0; i < arguments.size(); i++) {
+ if (arguments.get(i) == AnnotationTypePattern.ELLIPSIS) {
+ // match ellipsisMatchCount args
+ argsIndex += numArgsMatchedByEllipsis;
+ } else if (arguments.get(i) == AnnotationTypePattern.ANY) {
+ argsIndex++;
+ } else {
+ // match the argument type at argsIndex with the ExactAnnotationTypePattern
+ // we know it is exact because nothing else is allowed in args
+ ExactAnnotationTypePattern ap = (ExactAnnotationTypePattern) arguments.get(i);
+ UnresolvedType argType = shadow.getArgType(argsIndex);
+ ResolvedType rArgType = argType.resolve(shadow.getIWorld());
+ if (rArgType.isMissing()) {
+ shadow.getIWorld().getLint().cantFindType.signal(new String[] { WeaverMessages.format(
+ WeaverMessages.CANT_FIND_TYPE_ARG_TYPE, argType.getName()) }, shadow.getSourceLocation(),
+ new ISourceLocation[] { getSourceLocation() });
+ // IMessage msg = new Message(
+ // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_ARG_TYPE,argType.getName()),
+ // "",IMessage.ERROR,shadow.getSourceLocation(),null,new ISourceLocation[]{getSourceLocation()});
+ }
+
+ ResolvedType rAnnType = ap.getAnnotationType().resolve(shadow.getIWorld());
+ if (ap instanceof BindingAnnotationTypePattern) {
+ BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) ap;
+ Var annvar = shadow.getArgAnnotationVar(argsIndex, rAnnType);
+ state.set(btp.getFormalIndex(), annvar);
+ }
+ if (!ap.matches(rArgType).alwaysTrue()) {
+ // we need a test...
+ ret = Test.makeAnd(ret, Test.makeHasAnnotation(shadow.getArgVar(argsIndex), rAnnType));
+ }
+ argsIndex++;
+ }
+ }
+ return ret;
+ }
+
+ public List<BindingPattern> getBindingAnnotationTypePatterns() {
+ List<BindingPattern> l = new ArrayList<BindingPattern>();
+ AnnotationTypePattern[] pats = arguments.getAnnotationPatterns();
+ for (int i = 0; i < pats.length; i++) {
+ if (pats[i] instanceof BindingAnnotationTypePattern) {
+ l.add((BindingPattern)pats[i]);
+ }
+ }
+ return l;
+ }
+
+ public List<BindingTypePattern> getBindingTypePatterns() {
+ return Collections.emptyList();
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.ATARGS);
+ arguments.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationPatternList annotationPatternList = AnnotationPatternList.read(s, context);
+ ArgsAnnotationPointcut ret = new ArgsAnnotationPointcut(annotationPatternList);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ArgsAnnotationPointcut)) {
+ return false;
+ }
+ ArgsAnnotationPointcut other = (ArgsAnnotationPointcut) obj;
+ return other.arguments.equals(arguments);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return 17 + 37 * arguments.hashCode();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ private void buildDeclarationText() {
+ StringBuffer buf = new StringBuffer("@args");
+ buf.append(arguments.toString());
+ this.declarationText = buf.toString();
+ }
+
+ public String toString() {
+ return this.declarationText;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsPointcut.java
new file mode 100644
index 000000000..56b1a4dc5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ArgsPointcut.java
@@ -0,0 +1,288 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+/**
+ * args(arguments)
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public class ArgsPointcut extends NameBindingPointcut {
+ private static final String ASPECTJ_JP_SIGNATURE_PREFIX = "Lorg/aspectj/lang/JoinPoint";
+ private static final String ASPECTJ_SYNTHETIC_SIGNATURE_PREFIX = "Lorg/aspectj/runtime/internal/";
+
+ private TypePatternList arguments;
+ private String stringRepresentation;
+
+ public ArgsPointcut(TypePatternList arguments) {
+ this.arguments = arguments;
+ this.pointcutKind = ARGS;
+ this.stringRepresentation = "args" + arguments.toString() + "";
+ }
+
+ public TypePatternList getArguments() {
+ return arguments;
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ ArgsPointcut ret = new ArgsPointcut(this.arguments.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS; // empty args() matches jps with no args
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ ResolvedType[] argumentsToMatchAgainst = getArgumentsToMatchAgainst(shadow);
+ FuzzyBoolean ret = arguments.matches(argumentsToMatchAgainst, TypePattern.DYNAMIC);
+ return ret;
+ }
+
+ private ResolvedType[] getArgumentsToMatchAgainst(Shadow shadow) {
+
+ if (shadow.isShadowForArrayConstructionJoinpoint()) {
+ return shadow.getArgumentTypesForArrayConstructionShadow();
+ }
+
+ ResolvedType[] argumentsToMatchAgainst = shadow.getIWorld().resolve(shadow.getGenericArgTypes());
+
+ // special treatment for adviceexecution which may have synthetic arguments we
+ // want to ignore.
+ if (shadow.getKind() == Shadow.AdviceExecution) {
+ int numExtraArgs = 0;
+ for (int i = 0; i < argumentsToMatchAgainst.length; i++) {
+ String argumentSignature = argumentsToMatchAgainst[i].getSignature();
+ if (argumentSignature.startsWith(ASPECTJ_JP_SIGNATURE_PREFIX)
+ || argumentSignature.startsWith(ASPECTJ_SYNTHETIC_SIGNATURE_PREFIX)) {
+ numExtraArgs++;
+ } else {
+ // normal arg after AJ type means earlier arg was NOT synthetic
+ numExtraArgs = 0;
+ }
+ }
+ if (numExtraArgs > 0) {
+ int newArgLength = argumentsToMatchAgainst.length - numExtraArgs;
+ ResolvedType[] argsSubset = new ResolvedType[newArgLength];
+ System.arraycopy(argumentsToMatchAgainst, 0, argsSubset, 0, newArgLength);
+ argumentsToMatchAgainst = argsSubset;
+ }
+ } else if (shadow.getKind() == Shadow.ConstructorExecution) {
+ if (shadow.getMatchingSignature().getParameterTypes().length < argumentsToMatchAgainst.length) {
+ // there are one or more synthetic args on the end, caused by non-public itd constructor
+ int newArgLength = shadow.getMatchingSignature().getParameterTypes().length;
+ ResolvedType[] argsSubset = new ResolvedType[newArgLength];
+ System.arraycopy(argumentsToMatchAgainst, 0, argsSubset, 0, newArgLength);
+ argumentsToMatchAgainst = argsSubset;
+ }
+ }
+ return argumentsToMatchAgainst;
+ }
+
+ public List<BindingPattern> getBindingAnnotationTypePatterns() {
+ return Collections.emptyList();
+ }
+
+ public List<BindingTypePattern> getBindingTypePatterns() {
+ List<BindingTypePattern> l = new ArrayList<BindingTypePattern>();
+ TypePattern[] pats = arguments.getTypePatterns();
+ for (int i = 0; i < pats.length; i++) {
+ if (pats[i] instanceof BindingTypePattern) {
+ l.add((BindingTypePattern)pats[i]);
+ }
+ }
+ return l;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.ARGS);
+ arguments.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ArgsPointcut ret = new ArgsPointcut(TypePatternList.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof ArgsPointcut)) {
+ return false;
+ }
+ ArgsPointcut o = (ArgsPointcut) other;
+ return o.arguments.equals(this.arguments);
+ }
+
+ public int hashCode() {
+ return arguments.hashCode();
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ arguments.resolveBindings(scope, bindings, true, true);
+ if (arguments.ellipsisCount > 1) {
+ scope.message(IMessage.ERROR, this, "uses more than one .. in args (compiler limitation)");
+ }
+ }
+
+ public void postRead(ResolvedType enclosingType) {
+ arguments.postRead(enclosingType);
+ }
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ // Enforce rule about which designators are supported in declare
+ inAspect.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ARGS_IN_DECLARE),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+ TypePatternList args = arguments.resolveReferences(bindings);
+ if (inAspect.crosscuttingMembers != null) {
+ inAspect.crosscuttingMembers.exposeTypes(args.getExactTypes());
+ }
+ Pointcut ret = new ArgsPointcut(args);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ private Test findResidueNoEllipsis(Shadow shadow, ExposedState state, TypePattern[] patterns) {
+ ResolvedType[] argumentsToMatchAgainst = getArgumentsToMatchAgainst(shadow);
+ int len = argumentsToMatchAgainst.length;
+ // System.err.println("boudn to : " + len + ", " + patterns.length);
+ if (patterns.length != len) {
+ return Literal.FALSE;
+ }
+
+ Test ret = Literal.TRUE;
+
+ for (int i = 0; i < len; i++) {
+ UnresolvedType argType = shadow.getGenericArgTypes()[i];
+ TypePattern type = patterns[i];
+ ResolvedType argRTX = shadow.getIWorld().resolve(argType, true);
+ if (!(type instanceof BindingTypePattern)) {
+ if (argRTX.isMissing()) {
+ shadow.getIWorld().getLint().cantFindType.signal(new String[] { WeaverMessages.format(
+ WeaverMessages.CANT_FIND_TYPE_ARG_TYPE, argType.getName()) }, shadow.getSourceLocation(),
+ new ISourceLocation[] { getSourceLocation() });
+ // IMessage msg = new Message(
+ // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_ARG_TYPE,argType.getName()),
+ // "",IMessage.ERROR,shadow.getSourceLocation(),null,new ISourceLocation[]{getSourceLocation()});
+ // shadow.getIWorld().getMessageHandler().handleMessage(msg);
+ }
+ if (type.matchesInstanceof(argRTX).alwaysTrue()) {
+ continue;
+ }
+ }
+
+ World world = shadow.getIWorld();
+ ResolvedType typeToExpose = type.getExactType().resolve(world);
+ if (typeToExpose.isParameterizedType()) {
+ boolean inDoubt = (type.matchesInstanceof(argRTX) == FuzzyBoolean.MAYBE);
+ if (inDoubt && world.getLint().uncheckedArgument.isEnabled()) {
+ String uncheckedMatchWith = typeToExpose.getSimpleBaseName();
+ if (argRTX.isParameterizedType() && (argRTX.getRawType() == typeToExpose.getRawType())) {
+ uncheckedMatchWith = argRTX.getSimpleName();
+ }
+ if (!isUncheckedArgumentWarningSuppressed()) {
+ world.getLint().uncheckedArgument.signal(new String[] { typeToExpose.getSimpleName(), uncheckedMatchWith,
+ typeToExpose.getSimpleBaseName(), shadow.toResolvedString(world) }, getSourceLocation(),
+ new ISourceLocation[] { shadow.getSourceLocation() });
+ }
+ }
+ }
+
+ ret = Test.makeAnd(ret, exposeStateForVar(shadow.getArgVar(i), type, state, shadow.getIWorld()));
+ }
+
+ return ret;
+ }
+
+ /**
+ * We need to find out if someone has put the @SuppressAjWarnings{"uncheckedArgument"} annotation somewhere. That somewhere is
+ * going to be an a piece of advice that uses this pointcut. But how do we find it???
+ *
+ * @return
+ */
+ private boolean isUncheckedArgumentWarningSuppressed() {
+ return false;
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ ResolvedType[] argsToMatch = getArgumentsToMatchAgainst(shadow);
+ if (arguments.matches(argsToMatch, TypePattern.DYNAMIC).alwaysFalse()) {
+ return Literal.FALSE;
+ }
+ int ellipsisCount = arguments.ellipsisCount;
+ if (ellipsisCount == 0) {
+ return findResidueNoEllipsis(shadow, state, arguments.getTypePatterns());
+ } else if (ellipsisCount == 1) {
+ TypePattern[] patternsWithEllipsis = arguments.getTypePatterns();
+ TypePattern[] patternsWithoutEllipsis = new TypePattern[argsToMatch.length];
+ int lenWithEllipsis = patternsWithEllipsis.length;
+ int lenWithoutEllipsis = patternsWithoutEllipsis.length;
+ // l1+1 >= l0
+ int indexWithEllipsis = 0;
+ int indexWithoutEllipsis = 0;
+ while (indexWithoutEllipsis < lenWithoutEllipsis) {
+ TypePattern p = patternsWithEllipsis[indexWithEllipsis++];
+ if (p == TypePattern.ELLIPSIS) {
+ int newLenWithoutEllipsis = lenWithoutEllipsis - (lenWithEllipsis - indexWithEllipsis);
+ while (indexWithoutEllipsis < newLenWithoutEllipsis) {
+ patternsWithoutEllipsis[indexWithoutEllipsis++] = TypePattern.ANY;
+ }
+ } else {
+ patternsWithoutEllipsis[indexWithoutEllipsis++] = p;
+ }
+ }
+ return findResidueNoEllipsis(shadow, state, patternsWithoutEllipsis);
+ } else {
+ throw new BCException("unimplemented");
+ }
+ }
+
+ public String toString() {
+ return this.stringRepresentation;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicToken.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicToken.java
new file mode 100644
index 000000000..e6e201daf
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicToken.java
@@ -0,0 +1,75 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+
+public final class BasicToken implements IToken {
+ private String value;
+ private boolean isIdentifier;
+ private String literalKind;
+
+ private int start;
+ private int end;
+
+ public static BasicToken makeOperator(String value, int start, int end) {
+ return new BasicToken(value.intern(), false, null, start, end);
+ }
+
+ public static BasicToken makeIdentifier(String value, int start, int end) {
+ return new BasicToken(value, true, null, start, end);
+ }
+
+ public static BasicToken makeLiteral(String value, String kind, int start, int end) {
+ return new BasicToken(value, false, kind.intern(), start, end);
+ }
+
+
+ private BasicToken(String value, boolean isIdentifier, String literalKind, int start, int end) {
+ this.value = value;
+ this.isIdentifier = isIdentifier;
+ this.literalKind = literalKind;
+ this.start = start;
+ this.end = end;
+ }
+
+ public int getStart() { return start; }
+ public int getEnd() { return end; }
+ public String getFileName() { return "unknown"; }
+
+ public String getString() {
+ return value;
+ }
+
+ public boolean isIdentifier() {
+ return isIdentifier;
+ }
+
+ public Pointcut maybeGetParsedPointcut() {
+ return null;
+ }
+
+
+
+ public String toString() {
+ String s;
+ if (isIdentifier) s = value;
+ else s = "'" + value + "'";
+
+ return s + "@" + start + ":" + end;
+ }
+ public String getLiteralKind() {
+ return literalKind;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicTokenSource.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicTokenSource.java
new file mode 100644
index 000000000..0a099529b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BasicTokenSource.java
@@ -0,0 +1,188 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.ISourceContext;
+
+
+public class BasicTokenSource implements ITokenSource {
+ private int index = 0;
+ private IToken[] tokens;
+ private ISourceContext sourceContext;
+
+ public BasicTokenSource(IToken[] tokens, ISourceContext sourceContext) {
+ this.tokens = tokens;
+ this.sourceContext = sourceContext;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int newIndex) {
+ this.index = newIndex;
+ }
+
+ public IToken next() {
+ try {
+ return tokens[index++];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return IToken.EOF;
+ }
+ }
+
+ public IToken peek() {
+ try {
+ return tokens[index];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return IToken.EOF;
+ }
+ }
+
+ public IToken peek(int offset) {
+ try {
+ return tokens[index+offset];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return IToken.EOF;
+ }
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("[");
+ for (int i = 0; i < tokens.length; i++) {
+ IToken t = tokens[i];
+ if (t == null)
+ break;
+ if (i > 0)
+ buf.append(", ");
+ buf.append(t.toString());
+ }
+ buf.append("]");
+ return buf.toString();
+ }
+
+
+ //////////////////////////////////////////////////////
+ // Convenience, maybe just for testing
+ public static ITokenSource makeTokenSource(String input, ISourceContext context) {
+ char[] chars = input.toCharArray();
+
+ int i = 0;
+ List<BasicToken> tokens = new ArrayList<BasicToken>();
+
+ while (i < chars.length) {
+ char ch = chars[i++];
+ switch(ch) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ continue;
+ case '*':
+ case '(':
+ case ')':
+ case '+':
+ case '[':
+ case ']':
+ case ',':
+ case '!':
+ case ':':
+ case '@':
+ case '<':
+ case '>':
+ case '=':
+ case '?':
+ tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1));
+ continue;
+ case '.':
+ if ((i+2)<=chars.length) {
+ // could be '...'
+ char nextChar1 = chars[i];
+ char nextChar2 = chars[i+1];
+ if (ch==nextChar1 && ch==nextChar2) {
+ // '...'
+ tokens.add(BasicToken.makeIdentifier("...",i-1,i+1));
+ i=i+2;
+ } else {
+ tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1));
+ }
+ } else {
+ tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1));
+ }
+ continue;
+ case '&':
+ if ((i+1) <= chars.length && chars[i] != '&') {
+ tokens.add(BasicToken.makeOperator(makeString(ch),i-1,i-1));
+ continue;
+ }
+ // fall-through
+ case '|':
+ if (i == chars.length) {
+ throw new BCException("bad " + ch);
+ }
+ char nextChar = chars[i++];
+ if (nextChar == ch) {
+ tokens.add(BasicToken.makeOperator(makeString(ch, 2), i-2, i-1));
+ } else {
+ throw new RuntimeException("bad " + ch);
+ }
+ continue;
+
+ case '\"':
+ int start0 = i-1;
+ while (i < chars.length && !(chars[i]=='\"')) i++;
+ i += 1;
+ tokens.add(BasicToken.makeLiteral(new String(chars, start0+1, i-start0-2), "string", start0, i-1));
+ continue;
+ default:
+ int start = i-1;
+ while (i < chars.length && Character.isJavaIdentifierPart(chars[i])) { i++; }
+ tokens.add(BasicToken.makeIdentifier(new String(chars, start, i-start), start, i-1));
+
+ }
+ }
+
+ //System.out.println(tokens);
+
+ return new BasicTokenSource((IToken[])tokens.toArray(new IToken[tokens.size()]), context);
+ }
+
+ private static String makeString(char ch) {
+ return Character.toString(ch);
+ }
+
+ private static String makeString(char ch, int count) {
+ // slightly inefficient ;-)
+ char[] chars = new char[count];
+ for (int i=0; i<count; i++) { chars[i] = ch; }
+ return new String(chars);
+ }
+ public ISourceContext getSourceContext() {
+ return sourceContext;
+ }
+ public void setSourceContext(ISourceContext context) {
+ this.sourceContext = context;
+ }
+
+ @Override
+ public boolean hasMoreTokens() {
+ return index < tokens.length;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationFieldTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationFieldTypePattern.java
new file mode 100644
index 000000000..707f1e79e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationFieldTypePattern.java
@@ -0,0 +1,198 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * Represents an attempt to bind the field of an annotation within a pointcut. For example:<br>
+ * <code><pre>
+ * before(Level lev): execution(* *(..)) &amp;&amp; @annotation(TraceAnnotation(lev))
+ * </pre></code><br>
+ * This binding annotation type pattern will be for 'lev'.
+ */
+public class BindingAnnotationFieldTypePattern extends ExactAnnotationTypePattern implements BindingPattern {
+
+ protected int formalIndex;
+ UnresolvedType formalType; // In this construct the formal type differs from the annotation type
+
+ public BindingAnnotationFieldTypePattern(UnresolvedType formalType, int formalIndex, UnresolvedType theAnnotationType) {
+ super(theAnnotationType, null);
+ this.formalIndex = formalIndex;
+ this.formalType = formalType;
+ }
+
+ public void resolveBinding(World world) {
+ if (resolved) {
+ return;
+ }
+ resolved = true;
+ formalType = world.resolve(formalType);
+ annotationType = world.resolve(annotationType);
+ ResolvedType annoType = (ResolvedType) annotationType;
+ if (!annoType.isAnnotation()) {
+ IMessage m = MessageUtil
+ .error(WeaverMessages.format(WeaverMessages.REFERENCE_TO_NON_ANNOTATION_TYPE, annoType.getName()),
+ getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ resolved = false;
+ }
+ }
+
+ @Override
+ public AnnotationTypePattern parameterizeWith(Map typeVariableMap, World w) {
+ throw new BCException("Parameterization not implemented for annotation field binding construct (compiler limitation)");
+ // UnresolvedType newAnnotationType = annotationType;
+ // if (annotationType.isTypeVariableReference()) {
+ // TypeVariableReference t = (TypeVariableReference) annotationType;
+ // String key = t.getTypeVariable().getName();
+ // if (typeVariableMap.containsKey(key)) {
+ // newAnnotationType = (UnresolvedType) typeVariableMap.get(key);
+ // }
+ // } else if (annotationType.isParameterizedType()) {
+ // newAnnotationType = annotationType.parameterize(typeVariableMap);
+ // }
+ // BindingAnnotationTypePattern ret = new BindingAnnotationTypePattern(newAnnotationType, this.formalIndex);
+ // if (newAnnotationType instanceof ResolvedType) {
+ // ResolvedType rat = (ResolvedType) newAnnotationType;
+ // verifyRuntimeRetention(rat.getWorld(), rat);
+ // }
+ // ret.copyLocationFrom(this);
+ // return ret;
+ }
+
+ @Override
+ public int getFormalIndex() {
+ return formalIndex;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BindingAnnotationFieldTypePattern)) {
+ return false;
+ }
+ BindingAnnotationFieldTypePattern btp = (BindingAnnotationFieldTypePattern) obj;
+ return (btp.formalIndex == formalIndex) && (annotationType.equals(btp.annotationType))
+ && (formalType.equals(btp.formalType));
+ }
+
+ @Override
+ public int hashCode() {
+ return (annotationType.hashCode() * 37 + formalIndex * 37) + formalType.hashCode();
+ }
+
+ @Override
+ public AnnotationTypePattern remapAdviceFormals(IntMap bindings) {
+ if (!bindings.hasKey(formalIndex)) {
+ throw new BCException("Annotation field binding reference must be bound (compiler limitation)");
+ // must be something like returning the unbound form: return new ExactAnnotationTypePattern(annotationType,
+ // null);
+ } else {
+ int newFormalIndex = bindings.get(formalIndex);
+ BindingAnnotationFieldTypePattern baftp = new BindingAnnotationFieldTypePattern(formalType, newFormalIndex,
+ annotationType);
+ baftp.formalName = formalName;
+ return baftp;
+ }
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.BINDINGFIELD2);
+ formalType.write(s); // the type of the field within the annotation
+ s.writeShort((short) formalIndex);
+ annotationType.write(s); // the annotation type
+ s.writeUTF(formalName);
+ writeLocation(s);
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationTypePattern ret = new BindingAnnotationFieldTypePattern(UnresolvedType.read(s), s.readShort(),
+ UnresolvedType.read(s));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public static AnnotationTypePattern read2(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ BindingAnnotationFieldTypePattern ret = new BindingAnnotationFieldTypePattern(UnresolvedType.read(s), s.readShort(),
+ UnresolvedType.read(s));
+ ret.formalName = s.readUTF();
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ // Inheritance irrelevant because @annotation(Anno(x)) only supported at method execution join points (compiler limitation)
+ // boolean checkSupers = false;
+ // if (getResolvedAnnotationType().hasAnnotation(UnresolvedType.AT_INHERITED)) {
+ // if (annotated instanceof ResolvedType) {
+ // checkSupers = true;
+ // }
+ // }
+ //
+ if (annotated.hasAnnotation(annotationType)) {
+ if (annotationType instanceof ReferenceType) {
+ ReferenceType rt = (ReferenceType) annotationType;
+ if (rt.getRetentionPolicy() != null && rt.getRetentionPolicy().equals("SOURCE")) {
+ rt.getWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil.warn(WeaverMessages.format(WeaverMessages.NO_MATCH_BECAUSE_SOURCE_RETENTION,
+ annotationType, annotated), getSourceLocation()));
+ return FuzzyBoolean.NO;
+ }
+ ResolvedMember[] methods = rt.getDeclaredMethods();
+ boolean found = false;
+ for (int i = 0; i < methods.length && !found; i++) {
+ if (methods[i].getReturnType().equals(formalType)) {
+ found = true;
+ }
+ }
+ return (found ? FuzzyBoolean.YES : FuzzyBoolean.NO);
+ }
+ }
+ // else if (checkSupers) {
+ // ResolvedType toMatchAgainst = ((ResolvedType) annotated).getSuperclass();
+ // while (toMatchAgainst != null) {
+ // if (toMatchAgainst.hasAnnotation(annotationType)) {
+ // return FuzzyBoolean.YES;
+ // }
+ // toMatchAgainst = toMatchAgainst.getSuperclass();
+ // }
+ // }
+ //
+ return FuzzyBoolean.NO;
+ }
+
+ public UnresolvedType getFormalType() {
+ return formalType;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java
new file mode 100644
index 000000000..142f6155e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingAnnotationTypePattern.java
@@ -0,0 +1,138 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeVariableReference;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+public class BindingAnnotationTypePattern extends ExactAnnotationTypePattern implements BindingPattern {
+
+ protected int formalIndex;
+
+ /**
+ * @param annotationType
+ */
+ public BindingAnnotationTypePattern(UnresolvedType annotationType, int index) {
+ super(annotationType, null);
+ this.formalIndex = index;
+ }
+
+ public BindingAnnotationTypePattern(FormalBinding binding) {
+ this(binding.getType(), binding.getIndex());
+ }
+
+ public void resolveBinding(World world) {
+ if (resolved) {
+ return;
+ }
+ resolved = true;
+ annotationType = annotationType.resolve(world);
+ ResolvedType resolvedAnnotationType = (ResolvedType) annotationType;
+ if (!resolvedAnnotationType.isAnnotation()) {
+ IMessage m = MessageUtil.error(WeaverMessages.format(WeaverMessages.REFERENCE_TO_NON_ANNOTATION_TYPE, annotationType
+ .getName()), getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ resolved = false;
+ }
+ if (annotationType.isTypeVariableReference()) {
+ return; // we'll deal with this next check when the type var is actually bound...
+ }
+ verifyRuntimeRetention(world, resolvedAnnotationType);
+ }
+
+ private void verifyRuntimeRetention(World world, ResolvedType resolvedAnnotationType) {
+ if (!resolvedAnnotationType.isAnnotationWithRuntimeRetention()) { // default is class visibility
+ // default is class visibility
+ IMessage m = MessageUtil.error(WeaverMessages.format(WeaverMessages.BINDING_NON_RUNTIME_RETENTION_ANNOTATION,
+ annotationType.getName()), getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ resolved = false;
+ }
+ }
+
+ public AnnotationTypePattern parameterizeWith(Map typeVariableMap, World w) {
+ UnresolvedType newAnnotationType = annotationType;
+ if (annotationType.isTypeVariableReference()) {
+ TypeVariableReference t = (TypeVariableReference) annotationType;
+ String key = t.getTypeVariable().getName();
+ if (typeVariableMap.containsKey(key)) {
+ newAnnotationType = (UnresolvedType) typeVariableMap.get(key);
+ }
+ } else if (annotationType.isParameterizedType()) {
+ newAnnotationType = annotationType.parameterize(typeVariableMap);
+ }
+ BindingAnnotationTypePattern ret = new BindingAnnotationTypePattern(newAnnotationType, this.formalIndex);
+ if (newAnnotationType instanceof ResolvedType) {
+ ResolvedType rat = (ResolvedType) newAnnotationType;
+ verifyRuntimeRetention(rat.getWorld(), rat);
+ }
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public int getFormalIndex() {
+ return formalIndex;
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BindingAnnotationTypePattern)) {
+ return false;
+ }
+ BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) obj;
+ return (super.equals(btp) && (btp.formalIndex == formalIndex));
+ }
+
+ public int hashCode() {
+ return super.hashCode() * 37 + formalIndex;
+ }
+
+ public AnnotationTypePattern remapAdviceFormals(IntMap bindings) {
+ if (!bindings.hasKey(formalIndex)) {
+ return new ExactAnnotationTypePattern(annotationType, null);
+ } else {
+ int newFormalIndex = bindings.get(formalIndex);
+ return new BindingAnnotationTypePattern(annotationType, newFormalIndex);
+ }
+ }
+
+ private static final byte VERSION = 1; // rev if serialised form changed
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.BINDING);
+ s.writeByte(VERSION);
+ annotationType.write(s);
+ s.writeShort((short) formalIndex);
+ writeLocation(s);
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte version = s.readByte();
+ if (version > VERSION) {
+ throw new BCException("BindingAnnotationTypePattern was written by a more recent version of AspectJ");
+ }
+ AnnotationTypePattern ret = new BindingAnnotationTypePattern(UnresolvedType.read(s), s.readShort());
+ ret.readLocation(context, s);
+ return ret;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingPattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingPattern.java
new file mode 100644
index 000000000..4d909ede5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingPattern.java
@@ -0,0 +1,19 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.IHasPosition;
+
+/**
+ * Marker interface for BindingTypePattern and BindingAnnotationTypePattern
+ */
+public interface BindingPattern extends IHasPosition {
+ int getFormalIndex();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingTypePattern.java
new file mode 100644
index 000000000..900285038
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/BindingTypePattern.java
@@ -0,0 +1,110 @@
+/* *******************************************************************
+ * Copyright (c) 2002, 2010 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Nieraj Singh
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.weaver.AjAttribute;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public class BindingTypePattern extends ExactTypePattern implements BindingPattern {
+ private int formalIndex;
+ private String bindingName;
+
+ public BindingTypePattern(UnresolvedType type, int index, boolean isVarArgs) {
+ super(type, false, isVarArgs);
+ this.formalIndex = index;
+ }
+
+ public BindingTypePattern(FormalBinding binding, boolean isVarArgs) {
+ this(binding.getType(), binding.getIndex(), isVarArgs);
+ this.bindingName = binding.getName();
+ }
+
+ public int getFormalIndex() {
+ return formalIndex;
+ }
+
+ public String getBindingName() {
+ return bindingName;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof BindingTypePattern)) {
+ return false;
+ }
+ BindingTypePattern o = (BindingTypePattern) other;
+ if (includeSubtypes != o.includeSubtypes) {
+ return false;
+ }
+ if (isVarArgs != o.isVarArgs) {
+ return false;
+ }
+ return o.type.equals(this.type) && o.formalIndex == this.formalIndex;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + super.hashCode();
+ result = 37 * result + formalIndex;
+ return result;
+ }
+
+ public void write(CompressingDataOutputStream out) throws IOException {
+ out.writeByte(TypePattern.BINDING);
+ type.write(out);
+ out.writeShort((short) formalIndex);
+ out.writeBoolean(isVarArgs);
+ writeLocation(out);
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ UnresolvedType type = UnresolvedType.read(s);
+ int index = s.readShort();
+ boolean isVarargs = false;
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+ isVarargs = s.readBoolean();
+ }
+ TypePattern ret = new BindingTypePattern(type, index, isVarargs);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public TypePattern remapAdviceFormals(IntMap bindings) {
+ if (!bindings.hasKey(formalIndex)) {
+ return new ExactTypePattern(type, false, isVarArgs);
+ } else {
+ int newFormalIndex = bindings.get(formalIndex);
+ return new BindingTypePattern(type, newFormalIndex, isVarArgs);
+ }
+ }
+
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ ExactTypePattern superParameterized = (ExactTypePattern) super.parameterizeWith(typeVariableMap, w);
+ BindingTypePattern ret = new BindingTypePattern(superParameterized.getExactType(), this.formalIndex, this.isVarArgs);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public String toString() {
+ // Thread.currentThread().dumpStack();
+ return "BindingTypePattern(" + super.toString() + ", " + formalIndex + ")";
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Bindings.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Bindings.java
new file mode 100644
index 000000000..4853dd049
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Bindings.java
@@ -0,0 +1,136 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.UnresolvedType;
+
+public class Bindings {
+ public static final Bindings NONE = new Bindings(0);
+
+ private BindingPattern[] bindings;
+
+ public Bindings(BindingPattern[] bindings) {
+ this.bindings = bindings;
+ }
+
+ public Bindings(int count) {
+ this(new BindingPattern[count]);
+ }
+
+ public void register(BindingPattern binding, IScope scope) {
+ int index = binding.getFormalIndex();
+ BindingPattern existingBinding = bindings[index];
+ if (existingBinding != null) {
+ scope.message(IMessage.ERROR, existingBinding, binding, "multiple bindings" + index + ", " + binding);
+ }
+ bindings[index] = binding;
+ }
+
+ public void mergeIn(Bindings other, IScope scope) {
+ for (int i = 0, len = other.bindings.length; i < len; i++) {
+ if (other.bindings[i] != null) {
+ register(other.bindings[i], scope);
+ }
+ }
+ }
+
+ /**
+ * signals an error if one has a binding and other doesn't
+ */
+ public void checkEquals(Bindings other, IScope scope) {
+ BindingPattern[] b1 = this.bindings;
+ BindingPattern[] b2 = other.bindings;
+ int len = b1.length;
+ if (len != b2.length) {
+ throw new BCException("INSANE");
+ }
+
+ for (int i = 0; i < len; i++) {
+ if (b1[i] == null && b2[i] != null) {
+ scope.message(IMessage.ERROR, b2[i], "inconsistent binding");
+ b1[i] = b2[i]; // done just to produce fewer error messages
+ } else if (b2[i] == null && b1[i] != null) {
+ scope.message(IMessage.ERROR, b1[i], "inconsistent binding");
+ b2[i] = b1[i]; // done just to produce fewer error messages
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer("Bindings(");
+ for (int i = 0, len = bindings.length; i < len; i++) {
+ if (i > 0)
+ buf.append(", ");
+ buf.append(bindings[i]);
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ public int[] getUsedFormals() {
+ // System.out.println("used: " + this);
+ int[] ret = new int[bindings.length];
+ int index = 0;
+ for (int i = 0, len = bindings.length; i < len; i++) {
+ if (bindings[i] != null) {
+ ret[index++] = i;
+ }
+ }
+ int[] newRet = new int[index];
+ System.arraycopy(ret, 0, newRet, 0, index);
+ // System.out.println("ret: " + index);
+ return newRet;
+ }
+
+ public UnresolvedType[] getUsedFormalTypes() {
+ UnresolvedType[] ret = new UnresolvedType[bindings.length];
+ int index = 0;
+ for (int i = 0, len = bindings.length; i < len; i++) {
+ if (bindings[i] != null) {
+ ret[index++] = ((BindingTypePattern) bindings[i]).getExactType();
+ }
+ }
+ UnresolvedType[] newRet = new UnresolvedType[index];
+ System.arraycopy(ret, 0, newRet, 0, index);
+ // System.out.println("ret: " + index);
+ return newRet;
+ }
+
+ public Bindings copy() {
+ // int len = bindings.length;
+ // boolean[] a = new boolean[len];
+ // System.arraycopy(bindings, 0, a, 0, len);
+ return new Bindings((BindingPattern[]) bindings.clone());
+ }
+
+ public void checkAllBound(IScope scope) {
+ for (int i = 0, len = bindings.length; i < len; i++) {
+ if (bindings[i] == null) {
+ // ATAJ: avoid warnings for implicit bindings
+ if (scope.getFormal(i) instanceof FormalBinding.ImplicitFormalBinding) {
+ bindings[i] = new BindingTypePattern(scope.getFormal(i), false);
+ } else {
+ scope.message(IMessage.ERROR, scope.getFormal(i), "formal unbound in pointcut ");
+ }
+ }
+ }
+
+ }
+
+ public int size() {
+ return bindings.length;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/CflowPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/CflowPointcut.java
new file mode 100644
index 000000000..a83236e5c
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/CflowPointcut.java
@@ -0,0 +1,355 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.util.FileUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.CrosscuttingMembers;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.NameMangler;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedMemberImpl;
+import org.aspectj.weaver.ResolvedPointcutDefinition;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.patterns.ConcreteCflowPointcut.Slot;
+
+public class CflowPointcut extends Pointcut {
+ private final Pointcut entry; // The pointcut inside the cflow() that
+ // represents the 'entry' point
+ boolean isBelow;// Is this cflowbelow?
+ private int[] freeVars;
+
+ /**
+ * Used to indicate that we're in the context of a cflow when concretizing if's
+ *
+ * Will be removed or replaced with something better when we handle this as a non-error
+ */
+ public static final ResolvedPointcutDefinition CFLOW_MARKER = new ResolvedPointcutDefinition(null, 0, null,
+ UnresolvedType.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED));
+
+ public CflowPointcut(Pointcut entry, boolean isBelow, int[] freeVars) {
+ // System.err.println("Building cflow pointcut "+entry.toString());
+ this.entry = entry;
+ this.isBelow = isBelow;
+ this.freeVars = freeVars;
+ pointcutKind = CFLOW;
+ }
+
+ public boolean isCflowBelow() {
+ return isBelow;
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ // enh 76055
+ public Pointcut getEntry() {
+ return entry;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ // ??? this is not maximally efficient
+ return FuzzyBoolean.MAYBE;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.CFLOW);
+ entry.write(s);
+ s.writeBoolean(isBelow);
+ FileUtil.writeIntArray(freeVars, s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+
+ CflowPointcut ret = new CflowPointcut(Pointcut.read(s, context), s.readBoolean(), FileUtil.readIntArray(s));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ CflowPointcut ret = new CflowPointcut(entry.parameterizeWith(typeVariableMap, w), isBelow, freeVars);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ if (bindings == null) {
+ entry.resolveBindings(scope, null);
+ entry.state = RESOLVED;
+ freeVars = new int[0];
+ } else {
+ // ??? for if's sake we might need to be more careful here
+ Bindings entryBindings = new Bindings(bindings.size());
+
+ entry.resolveBindings(scope, entryBindings);
+ entry.state = RESOLVED;
+
+ freeVars = entryBindings.getUsedFormals();
+
+ bindings.mergeIn(entryBindings, scope);
+ }
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof CflowPointcut)) {
+ return false;
+ }
+ CflowPointcut o = (CflowPointcut) other;
+ return o.entry.equals(entry) && o.isBelow == isBelow;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + entry.hashCode();
+ result = 37 * result + (isBelow ? 0 : 1);
+ return result;
+ }
+
+ public String toString() {
+ return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")";
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ throw new RuntimeException("unimplemented - did concretization fail?");
+ }
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+
+ // the pointcut is marked as CONCRETE after returning from this
+ // call - so we can't skip concretization
+ // if (this.entry.state == Pointcut.SYMBOLIC) {
+ // // too early to concretize, return unchanged
+ // return this;
+ // }
+
+ // Enforce rule about which designators are supported in declare
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ inAspect.getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.CFLOW_IN_DECLARE, isBelow ? "below" : ""),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+
+ // make this remap from formal positions to arrayIndices
+ IntMap entryBindings = new IntMap();
+ if (freeVars != null) {
+ for (int i = 0, len = freeVars.length; i < len; i++) {
+ int freeVar = freeVars[i];
+ // int formalIndex = bindings.get(freeVar);
+ entryBindings.put(freeVar, i);
+ }
+ }
+ entryBindings.copyContext(bindings);
+ // System.out.println(this + " bindings: " + entryBindings);
+
+ World world = inAspect.getWorld();
+
+ Pointcut concreteEntry;
+
+ ResolvedType concreteAspect = bindings.getConcreteAspect();
+
+ CrosscuttingMembers xcut = concreteAspect.crosscuttingMembers;
+ Collection<ShadowMunger> previousCflowEntries = xcut.getCflowEntries();
+
+ entryBindings.pushEnclosingDefinition(CFLOW_MARKER);
+ // This block concretizes the pointcut within the cflow pointcut
+ try {
+ concreteEntry = entry.concretize(inAspect, declaringType, entryBindings);
+ } finally {
+ entryBindings.popEnclosingDefinitition();
+ }
+
+ List<ShadowMunger> innerCflowEntries = new ArrayList<ShadowMunger>(xcut.getCflowEntries());
+ innerCflowEntries.removeAll(previousCflowEntries);
+
+ // Four routes of interest through this code (did I hear someone say
+ // refactor??)
+ // 1) no state in the cflow - we can use a counter *and* we have seen
+ // this pointcut
+ // before - so use the same counter as before.
+ // 2) no state in the cflow - we can use a counter, but this is the
+ // first time
+ // we have seen this pointcut, so build the infrastructure.
+ // 3) state in the cflow - we need to use a stack *and* we have seen
+ // this pointcut
+ // before - so share the stack.
+ // 4) state in the cflow - we need to use a stack, but this is the first
+ // time
+ // we have seen this pointcut, so build the infrastructure.
+
+ if (freeVars == null || freeVars.length == 0) { // No state, so don't
+ // use a stack, use a
+ // counter.
+ ResolvedMember localCflowField = null;
+
+ Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "counter");
+
+ // Check if we have already got a counter for this cflow pointcut
+ if (field != null) {
+ localCflowField = (ResolvedMember) field; // Use the one we
+ // already have
+
+ } else {
+
+ // Create a counter field in the aspect
+ localCflowField = new ResolvedMemberImpl(Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC,
+ NameMangler.cflowCounter(xcut), UnresolvedType.forName(NameMangler.CFLOW_COUNTER_TYPE)
+ .getSignature());
+
+ // Create type munger to add field to the aspect
+ concreteAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().makeCflowCounterFieldAdder(
+ localCflowField));
+
+ // Create shadow munger to push stuff onto the stack
+ concreteAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makeCflowEntry(world, concreteEntry, isBelow,
+ localCflowField, freeVars == null ? 0 : freeVars.length, innerCflowEntries, inAspect));
+
+ putCflowfield(xcut, concreteEntry, concreteAspect, localCflowField, "counter"); // Remember
+ // it
+ }
+
+ Pointcut ret = new ConcreteCflowPointcut(concreteAspect, localCflowField, null, true);
+ ret.copyLocationFrom(this);
+ return ret;
+ } else {
+
+ List<Slot> slots = new ArrayList<Slot>();
+
+ for (int i = 0, len = freeVars.length; i < len; i++) {
+ int freeVar = freeVars[i];
+
+ // we don't need to keep state that isn't actually exposed to
+ // advice
+ // ??? this means that we will store some state that we won't
+ // actually use, optimize this later
+ if (!bindings.hasKey(freeVar)) {
+ continue;
+ }
+
+ int formalIndex = bindings.get(freeVar);
+
+ // We need to look in the right place for the type of the
+ // formal. Suppose the advice looks like this:
+ // before(String s): somePointcut(*,s)
+ // where the first argument in somePointcut is of type Number
+ // for free variable 0 we want to ask the pointcut for the type
+ // of its first argument, if we only
+ // ask the advice for the type of its first argument then we'll
+ // get the wrong type (pr86903)
+
+ ResolvedPointcutDefinition enclosingDef = bindings.peekEnclosingDefinition();
+ ResolvedType formalType = null;
+
+ // Is there a useful enclosing pointcut?
+ if (enclosingDef != null && enclosingDef.getParameterTypes().length > 0) {
+ formalType = enclosingDef.getParameterTypes()[freeVar].resolve(world);
+ } else {
+ formalType = bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
+ }
+
+ ConcreteCflowPointcut.Slot slot = new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
+ slots.add(slot);
+ }
+ ResolvedMember localCflowField = null;
+ Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "stack");
+ if (field != null) {
+ localCflowField = (ResolvedMember) field;
+ } else {
+
+ localCflowField = new ResolvedMemberImpl(Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC,
+ NameMangler.cflowStack(xcut), UnresolvedType.forName(NameMangler.CFLOW_STACK_TYPE)
+ .getSignature());
+ // System.out.println("adding field to: " + inAspect + " field "
+ // + cflowField);
+
+ // add field and initializer to inAspect
+ // XXX and then that info above needs to be mapped down here to
+ // help with
+ // XXX getting the exposed state right
+ concreteAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makeCflowEntry(world, concreteEntry, isBelow,
+ localCflowField, freeVars.length, innerCflowEntries, inAspect));
+
+ concreteAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport()
+ .makeCflowStackFieldAdder(localCflowField));
+ putCflowfield(xcut, concreteEntry, concreteAspect, localCflowField, "stack");
+ }
+ Pointcut ret = new ConcreteCflowPointcut(concreteAspect, localCflowField, slots, false);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ }
+
+ private String getKey(Pointcut p, ResolvedType a, String stackOrCounter) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(a.getName());
+ sb.append("::");
+ sb.append(p.toString());
+ sb.append("::");
+ sb.append(stackOrCounter);
+ return sb.toString();
+ }
+
+ private Object getCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect, String stackOrCounter) {
+ String key = getKey(pcutkey, concreteAspect, stackOrCounter);
+ Object o = null;
+ if (isBelow) {
+ o = xcut.getCflowBelowFields().get(key);
+ } else {
+ o = xcut.getCflowFields().get(key);
+ }
+ // System.err.println("Retrieving for key "+key+" returning "+o);
+ return o;
+ }
+
+ private void putCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect, Object o,
+ String stackOrCounter) {
+ String key = getKey(pcutkey, concreteAspect, stackOrCounter);
+ // System.err.println("Storing cflow field for key"+key);
+ if (isBelow) {
+ xcut.getCflowBelowFields().put(key, o);
+ } else {
+ xcut.getCflowFields().put(key, o);
+ }
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
new file mode 100644
index 000000000..09208f9c2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
@@ -0,0 +1,184 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.MemberImpl;
+import org.aspectj.weaver.NameMangler;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Test;
+
+public class ConcreteCflowPointcut extends Pointcut {
+ private final Member cflowField;
+ List<Slot> slots; // exposed for testing
+ boolean usesCounter;
+ ResolvedType aspect;
+
+ // Can either use a counter or a stack to implement cflow.
+ public ConcreteCflowPointcut(ResolvedType aspect, Member cflowField, List<Slot> slots, boolean usesCounter) {
+ this.aspect = aspect;
+ this.cflowField = cflowField;
+ this.slots = slots;
+ this.usesCounter = usesCounter;
+ this.pointcutKind = CFLOW;
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ // ??? this is not maximally efficient
+ // Check we'll be able to do the residue!
+
+ // this bit is for pr145693 - we cannot match at all if one of the types is missing, we will be unable
+ // to create the residue
+ if (slots != null) {
+ for (Slot slot: slots) {
+ ResolvedType rt = slot.formalType;
+ if (rt.isMissing()) {
+ ISourceLocation[] locs = new ISourceLocation[] { getSourceLocation() };
+ Message m = new Message(WeaverMessages.format(WeaverMessages.MISSING_TYPE_PREVENTS_MATCH, rt.getName()), "",
+ Message.WARNING, shadow.getSourceLocation(), null, locs);
+ rt.getWorld().getMessageHandler().handleMessage(m);
+ return FuzzyBoolean.NO;
+ }
+ }
+ }
+ return FuzzyBoolean.MAYBE;
+ }
+
+ // used by weaver when validating bindings
+ public int[] getUsedFormalSlots() {
+ if (slots == null) {
+ return new int[0];
+ }
+ int[] indices = new int[slots.size()];
+ for (int i = 0; i < indices.length; i++) {
+ indices[i] = ((Slot) slots.get(i)).formalIndex;
+ }
+ return indices;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof ConcreteCflowPointcut)) {
+ return false;
+ }
+ ConcreteCflowPointcut o = (ConcreteCflowPointcut) other;
+ return o.cflowField.equals(this.cflowField);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + cflowField.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return "concretecflow(" + cflowField + ")";
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ // System.out.println("find residue: " + this);
+ if (usesCounter) {
+ return Test.makeFieldGetCall(cflowField, cflowCounterIsValidMethod, Expr.NONE);
+ } else {
+ if (slots != null) { // null for cflows managed by counters
+ for (Slot slot: slots) {
+ // System.out.println("slot: " + slot.formalIndex);
+ state.set(slot.formalIndex,
+ aspect.getWorld().getWeavingSupport().makeCflowAccessVar(slot.formalType, cflowField, slot.arrayIndex));
+ }
+ }
+ return Test.makeFieldGetCall(cflowField, cflowStackIsValidMethod, Expr.NONE);
+ }
+ }
+
+ private static final Member cflowStackIsValidMethod = MemberImpl.method(NameMangler.CFLOW_STACK_UNRESOLVEDTYPE, 0,
+ UnresolvedType.BOOLEAN, "isValid", UnresolvedType.NONE);
+
+ private static final Member cflowCounterIsValidMethod = MemberImpl.method(NameMangler.CFLOW_COUNTER_UNRESOLVEDTYPE, 0,
+ UnresolvedType.BOOLEAN, "isValid", UnresolvedType.NONE);
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public static class Slot {
+ int formalIndex;
+ ResolvedType formalType;
+ int arrayIndex;
+
+ public Slot(int formalIndex, ResolvedType formalType, int arrayIndex) {
+ this.formalIndex = formalIndex;
+ this.formalType = formalType;
+ this.arrayIndex = arrayIndex;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof Slot)) {
+ return false;
+ }
+
+ Slot o = (Slot) other;
+ return o.formalIndex == this.formalIndex && o.arrayIndex == this.arrayIndex && o.formalType.equals(this.formalType);
+ }
+
+ public int hashCode() {
+ int result = 19;
+ result = 37 * result + formalIndex;
+ result = 37 * result + arrayIndex;
+ result = 37 * result + formalType.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return "Slot(" + formalIndex + ", " + formalType + ", " + arrayIndex + ")";
+ }
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Declare.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Declare.java
new file mode 100644
index 000000000..48769fcb6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Declare.java
@@ -0,0 +1,89 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public abstract class Declare extends PatternNode {
+ public static final byte ERROR_OR_WARNING = 1;
+ public static final byte PARENTS = 2;
+ public static final byte SOFT = 3;
+ public static final byte DOMINATES = 4;
+ public static final byte ANNOTATION = 5;
+ public static final byte PARENTSMIXIN = 6;
+ public static final byte TYPE_ERROR_OR_WARNING = 7;
+
+ // set when reading declare from aspect
+ private ResolvedType declaringType;
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte kind = s.readByte();
+ switch (kind) {
+ case ERROR_OR_WARNING:
+ return DeclareErrorOrWarning.read(s, context);
+ case DOMINATES:
+ return DeclarePrecedence.read(s, context);
+ case PARENTS:
+ return DeclareParents.read(s, context);
+ case SOFT:
+ return DeclareSoft.read(s, context);
+ case ANNOTATION:
+ return DeclareAnnotation.read(s, context);
+ case PARENTSMIXIN:
+ return DeclareParentsMixin.read(s, context);
+ case TYPE_ERROR_OR_WARNING:
+ return DeclareTypeErrorOrWarning.read(s, context);
+ default:
+ throw new RuntimeException("unimplemented");
+ }
+ }
+
+ /**
+ * Returns this declare mutated
+ */
+ public abstract void resolve(IScope scope);
+
+ /**
+ * Returns a version of this declare element in which all references to type variables are replaced with their bindings given in
+ * the map.
+ */
+ public abstract Declare parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World w);
+
+ /**
+ * Indicates if this declare should be treated like advice. If true, the declare will have no effect in an abstract aspect. It
+ * will be inherited by any concrete aspects and will have an effect for each concrete aspect it is ultimately inherited by.
+ */
+ public abstract boolean isAdviceLike();
+
+ /**
+ * Declares have methods in the .class file against which info can be stored (for example, the annotation in the case of declare
+ * annotation). The name is of the form ajc$declare_XXX_NNN where XXX can optionally be set in this 'getNameSuffix()' method -
+ * depending on whether, at weave time, we want to easily differentiate between the declare methods.
+ */
+ public abstract String getNameSuffix();
+
+ public void setDeclaringType(ResolvedType aType) {
+ this.declaringType = aType;
+ }
+
+ public ResolvedType getDeclaringType() {
+ return declaringType;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareAnnotation.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareAnnotation.java
new file mode 100644
index 000000000..ba1d29415
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareAnnotation.java
@@ -0,0 +1,537 @@
+/* *******************************************************************
+ * Copyright (c) 2005 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer initial implementation
+ * Andy Clement got it working
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.AnnotationAJ;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * Represents a declare annotation statement, one of atField, atMethod, atConstructor or atType.
+ *
+ * @author Andy Clement
+ */
+public class DeclareAnnotation extends Declare {
+
+ public static final Kind AT_TYPE = new Kind(1, "type");
+ public static final Kind AT_FIELD = new Kind(2, "field");
+ public static final Kind AT_METHOD = new Kind(3, "method");
+ public static final Kind AT_CONSTRUCTOR = new Kind(4, "constructor");
+ public static final Kind AT_REMOVE_FROM_FIELD = new Kind(5, "removeFromField");
+
+ private Kind kind;
+ // for declare @type
+ private TypePattern typePattern;
+ // for declare @field,@method,@constructor
+ private ISignaturePattern signaturePattern;
+ private ResolvedType containingAspect;
+ private List<String> annotationMethods;
+ private List<String> annotationStrings;
+ private AnnotationAJ annotation; // discovered when required
+ private ResolvedType annotationType; // discovered when required
+
+ // not serialized:
+ private int annotationStart;
+ private int annotationEnd;
+
+ /**
+ * Constructor for declare atType.
+ */
+ public DeclareAnnotation(Kind kind, TypePattern typePattern) {
+ this.typePattern = typePattern;
+ this.kind = kind;
+ init();
+ }
+
+ /**
+ * Constructor for declare atMethod/atField/atConstructor.
+ */
+ public DeclareAnnotation(Kind kind, ISignaturePattern sigPattern) {
+ this.signaturePattern = sigPattern;
+ this.kind = kind;
+ init();
+ }
+
+ private void init() {
+ this.annotationMethods = new ArrayList<String>();
+ annotationMethods.add("unknown");
+ this.annotationStrings = new ArrayList<String>();
+ annotationStrings.add("@<annotation>");
+ }
+
+ /**
+ * Returns the string, useful before the real annotation has been resolved
+ */
+ public String getAnnotationString() {
+ return annotationStrings.get(0);
+ }
+
+ public boolean isExactPattern() {
+ return typePattern instanceof ExactTypePattern;
+ }
+
+ public String getAnnotationMethod() {
+ return annotationMethods.get(0);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder ret = new StringBuilder();
+ ret.append("declare @");
+ ret.append(kind);
+ ret.append(" : ");
+ ret.append(typePattern != null ? typePattern.toString() : signaturePattern.toString());
+ ret.append(" : ");
+ ret.append(annotationStrings.get(0));
+ return ret.toString();
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public void resolve(IScope scope) {
+ if (!scope.getWorld().isInJava5Mode()) {
+ String msg = null;
+ if (kind == AT_TYPE) {
+ msg = WeaverMessages.DECLARE_ATTYPE_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
+ } else if (kind == AT_METHOD) {
+ msg = WeaverMessages.DECLARE_ATMETHOD_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
+ } else if (kind == AT_FIELD) {
+ msg = WeaverMessages.DECLARE_ATFIELD_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
+ } else if (kind == AT_CONSTRUCTOR) {
+ msg = WeaverMessages.DECLARE_ATCONS_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
+ }
+ scope.message(MessageUtil.error(WeaverMessages.format(msg), getSourceLocation()));
+ return;
+ }
+ if (typePattern != null) {
+ typePattern = typePattern.resolveBindings(scope, Bindings.NONE, false, false);
+ }
+ if (signaturePattern != null) {
+ signaturePattern = signaturePattern.resolveBindings(scope, Bindings.NONE);
+ }
+ this.containingAspect = scope.getEnclosingType();
+ }
+
+ @Override
+ public Declare parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World w) {
+ DeclareAnnotation ret;
+ if (this.kind == AT_TYPE) {
+ ret = new DeclareAnnotation(kind, this.typePattern.parameterizeWith(typeVariableBindingMap, w));
+ } else {
+ ret = new DeclareAnnotation(kind, this.signaturePattern.parameterizeWith(typeVariableBindingMap, w));
+ }
+ ret.annotationMethods = this.annotationMethods;
+ ret.annotationStrings = this.annotationStrings;
+ ret.annotation = this.annotation;
+ ret.containingAspect = this.containingAspect;
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public boolean isAdviceLike() {
+ return false;
+ }
+
+ public void setAnnotationString(String annotationString) {
+ this.annotationStrings.set(0, annotationString);
+ }
+
+ public void setAnnotationLocation(int start, int end) {
+ this.annotationStart = start;
+ this.annotationEnd = end;
+ }
+
+ public int getAnnotationSourceStart() {
+ return annotationStart;
+ }
+
+ public int getAnnotationSourceEnd() {
+ return annotationEnd;
+ }
+
+ public void setAnnotationMethod(String methodName) {
+ this.annotationMethods.set(0, methodName);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof DeclareAnnotation)) {
+ return false;
+ }
+ DeclareAnnotation other = (DeclareAnnotation) obj;
+ if (!this.kind.equals(other.kind)) {
+ return false;
+ }
+ if (!this.annotationStrings.get(0).equals(other.annotationStrings.get(0))) {
+ return false;
+ }
+ if (!this.annotationMethods.get(0).equals(other.annotationMethods.get(0))) {
+ return false;
+ }
+ if (this.typePattern != null) {
+ if (!typePattern.equals(other.typePattern)) {
+ return false;
+ }
+ }
+ if (this.signaturePattern != null) {
+ if (!signaturePattern.equals(other.signaturePattern)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 19;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + annotationStrings.get(0).hashCode();
+ result = 37 * result + annotationMethods.get(0).hashCode();
+ if (typePattern != null) {
+ result = 37 * result + typePattern.hashCode();
+ }
+ if (signaturePattern != null) {
+ result = 37 * result + signaturePattern.hashCode();
+ }
+ return result;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Declare.ANNOTATION);
+ if (kind.id == AT_FIELD.id && isRemover) {
+ s.writeInt(AT_REMOVE_FROM_FIELD.id);
+ } else {
+ s.writeInt(kind.id);
+ }
+ int max = 0;
+ s.writeByte(max = annotationStrings.size());
+ for (int i = 0; i < max; i++) {
+ s.writeUTF(annotationStrings.get(i));
+ }
+ s.writeByte(max = annotationMethods.size());
+ for (int i = 0; i < max; i++) {
+ s.writeUTF(annotationMethods.get(i));
+ }
+ if (typePattern != null) {
+ typePattern.write(s);
+ }
+ if (signaturePattern != null) {
+ AbstractSignaturePattern.writeCompoundSignaturePattern(s, signaturePattern);
+ }
+ writeLocation(s);
+ }
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ DeclareAnnotation ret = null;
+ boolean isRemover = false;
+ int kind = s.readInt();
+ if (kind == AT_REMOVE_FROM_FIELD.id) {
+ kind = AT_FIELD.id;
+ isRemover = true;
+ }
+ // old format was just a single string and method
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
+ // int numAnnotationStrings =
+ s.readByte();
+ }
+ String annotationString = s.readUTF();
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
+ // int numAnnotationMethods =
+ s.readByte();
+ }
+ String annotationMethod = s.readUTF();
+ TypePattern tp = null;
+ SignaturePattern sp = null;
+ switch (kind) {
+ case 1:
+ tp = TypePattern.read(s, context);
+ ret = new DeclareAnnotation(AT_TYPE, tp);
+ break;
+ case 2:
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
+ ret = new DeclareAnnotation(AT_FIELD, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
+ } else {
+ sp = SignaturePattern.read(s, context);
+ ret = new DeclareAnnotation(AT_FIELD, sp);
+ }
+ if (isRemover) {
+ ret.setRemover(true);
+ }
+ break;
+ case 3:
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
+ ret = new DeclareAnnotation(AT_METHOD, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
+ } else {
+ sp = SignaturePattern.read(s, context);
+ ret = new DeclareAnnotation(AT_METHOD, sp);
+ }
+ break;
+ case 4:
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
+ ret = new DeclareAnnotation(AT_CONSTRUCTOR, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
+ } else {
+ sp = SignaturePattern.read(s, context);
+ ret = new DeclareAnnotation(AT_CONSTRUCTOR, sp);
+ }
+ break;
+
+ }
+ ret.setAnnotationString(annotationString);
+ ret.setAnnotationMethod(annotationMethod);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ /**
+ * For declare atConstructor, atMethod, atField
+ */
+ public boolean matches(ResolvedMember resolvedmember, World world) {
+ if (kind == AT_METHOD || kind == AT_CONSTRUCTOR) {
+ if (resolvedmember != null && resolvedmember.getName().charAt(0) == '<') {
+ // <clinit> or <init>
+ if (kind == AT_METHOD) {
+ return false;
+ }
+ }
+ }
+ return signaturePattern.matches(resolvedmember, world, false);
+ }
+
+ /**
+ * For declare atType.
+ */
+ public boolean matches(ResolvedType type) {
+ if (!typePattern.matchesStatically(type)) {
+ return false;
+ }
+ if (type.getWorld().getLint().typeNotExposedToWeaver.isEnabled() && !type.isExposedToWeaver()) {
+ type.getWorld().getLint().typeNotExposedToWeaver.signal(type.getName(), getSourceLocation());
+ }
+ return true;
+ }
+
+ public void setAspect(ResolvedType typeX) {
+ containingAspect = typeX;
+ }
+
+ public UnresolvedType getAspect() {
+ return containingAspect;
+ }
+
+ public void copyAnnotationTo(ResolvedType onType) {
+ ensureAnnotationDiscovered();
+ if (!onType.hasAnnotation(annotation.getType())) {
+ onType.addAnnotation(annotation);
+ }
+ }
+
+ public AnnotationAJ getAnnotation() {
+ ensureAnnotationDiscovered();
+ return annotation;
+ }
+
+ /**
+ * The annotation specified in the declare @type is stored against a simple method of the form "ajc$declare_<NN>", this method
+ * finds that method and retrieves the annotation
+ */
+ private void ensureAnnotationDiscovered() {
+ if (annotation != null) {
+ return;
+ }
+ String annotationMethod = annotationMethods.get(0);
+ for (Iterator<ResolvedMember> iter = containingAspect.getMethods(true, true); iter.hasNext();) {
+ ResolvedMember member = iter.next();
+ if (member.getName().equals(annotationMethod)) {
+ AnnotationAJ[] annos = member.getAnnotations();
+ if (annos == null) {
+ // if weaving broken code, this can happen
+ return;
+ }
+ int idx = 0;
+ if (annos.length > 0
+ && annos[0].getType().getSignature().equals("Lorg/aspectj/internal/lang/annotation/ajcDeclareAnnotation;")) {
+ idx = 1;
+ }
+ annotation = annos[idx];
+ break;
+ }
+ }
+ }
+
+ public TypePattern getTypePattern() {
+ return typePattern;
+ }
+
+ public ISignaturePattern getSignaturePattern() {
+ return signaturePattern;
+ }
+
+ public boolean isStarredAnnotationPattern() {
+ if (typePattern != null) {
+ return typePattern.isStarAnnotation();
+ } else {
+ return signaturePattern.isStarAnnotation();
+ }
+ }
+
+ public Kind getKind() {
+ return kind;
+ }
+
+ public boolean isDeclareAtConstuctor() {
+ return kind.equals(AT_CONSTRUCTOR);
+ }
+
+ public boolean isDeclareAtMethod() {
+ return kind.equals(AT_METHOD);
+ }
+
+ public boolean isDeclareAtType() {
+ return kind.equals(AT_TYPE);
+ }
+
+ public boolean isDeclareAtField() {
+ return kind.equals(AT_FIELD);
+ }
+
+ /**
+ * @return the type of the annotation
+ */
+ public ResolvedType getAnnotationType() {
+ if (annotationType == null) {
+ String annotationMethod = annotationMethods.get(0);
+ for (Iterator<ResolvedMember> iter = containingAspect.getMethods(true, true); iter.hasNext();) {
+ ResolvedMember member = iter.next();
+ if (member.getName().equals(annotationMethod)) {
+ ResolvedType[] annoTypes = member.getAnnotationTypes();
+ if (annoTypes == null) {
+ // if weaving broken code, this can happen
+ return null;
+ }
+ int idx = 0;
+ if (annoTypes[0].getSignature().equals("Lorg/aspectj/internal/lang/annotation/ajcDeclareAnnotation;")) {
+ idx = 1;
+ }
+ annotationType = annoTypes[idx];
+ break;
+ }
+ }
+ }
+ return annotationType;
+ }
+
+ /**
+ * @return true if the annotation specified is allowed on a field
+ */
+ public boolean isAnnotationAllowedOnField() {
+ ensureAnnotationDiscovered();
+ return annotation.allowedOnField();
+ }
+
+ public String getPatternAsString() {
+ if (signaturePattern != null) {
+ return signaturePattern.toString();
+ }
+ if (typePattern != null) {
+ return typePattern.toString();
+ }
+ return "DONT KNOW";
+ }
+
+ /**
+ * Return true if this declare annotation could ever match something in the specified type - only really able to make
+ * intelligent decision if a type was specified in the sig/type pattern signature.
+ */
+ public boolean couldEverMatch(ResolvedType type) {
+ // Haven't implemented variant for typePattern (doesn't seem worth it!)
+ // BUGWARNING This test might not be sufficient for funny cases relating
+ // to interfaces and the use of '+' - but it seems really important to
+ // do something here so we don't iterate over all fields and all methods
+ // in all types exposed to the weaver! So look out for bugs here and
+ // we can update the test as appropriate.
+ if (signaturePattern != null) {
+ return signaturePattern.couldEverMatch(type);
+ }
+ return true;
+ }
+
+ /**
+ * Provide a name suffix so that we can tell the different declare annotations forms apart in the AjProblemReporter
+ */
+ @Override
+ public String getNameSuffix() {
+ return getKind().toString();
+ }
+
+ /**
+ * Captures type of declare annotation (method/type/field/constructor)
+ */
+ public static class Kind {
+ private final int id;
+ private String s;
+
+ private Kind(int n, String name) {
+ id = n;
+ s = name;
+ }
+
+ @Override
+ public int hashCode() {
+ return (19 + 37 * id);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Kind)) {
+ return false;
+ }
+ Kind other = (Kind) obj;
+ return other.id == id;
+ }
+
+ @Override
+ public String toString() {
+ return "at_" + s;
+ }
+ }
+
+ boolean isRemover = false;
+
+ public void setRemover(boolean b) {
+ isRemover = b;
+ }
+
+ public boolean isRemover() {
+ return isRemover;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareErrorOrWarning.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareErrorOrWarning.java
new file mode 100644
index 000000000..0a46fa1e9
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareErrorOrWarning.java
@@ -0,0 +1,130 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public class DeclareErrorOrWarning extends Declare {
+ private boolean isError;
+ private Pointcut pointcut;
+ private String message;
+
+ public DeclareErrorOrWarning(boolean isError, Pointcut pointcut, String message) {
+ this.isError = isError;
+ this.pointcut = pointcut;
+ this.message = message;
+ }
+
+ /**
+ * returns "declare warning: <message>" or "declare error: <message>"
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare ");
+ if (isError) {
+ buf.append("error: ");
+ } else {
+ buf.append("warning: ");
+ }
+ buf.append(pointcut);
+ buf.append(": ");
+ buf.append("\"");
+ buf.append(message);
+ buf.append("\";");
+ return buf.toString();
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof DeclareErrorOrWarning)) {
+ return false;
+ }
+ DeclareErrorOrWarning o = (DeclareErrorOrWarning) other;
+ return (o.isError == isError) && o.pointcut.equals(pointcut) && o.message.equals(message);
+ }
+
+ public int hashCode() {
+ int result = isError ? 19 : 23;
+ result = 37 * result + pointcut.hashCode();
+ result = 37 * result + message.hashCode();
+ return result;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Declare.ERROR_OR_WARNING);
+ s.writeBoolean(isError);
+ pointcut.write(s);
+ s.writeUTF(message);
+ writeLocation(s);
+ }
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ Declare ret = new DeclareErrorOrWarning(s.readBoolean(), Pointcut.read(s, context), s.readUTF());
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public boolean isError() {
+ return isError;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public Pointcut getPointcut() {
+ return pointcut;
+ }
+
+ public void resolve(IScope scope) {
+ pointcut = pointcut.resolve(scope);
+ }
+
+ public Declare parameterizeWith(Map<String,UnresolvedType> typeVariableBindingMap, World w) {
+ Declare ret = new DeclareErrorOrWarning(isError, pointcut.parameterizeWith(typeVariableBindingMap, w), message);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public boolean isAdviceLike() {
+ return true;
+ }
+
+ public String getNameSuffix() {
+ return "eow";
+ }
+
+ /**
+ * returns "declare warning" or "declare error"
+ */
+ public String getName() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare ");
+ if (isError) {
+ buf.append("error");
+ } else {
+ buf.append("warning");
+ }
+ return buf.toString();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParents.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParents.java
new file mode 100644
index 000000000..53553afb3
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParents.java
@@ -0,0 +1,364 @@
+/* *******************************************************************
+ * Copyright (c) 2002-2019 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * @author Thomas Kiviaho
+ * @author Andy Clement
+ * @author PARC
+ */
+public class DeclareParents extends Declare {
+ protected TypePattern child;
+ protected TypePatternList parents;
+ private boolean isWildChild = false;
+ protected boolean isExtends = true;
+
+ public DeclareParents(TypePattern child, List<TypePattern> parents, boolean isExtends) {
+ this(child, new TypePatternList(parents), isExtends);
+ }
+
+ protected DeclareParents(TypePattern child, TypePatternList parents, boolean isExtends) {
+ this.child = child;
+ this.parents = parents;
+ this.isExtends = isExtends;
+ WildChildFinder wildChildFinder = new WildChildFinder();
+ child.accept(wildChildFinder, null);
+ isWildChild = wildChildFinder.containedWildChild();
+ }
+
+ public boolean match(ResolvedType typeX) {
+ if (!child.matchesStatically(typeX)) {
+ return false;
+ }
+ if (typeX.getWorld().getLint().typeNotExposedToWeaver.isEnabled() && !typeX.isExposedToWeaver()) {
+ typeX.getWorld().getLint().typeNotExposedToWeaver.signal(typeX.getName(), getSourceLocation());
+ }
+
+ return true;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public Declare parameterizeWith(Map<String,UnresolvedType> typeVariableBindingMap, World w) {
+ DeclareParents ret = new DeclareParents(child.parameterizeWith(typeVariableBindingMap, w), parents.parameterizeWith(
+ typeVariableBindingMap, w), isExtends);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare parents: ");
+ buf.append(child);
+ buf.append(isExtends ? " extends " : " implements "); // extends and implements are treated equivalently
+ buf.append(parents);
+ buf.append(";");
+ return buf.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof DeclareParents)) {
+ return false;
+ }
+ DeclareParents o = (DeclareParents) other;
+ return o.child.equals(child) && o.parents.equals(parents);
+ }
+
+ // ??? cache this
+ @Override
+ public int hashCode() {
+ int result = 23;
+ result = 37 * result + child.hashCode();
+ result = 37 * result + parents.hashCode();
+ return result;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Declare.PARENTS);
+ child.write(s);
+ parents.write(s);
+ writeLocation(s);
+ }
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ DeclareParents ret = new DeclareParents(TypePattern.read(s, context), TypePatternList.read(s, context), true);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public boolean parentsIncludeInterface(World w) {
+ for (int i = 0; i < parents.size(); i++) {
+ if (parents.get(i).getExactType().resolve(w).isInterface()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean parentsIncludeClass(World w) {
+ for (int i = 0; i < parents.size(); i++) {
+ if (parents.get(i).getExactType().resolve(w).isClass()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void resolve(IScope scope) {
+ TypePattern resolvedChild = child.resolveBindings(scope, Bindings.NONE, false, false);
+ if (!resolvedChild.equals(child)) {
+ WildChildFinder wildChildFinder = new WildChildFinder();
+ resolvedChild.accept(wildChildFinder, null);
+ isWildChild = wildChildFinder.containedWildChild();
+ this.child = resolvedChild;
+ }
+ parents = parents.resolveBindings(scope, Bindings.NONE, false, true);
+ // Could assert this ...
+ // for (int i=0; i < parents.size(); i++) {
+ // parents.get(i).assertExactType(scope.getMessageHandler());
+ // }
+ }
+
+ public TypePatternList getParents() {
+ return parents;
+ }
+
+ public TypePattern getChild() {
+ return child;
+ }
+
+ // note - will always return true after deserialization, this doesn't affect weaver
+ public boolean isExtends() {
+ return this.isExtends;
+ }
+
+ @Override
+ public boolean isAdviceLike() {
+ return false;
+ }
+
+ private ResolvedType maybeGetNewParent(ResolvedType targetType, TypePattern typePattern, World world, boolean reportErrors) {
+ if (typePattern == TypePattern.NO) {
+ return null; // already had an error here
+ }
+
+ // isWildChild = (child instanceof WildTypePattern);
+ UnresolvedType iType = typePattern.getExactType();
+ ResolvedType parentType = iType.resolve(world);
+
+ if (targetType.equals(world.getCoreType(UnresolvedType.OBJECT))) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.DECP_OBJECT), this.getSourceLocation(), null);
+ return null;
+ }
+
+ // Ensure the target doesn't already have an
+ // alternate parameterization of the generic type on it
+ if (parentType.isParameterizedType() || parentType.isRawType()) {
+ // Let's take a look at the parents we already have
+ boolean isOK = verifyNoInheritedAlternateParameterization(targetType, parentType, world);
+ if (!isOK) {
+ return null;
+ }
+ }
+
+ if (parentType.isAssignableFrom(targetType)) {
+ return null; // already a parent
+ }
+
+ // Enum types that are targetted for decp through a wild type pattern get linted
+ if (reportErrors && isWildChild && targetType.isEnum()) {
+ world.getLint().enumAsTargetForDecpIgnored.signal(targetType.toString(), getSourceLocation());
+ }
+
+ // Annotation types that are targetted for decp through a wild type pattern get linted
+ if (reportErrors && isWildChild && targetType.isAnnotation()) {
+ world.getLint().annotationAsTargetForDecpIgnored.signal(targetType.toString(), getSourceLocation());
+ }
+
+ // 1. Can't use decp to make an enum/annotation type implement an interface
+ if (targetType.isEnum() && parentType.isInterface()) {
+ if (reportErrors && !isWildChild) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ENUM_TO_IMPL_INTERFACE,
+ targetType), getSourceLocation(), null);
+ }
+ return null;
+ }
+ if (targetType.isAnnotation() && parentType.isInterface()) {
+ if (reportErrors && !isWildChild) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ANNOTATION_TO_IMPL_INTERFACE,
+ targetType), getSourceLocation(), null);
+ }
+ return null;
+ }
+
+ // 2. Can't use decp to change supertype of an enum/annotation
+ if (targetType.isEnum() && parentType.isClass()) {
+ if (reportErrors && !isWildChild) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ENUM_TO_EXTEND_CLASS,
+ targetType), getSourceLocation(), null);
+ }
+ return null;
+ }
+ if (targetType.isAnnotation() && parentType.isClass()) {
+ if (reportErrors && !isWildChild) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_DECP_ON_ANNOTATION_TO_EXTEND_CLASS,
+ targetType), getSourceLocation(), null);
+ }
+ return null;
+ }
+
+ // 3. Can't use decp to declare java.lang.Enum/java.lang.annotation.Annotation as the parent of a type
+ if (parentType.getSignature().equals(UnresolvedType.ENUM.getSignature())) {
+ if (reportErrors && !isWildChild) {
+ world.showMessage(IMessage.ERROR, WeaverMessages
+ .format(WeaverMessages.CANT_DECP_TO_MAKE_ENUM_SUPERTYPE, targetType), getSourceLocation(), null);
+ }
+ return null;
+ }
+ if (parentType.getSignature().equals(UnresolvedType.ANNOTATION.getSignature())) {
+ if (reportErrors && !isWildChild) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_DECP_TO_MAKE_ANNOTATION_SUPERTYPE,
+ targetType), getSourceLocation(), null);
+ }
+ return null;
+ }
+
+ if (parentType.isAssignableFrom(targetType)) {
+ return null; // already a parent
+ }
+
+ if (targetType.isAssignableFrom(parentType)) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_EXTEND_SELF, targetType.getName()), this
+ .getSourceLocation(), null);
+ return null;
+ }
+
+ if (parentType.isClass()) {
+ if (targetType.isInterface()) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.INTERFACE_CANT_EXTEND_CLASS), this
+ .getSourceLocation(), null);
+ return null;
+ // how to handle xcutting errors???
+ }
+
+ if (!targetType.getSuperclass().isAssignableFrom(parentType)) {
+ world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.DECP_HIERARCHY_ERROR, iType.getName(),
+ targetType.getSuperclass().getName()), this.getSourceLocation(), null);
+ return null;
+ } else {
+ return parentType;
+ }
+ } else {
+ return parentType;
+ }
+ }
+
+ /**
+ * This method looks through the type hierarchy for some target type - it is attempting to find an existing parameterization
+ * that clashes with the new parent that the user wants to apply to the type. If it finds an existing parameterization that
+ * matches the new one, it silently completes, if it finds one that clashes (e.g. a type already has A<String> when the user
+ * wants to add A<Number>) then it will produce an error.
+ *
+ * It uses recursion and exits recursion on hitting 'jlObject'
+ *
+ * Related bugzilla entries: pr110788
+ */
+ private boolean verifyNoInheritedAlternateParameterization(ResolvedType typeToVerify, ResolvedType newParent, World world) {
+
+ if (typeToVerify.equals(ResolvedType.OBJECT)) {
+ return true;
+ }
+
+ ResolvedType newParentGenericType = newParent.getGenericType();
+ Iterator<ResolvedType> iter = typeToVerify.getDirectSupertypes();
+ while (iter.hasNext()) {
+ ResolvedType supertype = iter.next();
+ if (((supertype.isRawType() && newParent.isParameterizedType()) || (supertype.isParameterizedType() && newParent
+ .isRawType()))
+ && newParentGenericType.equals(supertype.getGenericType())) {
+ // new parent is a parameterized type, but this is a raw type
+ world.getMessageHandler().handleMessage(
+ new Message(WeaverMessages.format(WeaverMessages.CANT_DECP_MULTIPLE_PARAMETERIZATIONS, newParent.getName(),
+ typeToVerify.getName(), supertype.getName()), getSourceLocation(), true,
+ new ISourceLocation[] { typeToVerify.getSourceLocation() }));
+ return false;
+ }
+ if (supertype.isParameterizedType()) {
+ ResolvedType generictype = supertype.getGenericType();
+
+ // If the generic types are compatible but the parameterizations aren't then we have a problem
+ if (generictype.isAssignableFrom(newParentGenericType) && !supertype.isAssignableFrom(newParent)) {
+ world.getMessageHandler().handleMessage(
+ new Message(WeaverMessages.format(WeaverMessages.CANT_DECP_MULTIPLE_PARAMETERIZATIONS, newParent
+ .getName(), typeToVerify.getName(), supertype.getName()), getSourceLocation(), true,
+ new ISourceLocation[] { typeToVerify.getSourceLocation() }));
+ return false;
+ }
+ }
+ if (!verifyNoInheritedAlternateParameterization(supertype, newParent, world)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public List<ResolvedType> findMatchingNewParents(ResolvedType onType, boolean reportErrors) {
+ if (onType.isRawType()) {
+ onType = onType.getGenericType();
+ }
+ if (!match(onType)) {
+ return Collections.emptyList();
+ }
+
+ List<ResolvedType> ret = new ArrayList<ResolvedType>();
+ for (int i = 0; i < parents.size(); i++) {
+ ResolvedType t = maybeGetNewParent(onType, parents.get(i), onType.getWorld(), reportErrors);
+ if (t != null) {
+ ret.add(t);
+ }
+ }
+
+ return ret;
+ }
+
+ @Override
+ public String getNameSuffix() {
+ return "parents";
+ }
+
+ public boolean isMixin() {
+ return false;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParentsMixin.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParentsMixin.java
new file mode 100644
index 000000000..9c2db1156
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareParentsMixin.java
@@ -0,0 +1,83 @@
+/* *******************************************************************
+ * Copyright (c) 2009 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * initial implementation Andy Clement
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.VersionedDataInputStream;
+
+/**
+ * Constructed based on an @DeclareMixin being found in an aspect.
+ *
+ * @author Andy Clement
+ */
+public class DeclareParentsMixin extends DeclareParents {
+ private int bitflags = 0x0000; // for future expansion
+
+ public DeclareParentsMixin(TypePattern child, List parents) {
+ super(child, parents, true);
+ }
+
+ public DeclareParentsMixin(TypePattern child, TypePatternList parents) {
+ super(child, parents, true);
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof DeclareParentsMixin)) {
+ return false;
+ }
+ DeclareParentsMixin o = (DeclareParentsMixin) other;
+ return o.child.equals(child) && o.parents.equals(parents) && o.bitflags == bitflags;
+ }
+
+ public int hashCode() {
+ int result = 23;
+ result = 37 * result + child.hashCode();
+ result = 37 * result + parents.hashCode();
+ result = 37 * result + bitflags;
+ return result;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Declare.PARENTSMIXIN);
+ child.write(s);
+ parents.write(s);
+ writeLocation(s);
+ s.writeInt(bitflags);
+ }
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ DeclareParentsMixin ret = new DeclareParentsMixin(TypePattern.read(s, context), TypePatternList.read(s, context));
+ ret.readLocation(context, s);
+ ret.bitflags = s.readInt();
+ return ret;
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare parents mixin: ");
+ buf.append(child);
+ buf.append(" implements ");
+ buf.append(parents);
+ buf.append(";");
+ buf.append("bits=0x").append(Integer.toHexString(bitflags));
+ return buf.toString();
+ }
+
+ public boolean isMixin() {
+ return true;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclarePrecedence.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclarePrecedence.java
new file mode 100644
index 000000000..678ea89e6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclarePrecedence.java
@@ -0,0 +1,197 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+public class DeclarePrecedence extends Declare {
+ private TypePatternList patterns;
+ private IScope scope = null; // non-null means it has not yet been resolved (used by annotation style lazy resolution)
+
+ public DeclarePrecedence(List patterns) {
+ this(new TypePatternList(patterns));
+ }
+
+ private DeclarePrecedence(TypePatternList patterns) {
+ this.patterns = patterns;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Declare parameterizeWith(Map typeVariableBindingMap, World w) {
+ DeclarePrecedence ret = new DeclarePrecedence(this.patterns.parameterizeWith(typeVariableBindingMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare precedence: ");
+ buf.append(patterns);
+ buf.append(";");
+ return buf.toString();
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof DeclarePrecedence)) {
+ return false;
+ }
+ DeclarePrecedence o = (DeclarePrecedence) other;
+ return o.patterns.equals(patterns);
+ }
+
+ public int hashCode() {
+ return patterns.hashCode();
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Declare.DOMINATES);
+ patterns.write(s);
+ writeLocation(s);
+ }
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ Declare ret = new DeclarePrecedence(TypePatternList.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public void setScopeForResolution(IScope scope) {
+ this.scope = scope;
+ }
+
+ public void ensureResolved() { // Lazy resolution - due to pr256779
+ if (scope != null) {
+ try {
+ resolve(scope);
+ } finally {
+ scope = null;
+ }
+ }
+ }
+
+ public void resolve(IScope scope) {
+ patterns = patterns.resolveBindings(scope, Bindings.NONE, false, false);
+ boolean seenStar = false;
+
+ for (int i = 0; i < patterns.size(); i++) {
+ TypePattern pi = patterns.get(i);
+ if (pi.isStar()) {
+ if (seenStar) {
+ scope.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.TWO_STARS_IN_PRECEDENCE),
+ pi.getSourceLocation(), null);
+ }
+ seenStar = true;
+ continue;
+ }
+ ResolvedType exactType = pi.getExactType().resolve(scope.getWorld());
+ if (exactType.isMissing()) {
+ continue;
+ }
+
+ // Cannot do a dec prec specifying a non-aspect types unless suffixed with a '+'
+ if (!exactType.isAspect() && !exactType.isAnnotationStyleAspect() && !pi.isIncludeSubtypes()
+ && !exactType.isTypeVariableReference()) {
+ scope.getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.CLASSES_IN_PRECEDENCE, exactType.getName()), pi.getSourceLocation(),
+ null);
+ }
+
+ for (int j = 0; j < patterns.size(); j++) {
+ if (j == i) {
+ continue;
+ }
+ TypePattern pj = patterns.get(j);
+ if (pj.isStar()) {
+ continue;
+ }
+ if (pj.matchesStatically(exactType)) {
+ scope.getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.TWO_PATTERN_MATCHES_IN_PRECEDENCE, exactType.getName()),
+ pi.getSourceLocation(), pj.getSourceLocation());
+ }
+ }
+ }
+ }
+
+ public TypePatternList getPatterns() {
+ ensureResolved();
+ return patterns;
+ }
+
+ private int matchingIndex(ResolvedType a) {
+ ensureResolved();
+ int knownMatch = -1;
+ int starMatch = -1;
+ for (int i = 0, len = patterns.size(); i < len; i++) {
+ TypePattern p = patterns.get(i);
+ if (p.isStar()) {
+ starMatch = i;
+ } else if (p.matchesStatically(a)) {
+ if (knownMatch != -1) {
+ a.getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.MULTIPLE_MATCHES_IN_PRECEDENCE, a, patterns.get(knownMatch), p),
+ patterns.get(knownMatch).getSourceLocation(), p.getSourceLocation());
+ return -1;
+ } else {
+ knownMatch = i;
+ }
+ }
+ }
+ if (knownMatch == -1) {
+ return starMatch;
+ } else {
+ return knownMatch;
+ }
+ }
+
+ public int compare(ResolvedType aspect1, ResolvedType aspect2) {
+ ensureResolved();
+ int index1 = matchingIndex(aspect1);
+ int index2 = matchingIndex(aspect2);
+
+ // System.out.println("a1: " + aspect1 + ", " + aspect2 + " = " + index1 + ", " + index2);
+
+ if (index1 == -1 || index2 == -1) {
+ return 0;
+ }
+
+ if (index1 == index2) {
+ return 0;
+ } else if (index1 > index2) {
+ return -1;
+ } else {
+ return +1;
+ }
+ }
+
+ public boolean isAdviceLike() {
+ return false;
+ }
+
+ public String getNameSuffix() {
+ return "precedence";
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareSoft.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareSoft.java
new file mode 100644
index 000000000..3714d5fdc
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareSoft.java
@@ -0,0 +1,139 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeVariableReferenceType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+public class DeclareSoft extends Declare {
+ private TypePattern exception;
+ private Pointcut pointcut;
+
+ public DeclareSoft(TypePattern exception, Pointcut pointcut) {
+ this.exception = exception;
+ this.pointcut = pointcut;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public Declare parameterizeWith(Map typeVariableBindingMap, World w) {
+ DeclareSoft ret = new DeclareSoft(exception.parameterizeWith(typeVariableBindingMap, w), pointcut.parameterizeWith(
+ typeVariableBindingMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare soft: ");
+ buf.append(exception);
+ buf.append(": ");
+ buf.append(pointcut);
+ buf.append(";");
+ return buf.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof DeclareSoft)) {
+ return false;
+ }
+ DeclareSoft o = (DeclareSoft) other;
+ return o.pointcut.equals(pointcut) && o.exception.equals(exception);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 19;
+ result = 37 * result + pointcut.hashCode();
+ result = 37 * result + exception.hashCode();
+ return result;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Declare.SOFT);
+ exception.write(s);
+ pointcut.write(s);
+ writeLocation(s);
+ }
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ Declare ret = new DeclareSoft(TypePattern.read(s, context), Pointcut.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public Pointcut getPointcut() {
+ return pointcut;
+ }
+
+ public TypePattern getException() {
+ return exception;
+ }
+
+ @Override
+ public void resolve(IScope scope) {
+ exception = exception.resolveBindings(scope, null, false, true);
+ ResolvedType excType = exception.getExactType().resolve(scope.getWorld());
+ if (!excType.isMissing()) {
+ if (excType.isTypeVariableReference()) {
+ TypeVariableReferenceType typeVariableRT = (TypeVariableReferenceType) excType;
+ // a declare soft in a generic abstract aspect, we need to check the upper bound
+ // WIBBLE
+ excType = typeVariableRT.getTypeVariable().getFirstBound().resolve(scope.getWorld());
+ }
+ if (!scope.getWorld().getCoreType(UnresolvedType.THROWABLE).isAssignableFrom(excType)) {
+ scope.getWorld()
+ .showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.NOT_THROWABLE, excType.getName()),
+ exception.getSourceLocation(), null);
+ pointcut = Pointcut.makeMatchesNothing(Pointcut.RESOLVED);
+ return;
+ }
+ // ENH 42743 suggests that we don't soften runtime exceptions.
+ if (scope.getWorld().getCoreType(UnresolvedType.RUNTIME_EXCEPTION).isAssignableFrom(excType)) {
+ scope.getWorld().getLint().runtimeExceptionNotSoftened.signal(new String[] { excType.getName() }, exception
+ .getSourceLocation(), null);
+ pointcut = Pointcut.makeMatchesNothing(Pointcut.RESOLVED);
+ return;
+ }
+ }
+
+ pointcut = pointcut.resolve(scope);
+ }
+
+ @Override
+ public boolean isAdviceLike() {
+ return false;
+ }
+
+ @Override
+ public String getNameSuffix() {
+ return "soft";
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareTypeErrorOrWarning.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareTypeErrorOrWarning.java
new file mode 100644
index 000000000..daaf84496
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/DeclareTypeErrorOrWarning.java
@@ -0,0 +1,135 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * For a declare error/warning that specified a type pattern rather than a pointcut.
+ *
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public class DeclareTypeErrorOrWarning extends Declare {
+ private boolean isError;
+ private TypePattern typePattern;
+ private String message;
+
+ public DeclareTypeErrorOrWarning(boolean isError, TypePattern typePattern, String message) {
+ this.isError = isError;
+ this.typePattern = typePattern;
+ this.message = message;
+ }
+
+ /**
+ * returns "declare warning: <typepattern>: <message>" or "declare error: <typepattern>: <message>"
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare ");
+ if (isError) {
+ buf.append("error: ");
+ } else {
+ buf.append("warning: ");
+ }
+ buf.append(typePattern);
+ buf.append(": ");
+ buf.append("\"");
+ buf.append(message);
+ buf.append("\";");
+ return buf.toString();
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof DeclareTypeErrorOrWarning)) {
+ return false;
+ }
+ DeclareTypeErrorOrWarning o = (DeclareTypeErrorOrWarning) other;
+ return (o.isError == isError) && o.typePattern.equals(typePattern) && o.message.equals(message);
+ }
+
+ public int hashCode() {
+ int result = isError ? 19 : 23;
+ result = 37 * result + typePattern.hashCode();
+ result = 37 * result + message.hashCode();
+ return result;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Declare.TYPE_ERROR_OR_WARNING);
+ s.writeBoolean(isError);
+ typePattern.write(s);
+ s.writeUTF(message);
+ writeLocation(s);
+ }
+
+ public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ Declare ret = new DeclareTypeErrorOrWarning(s.readBoolean(), TypePattern.read(s, context), s.readUTF());
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public boolean isError() {
+ return isError;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public TypePattern getTypePattern() {
+ return typePattern;
+ }
+
+ public void resolve(IScope scope) {
+ typePattern.resolve(scope.getWorld());
+ }
+
+ public Declare parameterizeWith(Map typeVariableBindingMap, World w) {
+ Declare ret = new DeclareTypeErrorOrWarning(isError, typePattern.parameterizeWith(typeVariableBindingMap, w), message);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public boolean isAdviceLike() {
+ return false;
+ }
+
+ public String getNameSuffix() {
+ return "teow";
+ }
+
+ /**
+ * returns "declare type warning" or "declare type error"
+ */
+ public String getName() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("declare type ");
+ if (isError) {
+ buf.append("error");
+ } else {
+ buf.append("warning");
+ }
+ return buf.toString();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/EllipsisTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/EllipsisTypePattern.java
new file mode 100644
index 000000000..2abc51327
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/EllipsisTypePattern.java
@@ -0,0 +1,109 @@
+/* *******************************************************************
+ * Copyright (c) 2002, 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.World;
+
+public class EllipsisTypePattern extends TypePattern {
+
+ /**
+ * Constructor for EllipsisTypePattern.
+ *
+ * @param includeSubtypes
+ */
+ public EllipsisTypePattern() {
+ super(false, false, new TypePatternList());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
+ */
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ return true;
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType)
+ */
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ return false;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ return false;
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType)
+ */
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(ELLIPSIS_KEY);
+ }
+
+ @Override
+ public boolean isEllipsis() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "..";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof EllipsisTypePattern);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return 17 * 37;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map typeVariableMap, World w) {
+ return this;
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationFieldTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationFieldTypePattern.java
new file mode 100644
index 000000000..627b622eb
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationFieldTypePattern.java
@@ -0,0 +1,253 @@
+/* *******************************************************************
+ * Copyright (c) 2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * Represents an attempt to bind the field of an annotation within a pointcut. For example:<br>
+ * <code><pre>
+ * before(Level lev): execution(* *(..)) &amp;&amp; @annotation(TraceAnnotation(lev))
+ * </pre></code><br>
+ * This binding annotation type pattern will be for 'lev'.
+ */
+public class ExactAnnotationFieldTypePattern extends ExactAnnotationTypePattern {
+
+ UnresolvedType annotationType;
+ private ResolvedMember field;
+
+ public ExactAnnotationFieldTypePattern(ExactAnnotationTypePattern p, String formalName) {
+ super(formalName);
+ this.annotationType = p.annotationType;
+ this.copyLocationFrom(p);
+ }
+
+ public ExactAnnotationFieldTypePattern(UnresolvedType annotationType, String formalName) {
+ super(formalName);
+ this.annotationType = annotationType;
+ }
+
+ /**
+ * resolve one of these funky things. Need to: <br>
+ * (a) Check the formal is bound <br>
+ * (b) Check the annotation type is valid
+ */
+ @Override
+ public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ if (resolved) {
+ return this;
+ }
+ resolved = true;
+ FormalBinding formalBinding = scope.lookupFormal(formalName);
+ if (formalBinding == null) {
+ scope.message(IMessage.ERROR, this,
+ "When using @annotation(<annotationType>(<annotationField>)), <annotationField> must be bound");
+ return this;
+ }
+
+ annotationType = scope.getWorld().resolve(annotationType, true);
+
+ // May not be directly found if in a package, so go looking if that is the case:
+ if (ResolvedType.isMissing(annotationType)) {
+ String cleanname = annotationType.getName();
+ UnresolvedType type = null;
+ while (ResolvedType.isMissing(type = scope.lookupType(cleanname, this))) {
+ int lastDot = cleanname.lastIndexOf('.');
+ if (lastDot == -1) {
+ break;
+ }
+ cleanname = cleanname.substring(0, lastDot) + "$" + cleanname.substring(lastDot + 1);
+ }
+ annotationType = scope.getWorld().resolve(type, true);
+ if (ResolvedType.isMissing(annotationType)) {
+ // there are likely to be other errors around that have led to us being unable to
+ // resolve the annotation type, let's quit now
+ return this;
+ }
+ }
+
+ verifyIsAnnotationType((ResolvedType) annotationType, scope);
+
+ ResolvedType formalBindingType = formalBinding.getType().resolve(scope.getWorld());
+
+ String bindingTypeSignature = formalBindingType.getSignature();
+ if (!(formalBindingType.isEnum() || bindingTypeSignature.equals("Ljava/lang/String;") || bindingTypeSignature.equals("I"))) {
+ scope.message(IMessage.ERROR, this,
+ "The field within the annotation must be an enum, string or int. '" + formalBinding.getType()
+ + "' is not (compiler limitation)");
+ }
+ bindingPattern = true;
+
+ // Check that the formal is bound to a type that is represented by one field in the annotation type
+ ReferenceType theAnnotationType = (ReferenceType) annotationType;
+ ResolvedMember[] annotationFields = theAnnotationType.getDeclaredMethods();
+ field = null;
+ boolean looksAmbiguous = false;
+ for (int i = 0; i < annotationFields.length; i++) {
+ ResolvedMember resolvedMember = annotationFields[i];
+ if (resolvedMember.getReturnType().equals(formalBinding.getType())) {
+ if (field != null) {
+ boolean haveProblem = true;
+ // use the name to differentiate
+ if (field.getName().equals(formalName)) {
+ // don't use this new field
+ haveProblem = false;
+ } else if (resolvedMember.getName().equals(formalName)) {
+ // ok, let's use this one
+ field = resolvedMember;
+ haveProblem = false;
+ }
+ if (haveProblem) {
+ looksAmbiguous = true;
+ }
+ } else {
+ field = resolvedMember;
+ }
+ }
+ }
+ if (looksAmbiguous) {
+ // did we find something that does match by name?
+ if (field == null || !field.getName().equals(formalName)) {
+ scope.message(IMessage.ERROR, this, "The field type '" + formalBinding.getType()
+ + "' is ambiguous for annotation type '" + theAnnotationType.getName() + "'");
+ }
+ }
+ if (field == null) {
+ scope.message(IMessage.ERROR, this, "No field of type '" + formalBinding.getType() + "' exists on annotation type '"
+ + theAnnotationType.getName() + "'");
+ }
+
+ BindingAnnotationFieldTypePattern binding = new BindingAnnotationFieldTypePattern(formalBinding.getType(),
+ formalBinding.getIndex(), theAnnotationType);
+ binding.copyLocationFrom(this);
+ binding.formalName = this.formalName;
+ bindings.register(binding, scope);
+ binding.resolveBinding(scope.getWorld());
+ return binding;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.EXACTFIELD);
+ s.writeUTF(formalName);
+ annotationType.write(s);
+ writeLocation(s);
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ExactAnnotationFieldTypePattern ret;
+ String formalName = s.readUTF();
+ UnresolvedType annotationType = UnresolvedType.read(s);
+ ret = new ExactAnnotationFieldTypePattern(annotationType, formalName);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ // ---
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ExactAnnotationFieldTypePattern)) {
+ return false;
+ }
+ ExactAnnotationFieldTypePattern other = (ExactAnnotationFieldTypePattern) obj;
+ return (other.annotationType.equals(annotationType)) && (other.field.equals(field))
+ && (other.formalName.equals(this.formalName));
+ }
+
+ @Override
+ public int hashCode() {
+ int hashcode = annotationType.hashCode();
+ hashcode = hashcode * 37 + field.hashCode();
+ hashcode = hashcode * 37 + formalName.hashCode();
+ return hashcode;
+ }
+
+ // TODO these are currently unimplemented as I believe it resolves to a Binding form *always* and so they don't get
+ // called
+
+ @Override
+ public FuzzyBoolean fastMatches(AnnotatedElement annotated) {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public UnresolvedType getAnnotationType() {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public Map getAnnotationValues() {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public ResolvedType getResolvedAnnotationType() {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public FuzzyBoolean matchesRuntimeType(AnnotatedElement annotated) {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public AnnotationTypePattern parameterizeWith(Map typeVariableMap, World w) {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public void resolve(World world) {
+ throw new BCException("unimplemented");
+ }
+
+ @Override
+ public String toString() {
+ if (!resolved && formalName != null) {
+ return formalName;
+ }
+ StringBuffer ret = new StringBuffer();
+ ret.append("@").append(annotationType.toString());
+ ret.append("(").append(formalName).append(")");
+ return ret.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java
new file mode 100644
index 000000000..b51d72df9
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactAnnotationTypePattern.java
@@ -0,0 +1,470 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.AnnotationAJ;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeVariableReference;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * Matches an annotation of a given type
+ */
+public class ExactAnnotationTypePattern extends AnnotationTypePattern {
+
+ protected UnresolvedType annotationType;
+ protected String formalName;
+ protected boolean resolved = false;
+ protected boolean bindingPattern = false;
+ private Map<String, String> annotationValues;
+
+ // OPTIMIZE is annotationtype really unresolved???? surely it is resolved by
+ // now...
+ public ExactAnnotationTypePattern(UnresolvedType annotationType, Map<String, String> annotationValues) {
+ this.annotationType = annotationType;
+ this.annotationValues = annotationValues;
+ this.resolved = (annotationType instanceof ResolvedType);
+ }
+
+ // Used when deserializing, values will be added
+ private ExactAnnotationTypePattern(UnresolvedType annotationType) {
+ this.annotationType = annotationType;
+ this.resolved = (annotationType instanceof ResolvedType);
+ }
+
+ protected ExactAnnotationTypePattern(String formalName) {
+ this.formalName = formalName;
+ this.resolved = false;
+ this.bindingPattern = true;
+ // will be turned into BindingAnnotationTypePattern during resolution
+ }
+
+ public ResolvedType getResolvedAnnotationType() {
+ if (!resolved) {
+ throw new IllegalStateException("I need to be resolved first!");
+ }
+ return (ResolvedType) annotationType;
+ }
+
+ public UnresolvedType getAnnotationType() {
+ return annotationType;
+ }
+
+ public Map<String, String> getAnnotationValues() {
+ return annotationValues;
+ }
+
+ @Override
+ public FuzzyBoolean fastMatches(AnnotatedElement annotated) {
+ if (annotated.hasAnnotation(annotationType) && annotationValues == null) {
+ return FuzzyBoolean.YES;
+ } else {
+ // could be inherited, but we don't know that until we are
+ // resolved, and we're not yet...
+ return FuzzyBoolean.MAYBE;
+ }
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ return matches(annotated, null);
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ if (!isForParameterAnnotationMatch()) {
+ boolean checkSupers = false;
+ if (getResolvedAnnotationType().isInheritedAnnotation()) {
+ if (annotated instanceof ResolvedType) {
+ checkSupers = true;
+ }
+ }
+
+ if (annotated.hasAnnotation(annotationType)) {
+ if (annotationType instanceof ReferenceType) {
+ ReferenceType rt = (ReferenceType) annotationType;
+ if (rt.getRetentionPolicy() != null && rt.getRetentionPolicy().equals("SOURCE")) {
+ rt.getWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil.warn(WeaverMessages.format(WeaverMessages.NO_MATCH_BECAUSE_SOURCE_RETENTION,
+ annotationType, annotated), getSourceLocation()));
+ return FuzzyBoolean.NO;
+ }
+ }
+
+ // Are we also matching annotation values?
+ if (annotationValues != null) {
+ AnnotationAJ theAnnotation = annotated.getAnnotationOfType(annotationType);
+
+ // Check each one
+ Set<String> keys = annotationValues.keySet();
+ for (String k : keys) {
+ boolean notEqual = false;
+ String v = annotationValues.get(k);
+ // if the key has a trailing '!' then it means the source expressed k!=v - so we are looking for
+ // something other than the value specified
+ if (k.endsWith("!")) {
+ notEqual = true;
+ k = k.substring(0, k.length() - 1);
+ }
+ if (theAnnotation.hasNamedValue(k)) {
+ // Simple case, value is 'name=value' and the
+ // annotation specified the same thing
+ if (notEqual) {
+ if (theAnnotation.hasNameValuePair(k, v)) {
+ return FuzzyBoolean.NO;
+ }
+ } else {
+ if (!theAnnotation.hasNameValuePair(k, v)) {
+ return FuzzyBoolean.NO;
+ }
+ }
+ } else {
+ // Complex case, look at the default value
+ ResolvedMember[] ms = ((ResolvedType) annotationType).getDeclaredMethods();
+ boolean foundMatch = false;
+ for (int i = 0; i < ms.length && !foundMatch; i++) {
+ if (ms[i].isAbstract() && ms[i].getParameterTypes().length == 0 && ms[i].getName().equals(k)) {
+ // we might be onto something
+ String s = ms[i].getAnnotationDefaultValue();
+ if (s != null && s.equals(v)) {
+ foundMatch = true;
+ }
+ }
+ }
+ if (notEqual) {
+ if (foundMatch) {
+ return FuzzyBoolean.NO;
+ }
+ } else {
+ if (!foundMatch) {
+ return FuzzyBoolean.NO;
+ }
+ }
+ }
+ }
+ }
+ return FuzzyBoolean.YES;
+ } else if (checkSupers) {
+ ResolvedType toMatchAgainst = ((ResolvedType) annotated).getSuperclass();
+ while (toMatchAgainst != null) {
+ if (toMatchAgainst.hasAnnotation(annotationType)) {
+ // Are we also matching annotation values?
+ if (annotationValues != null) {
+ AnnotationAJ theAnnotation = toMatchAgainst.getAnnotationOfType(annotationType);
+
+ // Check each one
+ Set<String> keys = annotationValues.keySet();
+ for (String k : keys) {
+ String v = annotationValues.get(k);
+ if (theAnnotation.hasNamedValue(k)) {
+ // Simple case, value is 'name=value' and
+ // the annotation specified the same thing
+ if (!theAnnotation.hasNameValuePair(k, v)) {
+ return FuzzyBoolean.NO;
+ }
+ } else {
+ // Complex case, look at the default value
+ ResolvedMember[] ms = ((ResolvedType) annotationType).getDeclaredMethods();
+ boolean foundMatch = false;
+ for (int i = 0; i < ms.length && !foundMatch; i++) {
+ if (ms[i].isAbstract() && ms[i].getParameterTypes().length == 0
+ && ms[i].getName().equals(k)) {
+ // we might be onto something
+ String s = ms[i].getAnnotationDefaultValue();
+ if (s != null && s.equals(v)) {
+ foundMatch = true;
+ }
+ }
+ }
+ if (!foundMatch) {
+ return FuzzyBoolean.NO;
+ }
+ }
+ }
+ }
+ return FuzzyBoolean.YES;
+ }
+ toMatchAgainst = toMatchAgainst.getSuperclass();
+ }
+ }
+ } else {
+ // check parameter annotations
+ if (parameterAnnotations == null) {
+ return FuzzyBoolean.NO;
+ }
+ for (int i = 0; i < parameterAnnotations.length; i++) {
+ if (annotationType.equals(parameterAnnotations[i])) {
+ // Are we also matching annotation values?
+ if (annotationValues != null) {
+ parameterAnnotations[i]
+ .getWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil
+ .error("Compiler limitation: annotation value matching for parameter annotations not yet supported"));
+ return FuzzyBoolean.NO;
+ }
+ return FuzzyBoolean.YES;
+ }
+ }
+ }
+
+ return FuzzyBoolean.NO;
+ }
+
+ // this version should be called for @this, @target, @args
+ public FuzzyBoolean matchesRuntimeType(AnnotatedElement annotated) {
+ if (getResolvedAnnotationType().isInheritedAnnotation()) {
+ // a static match is good enough
+ if (matches(annotated).alwaysTrue()) {
+ return FuzzyBoolean.YES;
+ }
+ }
+ // a subtype could match at runtime
+ return FuzzyBoolean.MAYBE;
+ }
+
+ @Override
+ public void resolve(World world) {
+ if (!resolved) {
+ annotationType = annotationType.resolve(world);
+ resolved = true;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.AnnotationTypePattern#resolveBindings(org .aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings, boolean)
+ */
+ @Override
+ public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ if (resolved) {
+ return this;
+ }
+ resolved = true;
+ String simpleName = maybeGetSimpleName();
+ if (simpleName != null) {
+ FormalBinding formalBinding = scope.lookupFormal(simpleName);
+ if (formalBinding != null) {
+ if (bindings == null) {
+ scope.message(IMessage.ERROR, this, "negation doesn't allow binding");
+ return this;
+ }
+ if (!allowBinding) {
+ scope.message(IMessage.ERROR, this, "name binding only allowed in @pcds, args, this, and target");
+ return this;
+ }
+ formalName = simpleName;
+ bindingPattern = true;
+ verifyIsAnnotationType(formalBinding.getType().resolve(scope.getWorld()), scope);
+ BindingAnnotationTypePattern binding = new BindingAnnotationTypePattern(formalBinding);
+ binding.copyLocationFrom(this);
+ bindings.register(binding, scope);
+ binding.resolveBinding(scope.getWorld());
+ if (isForParameterAnnotationMatch()) {
+ binding.setForParameterAnnotationMatch();
+ }
+
+ return binding;
+ }
+ }
+
+ // Non binding case
+ String cleanname = annotationType.getName();
+ annotationType = scope.getWorld().resolve(annotationType, true);
+
+ // We may not have found it if it is in a package, lets look it up...
+ if (ResolvedType.isMissing(annotationType)) {
+ UnresolvedType type = null;
+ while (ResolvedType.isMissing(type = scope.lookupType(cleanname, this))) {
+ int lastDot = cleanname.lastIndexOf('.');
+ if (lastDot == -1) {
+ break;
+ }
+ cleanname = cleanname.substring(0, lastDot) + "$" + cleanname.substring(lastDot + 1);
+ }
+ annotationType = scope.getWorld().resolve(type, true);
+ }
+
+ verifyIsAnnotationType((ResolvedType) annotationType, scope);
+ return this;
+ }
+
+ @Override
+ public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ UnresolvedType newAnnotationType = annotationType;
+ if (annotationType.isTypeVariableReference()) {
+ TypeVariableReference t = (TypeVariableReference) annotationType;
+ String key = t.getTypeVariable().getName();
+ if (typeVariableMap.containsKey(key)) {
+ newAnnotationType = typeVariableMap.get(key);
+ }
+ } else if (annotationType.isParameterizedType()) {
+ newAnnotationType = annotationType.parameterize(typeVariableMap);
+ }
+ ExactAnnotationTypePattern ret = new ExactAnnotationTypePattern(newAnnotationType, annotationValues);
+ ret.formalName = formalName;
+ ret.bindingPattern = bindingPattern;
+ ret.copyLocationFrom(this);
+ if (isForParameterAnnotationMatch()) {
+ ret.setForParameterAnnotationMatch();
+ }
+ return ret;
+ }
+
+ protected String maybeGetSimpleName() {
+ if (formalName != null) {
+ return formalName;
+ }
+ String ret = annotationType.getName();
+ return (ret.indexOf('.') == -1) ? ret : null;
+ }
+
+ protected void verifyIsAnnotationType(ResolvedType type, IScope scope) {
+ if (!type.isAnnotation()) {
+ IMessage m = MessageUtil.error(WeaverMessages.format(WeaverMessages.REFERENCE_TO_NON_ANNOTATION_TYPE, type.getName()),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ resolved = false;
+ }
+ }
+
+ private static byte VERSION = 1; // rev if serialisation form changes
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
+ */
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.EXACT);
+ s.writeByte(VERSION);
+ s.writeBoolean(bindingPattern);
+ if (bindingPattern) {
+ s.writeUTF(formalName);
+ } else {
+ annotationType.write(s);
+ }
+ writeLocation(s);
+ s.writeBoolean(isForParameterAnnotationMatch());
+ if (annotationValues == null) {
+ s.writeInt(0);
+ } else {
+ s.writeInt(annotationValues.size());
+ Set<String> key = annotationValues.keySet();
+ for (Iterator<String> keys = key.iterator(); keys.hasNext();) {
+ String k = keys.next();
+ s.writeUTF(k);
+ s.writeUTF(annotationValues.get(k));
+ }
+ }
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ ExactAnnotationTypePattern ret;
+ byte version = s.readByte();
+ if (version > VERSION) {
+ throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ");
+ }
+ boolean isBindingPattern = s.readBoolean();
+ if (isBindingPattern) {
+ ret = new ExactAnnotationTypePattern(s.readUTF());
+ } else {
+ ret = new ExactAnnotationTypePattern(UnresolvedType.read(s));
+ }
+ ret.readLocation(context, s);
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) {
+ if (s.readBoolean()) {
+ ret.setForParameterAnnotationMatch();
+ }
+ }
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160M2) {
+ int annotationValueCount = s.readInt();
+ if (annotationValueCount > 0) {
+ Map<String, String> aValues = new HashMap<String, String>();
+ for (int i = 0; i < annotationValueCount; i++) {
+ String key = s.readUTF();
+ String val = s.readUTF();
+ aValues.put(key, val);
+ }
+ ret.annotationValues = aValues;
+ }
+ }
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ExactAnnotationTypePattern)) {
+ return false;
+ }
+ ExactAnnotationTypePattern other = (ExactAnnotationTypePattern) obj;
+ return (other.annotationType.equals(annotationType))
+ && isForParameterAnnotationMatch() == other.isForParameterAnnotationMatch()
+ && (annotationValues == null ? other.annotationValues == null : annotationValues.equals(other.annotationValues));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return (((annotationType.hashCode()) * 37 + (isForParameterAnnotationMatch() ? 0 : 1)) * 37)
+ + (annotationValues == null ? 0 : annotationValues.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ if (!resolved && formalName != null) {
+ return formalName;
+ }
+ String ret = "@" + annotationType.toString();
+ if (formalName != null) {
+ ret = ret + " " + formalName;
+ }
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactTypePattern.java
new file mode 100644
index 000000000..68353422f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExactTypePattern.java
@@ -0,0 +1,341 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjAttribute;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeVariableReference;
+import org.aspectj.weaver.TypeVariableReferenceType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public class ExactTypePattern extends TypePattern {
+ protected UnresolvedType type;
+ protected transient ResolvedType resolvedType;
+ public boolean checked = false;
+ public boolean isVoid = false;
+
+ public static final Map<String, Class<?>> primitiveTypesMap;
+ public static final Map<String, Class<?>> boxedPrimitivesMap;
+ private static final Map<String, Class<?>> boxedTypesMap;
+
+ static {
+ primitiveTypesMap = new HashMap<String, Class<?>>();
+ primitiveTypesMap.put("int", int.class);
+ primitiveTypesMap.put("short", short.class);
+ primitiveTypesMap.put("long", long.class);
+ primitiveTypesMap.put("byte", byte.class);
+ primitiveTypesMap.put("char", char.class);
+ primitiveTypesMap.put("float", float.class);
+ primitiveTypesMap.put("double", double.class);
+
+ boxedPrimitivesMap = new HashMap<String, Class<?>>();
+ boxedPrimitivesMap.put("java.lang.Integer", Integer.class);
+ boxedPrimitivesMap.put("java.lang.Short", Short.class);
+ boxedPrimitivesMap.put("java.lang.Long", Long.class);
+ boxedPrimitivesMap.put("java.lang.Byte", Byte.class);
+ boxedPrimitivesMap.put("java.lang.Character", Character.class);
+ boxedPrimitivesMap.put("java.lang.Float", Float.class);
+ boxedPrimitivesMap.put("java.lang.Double", Double.class);
+
+ boxedTypesMap = new HashMap<String, Class<?>>();
+ boxedTypesMap.put("int", Integer.class);
+ boxedTypesMap.put("short", Short.class);
+ boxedTypesMap.put("long", Long.class);
+ boxedTypesMap.put("byte", Byte.class);
+ boxedTypesMap.put("char", Character.class);
+ boxedTypesMap.put("float", Float.class);
+ boxedTypesMap.put("double", Double.class);
+
+ }
+
+ @Override
+ protected boolean matchesSubtypes(ResolvedType type) {
+ boolean match = super.matchesSubtypes(type);
+ if (match) {
+ return match;
+ }
+ // are we dealing with array funkyness - pattern might be jlObject[]+ and type jlString[]
+ if (type.isArray() && this.type.isArray()) {
+ ResolvedType componentType = type.getComponentType().resolve(type.getWorld());
+ UnresolvedType newPatternType = this.type.getComponentType();
+ ExactTypePattern etp = new ExactTypePattern(newPatternType, includeSubtypes, false);
+ return etp.matchesSubtypes(componentType, type);
+ }
+ return match;
+ }
+
+ public ExactTypePattern(UnresolvedType type, boolean includeSubtypes, boolean isVarArgs) {
+ super(includeSubtypes, isVarArgs);
+ this.type = type;
+ }
+
+ @Override
+ public boolean isArray() {
+ return type.isArray();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
+ */
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ if (super.couldEverMatchSameTypesAs(other)) {
+ return true;
+ }
+ // false is necessary but not sufficient
+ UnresolvedType otherType = other.getExactType();
+ if (!ResolvedType.isMissing(otherType)) {
+ return type.equals(otherType);
+ }
+ if (other instanceof WildTypePattern) {
+ WildTypePattern owtp = (WildTypePattern) other;
+ String yourSimpleNamePrefix = owtp.getNamePatterns()[0].maybeGetSimpleName();
+ if (yourSimpleNamePrefix != null) {
+ return (type.getName().startsWith(yourSimpleNamePrefix));
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType matchType) {
+ boolean typeMatch = this.type.equals(matchType);
+ if (!typeMatch && (matchType.isParameterizedType() || matchType.isGenericType())) {
+ typeMatch = this.type.equals(matchType.getRawType());
+ }
+ if (!typeMatch && matchType.isTypeVariableReference()) {
+ typeMatch = matchesTypeVariable((TypeVariableReferenceType) matchType);
+ }
+ if (!typeMatch) {
+ return false;
+ }
+ annotationPattern.resolve(matchType.getWorld());
+ boolean annMatch = false;
+ if (matchType.temporaryAnnotationTypes != null) {
+ annMatch = annotationPattern.matches(matchType, matchType.temporaryAnnotationTypes).alwaysTrue();
+ } else {
+ annMatch = annotationPattern.matches(matchType).alwaysTrue();
+ }
+ return (typeMatch && annMatch);
+ }
+
+ private boolean matchesTypeVariable(TypeVariableReferenceType matchType) {
+ // was this method previously coded to return false *on purpose* ?? pr124808
+ return this.type.equals(((TypeVariableReference) matchType).getTypeVariable().getFirstBound());
+ // return false;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType matchType, ResolvedType annotatedType) {
+ boolean typeMatch = this.type.equals(matchType);
+ if (!typeMatch && (matchType.isParameterizedType() || matchType.isGenericType())) {
+ typeMatch = this.type.equals(matchType.getRawType());
+ }
+ if (!typeMatch && matchType.isTypeVariableReference()) {
+ typeMatch = matchesTypeVariable((TypeVariableReferenceType) matchType);
+ }
+ annotationPattern.resolve(matchType.getWorld());
+ boolean annMatch = false;
+ if (annotatedType.temporaryAnnotationTypes != null) {
+ annMatch = annotationPattern.matches(annotatedType, annotatedType.temporaryAnnotationTypes).alwaysTrue();
+ } else {
+ annMatch = annotationPattern.matches(annotatedType).alwaysTrue();
+ }
+ return (typeMatch && annMatch);
+ }
+
+ public UnresolvedType getType() {
+ return type;
+ }
+
+ public ResolvedType getResolvedExactType(World world) {
+ if (resolvedType == null) {
+ resolvedType = world.resolve(type);
+ }
+ return resolvedType;
+ }
+
+ @Override
+ public boolean isVoid() {
+ if (!checked) {
+ isVoid = this.type.getSignature().equals("V");
+ checked = true;
+ }
+ return isVoid;
+ }
+
+ // true if (matchType instanceof this.type)
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType matchType) {
+ // in our world, Object is assignable from anything
+ annotationPattern.resolve(matchType.getWorld());
+ if (type.equals(ResolvedType.OBJECT)) {
+ return FuzzyBoolean.YES.and(annotationPattern.matches(matchType));
+ }
+
+ ResolvedType resolvedType = type.resolve(matchType.getWorld());
+ if (resolvedType.isAssignableFrom(matchType)) {
+ return FuzzyBoolean.YES.and(annotationPattern.matches(matchType));
+ }
+
+ // fix for PR 64262 - shouldn't try to coerce primitives
+ if (type.isPrimitiveType()) {
+ return FuzzyBoolean.NO;
+ } else {
+ return matchType.isCoerceableFrom(type.resolve(matchType.getWorld())) ? FuzzyBoolean.MAYBE : FuzzyBoolean.NO;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof ExactTypePattern)) {
+ return false;
+ }
+ if (other instanceof BindingTypePattern) {
+ return false;
+ }
+ ExactTypePattern o = (ExactTypePattern) other;
+ if (includeSubtypes != o.includeSubtypes) {
+ return false;
+ }
+ if (isVarArgs != o.isVarArgs) {
+ return false;
+ }
+ if (!typeParameters.equals(o.typeParameters)) {
+ return false;
+ }
+ return (o.type.equals(this.type) && o.annotationPattern.equals(this.annotationPattern));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + type.hashCode();
+ result = 37 * result + new Boolean(includeSubtypes).hashCode();
+ result = 37 * result + new Boolean(isVarArgs).hashCode();
+ result = 37 * result + typeParameters.hashCode();
+ result = 37 * result + annotationPattern.hashCode();
+ return result;
+ }
+
+ private static final byte EXACT_VERSION = 1; // rev if changed
+
+ @Override
+ public void write(CompressingDataOutputStream out) throws IOException {
+ out.writeByte(TypePattern.EXACT);
+ out.writeByte(EXACT_VERSION);
+ out.writeCompressedSignature(type.getSignature());
+ out.writeBoolean(includeSubtypes);
+ out.writeBoolean(isVarArgs);
+ annotationPattern.write(out);
+ typeParameters.write(out);
+ writeLocation(out);
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+ return readTypePattern150(s, context);
+ } else {
+ return readTypePatternOldStyle(s, context);
+ }
+ }
+
+ public static TypePattern readTypePattern150(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte version = s.readByte();
+ if (version > EXACT_VERSION) {
+ throw new BCException("ExactTypePattern was written by a more recent version of AspectJ");
+ }
+ TypePattern ret = new ExactTypePattern(s.isAtLeast169() ? s.readSignatureAsUnresolvedType() : UnresolvedType.read(s), s
+ .readBoolean(), s.readBoolean());
+ ret.setAnnotationTypePattern(AnnotationTypePattern.read(s, context));
+ ret.setTypeParameters(TypePatternList.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public static TypePattern readTypePatternOldStyle(DataInputStream s, ISourceContext context) throws IOException {
+ TypePattern ret = new ExactTypePattern(UnresolvedType.read(s), s.readBoolean(), false);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buff = new StringBuffer();
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append('(');
+ buff.append(annotationPattern.toString());
+ buff.append(' ');
+ }
+ String typeString = type.toString();
+ if (isVarArgs) {
+ typeString = typeString.substring(0, typeString.lastIndexOf('['));
+ }
+ buff.append(typeString);
+ if (includeSubtypes) {
+ buff.append('+');
+ }
+ if (isVarArgs) {
+ buff.append("...");
+ }
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append(')');
+ }
+ return buff.toString();
+ }
+
+ @Override
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ throw new BCException("trying to re-resolve");
+ }
+
+ /**
+ * return a version of this type pattern with all type variables references replaced by the corresponding entry in the map.
+ */
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ UnresolvedType newType = type;
+ if (type.isTypeVariableReference()) {
+ TypeVariableReference t = (TypeVariableReference) type;
+ String key = t.getTypeVariable().getName();
+ if (typeVariableMap.containsKey(key)) {
+ newType = (UnresolvedType) typeVariableMap.get(key);
+ }
+ } else if (type.isParameterizedType()) {
+ newType = w.resolve(type).parameterize(typeVariableMap);
+ }
+ ExactTypePattern ret = new ExactTypePattern(newType, includeSubtypes, isVarArgs);
+ ret.annotationPattern = annotationPattern.parameterizeWith(typeVariableMap, w);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExposedState.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExposedState.java
new file mode 100644
index 000000000..2a9807118
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ExposedState.java
@@ -0,0 +1,117 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.util.Arrays;
+
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Var;
+
+public class ExposedState {
+ public static final boolean[] NO_ERRONEOUS_VARS = new boolean[0];
+ public Var[] vars;
+ private boolean[] erroneousVars;
+ private Expr aspectInstance;
+ private UnresolvedType[] expectedVarTypes; // enables us to check that binding is occurring with the *right* types
+ private ResolvedType concreteAspect;
+
+ public ExposedState(int size) {
+ super();
+ if (size == 0) {
+ vars = Var.NONE;
+ erroneousVars = NO_ERRONEOUS_VARS;
+ } else {
+ vars = new Var[size];
+ erroneousVars = new boolean[size];
+
+ }
+ }
+
+ public ExposedState(Member signature) {
+ // XXX there maybe something about target for non-static sigs
+ this(signature.getParameterTypes().length);
+ expectedVarTypes = new UnresolvedType[signature.getParameterTypes().length];
+ if (expectedVarTypes.length > 0) {
+ for (int i = 0; i < signature.getParameterTypes().length; i++) {
+ expectedVarTypes[i] = signature.getParameterTypes()[i];
+ }
+ }
+
+ }
+
+ public boolean isFullySetUp() {
+ for (int i = 0; i < vars.length; i++) {
+ if (vars[i] == null)
+ return false;
+ }
+ return true;
+ }
+
+ public void set(int i, Var var) {
+ // check the type is OK if we can... these are the same rules as in matchesInstanceOf() processing
+ if (expectedVarTypes != null) {
+ ResolvedType expected = expectedVarTypes[i].resolve(var.getType().getWorld());
+ if (!expected.equals(ResolvedType.OBJECT)) {
+ if (!expected.isAssignableFrom(var.getType())) {
+ if (!var.getType().isCoerceableFrom(expected)) {
+ // throw new
+ // BCException("Expected type "+expectedVarTypes[i]+" in slot "+i+" but attempt to put "+var.getType()+" into it");
+ return;
+ }
+ }
+ }
+ }
+ vars[i] = var;
+ }
+
+ public Var get(int i) {
+ return vars[i];
+ }
+
+ public int size() {
+ return vars.length;
+ }
+
+ public Expr getAspectInstance() {
+ return aspectInstance;
+ }
+
+ public void setAspectInstance(Expr aspectInstance) {
+ this.aspectInstance = aspectInstance;
+ }
+
+ public String toString() {
+ return "ExposedState(#Vars=" + vars.length + ",Vars=" + Arrays.asList(vars) + ",AspectInstance=" + aspectInstance + ")";
+ }
+
+ // Set to true if we have reported an error message against it,
+ // prevents us blowing up in later code gen.
+ public void setErroneousVar(int formalIndex) {
+ erroneousVars[formalIndex] = true;
+ }
+
+ public boolean isErroneousVar(int formalIndex) {
+ return erroneousVars[formalIndex];
+ }
+
+ public void setConcreteAspect(ResolvedType concreteAspect) {
+ this.concreteAspect = concreteAspect;
+ }
+
+ public ResolvedType getConcreteAspect() {
+ return this.concreteAspect;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FastMatchInfo.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FastMatchInfo.java
new file mode 100644
index 000000000..a18830832
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FastMatchInfo.java
@@ -0,0 +1,52 @@
+/* *******************************************************************
+ * Copyright (c) 2004 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Jim Hugunin initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.Shadow.Kind;
+
+/**
+ * Represents a type that pointcuts may match. Fast match for a pointcut should quickly say NO if it can.
+ */
+public class FastMatchInfo {
+ private Kind kind;
+ private ResolvedType type;
+ public World world;
+
+ public FastMatchInfo(ResolvedType type, Shadow.Kind kind, World world) {
+ this.type = type;
+ this.kind = kind;
+ this.world = world;
+ }
+
+ /**
+ * kind can be null to indicate that all kinds should be considered. This is usually done as a first pass
+ *
+ * @return
+ */
+ public Kind getKind() {
+ return kind;
+ }
+
+ public ResolvedType getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return "FastMatchInfo [type=" + type.getName() + "] [" + (kind == null ? "AllKinds" : "Kind=" + kind) + "]";
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FormalBinding.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FormalBinding.java
new file mode 100644
index 000000000..73693f07c
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/FormalBinding.java
@@ -0,0 +1,82 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.IHasPosition;
+import org.aspectj.weaver.UnresolvedType;
+
+public class FormalBinding implements IHasPosition {
+ private final UnresolvedType type;
+ private final String name;
+ private final int index;
+ private final int start, end;
+
+ public FormalBinding(UnresolvedType type, String name, int index, int start, int end) {
+ this.type = type;
+ this.name = name;
+ this.index = index;
+ this.start = start;
+ this.end = end;
+ }
+
+ public FormalBinding(UnresolvedType type, int index) {
+ this(type, "unknown", index, 0, 0);
+ }
+
+ public FormalBinding(UnresolvedType type, String name, int index) {
+ this(type, name, index, 0, 0);
+ }
+
+ // ----
+
+ public String toString() {
+ return type.toString() + ":" + index;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public UnresolvedType getType() {
+ return type;
+ }
+
+ // ----
+
+ public static final FormalBinding[] NONE = new FormalBinding[0];
+
+ /**
+ * A marker class for bindings for which we want to ignore unbound issue and consider them as implicit binding - f.e. to handle
+ * JoinPoint in @AJ advices
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ public static class ImplicitFormalBinding extends FormalBinding {
+ public ImplicitFormalBinding(UnresolvedType type, String name, int index) {
+ super(type, name, index);
+ }
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HandlerPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HandlerPointcut.java
new file mode 100644
index 000000000..3f92ab04a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HandlerPointcut.java
@@ -0,0 +1,141 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+/**
+ * This is a kind of KindedPointcut. This belongs either in a hierarchy with it or in a new place to share code with other potential
+ * future statement-level pointcuts like synchronized and throws
+ */
+public class HandlerPointcut extends Pointcut {
+ TypePattern exceptionType;
+
+ private static final int MATCH_KINDS = Shadow.ExceptionHandler.bit;
+
+ public HandlerPointcut(TypePattern exceptionType) {
+ this.exceptionType = exceptionType;
+ this.pointcutKind = HANDLER;
+ }
+
+ public int couldMatchKinds() {
+ return MATCH_KINDS;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ // ??? should be able to do better by finding all referenced types in type
+ return FuzzyBoolean.MAYBE;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ if (shadow.getKind() != Shadow.ExceptionHandler) {
+ return FuzzyBoolean.NO;
+ }
+
+ exceptionType.resolve(shadow.getIWorld());
+
+ // we know we have exactly one parameter since we're checking an exception handler
+ return exceptionType.matches(shadow.getSignature().getParameterTypes()[0].resolve(shadow.getIWorld()), TypePattern.STATIC);
+ }
+
+ public Pointcut parameterizeWith(Map typeVariableMap, World w) {
+ HandlerPointcut ret = new HandlerPointcut(exceptionType.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof HandlerPointcut)) {
+ return false;
+ }
+ HandlerPointcut o = (HandlerPointcut) other;
+ return o.exceptionType.equals(this.exceptionType);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + exceptionType.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("handler(");
+ buf.append(exceptionType.toString());
+ buf.append(")");
+ return buf.toString();
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.HANDLER);
+ exceptionType.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ HandlerPointcut ret = new HandlerPointcut(TypePattern.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ // XXX note: there is no namebinding in any kinded pointcut.
+ // still might want to do something for better error messages
+ // We want to do something here to make sure we don't sidestep the parameter
+ // list in capturing type identifiers.
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ exceptionType = exceptionType.resolveBindings(scope, bindings, false, false);
+ boolean invalidParameterization = false;
+ if (exceptionType.getTypeParameters().size() > 0) {
+ invalidParameterization = true;
+ }
+ UnresolvedType exactType = exceptionType.getExactType();
+ if (exactType != null && exactType.isParameterizedType()) {
+ invalidParameterization = true;
+ }
+ if (invalidParameterization) {
+ // no parameterized or generic types for handler
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.HANDLER_PCD_DOESNT_SUPPORT_PARAMETERS),
+ getSourceLocation()));
+ }
+ // XXX add error if exact binding and not an exception
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
+ }
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ Pointcut ret = new HandlerPointcut(exceptionType);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePattern.java
new file mode 100644
index 000000000..2b1f28fd4
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePattern.java
@@ -0,0 +1,196 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * Nieraj Singh
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ConcreteTypeMunger;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * @author colyer Matches types that have a certain method / constructor / field Currently only allowed within declare parents and
+ * declare @type
+ */
+public class HasMemberTypePattern extends TypePattern {
+
+ private SignaturePattern signaturePattern;
+
+ public HasMemberTypePattern(SignaturePattern aSignaturePattern) {
+ super(false, false);
+ this.signaturePattern = aSignaturePattern;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ if (signaturePattern.getKind() == Member.FIELD) {
+ return hasField(type);
+ } else {
+ return hasMethod(type);
+ }
+ }
+
+ public ISignaturePattern getSignaturePattern() {
+ return signaturePattern;
+ }
+
+ private final static String declareAtPrefix = "ajc$declare_at";
+
+ private boolean hasField(ResolvedType type) {
+ // TODO what about ITDs
+ World world = type.getWorld();
+ for (Iterator iter = type.getFields(); iter.hasNext();) {
+ Member field = (Member) iter.next();
+ if (field.getName().startsWith(declareAtPrefix)) {
+ continue;
+ }
+ if (signaturePattern.matches(field, type.getWorld(), false)) {
+ if (field.getDeclaringType().resolve(world) != type) {
+ if (Modifier.isPrivate(field.getModifiers())) {
+ continue;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean hasMethod(ResolvedType type) {
+ // TODO what about ITDs
+ World world = type.getWorld();
+ for (Iterator<ResolvedMember> iter = type.getMethods(true, true); iter.hasNext();) {
+ Member method = (Member) iter.next();
+ if (method.getName().startsWith(declareAtPrefix)) {
+ continue;
+ }
+ if (signaturePattern.matches(method, type.getWorld(), false)) {
+ ResolvedType declaringType = method.getDeclaringType().resolve(world);
+ if (declaringType != type) {
+ if (Modifier.isPrivate(method.getModifiers())) {
+ continue;
+ }
+ }
+ // J9: Object.finalize() is marked Deprecated it seems... triggers unhelpful messages
+ if (method.getName().equals("finalize") && declaringType.equals(ResolvedType.OBJECT)
+ && (signaturePattern.getAnnotationPattern() instanceof ExactAnnotationTypePattern)
+ && ((ExactAnnotationTypePattern)signaturePattern.getAnnotationPattern()).getAnnotationType().getSignature().equals("Ljava/lang/Deprecated;")) {
+ continue;
+ }
+ return true;
+ }
+ }
+ // try itds before we give up (this doesnt find annotations - the signature returned may not include them)
+ List<ConcreteTypeMunger> mungers = type.getInterTypeMungersIncludingSupers();
+ for (Iterator<ConcreteTypeMunger> iter = mungers.iterator(); iter.hasNext();) {
+ ConcreteTypeMunger munger = iter.next();
+ Member member = munger.getSignature();
+ if (signaturePattern.matches(member, type.getWorld(), false)) {
+ if (!Modifier.isPublic(member.getModifiers())) {
+ continue;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ return matchesExactly(type);
+ }
+
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ throw new UnsupportedOperationException("hasmethod/field do not support instanceof matching");
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map typeVariableMap, World w) {
+ HasMemberTypePattern ret = new HasMemberTypePattern(signaturePattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ // check that hasmember type patterns are allowed!
+ if (!scope.getWorld().isHasMemberSupportEnabled()) {
+ String msg = WeaverMessages.format(WeaverMessages.HAS_MEMBER_NOT_ENABLED, this.toString());
+ scope.message(IMessage.ERROR, this, msg);
+ }
+ signaturePattern.resolveBindings(scope, bindings);
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof HasMemberTypePattern)) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ return signaturePattern.equals(((HasMemberTypePattern) obj).signaturePattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return signaturePattern.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buff = new StringBuffer();
+ if (signaturePattern.getKind() == Member.FIELD) {
+ buff.append("hasfield(");
+ } else {
+ buff.append("hasmethod(");
+ }
+ buff.append(signaturePattern.toString());
+ buff.append(")");
+ return buff.toString();
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(TypePattern.HAS_MEMBER);
+ signaturePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ SignaturePattern sp = SignaturePattern.read(s, context);
+ HasMemberTypePattern ret = new HasMemberTypePattern(sp);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternFinder.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternFinder.java
new file mode 100644
index 000000000..5fb59503f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternFinder.java
@@ -0,0 +1,33 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+/**
+ * @author colyer
+ * usage : new HasMemberTypePatternFinder(pattern).hasMemberTypePattern()
+ */
+public class HasMemberTypePatternFinder extends AbstractPatternNodeVisitor {
+
+ private boolean hasMemberTypePattern = false;
+
+ public HasMemberTypePatternFinder(TypePattern aPattern) {
+ aPattern.traverse(this, null);
+ }
+
+ public Object visit(HasMemberTypePattern node, Object data) {
+ hasMemberTypePattern = true;
+ return null;
+ }
+
+ public boolean hasMemberTypePattern() { return hasMemberTypePattern; }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternForPerThisMatching.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternForPerThisMatching.java
new file mode 100644
index 000000000..128338f8e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasMemberTypePatternForPerThisMatching.java
@@ -0,0 +1,65 @@
+/* *******************************************************************
+ * Copyright (c) 2011 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ConcreteTypeMunger;
+import org.aspectj.weaver.ResolvedType;
+
+/**
+ * pr354470. This is a special subtype of HasMemberTypePattern. In order to optimize this situation: <br>
+ * <code><pre>
+ * aspect X perthis(transactional()) {<br>
+ * pointcut transactional: execution(@Foo * *(..));<br>
+ * </pre></code>
+ * <p>
+ * When this occurs we obviously only want an aspect instance when there is a method annotated with @Foo. For a regular execution
+ * pointcut we couldn't really do this due to the multiple joinpoint signatures for each joinpoint (and so lots of types get the
+ * ajcMightHaveAspect interface). However, for an execution pointcut involving an annotation we can do something clever. Annotations
+ * must match against the first primary joinpoint signature - so when computing the type pattern to use for matching when processing
+ * the perthis() clause above, we can use the HasMemberTypePattern - because that effectively does what we want. We want an aspect
+ * instance if the type hasmethod(...) with the appropriate annotation. This would be great... but breaks in the face of ITDs. If
+ * the method that hasmethod() would match is introduced via an ITD we come unstuck, the code in HasMemberTypePattern.hasMethod()
+ * does look at ITDs but it won't see annotations, they aren't visible (at least through EclipseResolvedMember objects). And so this
+ * subclass is created to say 'if the supertype thinks it is a match, great, but if it doesnt then if there are ITDs on the target,
+ * they might match so just say 'true''. Note that returning true is just confirming whether the 'mightHaveAspect' interface (and
+ * friends) are getting added.
+ *
+ * @author Andy Clement
+ */
+public class HasMemberTypePatternForPerThisMatching extends HasMemberTypePattern {
+
+ public HasMemberTypePatternForPerThisMatching(SignaturePattern aSignaturePattern) {
+ super(aSignaturePattern);
+ }
+
+ protected boolean hasMethod(ResolvedType type) {
+ boolean b = super.hasMethod(type);
+ if (b) {
+ return true;
+ }
+ // If there are ITDs, have to be safe and just assume one of them might match
+ List<ConcreteTypeMunger> mungers = type.getInterTypeMungersIncludingSupers();
+ if (mungers.size() != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ throw new IllegalAccessError("Should never be called, these are transient and don't get serialized");
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor.java
new file mode 100644
index 000000000..0b2b9b5fc
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor.java
@@ -0,0 +1,50 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.UnresolvedType;
+
+/**
+ * @author colyer
+ *
+ */
+public class HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor
+ extends AbstractPatternNodeVisitor {
+
+ boolean ohYesItHas = false;
+
+ /**
+ * Is the Exact type parameterized?
+ * Generic is ok as that just means we resolved a simple type pattern to a generic type
+ */
+ public Object visit(ExactTypePattern node, Object data) {
+ UnresolvedType theExactType = node.getExactType();
+ if (theExactType.isParameterizedType()) ohYesItHas = true;
+ //if (theExactType.isGenericType()) ohYesItHas = true;
+ return data;
+ }
+
+ /**
+ * Any type bounds are bad.
+ * Type parameters are right out.
+ */
+ public Object visit(WildTypePattern node, Object data) {
+ if (node.getUpperBound() != null) ohYesItHas = true;
+ if (node.getLowerBound() != null) ohYesItHas = true;
+ if (node.getTypeParameters().size() != 0) ohYesItHas = true;
+ return data;
+ }
+
+ public boolean wellHasItThen/*?*/() {
+ return ohYesItHas;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IScope.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IScope.java
new file mode 100644
index 000000000..69ba19686
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IScope.java
@@ -0,0 +1,59 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.weaver.IHasPosition;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+public interface IScope {
+
+ /**
+ * @return the type corresponding to the name in this scope, or ResolvedType.MISSING if no such type exists
+ */
+ UnresolvedType lookupType(String name, IHasPosition location);
+
+ World getWorld();
+
+ ResolvedType getEnclosingType();
+
+ // these next three are used to create {@link BindingTypePattern} objects.
+ IMessageHandler getMessageHandler();
+
+ /**
+ * @return the formal associated with the name, or null if no such formal exists
+ */
+ FormalBinding lookupFormal(String name);
+
+ /**
+ * @return the formal with the index. Throws ArrayOutOfBounds exception if out of bounds
+ */
+ FormalBinding getFormal(int i);
+
+ int getFormalCount();
+
+ String[] getImportedPrefixes();
+
+ String[] getImportedNames();
+
+ void message(IMessage.Kind kind, IHasPosition location, String message);
+
+ void message(IMessage.Kind kind, IHasPosition location1, IHasPosition location2, String message);
+
+ void message(IMessage aMessage);
+
+ // ISourceLocation makeSourceLocation(ILocation location);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ISignaturePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ISignaturePattern.java
new file mode 100644
index 000000000..99ad99377
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ISignaturePattern.java
@@ -0,0 +1,32 @@
+package org.aspectj.weaver.patterns;
+
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+public interface ISignaturePattern {
+
+ byte PATTERN = 1;
+ byte NOT = 2;
+ byte OR = 3;
+ byte AND = 4;
+
+ boolean matches(Member member, World world, boolean b);
+
+ ISignaturePattern parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World world);
+
+ ISignaturePattern resolveBindings(IScope scope, Bindings none);
+
+ List<ExactTypePattern> getExactDeclaringTypes();
+
+ boolean isMatchOnAnyName();
+
+ boolean couldEverMatch(ResolvedType type);
+
+ boolean isStarAnnotation();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IToken.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IToken.java
new file mode 100644
index 000000000..aa925fd69
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IToken.java
@@ -0,0 +1,53 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.IHasPosition;
+
+public interface IToken extends IHasPosition {
+ public static final IToken EOF = BasicToken.makeOperator("<eof>", 0, 0);
+
+ /**
+ * Returns the string value of this token.
+ *
+ * If isIdentifier is false, then this string must be intern'd
+ * so that == matching can be used.
+ *
+ * If isIdentifier is true, interning is not required.
+ */
+ public String getString();
+
+ /**
+ * Whether this should be treated as a token or a generic identifier
+ */
+ public boolean isIdentifier();
+
+ /**
+ * Whether this should be treated as a literal value
+ *
+ * Kinds == "string", ???
+ *
+ * returns null if this isn't a literal
+ */
+ public String getLiteralKind();
+
+
+ /**
+ * If this token represents a pre-parsed Pointcut, then return it;
+ * otherwise returns null.
+ *
+ * Needed for the implementation of 'if'
+ */
+ public Pointcut maybeGetParsedPointcut();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ITokenSource.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ITokenSource.java
new file mode 100644
index 000000000..4649b046f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ITokenSource.java
@@ -0,0 +1,27 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.ISourceContext;
+
+
+public interface ITokenSource {
+ public IToken next();
+ public IToken peek();
+ public IToken peek(int offset);
+ public int getIndex();
+ public void setIndex(int newIndex);
+ public ISourceContext getSourceContext();
+ public boolean hasMoreTokens();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IVerificationRequired.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IVerificationRequired.java
new file mode 100644
index 000000000..f1ce19eff
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IVerificationRequired.java
@@ -0,0 +1,22 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement IBM initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+
+/**
+ * Implementors provide a 'verify()' method that is invoked at the end of type
+ * binding completion.
+ * @see WildTypePattern.VerifyBoundsForTypePattern
+ */
+public interface IVerificationRequired {
+ public void verify();
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IfPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IfPointcut.java
new file mode 100644
index 000000000..a845153f9
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/IfPointcut.java
@@ -0,0 +1,614 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Alexandre Vasseur if() implementation for @AJ style
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedMemberImpl;
+import org.aspectj.weaver.ResolvedPointcutDefinition;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+public class IfPointcut extends Pointcut {
+ public ResolvedMember testMethod;
+ public int extraParameterFlags;
+
+ /**
+ * A token source dump that looks like a pointcut (but is NOT parseable at all - just here to help debugging etc)
+ */
+ private final String enclosingPointcutHint;
+
+ public Pointcut residueSource;
+ int baseArgsCount;
+
+ // XXX some way to compute args
+
+ public IfPointcut(ResolvedMember testMethod, int extraParameterFlags) {
+ this.testMethod = testMethod;
+ this.extraParameterFlags = extraParameterFlags;
+ this.pointcutKind = IF;
+ this.enclosingPointcutHint = null;
+ }
+
+ /**
+ * No-arg constructor for @AJ style, where the if() body is actually the @Pointcut annotated method
+ */
+ public IfPointcut(String enclosingPointcutHint) {
+ this.pointcutKind = IF;
+ this.enclosingPointcutHint = enclosingPointcutHint;
+ this.testMethod = null;// resolved during concretize
+ this.extraParameterFlags = -1;// allows to keep track of the @Aj style
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ if ((extraParameterFlags & Advice.ConstantReference) != 0) {
+ if ((extraParameterFlags & Advice.ConstantValue) != 0) {
+ return FuzzyBoolean.YES;
+ } else {
+ return FuzzyBoolean.NO;
+ }
+ }
+ // ??? this is not maximally efficient
+ return FuzzyBoolean.MAYBE;
+ }
+
+ public boolean alwaysFalse() {
+ return false;
+ }
+
+ public boolean alwaysTrue() {
+ return false;
+ }
+
+ // enh 76055
+ public Pointcut getResidueSource() {
+ return residueSource;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.IF);
+ s.writeBoolean(testMethod != null); // do we have a test method?
+ if (testMethod != null) {
+ testMethod.write(s);
+ }
+ s.writeByte(extraParameterFlags);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ boolean hasTestMethod = s.readBoolean();
+ ResolvedMember resolvedTestMethod = null;
+ if (hasTestMethod) { // should always have a test method unless @AJ style
+ resolvedTestMethod = ResolvedMemberImpl.readResolvedMember(s, context);
+ }
+ IfPointcut ret = new IfPointcut(resolvedTestMethod, s.readByte());
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ // ??? all we need is good error messages in here in cflow contexts
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof IfPointcut)) {
+ return false;
+ }
+ IfPointcut o = (IfPointcut) other;
+ if (o.testMethod == null) {
+ return (this.testMethod == null);
+ }
+ return o.testMethod.equals(this.testMethod);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + testMethod.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ if (extraParameterFlags < 0) {
+ // @AJ style
+ return "if()";
+ } else {
+ return "if(" + testMethod + ")";// FIXME AV - bad, this makes it unparsable. Perhaps we can use if() for code style
+ // behind the scene!
+ }
+ }
+
+ // ??? The implementation of name binding and type checking in if PCDs is very convoluted
+ // There has to be a better way...
+ private boolean findingResidue = false;
+
+ // Similar to lastMatchedShadowId - but only for if PCDs.
+ private int ifLastMatchedShadowId;
+ private Test ifLastMatchedShadowResidue;
+
+ /**
+ * At each shadow that matched, the residue can be different.
+ */
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ if (findingResidue) {
+ return Literal.TRUE;
+ }
+ findingResidue = true;
+ try {
+
+ // Have we already been asked this question?
+ if (shadow.shadowId == ifLastMatchedShadowId) {
+ return ifLastMatchedShadowResidue;
+ }
+
+ Test ret = Literal.TRUE;
+ List<Var> args = new ArrayList<Var>();
+
+ // code style
+ if (extraParameterFlags >= 0) {
+ if ((extraParameterFlags & Advice.ConstantReference) != 0) {
+ // it is either always true or always false, no need for test
+ if ((extraParameterFlags & Advice.ConstantValue) != 0) {
+ ret = Literal.TRUE;
+ ifLastMatchedShadowId = shadow.shadowId;
+ ifLastMatchedShadowResidue = ret;
+ return ret;
+ } else {
+ // Dont think we should be in here as the match cannot have succeeded...
+ ret = Literal.FALSE;
+ ifLastMatchedShadowId = shadow.shadowId;
+ ifLastMatchedShadowResidue = ret;
+ return ret;
+ }
+ }
+
+ // If there are no args to sort out, don't bother with the recursive call
+ if (baseArgsCount > 0) {
+ ExposedState myState = new ExposedState(baseArgsCount);
+ myState.setConcreteAspect(state.getConcreteAspect());
+ // ??? we throw out the test that comes from this walk. All we want here
+ // is bindings for the arguments
+ residueSource.findResidue(shadow, myState);
+
+ UnresolvedType[] pTypes = (testMethod == null ? null : testMethod.getParameterTypes());
+ if (pTypes != null && baseArgsCount > pTypes.length) { // pr155347
+ throw new BCException("Unexpected problem with testMethod " + testMethod + ": expecting " + baseArgsCount
+ + " arguments");
+ }
+ // pr118149
+ // It is possible for vars in myState (which would normally be set
+ // in the call to residueSource.findResidue) to not be set (be null)
+ // in an Or pointcut with if expressions in both branches, and where
+ // one branch is known statically to not match. In this situation we
+ // simply return Test.
+ for (int i = 0; i < baseArgsCount; i++) {
+ Var v = myState.get(i);
+ if (v == null) {
+ continue; // pr118149
+ }
+ args.add(v);
+ ret = Test.makeAnd(ret, Test.makeInstanceof(v, pTypes[i].resolve(shadow.getIWorld())));
+ }
+ }
+
+ // handle thisJoinPoint parameters
+ if ((extraParameterFlags & Advice.ThisJoinPoint) != 0) {
+ args.add(shadow.getThisJoinPointVar());
+ }
+
+ if ((extraParameterFlags & Advice.ThisJoinPointStaticPart) != 0) {
+ args.add(shadow.getThisJoinPointStaticPartVar());
+ }
+
+ if ((extraParameterFlags & Advice.ThisEnclosingJoinPointStaticPart) != 0) {
+ args.add(shadow.getThisEnclosingJoinPointStaticPartVar());
+ }
+
+ if ((extraParameterFlags & Advice.ThisAspectInstance) != 0) {
+ args.add(shadow.getThisAspectInstanceVar(state.getConcreteAspect()));
+ }
+ } else {
+ // @style is slightly different
+ int currentStateIndex = 0;
+ // FIXME AV - "args(jp)" test(jp, thejp) will fail here
+ for (int i = 0; i < testMethod.getParameterTypes().length; i++) {
+ String argSignature = testMethod.getParameterTypes()[i].getSignature();
+ if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argSignature)) {
+ args.add(shadow.getThisJoinPointVar());
+ } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argSignature)) {
+ args.add(shadow.getThisJoinPointVar());
+ } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argSignature)) {
+ args.add(shadow.getThisJoinPointStaticPartVar());
+ } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argSignature)) {
+ args.add(shadow.getThisEnclosingJoinPointStaticPartVar());
+ } else {
+ if (state.size() == 0 || currentStateIndex > state.size()) {
+ String[] paramNames = testMethod.getParameterNames();
+ StringBuffer errorParameter = new StringBuffer();
+ if (paramNames != null) {
+ errorParameter.append(testMethod.getParameterTypes()[i].getName()).append(" ");
+ errorParameter.append(paramNames[i]);
+ shadow.getIWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil.error("Missing binding for if() pointcut method. Parameter " + (i + 1)
+ + "(" + errorParameter.toString()
+ + ") must be bound - even in reference pointcuts (compiler limitation)",
+ testMethod.getSourceLocation()));
+ } else {
+ shadow.getIWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil.error("Missing binding for if() pointcut method. Parameter " + (i + 1)
+ + " must be bound - even in reference pointcuts (compiler limitation)",
+ testMethod.getSourceLocation()));
+ }
+ return Literal.TRUE; // exit quickly
+ }
+ // we don't use i as JoinPoint.* can be anywhere in the signature in @style
+ Var v = state.get(currentStateIndex++);
+
+ while (v == null && currentStateIndex < state.size()) { // pr162135
+ v = state.get(currentStateIndex++);
+ }
+ args.add(v);
+
+ ret = Test.makeAnd(ret,
+ Test.makeInstanceof(v, testMethod.getParameterTypes()[i].resolve(shadow.getIWorld())));
+ }
+ }
+ }
+
+ ret = Test.makeAnd(ret, Test.makeCall(testMethod, (Expr[]) args.toArray(new Expr[args.size()])));
+
+ // Remember...
+ ifLastMatchedShadowId = shadow.shadowId;
+ ifLastMatchedShadowResidue = ret;
+ return ret;
+ } finally {
+ findingResidue = false;
+ }
+ }
+
+ // amc - the only reason this override seems to be here is to stop the copy, but
+ // that can be prevented by overriding shouldCopyLocationForConcretization,
+ // allowing me to make the method final in Pointcut.
+ // public Pointcut concretize(ResolvedType inAspect, IntMap bindings) {
+ // return this.concretize1(inAspect, bindings);
+ // }
+
+ @Override
+ protected boolean shouldCopyLocationForConcretize() {
+ return false;
+ }
+
+ private IfPointcut partiallyConcretized = null;
+
+ @Override
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ // System.err.println("concretize: " + this + " already: " + partiallyConcretized);
+
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ // Enforce rule about which designators are supported in declare
+ inAspect.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.IF_IN_DECLARE),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+
+ if (partiallyConcretized != null) {
+ return partiallyConcretized;
+ }
+
+ final IfPointcut ret;
+ if (extraParameterFlags < 0 && testMethod == null) {
+ // @AJ style, we need to find the testMethod in the aspect defining the "if()" enclosing pointcut
+ ResolvedPointcutDefinition def = bindings.peekEnclosingDefinition();
+ if (def != null) {
+ ResolvedType aspect = inAspect.getWorld().resolve(def.getDeclaringType());
+ for (Iterator memberIter = aspect.getMethods(true, true); memberIter.hasNext();) {
+ ResolvedMember method = (ResolvedMember) memberIter.next();
+ if (def.getName().equals(method.getName())
+ && def.getParameterTypes().length == method.getParameterTypes().length) {
+ boolean sameSig = true;
+ for (int j = 0; j < method.getParameterTypes().length; j++) {
+ UnresolvedType argJ = method.getParameterTypes()[j];
+ if (!argJ.equals(def.getParameterTypes()[j])) {
+ sameSig = false;
+ break;
+ }
+ }
+ if (sameSig) {
+ testMethod = method;
+ break;
+ }
+ }
+ }
+ if (testMethod == null) {
+ inAspect.getWorld().showMessage(IMessage.ERROR,
+ "Cannot find if() body from '" + def.toString() + "' for '" + enclosingPointcutHint + "'",
+ this.getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+ } else {
+ testMethod = inAspect.getWorld().resolve(bindings.getAdviceSignature());
+ }
+ ret = new IfPointcut(enclosingPointcutHint);
+ ret.testMethod = testMethod;
+ } else {
+ ret = new IfPointcut(testMethod, extraParameterFlags);
+ }
+ ret.copyLocationFrom(this);
+ partiallyConcretized = ret;
+
+ // It is possible to directly code your pointcut expression in a per clause
+ // rather than defining a pointcut declaration and referencing it in your
+ // per clause. If you do this, we have problems (bug #62458). For now,
+ // let's police that you are trying to code a pointcut in a per clause and
+ // put out a compiler error.
+ if (bindings.directlyInAdvice() && bindings.getEnclosingAdvice() == null) {
+ // Assumption: if() is in a per clause if we say we are directly in advice
+ // but we have no enclosing advice.
+ inAspect.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.IF_IN_PERCLAUSE),
+ this.getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+
+ if (bindings.directlyInAdvice()) {
+ ShadowMunger advice = bindings.getEnclosingAdvice();
+ if (advice instanceof Advice) {
+ ret.baseArgsCount = ((Advice) advice).getBaseParameterCount();
+ } else {
+ ret.baseArgsCount = 0;
+ }
+ ret.residueSource = advice.getPointcut().concretize(inAspect, inAspect, ret.baseArgsCount, advice);
+ } else {
+ ResolvedPointcutDefinition def = bindings.peekEnclosingDefinition();
+ if (def == CflowPointcut.CFLOW_MARKER) {
+ inAspect.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.IF_LEXICALLY_IN_CFLOW),
+ getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+ ret.baseArgsCount = def.getParameterTypes().length;
+
+ // for @style, we have implicit binding for JoinPoint.* things
+ // FIXME AV - will lead to failure for "args(jp)" test(jp, thejp) / see args() implementation
+ if (ret.extraParameterFlags < 0) {
+ ret.baseArgsCount = 0;
+ for (int i = 0; i < testMethod.getParameterTypes().length; i++) {
+ String argSignature = testMethod.getParameterTypes()[i].getSignature();
+ if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argSignature)
+ || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argSignature)
+ || AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argSignature)
+ || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argSignature)) {
+
+ } else {
+ ret.baseArgsCount++;
+ }
+ }
+ }
+
+ IntMap newBindings = IntMap.idMap(ret.baseArgsCount);
+ newBindings.copyContext(bindings);
+ ret.residueSource = def.getPointcut().concretize(inAspect, declaringType, newBindings);
+ }
+
+ return ret;
+ }
+
+ // we can't touch "if" methods
+ @Override
+ public Pointcut parameterizeWith(Map typeVariableMap, World w) {
+ return this;
+ }
+
+ // public static Pointcut MatchesNothing = new MatchesNothingPointcut();
+ // ??? there could possibly be some good optimizations to be done at this point
+ public static IfPointcut makeIfFalsePointcut(State state) {
+ IfPointcut ret = new IfFalsePointcut();
+ ret.state = state;
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public static class IfFalsePointcut extends IfPointcut {
+
+ public IfFalsePointcut() {
+ super(null, 0);
+ this.pointcutKind = Pointcut.IF_FALSE;
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return Shadow.NO_SHADOW_KINDS_BITS;
+ }
+
+ @Override
+ public boolean alwaysFalse() {
+ return true;
+ }
+
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return Literal.FALSE; // can only get here if an earlier error occurred
+ }
+
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ }
+
+ @Override
+ public void postRead(ResolvedType enclosingType) {
+ }
+
+ @Override
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ // Enforce rule about which designators are supported in declare
+ inAspect.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.IF_IN_DECLARE),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+ return makeIfFalsePointcut(state);
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.IF_FALSE);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "if(false)";
+ }
+ }
+
+ public static IfPointcut makeIfTruePointcut(State state) {
+ IfPointcut ret = new IfTruePointcut();
+ ret.state = state;
+ return ret;
+ }
+
+ public static class IfTruePointcut extends IfPointcut {
+
+ public IfTruePointcut() {
+ super(null, 0);
+ this.pointcutKind = Pointcut.IF_TRUE;
+ }
+
+ @Override
+ public boolean alwaysTrue() {
+ return true;
+ }
+
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return Literal.TRUE; // can only get here if an earlier error occurred
+ }
+
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.YES;
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ return FuzzyBoolean.YES;
+ }
+
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ }
+
+ @Override
+ public void postRead(ResolvedType enclosingType) {
+ }
+
+ @Override
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ // Enforce rule about which designators are supported in declare
+ inAspect.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.IF_IN_DECLARE),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+ return makeIfTruePointcut(state);
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(IF_TRUE);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 37;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "if(true)";
+ }
+ }
+
+ /**
+ * Called when it is determined that the pointcut refers to a constant value of TRUE or FALSE - enabling exact matching and no
+ * unnecessary calls to the method representing the if body.
+ */
+ public void setAlways(boolean matches) {
+ extraParameterFlags |= Advice.ConstantReference;
+ if (matches) {
+ extraParameterFlags |= Advice.ConstantValue;
+ }
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/KindedPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/KindedPointcut.java
new file mode 100644
index 000000000..56a45892d
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/KindedPointcut.java
@@ -0,0 +1,478 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import static org.aspectj.util.FuzzyBoolean.MAYBE;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Checker;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+public class KindedPointcut extends Pointcut {
+ Shadow.Kind kind;
+ private SignaturePattern signature;
+ private int matchKinds;
+
+ private ShadowMunger munger = null; // only set after concretization
+
+ public KindedPointcut(Shadow.Kind kind, SignaturePattern signature) {
+ this.kind = kind;
+ this.signature = signature;
+ this.pointcutKind = KINDED;
+ this.matchKinds = kind.bit;
+ }
+
+ public KindedPointcut(Shadow.Kind kind, SignaturePattern signature, ShadowMunger munger) {
+ this(kind, signature);
+ this.munger = munger;
+ }
+
+ public SignaturePattern getSignature() {
+ return signature;
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return matchKinds;
+ }
+
+ public boolean couldEverMatchSameJoinPointsAs(KindedPointcut other) {
+ if (this.kind != other.kind) {
+ return false;
+ }
+ String myName = signature.getName().maybeGetSimpleName();
+ String yourName = other.signature.getName().maybeGetSimpleName();
+ if (myName != null && yourName != null) {
+ if (!myName.equals(yourName)) {
+ return false;
+ }
+ }
+ if (signature.getParameterTypes().ellipsisCount == 0) {
+ if (other.signature.getParameterTypes().ellipsisCount == 0) {
+ if (signature.getParameterTypes().getTypePatterns().length != other.signature.getParameterTypes().getTypePatterns().length) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ // info.getKind()==null means all kinds
+ if (info.getKind() != null) {
+ if (info.getKind() != kind) {
+ return FuzzyBoolean.NO;
+ }
+ }
+
+ // KindedPointcut represents these join points:
+ // method-execution/ctor-execution/method-call/ctor-call/field-get/field-set/advice-execution/static-initialization
+ // initialization/pre-initialization
+
+ // Check if the global fastmatch flag is on - the flag can be removed (and this made default) once it proves stable!
+ if (info.world.optimizedMatching) {
+
+ // For now, just consider MethodExecution and Initialization
+ if ((kind == Shadow.MethodExecution || kind == Shadow.Initialization) && info.getKind() == null) {
+ boolean fastMatchingOnAspect = info.getType().isAspect();
+ // an Aspect may define ITDs, and although our signature declaring type pattern may not match on the
+ // aspect, the ITDs may have a different signature as we iterate through the members of the aspect. Let's not
+ // try and work through that here and just say MAYBE
+ if (fastMatchingOnAspect) {
+ return MAYBE;
+ }
+ // Aim here is to do the same test as is done for signature pattern declaring type pattern matching
+ if (this.getSignature().isExactDeclaringTypePattern()) {
+ ExactTypePattern typePattern = (ExactTypePattern) this.getSignature().getDeclaringType();
+ // Interface checks are more expensive, they could be anywhere...
+ ResolvedType patternExactType = typePattern.getResolvedExactType(info.world);
+ if (patternExactType.isInterface()) {
+ ResolvedType curr = info.getType();
+ Iterator<ResolvedType> hierarchyWalker = curr.getHierarchy(true, true);
+ boolean found = false;
+ while (hierarchyWalker.hasNext()) {
+ curr = hierarchyWalker.next();
+ if (typePattern.matchesStatically(curr)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return FuzzyBoolean.NO;
+ }
+ } else if (patternExactType.isClass()) {
+ ResolvedType curr = info.getType();
+ do {
+ if (typePattern.matchesStatically(curr)) {
+ break;
+ }
+ curr = curr.getSuperclass();
+ } while (curr != null);
+ if (curr == null) {
+ return FuzzyBoolean.NO;
+ }
+ }
+ } else if (this.getSignature().getDeclaringType() instanceof AnyWithAnnotationTypePattern) {
+ // aim here is to say NO if the annotation is not possible in the hierarchy here
+ ResolvedType type = info.getType();
+ AnnotationTypePattern annotationTypePattern = ((AnyWithAnnotationTypePattern) getSignature().getDeclaringType())
+ .getAnnotationPattern();
+ if (annotationTypePattern instanceof ExactAnnotationTypePattern) {
+ ExactAnnotationTypePattern exactAnnotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern;
+ if (exactAnnotationTypePattern.getAnnotationValues() == null
+ || exactAnnotationTypePattern.getAnnotationValues().size() == 0) {
+ ResolvedType annotationType = exactAnnotationTypePattern.getAnnotationType().resolve(info.world);
+ if (type.hasAnnotation(annotationType)) {
+ return FuzzyBoolean.MAYBE;
+ }
+ if (annotationType.isInheritedAnnotation()) {
+ // ok - we may be picking it up from further up the hierarchy (but only a super*class*)
+ ResolvedType toMatchAgainst = type.getSuperclass();
+ boolean found = false;
+ while (toMatchAgainst != null) {
+ if (toMatchAgainst.hasAnnotation(annotationType)) {
+ found = true;
+ break;
+ }
+ toMatchAgainst = toMatchAgainst.getSuperclass();
+ }
+ if (!found) {
+ return FuzzyBoolean.NO;
+ }
+ } else {
+ return FuzzyBoolean.NO;
+ }
+ }
+ }
+ } else if (this.getSignature().getDeclaringType() instanceof WildTypePattern) {
+ final WildTypePattern pattern = (WildTypePattern) this.getSignature().getDeclaringType();
+ final ResolvedType type = info.getType();
+ return pattern.matches(type, TypePattern.STATIC);
+ }
+ }
+ }
+
+ return FuzzyBoolean.MAYBE;
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ if (shadow.getKind() != kind) {
+ return FuzzyBoolean.NO;
+ }
+
+ if (shadow.getKind() == Shadow.SynchronizationLock && kind == Shadow.SynchronizationLock) {
+ return FuzzyBoolean.YES;
+ }
+ if (shadow.getKind() == Shadow.SynchronizationUnlock && kind == Shadow.SynchronizationUnlock) {
+ return FuzzyBoolean.YES;
+ }
+
+ if (!signature.matches(shadow.getMatchingSignature(), shadow.getIWorld(), this.kind == Shadow.MethodCall)) {
+
+ if (kind == Shadow.MethodCall) {
+ warnOnConfusingSig(shadow);
+ // warnOnBridgeMethod(shadow);
+ }
+ return FuzzyBoolean.NO;
+ }
+
+ return FuzzyBoolean.YES;
+ }
+
+ // private void warnOnBridgeMethod(Shadow shadow) {
+ // if (shadow.getIWorld().getLint().noJoinpointsForBridgeMethods.isEnabled()) {
+ // ResolvedMember rm = shadow.getSignature().resolve(shadow.getIWorld());
+ // if (rm!=null) {
+ // int shadowModifiers = rm.getModifiers(); //shadow.getSignature().getModifiers(shadow.getIWorld());
+ // if (ResolvedType.hasBridgeModifier(shadowModifiers)) {
+ // shadow.getIWorld().getLint().noJoinpointsForBridgeMethods.signal(new String[]{},getSourceLocation(),
+ // new ISourceLocation[]{shadow.getSourceLocation()});
+ // }
+ // }
+ // }
+ // }
+
+ private void warnOnConfusingSig(Shadow shadow) {
+ // Don't do all this processing if we don't need to !
+ if (!shadow.getIWorld().getLint().unmatchedSuperTypeInCall.isEnabled()) {
+ return;
+ }
+
+ // no warnings for declare error/warning
+ if (munger instanceof Checker) {
+ return;
+ }
+
+ World world = shadow.getIWorld();
+
+ // warning never needed if the declaring type is any
+ UnresolvedType exactDeclaringType = signature.getDeclaringType().getExactType();
+
+ ResolvedType shadowDeclaringType = shadow.getSignature().getDeclaringType().resolve(world);
+
+ if (signature.getDeclaringType().isStar() || ResolvedType.isMissing(exactDeclaringType)
+ || exactDeclaringType.resolve(world).isMissing()) {
+ return;
+ }
+
+ // warning not needed if match type couldn't ever be the declaring type
+ if (!shadowDeclaringType.isAssignableFrom(exactDeclaringType.resolve(world))) {
+ return;
+ }
+
+ // if the method in the declaring type is *not* visible to the
+ // exact declaring type then warning not needed.
+ ResolvedMember rm = shadow.getSignature().resolve(world);
+ // rm can be null in the case where we are binary weaving, and looking at a class with a call to a method in another class,
+ // but because of class incompatibilities, the method does not exist on the target class anymore.
+ // this will be reported elsewhere.
+ if (rm == null) {
+ return;
+ }
+
+ int shadowModifiers = rm.getModifiers();
+ if (!ResolvedType.isVisible(shadowModifiers, shadowDeclaringType, exactDeclaringType.resolve(world))) {
+ return;
+ }
+
+ if (!signature.getReturnType().matchesStatically(shadow.getSignature().getReturnType().resolve(world))) {
+ // Covariance issue...
+ // The reason we didn't match is that the type pattern for the pointcut (Car) doesn't match the
+ // return type for the specific declaration at the shadow. (FastCar Sub.getCar())
+ // XXX Put out another XLINT in this case?
+ return;
+ }
+ // PR60015 - Don't report the warning if the declaring type is object and 'this' is an interface
+ if (exactDeclaringType.resolve(world).isInterface() && shadowDeclaringType.equals(world.resolve("java.lang.Object"))) {
+ return;
+ }
+
+ SignaturePattern nonConfusingPattern = new SignaturePattern(signature.getKind(), signature.getModifiers(),
+ signature.getReturnType(), TypePattern.ANY, signature.getName(), signature.getParameterTypes(),
+ signature.getThrowsPattern(), signature.getAnnotationPattern());
+
+ if (nonConfusingPattern.matches(shadow.getSignature(), shadow.getIWorld(), true)) {
+ shadow.getIWorld().getLint().unmatchedSuperTypeInCall.signal(new String[] {
+ shadow.getSignature().getDeclaringType().toString(), signature.getDeclaringType().toString() },
+ this.getSourceLocation(), new ISourceLocation[] { shadow.getSourceLocation() });
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof KindedPointcut)) {
+ return false;
+ }
+ KindedPointcut o = (KindedPointcut) other;
+ return o.kind == this.kind && o.signature.equals(this.signature);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + signature.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(kind.getSimpleName());
+ buf.append("(");
+ buf.append(signature.toString());
+ buf.append(")");
+ return buf.toString();
+ }
+
+ @Override
+ public void postRead(ResolvedType enclosingType) {
+ signature.postRead(enclosingType);
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.KINDED);
+ kind.write(s);
+ signature.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ Shadow.Kind kind = Shadow.Kind.read(s);
+ SignaturePattern sig = SignaturePattern.read(s, context);
+ KindedPointcut ret = new KindedPointcut(kind, sig);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ // XXX note: there is no namebinding in any kinded pointcut.
+ // still might want to do something for better error messages
+ // We want to do something here to make sure we don't sidestep the parameter
+ // list in capturing type identifiers.
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ if (kind == Shadow.Initialization) {
+ // scope.getMessageHandler().handleMessage(
+ // MessageUtil.error(
+ // "initialization unimplemented in 1.1beta1",
+ // this.getSourceLocation()));
+ }
+ signature = signature.resolveBindings(scope, bindings);
+
+ if (kind == Shadow.ConstructorExecution) { // Bug fix 60936
+ if (signature.getDeclaringType() != null) {
+ World world = scope.getWorld();
+ UnresolvedType exactType = signature.getDeclaringType().getExactType();
+ if (signature.getKind() == Member.CONSTRUCTOR && !ResolvedType.isMissing(exactType)
+ && exactType.resolve(world).isInterface() && !signature.getDeclaringType().isIncludeSubtypes()) {
+ world.getLint().noInterfaceCtorJoinpoint.signal(exactType.toString(), getSourceLocation());
+ }
+ }
+ }
+
+ // no parameterized types
+ if (kind == Shadow.StaticInitialization) {
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getDeclaringType().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_STATIC_INIT_JPS_FOR_PARAMETERIZED_TYPES),
+ getSourceLocation()));
+ }
+ }
+
+ // no parameterized types in declaring type position
+ if ((kind == Shadow.FieldGet) || (kind == Shadow.FieldSet)) {
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getDeclaringType().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.GET_AND_SET_DONT_SUPPORT_DEC_TYPE_PARAMETERS),
+ getSourceLocation()));
+ }
+
+ // fields can't have a void type!
+ UnresolvedType returnType = signature.getReturnType().getExactType();
+ if (returnType.equals(UnresolvedType.VOID)) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.FIELDS_CANT_HAVE_VOID_TYPE),
+ getSourceLocation()));
+ }
+ }
+
+ // no join points for initialization and preinitialization of parameterized types
+ // no throwable parameterized types
+ if ((kind == Shadow.Initialization) || (kind == Shadow.PreInitialization)) {
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getDeclaringType().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_INIT_JPS_FOR_PARAMETERIZED_TYPES),
+ getSourceLocation()));
+ }
+
+ visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getThrowsPattern().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_GENERIC_THROWABLES), getSourceLocation()));
+ }
+ }
+
+ // no parameterized types in declaring type position
+ // no throwable parameterized types
+ if ((kind == Shadow.MethodExecution) || (kind == Shadow.ConstructorExecution)) {
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getDeclaringType().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.EXECUTION_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES),
+ getSourceLocation()));
+ }
+
+ visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getThrowsPattern().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_GENERIC_THROWABLES), getSourceLocation()));
+ }
+ }
+
+ // no parameterized types in declaring type position
+ // no throwable parameterized types
+ if ((kind == Shadow.MethodCall) || (kind == Shadow.ConstructorCall)) {
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getDeclaringType().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.CALL_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES),
+ getSourceLocation()));
+ }
+
+ visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getThrowsPattern().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_GENERIC_THROWABLES), getSourceLocation()));
+ }
+ if (!scope.getWorld().isJoinpointArrayConstructionEnabled() && kind == Shadow.ConstructorCall
+ && signature.getDeclaringType().isArray()) {
+ scope.message(MessageUtil.warn(WeaverMessages.format(WeaverMessages.NO_NEWARRAY_JOINPOINTS_BY_DEFAULT),
+ getSourceLocation()));
+ }
+ }
+ }
+
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
+ }
+
+ @Override
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ Pointcut ret = new KindedPointcut(kind, signature, bindings.getEnclosingAdvice());
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ Pointcut ret = new KindedPointcut(kind, signature.parameterizeWith(typeVariableMap, w), munger);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public Shadow.Kind getKind() {
+ return kind;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ModifiersPattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ModifiersPattern.java
new file mode 100644
index 000000000..6c1d0557e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ModifiersPattern.java
@@ -0,0 +1,105 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.VersionedDataInputStream;
+
+public class ModifiersPattern extends PatternNode {
+ private int requiredModifiers;
+ private int forbiddenModifiers;
+
+ public static final ModifiersPattern ANY = new ModifiersPattern(0, 0);
+
+ private static Map<String, Integer> modifierFlags = null;
+
+ static {
+ modifierFlags = new HashMap<String, Integer>();
+ int flag = 1;
+ while (flag <= Modifier.STRICT) {
+ String flagName = Modifier.toString(flag);
+ modifierFlags.put(flagName, new Integer(flag));
+ flag = flag << 1;
+ }
+ modifierFlags.put("synthetic", new Integer(0x1000 /* Modifier.SYNTHETIC */));
+ }
+
+ public ModifiersPattern(int requiredModifiers, int forbiddenModifiers) {
+ this.requiredModifiers = requiredModifiers;
+ this.forbiddenModifiers = forbiddenModifiers;
+ }
+
+ public String toString() {
+ if (this == ANY) {
+ return "";
+ }
+
+ String ret = Modifier.toString(requiredModifiers);
+ if (forbiddenModifiers == 0) {
+ return ret;
+ } else {
+ return ret + " !" + Modifier.toString(forbiddenModifiers);
+ }
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof ModifiersPattern)) {
+ return false;
+ }
+ ModifiersPattern o = (ModifiersPattern) other;
+ return o.requiredModifiers == this.requiredModifiers && o.forbiddenModifiers == this.forbiddenModifiers;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + requiredModifiers;
+ result = 37 * result + forbiddenModifiers;
+ return result;
+ }
+
+ public boolean matches(int modifiers) {
+ return ((modifiers & requiredModifiers) == requiredModifiers) && ((modifiers & forbiddenModifiers) == 0);
+ }
+
+ public static ModifiersPattern read(VersionedDataInputStream s) throws IOException {
+ int requiredModifiers = s.readShort();
+ int forbiddenModifiers = s.readShort();
+ if (requiredModifiers == 0 && forbiddenModifiers == 0) {
+ return ANY;
+ }
+ return new ModifiersPattern(requiredModifiers, forbiddenModifiers);
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ // s.writeByte(MODIFIERS_PATTERN);
+ s.writeShort(requiredModifiers);
+ s.writeShort(forbiddenModifiers);
+ }
+
+ public static int getModifierFlag(String name) {
+ Integer flag = modifierFlags.get(name);
+ if (flag == null) {
+ return -1;
+ }
+ return flag.intValue();
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NameBindingPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NameBindingPointcut.java
new file mode 100644
index 000000000..34b25e207
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NameBindingPointcut.java
@@ -0,0 +1,52 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+import java.util.List;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * Common super type for Pointcuts that can bind formal parameters.
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public abstract class NameBindingPointcut extends Pointcut {
+
+ public NameBindingPointcut() {
+ super();
+ }
+
+ protected Test exposeStateForVar(Var var,TypePattern type, ExposedState state, World world) {
+ if (type instanceof BindingTypePattern) {
+ BindingTypePattern b = (BindingTypePattern)type;
+ state.set(b.getFormalIndex(), var);
+ }
+ ResolvedType myType = type.getExactType().resolve(world);
+ if (myType.isParameterizedType()) {
+ // unchecked warning already issued...
+ myType = (ResolvedType) myType.getRawType();
+ }
+ return Test.makeInstanceof(var, myType.resolve(world));
+ }
+
+ public abstract List<BindingTypePattern> getBindingTypePatterns();
+ public abstract List<BindingPattern> getBindingAnnotationTypePatterns();
+
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NamePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NamePattern.java
new file mode 100644
index 000000000..561b99197
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NamePattern.java
@@ -0,0 +1,208 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.VersionedDataInputStream;
+
+public class NamePattern extends PatternNode {
+ char[] pattern;
+ int starCount = 0;
+ private int hashcode = -1;
+
+ public static final NamePattern ELLIPSIS = new NamePattern("");
+ public static final NamePattern ANY = new NamePattern("*");
+
+ public NamePattern(String name) {
+ this(name.toCharArray());
+ }
+
+ public NamePattern(char[] pattern) {
+ this.pattern = pattern;
+
+ for (int i = 0, len = pattern.length; i < len; i++) {
+ if (pattern[i] == '*') {
+ starCount++;
+ }
+ }
+ hashcode = new String(pattern).hashCode();
+ }
+
+ public boolean matches(char[] a2) {
+ char[] a1 = pattern;
+ int len1 = a1.length;
+ int len2 = a2.length;
+ if (starCount == 0) {
+ if (len1 != len2) {
+ return false;
+ }
+ for (int i = 0; i < len1; i++) {
+ if (a1[i] != a2[i]) {
+ return false;
+ }
+ }
+ return true;
+ } else if (starCount == 1) {
+ // just '*' matches anything
+ if (len1 == 1) {
+ return true;
+ }
+ if (len1 > len2 + 1) {
+ return false;
+ }
+ int i2 = 0;
+ for (int i1 = 0; i1 < len1; i1++) {
+ char c1 = a1[i1];
+ if (c1 == '*') {
+ i2 = len2 - (len1 - (i1 + 1));
+ } else if (c1 != a2[i2++]) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ // System.err.print("match(\"" + pattern + "\", \"" + target + "\") -> ");
+ boolean b = outOfStar(a1, a2, 0, 0, len1 - starCount, len2, starCount);
+ // System.err.println(b);
+ return b;
+ }
+ }
+
+ private static boolean outOfStar(final char[] pattern, final char[] target, int pi, int ti, int pLeft, int tLeft,
+ final int starsLeft) {
+ if (pLeft > tLeft) {
+ return false;
+ }
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
+ if (tLeft == 0) {
+ return true;
+ }
+ if (pLeft == 0) {
+ return (starsLeft > 0);
+ }
+ if (pattern[pi] == '*') {
+ return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1);
+ }
+ if (target[ti] != pattern[pi]) {
+ return false;
+ }
+ pi++;
+ ti++;
+ pLeft--;
+ tLeft--;
+ }
+ }
+
+ private static boolean inStar(final char[] pattern, final char[] target, int pi, int ti, final int pLeft, int tLeft,
+ int starsLeft) {
+ // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
+ char patternChar = pattern[pi];
+ while (patternChar == '*') {
+ starsLeft--;
+ patternChar = pattern[++pi];
+ }
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length)
+ if (pLeft > tLeft) {
+ return false;
+ }
+ if (target[ti] == patternChar) {
+ if (outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft)) {
+ return true;
+ }
+ }
+ ti++;
+ tLeft--;
+ }
+ }
+
+ public boolean matches(String other) {
+ if (starCount == 1 && pattern.length == 1) {
+ // optimize for wildcard
+ return true;
+ }
+ return matches(other.toCharArray());
+ }
+
+ @Override
+ public String toString() {
+ return new String(pattern);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof NamePattern) {
+ NamePattern otherPat = (NamePattern) other;
+ if (otherPat.starCount != this.starCount) {
+ return false;
+ }
+ if (otherPat.pattern.length != this.pattern.length) {
+ return false;
+ }
+ for (int i = 0; i < this.pattern.length; i++) {
+ if (this.pattern[i] != otherPat.pattern[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashcode;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream out) throws IOException {
+ out.writeUTF(new String(pattern));
+ }
+
+ public static NamePattern read(VersionedDataInputStream in) throws IOException {
+ String s = in.readUTF();
+ if (s.length() == 0) {
+ return ELLIPSIS;
+ }
+ return new NamePattern(s);
+ }
+
+ /**
+ * Method maybeGetSimpleName.
+ *
+ * @return String
+ */
+ public String maybeGetSimpleName() {
+ if (starCount == 0 && pattern.length > 0) {
+ return new String(pattern);
+ }
+ return null;
+ }
+
+ /**
+ * Method isAny.
+ *
+ * @return boolean
+ */
+ public boolean isAny() {
+ return starCount == 1 && pattern.length == 1;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NoTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NoTypePattern.java
new file mode 100644
index 000000000..e5be0a969
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NoTypePattern.java
@@ -0,0 +1,118 @@
+/* *******************************************************************
+ * Copyright (c) 2002, 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+public class NoTypePattern extends TypePattern {
+
+ public NoTypePattern() {
+ super(false, false, new TypePatternList());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
+ */
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ return false;
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType)
+ */
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ return false;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ return false;
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType)
+ */
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(NO_KEY);
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matches(IType, MatchKind)
+ */
+ // public FuzzyBoolean matches(IType type, MatchKind kind) {
+ // return FuzzyBoolean.YES;
+ // }
+ /**
+ * @see org.aspectj.weaver.patterns.TypePattern#matchesSubtypes(IType)
+ */
+ @Override
+ protected boolean matchesSubtypes(ResolvedType type) {
+ return false;
+ }
+
+ @Override
+ public boolean isStar() {
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "<nothing>";
+ }// FIXME AV - bad! toString() cannot be parsed back (not idempotent)
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof NoTypePattern);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return 17 * 37 * 37;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> arg0, World w) {
+ return this;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotAnnotationTypePattern.java
new file mode 100644
index 000000000..0317b85a5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotAnnotationTypePattern.java
@@ -0,0 +1,136 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+
+public class NotAnnotationTypePattern extends AnnotationTypePattern {
+
+ AnnotationTypePattern negatedPattern;
+
+ public NotAnnotationTypePattern(AnnotationTypePattern pattern) {
+ this.negatedPattern = pattern;
+ setLocation(pattern.getSourceContext(), pattern.getStart(), pattern.getEnd());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.AnnotationTypePattern#matches(org.aspectj.weaver.AnnotatedElement)
+ */
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ return negatedPattern.matches(annotated).not();
+ }
+
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ return negatedPattern.matches(annotated, parameterAnnotations).not();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.AnnotationTypePattern#resolve(org.aspectj.weaver.World)
+ */
+ public void resolve(World world) {
+ negatedPattern.resolve(world);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.AnnotationTypePattern#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings, boolean)
+ */
+ public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ negatedPattern = negatedPattern.resolveBindings(scope, bindings, allowBinding);
+ return this;
+ }
+
+ public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ AnnotationTypePattern newNegatedPattern = negatedPattern.parameterizeWith(typeVariableMap, w);
+ NotAnnotationTypePattern ret = new NotAnnotationTypePattern(newNegatedPattern);
+ ret.copyLocationFrom(this);
+ if (this.isForParameterAnnotationMatch()) {
+ ret.setForParameterAnnotationMatch();
+ }
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
+ */
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.NOT);
+ negatedPattern.write(s);
+ writeLocation(s);
+ s.writeBoolean(isForParameterAnnotationMatch());
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationTypePattern ret = new NotAnnotationTypePattern(AnnotationTypePattern.read(s, context));
+ ret.readLocation(context, s);
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) {
+ if (s.readBoolean()) {
+ ret.setForParameterAnnotationMatch();
+ }
+ }
+ return ret;
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof NotAnnotationTypePattern)) {
+ return false;
+ }
+ NotAnnotationTypePattern other = (NotAnnotationTypePattern) obj;
+ return other.negatedPattern.equals(negatedPattern)
+ && other.isForParameterAnnotationMatch() == isForParameterAnnotationMatch();
+ }
+
+ public int hashCode() {
+ int result = 17 + 37 * negatedPattern.hashCode();
+ result = 37 * result + (isForParameterAnnotationMatch() ? 0 : 1);
+ return result;
+ }
+
+ public String toString() {
+ return "!" + negatedPattern.toString();
+ }
+
+ public AnnotationTypePattern getNegatedPattern() {
+ return negatedPattern;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ negatedPattern.traverse(visitor, ret);
+ return ret;
+ }
+
+ public void setForParameterAnnotationMatch() {
+ negatedPattern.setForParameterAnnotationMatch();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotPointcut.java
new file mode 100644
index 000000000..85d2cdb7a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotPointcut.java
@@ -0,0 +1,140 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Test;
+
+public class NotPointcut extends Pointcut {
+ private Pointcut body;
+
+ public NotPointcut(Pointcut negated) {
+ super();
+ this.body = negated;
+ this.pointcutKind = NOT;
+ setLocation(negated.getSourceContext(), negated.getStart(), negated.getEnd()); // should that be at least start-1?
+ }
+
+ public NotPointcut(Pointcut pointcut, int startPos) {
+ this(pointcut);
+ setLocation(pointcut.getSourceContext(), startPos, pointcut.getEnd());
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ public Pointcut getNegatedPointcut() {
+ return body;
+ }
+
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return body.fastMatch(type).not();
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ return body.match(shadow).not();
+ }
+
+ @Override
+ public String toString() {
+ return "!" + body.toString();
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof NotPointcut)) {
+ return false;
+ }
+ NotPointcut o = (NotPointcut) other;
+ return o.body.equals(body);
+ }
+
+ @Override
+ public int hashCode() {
+ return 37 * 23 + body.hashCode();
+ }
+
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ // Bindings old = bindings.copy();
+
+ // Bindings newBindings = new Bindings(bindings.size());
+
+ body.resolveBindings(scope, null);
+
+ // newBindings.checkEmpty(scope, "negation does not allow binding");
+ // bindings.checkEquals(old, scope);
+
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.NOT);
+ body.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ NotPointcut ret = new NotPointcut(Pointcut.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return Test.makeNot(body.findResidue(shadow, state));
+ }
+
+ @Override
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ Pointcut ret = new NotPointcut(body.concretize(inAspect, declaringType, bindings));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ Pointcut ret = new NotPointcut(body.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ this.body.traverse(visitor, ret);
+ return ret;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotSignaturePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotSignaturePattern.java
new file mode 100644
index 000000000..b6140ece1
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotSignaturePattern.java
@@ -0,0 +1,91 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * Represents the NOT of a signature pattern
+ *
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public class NotSignaturePattern extends AbstractSignaturePattern {
+
+ private ISignaturePattern negatedSp;
+
+ public NotSignaturePattern(ISignaturePattern negatedSp) {
+ this.negatedSp = negatedSp;
+ }
+
+ public boolean couldEverMatch(ResolvedType type) {
+ if (negatedSp.getExactDeclaringTypes().size() == 0) {
+ return true;
+ }
+ return !negatedSp.couldEverMatch(type);
+ }
+
+ public List<ExactTypePattern> getExactDeclaringTypes() {
+ return negatedSp.getExactDeclaringTypes();
+ }
+
+ public boolean isMatchOnAnyName() {
+ return negatedSp.isMatchOnAnyName();
+ }
+
+ public boolean isStarAnnotation() {
+ return negatedSp.isStarAnnotation();
+ }
+
+ public boolean matches(Member member, World world, boolean b) {
+ return !negatedSp.matches(member, world, b);
+ }
+
+ public ISignaturePattern parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World world) {
+ return new NotSignaturePattern(negatedSp.parameterizeWith(typeVariableBindingMap, world));
+ }
+
+ public ISignaturePattern resolveBindings(IScope scope, Bindings bindings) {
+ // Whilst the real SignaturePattern returns 'this' we are safe to return 'this' here rather than build a new
+ // AndSignaturePattern
+ negatedSp.resolveBindings(scope, bindings);
+ return this;
+ }
+
+ public static ISignaturePattern readNotSignaturePattern(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ NotSignaturePattern ret = new NotSignaturePattern(readCompoundSignaturePattern(s, context));
+ // ret.readLocation(context, s); // TODO output position currently useless so dont need to do this
+ s.readInt();
+ s.readInt();
+ return ret;
+ }
+
+ public ISignaturePattern getNegated() {
+ return negatedSp;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("!").append(negatedSp.toString());
+ return sb.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotTypePattern.java
new file mode 100644
index 000000000..0f8f82c21
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/NotTypePattern.java
@@ -0,0 +1,180 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjAttribute;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * !TypePattern
+ *
+ * <p>
+ * any binding to formals is explicitly forbidden for any composite, ! is just the most obviously wrong case.
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public class NotTypePattern extends TypePattern {
+ private TypePattern negatedPattern;
+ private boolean isBangVoid = false; // is this '!void'
+ private boolean checked = false;
+
+ public NotTypePattern(TypePattern pattern) {
+ super(false, false); // ??? we override all methods that care about includeSubtypes
+ this.negatedPattern = pattern;
+ setLocation(pattern.getSourceContext(), pattern.getStart(), pattern.getEnd());
+ }
+
+ public TypePattern getNegatedPattern() {
+ return negatedPattern;
+ }
+
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ return true;
+ }
+
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ return negatedPattern.matchesInstanceof(type).not();
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ return (!negatedPattern.matchesExactly(type) && annotationPattern.matches(type).alwaysTrue());
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ return (!negatedPattern.matchesExactly(type, annotatedType) && annotationPattern.matches(annotatedType).alwaysTrue());
+ }
+
+ @Override
+ public boolean matchesStatically(ResolvedType type) {
+ return !negatedPattern.matchesStatically(type);
+ }
+
+ @Override
+ public void setAnnotationTypePattern(AnnotationTypePattern annPatt) {
+ super.setAnnotationTypePattern(annPatt);
+ }
+
+ @Override
+ public void setIsVarArgs(boolean isVarArgs) {
+ negatedPattern.setIsVarArgs(isVarArgs);
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(TypePattern.NOT);
+ negatedPattern.write(s);
+ annotationPattern.write(s);
+ writeLocation(s);
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ TypePattern ret = new NotTypePattern(TypePattern.read(s, context));
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+ ret.annotationPattern = AnnotationTypePattern.read(s, context);
+ }
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ if (requireExactType) {
+ return notExactType(scope);
+ }
+ negatedPattern = negatedPattern.resolveBindings(scope, bindings, false, false);
+ return this;
+ }
+
+ @Override
+ public boolean isBangVoid() {
+ if (!checked) {
+ isBangVoid = negatedPattern.getExactType().isVoid();
+ checked = true;
+ }
+ return isBangVoid;
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ TypePattern newNegatedPattern = negatedPattern.parameterizeWith(typeVariableMap, w);
+ NotTypePattern ret = new NotTypePattern(newNegatedPattern);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buff = new StringBuffer();
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append('(');
+ buff.append(annotationPattern.toString());
+ buff.append(' ');
+ }
+ buff.append('!');
+ buff.append(negatedPattern);
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append(')');
+ }
+ return buff.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof NotTypePattern)) {
+ return false;
+ }
+ return (negatedPattern.equals(((NotTypePattern) obj).negatedPattern));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return 17 + 37 * negatedPattern.hashCode();
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ negatedPattern.traverse(visitor, ret);
+ return ret;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrAnnotationTypePattern.java
new file mode 100644
index 000000000..3cfe1de8b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrAnnotationTypePattern.java
@@ -0,0 +1,131 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+
+public class OrAnnotationTypePattern extends AnnotationTypePattern {
+
+ private AnnotationTypePattern left;
+ private AnnotationTypePattern right;
+
+ public OrAnnotationTypePattern(AnnotationTypePattern left, AnnotationTypePattern right) {
+ this.left = left;
+ this.right = right;
+ setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
+ }
+
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ return left.matches(annotated).or(right.matches(annotated));
+ }
+
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ return left.matches(annotated, parameterAnnotations).or(right.matches(annotated, parameterAnnotations));
+ }
+
+ public void resolve(World world) {
+ left.resolve(world);
+ right.resolve(world);
+ }
+
+ public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ left = left.resolveBindings(scope, bindings, allowBinding);
+ right = right.resolveBindings(scope, bindings, allowBinding);
+ return this;
+ }
+
+ public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ AnnotationTypePattern newLeft = left.parameterizeWith(typeVariableMap, w);
+ AnnotationTypePattern newRight = right.parameterizeWith(typeVariableMap, w);
+ OrAnnotationTypePattern ret = new OrAnnotationTypePattern(newLeft, newRight);
+ ret.copyLocationFrom(this);
+ if (isForParameterAnnotationMatch()) {
+ ret.setForParameterAnnotationMatch();
+ }
+ return ret;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ left.traverse(visitor, ret);
+ right.traverse(visitor, ret);
+ return ret;
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationTypePattern p = new OrAnnotationTypePattern(AnnotationTypePattern.read(s, context), AnnotationTypePattern.read(s,
+ context));
+ p.readLocation(context, s);
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) {
+ if (s.readBoolean()) {
+ p.setForParameterAnnotationMatch();
+ }
+ }
+ return p;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.OR);
+ left.write(s);
+ right.write(s);
+ writeLocation(s);
+ s.writeBoolean(isForParameterAnnotationMatch());
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof OrAnnotationTypePattern)) {
+ return false;
+ }
+ OrAnnotationTypePattern other = (OrAnnotationTypePattern) obj;
+ return (left.equals(other.left) && right.equals(other.right))
+ && isForParameterAnnotationMatch() == other.isForParameterAnnotationMatch();
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = result * 37 + left.hashCode();
+ result = result * 37 + right.hashCode();
+ result = result * 37 + (isForParameterAnnotationMatch() ? 0 : 1);
+ return result;
+ }
+
+ public String toString() {
+ return "(" + left.toString() + " || " + right.toString() + ")";
+ }
+
+ public AnnotationTypePattern getLeft() {
+ return left;
+ }
+
+ public AnnotationTypePattern getRight() {
+ return right;
+ }
+
+ public void setForParameterAnnotationMatch() {
+ left.setForParameterAnnotationMatch();
+ right.setForParameterAnnotationMatch();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrPointcut.java
new file mode 100644
index 000000000..dde02f726
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrPointcut.java
@@ -0,0 +1,146 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.UnresolvedType;
+
+
+public class OrPointcut extends Pointcut {
+ Pointcut left, right;
+ private int couldMatchKinds;
+
+ public OrPointcut(Pointcut left, Pointcut right) {
+ super();
+ this.left = left;
+ this.right = right;
+ setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
+ this.pointcutKind = OR;
+ this.couldMatchKinds = left.couldMatchKinds() | right.couldMatchKinds();
+ }
+
+ public int couldMatchKinds() {
+ return couldMatchKinds;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ FuzzyBoolean leftMatch = left.fastMatch(type);
+ if (leftMatch.alwaysTrue()) {
+ return leftMatch;
+ }
+ return leftMatch.or(right.fastMatch(type));
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ FuzzyBoolean leftMatch = left.match(shadow);
+ if (leftMatch.alwaysTrue()) {
+ return leftMatch;
+ }
+ return leftMatch.or(right.match(shadow));
+ }
+
+ public String toString() {
+ return "(" + left.toString() + " || " + right.toString() + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof OrPointcut)) {
+ return false;
+ }
+ OrPointcut o = (OrPointcut) other;
+ return o.left.equals(left) && o.right.equals(right);
+ }
+
+ public int hashCode() {
+ int result = 31;
+ result = 37 * result + left.hashCode();
+ result = 37 * result + right.hashCode();
+ return result;
+ }
+
+ /**
+ * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(IScope, Bindings)
+ */
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ Bindings old = bindings == null ? null : bindings.copy();
+
+ left.resolveBindings(scope, bindings);
+ right.resolveBindings(scope, old);
+ if (bindings != null) {
+ bindings.checkEquals(old, scope);
+ }
+
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.OR);
+ left.write(s);
+ right.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ OrPointcut ret = new OrPointcut(Pointcut.read(s, context), Pointcut.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return Test.makeOr(left.findResidue(shadow, state), right.findResidue(shadow, state));
+ }
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ Pointcut ret = new OrPointcut(left.concretize(inAspect, declaringType, bindings), right.concretize(inAspect, declaringType,
+ bindings));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ Pointcut ret = new OrPointcut(left.parameterizeWith(typeVariableMap, w), right.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public Pointcut getLeft() {
+ return left;
+ }
+
+ public Pointcut getRight() {
+ return right;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ left.traverse(visitor, ret);
+ right.traverse(visitor, ret);
+ return ret;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrSignaturePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrSignaturePattern.java
new file mode 100644
index 000000000..67346f444
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrSignaturePattern.java
@@ -0,0 +1,104 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - SpringSource
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * Represents the OR of two other signature patterns.
+ *
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public class OrSignaturePattern extends AbstractSignaturePattern {
+
+ private ISignaturePattern leftSp;
+ private ISignaturePattern rightSp;
+ private List<ExactTypePattern> exactDeclaringTypes;
+
+ public OrSignaturePattern(ISignaturePattern leftSp, ISignaturePattern rightSp) {
+ this.leftSp = leftSp;
+ this.rightSp = rightSp;
+ }
+
+ public boolean couldEverMatch(ResolvedType type) {
+ return leftSp.couldEverMatch(type) || rightSp.couldEverMatch(type);
+ }
+
+ public List<ExactTypePattern> getExactDeclaringTypes() {
+ if (exactDeclaringTypes == null) {
+ exactDeclaringTypes = new ArrayList<ExactTypePattern>();
+ exactDeclaringTypes.addAll(leftSp.getExactDeclaringTypes());
+ exactDeclaringTypes.addAll(rightSp.getExactDeclaringTypes());
+ }
+ return exactDeclaringTypes;
+ }
+
+ public boolean isMatchOnAnyName() {
+ return leftSp.isMatchOnAnyName() || rightSp.isMatchOnAnyName();
+ }
+
+ public boolean isStarAnnotation() {
+ return leftSp.isStarAnnotation() || rightSp.isStarAnnotation();
+ }
+
+ public boolean matches(Member member, World world, boolean b) {
+ return (leftSp.matches(member, world, b)) || (rightSp.matches(member, world, b));
+ }
+
+ public ISignaturePattern parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World world) {
+ return new OrSignaturePattern(leftSp.parameterizeWith(typeVariableBindingMap, world), rightSp.parameterizeWith(
+ typeVariableBindingMap, world));
+ }
+
+ public ISignaturePattern resolveBindings(IScope scope, Bindings bindings) {
+ // Whilst the real SignaturePattern returns 'this' we are safe to return 'this' here rather than build a new
+ // AndSignaturePattern
+ leftSp.resolveBindings(scope, bindings);
+ rightSp.resolveBindings(scope, bindings);
+ return this;
+ }
+
+ public static ISignaturePattern readOrSignaturePattern(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ OrSignaturePattern ret = new OrSignaturePattern(readCompoundSignaturePattern(s, context), readCompoundSignaturePattern(s,
+ context));
+ s.readInt();
+ s.readInt();
+ // ret.readLocation(context, s); // TODO output position currently useless so dont need to do this
+ return ret;
+ }
+
+ public ISignaturePattern getLeft() {
+ return leftSp;
+ }
+
+ public ISignaturePattern getRight() {
+ return rightSp;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(leftSp.toString()).append(" || ").append(rightSp.toString());
+ return sb.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrTypePattern.java
new file mode 100644
index 000000000..b31a4e9ad
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/OrTypePattern.java
@@ -0,0 +1,193 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * left || right
+ *
+ * <p>
+ * any binding to formals is explicitly forbidden for any composite by the language
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public class OrTypePattern extends TypePattern {
+ private TypePattern left, right;
+
+ public OrTypePattern(TypePattern left, TypePattern right) {
+ super(false, false); // ??? we override all methods that care about includeSubtypes
+ this.left = left;
+ this.right = right;
+ setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
+ }
+
+ public TypePattern getRight() {
+ return right;
+ }
+
+ public TypePattern getLeft() {
+ return left;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
+ */
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ return true; // don't dive at the moment...
+ }
+
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ return left.matchesInstanceof(type).or(right.matchesInstanceof(type));
+ }
+
+ protected boolean matchesExactly(ResolvedType type) {
+ // ??? if these had side-effects, this sort-circuit could be a mistake
+ return left.matchesExactly(type) || right.matchesExactly(type);
+ }
+
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ // ??? if these had side-effects, this sort-circuit could be a mistake
+ return left.matchesExactly(type, annotatedType) || right.matchesExactly(type, annotatedType);
+ }
+
+ public boolean matchesStatically(ResolvedType type) {
+ return left.matchesStatically(type) || right.matchesStatically(type);
+ }
+
+ public void setIsVarArgs(boolean isVarArgs) {
+ this.isVarArgs = isVarArgs;
+ left.setIsVarArgs(isVarArgs);
+ right.setIsVarArgs(isVarArgs);
+ }
+
+ public void setAnnotationTypePattern(AnnotationTypePattern annPatt) {
+ if (annPatt == AnnotationTypePattern.ANY) {
+ return;
+ }
+ if (left.annotationPattern == AnnotationTypePattern.ANY) {
+ left.setAnnotationTypePattern(annPatt);
+ } else {
+ left.setAnnotationTypePattern(new AndAnnotationTypePattern(left.annotationPattern, annPatt));
+ }
+ if (right.annotationPattern == AnnotationTypePattern.ANY) {
+ right.setAnnotationTypePattern(annPatt);
+ } else {
+ right.setAnnotationTypePattern(new AndAnnotationTypePattern(right.annotationPattern, annPatt));
+ }
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(TypePattern.OR);
+ left.write(s);
+ right.write(s);
+ writeLocation(s);
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ OrTypePattern ret = new OrTypePattern(TypePattern.read(s, context), TypePattern.read(s, context));
+ ret.readLocation(context, s);
+ if (ret.left.isVarArgs && ret.right.isVarArgs) {
+ ret.isVarArgs = true;
+ }
+ return ret;
+ }
+
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ if (requireExactType) {
+ return notExactType(scope);
+ }
+ left = left.resolveBindings(scope, bindings, false, false);
+ right = right.resolveBindings(scope, bindings, false, false);
+ return this;
+ }
+
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ TypePattern newLeft = left.parameterizeWith(typeVariableMap, w);
+ TypePattern newRight = right.parameterizeWith(typeVariableMap, w);
+ OrTypePattern ret = new OrTypePattern(newLeft, newRight);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public String toString() {
+ StringBuffer buff = new StringBuffer();
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append('(');
+ buff.append(annotationPattern.toString());
+ buff.append(' ');
+ }
+ buff.append('(');
+ buff.append(left.toString());
+ buff.append(" || ");
+ buff.append(right.toString());
+ buff.append(')');
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buff.append(')');
+ }
+ return buff.toString();
+ }
+
+ public boolean isStarAnnotation() {
+ return left.isStarAnnotation() || right.isStarAnnotation();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof OrTypePattern)) {
+ return false;
+ }
+ OrTypePattern other = (OrTypePattern) obj;
+ return left.equals(other.left) && right.equals(other.right);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ int ret = 17;
+ ret = ret + 37 * left.hashCode();
+ ret = ret + 37 * right.hashCode();
+ return ret;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ left.traverse(visitor, ret);
+ right.traverse(visitor, ret);
+ return ret;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ParserException.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ParserException.java
new file mode 100644
index 000000000..036061f15
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ParserException.java
@@ -0,0 +1,28 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.IHasPosition;
+
+public class ParserException extends RuntimeException {
+ private IHasPosition token;
+
+ public ParserException(String message, IHasPosition token) {
+ super(message);
+ this.token = token;
+ }
+
+ public IHasPosition getLocation() {
+ return token;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNode.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNode.java
new file mode 100644
index 000000000..8a7aae097
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNode.java
@@ -0,0 +1,88 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.IHasSourceLocation;
+import org.aspectj.weaver.ISourceContext;
+
+public abstract class PatternNode implements IHasSourceLocation {
+ protected int start, end;
+ protected ISourceContext sourceContext;
+
+ public PatternNode() {
+ super();
+ start = end = -1;
+ }
+
+ public int getStart() {
+ return start + (sourceContext != null ? sourceContext.getOffset() : 0);
+ }
+
+ public int getEnd() {
+ return end + (sourceContext != null ? sourceContext.getOffset() : 0);
+ }
+
+ public ISourceContext getSourceContext() {
+ return sourceContext;
+ }
+
+ public String getFileName() {
+ return "unknown";
+ }
+
+ public void setLocation(ISourceContext sourceContext, int start, int end) {
+ this.sourceContext = sourceContext;
+ this.start = start;
+ this.end = end;
+ }
+
+ public void copyLocationFrom(PatternNode other) {
+ this.start = other.start;
+ this.end = other.end;
+ this.sourceContext = other.sourceContext;
+ }
+
+ public ISourceLocation getSourceLocation() {
+ // System.out.println("get context: " + this + " is " + sourceContext);
+ if (sourceContext == null) {
+ // System.err.println("no context: " + this);
+ return null;
+ }
+ return sourceContext.makeSourceLocation(this);
+ }
+
+ public abstract void write(CompressingDataOutputStream s) throws IOException;
+
+ public void writeLocation(DataOutputStream s) throws IOException {
+ s.writeInt(start);
+ s.writeInt(end);
+ }
+
+ public void readLocation(ISourceContext context, DataInputStream s) throws IOException {
+ start = s.readInt();
+ end = s.readInt();
+ this.sourceContext = context;
+ }
+
+ public abstract Object accept(PatternNodeVisitor visitor, Object data);
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ return accept(visitor, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNodeVisitor.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNodeVisitor.java
new file mode 100644
index 000000000..336a33e51
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternNodeVisitor.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Vasseur initial implementation
+ * Adrian Colyer refactoring for traversal and grouping by kind
+ *******************************************************************************/
+package org.aspectj.weaver.patterns;
+
+
+/**
+ * A Pointcut or TypePattern visitor
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+public interface PatternNodeVisitor {
+
+ // Annotation type patterns
+ Object visit(AndAnnotationTypePattern node, Object data);
+ Object visit(AnyAnnotationTypePattern node, Object data);
+ Object visit(EllipsisAnnotationTypePattern node, Object data);
+ Object visit(ExactAnnotationTypePattern node, Object data);
+ Object visit(BindingAnnotationTypePattern node, Object data);
+ Object visit(NotAnnotationTypePattern node, Object data);
+ Object visit(OrAnnotationTypePattern node, Object data);
+ Object visit(WildAnnotationTypePattern node, Object data);
+ Object visit(AnnotationPatternList node, Object data);
+
+ // Regular type patterns
+ Object visit(AndTypePattern node, Object data);
+ Object visit(AnyTypePattern node, Object data);
+ Object visit(AnyWithAnnotationTypePattern node, Object data);
+ Object visit(EllipsisTypePattern node, Object data);
+ Object visit(ExactTypePattern node, Object data);
+ Object visit(BindingTypePattern node, Object data);
+ Object visit(NotTypePattern node, Object data);
+ Object visit(NoTypePattern node, Object data);
+ Object visit(OrTypePattern node, Object data);
+ Object visit(WildTypePattern node, Object data);
+ Object visit(TypePatternList node, Object data);
+ Object visit(HasMemberTypePattern node, Object data);
+ Object visit(TypeCategoryTypePattern node, Object data);
+
+ // Pointcuts
+ Object visit(AndPointcut node, Object data);
+ Object visit(CflowPointcut node, Object data);
+ Object visit(ConcreteCflowPointcut node, Object data);
+ Object visit(HandlerPointcut node, Object data);
+ Object visit(IfPointcut node, Object data);
+ Object visit(KindedPointcut node, Object data);
+ Object visit(Pointcut.MatchesNothingPointcut node, Object data);
+ Object visit(AnnotationPointcut node, Object data);
+ Object visit(ArgsAnnotationPointcut node, Object data);
+ Object visit(ArgsPointcut node, Object data);
+ Object visit(ThisOrTargetAnnotationPointcut node, Object data);
+ Object visit(ThisOrTargetPointcut node, Object data);
+ Object visit(WithinAnnotationPointcut node, Object data);
+ Object visit(WithinCodeAnnotationPointcut node, Object data);
+ Object visit(NotPointcut node, Object data);
+ Object visit(OrPointcut node, Object data);
+ Object visit(ReferencePointcut node, Object data);
+ Object visit(WithinPointcut node, Object data);
+ Object visit(WithincodePointcut node, Object data);
+
+ // Per-clauses
+ Object visit(PerCflow node, Object data);
+ Object visit(PerFromSuper node, Object data);
+ Object visit(PerObject node, Object data);
+ Object visit(PerSingleton node, Object data);
+ Object visit(PerTypeWithin node, Object data);
+
+
+ // Declares
+ Object visit(DeclareAnnotation node, Object data);
+ Object visit(DeclareErrorOrWarning node, Object data);
+ Object visit(DeclareParents node, Object data);
+ Object visit(DeclarePrecedence node, Object data);
+ Object visit(DeclareSoft node, Object data);
+
+ // Miscellaneous patterns
+ Object visit(ModifiersPattern node, Object data);
+ Object visit(NamePattern node, Object data);
+ Object visit(SignaturePattern node, Object data);
+ Object visit(ThrowsPattern node, Object data);
+ Object visit(TypeVariablePattern node, Object data);
+ Object visit(TypeVariablePatternList node,Object data);
+
+ // Catch-all
+ Object visit(PatternNode node, Object data);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternParser.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternParser.java
new file mode 100644
index 000000000..effecfeaf
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PatternParser.java
@@ -0,0 +1,1914 @@
+/* *******************************************************************
+ * Copyright (c) 2002,2010
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Adrian Colyer, IBM
+ * Andy Clement, IBM, SpringSource
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.MemberKind;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.internal.tools.PointcutDesignatorHandlerBasedPointcut;
+import org.aspectj.weaver.tools.ContextBasedMatcher;
+import org.aspectj.weaver.tools.PointcutDesignatorHandler;
+
+/**
+ * @author PARC
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+// XXX doesn't handle errors for extra tokens very well (sometimes ignores)
+public class PatternParser {
+
+ private ITokenSource tokenSource;
+ private ISourceContext sourceContext;
+
+ /** not thread-safe, but this class is not intended to be... */
+ private boolean allowHasTypePatterns = false;
+
+ /** extension handlers used in weaver tools API only */
+ private Set<PointcutDesignatorHandler> pointcutDesignatorHandlers = Collections.emptySet();
+ private World world;
+
+ /**
+ * Constructor for PatternParser.
+ */
+ public PatternParser(ITokenSource tokenSource) {
+ super();
+ this.tokenSource = tokenSource;
+ this.sourceContext = tokenSource.getSourceContext();
+ }
+
+ /** only used by weaver tools API */
+ public void setPointcutDesignatorHandlers(Set<PointcutDesignatorHandler> handlers, World world) {
+ this.pointcutDesignatorHandlers = handlers;
+ this.world = world;
+ }
+
+ public PerClause maybeParsePerClause() {
+ IToken tok = tokenSource.peek();
+ if (tok == IToken.EOF) {
+ return null;
+ }
+ if (tok.isIdentifier()) {
+ String name = tok.getString();
+ if (name.equals("issingleton")) {
+ return parsePerSingleton();
+ } else if (name.equals("perthis")) {
+ return parsePerObject(true);
+ } else if (name.equals("pertarget")) {
+ return parsePerObject(false);
+ } else if (name.equals("percflow")) {
+ return parsePerCflow(false);
+ } else if (name.equals("percflowbelow")) {
+ return parsePerCflow(true);
+ } else if (name.equals("pertypewithin")) { // PTWIMPL Parse the pertypewithin clause
+ return parsePerTypeWithin();
+ } else {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ private PerClause parsePerCflow(boolean isBelow) {
+ parseIdentifier();
+ eat("(");
+ Pointcut entry = parsePointcut();
+ eat(")");
+ return new PerCflow(entry, isBelow);
+ }
+
+ public boolean moreToParse() {
+ return tokenSource.hasMoreTokens();
+ }
+
+ private PerClause parsePerObject(boolean isThis) {
+ parseIdentifier();
+ eat("(");
+ Pointcut entry = parsePointcut();
+ eat(")");
+ return new PerObject(entry, isThis);
+ }
+
+ private PerClause parsePerTypeWithin() {
+ parseIdentifier();
+ eat("(");
+ TypePattern withinTypePattern = parseTypePattern();
+ eat(")");
+ return new PerTypeWithin(withinTypePattern);
+ }
+
+ private PerClause parsePerSingleton() {
+ parseIdentifier();
+ eat("(");
+ eat(")");
+ return new PerSingleton();
+ }
+
+ public Declare parseDeclare() {
+ int startPos = tokenSource.peek().getStart();
+
+ eatIdentifier("declare");
+ String kind = parseIdentifier();
+ Declare ret;
+ if (kind.equals("error")) {
+ eat(":");
+ ret = parseErrorOrWarning(true);
+ } else if (kind.equals("warning")) {
+ eat(":");
+ ret = parseErrorOrWarning(false);
+ } else if (kind.equals("precedence")) {
+ eat(":");
+ ret = parseDominates();
+ } else if (kind.equals("dominates")) {
+ throw new ParserException("name changed to declare precedence", tokenSource.peek(-2));
+ } else if (kind.equals("parents")) {
+ ret = parseParents();
+ } else if (kind.equals("soft")) {
+ eat(":");
+ ret = parseSoft();
+ } else {
+ throw new ParserException(
+ "expected one of error, warning, parents, soft, precedence, @type, @method, @constructor, @field",
+ tokenSource.peek(-1));
+ }
+ int endPos = tokenSource.peek(-1).getEnd();
+ ret.setLocation(sourceContext, startPos, endPos);
+ return ret;
+ }
+
+ public Declare parseDeclareAnnotation() {
+ int startPos = tokenSource.peek().getStart();
+
+ eatIdentifier("declare");
+ eat("@");
+ String kind = parseIdentifier();
+ eat(":");
+ Declare ret;
+ if (kind.equals("type")) {
+ ret = parseDeclareAtType();
+ } else if (kind.equals("method")) {
+ ret = parseDeclareAtMethod(true);
+ } else if (kind.equals("field")) {
+ ret = parseDeclareAtField();
+ } else if (kind.equals("constructor")) {
+ ret = parseDeclareAtMethod(false);
+ } else {
+ throw new ParserException("one of type, method, field, constructor", tokenSource.peek(-1));
+ }
+ eat(";");
+ int endPos = tokenSource.peek(-1).getEnd();
+ ret.setLocation(sourceContext, startPos, endPos);
+ return ret;
+
+ }
+
+ public DeclareAnnotation parseDeclareAtType() {
+ allowHasTypePatterns = true;
+ TypePattern p = parseTypePattern();
+ allowHasTypePatterns = false;
+ return new DeclareAnnotation(DeclareAnnotation.AT_TYPE, p);
+ }
+
+ public DeclareAnnotation parseDeclareAtMethod(boolean isMethod) {
+ ISignaturePattern sp = parseCompoundMethodOrConstructorSignaturePattern(isMethod);// parseMethodOrConstructorSignaturePattern();
+
+ if (!isMethod) {
+ return new DeclareAnnotation(DeclareAnnotation.AT_CONSTRUCTOR, sp);
+ } else {
+ return new DeclareAnnotation(DeclareAnnotation.AT_METHOD, sp);
+ }
+ }
+
+ public DeclareAnnotation parseDeclareAtField() {
+ ISignaturePattern compoundFieldSignaturePattern = parseCompoundFieldSignaturePattern();
+ DeclareAnnotation da = new DeclareAnnotation(DeclareAnnotation.AT_FIELD, compoundFieldSignaturePattern);
+ return da;
+ }
+
+ public ISignaturePattern parseCompoundFieldSignaturePattern() {
+ int index = tokenSource.getIndex();
+ try {
+ ISignaturePattern atomicFieldSignaturePattern = parseMaybeParenthesizedFieldSignaturePattern();
+
+ while (isEitherAndOrOr()) {
+ if (maybeEat("&&")) {
+ atomicFieldSignaturePattern = new AndSignaturePattern(atomicFieldSignaturePattern,
+ parseMaybeParenthesizedFieldSignaturePattern());
+ }
+ if (maybeEat("||")) {
+ atomicFieldSignaturePattern = new OrSignaturePattern(atomicFieldSignaturePattern,
+ parseMaybeParenthesizedFieldSignaturePattern());
+ }
+ }
+ return atomicFieldSignaturePattern;
+ } catch (ParserException e) {
+ // fallback in the case of a regular single field signature pattern that just happened to start with '('
+ int nowAt = tokenSource.getIndex();
+ tokenSource.setIndex(index);
+ try {
+ ISignaturePattern fsp = parseFieldSignaturePattern();
+ return fsp;
+ } catch (Exception e2) {
+ tokenSource.setIndex(nowAt);
+ // throw the original
+ throw e;
+ }
+ }
+ }
+
+ private boolean isEitherAndOrOr() {
+ String tokenstring = tokenSource.peek().getString();
+ return tokenstring.equals("&&") || tokenstring.equals("||");
+ }
+
+ public ISignaturePattern parseCompoundMethodOrConstructorSignaturePattern(boolean isMethod) {
+ ISignaturePattern atomicMethodCtorSignaturePattern = parseMaybeParenthesizedMethodOrConstructorSignaturePattern(isMethod);
+
+ while (isEitherAndOrOr()) {
+ if (maybeEat("&&")) {
+ atomicMethodCtorSignaturePattern = new AndSignaturePattern(atomicMethodCtorSignaturePattern,
+ parseMaybeParenthesizedMethodOrConstructorSignaturePattern(isMethod));
+ }
+ if (maybeEat("||")) {
+ atomicMethodCtorSignaturePattern = new OrSignaturePattern(atomicMethodCtorSignaturePattern,
+ parseMaybeParenthesizedMethodOrConstructorSignaturePattern(isMethod));
+ }
+ }
+ return atomicMethodCtorSignaturePattern;
+ }
+
+ public DeclarePrecedence parseDominates() {
+ List<TypePattern> l = new ArrayList<TypePattern>();
+ do {
+ l.add(parseTypePattern());
+ } while (maybeEat(","));
+
+ return new DeclarePrecedence(l);
+ }
+
+ private Declare parseParents() {
+ /*
+ * simplified design requires use of raw types for declare parents, no generic spec. allowed String[] typeParameters =
+ * maybeParseSimpleTypeVariableList();
+ */
+ eat(":");
+ allowHasTypePatterns = true;
+ TypePattern p = parseTypePattern(false, false);
+ allowHasTypePatterns = false;
+ IToken t = tokenSource.next();
+ if (!(t.getString().equals("extends") || t.getString().equals("implements"))) {
+ throw new ParserException("extends or implements", t);
+ }
+ boolean isExtends = t.getString().equals("extends");
+
+ List<TypePattern> l = new ArrayList<TypePattern>();
+ do {
+ l.add(parseTypePattern());
+ } while (maybeEat(","));
+
+ // XXX somewhere in the chain we need to enforce that we have only ExactTypePatterns
+
+ DeclareParents decp = new DeclareParents(p, l, isExtends);
+ return decp;
+ }
+
+ private Declare parseSoft() {
+ TypePattern p = parseTypePattern();
+ eat(":");
+ Pointcut pointcut = parsePointcut();
+ return new DeclareSoft(p, pointcut);
+ }
+
+ /**
+ * Attempt to parse a pointcut, if that fails then try again for a type pattern.
+ *
+ * @param isError true if it is declare error rather than declare warning
+ * @return the new declare
+ */
+ private Declare parseErrorOrWarning(boolean isError) {
+ Pointcut pointcut = null;
+ int index = tokenSource.getIndex();
+ try {
+ pointcut = parsePointcut();
+ } catch (ParserException pe) {
+ try {
+ tokenSource.setIndex(index);
+ boolean oldValue = allowHasTypePatterns;
+ TypePattern typePattern = null;
+ try {
+ allowHasTypePatterns = true;
+ typePattern = parseTypePattern();
+ } finally {
+ allowHasTypePatterns = oldValue;
+ }
+ eat(":");
+ String message = parsePossibleStringSequence(true);
+ return new DeclareTypeErrorOrWarning(isError, typePattern, message);
+ } catch (ParserException pe2) {
+ // deliberately throw the original problem
+ throw pe;
+ }
+ }
+ eat(":");
+ String message = parsePossibleStringSequence(true);
+ return new DeclareErrorOrWarning(isError, pointcut, message);
+ }
+
+ public Pointcut parsePointcut(boolean shouldConsumeAllInput) {
+ Pointcut p = parsePointcut();
+ if (shouldConsumeAllInput && tokenSource.hasMoreTokens()) {
+ throw new ParserException(
+ "Found unexpected data after parsing pointcut",
+ tokenSource.next());
+ }
+ return p;
+ }
+
+ public Pointcut parsePointcut() {
+ Pointcut p = parseAtomicPointcut();
+ if (maybeEat("&&")) {
+ p = new AndPointcut(p, parseNotOrPointcut());
+ }
+
+ if (maybeEat("||")) {
+ p = new OrPointcut(p, parsePointcut());
+ }
+
+ return p;
+ }
+
+ private Pointcut parseNotOrPointcut() {
+ Pointcut p = parseAtomicPointcut();
+ if (maybeEat("&&")) {
+ p = new AndPointcut(p, parseNotOrPointcut());
+ }
+ return p;
+ }
+
+ private Pointcut parseAtomicPointcut() {
+ if (maybeEat("!")) {
+ int startPos = tokenSource.peek(-1).getStart();
+ Pointcut p = new NotPointcut(parseAtomicPointcut(), startPos);
+ return p;
+ }
+ if (maybeEat("(")) {
+ Pointcut p = parsePointcut();
+ eat(")");
+ return p;
+ }
+ if (maybeEat("@")) {
+ int startPos = tokenSource.peek().getStart();
+ Pointcut p = parseAnnotationPointcut();
+ int endPos = tokenSource.peek(-1).getEnd();
+ p.setLocation(sourceContext, startPos, endPos);
+ return p;
+ }
+ int startPos = tokenSource.peek().getStart();
+ Pointcut p = parseSinglePointcut();
+ int endPos = tokenSource.peek(-1).getEnd();
+ p.setLocation(sourceContext, startPos, endPos);
+ return p;
+ }
+
+ public Pointcut parseSinglePointcut() {
+ int start = tokenSource.getIndex();
+ IToken t = tokenSource.peek();
+ Pointcut p = t.maybeGetParsedPointcut();
+ if (p != null) {
+ tokenSource.next();
+ return p;
+ }
+
+ String kind = parseIdentifier();
+ // IToken possibleTypeVariableToken = tokenSource.peek();
+ // String[] typeVariables = maybeParseSimpleTypeVariableList();
+ if (kind.equals("execution") || kind.equals("call") || kind.equals("get") || kind.equals("set")) {
+ p = parseKindedPointcut(kind);
+ } else if (kind.equals("args")) {
+ p = parseArgsPointcut();
+ } else if (kind.equals("this")) {
+ p = parseThisOrTargetPointcut(kind);
+ } else if (kind.equals("target")) {
+ p = parseThisOrTargetPointcut(kind);
+ } else if (kind.equals("within")) {
+ p = parseWithinPointcut();
+ } else if (kind.equals("withincode")) {
+ p = parseWithinCodePointcut();
+ } else if (kind.equals("cflow")) {
+ p = parseCflowPointcut(false);
+ } else if (kind.equals("cflowbelow")) {
+ p = parseCflowPointcut(true);
+ } else if (kind.equals("adviceexecution")) {
+ eat("(");
+ eat(")");
+ p = new KindedPointcut(Shadow.AdviceExecution, new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY,
+ TypePattern.ANY, TypePattern.ANY, NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY,
+ AnnotationTypePattern.ANY));
+ } else if (kind.equals("handler")) {
+ eat("(");
+ TypePattern typePat = parseTypePattern(false, false);
+ eat(")");
+ p = new HandlerPointcut(typePat);
+ } else if (kind.equals("lock") || kind.equals("unlock")) {
+ p = parseMonitorPointcut(kind);
+ } else if (kind.equals("initialization")) {
+ eat("(");
+ SignaturePattern sig = parseConstructorSignaturePattern();
+ eat(")");
+ p = new KindedPointcut(Shadow.Initialization, sig);
+ } else if (kind.equals("staticinitialization")) {
+ eat("(");
+ TypePattern typePat = parseTypePattern(false, false);
+ eat(")");
+ p = new KindedPointcut(Shadow.StaticInitialization, new SignaturePattern(Member.STATIC_INITIALIZATION,
+ ModifiersPattern.ANY, TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY, ThrowsPattern.ANY,
+ AnnotationTypePattern.ANY));
+ } else if (kind.equals("preinitialization")) {
+ eat("(");
+ SignaturePattern sig = parseConstructorSignaturePattern();
+ eat(")");
+ p = new KindedPointcut(Shadow.PreInitialization, sig);
+ } else if (kind.equals("if")) {
+ // - annotation style only allows if(), if(true) or if(false)
+ // - if() means the body of the annotated method represents the if expression
+ // - anything else is an error because code cannot be put into the if()
+ // - code style will already have been processed and the call to maybeGetParsedPointcut()
+ // at the top of this method will have succeeded.
+ eat("(");
+ if (maybeEatIdentifier("true")) {
+ eat(")");
+ p = new IfPointcut.IfTruePointcut();
+ } else if (maybeEatIdentifier("false")) {
+ eat(")");
+ p = new IfPointcut.IfFalsePointcut();
+ } else {
+ if (!maybeEat(")")) {
+ throw new ParserException(
+ "in annotation style, if(...) pointcuts cannot contain code. Use if() and put the code in the annotated method",
+ t);
+ }
+ // TODO - Alex has some token stuff going on here to get a readable name in place of ""...
+ p = new IfPointcut("");
+ }
+ } else {
+ boolean matchedByExtensionDesignator = false;
+ // see if a registered handler wants to parse it, otherwise
+ // treat as a reference pointcut
+ for (PointcutDesignatorHandler pcd : pointcutDesignatorHandlers) {
+ if (pcd.getDesignatorName().equals(kind)) {
+ p = parseDesignatorPointcut(pcd);
+ matchedByExtensionDesignator = true;
+ }
+
+ }
+ if (!matchedByExtensionDesignator) {
+ tokenSource.setIndex(start);
+ p = parseReferencePointcut();
+ }
+ }
+ return p;
+ }
+
+ private void assertNoTypeVariables(String[] tvs, String errorMessage, IToken token) {
+ if (tvs != null) {
+ throw new ParserException(errorMessage, token);
+ }
+ }
+
+ public Pointcut parseAnnotationPointcut() {
+ int start = tokenSource.getIndex();
+ IToken t = tokenSource.peek();
+ String kind = parseIdentifier();
+ IToken possibleTypeVariableToken = tokenSource.peek();
+ String[] typeVariables = maybeParseSimpleTypeVariableList();
+ if (typeVariables != null) {
+ String message = "(";
+ assertNoTypeVariables(typeVariables, message, possibleTypeVariableToken);
+ }
+ tokenSource.setIndex(start);
+ if (kind.equals("annotation")) {
+ return parseAtAnnotationPointcut();
+ } else if (kind.equals("args")) {
+ return parseArgsAnnotationPointcut();
+ } else if (kind.equals("this") || kind.equals("target")) {
+ return parseThisOrTargetAnnotationPointcut();
+ } else if (kind.equals("within")) {
+ return parseWithinAnnotationPointcut();
+ } else if (kind.equals("withincode")) {
+ return parseWithinCodeAnnotationPointcut();
+ }
+ throw new ParserException("pointcut name", t);
+ }
+
+ private Pointcut parseAtAnnotationPointcut() {
+ parseIdentifier();
+ eat("(");
+ if (maybeEat(")")) {
+ throw new ParserException("@AnnotationName or parameter", tokenSource.peek());
+ }
+ ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
+ eat(")");
+ return new AnnotationPointcut(type);
+ }
+
+ private SignaturePattern parseConstructorSignaturePattern() {
+ SignaturePattern ret = parseMethodOrConstructorSignaturePattern();
+ if (ret.getKind() == Member.CONSTRUCTOR) {
+ return ret;
+ }
+
+ throw new ParserException("constructor pattern required, found method pattern", ret);
+ }
+
+ private Pointcut parseWithinCodePointcut() {
+ // parseIdentifier();
+ eat("(");
+ SignaturePattern sig = parseMethodOrConstructorSignaturePattern();
+ eat(")");
+ return new WithincodePointcut(sig);
+ }
+
+ private Pointcut parseCflowPointcut(boolean isBelow) {
+ // parseIdentifier();
+ eat("(");
+ Pointcut entry = parsePointcut();
+ eat(")");
+ return new CflowPointcut(entry, isBelow, null);
+ }
+
+ /**
+ * Method parseWithinPointcut.
+ *
+ * @return Pointcut
+ */
+ private Pointcut parseWithinPointcut() {
+ // parseIdentifier();
+ eat("(");
+ TypePattern type = parseTypePattern();
+ eat(")");
+ return new WithinPointcut(type);
+ }
+
+ /**
+ * Method parseThisOrTargetPointcut.
+ *
+ * @return Pointcut
+ */
+ private Pointcut parseThisOrTargetPointcut(String kind) {
+ eat("(");
+ TypePattern type = parseTypePattern();
+ eat(")");
+ return new ThisOrTargetPointcut(kind.equals("this"), type);
+ }
+
+ private Pointcut parseThisOrTargetAnnotationPointcut() {
+ String kind = parseIdentifier();
+ eat("(");
+ if (maybeEat(")")) {
+ throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
+ }
+ ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
+ eat(")");
+ return new ThisOrTargetAnnotationPointcut(kind.equals("this"), type);
+ }
+
+ private Pointcut parseWithinAnnotationPointcut() {
+ /* String kind = */parseIdentifier();
+ eat("(");
+ if (maybeEat(")")) {
+ throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
+ }
+ AnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
+ eat(")");
+ return new WithinAnnotationPointcut(type);
+ }
+
+ private Pointcut parseWithinCodeAnnotationPointcut() {
+ /* String kind = */parseIdentifier();
+ eat("(");
+ if (maybeEat(")")) {
+ throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
+ }
+ ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
+ eat(")");
+ return new WithinCodeAnnotationPointcut(type);
+ }
+
+ /**
+ * Method parseArgsPointcut.
+ *
+ * @return Pointcut
+ */
+ private Pointcut parseArgsPointcut() {
+ // parseIdentifier();
+ TypePatternList arguments = parseArgumentsPattern(false);
+ return new ArgsPointcut(arguments);
+ }
+
+ private Pointcut parseArgsAnnotationPointcut() {
+ parseIdentifier();
+ AnnotationPatternList arguments = parseArgumentsAnnotationPattern();
+ return new ArgsAnnotationPointcut(arguments);
+ }
+
+ private Pointcut parseReferencePointcut() {
+ TypePattern onType = parseTypePattern();
+ NamePattern name = null;
+ if (onType.typeParameters.size() > 0) {
+ eat(".");
+ name = parseNamePattern();
+ } else {
+ name = tryToExtractName(onType);
+ }
+ if (name == null) {
+ throw new ParserException("name pattern", tokenSource.peek());
+ }
+ if (onType.toString().equals("")) {
+ onType = null;
+ }
+
+ String simpleName = name.maybeGetSimpleName();
+ if (simpleName == null) {
+ throw new ParserException("(", tokenSource.peek(-1));
+ }
+
+ TypePatternList arguments = parseArgumentsPattern(false);
+ return new ReferencePointcut(onType, simpleName, arguments);
+ }
+
+ private Pointcut parseDesignatorPointcut(PointcutDesignatorHandler pcdHandler) {
+ eat("(");
+ int parenCount = 1;
+ StringBuffer pointcutBody = new StringBuffer();
+ while (parenCount > 0) {
+ if (maybeEat("(")) {
+ parenCount++;
+ pointcutBody.append("(");
+ } else if (maybeEat(")")) {
+ parenCount--;
+ if (parenCount > 0) {
+ pointcutBody.append(")");
+ }
+ } else {
+ pointcutBody.append(nextToken().getString());
+ }
+ }
+ ContextBasedMatcher pcExpr = pcdHandler.parse(pointcutBody.toString());
+ return new PointcutDesignatorHandlerBasedPointcut(pcExpr, world);
+ }
+
+ public List<String> parseDottedIdentifier() {
+ List<String> ret = new ArrayList<String>();
+ ret.add(parseIdentifier());
+ while (maybeEat(".")) {
+ ret.add(parseIdentifier());
+ }
+ return ret;
+ }
+
+ private KindedPointcut parseKindedPointcut(String kind) {
+ eat("(");
+ SignaturePattern sig;
+
+ Shadow.Kind shadowKind = null;
+ if (kind.equals("execution")) {
+ sig = parseMethodOrConstructorSignaturePattern();
+ if (sig.getKind() == Member.METHOD) {
+ shadowKind = Shadow.MethodExecution;
+ } else if (sig.getKind() == Member.CONSTRUCTOR) {
+ shadowKind = Shadow.ConstructorExecution;
+ }
+ } else if (kind.equals("call")) {
+ sig = parseMethodOrConstructorSignaturePattern();
+ if (sig.getKind() == Member.METHOD) {
+ shadowKind = Shadow.MethodCall;
+ } else if (sig.getKind() == Member.CONSTRUCTOR) {
+ shadowKind = Shadow.ConstructorCall;
+ }
+ } else if (kind.equals("get")) {
+ sig = parseFieldSignaturePattern();
+ shadowKind = Shadow.FieldGet;
+ } else if (kind.equals("set")) {
+ sig = parseFieldSignaturePattern();
+ shadowKind = Shadow.FieldSet;
+ } else {
+ throw new ParserException("bad kind: " + kind, tokenSource.peek());
+ }
+ eat(")");
+ return new KindedPointcut(shadowKind, sig);
+ }
+
+ /** Covers the 'lock()' and 'unlock()' pointcuts */
+ private KindedPointcut parseMonitorPointcut(String kind) {
+ eat("(");
+ // TypePattern type = TypePattern.ANY;
+ eat(")");
+
+ if (kind.equals("lock")) {
+ return new KindedPointcut(Shadow.SynchronizationLock, new SignaturePattern(Member.MONITORENTER, ModifiersPattern.ANY,
+ TypePattern.ANY, TypePattern.ANY,
+ // type,
+ NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY, AnnotationTypePattern.ANY));
+ } else {
+ return new KindedPointcut(Shadow.SynchronizationUnlock, new SignaturePattern(Member.MONITORENTER, ModifiersPattern.ANY,
+ TypePattern.ANY, TypePattern.ANY,
+ // type,
+ NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY, AnnotationTypePattern.ANY));
+ }
+ }
+
+ public TypePattern parseTypePattern() {
+ return parseTypePattern(false, false);
+ }
+
+ public TypePattern parseTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
+ TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
+ if (maybeEat("&&")) {
+ p = new AndTypePattern(p, parseNotOrTypePattern(insideTypeParameters, parameterAnnotationsPossible));
+ }
+
+ if (maybeEat("||")) {
+ p = new OrTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
+ }
+ return p;
+ }
+
+ private TypePattern parseNotOrTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
+ TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
+ if (maybeEat("&&")) {
+ p = new AndTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
+ }
+ return p;
+ }
+
+ // Need to differentiate in here between two kinds of annotation pattern - depending on where the ( is
+
+ private TypePattern parseAtomicTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
+ AnnotationTypePattern ap = maybeParseAnnotationPattern(); // might be parameter annotation pattern or type annotation
+ // pattern
+ if (maybeEat("!")) {
+ // int startPos = tokenSource.peek(-1).getStart();
+ // ??? we lose source location for true start of !type
+
+ // An annotation, if processed, is outside of the Not - so here we have to build
+ // an And pattern containing the annotation and the not as left and right children
+ // *unless* the annotation pattern was just 'Any' then we can skip building the
+ // And and just return the Not directly (pr228980)
+ TypePattern p = null;
+ TypePattern tp = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
+ if (!(ap instanceof AnyAnnotationTypePattern)) {
+ p = new NotTypePattern(tp);
+ p = new AndTypePattern(setAnnotationPatternForTypePattern(TypePattern.ANY, ap, false), p);
+ } else {
+ p = new NotTypePattern(tp);
+ }
+ return p;
+ }
+ if (maybeEat("(")) {
+ int openParenPos = tokenSource.peek(-1).getStart();
+ TypePattern p = parseTypePattern(insideTypeParameters, false);
+ if ((p instanceof NotTypePattern) && !(ap instanceof AnyAnnotationTypePattern)) {
+ // dont set the annotation on it, we don't want the annotation to be
+ // considered as part of the not, it is outside the not (pr228980)
+ TypePattern tp = setAnnotationPatternForTypePattern(TypePattern.ANY, ap, parameterAnnotationsPossible);
+ p = new AndTypePattern(tp, p);
+ } else {
+ p = setAnnotationPatternForTypePattern(p, ap, parameterAnnotationsPossible);
+ }
+ eat(")");
+ int closeParenPos = tokenSource.peek(-1).getStart();
+ boolean isVarArgs = maybeEat("...");
+ if (isVarArgs) {
+ p.setIsVarArgs(isVarArgs);
+ }
+ boolean isIncludeSubtypes = maybeEat("+");
+ if (isIncludeSubtypes) {
+ p.includeSubtypes = true; // need the test because (A+) should not set subtypes to false!
+ }
+ p.start = openParenPos;
+ p.end = closeParenPos;
+ return p;
+ }
+ int startPos = tokenSource.peek().getStart();
+ if (ap.start != -1) {
+ startPos = ap.start;
+ }
+ TypePattern p = parseSingleTypePattern(insideTypeParameters);
+ int endPos = tokenSource.peek(-1).getEnd();
+ p = setAnnotationPatternForTypePattern(p, ap, false);
+ p.setLocation(sourceContext, startPos, endPos);
+ return p;
+ }
+
+ private TypePattern setAnnotationPatternForTypePattern(TypePattern t, AnnotationTypePattern ap,
+ boolean parameterAnnotationsPattern) {
+ TypePattern ret = t;
+ if (parameterAnnotationsPattern) {
+ ap.setForParameterAnnotationMatch();
+ }
+ if (ap != AnnotationTypePattern.ANY) {
+ if (t == TypePattern.ANY) {
+ if (t.annotationPattern == AnnotationTypePattern.ANY) {
+ return new AnyWithAnnotationTypePattern(ap);
+ } else {
+ return new AnyWithAnnotationTypePattern(new AndAnnotationTypePattern(ap, t.annotationPattern));
+ }
+ // ret = new WildTypePattern(new NamePattern[] { NamePattern.ANY }, false, 0, false, null);
+ }
+ if (t.annotationPattern == AnnotationTypePattern.ANY) {
+ ret.setAnnotationTypePattern(ap);
+ } else {
+ ret.setAnnotationTypePattern(new AndAnnotationTypePattern(ap, t.annotationPattern)); // ???
+ }
+ }
+ return ret;
+ }
+
+ public AnnotationTypePattern maybeParseAnnotationPattern() {
+ AnnotationTypePattern ret = AnnotationTypePattern.ANY;
+ AnnotationTypePattern nextPattern = null;
+ while ((nextPattern = maybeParseSingleAnnotationPattern()) != null) {
+ if (ret == AnnotationTypePattern.ANY) {
+ ret = nextPattern;
+ } else {
+ ret = new AndAnnotationTypePattern(ret, nextPattern);
+ }
+ }
+ return ret;
+ }
+
+ // PVAL cope with annotation values at other places in this code
+ public AnnotationTypePattern maybeParseSingleAnnotationPattern() {
+ AnnotationTypePattern ret = null;
+ Map<String, String> values = null;
+ // LALR(2) - fix by making "!@" a single token
+ int startIndex = tokenSource.getIndex();
+ if (maybeEat("!")) {
+ if (maybeEat("@")) {
+ if (maybeEat("(")) {
+ TypePattern p = parseTypePattern();
+ ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
+ eat(")");
+ return ret;
+ } else {
+ TypePattern p = parseSingleTypePattern();
+ if (maybeEatAdjacent("(")) {
+ values = parseAnnotationValues();
+ eat(")");
+ ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p, values));
+ } else {
+ ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
+ }
+ return ret;
+ }
+ } else {
+ tokenSource.setIndex(startIndex); // not for us!
+ return ret;
+ }
+ }
+ if (maybeEat("@")) {
+ if (maybeEat("(")) {
+ TypePattern p = parseTypePattern();
+ ret = new WildAnnotationTypePattern(p);
+ eat(")");
+ return ret;
+ } else {
+ int atPos = tokenSource.peek(-1).getStart();
+ TypePattern p = parseSingleTypePattern();
+ if (maybeEatAdjacent("(")) {
+ values = parseAnnotationValues();
+ eat(")");
+ ret = new WildAnnotationTypePattern(p, values);
+ } else {
+ ret = new WildAnnotationTypePattern(p);
+ }
+ ret.start = atPos;
+ return ret;
+ }
+ } else {
+ tokenSource.setIndex(startIndex); // not for us!
+ return ret;
+ }
+ }
+
+ // Parse annotation values. In an expression in @A(a=b,c=d) this method will be
+ // parsing the a=b,c=d.)
+ public Map<String, String> parseAnnotationValues() {
+ Map<String, String> values = new HashMap<String, String>();
+ boolean seenDefaultValue = false;
+ do {
+ String possibleKeyString = parseAnnotationNameValuePattern();
+ if (possibleKeyString == null) {
+ throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
+ }
+ // did they specify just a single entry 'v' or a keyvalue pair 'k=v'
+ if (maybeEat("=")) {
+ // it was a key!
+ String valueString = parseAnnotationNameValuePattern();
+ if (valueString == null) {
+ throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
+ }
+ values.put(possibleKeyString, valueString);
+ } else if (maybeEat("!=")) {
+ // it was a key, with a !=
+ String valueString = parseAnnotationNameValuePattern();
+ if (valueString == null) {
+ throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
+ }
+ // negation is captured by adding a trailing ! to the key name
+ values.put(possibleKeyString + "!", valueString);
+ } else {
+ if (seenDefaultValue) {
+ throw new ParserException("cannot specify two default values", tokenSource.peek(-1));
+ }
+ seenDefaultValue = true;
+ values.put("value", possibleKeyString);
+ }
+ } while (maybeEat(",")); // keep going whilst there are ','
+ return values;
+ }
+
+ public TypePattern parseSingleTypePattern() {
+ return parseSingleTypePattern(false);
+ }
+
+ public TypePattern parseSingleTypePattern(boolean insideTypeParameters) {
+ if (insideTypeParameters && maybeEat("?")) {
+ return parseGenericsWildcardTypePattern();
+ }
+ if (allowHasTypePatterns) {
+ if (maybeEatIdentifier("hasmethod")) {
+ return parseHasMethodTypePattern();
+ }
+ if (maybeEatIdentifier("hasfield")) {
+ return parseHasFieldTypePattern();
+ }
+ }
+
+ // // Check for a type category
+ // IToken token = tokenSource.peek();
+ // if (token.isIdentifier()) {
+ // String category = token.getString();
+ // TypeCategoryTypePattern typeIsPattern = null;
+ // if (category.equals("isClass")) {
+ // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.CLASS);
+ // } else if (category.equals("isAspect")) {
+ // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ASPECT);
+ // } else if (category.equals("isInterface")) {
+ // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INTERFACE);
+ // } else if (category.equals("isInner")) {
+ // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INNER);
+ // } else if (category.equals("isAnonymous")) {
+ // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANONYMOUS);
+ // } else if (category.equals("isEnum")) {
+ // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ENUM);
+ // } else if (category.equals("isAnnotation")) {
+ // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION);
+ // }
+ // if (typeIsPattern != null) {
+ // tokenSource.next();
+ // typeIsPattern.setLocation(tokenSource.getSourceContext(), token.getStart(), token.getEnd());
+ // return typeIsPattern;
+ // }
+ // }
+ if (maybeEatIdentifier("is")) {
+ int pos = tokenSource.getIndex() - 1;
+ TypePattern typeIsPattern = parseIsTypePattern();
+ if (typeIsPattern != null) {
+ return typeIsPattern;
+ }
+ // rewind as if we never tried to parse it as a typeIs
+ tokenSource.setIndex(pos);
+ }
+
+ List<NamePattern> names = parseDottedNamePattern();
+
+ int dim = 0;
+ while (maybeEat("[")) {
+ eat("]");
+ dim++;
+ }
+
+ TypePatternList typeParameters = maybeParseTypeParameterList();
+ int endPos = tokenSource.peek(-1).getEnd();
+
+ boolean includeSubtypes = maybeEat("+");
+
+ // TODO do we need to associate the + with either the type or the array?
+ while (maybeEat("[")) {
+ eat("]");
+ dim++;
+ }
+
+ boolean isVarArgs = maybeEat("...");
+
+ // ??? what about the source location of any's????
+ if (names.size() == 1 && names.get(0).isAny() && dim == 0 && !isVarArgs && typeParameters == null) {
+ return TypePattern.ANY;
+ }
+
+ // Notice we increase the dimensions if varargs is set. this is to allow type matching to
+ // succeed later: The actual signature at runtime of a method declared varargs is an array type of
+ // the original declared type (so Integer... becomes Integer[] in the bytecode). So, here for the
+ // pattern 'Integer...' we create a WildTypePattern 'Integer[]' with varargs set. If this matches
+ // during shadow matching, we confirm that the varargs flags match up before calling it a successful
+ // match.
+ return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs, typeParameters);
+ }
+
+ public TypePattern parseHasMethodTypePattern() {
+ int startPos = tokenSource.peek(-1).getStart();
+ eat("(");
+ SignaturePattern sp = parseMethodOrConstructorSignaturePattern();
+ eat(")");
+ int endPos = tokenSource.peek(-1).getEnd();
+ HasMemberTypePattern ret = new HasMemberTypePattern(sp);
+ ret.setLocation(sourceContext, startPos, endPos);
+ return ret;
+ }
+
+ /**
+ * Attempt to parse a typeIs(<category>) construct. If it cannot be parsed we just return null and that should cause the caller
+ * to reset their position and attempt to consume it in another way. This means we won't have problems here: execution(*
+ * typeIs(..)) because someone has decided to call a method the same as our construct.
+ *
+ * @return a TypeIsTypePattern or null if could not be parsed
+ */
+ public TypePattern parseIsTypePattern() {
+ int startPos = tokenSource.peek(-1).getStart(); // that will be the start of the 'typeIs'
+ if (!maybeEatAdjacent("(")) {
+ return null;
+ }
+ IToken token = tokenSource.next();
+ TypeCategoryTypePattern typeIsPattern = null;
+ if (token.isIdentifier()) {
+ String category = token.getString();
+ if (category.equals("ClassType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.CLASS);
+ } else if (category.equals("AspectType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ASPECT);
+ } else if (category.equals("InterfaceType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INTERFACE);
+ } else if (category.equals("InnerType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INNER);
+ } else if (category.equals("AnonymousType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANONYMOUS);
+ } else if (category.equals("EnumType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ENUM);
+ } else if (category.equals("AnnotationType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION);
+ } else if (category.equals("FinalType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.FINAL);
+ } else if (category.equals("AbstractType")) {
+ typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ABSTRACT);
+ }
+ }
+ if (typeIsPattern == null) {
+ return null;
+ }
+ if (!maybeEat(")")) {
+ throw new ParserException(")", tokenSource.peek());
+ }
+ int endPos = tokenSource.peek(-1).getEnd();
+ typeIsPattern.setLocation(tokenSource.getSourceContext(), startPos, endPos);
+ return typeIsPattern;
+ }
+
+ // if (names.size() == 1 && !names.get(0).isAny()) {
+ // if (maybeEatAdjacent("(")) {
+ // if (maybeEat(")")) {
+ // // likely to be one of isClass()/isInterface()/isInner()/isAnonymous()/isAspect()
+ // if (names.size() == 1) {
+ // NamePattern np = names.get(0);
+ // String simpleName = np.maybeGetSimpleName();
+ // if (simpleName != null) {
+
+ // return new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION, np);
+ // } else {
+ // throw new ParserException(
+ // "not a supported type category, supported are isClass/isInterface/isEnum/isAnnotation/isInner/isAnonymous",
+ // tokenSource.peek(-3));
+ // }
+ // }
+ // int stop = 1;
+ // // return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs,
+ // // typeParameters);
+ // }
+ // } else {
+ // throw new ParserException("category type pattern is missing closing parentheses", tokenSource.peek(-2));
+ // }
+ // }
+ // }
+
+ public TypePattern parseHasFieldTypePattern() {
+ int startPos = tokenSource.peek(-1).getStart();
+ eat("(");
+ SignaturePattern sp = parseFieldSignaturePattern();
+ eat(")");
+ int endPos = tokenSource.peek(-1).getEnd();
+ HasMemberTypePattern ret = new HasMemberTypePattern(sp);
+ ret.setLocation(sourceContext, startPos, endPos);
+ return ret;
+ }
+
+ public TypePattern parseGenericsWildcardTypePattern() {
+ List<NamePattern> names = new ArrayList<NamePattern>();
+ names.add(new NamePattern("?"));
+ TypePattern upperBound = null;
+ TypePattern[] additionalInterfaceBounds = new TypePattern[0];
+ TypePattern lowerBound = null;
+ if (maybeEatIdentifier("extends")) {
+ upperBound = parseTypePattern(false, false);
+ additionalInterfaceBounds = maybeParseAdditionalInterfaceBounds();
+ }
+ if (maybeEatIdentifier("super")) {
+ lowerBound = parseTypePattern(false, false);
+ }
+ int endPos = tokenSource.peek(-1).getEnd();
+ return new WildTypePattern(names, false, 0, endPos, false, null, upperBound, additionalInterfaceBounds, lowerBound);
+ }
+
+ // private AnnotationTypePattern completeAnnotationPattern(AnnotationTypePattern p) {
+ // if (maybeEat("&&")) {
+ // return new AndAnnotationTypePattern(p,parseNotOrAnnotationPattern());
+ // }
+ // if (maybeEat("||")) {
+ // return new OrAnnotationTypePattern(p,parseAnnotationTypePattern());
+ // }
+ // return p;
+ // }
+ //
+ // protected AnnotationTypePattern parseAnnotationTypePattern() {
+ // AnnotationTypePattern ap = parseAtomicAnnotationPattern();
+ // if (maybeEat("&&")) {
+ // ap = new AndAnnotationTypePattern(ap, parseNotOrAnnotationPattern());
+ // }
+ //
+ // if (maybeEat("||")) {
+ // ap = new OrAnnotationTypePattern(ap, parseAnnotationTypePattern());
+ // }
+ // return ap;
+ // }
+ //
+ // private AnnotationTypePattern parseNotOrAnnotationPattern() {
+ // AnnotationTypePattern p = parseAtomicAnnotationPattern();
+ // if (maybeEat("&&")) {
+ // p = new AndAnnotationTypePattern(p,parseAnnotationTypePattern());
+ // }
+ // return p;
+ // }
+
+ protected ExactAnnotationTypePattern parseAnnotationNameOrVarTypePattern() {
+ ExactAnnotationTypePattern p = null;
+ int startPos = tokenSource.peek().getStart();
+ if (maybeEat("@")) {
+ throw new ParserException("@Foo form was deprecated in AspectJ 5 M2: annotation name or var ", tokenSource.peek(-1));
+ }
+ p = parseSimpleAnnotationName();
+ int endPos = tokenSource.peek(-1).getEnd();
+ p.setLocation(sourceContext, startPos, endPos);
+ // For optimized syntax that allows binding directly to annotation values (pr234943)
+ if (maybeEat("(")) {
+ String formalName = parseIdentifier();
+ p = new ExactAnnotationFieldTypePattern(p, formalName);
+ eat(")");
+ }
+ return p;
+ }
+
+ /**
+ * @return
+ */
+ private ExactAnnotationTypePattern parseSimpleAnnotationName() {
+ // the @ has already been eaten...
+ ExactAnnotationTypePattern p;
+ StringBuffer annotationName = new StringBuffer();
+ annotationName.append(parseIdentifier());
+ while (maybeEat(".")) {
+ annotationName.append('.');
+ annotationName.append(parseIdentifier());
+ }
+ UnresolvedType type = UnresolvedType.forName(annotationName.toString());
+ p = new ExactAnnotationTypePattern(type, null);
+ return p;
+ }
+
+ // private AnnotationTypePattern parseAtomicAnnotationPattern() {
+ // if (maybeEat("!")) {
+ // //int startPos = tokenSource.peek(-1).getStart();
+ // //??? we lose source location for true start of !type
+ // AnnotationTypePattern p = new NotAnnotationTypePattern(parseAtomicAnnotationPattern());
+ // return p;
+ // }
+ // if (maybeEat("(")) {
+ // AnnotationTypePattern p = parseAnnotationTypePattern();
+ // eat(")");
+ // return p;
+ // }
+ // int startPos = tokenSource.peek().getStart();
+ // eat("@");
+ // StringBuffer annotationName = new StringBuffer();
+ // annotationName.append(parseIdentifier());
+ // while (maybeEat(".")) {
+ // annotationName.append('.');
+ // annotationName.append(parseIdentifier());
+ // }
+ // UnresolvedType type = UnresolvedType.forName(annotationName.toString());
+ // AnnotationTypePattern p = new ExactAnnotationTypePattern(type);
+ // int endPos = tokenSource.peek(-1).getEnd();
+ // p.setLocation(sourceContext, startPos, endPos);
+ // return p;
+ // }
+
+ public List<NamePattern> parseDottedNamePattern() {
+ List<NamePattern> names = new ArrayList<NamePattern>();
+ StringBuffer buf = new StringBuffer();
+ IToken previous = null;
+ boolean justProcessedEllipsis = false; // Remember if we just dealt with an ellipsis (PR61536)
+ boolean justProcessedDot = false;
+ boolean onADot = false;
+
+ while (true) {
+ IToken tok = null;
+ int startPos = tokenSource.peek().getStart();
+ String afterDot = null;
+ while (true) {
+ if (previous != null && previous.getString().equals(".")) {
+ justProcessedDot = true;
+ }
+ tok = tokenSource.peek();
+ onADot = (tok.getString().equals("."));
+ if (previous != null) {
+ if (!isAdjacent(previous, tok)) {
+ break;
+ }
+ }
+ if (tok.getString() == "*" || (tok.isIdentifier() && tok.getString() != "...")) {
+ buf.append(tok.getString());
+ } else if (tok.getString() == "...") {
+ break;
+ } else if (tok.getLiteralKind() != null) {
+ // System.err.println("literal kind: " + tok.getString());
+ String s = tok.getString();
+ int dot = s.indexOf('.');
+ if (dot != -1) {
+ buf.append(s.substring(0, dot));
+ afterDot = s.substring(dot + 1);
+ previous = tokenSource.next();
+ break;
+ }
+ buf.append(s); // ??? so-so
+ } else {
+ break;
+ }
+ previous = tokenSource.next();
+ // XXX need to handle floats and other fun stuff
+ }
+ int endPos = tokenSource.peek(-1).getEnd();
+ if (buf.length() == 0 && names.isEmpty()) {
+ throw new ParserException("name pattern", tok);
+ }
+
+ if (buf.length() == 0 && justProcessedEllipsis) {
+ throw new ParserException("name pattern cannot finish with ..", tok);
+ }
+ if (buf.length() == 0 && justProcessedDot && !onADot) {
+ throw new ParserException("name pattern cannot finish with .", tok);
+ }
+
+ if (buf.length() == 0) {
+ names.add(NamePattern.ELLIPSIS);
+ justProcessedEllipsis = true;
+ } else {
+ checkLegalName(buf.toString(), previous);
+ NamePattern ret = new NamePattern(buf.toString());
+ ret.setLocation(sourceContext, startPos, endPos);
+ names.add(ret);
+ justProcessedEllipsis = false;
+ }
+
+ if (afterDot == null) {
+ buf.setLength(0);
+ // no elipsis or dotted name part
+ if (!maybeEat(".")) {
+ break;
+ // go on
+ } else {
+ previous = tokenSource.peek(-1);
+ }
+ } else {
+ buf.setLength(0);
+ buf.append(afterDot);
+ afterDot = null;
+ }
+ }
+ // System.err.println("parsed: " + names);
+ return names;
+ }
+
+ // supported form 'a.b.c.d' or just 'a'
+ public String parseAnnotationNameValuePattern() {
+ StringBuffer buf = new StringBuffer();
+ IToken tok;
+ // int startPos =
+ tokenSource.peek().getStart();
+ boolean dotOK = false;
+ int depth = 0;
+ while (true) {
+ tok = tokenSource.peek();
+ // keep going until we hit ')' or '=' or ','
+ if (tok.getString() == ")" && depth == 0) {
+ break;
+ }
+ if (tok.getString() == "!=" && depth == 0) {
+ break;
+ }
+ if (tok.getString() == "=" && depth == 0) {
+ break;
+ }
+ if (tok.getString() == "," && depth == 0) {
+ break;
+ }
+ if (tok == IToken.EOF) {
+ throw new ParserException("eof", tokenSource.peek());
+ }
+
+ // keep track of nested brackets
+ if (tok.getString() == "(") {
+ depth++;
+ }
+ if (tok.getString() == ")") {
+ depth--;
+ }
+ if (tok.getString() == "{") {
+ depth++;
+ }
+ if (tok.getString() == "}") {
+ depth--;
+ }
+
+ if (tok.getString() == "." && !dotOK) {
+ throw new ParserException("dot not expected", tok);
+ }
+ buf.append(tok.getString());
+ tokenSource.next();
+ dotOK = true;
+ }
+ return buf.toString();
+ }
+
+ public NamePattern parseNamePattern() {
+ StringBuffer buf = new StringBuffer();
+ IToken previous = null;
+ IToken tok;
+ int startPos = tokenSource.peek().getStart();
+ while (true) {
+ tok = tokenSource.peek();
+ if (previous != null) {
+ if (!isAdjacent(previous, tok)) {
+ break;
+ }
+ }
+ if (tok.getString() == "*" || tok.isIdentifier()) {
+ buf.append(tok.getString());
+ } else if (tok.getLiteralKind() != null) {
+ // System.err.println("literal kind: " + tok.getString());
+ String s = tok.getString();
+ if (s.indexOf('.') != -1) {
+ break;
+ }
+ buf.append(s); // ??? so-so
+ } else {
+ break;
+ }
+ previous = tokenSource.next();
+ // XXX need to handle floats and other fun stuff
+ }
+ int endPos = tokenSource.peek(-1).getEnd();
+ if (buf.length() == 0) {
+ throw new ParserException("name pattern", tok);
+ }
+
+ checkLegalName(buf.toString(), previous);
+ NamePattern ret = new NamePattern(buf.toString());
+ ret.setLocation(sourceContext, startPos, endPos);
+ return ret;
+ }
+
+ private void checkLegalName(String s, IToken tok) {
+ char ch = s.charAt(0);
+ if (!(ch == '*' || Character.isJavaIdentifierStart(ch))) {
+ throw new ParserException("illegal identifier start (" + ch + ")", tok);
+ }
+
+ for (int i = 1, len = s.length(); i < len; i++) {
+ ch = s.charAt(i);
+ if (!(ch == '*' || Character.isJavaIdentifierPart(ch))) {
+ throw new ParserException("illegal identifier character (" + ch + ")", tok);
+ }
+ }
+
+ }
+
+ private boolean isAdjacent(IToken first, IToken second) {
+ return first.getEnd() == second.getStart() - 1;
+ }
+
+ public ModifiersPattern parseModifiersPattern() {
+ int requiredFlags = 0;
+ int forbiddenFlags = 0;
+ int start;
+ while (true) {
+ start = tokenSource.getIndex();
+ boolean isForbidden = false;
+ isForbidden = maybeEat("!");
+ IToken t = tokenSource.next();
+ int flag = ModifiersPattern.getModifierFlag(t.getString());
+ if (flag == -1) {
+ break;
+ }
+ if (isForbidden) {
+ forbiddenFlags |= flag;
+ } else {
+ requiredFlags |= flag;
+ }
+ }
+
+ tokenSource.setIndex(start);
+ if (requiredFlags == 0 && forbiddenFlags == 0) {
+ return ModifiersPattern.ANY;
+ } else {
+ return new ModifiersPattern(requiredFlags, forbiddenFlags);
+ }
+ }
+
+ public TypePatternList parseArgumentsPattern(boolean parameterAnnotationsPossible) {
+ List<TypePattern> patterns = new ArrayList<TypePattern>();
+ eat("(");
+
+ // ()
+ if (maybeEat(")")) {
+ return new TypePatternList();
+ }
+
+ do {
+ if (maybeEat(".")) { // ..
+ eat(".");
+ patterns.add(TypePattern.ELLIPSIS);
+ } else {
+ patterns.add(parseTypePattern(false, parameterAnnotationsPossible));
+ }
+ } while (maybeEat(","));
+ eat(")");
+ return new TypePatternList(patterns);
+ }
+
+ public AnnotationPatternList parseArgumentsAnnotationPattern() {
+ List<AnnotationTypePattern> patterns = new ArrayList<AnnotationTypePattern>();
+ eat("(");
+ if (maybeEat(")")) {
+ return new AnnotationPatternList();
+ }
+
+ do {
+ if (maybeEat(".")) {
+ eat(".");
+ patterns.add(AnnotationTypePattern.ELLIPSIS);
+ } else if (maybeEat("*")) {
+ patterns.add(AnnotationTypePattern.ANY);
+ } else {
+ patterns.add(parseAnnotationNameOrVarTypePattern());
+ }
+ } while (maybeEat(","));
+ eat(")");
+ return new AnnotationPatternList(patterns);
+ }
+
+ public ThrowsPattern parseOptionalThrowsPattern() {
+ IToken t = tokenSource.peek();
+ if (t.isIdentifier() && t.getString().equals("throws")) {
+ tokenSource.next();
+ List<TypePattern> required = new ArrayList<TypePattern>();
+ List<TypePattern> forbidden = new ArrayList<TypePattern>();
+ do {
+ boolean isForbidden = maybeEat("!");
+ // ???might want an error for a second ! without a paren
+ TypePattern p = parseTypePattern();
+ if (isForbidden) {
+ forbidden.add(p);
+ } else {
+ required.add(p);
+ }
+ } while (maybeEat(","));
+ return new ThrowsPattern(new TypePatternList(required), new TypePatternList(forbidden));
+ }
+ return ThrowsPattern.ANY;
+ }
+
+ public SignaturePattern parseMethodOrConstructorSignaturePattern() {
+ int startPos = tokenSource.peek().getStart();
+ AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
+ ModifiersPattern modifiers = parseModifiersPattern();
+ TypePattern returnType = parseTypePattern(false, false);
+
+ TypePattern declaringType;
+ NamePattern name = null;
+ MemberKind kind;
+ // here we can check for 'new'
+ if (maybeEatNew(returnType)) {
+ kind = Member.CONSTRUCTOR;
+ if (returnType.toString().length() == 0) {
+ declaringType = TypePattern.ANY;
+ } else {
+ declaringType = returnType;
+ }
+ returnType = TypePattern.ANY;
+ name = NamePattern.ANY;
+ } else {
+ kind = Member.METHOD;
+ IToken nameToken = tokenSource.peek();
+ declaringType = parseTypePattern(false, false);
+ if (maybeEat(".")) {
+ nameToken = tokenSource.peek();
+ name = parseNamePattern();
+ } else {
+ name = tryToExtractName(declaringType);
+ if (declaringType.toString().equals("")) {
+ declaringType = TypePattern.ANY;
+ }
+ }
+ if (name == null) {
+ throw new ParserException("name pattern", tokenSource.peek());
+ }
+ String simpleName = name.maybeGetSimpleName();
+ // XXX should add check for any Java keywords
+ if (simpleName != null && simpleName.equals("new")) {
+ throw new ParserException("method name (not constructor)", nameToken);
+ }
+ }
+
+ TypePatternList parameterTypes = parseArgumentsPattern(true);
+
+ ThrowsPattern throwsPattern = parseOptionalThrowsPattern();
+ SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
+ throwsPattern, annotationPattern);
+ int endPos = tokenSource.peek(-1).getEnd();
+ ret.setLocation(sourceContext, startPos, endPos);
+ return ret;
+ }
+
+ private boolean maybeEatNew(TypePattern returnType) {
+ if (returnType instanceof WildTypePattern) {
+ WildTypePattern p = (WildTypePattern) returnType;
+ if (p.maybeExtractName("new")) {
+ return true;
+ }
+ }
+ int start = tokenSource.getIndex();
+ if (maybeEat(".")) {
+ String id = maybeEatIdentifier();
+ if (id != null && id.equals("new")) {
+ return true;
+ }
+ tokenSource.setIndex(start);
+ }
+
+ return false;
+ }
+
+ public ISignaturePattern parseMaybeParenthesizedFieldSignaturePattern() {
+ boolean negated = tokenSource.peek().getString().equals("!") && tokenSource.peek(1).getString().equals("(");
+ if (negated) {
+ eat("!");
+ }
+ ISignaturePattern result = null;
+ if (maybeEat("(")) {
+ result = parseCompoundFieldSignaturePattern();
+ eat(")", "missing ')' - unbalanced parentheses around field signature pattern in declare @field");
+ if (negated) {
+ result = new NotSignaturePattern(result);
+ }
+ } else {
+ result = parseFieldSignaturePattern();
+ }
+ return result;
+ }
+
+ public ISignaturePattern parseMaybeParenthesizedMethodOrConstructorSignaturePattern(boolean isMethod) {
+ boolean negated = tokenSource.peek().getString().equals("!") && tokenSource.peek(1).getString().equals("(");
+ if (negated) {
+ eat("!");
+ }
+ ISignaturePattern result = null;
+ if (maybeEat("(")) {
+ result = parseCompoundMethodOrConstructorSignaturePattern(isMethod);
+ eat(")", "missing ')' - unbalanced parentheses around method/ctor signature pattern in declare annotation");
+ if (negated) {
+ result = new NotSignaturePattern(result);
+ }
+ } else {
+ SignaturePattern sp = parseMethodOrConstructorSignaturePattern();
+ boolean isConstructorPattern = (sp.getKind() == Member.CONSTRUCTOR);
+ if (isMethod && isConstructorPattern) {
+ throw new ParserException("method signature pattern", tokenSource.peek(-1));
+ }
+ if (!isMethod && !isConstructorPattern) {
+ throw new ParserException("constructor signature pattern", tokenSource.peek(-1));
+ }
+ result = sp;
+ }
+
+ return result;
+ }
+
+ public SignaturePattern parseFieldSignaturePattern() {
+ int startPos = tokenSource.peek().getStart();
+
+ // TypePatternList followMe = TypePatternList.ANY;
+
+ AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
+ ModifiersPattern modifiers = parseModifiersPattern();
+ TypePattern returnType = parseTypePattern();
+ TypePattern declaringType = parseTypePattern();
+ NamePattern name;
+ // System.err.println("parsed field: " + declaringType.toString());
+ if (maybeEat(".")) {
+ name = parseNamePattern();
+ } else {
+ name = tryToExtractName(declaringType);
+ if (name == null) {
+ throw new ParserException("name pattern", tokenSource.peek());
+ }
+ if (declaringType.toString().equals("")) {
+ declaringType = TypePattern.ANY;
+ }
+ }
+ SignaturePattern ret = new SignaturePattern(Member.FIELD, modifiers, returnType, declaringType, name, TypePatternList.ANY,
+ ThrowsPattern.ANY, annotationPattern);
+
+ int endPos = tokenSource.peek(-1).getEnd();
+ ret.setLocation(sourceContext, startPos, endPos);
+ return ret;
+ }
+
+ private NamePattern tryToExtractName(TypePattern nextType) {
+ if (nextType == TypePattern.ANY) {
+ return NamePattern.ANY;
+ } else if (nextType instanceof WildTypePattern) {
+ WildTypePattern p = (WildTypePattern) nextType;
+ return p.extractName();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Parse type variable declarations for a generic method or at the start of a signature pointcut to identify type variable names
+ * in a generic type.
+ *
+ * @param includeParameterizedTypes
+ * @return
+ */
+ public TypeVariablePatternList maybeParseTypeVariableList() {
+ if (!maybeEat("<")) {
+ return null;
+ }
+ List<TypeVariablePattern> typeVars = new ArrayList<TypeVariablePattern>();
+ TypeVariablePattern t = parseTypeVariable();
+ typeVars.add(t);
+ while (maybeEat(",")) {
+ TypeVariablePattern nextT = parseTypeVariable();
+ typeVars.add(nextT);
+ }
+ eat(">");
+ TypeVariablePattern[] tvs = new TypeVariablePattern[typeVars.size()];
+ typeVars.toArray(tvs);
+ return new TypeVariablePatternList(tvs);
+ }
+
+ // of the form execution<T,S,V> - allows identifiers only
+ public String[] maybeParseSimpleTypeVariableList() {
+ if (!maybeEat("<")) {
+ return null;
+ }
+ List<String> typeVarNames = new ArrayList<String>();
+ do {
+ typeVarNames.add(parseIdentifier());
+ } while (maybeEat(","));
+ eat(">", "',' or '>'");
+ String[] tvs = new String[typeVarNames.size()];
+ typeVarNames.toArray(tvs);
+ return tvs;
+ }
+
+ public TypePatternList maybeParseTypeParameterList() {
+ if (!maybeEat("<")) {
+ return null;
+ }
+ List<TypePattern> typePats = new ArrayList<TypePattern>();
+ do {
+ TypePattern tp = parseTypePattern(true, false);
+ typePats.add(tp);
+ } while (maybeEat(","));
+ eat(">");
+ TypePattern[] tps = new TypePattern[typePats.size()];
+ typePats.toArray(tps);
+ return new TypePatternList(tps);
+ }
+
+ public TypeVariablePattern parseTypeVariable() {
+ TypePattern upperBound = null;
+ TypePattern[] additionalInterfaceBounds = null;
+ TypePattern lowerBound = null;
+ String typeVariableName = parseIdentifier();
+ if (maybeEatIdentifier("extends")) {
+ upperBound = parseTypePattern();
+ additionalInterfaceBounds = maybeParseAdditionalInterfaceBounds();
+ } else if (maybeEatIdentifier("super")) {
+ lowerBound = parseTypePattern();
+ }
+ return new TypeVariablePattern(typeVariableName, upperBound, additionalInterfaceBounds, lowerBound);
+ }
+
+ private TypePattern[] maybeParseAdditionalInterfaceBounds() {
+ List<TypePattern> boundsList = new ArrayList<TypePattern>();
+ while (maybeEat("&")) {
+ TypePattern tp = parseTypePattern();
+ boundsList.add(tp);
+ }
+ if (boundsList.size() == 0) {
+ return null;
+ }
+ TypePattern[] ret = new TypePattern[boundsList.size()];
+ boundsList.toArray(ret);
+ return ret;
+ }
+
+ public String parsePossibleStringSequence(boolean shouldEnd) {
+ StringBuffer result = new StringBuffer();
+
+ IToken token = tokenSource.next();
+ if (token.getLiteralKind() == null) {
+ throw new ParserException("string", token);
+ }
+ while (token.getLiteralKind().equals("string")) {
+ result.append(token.getString());
+ boolean plus = maybeEat("+");
+ if (!plus) {
+ break;
+ }
+ token = tokenSource.next();
+ if (token.getLiteralKind() == null) {
+ throw new ParserException("string", token);
+ }
+ }
+ eatIdentifier(";");
+ IToken t = tokenSource.next();
+ if (shouldEnd && t != IToken.EOF) {
+ throw new ParserException("<string>;", token);
+ }
+ // bug 125027: since we've eaten the ";" we need to set the index
+ // to be one less otherwise the end position isn't set correctly.
+ int currentIndex = tokenSource.getIndex();
+ tokenSource.setIndex(currentIndex - 1);
+
+ return result.toString();
+
+ }
+
+ public String parseStringLiteral() {
+ IToken token = tokenSource.next();
+ String literalKind = token.getLiteralKind();
+ if (literalKind == "string") {
+ return token.getString();
+ }
+
+ throw new ParserException("string", token);
+ }
+
+ public String parseIdentifier() {
+ IToken token = tokenSource.next();
+ if (token.isIdentifier()) {
+ return token.getString();
+ }
+ throw new ParserException("identifier", token);
+ }
+
+ public void eatIdentifier(String expectedValue) {
+ IToken next = tokenSource.next();
+ if (!next.getString().equals(expectedValue)) {
+ throw new ParserException(expectedValue, next);
+ }
+ }
+
+ public boolean maybeEatIdentifier(String expectedValue) {
+ IToken next = tokenSource.peek();
+ if (next.getString().equals(expectedValue)) {
+ tokenSource.next();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void eat(String expectedValue) {
+ eat(expectedValue, expectedValue);
+ }
+
+ private void eat(String expectedValue, String expectedMessage) {
+ IToken next = nextToken();
+ if (next.getString() != expectedValue) {
+ if (expectedValue.equals(">") && next.getString().startsWith(">")) {
+ // handle problem of >> and >>> being lexed as single tokens
+ pendingRightArrows = BasicToken.makeLiteral(next.getString().substring(1).intern(), "string", next.getStart() + 1,
+ next.getEnd());
+ return;
+ }
+ throw new ParserException(expectedMessage, next);
+ }
+ }
+
+ private IToken pendingRightArrows;
+
+ private IToken nextToken() {
+ if (pendingRightArrows != null) {
+ IToken ret = pendingRightArrows;
+ pendingRightArrows = null;
+ return ret;
+ } else {
+ return tokenSource.next();
+ }
+ }
+
+ public boolean maybeEatAdjacent(String token) {
+ IToken next = tokenSource.peek();
+ if (next.getString() == token) {
+ if (isAdjacent(tokenSource.peek(-1), next)) {
+ tokenSource.next();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean maybeEat(String token) {
+ IToken next = tokenSource.peek();
+ if (next.getString() == token) {
+ tokenSource.next();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public String maybeEatIdentifier() {
+ IToken next = tokenSource.peek();
+ if (next.isIdentifier()) {
+ tokenSource.next();
+ return next.getString();
+ } else {
+ return null;
+ }
+ }
+
+ public boolean peek(String token) {
+ IToken next = tokenSource.peek();
+ return next.getString() == token;
+ }
+
+ public void checkEof() {
+ IToken last = tokenSource.next();
+ if (last != IToken.EOF) {
+ throw new ParserException("unexpected pointcut element: " + last.toString(), last);
+ }
+ }
+
+ public PatternParser(String data) {
+ this(BasicTokenSource.makeTokenSource(data, null));
+ }
+
+ public PatternParser(String data, ISourceContext context) {
+ this(BasicTokenSource.makeTokenSource(data, context));
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerCflow.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerCflow.java
new file mode 100644
index 000000000..1ad834e06
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerCflow.java
@@ -0,0 +1,175 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.CrosscuttingMembers;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.NameMangler;
+import org.aspectj.weaver.ResolvedMemberImpl;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Test;
+
+public class PerCflow extends PerClause {
+ private final boolean isBelow;
+ private final Pointcut entry;
+
+ public PerCflow(Pointcut entry, boolean isBelow) {
+ this.entry = entry;
+ this.isBelow = isBelow;
+ }
+
+ // -----
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ return FuzzyBoolean.YES;
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ // assert bindings == null;
+ entry.resolve(scope);
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ PerCflow ret = new PerCflow(entry.parameterizeWith(typeVariableMap, w), isBelow);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ Expr myInstance = Expr.makeCallExpr(AjcMemberMaker.perCflowAspectOfMethod(inAspect), Expr.NONE, inAspect);
+ state.setAspectInstance(myInstance);
+ return Test.makeCall(AjcMemberMaker.perCflowHasAspectMethod(inAspect), Expr.NONE);
+ }
+
+ public PerClause concretize(ResolvedType inAspect) {
+ PerCflow ret = new PerCflow(entry, isBelow);
+ ret.inAspect = inAspect;
+ if (inAspect.isAbstract()) {
+ return ret;
+ }
+
+ Member cflowStackField = new ResolvedMemberImpl(Member.FIELD, inAspect, Modifier.PUBLIC | Modifier.STATIC,
+ UnresolvedType.forName(NameMangler.CFLOW_STACK_TYPE), NameMangler.PERCFLOW_FIELD_NAME, UnresolvedType.NONE);
+
+ World world = inAspect.getWorld();
+
+ CrosscuttingMembers xcut = inAspect.crosscuttingMembers;
+
+ Collection<ShadowMunger> previousCflowEntries = xcut.getCflowEntries();
+ Pointcut concreteEntry = entry.concretize(inAspect, inAspect, 0, null); // IntMap
+ // .
+ // EMPTY
+ // )
+ // ;
+ List<ShadowMunger> innerCflowEntries = new ArrayList<ShadowMunger>(xcut.getCflowEntries());
+ innerCflowEntries.removeAll(previousCflowEntries);
+
+ xcut.addConcreteShadowMunger(Advice.makePerCflowEntry(world, concreteEntry, isBelow, cflowStackField, inAspect,
+ innerCflowEntries));
+
+ // ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects
+ if (inAspect.isAnnotationStyleAspect() && !inAspect.isAbstract()) {
+ inAspect.crosscuttingMembers.addLateTypeMunger(inAspect.getWorld().getWeavingSupport()
+ .makePerClauseAspect(inAspect, getKind()));
+ }
+
+ // ATAJ inline around advice support - don't use a late munger to allow
+ // around inling for itself
+ if (inAspect.isAnnotationStyleAspect() && !inAspect.getWorld().isXnoInline()) {
+ inAspect.crosscuttingMembers.addTypeMunger(inAspect.getWorld().getWeavingSupport()
+ .createAccessForInlineMunger(inAspect));
+ }
+
+ return ret;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ PERCFLOW.write(s);
+ entry.write(s);
+ s.writeBoolean(isBelow);
+ writeLocation(s);
+ }
+
+ public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ PerCflow ret = new PerCflow(Pointcut.read(s, context), s.readBoolean());
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public PerClause.Kind getKind() {
+ return PERCFLOW;
+ }
+
+ public Pointcut getEntry() {
+ return entry;
+ }
+
+ public String toString() {
+ return "percflow(" + inAspect + " on " + entry + ")";
+ }
+
+ public String toDeclarationString() {
+ if (isBelow) {
+ return "percflowbelow(" + entry + ")";
+ }
+ return "percflow(" + entry + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof PerCflow)) {
+ return false;
+ }
+ PerCflow pc = (PerCflow) other;
+ return (pc.isBelow && isBelow) && ((pc.inAspect == null) ? (inAspect == null) : pc.inAspect.equals(inAspect))
+ && ((pc.entry == null) ? (entry == null) : pc.entry.equals(entry));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + (isBelow ? 0 : 1);
+ result = 37 * result + ((inAspect == null) ? 0 : inAspect.hashCode());
+ result = 37 * result + ((entry == null) ? 0 : entry.hashCode());
+ return result;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerClause.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerClause.java
new file mode 100644
index 000000000..62b2b1b85
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerClause.java
@@ -0,0 +1,91 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+
+import org.aspectj.util.TypeSafeEnum;
+import org.aspectj.weaver.*;
+
+// PTWIMPL New kind added to this class, can be (de)serialized
+public abstract class PerClause extends Pointcut {
+ protected ResolvedType inAspect;
+
+ public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ Kind kind = Kind.read(s);
+ if (kind == SINGLETON) return PerSingleton.readPerClause(s, context);
+ else if (kind == PERCFLOW) return PerCflow.readPerClause(s, context);
+ else if (kind == PEROBJECT) return PerObject.readPerClause(s, context);
+ else if (kind == FROMSUPER) return PerFromSuper.readPerClause(s, context);
+ else if (kind == PERTYPEWITHIN) return PerTypeWithin.readPerClause(s,context);
+
+ throw new BCException("unknown kind: " + kind);
+ }
+
+ public final Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ throw new RuntimeException("unimplemented: wrong concretize");
+ }
+
+ public abstract PerClause concretize(ResolvedType inAspect);
+
+ public abstract PerClause.Kind getKind();
+
+ public abstract String toDeclarationString();
+
+ public static class Kind extends TypeSafeEnum {
+ public Kind(String name, int key) { super(name, key); }
+
+ public static Kind read(VersionedDataInputStream s) throws IOException {
+ int key = s.readByte();
+ switch(key) {
+ case 1: return SINGLETON;
+ case 2: return PERCFLOW;
+ case 3: return PEROBJECT;
+ case 4: return FROMSUPER;
+ case 5: return PERTYPEWITHIN;
+ }
+ throw new BCException("weird kind " + key);
+ }
+ }
+
+ public static final Kind SINGLETON = new Kind("issingleton", 1);
+ public static final Kind PERCFLOW = new Kind("percflow", 2);
+ public static final Kind PEROBJECT = new Kind("perobject", 3);
+ public static final Kind FROMSUPER = new Kind("fromsuper", 4);
+ public static final Kind PERTYPEWITHIN = new Kind("pertypewithin",5);
+
+ public static class KindAnnotationPrefix extends TypeSafeEnum {
+ private KindAnnotationPrefix(String name, int key) {
+ super(name, key);
+ }
+
+ public String extractPointcut(String perClause) {
+ int from = getName().length();
+ int to = perClause.length()-1;
+ if (!perClause.startsWith(getName())
+ || !perClause.endsWith(")")
+ || from > perClause.length()) {
+ throw new RuntimeException("cannot read perclause " + perClause);
+ }
+
+ return perClause.substring(from, to);
+ }
+
+ public static final KindAnnotationPrefix PERCFLOW = new KindAnnotationPrefix("percflow(", 1);
+ public static final KindAnnotationPrefix PERCFLOWBELOW = new KindAnnotationPrefix("percflowbelow(", 2);
+ public static final KindAnnotationPrefix PERTHIS = new KindAnnotationPrefix("perthis(", 3);
+ public static final KindAnnotationPrefix PERTARGET = new KindAnnotationPrefix("pertarget(", 4);
+ public static final KindAnnotationPrefix PERTYPEWITHIN = new KindAnnotationPrefix("pertypewithin(", 5);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerFromSuper.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerFromSuper.java
new file mode 100644
index 000000000..9875291f3
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerFromSuper.java
@@ -0,0 +1,132 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Test;
+
+public class PerFromSuper extends PerClause {
+ private PerClause.Kind kind;
+
+ public PerFromSuper(PerClause.Kind kind) {
+ this.kind = kind;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ throw new RuntimeException("unimplemented");
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ // this method intentionally left blank
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ throw new RuntimeException("unimplemented");
+ }
+
+ public PerClause concretize(ResolvedType inAspect) {
+ PerClause p = lookupConcretePerClause(inAspect.getSuperclass());
+ if (p == null) {
+ inAspect.getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.MISSING_PER_CLAUSE, inAspect.getSuperclass()),
+ getSourceLocation()));
+ return new PerSingleton().concretize(inAspect);// AV: fallback on something else NPE in AJDT
+ } else {
+ if (p.getKind() != kind) {
+ inAspect.getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.WRONG_PER_CLAUSE, kind, p.getKind()),
+ getSourceLocation()));
+ }
+ return p.concretize(inAspect);
+ }
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ return this;
+ }
+
+ public PerClause lookupConcretePerClause(ResolvedType lookupType) {
+ PerClause ret = lookupType.getPerClause();
+ if (ret == null) {
+ return null;
+ }
+ if (ret instanceof PerFromSuper) {
+ return lookupConcretePerClause(lookupType.getSuperclass());
+ }
+ return ret;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ FROMSUPER.write(s);
+ kind.write(s);
+ writeLocation(s);
+ }
+
+ public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ PerFromSuper ret = new PerFromSuper(Kind.read(s));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public String toString() {
+ return "perFromSuper(" + kind + ", " + inAspect + ")";
+ }
+
+ public String toDeclarationString() {
+ return "";
+ }
+
+ public PerClause.Kind getKind() {
+ return kind;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof PerFromSuper)) {
+ return false;
+ }
+ PerFromSuper pc = (PerFromSuper) other;
+ return pc.kind.equals(kind) && ((pc.inAspect == null) ? (inAspect == null) : pc.inAspect.equals(inAspect));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + kind.hashCode();
+ result = 37 * result + ((inAspect == null) ? 0 : inAspect.hashCode());
+ return result;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerObject.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerObject.java
new file mode 100644
index 000000000..237a64a8e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerObject.java
@@ -0,0 +1,193 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.PerObjectInterfaceTypeMunger;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.ResolvedTypeMunger;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+public class PerObject extends PerClause {
+ private final boolean isThis;
+ private final Pointcut entry;
+
+ private static final int thisKindSet;
+ private static final int targetKindSet;
+
+ static {
+ int thisFlags = Shadow.ALL_SHADOW_KINDS_BITS;
+ int targFlags = Shadow.ALL_SHADOW_KINDS_BITS;
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
+ if (kind.neverHasThis()) {
+ thisFlags -= kind.bit;
+ }
+ if (kind.neverHasTarget()) {
+ targFlags -= kind.bit;
+ }
+ }
+ thisKindSet = thisFlags;
+ targetKindSet = targFlags;
+ }
+
+ public PerObject(Pointcut entry, boolean isThis) {
+ this.entry = entry;
+ this.isThis = isThis;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public int couldMatchKinds() {
+ return isThis ? thisKindSet : targetKindSet;
+ }
+
+ // -----
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ // System.err.println("matches " + this + " ? " + shadow + ", " +
+ // shadow.hasTarget());
+ // ??? could probably optimize this better by testing could match
+ if (isThis) {
+ return FuzzyBoolean.fromBoolean(shadow.hasThis());
+ } else {
+ return FuzzyBoolean.fromBoolean(shadow.hasTarget());
+ }
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ // assert bindings == null;
+ entry.resolve(scope);
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ PerObject ret = new PerObject(entry.parameterizeWith(typeVariableMap, w), isThis);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ private Var getVar(Shadow shadow) {
+ return isThis ? shadow.getThisVar() : shadow.getTargetVar();
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ Expr myInstance = Expr.makeCallExpr(AjcMemberMaker.perObjectAspectOfMethod(inAspect), new Expr[] { getVar(shadow) },
+ inAspect);
+ state.setAspectInstance(myInstance);
+ return Test.makeCall(AjcMemberMaker.perObjectHasAspectMethod(inAspect), new Expr[] { getVar(shadow) });
+ }
+
+ public PerClause concretize(ResolvedType inAspect) {
+ PerObject ret = new PerObject(entry, isThis);
+
+ ret.inAspect = inAspect;
+ if (inAspect.isAbstract()) {
+ return ret;
+ }
+
+ World world = inAspect.getWorld();
+
+ Pointcut concreteEntry = entry.concretize(inAspect, inAspect, 0, null);
+ // concreteEntry = new AndPointcut(this, concreteEntry);
+ // concreteEntry.state = Pointcut.CONCRETE;
+ inAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makePerObjectEntry(world, concreteEntry, isThis, inAspect));
+
+ // FIXME AV - don't use lateMunger here due to test
+ // "inheritance, around advice and abstract pointcuts"
+ // see #75442 thread. Issue with weaving order.
+ ResolvedTypeMunger munger = new PerObjectInterfaceTypeMunger(inAspect, concreteEntry);
+ inAspect.crosscuttingMembers.addLateTypeMunger(world.getWeavingSupport().concreteTypeMunger(munger, inAspect));
+
+ // ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects
+ if (inAspect.isAnnotationStyleAspect() && !inAspect.isAbstract()) {
+ inAspect.crosscuttingMembers.addLateTypeMunger(inAspect.getWorld().getWeavingSupport().makePerClauseAspect(inAspect,
+ getKind()));
+ }
+
+ // ATAJ inline around advice support - don't use a late munger to allow
+ // around inling for itself
+ if (inAspect.isAnnotationStyleAspect() && !inAspect.getWorld().isXnoInline()) {
+ inAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().createAccessForInlineMunger(inAspect));
+ }
+
+ return ret;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ PEROBJECT.write(s);
+ entry.write(s);
+ s.writeBoolean(isThis);
+ writeLocation(s);
+ }
+
+ public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ PerClause ret = new PerObject(Pointcut.read(s, context), s.readBoolean());
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public PerClause.Kind getKind() {
+ return PEROBJECT;
+ }
+
+ public boolean isThis() {
+ return isThis;
+ }
+
+ public String toString() {
+ return "per" + (isThis ? "this" : "target") + "(" + entry + ")";
+ }
+
+ public String toDeclarationString() {
+ return toString();
+ }
+
+ public Pointcut getEntry() {
+ return entry;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof PerObject)) {
+ return false;
+ }
+ PerObject pc = (PerObject) other;
+ return (pc.isThis && isThis) && ((pc.inAspect == null) ? (inAspect == null) : pc.inAspect.equals(inAspect))
+ && ((pc.entry == null) ? (entry == null) : pc.entry.equals(entry));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + (isThis ? 0 : 1);
+ result = 37 * result + ((inAspect == null) ? 0 : inAspect.hashCode());
+ result = 37 * result + ((entry == null) ? 0 : entry.hashCode());
+ return result;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerSingleton.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerSingleton.java
new file mode 100644
index 000000000..f53c3a4a5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerSingleton.java
@@ -0,0 +1,175 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+public class PerSingleton extends PerClause {
+
+ private ResolvedMember perSingletonAspectOfMethod;
+
+ public PerSingleton() {
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.YES;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ return FuzzyBoolean.YES;
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ // this method intentionally left blank
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ return this;
+ }
+
+ public Test findResidueInternal(Shadow shadow, ExposedState state) {
+ // TODO: the commented code is for slow Aspects.aspectOf() style - keep
+ // or remove
+ //
+ // Expr myInstance =
+ // Expr.makeCallExpr(AjcMemberMaker.perSingletonAspectOfMethod(inAspect),
+ // Expr.NONE, inAspect);
+ //
+ // state.setAspectInstance(myInstance);
+ //
+ // // we have no test
+ // // a NoAspectBoundException will be thrown if we need an instance of
+ // this
+ // // aspect before we are bound
+ // return Literal.TRUE;
+ // if (!Ajc5MemberMaker.isSlowAspect(inAspect)) {
+ if (perSingletonAspectOfMethod == null) {
+ // Build this just once
+ perSingletonAspectOfMethod = AjcMemberMaker.perSingletonAspectOfMethod(inAspect);
+ }
+ Expr myInstance = Expr.makeCallExpr(perSingletonAspectOfMethod, Expr.NONE, inAspect);
+
+ state.setAspectInstance(myInstance);
+
+ // we have no test
+ // a NoAspectBoundException will be thrown if we need an instance of
+ // this
+ // aspect before we are bound
+ return Literal.TRUE;
+ // } else {
+ // CallExpr callAspectOf =Expr.makeCallExpr(
+ // Ajc5MemberMaker.perSingletonAspectOfMethod(inAspect),
+ // new Expr[]{
+ // Expr.makeStringConstantExpr(inAspect.getName(), inAspect),
+ // //FieldGet is using ResolvedType and I don't need that here
+ // new FieldGetOn(Member.ajClassField, shadow.getEnclosingType())
+ // },
+ // inAspect
+ // );
+ // Expr castedCallAspectOf = new CastExpr(callAspectOf,
+ // inAspect.getName());
+ // state.setAspectInstance(castedCallAspectOf);
+ // return Literal.TRUE;
+ // }
+ }
+
+ public PerClause concretize(ResolvedType inAspect) {
+ PerSingleton ret = new PerSingleton();
+
+ ret.copyLocationFrom(this);
+
+ World world = inAspect.getWorld();
+
+ ret.inAspect = inAspect;
+
+ // ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects
+ if (inAspect.isAnnotationStyleAspect() && !inAspect.isAbstract()) {
+ // TODO will those change be ok if we add a serializable aspect ?
+ // dig:
+ // "can't be Serializable/Cloneable unless -XserializableAspects"
+ if (getKind() == SINGLETON) { // pr149560
+ inAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().makePerClauseAspect(inAspect, getKind()));
+ } else {
+ inAspect.crosscuttingMembers.addLateTypeMunger(world.getWeavingSupport().makePerClauseAspect(inAspect, getKind()));
+ }
+ }
+
+ // ATAJ inline around advice support
+ if (inAspect.isAnnotationStyleAspect() && !inAspect.getWorld().isXnoInline()) {
+ inAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().createAccessForInlineMunger(inAspect));
+ }
+
+ return ret;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ SINGLETON.write(s);
+ writeLocation(s);
+ }
+
+ public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ PerSingleton ret = new PerSingleton();
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public PerClause.Kind getKind() {
+ return SINGLETON;
+ }
+
+ public String toString() {
+ return "persingleton(" + inAspect + ")";
+ }
+
+ public String toDeclarationString() {
+ return "";
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof PerSingleton)) {
+ return false;
+ }
+ PerSingleton pc = (PerSingleton) other;
+ return ((pc.inAspect == null) ? (inAspect == null) : pc.inAspect.equals(inAspect));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + ((inAspect == null) ? 0 : inAspect.hashCode());
+ return result;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java
new file mode 100644
index 000000000..0020cefdc
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Vasseur initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.ResolvedPointcutDefinition;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+
+/**
+ * A visitor that turns a pointcut into a type pattern equivalent for a perthis or pertarget matching: - pertarget(target(Foo)) =>
+ * Foo+ (this one is a special case..) - pertarget(execution(* Foo.do()) => Foo - perthis(call(* Foo.do()) => * - perthis(!call(*
+ * Foo.do()) => * (see how the ! has been absorbed here..)
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+public class PerThisOrTargetPointcutVisitor extends AbstractPatternNodeVisitor {
+
+ /** A maybe marker */
+ private final static TypePattern MAYBE = new TypePatternMayBe();
+
+ private final boolean m_isTarget;
+ private final ResolvedType m_fromAspectType;
+
+ public PerThisOrTargetPointcutVisitor(boolean isTarget, ResolvedType fromAspectType) {
+ m_isTarget = isTarget;
+ m_fromAspectType = fromAspectType;
+ }
+
+ public TypePattern getPerTypePointcut(Pointcut perClausePointcut) {
+ Object o = perClausePointcut.accept(this, perClausePointcut);
+ if (o instanceof TypePattern) {
+ return (TypePattern) o;
+ } else {
+ throw new BCException("perClausePointcut visitor did not return a typepattern, it returned " + o
+ + (o == null ? "" : " of type " + o.getClass()));
+ }
+ }
+
+ // -- visitor methods, all is like Identity visitor except when it comes to transform pointcuts
+
+ public Object visit(WithinPointcut node, Object data) {
+ if (m_isTarget) {
+ // pertarget(.. && within(Foo)) => true
+ // pertarget(.. && !within(Foo)) => true as well !
+ return MAYBE;
+ } else {
+ return node.getTypePattern();
+ }
+ }
+
+ public Object visit(WithincodePointcut node, Object data) {
+ if (m_isTarget) {
+ // pertarget(.. && withincode(* Foo.do())) => true
+ // pertarget(.. && !withincode(* Foo.do())) => true as well !
+ return MAYBE;
+ } else {
+ return node.getSignature().getDeclaringType();
+ }
+ }
+
+ public Object visit(WithinAnnotationPointcut node, Object data) {
+ if (m_isTarget) {
+ return MAYBE;
+ } else {
+ return new AnyWithAnnotationTypePattern(node.getAnnotationTypePattern());
+ }
+ }
+
+ public Object visit(WithinCodeAnnotationPointcut node, Object data) {
+ if (m_isTarget) {
+ return MAYBE;
+ } else {
+ return MAYBE;// FIXME AV - can we optimize ? perthis(@withincode(Foo)) = hasmethod(..)
+ }
+ }
+
+ public Object visit(KindedPointcut node, Object data) {
+ if (node.getKind().equals(Shadow.AdviceExecution)) {
+ return MAYBE;// TODO AV - can we do better ?
+ } else if (node.getKind().equals(Shadow.ConstructorExecution) || node.getKind().equals(Shadow.Initialization)
+ || node.getKind().equals(Shadow.MethodExecution) || node.getKind().equals(Shadow.PreInitialization)
+ || node.getKind().equals(Shadow.StaticInitialization)) {
+ SignaturePattern signaturePattern = node.getSignature();
+ boolean isStarAnnotation = signaturePattern.isStarAnnotation();
+ // For a method execution joinpoint, we check for an annotation pattern. If there is one we know it will be matched
+ // against the 'primary' joinpoint (the one in the type) - 'super'joinpoints can't match it. If this situation occurs
+ // we can re-use the HasMemberTypePattern to guard on whether the perthis/target should match. pr354470
+ if (!m_isTarget && node.getKind().equals(Shadow.MethodExecution)) {
+ if (!isStarAnnotation) {
+ return new HasMemberTypePatternForPerThisMatching(signaturePattern);
+ }
+ }
+ return signaturePattern.getDeclaringType();
+ } else if (node.getKind().equals(Shadow.ConstructorCall) || node.getKind().equals(Shadow.FieldGet)
+ || node.getKind().equals(Shadow.FieldSet) || node.getKind().equals(Shadow.MethodCall)) {
+ if (m_isTarget) {
+ return node.getSignature().getDeclaringType();
+ } else {
+ return MAYBE;
+ }
+ } else if (node.getKind().equals(Shadow.ExceptionHandler)) {
+ return MAYBE;
+ } else {
+ throw new ParserException("Undetermined - should not happen: " + node.getKind().getSimpleName(), null);
+ }
+ }
+
+ public Object visit(AndPointcut node, Object data) {
+ return new AndTypePattern(getPerTypePointcut(node.left), getPerTypePointcut(node.right));
+ }
+
+ public Object visit(OrPointcut node, Object data) {
+ return new OrTypePattern(getPerTypePointcut(node.left), getPerTypePointcut(node.right));
+ }
+
+ public Object visit(NotPointcut node, Object data) {
+ // TypePattern negated = getPerTypePointcut(node.getNegatedPointcut());
+ // if (MAYBE.equals(negated)) {
+ // return MAYBE;
+ // }
+ // return new NotTypePattern(negated);
+ // AMC - the only safe thing to return here is maybe...
+ // see for example pr114054
+ return MAYBE;
+ }
+
+ public Object visit(ThisOrTargetAnnotationPointcut node, Object data) {
+ if (m_isTarget && !node.isThis()) {
+ return new AnyWithAnnotationTypePattern(node.getAnnotationTypePattern());
+ } else if (!m_isTarget && node.isThis()) {
+ return new AnyWithAnnotationTypePattern(node.getAnnotationTypePattern());
+ } else {
+ // perthis(@target(Foo))
+ return MAYBE;
+ }
+ }
+
+ public Object visit(ThisOrTargetPointcut node, Object data) {
+ if ((m_isTarget && !node.isThis()) || (!m_isTarget && node.isThis())) {
+ String pointcutString = node.getType().toString();
+ // see pr115788 "<nothing>" means there was a problem resolving types - that will be reported so dont blow up
+ // the parser here..
+ if (pointcutString.equals("<nothing>")) {
+ return new NoTypePattern();
+ }
+ // pertarget(target(Foo)) => Foo+ for type pattern matching
+ // perthis(this(Foo)) => Foo+ for type pattern matching
+ // TODO AV - we do like a deep copy by parsing it again.. quite dirty, would need a clean deep copy
+ TypePattern copy = new PatternParser(pointcutString.replace('$', '.')).parseTypePattern();
+ // TODO AV - see dirty replace from $ to . here as inner classes are with $ instead (#108488)
+ copy.includeSubtypes = true;
+ return copy;
+ } else {
+ // perthis(target(Foo)) => maybe
+ return MAYBE;
+ }
+ }
+
+ public Object visit(ReferencePointcut node, Object data) {
+ // && pc_ref()
+ // we know there is no support for binding in perClause: perthis(pc_ref(java.lang.String))
+ // TODO AV - may need some work for generics..
+
+ ResolvedPointcutDefinition pointcutDec;
+ ResolvedType searchStart = m_fromAspectType;
+ if (node.onType != null) {
+ searchStart = node.onType.resolve(m_fromAspectType.getWorld());
+ if (searchStart.isMissing()) {
+ return MAYBE;// this should not happen since concretize will fails but just in case..
+ }
+ }
+ pointcutDec = searchStart.findPointcut(node.name);
+
+ return getPerTypePointcut(pointcutDec.getPointcut());
+ }
+
+ public Object visit(IfPointcut node, Object data) {
+ return TypePattern.ANY;
+ }
+
+ public Object visit(HandlerPointcut node, Object data) {
+ // quiet unexpected since a KindedPointcut but do as if...
+ return MAYBE;
+ }
+
+ public Object visit(CflowPointcut node, Object data) {
+ return MAYBE;
+ }
+
+ public Object visit(ConcreteCflowPointcut node, Object data) {
+ return MAYBE;
+ }
+
+ public Object visit(ArgsPointcut node, Object data) {
+ return MAYBE;
+ }
+
+ public Object visit(ArgsAnnotationPointcut node, Object data) {
+ return MAYBE;
+ }
+
+ public Object visit(AnnotationPointcut node, Object data) {
+ return MAYBE;
+ }
+
+ public Object visit(Pointcut.MatchesNothingPointcut node, Object data) {
+ // a small hack since the usual MatchNothing has its toString = "<nothing>" which is not parseable back
+ // while I use back parsing for check purpose.
+ return new NoTypePattern() {
+ public String toString() {
+ return "false";
+ }
+ };
+ }
+
+ /**
+ * A MayBe type pattern that acts as ANY except that !MAYBE = MAYBE
+ *
+ * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
+ */
+ private static class TypePatternMayBe extends AnyTypePattern {
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerTypeWithin.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerTypeWithin.java
new file mode 100644
index 000000000..d912b52ed
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PerTypeWithin.java
@@ -0,0 +1,249 @@
+/* *******************************************************************
+ * Copyright (c) 2005 IBM
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.PerTypeWithinTargetTypeMunger;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.ResolvedTypeMunger;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Expr;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+// PTWIMPL Represents a parsed pertypewithin()
+public class PerTypeWithin extends PerClause {
+
+ private TypePattern typePattern;
+
+ // Any shadow could be considered within a pertypewithin() type pattern
+ private static final int kindSet = Shadow.ALL_SHADOW_KINDS_BITS;
+
+ public TypePattern getTypePattern() {
+ return typePattern;
+ }
+
+ public PerTypeWithin(TypePattern p) {
+ typePattern = p;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return kindSet;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ PerTypeWithin ret = new PerTypeWithin(typePattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ // -----
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ if (typePattern.annotationPattern instanceof AnyAnnotationTypePattern) {
+ return isWithinType(info.getType());
+ }
+ return FuzzyBoolean.MAYBE;
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ ResolvedType enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(), true);
+ if (enclosingType.isMissing()) {
+ // PTWIMPL ?? Add a proper message
+ IMessage msg = new Message("Cant find type pertypewithin matching...", shadow.getSourceLocation(), true,
+ new ISourceLocation[] { getSourceLocation() });
+ shadow.getIWorld().getMessageHandler().handleMessage(msg);
+ }
+
+ // See pr106554 - we can't put advice calls in an interface when the
+ // advice is defined
+ // in a pertypewithin aspect - the JPs only exist in the static
+ // initializer and can't
+ // call the localAspectOf() method.
+ if (enclosingType.isInterface()) {
+ return FuzzyBoolean.NO;
+ }
+ if (!(enclosingType.canBeSeenBy(inAspect) || inAspect.isPrivilegedAspect())) {
+ return FuzzyBoolean.NO;
+ }
+
+ typePattern.resolve(shadow.getIWorld());
+ return isWithinType(enclosingType);
+ }
+
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ typePattern = typePattern.resolveBindings(scope, bindings, false, false);
+ }
+
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ // Member ptwField =
+ // AjcMemberMaker.perTypeWithinField(shadow.getEnclosingType
+ // (),inAspect);
+
+ Expr myInstance = Expr.makeCallExpr(AjcMemberMaker.perTypeWithinLocalAspectOf(shadow.getEnclosingType(), inAspect/*
+ * shadow.
+ * getEnclosingType
+ * ( )
+ */),
+ Expr.NONE, inAspect);
+ state.setAspectInstance(myInstance);
+
+ // this worked at one point
+ // Expr myInstance =
+ // Expr.makeFieldGet(ptwField,shadow.getEnclosingType()
+ // .resolve(shadow.getIWorld()));//inAspect);
+ // state.setAspectInstance(myInstance);
+
+ // return Test.makeFieldGetCall(ptwField,null,Expr.NONE);
+ // cflowField, cflowCounterIsValidMethod, Expr.NONE
+
+ // This is what is in the perObject variant of this ...
+ // Expr myInstance =
+ // Expr.makeCallExpr(AjcMemberMaker.perTypeWithinAspectOfMethod(inAspect)
+ // ,
+ // new Expr[] {getVar(shadow)}, inAspect);
+ // state.setAspectInstance(myInstance);
+ // return
+ // Test.makeCall(AjcMemberMaker.perTypeWithinHasAspectMethod(inAspect),
+ // new Expr[] { getVar(shadow) });
+ //
+
+ return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
+ }
+
+ @Override
+ public PerClause concretize(ResolvedType inAspect) {
+ PerTypeWithin ret = new PerTypeWithin(typePattern);
+ ret.copyLocationFrom(this);
+ ret.inAspect = inAspect;
+ if (inAspect.isAbstract()) {
+ return ret;
+ }
+
+ World world = inAspect.getWorld();
+
+ SignaturePattern sigpat = new SignaturePattern(Member.STATIC_INITIALIZATION, ModifiersPattern.ANY, TypePattern.ANY,
+ TypePattern.ANY,// typePattern,
+ NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY, AnnotationTypePattern.ANY);
+
+ Pointcut staticInitStar = new KindedPointcut(Shadow.StaticInitialization, sigpat);
+ Pointcut withinTp = new WithinPointcut(typePattern);
+ Pointcut andPcut = new AndPointcut(staticInitStar, withinTp);
+ // We want the pointcut to be:
+ // 'staticinitialization(*) && within(<typepattern>)' -
+ // we *cannot* shortcut this to staticinitialization(<typepattern>)
+ // because it doesnt mean the same thing.
+
+ // This munger will initialize the aspect instance field in the matched type
+
+ inAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makePerTypeWithinEntry(world, andPcut, inAspect));
+
+ ResolvedTypeMunger munger = new PerTypeWithinTargetTypeMunger(inAspect, ret);
+ inAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().concreteTypeMunger(munger, inAspect));
+
+ // ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects
+ if (inAspect.isAnnotationStyleAspect() && !inAspect.isAbstract()) {
+ inAspect.crosscuttingMembers.addLateTypeMunger(world.getWeavingSupport().makePerClauseAspect(inAspect, getKind()));
+ }
+
+ // ATAJ inline around advice support - don't use a late munger to allow
+ // around inling for itself
+ if (inAspect.isAnnotationStyleAspect() && !world.isXnoInline()) {
+ inAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().createAccessForInlineMunger(inAspect));
+ }
+
+ return ret;
+
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ PERTYPEWITHIN.write(s);
+ typePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static PerClause readPerClause(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ PerClause ret = new PerTypeWithin(TypePattern.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public PerClause.Kind getKind() {
+ return PERTYPEWITHIN;
+ }
+
+ @Override
+ public String toString() {
+ return "pertypewithin(" + typePattern + ")";
+ }
+
+ @Override
+ public String toDeclarationString() {
+ return toString();
+ }
+
+ private FuzzyBoolean isWithinType(ResolvedType type) {
+ while (type != null) {
+ if (typePattern.matchesStatically(type)) {
+ return FuzzyBoolean.YES;
+ }
+ type = type.getDeclaringType();
+ }
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof PerTypeWithin)) {
+ return false;
+ }
+ PerTypeWithin pc = (PerTypeWithin) other;
+ return ((pc.inAspect == null) ? (inAspect == null) : pc.inAspect.equals(inAspect))
+ && ((pc.typePattern == null) ? (typePattern == null) : pc.typePattern.equals(typePattern));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + ((inAspect == null) ? 0 : inAspect.hashCode());
+ result = 37 * result + ((typePattern == null) ? 0 : typePattern.hashCode());
+ return result;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Pointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Pointcut.java
new file mode 100644
index 000000000..f927286ec
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/Pointcut.java
@@ -0,0 +1,436 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.util.TypeSafeEnum;
+import org.aspectj.weaver.Advice;
+import org.aspectj.weaver.AdviceKind;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.Checker;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.PoliceExtensionUse;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+/**
+ * The lifecycle of Pointcuts is modeled by Pointcut.State. It has three things:
+ *
+ * <p>
+ * Creation -- SYMBOLIC -- then resolve(IScope) -- RESOLVED -- concretize(...) -- CONCRETE
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ *
+ * A day in the life of a pointcut.... - AMC. ==========================================
+ *
+ * Pointcuts are created by the PatternParser, which is called by ajdt to parse a pointcut from the PseudoTokens AST node
+ * (which in turn are part of a PointcutDesignator AST node).
+ *
+ * Pointcuts are resolved by ajdt when an AdviceDeclaration or a PointcutDeclaration has its statements resolved. This
+ * happens as part of completeTypeBindings in the AjLookupEnvironment which is called after the diet parse phase of the
+ * compiler. Named pointcuts, and references to named pointcuts are instances of ReferencePointcut.
+ *
+ * At the end of the compilation process, the pointcuts are serialized (write method) into attributes in the class file.
+ *
+ * When the weaver loads the class files, it unpacks the attributes and deserializes the pointcuts (read). All aspects are
+ * added to the world, by calling addOrReplaceAspect on the crosscutting members set of the world. When aspects are added or
+ * replaced, the crosscutting members in the aspect are extracted as ShadowMungers (each holding a pointcut). The
+ * ShadowMungers are concretized, which concretizes the pointcuts. At this stage ReferencePointcuts are replaced by their
+ * declared content.
+ *
+ * During weaving, the weaver processes type by type. It first culls potentially matching ShadowMungers by calling the
+ * fastMatch method on their pointcuts. Only those that might match make it through to the next phase. At the next phase,
+ * all of the shadows within the type are created and passed to the pointcut for matching (match).
+ *
+ * When the actual munging happens, matched pointcuts are asked for their residue (findResidue) - the runtime test if any.
+ * Because of negation, findResidue may be called on pointcuts that could never match the shadow.
+ *
+ */
+public abstract class Pointcut extends PatternNode {
+ public static final class State extends TypeSafeEnum {
+ public State(String name, int key) {
+ super(name, key);
+ }
+ }
+
+ /**
+ * ATAJ the name of the formal for which we don't want any warning when unbound since we consider them as implicitly bound. f.e.
+ * JoinPoint for @AJ advices
+ */
+ public String[] m_ignoreUnboundBindingForNames = EMPTY_STRING_ARRAY;
+
+ public static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ public static final State SYMBOLIC = new State("symbolic", 0);
+ public static final State RESOLVED = new State("resolved", 1);
+ public static final State CONCRETE = new State("concrete", 2);
+
+ protected byte pointcutKind;
+
+ public State state;
+
+ protected int lastMatchedShadowId;
+ private FuzzyBoolean lastMatchedShadowResult;
+ private String[] typeVariablesInScope = EMPTY_STRING_ARRAY;
+
+ protected boolean hasBeenParameterized = false;
+
+ /**
+ * Constructor for Pattern.
+ */
+ public Pointcut() {
+ super();
+ this.state = SYMBOLIC;
+ }
+
+ /**
+ * Could I match any shadows in the code defined within this type?
+ */
+ public abstract FuzzyBoolean fastMatch(FastMatchInfo info);
+
+ /**
+ * The set of ShadowKinds that this Pointcut could possibly match - an int whose bits are set according to the Kinds specified
+ * in Shadow.java
+ */
+ public abstract int couldMatchKinds();
+
+ public String[] getTypeVariablesInScope() {
+ return typeVariablesInScope;
+ }
+
+ public void setTypeVariablesInScope(String[] typeVars) {
+ this.typeVariablesInScope = typeVars;
+ }
+
+ /**
+ * Do I really match this shadow? XXX implementors need to handle state
+ */
+ public final FuzzyBoolean match(Shadow shadow) {
+ if (shadow.shadowId == lastMatchedShadowId) {
+ return lastMatchedShadowResult;
+ }
+ FuzzyBoolean ret;
+ // this next test will prevent a lot of un-needed matching going on....
+ if (shadow.getKind().isSet(couldMatchKinds())) {
+ ret = matchInternal(shadow);
+ } else {
+ ret = FuzzyBoolean.NO;
+ }
+ lastMatchedShadowId = shadow.shadowId;
+ lastMatchedShadowResult = ret;
+ return ret;
+ }
+
+ protected abstract FuzzyBoolean matchInternal(Shadow shadow);
+
+ public static final byte KINDED = 1;
+ public static final byte WITHIN = 2;
+ public static final byte THIS_OR_TARGET = 3;
+ public static final byte ARGS = 4;
+ public static final byte AND = 5;
+ public static final byte OR = 6;
+ public static final byte NOT = 7;
+ public static final byte REFERENCE = 8;
+ public static final byte IF = 9;
+ public static final byte CFLOW = 10;
+ public static final byte WITHINCODE = 12;
+ public static final byte HANDLER = 13;
+ public static final byte IF_TRUE = 14;
+ public static final byte IF_FALSE = 15;
+ public static final byte ANNOTATION = 16;
+ public static final byte ATWITHIN = 17;
+ public static final byte ATWITHINCODE = 18;
+ public static final byte ATTHIS_OR_TARGET = 19;
+
+ public static final byte NONE = 20; // DO NOT CHANGE OR REORDER THIS SEQUENCE, THIS VALUE CAN BE PUT OUT BY ASPECTJ1.2.1
+
+ public static final byte ATARGS = 21;
+ public static final byte USER_EXTENSION = 22;
+
+ public byte getPointcutKind() {
+ return pointcutKind;
+ }
+
+ // internal, only called from resolve
+ protected abstract void resolveBindings(IScope scope, Bindings bindings);
+
+ /**
+ * Returns this pointcut mutated
+ */
+ public final Pointcut resolve(IScope scope) {
+ assertState(SYMBOLIC);
+ Bindings bindingTable = new Bindings(scope.getFormalCount());
+ IScope bindingResolutionScope = scope;
+ if (typeVariablesInScope.length > 0) {
+ bindingResolutionScope = new ScopeWithTypeVariables(typeVariablesInScope, scope);
+ }
+ this.resolveBindings(bindingResolutionScope, bindingTable);
+ bindingTable.checkAllBound(bindingResolutionScope);
+ this.state = RESOLVED;
+ return this;
+ }
+
+ /**
+ * Returns a new pointcut Only used by test cases
+ */
+ public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, int arity) {
+ Pointcut ret = concretize(inAspect, declaringType, IntMap.idMap(arity));
+ // copy the unbound ignore list
+ ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
+ return ret;
+ }
+
+ // XXX this is the signature we're moving to
+ public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, int arity, ShadowMunger advice) {
+ // if (state == CONCRETE) return this; //???
+ IntMap map = IntMap.idMap(arity);
+ map.setEnclosingAdvice(advice);
+ map.setConcreteAspect(inAspect);
+ return concretize(inAspect, declaringType, map);
+ }
+
+ public boolean isDeclare(ShadowMunger munger) {
+ if (munger == null) {
+ return false; // ??? Is it actually an error if we get a null munger into this method.
+ }
+ if (munger instanceof Checker) {
+ return true;
+ }
+ if (((Advice) munger).getKind().equals(AdviceKind.Softener)) {
+ return true;
+ }
+ return false;
+ }
+
+ public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ // !!! add this test -- assertState(RESOLVED);
+ Pointcut ret = this.concretize1(inAspect, declaringType, bindings);
+ if (shouldCopyLocationForConcretize()) {
+ ret.copyLocationFrom(this);
+ }
+ ret.state = CONCRETE;
+ // copy the unbound ignore list
+ ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
+ return ret;
+ }
+
+ protected boolean shouldCopyLocationForConcretize() {
+ return true;
+ }
+
+ /**
+ * Resolves and removes ReferencePointcuts, replacing with basic ones
+ *
+ * @param inAspect the aspect to resolve relative to
+ * @param bindings a Map from formal index in the current lexical context -> formal index in the concrete advice that will run
+ *
+ * This must always return a new Pointcut object (even if the concretized Pointcut is identical to the resolved one).
+ * That behavior is assumed in many places. XXX fix implementors to handle state
+ */
+ protected abstract Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings);
+
+ // XXX implementors need to handle state
+ /**
+ * This can be called from NotPointcut even for Pointcuts that don't match the shadow
+ */
+ public final Test findResidue(Shadow shadow, ExposedState state) {
+ // if (shadow.shadowId == lastMatchedShadowId) return lastMatchedShadowResidue;
+ Test ret = findResidueInternal(shadow, state);
+ // lastMatchedShadowResidue = ret;
+ lastMatchedShadowId = shadow.shadowId;
+ return ret;
+ }
+
+ protected abstract Test findResidueInternal(Shadow shadow, ExposedState state);
+
+ // XXX we're not sure whether or not this is needed
+ // XXX currently it's unused we're keeping it around as a stub
+ public void postRead(ResolvedType enclosingType) {
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte kind = s.readByte();
+ Pointcut ret;
+
+ switch (kind) {
+ case KINDED:
+ ret = KindedPointcut.read(s, context);
+ break;
+ case WITHIN:
+ ret = WithinPointcut.read(s, context);
+ break;
+ case THIS_OR_TARGET:
+ ret = ThisOrTargetPointcut.read(s, context);
+ break;
+ case ARGS:
+ ret = ArgsPointcut.read(s, context);
+ break;
+ case AND:
+ ret = AndPointcut.read(s, context);
+ break;
+ case OR:
+ ret = OrPointcut.read(s, context);
+ break;
+ case NOT:
+ ret = NotPointcut.read(s, context);
+ break;
+ case REFERENCE:
+ ret = ReferencePointcut.read(s, context);
+ break;
+ case IF:
+ ret = IfPointcut.read(s, context);
+ break;
+ case CFLOW:
+ ret = CflowPointcut.read(s, context);
+ break;
+ case WITHINCODE:
+ ret = WithincodePointcut.read(s, context);
+ break;
+ case HANDLER:
+ ret = HandlerPointcut.read(s, context);
+ break;
+ case IF_TRUE:
+ ret = IfPointcut.makeIfTruePointcut(RESOLVED);
+ break;
+ case IF_FALSE:
+ ret = IfPointcut.makeIfFalsePointcut(RESOLVED);
+ break;
+ case ANNOTATION:
+ ret = AnnotationPointcut.read(s, context);
+ break;
+ case ATWITHIN:
+ ret = WithinAnnotationPointcut.read(s, context);
+ break;
+ case ATWITHINCODE:
+ ret = WithinCodeAnnotationPointcut.read(s, context);
+ break;
+ case ATTHIS_OR_TARGET:
+ ret = ThisOrTargetAnnotationPointcut.read(s, context);
+ break;
+ case ATARGS:
+ ret = ArgsAnnotationPointcut.read(s, context);
+ break;
+ case NONE:
+ ret = makeMatchesNothing(RESOLVED);
+ break;
+ default:
+ throw new BCException("unknown kind: " + kind);
+ }
+ ret.state = RESOLVED;
+ ret.pointcutKind = kind;
+ return ret;
+
+ }
+
+ public void check(ISourceContext ctx, World world) {
+ // this is a quick visitor...
+ PoliceExtensionUse pointcutPolice = new PoliceExtensionUse(world, this);
+ this.accept(pointcutPolice, null);
+ if (pointcutPolice.synchronizationDesignatorEncountered()) {
+ world.setSynchronizationPointcutsInUse();
+ }
+ }
+
+ // public void prepare(Shadow shadow) {}
+
+ // ---- test method
+
+ public static Pointcut fromString(String str) {
+ PatternParser parser = new PatternParser(str);
+ return parser.parsePointcut();
+ }
+
+ static class MatchesNothingPointcut extends Pointcut {
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return Literal.FALSE; // can only get here if an earlier error occurred
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return Shadow.NO_SHADOW_KINDS_BITS;
+ }
+
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ return FuzzyBoolean.NO;
+ }
+
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ }
+
+ @Override
+ public void postRead(ResolvedType enclosingType) {
+ }
+
+ @Override
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ return makeMatchesNothing(state);
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(NONE);
+ }
+
+ @Override
+ public String toString() {
+ return "";
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
+ return this;
+ }
+ }
+
+ // public static Pointcut MatchesNothing = new MatchesNothingPointcut();
+ // ??? there could possibly be some good optimizations to be done at this point
+ public static Pointcut makeMatchesNothing(State state) {
+ Pointcut ret = new MatchesNothingPointcut();
+ ret.state = state;
+ return ret;
+ }
+
+ public void assertState(State state) {
+ if (this.state != state) {
+ throw new BCException("expected state: " + state + " got: " + this.state);
+ }
+ }
+
+ public abstract Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java
new file mode 100644
index 000000000..5f3a3291f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutEvaluationExpenseComparator.java
@@ -0,0 +1,161 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.util.Comparator;
+
+import org.aspectj.weaver.Shadow;
+
+public class PointcutEvaluationExpenseComparator implements Comparator<Pointcut> {
+
+ private static final int MATCHES_NOTHING = -1;
+ private static final int WITHIN = 1;
+ private static final int ATWITHIN = 2;
+ private static final int STATICINIT = 3;
+ private static final int ADVICEEXECUTION = 4;
+ private static final int HANDLER = 5;
+ private static final int GET_OR_SET = 6;
+ private static final int WITHINCODE = 7;
+ private static final int ATWITHINCODE = 8;
+ private static final int EXE_INIT_PREINIT = 9;
+ private static final int CALL_WITH_DECLARING_TYPE = 10;
+ private static final int THIS_OR_TARGET = 11;
+ private static final int CALL_WITHOUT_DECLARING_TYPE = 12;
+ private static final int ANNOTATION = 13;
+ private static final int AT_THIS_OR_TARGET = 14;
+ private static final int ARGS = 15;
+ private static final int AT_ARGS = 16;
+ private static final int CFLOW = 17;
+ private static final int IF = 18;
+ private static final int OTHER = 20;
+
+ /**
+ * Compare 2 pointcuts based on an estimate of how expensive they may be to evaluate.
+ *
+ * within
+ *
+ * @within staticinitialization [make sure this has a fast match method] adviceexecution handler get, set withincode
+ * @withincode execution, initialization, preinitialization call
+ * @annotation this, target
+ * @this, @target args
+ * @args cflow, cflowbelow if
+ */
+ public int compare(Pointcut p1, Pointcut p2) {
+ // important property for a well-defined comparator
+ if (p1.equals(p2)) {
+ return 0;
+ }
+ int result = getScore(p1) - getScore(p2);
+ if (result == 0) {
+ // they have the same evaluation expense, but are not 'equal'
+ // sort by hashCode
+ int p1code = p1.hashCode();
+ int p2code = p2.hashCode();
+ if (p1code == p2code) {
+ return 0;
+ } else if (p1code < p2code) {
+ return -1;
+ } else {
+ return +1;
+ }
+ }
+ return result;
+ }
+
+ // a higher score means a more expensive evaluation
+ private int getScore(Pointcut p) {
+ if (p.couldMatchKinds() == Shadow.NO_SHADOW_KINDS_BITS) {
+ return MATCHES_NOTHING;
+ }
+ if (p instanceof WithinPointcut) {
+ return WITHIN;
+ }
+ if (p instanceof WithinAnnotationPointcut) {
+ return ATWITHIN;
+ }
+ if (p instanceof KindedPointcut) {
+ KindedPointcut kp = (KindedPointcut) p;
+ Shadow.Kind kind = kp.getKind();
+ if (kind == Shadow.AdviceExecution) {
+ return ADVICEEXECUTION;
+ } else if ((kind == Shadow.ConstructorCall) || (kind == Shadow.MethodCall)) {
+ TypePattern declaringTypePattern = kp.getSignature().getDeclaringType();
+ if (declaringTypePattern instanceof AnyTypePattern) {
+ return CALL_WITHOUT_DECLARING_TYPE;
+ } else {
+ return CALL_WITH_DECLARING_TYPE;
+ }
+ } else if ((kind == Shadow.ConstructorExecution) || (kind == Shadow.MethodExecution) || (kind == Shadow.Initialization)
+ || (kind == Shadow.PreInitialization)) {
+ return EXE_INIT_PREINIT;
+ } else if (kind == Shadow.ExceptionHandler) {
+ return HANDLER;
+ } else if ((kind == Shadow.FieldGet) || (kind == Shadow.FieldSet)) {
+ return GET_OR_SET;
+ } else if (kind == Shadow.StaticInitialization) {
+ return STATICINIT;
+ } else {
+ return OTHER;
+ }
+ }
+ if (p instanceof AnnotationPointcut) {
+ return ANNOTATION;
+ }
+ if (p instanceof ArgsPointcut) {
+ return ARGS;
+ }
+ if (p instanceof ArgsAnnotationPointcut) {
+ return AT_ARGS;
+ }
+ if (p instanceof CflowPointcut || p instanceof ConcreteCflowPointcut) {
+ return CFLOW;
+ }
+ if (p instanceof HandlerPointcut) {
+ return HANDLER;
+ }
+ if (p instanceof IfPointcut) {
+ return IF;
+ }
+ if (p instanceof ThisOrTargetPointcut) {
+ return THIS_OR_TARGET;
+ }
+ if (p instanceof ThisOrTargetAnnotationPointcut) {
+ return AT_THIS_OR_TARGET;
+ }
+ if (p instanceof WithincodePointcut) {
+ return WITHINCODE;
+ }
+ if (p instanceof WithinCodeAnnotationPointcut) {
+ return ATWITHINCODE;
+ }
+ if (p instanceof NotPointcut) {
+ return getScore(((NotPointcut) p).getNegatedPointcut());
+ }
+ if (p instanceof AndPointcut) {
+ int leftScore = getScore(((AndPointcut) p).getLeft());
+ int rightScore = getScore(((AndPointcut) p).getRight());
+ if (leftScore < rightScore) {
+ return leftScore;
+ } else {
+ return rightScore;
+ }
+ }
+ if (p instanceof OrPointcut) {
+ int leftScore = getScore(((OrPointcut) p).getLeft());
+ int rightScore = getScore(((OrPointcut) p).getRight());
+ if (leftScore > rightScore) {
+ return leftScore;
+ } else {
+ return rightScore;
+ }
+ }
+ return OTHER;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutRewriter.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutRewriter.java
new file mode 100644
index 000000000..81ff33bab
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/PointcutRewriter.java
@@ -0,0 +1,443 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.patterns.Pointcut.MatchesNothingPointcut;
+
+/**
+ * Performs term rewriting for pointcut expressions.
+ *
+ * @author colyer
+ * @author clement
+ */
+public class PointcutRewriter {
+
+ private static final boolean WATCH_PROGRESS = false;
+
+ /**
+ * Set forcerewrite if you want to override the checking for something already in DNF (useful for some testing) Repeated
+ * processing of something already in DNF is expensive (it ends up being done for every pointcut on every incremental compile) -
+ * so let's not do it if we don't have to. See pr113257
+ */
+ public Pointcut rewrite(Pointcut pc, boolean forceRewrite) {
+ Pointcut result = pc;// checkPC(result);
+ if (forceRewrite || !isDNF(pc)) {
+ if (WATCH_PROGRESS) {
+ System.out.println("Initial pointcut is ==> " + format(pc));
+ }
+ result = distributeNot(result);// checkPC(result);
+ if (WATCH_PROGRESS) {
+ System.out.println("Distributing NOT gives ==> " + format(result));
+ }
+ result = pullUpDisjunctions(result);// checkPC(result);
+ if (WATCH_PROGRESS) {
+ System.out.println("Pull up disjunctions gives ==> " + format(result));
+ }
+ } else {
+ if (WATCH_PROGRESS) {
+ System.out.println("Not distributing NOTs or pulling up disjunctions, already DNF ==> " + format(pc));
+ }
+ }
+ result = simplifyAnds(result); // checkPC(result);
+ if (WATCH_PROGRESS) {
+ System.out.println("Simplifying ANDs gives ==> " + format(result));
+ }
+ result = removeNothings(result); // checkPC(result);
+ if (WATCH_PROGRESS) {
+ System.out.println("Removing nothings gives ==> " + format(result));
+ }
+ result = sortOrs(result); // checkPC(result);
+ if (WATCH_PROGRESS) {
+ System.out.println("Sorting ORs gives ==> " + format(result));
+ }
+ return result;
+ }
+
+ // /**
+ // * Checks pointcuts - used for debugging.
+ // * - this variant checks if the context has been lost, since
+ // * that can indicate an NPE will happen later reporting a message (pr162657).
+ // * Not finished, but helped locate the problem ;)
+ // */
+ // private void checkPC(Pointcut pc) {
+ // if (isNot(pc)) {
+ // NotPointcut npc = (NotPointcut)pc;
+ // checkPC(npc.getNegatedPointcut());
+ // if (npc.getSourceContext()==null) {
+ // System.out.println("Lost context for "+npc);
+ // throw new RuntimeException("Lost context");
+ // }
+ // } else if (isOr(pc)) {
+ // OrPointcut opc = (OrPointcut)pc;
+ // checkPC(opc.getLeft());
+ // checkPC(opc.getRight());
+ // if (opc.getSourceContext()==null) {
+ // System.out.println("Lost context for "+opc);
+ // throw new RuntimeException("Lost context");
+ // }
+ // } else if (isAnd(pc)) {
+ // AndPointcut apc = (AndPointcut)pc;
+ // checkPC(apc.getLeft());
+ // checkPC(apc.getRight());
+ // if (apc.getSourceContext()==null) {
+ // System.out.println("Lost context for "+apc);
+ // throw new RuntimeException("Lost context");
+ // }
+ // } else {
+ // if (pc.getSourceContext()==null) {
+ // System.out.println("Lost context for "+pc);
+ // throw new RuntimeException("Lost context");
+ // }
+ // }
+ // }
+
+ public Pointcut rewrite(Pointcut pc) {
+ return rewrite(pc, false);
+ }
+
+ /**
+ * Check if a pointcut is in DNF - if it is then it should be lots of 'ORs' up the top with 'ANDs' beneath them.
+ */
+ private boolean isDNF(Pointcut pc) {
+ return isDNFHelper(pc, true);
+ }
+
+ /**
+ * Helper function for determining DNFness. Records when we have crossed the point of allowing ORs.
+ */
+ private boolean isDNFHelper(Pointcut pc, boolean canStillHaveOrs) {
+ if (isAnd(pc)) {
+ AndPointcut ap = (AndPointcut) pc;
+ return isDNFHelper(ap.getLeft(), false) && isDNFHelper(ap.getRight(), false);
+ } else if (isOr(pc)) {
+ if (!canStillHaveOrs) {
+ return false;
+ }
+ OrPointcut op = (OrPointcut) pc;
+ return isDNFHelper(op.getLeft(), true) && isDNFHelper(op.getRight(), true);
+ } else if (isNot(pc)) {
+ return isDNFHelper(((NotPointcut) pc).getNegatedPointcut(), canStillHaveOrs);
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Allows formatting of the output pointcut for debugging...
+ */
+ public static String format(Pointcut p) {
+ String s = p.toString();
+ // Regex param needs '(' and '*' changing to '.'
+ // s = s.replaceAll("persingleton.pkg1.monitoring.ErrorMonitoring.","M");
+ // s = s.replaceAll("args.BindingTypePattern.java.lang.Throwable, 0.","Z");
+ // s = s.replaceAll("within.pkg1.monitoring.DoMonitorErrors+.","X");
+ // s=s.replaceAll("within.pkg1.monitoring....","Y");
+ // s=s.replaceAll("if.true.","N");
+ return s;
+ }
+
+ // !!X => X
+ // !(X && Y) => !X || !Y
+ // !(X || Y) => !X && !Y
+ private Pointcut distributeNot(Pointcut pc) {
+ if (isNot(pc)) {
+ NotPointcut npc = (NotPointcut) pc;
+ Pointcut notBody = distributeNot(npc.getNegatedPointcut());
+ if (isNot(notBody)) {
+ // !!X => X
+ return ((NotPointcut) notBody).getNegatedPointcut();
+ } else if (isAnd(notBody)) {
+ // !(X && Y) => !X || !Y
+ AndPointcut apc = (AndPointcut) notBody;
+ Pointcut newLeft = distributeNot(new NotPointcut(apc.getLeft(), npc.getStart()));
+ Pointcut newRight = distributeNot(new NotPointcut(apc.getRight(), npc.getStart()));
+ return new OrPointcut(newLeft, newRight);
+ } else if (isOr(notBody)) {
+ // !(X || Y) => !X && !Y
+ OrPointcut opc = (OrPointcut) notBody;
+ Pointcut newLeft = distributeNot(new NotPointcut(opc.getLeft(), npc.getStart()));
+ Pointcut newRight = distributeNot(new NotPointcut(opc.getRight(), npc.getStart()));
+ return new AndPointcut(newLeft, newRight);
+ } else {
+ return new NotPointcut(notBody, npc.getStart());
+ }
+ } else if (isAnd(pc)) {
+ AndPointcut apc = (AndPointcut) pc;
+ Pointcut left = distributeNot(apc.getLeft());
+ Pointcut right = distributeNot(apc.getRight());
+ return new AndPointcut(left, right);
+ } else if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ Pointcut left = distributeNot(opc.getLeft());
+ Pointcut right = distributeNot(opc.getRight());
+ return new OrPointcut(left, right);
+ } else {
+ return pc;
+ }
+ }
+
+ // A && (B || C) => (A && B) || (A && C)
+ // (A || B) && C => (A && C) || (B && C)
+ private Pointcut pullUpDisjunctions(Pointcut pc) {
+ if (isNot(pc)) {
+ NotPointcut npc = (NotPointcut) pc;
+ return new NotPointcut(pullUpDisjunctions(npc.getNegatedPointcut()));
+ } else if (isAnd(pc)) {
+ AndPointcut apc = (AndPointcut) pc;
+ // dive into left and right here...
+ Pointcut left = pullUpDisjunctions(apc.getLeft());
+ Pointcut right = pullUpDisjunctions(apc.getRight());
+ if (isOr(left) && !isOr(right)) {
+ // (A || B) && C => (A && C) || (B && C)
+ Pointcut leftLeft = ((OrPointcut) left).getLeft();
+ Pointcut leftRight = ((OrPointcut) left).getRight();
+ return pullUpDisjunctions(new OrPointcut(new AndPointcut(leftLeft, right), new AndPointcut(leftRight, right)));
+ } else if (isOr(right) && !isOr(left)) {
+ // A && (B || C) => (A && B) || (A && C)
+ Pointcut rightLeft = ((OrPointcut) right).getLeft();
+ Pointcut rightRight = ((OrPointcut) right).getRight();
+ return pullUpDisjunctions(new OrPointcut(new AndPointcut(left, rightLeft), new AndPointcut(left, rightRight)));
+ } else if (isOr(right) && isOr(left)) {
+ // (A || B) && (C || D) => (A && C) || (A && D) || (B && C) || (B && D)
+ Pointcut A = pullUpDisjunctions(((OrPointcut) left).getLeft());
+ Pointcut B = pullUpDisjunctions(((OrPointcut) left).getRight());
+ Pointcut C = pullUpDisjunctions(((OrPointcut) right).getLeft());
+ Pointcut D = pullUpDisjunctions(((OrPointcut) right).getRight());
+ Pointcut newLeft = new OrPointcut(new AndPointcut(A, C), new AndPointcut(A, D));
+ Pointcut newRight = new OrPointcut(new AndPointcut(B, C), new AndPointcut(B, D));
+ return pullUpDisjunctions(new OrPointcut(newLeft, newRight));
+ } else {
+ return new AndPointcut(left, right);
+ }
+ } else if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ return new OrPointcut(pullUpDisjunctions(opc.getLeft()), pullUpDisjunctions(opc.getRight()));
+ } else {
+ return pc;
+ }
+ }
+
+ /**
+ * Returns a NOTted form of the pointcut p - we cope with already NOTted pointcuts.
+ */
+ public Pointcut not(Pointcut p) {
+ if (isNot(p)) {
+ return ((NotPointcut) p).getNegatedPointcut();
+ }
+ return new NotPointcut(p);
+ }
+
+ /**
+ * Passed an array of pointcuts, returns an AND tree with them in.
+ */
+ public Pointcut createAndsFor(Pointcut[] ps) {
+ if (ps.length == 1) {
+ return ps[0]; // dumb case
+ }
+ if (ps.length == 2) { // recursion exit case
+ return new AndPointcut(ps[0], ps[1]);
+ }
+ // otherwise ...
+ Pointcut[] subset = new Pointcut[ps.length - 1];
+ for (int i = 1; i < ps.length; i++) {
+ subset[i - 1] = ps[i];
+ }
+ return new AndPointcut(ps[0], createAndsFor(subset));
+ }
+
+ // NOT: execution(* TP.*(..)) => within(TP) && execution(* *(..))
+ // since this breaks when the pattern matches an interface
+ // NOT: withincode(* TP.*(..)) => within(TP) && withincode(* *(..))
+ // since this is not correct when an aspect makes an ITD
+ // private Pointcut splitOutWithins(Pointcut pc) {
+ // if (isExecution(pc)) {
+ // KindedPointcut kpc = (KindedPointcut) pc;
+ // SignaturePattern sp = kpc.signature;
+ // TypePattern within = sp.getDeclaringType();
+ // if (isAnyType(within)) return pc;
+ // SignaturePattern simplified = removeDeclaringTypePattern(sp);
+ // return new AndPointcut(new WithinPointcut(within),
+ // new KindedPointcut(kpc.kind,simplified));
+ // } else if (isNot(pc)) {
+ // return new NotPointcut(splitOutWithins(((NotPointcut)pc).getNegatedPointcut()));
+ // } else if (isAnd(pc)) {
+ // AndPointcut apc = (AndPointcut) pc;
+ // return new AndPointcut(splitOutWithins(apc.getLeft()),
+ // splitOutWithins(apc.getRight()));
+ // } else if (isOr(pc)) {
+ // OrPointcut opc = (OrPointcut) pc;
+ // return new OrPointcut(splitOutWithins(opc.getLeft()),
+ // splitOutWithins(opc.getRight()));
+ // } else {
+ // return pc;
+ // }
+ // }
+
+ // private SignaturePattern removeDeclaringTypePattern(SignaturePattern sp) {
+ // return new SignaturePattern(
+ // sp.getKind(),
+ // sp.getModifiers(),
+ // sp.getReturnType(),
+ // TypePattern.ANY,
+ // sp.getName(),
+ // sp.getParameterTypes(),
+ // sp.getThrowsPattern(),
+ // sp.getAnnotationPattern()
+ // );
+ // }
+
+ // this finds the root of each && tree and then aggregates all of the branches
+ // into a sorted set:
+ // - duplicates are removed
+ // - A && !A is replaced by a matchesNothingPointcut
+ // - the kind(s) matched by the set are evaluated
+ // - elements are sorted by evaluation complexity
+ // - the result is written out with the least expensive branch leftmost
+ private Pointcut simplifyAnds(Pointcut pc) {
+ if (isNot(pc)) {
+ NotPointcut npc = (NotPointcut) pc;
+ Pointcut notBody = npc.getNegatedPointcut();
+ if (isNot(notBody)) {
+ // !!X => X
+ return simplifyAnds(((NotPointcut) notBody).getNegatedPointcut());
+ } else {
+ return new NotPointcut(simplifyAnds(npc.getNegatedPointcut()));
+ }
+ } else if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ return new OrPointcut(simplifyAnds(opc.getLeft()), simplifyAnds(opc.getRight()));
+ } else if (isAnd(pc)) {
+ return simplifyAnd((AndPointcut) pc);
+ } else {
+ return pc;
+ }
+ }
+
+ private Pointcut simplifyAnd(AndPointcut apc) {
+ SortedSet<Pointcut> nodes = new TreeSet<Pointcut>(new PointcutEvaluationExpenseComparator());
+ collectAndNodes(apc, nodes);
+ // look for A and !A, or IfFalse
+ for (Iterator<Pointcut> iter = nodes.iterator(); iter.hasNext();) {
+ Pointcut element = iter.next();
+ if (element instanceof NotPointcut) {
+ Pointcut body = ((NotPointcut) element).getNegatedPointcut();
+ if (nodes.contains(body)) {
+ return Pointcut.makeMatchesNothing(body.state);
+ }
+ }
+ if (element instanceof IfPointcut) {
+ if (((IfPointcut) element).alwaysFalse()) {
+ return Pointcut.makeMatchesNothing(element.state);
+ }
+ }
+ // If it can't match anything, the whole AND can't match anything
+ if (element.couldMatchKinds() == Shadow.NO_SHADOW_KINDS_BITS) {
+ return element;
+ }
+ }
+ if (apc.couldMatchKinds() == Shadow.NO_SHADOW_KINDS_BITS) {
+ return Pointcut.makeMatchesNothing(apc.state);
+ }
+ // write out with cheapest on left
+ Iterator<Pointcut> iter = nodes.iterator();
+ Pointcut result = iter.next();
+ while (iter.hasNext()) {
+ Pointcut right = iter.next();
+ result = new AndPointcut(result, right);
+ }
+ return result;
+ }
+
+ private Pointcut sortOrs(Pointcut pc) {
+ SortedSet<Pointcut> nodes = new TreeSet<Pointcut>(new PointcutEvaluationExpenseComparator());
+ collectOrNodes(pc, nodes);
+ // write out with cheapest on left
+ Iterator<Pointcut> iter = nodes.iterator();
+ Pointcut result = iter.next();
+ while (iter.hasNext()) {
+ Pointcut right = iter.next();
+ result = new OrPointcut(result, right);
+ }
+ return result;
+ }
+
+ /**
+ * Removes MATCHES_NOTHING pointcuts
+ */
+ private Pointcut removeNothings(Pointcut pc) {
+ if (isAnd(pc)) {
+ AndPointcut apc = (AndPointcut) pc;
+ Pointcut right = removeNothings(apc.getRight());
+ Pointcut left = removeNothings(apc.getLeft());
+ if (left instanceof MatchesNothingPointcut || right instanceof MatchesNothingPointcut) {
+ return new MatchesNothingPointcut();
+ }
+ return new AndPointcut(left, right);
+ } else if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ Pointcut right = removeNothings(opc.getRight());
+ Pointcut left = removeNothings(opc.getLeft());
+ if (left instanceof MatchesNothingPointcut && !(right instanceof MatchesNothingPointcut)) {
+ return right;
+ } else if (right instanceof MatchesNothingPointcut && !(left instanceof MatchesNothingPointcut)) {
+ return left;
+ } else if (!(left instanceof MatchesNothingPointcut) && !(right instanceof MatchesNothingPointcut)) {
+ return new OrPointcut(left, right);
+ } else if (left instanceof MatchesNothingPointcut && right instanceof MatchesNothingPointcut) {
+ return new MatchesNothingPointcut();
+ }
+ }
+ return pc;
+ }
+
+ private void collectAndNodes(AndPointcut apc, Set<Pointcut> nodesSoFar) {
+ Pointcut left = apc.getLeft();
+ Pointcut right = apc.getRight();
+ if (isAnd(left)) {
+ collectAndNodes((AndPointcut) left, nodesSoFar);
+ } else {
+ nodesSoFar.add(left);
+ }
+ if (isAnd(right)) {
+ collectAndNodes((AndPointcut) right, nodesSoFar);
+ } else {
+ nodesSoFar.add(right);
+ }
+ }
+
+ private void collectOrNodes(Pointcut pc, Set<Pointcut> nodesSoFar) {
+ if (isOr(pc)) {
+ OrPointcut opc = (OrPointcut) pc;
+ collectOrNodes(opc.getLeft(), nodesSoFar);
+ collectOrNodes(opc.getRight(), nodesSoFar);
+ } else {
+ nodesSoFar.add(pc);
+ }
+ }
+
+ private boolean isNot(Pointcut pc) {
+ return (pc instanceof NotPointcut);
+ }
+
+ private boolean isAnd(Pointcut pc) {
+ return (pc instanceof AndPointcut);
+ }
+
+ private boolean isOr(Pointcut pc) {
+ return (pc instanceof OrPointcut);
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ReferencePointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ReferencePointcut.java
new file mode 100644
index 000000000..6e74a1a2f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ReferencePointcut.java
@@ -0,0 +1,414 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedPointcutDefinition;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.TypeVariable;
+import org.aspectj.weaver.TypeVariableReference;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Test;
+
+/**
+ */
+// XXX needs check that arguments contains no WildTypePatterns
+public class ReferencePointcut extends Pointcut {
+ public UnresolvedType onType;
+ public TypePattern onTypeSymbolic;
+ public String name;
+ public TypePatternList arguments;
+
+ /**
+ * if this is non-null then when the pointcut is concretized the result will be parameterized too.
+ */
+ private Map<String, UnresolvedType> typeVariableMap;
+
+ // public ResolvedPointcut binding;
+
+ public ReferencePointcut(TypePattern onTypeSymbolic, String name, TypePatternList arguments) {
+ this.onTypeSymbolic = onTypeSymbolic;
+ this.name = name;
+ this.arguments = arguments;
+ this.pointcutKind = REFERENCE;
+ }
+
+ public ReferencePointcut(UnresolvedType onType, String name, TypePatternList arguments) {
+ this.onType = onType;
+ this.name = name;
+ this.arguments = arguments;
+ this.pointcutKind = REFERENCE;
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ // ??? do either of these match methods make any sense???
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ /**
+ * Do I really match this shadow?
+ */
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ return FuzzyBoolean.NO;
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ if (onType != null) {
+ buf.append(onType);
+ buf.append(".");
+ // for (int i=0, len=fromType.length; i < len; i++) {
+ // buf.append(fromType[i]);
+ // buf.append(".");
+ // }
+ }
+ buf.append(name);
+ buf.append(arguments.toString());
+ return buf.toString();
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ // XXX ignores onType
+ s.writeByte(Pointcut.REFERENCE);
+ if (onType != null) {
+ s.writeBoolean(true);
+ onType.write(s);
+ } else {
+ s.writeBoolean(false);
+ }
+
+ s.writeUTF(name);
+ arguments.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ UnresolvedType onType = null;
+ if (s.readBoolean()) {
+ onType = UnresolvedType.read(s);
+ }
+ ReferencePointcut ret = new ReferencePointcut(onType, s.readUTF(), TypePatternList.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ if (onTypeSymbolic != null) {
+ onType = onTypeSymbolic.resolveExactType(scope, bindings);
+ // in this case we've already signaled an error
+ if (ResolvedType.isMissing(onType)) {
+ return;
+ }
+ }
+
+ ResolvedType searchType;
+ if (onType != null) {
+ searchType = scope.getWorld().resolve(onType);
+ } else {
+ searchType = scope.getEnclosingType();
+ }
+ if (searchType.isTypeVariableReference()) {
+ searchType = ((TypeVariableReference) searchType).getTypeVariable().getFirstBound().resolve(scope.getWorld());
+ }
+
+ arguments.resolveBindings(scope, bindings, true, true);
+ // XXX ensure that arguments has no ..'s in it
+
+ // check that I refer to a real pointcut declaration and that I match
+
+ ResolvedPointcutDefinition pointcutDef = searchType.findPointcut(name);
+ // if we're not a static reference, then do a lookup of outers
+ if (pointcutDef == null && onType == null) {
+ while (true) {
+ UnresolvedType declaringType = searchType.getDeclaringType();
+ if (declaringType == null) {
+ break;
+ }
+ searchType = declaringType.resolve(scope.getWorld());
+ pointcutDef = searchType.findPointcut(name);
+ if (pointcutDef != null) {
+ // make this a static reference
+ onType = searchType;
+ break;
+ }
+ }
+ }
+
+ if (pointcutDef == null) {
+ scope.message(IMessage.ERROR, this, "can't find referenced pointcut " + name);
+ return;
+ }
+
+ // check visibility
+ if (!pointcutDef.isVisible(scope.getEnclosingType())) {
+ scope.message(IMessage.ERROR, this, "pointcut declaration " + pointcutDef + " is not accessible");
+ return;
+ }
+
+ if (Modifier.isAbstract(pointcutDef.getModifiers())) {
+ if (onType != null && !onType.isTypeVariableReference()) {
+ scope.message(IMessage.ERROR, this, "can't make static reference to abstract pointcut");
+ return;
+ } else if (!searchType.isAbstract()) {
+ scope.message(IMessage.ERROR, this, "can't use abstract pointcut in concrete context");
+ return;
+ }
+ }
+
+ ResolvedType[] parameterTypes = scope.getWorld().resolve(pointcutDef.getParameterTypes());
+
+ if (parameterTypes.length != arguments.size()) {
+ scope.message(IMessage.ERROR, this, "incompatible number of arguments to pointcut, expected " + parameterTypes.length
+ + " found " + arguments.size());
+ return;
+ }
+
+ // if (onType == null) onType = pointcutDef.getDeclaringType();
+ if (onType != null) {
+ if (onType.isParameterizedType()) {
+ // build a type map mapping type variable names in the generic type to
+ // the type parameters presented
+ typeVariableMap = new HashMap<String, UnresolvedType>();
+ ResolvedType underlyingGenericType = ((ResolvedType) onType).getGenericType();
+ TypeVariable[] tVars = underlyingGenericType.getTypeVariables();
+ ResolvedType[] typeParams = ((ResolvedType) onType).getResolvedTypeParameters();
+ for (int i = 0; i < tVars.length; i++) {
+ typeVariableMap.put(tVars[i].getName(), typeParams[i]);
+ }
+ } else if (onType.isGenericType()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_REFERENCE_POINTCUT_IN_RAW_TYPE),
+ getSourceLocation()));
+ }
+ }
+
+ for (int i = 0, len = arguments.size(); i < len; i++) {
+ TypePattern p = arguments.get(i);
+ // we are allowed to bind to pointcuts which use subtypes as this is type safe
+ if (typeVariableMap != null) {
+ p = p.parameterizeWith(typeVariableMap, scope.getWorld());
+ }
+ if (p == TypePattern.NO) {
+ scope.message(IMessage.ERROR, this, "bad parameter to pointcut reference");
+ return;
+ }
+
+ boolean reportProblem = false;
+ if (parameterTypes[i].isTypeVariableReference() && p.getExactType().isTypeVariableReference()) {
+ UnresolvedType One = ((TypeVariableReference) parameterTypes[i]).getTypeVariable().getFirstBound();
+ UnresolvedType Two = ((TypeVariableReference) p.getExactType()).getTypeVariable().getFirstBound();
+ reportProblem = !One.resolve(scope.getWorld()).isAssignableFrom(Two.resolve(scope.getWorld()));
+ } else {
+ reportProblem = !p.matchesSubtypes(parameterTypes[i]) && !p.getExactType().equals(UnresolvedType.OBJECT);
+ }
+ if (reportProblem) {
+ scope.message(IMessage.ERROR, this, "incompatible type, expected " + parameterTypes[i].getName() + " found " + p
+ + ". Check the type specified in your pointcut");
+ return;
+ }
+ }
+
+ }
+
+ public void postRead(ResolvedType enclosingType) {
+ arguments.postRead(enclosingType);
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ throw new RuntimeException("shouldn't happen");
+ }
+
+ // ??? This is not thread safe, but this class is not designed for multi-threading
+ private boolean concretizing = false;
+
+ // declaring type is the type that declared the member referencing this pointcut.
+ // If it declares a matching private pointcut, then that pointcut should be used
+ // and not one in a subtype that happens to have the same name.
+ public Pointcut concretize1(ResolvedType searchStart, ResolvedType declaringType, IntMap bindings) {
+ if (concretizing) {
+ // Thread.currentThread().dumpStack();
+ searchStart
+ .getWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.CIRCULAR_POINTCUT, this), getSourceLocation()));
+ Pointcut p = Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ p.sourceContext = sourceContext;
+ return p;
+ }
+
+ try {
+ concretizing = true;
+
+ ResolvedPointcutDefinition pointcutDec;
+ if (onType != null) {
+ searchStart = onType.resolve(searchStart.getWorld());
+ if (searchStart.isMissing()) {
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+
+ if (onType.isTypeVariableReference()) {
+ // need to replace on type with the binding for the type variable
+ // in the declaring type
+ if (declaringType.isParameterizedType()) {
+ TypeVariable[] tvs = declaringType.getGenericType().getTypeVariables();
+ String typeVariableName = ((TypeVariableReference) onType).getTypeVariable().getName();
+ for (int i = 0; i < tvs.length; i++) {
+ if (tvs[i].getName().equals(typeVariableName)) {
+ ResolvedType realOnType = declaringType.getTypeParameters()[i].resolve(declaringType.getWorld());
+ onType = realOnType;
+ searchStart = realOnType;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ if (declaringType == null) {
+ declaringType = searchStart;
+ }
+ pointcutDec = declaringType.findPointcut(name);
+ boolean foundMatchingPointcut = (pointcutDec != null && Modifier.isPrivate(pointcutDec.getModifiers()));
+ if (!foundMatchingPointcut) {
+ pointcutDec = searchStart.findPointcut(name);
+ if (pointcutDec == null) {
+ searchStart
+ .getWorld()
+ .getMessageHandler()
+ .handleMessage(
+ MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.CANT_FIND_POINTCUT, name, searchStart.getName()),
+ getSourceLocation()));
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+ }
+
+ if (pointcutDec.isAbstract()) {
+ // Thread.currentThread().dumpStack();
+ ShadowMunger enclosingAdvice = bindings.getEnclosingAdvice();
+ searchStart.getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.ABSTRACT_POINTCUT, pointcutDec), getSourceLocation(),
+ (null == enclosingAdvice) ? null : enclosingAdvice.getSourceLocation());
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+
+ // System.err.println("start: " + searchStart);
+ // ResolvedType[] parameterTypes = searchStart.getWorld().resolve(pointcutDec.getParameterTypes());
+
+ TypePatternList arguments = this.arguments.resolveReferences(bindings);
+
+ IntMap newBindings = new IntMap();
+ for (int i = 0, len = arguments.size(); i < len; i++) {
+ TypePattern p = arguments.get(i);
+ if (p == TypePattern.NO) {
+ continue;
+ }
+ // we are allowed to bind to pointcuts which use subtypes as this is type safe
+ // this will be checked in ReferencePointcut.resolveBindings(). Can't check it here
+ // as we don't know about any new parents added via decp.
+ if (p instanceof BindingTypePattern) {
+ newBindings.put(i, ((BindingTypePattern) p).getFormalIndex());
+ }
+ }
+
+ if (searchStart.isParameterizedType()) {
+ // build a type map mapping type variable names in the generic type to
+ // the type parameters presented
+ typeVariableMap = new HashMap<String, UnresolvedType>();
+ ResolvedType underlyingGenericType = searchStart.getGenericType();
+ TypeVariable[] tVars = underlyingGenericType.getTypeVariables();
+ ResolvedType[] typeParams = searchStart.getResolvedTypeParameters();
+ for (int i = 0; i < tVars.length; i++) {
+ typeVariableMap.put(tVars[i].getName(), typeParams[i]);
+ }
+ }
+
+ newBindings.copyContext(bindings);
+ newBindings.pushEnclosingDefinition(pointcutDec);
+ try {
+ Pointcut ret = pointcutDec.getPointcut();
+ if (typeVariableMap != null && !hasBeenParameterized) {
+ ret = ret.parameterizeWith(typeVariableMap, searchStart.getWorld());
+ ret.hasBeenParameterized = true;
+ }
+ return ret.concretize(searchStart, declaringType, newBindings);
+ } finally {
+ newBindings.popEnclosingDefinitition();
+ }
+
+ } finally {
+ concretizing = false;
+ }
+ }
+
+ /**
+ * make a version of this pointcut with any refs to typeVariables replaced by their entry in the map. Tricky thing is, we can't
+ * do this at the point in time this method will be called, so we make a version that will parameterize the pointcut it
+ * ultimately resolves to.
+ */
+ public Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
+ ReferencePointcut ret = new ReferencePointcut(onType, name, arguments);
+ ret.onTypeSymbolic = onTypeSymbolic;
+ ret.typeVariableMap = typeVariableMap;
+ return ret;
+ }
+
+ // We want to keep the original source location, not the reference location
+ protected boolean shouldCopyLocationForConcretize() {
+ return false;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof ReferencePointcut)) {
+ return false;
+ }
+ if (this == other) {
+ return true;
+ }
+ ReferencePointcut o = (ReferencePointcut) other;
+ return o.name.equals(name) && o.arguments.equals(arguments)
+ && ((o.onType == null) ? (onType == null) : o.onType.equals(onType));
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + ((onType == null) ? 0 : onType.hashCode());
+ result = 37 * result + arguments.hashCode();
+ result = 37 * result + name.hashCode();
+ return result;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ScopeWithTypeVariables.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ScopeWithTypeVariables.java
new file mode 100644
index 000000000..537fb2c22
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ScopeWithTypeVariables.java
@@ -0,0 +1,130 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.IMessage.Kind;
+import org.aspectj.weaver.IHasPosition;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeVariable;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.UnresolvedTypeVariableReferenceType;
+import org.aspectj.weaver.World;
+
+/**
+ * A scope that also considers type variables when looking up a type.
+ *
+ */
+public class ScopeWithTypeVariables implements IScope {
+
+ private IScope delegateScope;
+ private String[] typeVariableNames;
+ private UnresolvedTypeVariableReferenceType[] typeVarTypeXs;
+
+ public ScopeWithTypeVariables(String[] typeVarNames, IScope delegate) {
+ this.delegateScope = delegate;
+ this.typeVariableNames = typeVarNames;
+ this.typeVarTypeXs = new UnresolvedTypeVariableReferenceType[typeVarNames.length];
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#lookupType(java.lang.String, org.aspectj.weaver.IHasPosition)
+ */
+ public UnresolvedType lookupType(String name, IHasPosition location) {
+ for (int i = 0; i < typeVariableNames.length; i++) {
+ if (typeVariableNames[i].equals(name)) {
+ if (typeVarTypeXs[i] == null) {
+ typeVarTypeXs[i] = new UnresolvedTypeVariableReferenceType(new TypeVariable(name));
+ }
+ return typeVarTypeXs[i];
+ }
+ }
+ return delegateScope.lookupType(name, location);
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#getWorld()
+ */
+ public World getWorld() {
+ return delegateScope.getWorld();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#getEnclosingType()
+ */
+ public ResolvedType getEnclosingType() {
+ return delegateScope.getEnclosingType();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#getMessageHandler()
+ */
+ public IMessageHandler getMessageHandler() {
+ return delegateScope.getMessageHandler();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#lookupFormal(java.lang.String)
+ */
+ public FormalBinding lookupFormal(String name) {
+ return delegateScope.lookupFormal(name);
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#getFormal(int)
+ */
+ public FormalBinding getFormal(int i) {
+ return delegateScope.getFormal(i);
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#getFormalCount()
+ */
+ public int getFormalCount() {
+ return delegateScope.getFormalCount();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#getImportedPrefixes()
+ */
+ public String[] getImportedPrefixes() {
+ return delegateScope.getImportedPrefixes();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#getImportedNames()
+ */
+ public String[] getImportedNames() {
+ return delegateScope.getImportedNames();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#message(org.aspectj.bridge.IMessage.Kind, org.aspectj.weaver.IHasPosition, java.lang.String)
+ */
+ public void message(Kind kind, IHasPosition location, String message) {
+ delegateScope.message(kind, location, message);
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.patterns.IScope#message(org.aspectj.bridge.IMessage.Kind, org.aspectj.weaver.IHasPosition, org.aspectj.weaver.IHasPosition, java.lang.String)
+ */
+ public void message(Kind kind, IHasPosition location1,
+ IHasPosition location2, String message) {
+ delegateScope.message(kind,location1,location2,message);
+ }
+
+ public void message(IMessage aMessage) {
+ delegateScope.message(aMessage);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SignaturePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SignaturePattern.java
new file mode 100644
index 000000000..365b5b7a7
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SignaturePattern.java
@@ -0,0 +1,1009 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjAttribute;
+import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.AnnotationTargetKind;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ConcreteTypeMunger;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.JoinPointSignature;
+import org.aspectj.weaver.JoinPointSignatureIterator;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.MemberKind;
+import org.aspectj.weaver.NewFieldTypeMunger;
+import org.aspectj.weaver.ResolvableTypeList;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public class SignaturePattern extends PatternNode implements ISignaturePattern {
+ private MemberKind kind;
+ private ModifiersPattern modifiers;
+ private TypePattern returnType;
+ private TypePattern declaringType;
+ private NamePattern name;
+ private TypePatternList parameterTypes;
+ private int bits = 0x0000;
+ private static final int PARAMETER_ANNOTATION_MATCHING = 0x0001;
+ private static final int CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING = 0x0002;
+
+ private ThrowsPattern throwsPattern;
+ private AnnotationTypePattern annotationPattern;
+ private transient int hashcode = -1;
+
+ private transient boolean isExactDeclaringTypePattern = false;
+
+ public SignaturePattern(MemberKind kind, ModifiersPattern modifiers, TypePattern returnType, TypePattern declaringType,
+ NamePattern name, TypePatternList parameterTypes, ThrowsPattern throwsPattern, AnnotationTypePattern annotationPattern) {
+ this.kind = kind;
+ this.modifiers = modifiers;
+ this.returnType = returnType;
+ this.name = name;
+ this.declaringType = declaringType;
+ this.parameterTypes = parameterTypes;
+ this.throwsPattern = throwsPattern;
+ this.annotationPattern = annotationPattern;
+ this.isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
+ }
+
+ @Override
+ public SignaturePattern resolveBindings(IScope scope, Bindings bindings) {
+ if (returnType != null) {
+ returnType = returnType.resolveBindings(scope, bindings, false, false);
+ checkForIncorrectTargetKind(returnType, scope, false);
+ }
+ if (declaringType != null) {
+ declaringType = declaringType.resolveBindings(scope, bindings, false, false);
+ checkForIncorrectTargetKind(declaringType, scope, false);
+ isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
+ }
+ if (parameterTypes != null) {
+ parameterTypes = parameterTypes.resolveBindings(scope, bindings, false, false);
+ checkForIncorrectTargetKind(parameterTypes, scope, false, true);
+ }
+ if (throwsPattern != null) {
+ throwsPattern = throwsPattern.resolveBindings(scope, bindings);
+ if (throwsPattern.getForbidden().getTypePatterns().length > 0
+ || throwsPattern.getRequired().getTypePatterns().length > 0) {
+ checkForIncorrectTargetKind(throwsPattern, scope, false);
+ }
+ }
+ if (annotationPattern != null) {
+ annotationPattern = annotationPattern.resolveBindings(scope, bindings, false);
+ checkForIncorrectTargetKind(annotationPattern, scope, true);
+ }
+ hashcode = -1;
+ return this;
+ }
+
+ private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed) {
+ checkForIncorrectTargetKind(patternNode, scope, targetsOtherThanTypeAllowed, false);
+
+ }
+
+ // bug 115252 - adding an xlint warning if the annnotation target type is
+ // wrong. This logic, or similar, may have to be applied elsewhere in the case
+ // of pointcuts which don't go through SignaturePattern.resolveBindings(..)
+ private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed,
+ boolean parameterTargettingAnnotationsAllowed) {
+ // return if we're not in java5 mode, if the unmatchedTargetKind Xlint
+ // warning has been turned off, or if the patternNode is *
+ if (!scope.getWorld().isInJava5Mode() || scope.getWorld().getLint().unmatchedTargetKind == null
+ || (patternNode instanceof AnyTypePattern)) {
+ return;
+ }
+ if (patternNode instanceof ExactAnnotationTypePattern) {
+ ResolvedType resolvedType = ((ExactAnnotationTypePattern) patternNode).getAnnotationType().resolve(scope.getWorld());
+ if (targetsOtherThanTypeAllowed) {
+ AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
+ if (targetKinds == null) {
+ return;
+ }
+ reportUnmatchedTargetKindMessage(targetKinds, patternNode, scope, true);
+ } else if (!targetsOtherThanTypeAllowed && !resolvedType.canAnnotationTargetType()) {
+ // everything is incorrect since we've already checked whether we have the TYPE target annotation
+ AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
+ if (targetKinds == null) {
+ return;
+ }
+ reportUnmatchedTargetKindMessage(targetKinds, patternNode, scope, false);
+ }
+ } else {
+ TypePatternVisitor visitor = new TypePatternVisitor(scope, targetsOtherThanTypeAllowed,
+ parameterTargettingAnnotationsAllowed);
+ patternNode.traverse(visitor, null);
+ if (visitor.containedIncorrectTargetKind()) {
+ Set<ExactAnnotationTypePattern> keys = visitor.getIncorrectTargetKinds().keySet();
+ for (Iterator<ExactAnnotationTypePattern> iter = keys.iterator(); iter.hasNext();) {
+ PatternNode node = iter.next();
+ AnnotationTargetKind[] targetKinds = visitor.getIncorrectTargetKinds().get(node);
+ reportUnmatchedTargetKindMessage(targetKinds, node, scope, false);
+ }
+ }
+ }
+ }
+
+ private void reportUnmatchedTargetKindMessage(AnnotationTargetKind[] annotationTargetKinds, PatternNode node, IScope scope,
+ boolean checkMatchesMemberKindName) {
+ StringBuffer targetNames = new StringBuffer("{");
+ for (int i = 0; i < annotationTargetKinds.length; i++) {
+ AnnotationTargetKind targetKind = annotationTargetKinds[i];
+ if (checkMatchesMemberKindName && kind.getName().equals(targetKind.getName())) {
+ return;
+ }
+ if (i < (annotationTargetKinds.length - 1)) {
+ targetNames.append("ElementType." + targetKind.getName() + ",");
+ } else {
+ targetNames.append("ElementType." + targetKind.getName() + "}");
+ }
+ }
+ scope.getWorld().getLint().unmatchedTargetKind.signal(new String[] { node.toString(), targetNames.toString() },
+ getSourceLocation(), new ISourceLocation[0]);
+ }
+
+ /**
+ * Class which visits the nodes in the TypePattern tree until an ExactTypePattern is found. Once this is found it creates a new
+ * ExactAnnotationTypePattern and checks whether the targetKind (created via the @Target annotation) matches ElementType.TYPE if
+ * this is the only target kind which is allowed, or matches the signature pattern kind if there is no restriction.
+ */
+ private class TypePatternVisitor extends AbstractPatternNodeVisitor {
+
+ private IScope scope;
+ private Map<ExactAnnotationTypePattern, AnnotationTargetKind[]> incorrectTargetKinds = new HashMap<ExactAnnotationTypePattern, AnnotationTargetKind[]>();
+ private boolean targetsOtherThanTypeAllowed;
+ private boolean parameterTargettingAnnotationsAllowed;
+
+ /**
+ * @param requiredTarget - the signature pattern Kind
+ * @param scope
+ * @param parameterTargettingAnnotationsAllowed
+ */
+ public TypePatternVisitor(IScope scope, boolean targetsOtherThanTypeAllowed, boolean parameterTargettingAnnotationsAllowed) {
+ this.scope = scope;
+ this.targetsOtherThanTypeAllowed = targetsOtherThanTypeAllowed;
+ this.parameterTargettingAnnotationsAllowed = parameterTargettingAnnotationsAllowed;
+ }
+
+ @Override
+ public Object visit(WildAnnotationTypePattern node, Object data) {
+ node.getTypePattern().accept(this, data);
+ return node;
+ }
+
+ /**
+ * Do the ExactAnnotationTypePatterns have the incorrect target?
+ */
+ @Override
+ public Object visit(ExactAnnotationTypePattern node, Object data) {
+ ResolvedType resolvedType = node.getAnnotationType().resolve(scope.getWorld());
+ if (targetsOtherThanTypeAllowed) {
+ AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
+ if (targetKinds == null) {
+ return data;
+ }
+ List<AnnotationTargetKind> incorrectTargets = new ArrayList<AnnotationTargetKind>();
+ for (int i = 0; i < targetKinds.length; i++) {
+ if (targetKinds[i].getName().equals(kind.getName())
+ || (targetKinds[i].getName().equals("PARAMETER") && node.isForParameterAnnotationMatch())) {
+ return data;
+ }
+ incorrectTargets.add(targetKinds[i]);
+ }
+ if (incorrectTargets.isEmpty()) {
+ return data;
+ }
+ AnnotationTargetKind[] kinds = new AnnotationTargetKind[incorrectTargets.size()];
+ incorrectTargetKinds.put(node, incorrectTargets.toArray(kinds));
+ } else if (!targetsOtherThanTypeAllowed && !resolvedType.canAnnotationTargetType()) {
+ AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
+ if (targetKinds == null) {
+ return data;
+ }
+ // exception here is if parameter annotations are allowed
+ if (parameterTargettingAnnotationsAllowed) {
+ for (int i = 0; i < targetKinds.length; i++) {
+ AnnotationTargetKind annotationTargetKind = targetKinds[i];
+ if (annotationTargetKind.getName().equals("PARAMETER") && node.isForParameterAnnotationMatch()) {
+ return data;
+ }
+ }
+ }
+ incorrectTargetKinds.put(node, targetKinds);
+ }
+ return data;
+ }
+
+ @Override
+ public Object visit(ExactTypePattern node, Object data) {
+ ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(node.getExactType().resolve(scope.getWorld()), null);
+ eatp.accept(this, data);
+ return data;
+ }
+
+ @Override
+ public Object visit(AndTypePattern node, Object data) {
+ node.getLeft().accept(this, data);
+ node.getRight().accept(this, data);
+ return node;
+ }
+
+ @Override
+ public Object visit(OrTypePattern node, Object data) {
+ node.getLeft().accept(this, data);
+ node.getRight().accept(this, data);
+ return node;
+ }
+
+ @Override
+ public Object visit(AnyWithAnnotationTypePattern node, Object data) {
+ node.getAnnotationPattern().accept(this, data);
+ return node;
+ }
+
+ public boolean containedIncorrectTargetKind() {
+ return (incorrectTargetKinds.size() != 0);
+ }
+
+ public Map<ExactAnnotationTypePattern, AnnotationTargetKind[]> getIncorrectTargetKinds() {
+ return incorrectTargetKinds;
+ }
+ }
+
+ public void postRead(ResolvedType enclosingType) {
+ if (returnType != null) {
+ returnType.postRead(enclosingType);
+ }
+ if (declaringType != null) {
+ declaringType.postRead(enclosingType);
+ }
+ if (parameterTypes != null) {
+ parameterTypes.postRead(enclosingType);
+ }
+ }
+
+ /**
+ * return a copy of this signature pattern in which every type variable reference is replaced by the corresponding entry in the
+ * map.
+ */
+ @Override
+ public SignaturePattern parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
+ SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType.parameterizeWith(typeVariableMap, w), declaringType
+ .parameterizeWith(typeVariableMap, w), name, parameterTypes.parameterizeWith(typeVariableMap, w), throwsPattern
+ .parameterizeWith(typeVariableMap, w), annotationPattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public boolean matches(Member joinPointSignature, World world, boolean allowBridgeMethods) {
+ // fail (or succeed!) fast tests...
+ if (joinPointSignature == null) {
+ return false;
+ }
+ if (kind != joinPointSignature.getKind()) {
+ return false;
+ }
+ if (kind == Member.ADVICE) {
+ return true;
+ }
+
+ // do the hard work then...
+ boolean subjectMatch = true;
+ boolean wantsAnnotationMatch = wantToMatchAnnotationPattern();
+ JoinPointSignatureIterator candidateMatches = joinPointSignature.getJoinPointSignatures(world);
+ while (candidateMatches.hasNext()) {
+ JoinPointSignature aSig = candidateMatches.next();
+ // System.out.println(aSig);
+ FuzzyBoolean matchResult = matchesExactly(aSig, world, allowBridgeMethods, subjectMatch);
+ if (matchResult.alwaysTrue()) {
+ return true;
+ } else if (matchResult.alwaysFalse()) {
+ return false;
+ }
+ // if we got a "MAYBE" it's worth looking at the other signatures
+ // The first signature is the subject signature - and against it we must match modifiers/annotations/throws
+ // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
+ subjectMatch = false;
+ // Early exit
+ if (wantsAnnotationMatch) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ // Does this pattern match this exact signature (no declaring type mucking about
+ // or chasing up the hierarchy)
+ // return YES if it does, NO if it doesn't and no ancester member could match either,
+ // and MAYBE if it doesn't but an ancester member could.
+ private FuzzyBoolean matchesExactly(JoinPointSignature aMember, World inAWorld, boolean allowBridgeMethods, boolean subjectMatch) {
+ // Java5 introduces bridge methods, we match a call to them but nothing else...
+ if (aMember.isBridgeMethod() && !allowBridgeMethods) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ // Only the subject is checked for modifiers
+ // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
+ if (subjectMatch && !modifiers.matches(aMember.getModifiers())) {
+ return FuzzyBoolean.NO;
+ }
+
+ FuzzyBoolean matchesIgnoringAnnotations = FuzzyBoolean.YES;
+ if (kind == Member.STATIC_INITIALIZATION) {
+ matchesIgnoringAnnotations = matchesExactlyStaticInitialization(aMember, inAWorld);
+ } else if (kind == Member.FIELD) {
+ matchesIgnoringAnnotations = matchesExactlyField(aMember, inAWorld);
+ } else if (kind == Member.METHOD) {
+ matchesIgnoringAnnotations = matchesExactlyMethod(aMember, inAWorld, subjectMatch);
+ } else if (kind == Member.CONSTRUCTOR) {
+ matchesIgnoringAnnotations = matchesExactlyConstructor(aMember, inAWorld);
+ }
+ if (matchesIgnoringAnnotations.alwaysFalse()) {
+ return FuzzyBoolean.NO;
+ }
+
+ // Only the subject is checked for annotations (239441/119749)
+ // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
+ if (subjectMatch) {
+ // The annotations must match if specified
+ if (!matchesAnnotations(aMember, inAWorld).alwaysTrue()) {
+ return FuzzyBoolean.NO;
+ } else {
+ return matchesIgnoringAnnotations;
+ }
+ } else {
+ // Unless they specified any annotation then it is a failure
+ if (annotationPattern instanceof AnyAnnotationTypePattern) {
+ return matchesIgnoringAnnotations;
+ } else {
+ return FuzzyBoolean.NO;
+ }
+ }
+
+ // if (subjectMatch && !matchesAnnotations(aMember, inAWorld).alwaysTrue()) {
+ // return FuzzyBoolean.NO;
+ // } else {
+ //
+ // return matchesIgnoringAnnotations;
+ // }
+
+ }
+
+ private boolean wantToMatchAnnotationPattern() {
+ return !(annotationPattern instanceof AnyAnnotationTypePattern);
+ }
+
+ /**
+ * Matches on declaring type
+ */
+ private FuzzyBoolean matchesExactlyStaticInitialization(JoinPointSignature aMember, World world) {
+ return FuzzyBoolean.fromBoolean(declaringType.matchesStatically(aMember.getDeclaringType().resolve(world)));
+ }
+
+ /**
+ * Matches on name, declaring type, field type
+ */
+ private FuzzyBoolean matchesExactlyField(JoinPointSignature aField, World world) {
+ if (!name.matches(aField.getName())) {
+ return FuzzyBoolean.NO;
+ }
+ ResolvedType fieldDeclaringType = aField.getDeclaringType().resolve(world);
+ if (!declaringType.matchesStatically(fieldDeclaringType)) {
+ return FuzzyBoolean.MAYBE;
+ }
+ if (!returnType.matchesStatically(aField.getReturnType().resolve(world))) {
+ // looking bad, but there might be parameterization to consider...
+ if (!returnType.matchesStatically(aField.getGenericReturnType().resolve(world))) {
+ // ok, it's bad.
+ return FuzzyBoolean.MAYBE;
+ }
+ }
+ // passed all the guards...
+ return FuzzyBoolean.YES;
+ }
+
+ /**
+ * Quickly detect if the joinpoint absolutely cannot match becaused the method parameters at the joinpoint cannot match against
+ * this signature pattern.
+ *
+ * @param methodJoinpoint the joinpoint to quickly match against
+ * @return true if it is impossible for the joinpoint to match this signature
+ */
+ private boolean parametersCannotMatch(JoinPointSignature methodJoinpoint) {
+ if (methodJoinpoint.isVarargsMethod()) {
+ // just give up early (for now)
+ return false;
+ }
+
+ int patternParameterCount = parameterTypes.size();
+
+ if (patternParameterCount == 0 || parameterTypes.ellipsisCount == 0) {
+ boolean equalCount = patternParameterCount == methodJoinpoint.getParameterTypes().length;
+
+ // Quick rule: pattern specifies zero parameters, and joinpoint has parameters *OR*
+ if (patternParameterCount == 0 && !equalCount) {
+ return true;
+ }
+
+ // Quick rule: pattern doesn't specify ellipsis and there are a different number of parameters on the
+ // method join point as compared with the pattern
+ if (parameterTypes.ellipsisCount == 0 && !equalCount) {
+ if (patternParameterCount > 0 && parameterTypes.get(patternParameterCount - 1).isVarArgs()) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Matches on name, declaring type, return type, parameter types, throws types
+ */
+ private FuzzyBoolean matchesExactlyMethod(JoinPointSignature aMethod, World world, boolean subjectMatch) {
+ if (parametersCannotMatch(aMethod)) {
+ // System.err.println("Parameter types pattern " + parameterTypes + " pcount: " + aMethod.getParameterTypes().length);
+ return FuzzyBoolean.NO;
+ }
+ // OPTIMIZE only for exact match do the pattern match now? Otherwise defer it until other fast checks complete?
+ if (!name.matches(aMethod.getName())) {
+ return FuzzyBoolean.NO;
+ }
+ // Check the throws pattern
+ if (subjectMatch && !throwsPattern.matches(aMethod.getExceptions(), world)) {
+ return FuzzyBoolean.NO;
+ }
+
+ // '*' trivially matches everything, no need to check further
+ if (!declaringType.isStar()) {
+ if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) {
+ return FuzzyBoolean.MAYBE;
+ }
+ }
+
+ // '*' would match any return value
+ if (!returnType.isStar()) {
+ boolean b = returnType.isBangVoid();
+ if (b) {
+ String s = aMethod.getReturnType().getSignature();
+ if (s.length() == 1 && s.charAt(0) == 'V') {
+ // it is void, so not a match
+ return FuzzyBoolean.NO;
+ }
+ } else {
+ if (returnType.isVoid()) {
+ String s = aMethod.getReturnType().getSignature();
+ if (s.length() != 1 || s.charAt(0) != 'V') {
+ // it is not void, so not a match
+ return FuzzyBoolean.NO;
+ }
+ } else {
+ if (!returnType.matchesStatically(aMethod.getReturnType().resolve(world))) {
+ // looking bad, but there might be parameterization to consider...
+ if (!returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) {
+ // ok, it's bad.
+ return FuzzyBoolean.MAYBE;
+ }
+ }
+ }
+ }
+ }
+
+ // The most simple case: pattern is (..) will match anything
+ if (parameterTypes.size() == 1 && parameterTypes.get(0).isEllipsis()) {
+ return FuzzyBoolean.YES;
+ }
+
+ if (!parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) {
+ return FuzzyBoolean.NO;
+ }
+
+ // OPTIMIZE both resolution of these types and their annotations should be deferred - just pass down a world and do it lower
+ // down
+ // ResolvedType[] resolvedParameters = world.resolve(aMethod.getParameterTypes());
+
+ ResolvableTypeList rtl = new ResolvableTypeList(world, aMethod.getParameterTypes());
+ // Only fetch the parameter annotations if the pointcut is going to be matching on them
+ ResolvedType[][] parameterAnnotationTypes = null;
+ if (isMatchingParameterAnnotations()) {
+ parameterAnnotationTypes = aMethod.getParameterAnnotationTypes();
+ if (parameterAnnotationTypes != null && parameterAnnotationTypes.length == 0) {
+ parameterAnnotationTypes = null;
+ }
+ }
+
+ if (!parameterTypes.matches(rtl, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
+ // It could still be a match based on the generic sig parameter types of a parameterized type
+ if (!parameterTypes.matches(new ResolvableTypeList(world, aMethod.getGenericParameterTypes()), TypePattern.STATIC,
+ parameterAnnotationTypes).alwaysTrue()) {
+ return FuzzyBoolean.MAYBE;
+ // It could STILL be a match based on the erasure of the parameter types??
+ // to be determined via test cases...
+ }
+ }
+
+ // check that varargs specifications match
+ if (!matchesVarArgs(aMethod, world)) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ // passed all the guards..
+ return FuzzyBoolean.YES;
+ }
+
+ /**
+ * Determine if any pattern in the parameter type pattern list is attempting to match on parameter annotations.
+ *
+ * @return true if a parameter type pattern wants to match on a parameter annotation
+ */
+ private boolean isMatchingParameterAnnotations() {
+ if ((bits & CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING) == 0) {
+ bits |= CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING;
+ for (int tp = 0, max = parameterTypes.size(); tp < max; tp++) {
+ TypePattern typePattern = parameterTypes.get(tp);
+ if (isParameterAnnotationMatching(typePattern)) {
+ bits |= PARAMETER_ANNOTATION_MATCHING;
+ }
+ }
+ }
+ return (bits & PARAMETER_ANNOTATION_MATCHING) != 0;
+ }
+
+ /**
+ * Walk the simple structure of a type pattern and determine if any leaf node is involved in parameter annotation matching.
+ */
+ private boolean isParameterAnnotationMatching(TypePattern tp) {
+ if (tp instanceof OrTypePattern) {
+ OrTypePattern orAtp = (OrTypePattern) tp;
+ return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
+ } else if (tp instanceof AndTypePattern) {
+ AndTypePattern andAtp = (AndTypePattern) tp;
+ return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
+ } else if (tp instanceof NotTypePattern) {
+ NotTypePattern notAtp = (NotTypePattern) tp;
+ return (isParameterAnnotationMatching(notAtp.getNegatedPattern()));
+ } else {
+ AnnotationTypePattern atp = tp.getAnnotationPattern();
+ return isParameterAnnotationMatching(atp);
+ }
+ }
+
+ private boolean isParameterAnnotationMatching(AnnotationTypePattern tp) {
+ if (tp instanceof OrAnnotationTypePattern) {
+ OrAnnotationTypePattern orAtp = (OrAnnotationTypePattern) tp;
+ return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
+ } else if (tp instanceof AndAnnotationTypePattern) {
+ AndAnnotationTypePattern andAtp = (AndAnnotationTypePattern) tp;
+ return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
+ } else if (tp instanceof NotAnnotationTypePattern) {
+ NotAnnotationTypePattern notAtp = (NotAnnotationTypePattern) tp;
+ return (isParameterAnnotationMatching(notAtp.negatedPattern));
+ } else {
+ return tp.isForParameterAnnotationMatch();
+ }
+ }
+
+ /**
+ * match on declaring type, parameter types, throws types
+ */
+ private FuzzyBoolean matchesExactlyConstructor(JoinPointSignature aConstructor, World world) {
+ if (!declaringType.matchesStatically(aConstructor.getDeclaringType().resolve(world))) {
+ return FuzzyBoolean.NO;
+ }
+
+ if (!parameterTypes.canMatchSignatureWithNParameters(aConstructor.getParameterTypes().length)) {
+ return FuzzyBoolean.NO;
+ }
+ ResolvedType[] resolvedParameters = world.resolve(aConstructor.getParameterTypes());
+
+ ResolvedType[][] parameterAnnotationTypes = aConstructor.getParameterAnnotationTypes();
+
+ if (parameterAnnotationTypes == null || parameterAnnotationTypes.length == 0) {
+ parameterAnnotationTypes = null;
+ }
+
+ if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
+ // It could still be a match based on the generic sig parameter types of a parameterized type
+ if (!parameterTypes.matches(world.resolve(aConstructor.getGenericParameterTypes()), TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
+ return FuzzyBoolean.MAYBE;
+ // It could STILL be a match based on the erasure of the parameter types??
+ // to be determined via test cases...
+ }
+ }
+
+ // check that varargs specifications match
+ if (!matchesVarArgs(aConstructor, world)) {
+ return FuzzyBoolean.NO;
+ }
+
+ // Check the throws pattern
+ if (!throwsPattern.matches(aConstructor.getExceptions(), world)) {
+ return FuzzyBoolean.NO;
+ }
+
+ // passed all the guards..
+ return FuzzyBoolean.YES;
+ }
+
+ /**
+ * We've matched against this method or constructor so far, but without considering varargs (which has been matched as a simple
+ * array thus far). Now we do the additional checks to see if the parties agree on whether the last parameter is varargs or a
+ * straight array.
+ */
+ private boolean matchesVarArgs(JoinPointSignature aMethodOrConstructor, World inAWorld) {
+ if (parameterTypes.size() == 0) {
+ return true;
+ }
+
+ TypePattern lastPattern = parameterTypes.get(parameterTypes.size() - 1);
+ boolean canMatchVarArgsSignature = lastPattern.isStar() || lastPattern.isVarArgs() || (lastPattern == TypePattern.ELLIPSIS);
+
+ if (aMethodOrConstructor.isVarargsMethod()) {
+ // we have at least one parameter in the pattern list, and the method has a varargs signature
+ if (!canMatchVarArgsSignature) {
+ // XXX - Ideally the shadow would be included in the msg but we don't know it...
+ inAWorld.getLint().cantMatchArrayTypeOnVarargs.signal(aMethodOrConstructor.toString(), getSourceLocation());
+ return false;
+ }
+ } else {
+ // the method ends with an array type, check that we don't *require* a varargs
+ if (lastPattern.isVarArgs()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private FuzzyBoolean matchesAnnotations(ResolvedMember member, World world) {
+ if (member == null) {
+ // world.getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
+ return FuzzyBoolean.NO;
+ }
+ annotationPattern.resolve(world);
+
+ // optimization before we go digging around for annotations on ITDs
+ if (annotationPattern instanceof AnyAnnotationTypePattern) {
+ return FuzzyBoolean.YES;
+ }
+
+ // fake members represent ITD'd fields - for their annotations we should go and look up the
+ // relevant member in the original aspect
+ if (member.isAnnotatedElsewhere() && member.getKind() == Member.FIELD) {
+ // FIXME asc duplicate of code in AnnotationPointcut.matchInternal()? same fixmes apply here.
+ // ResolvedMember [] mems = member.getDeclaringType().resolve(world).getDeclaredFields(); // FIXME asc should include
+ // supers with getInterTypeMungersIncludingSupers?
+ List<ConcreteTypeMunger> mungers = member.getDeclaringType().resolve(world).getInterTypeMungers();
+ for (ConcreteTypeMunger typeMunger : mungers) {
+ if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
+ ResolvedMember fakerm = typeMunger.getSignature();
+ ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
+ ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
+ if (fakerm.equals(member)) {
+ member = rmm;
+ }
+ }
+ }
+ }
+
+ if (annotationPattern.matches(member).alwaysTrue()) {
+ return FuzzyBoolean.YES;
+ } else {
+ // do NOT look at ancestor members... only the subject can have an annotation match
+ // see http://www.eclipse.org/aspectj/doc/next/adk15notebook/join-point-modifiers.html
+ return FuzzyBoolean.NO;
+ }
+ }
+
+ private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
+ ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
+ for (int i = 0; i < decMethods.length; i++) {
+ ResolvedMember member = decMethods[i];
+ if (member.equals(ajcMethod)) {
+ return member;
+ }
+ }
+ return null;
+ }
+
+ public boolean declaringTypeMatchAllowingForCovariance(Member member, UnresolvedType shadowDeclaringType, World world,
+ TypePattern returnTypePattern, ResolvedType sigReturn) {
+
+ ResolvedType onType = shadowDeclaringType.resolve(world);
+
+ // fastmatch
+ if (declaringType.matchesStatically(onType) && returnTypePattern.matchesStatically(sigReturn)) {
+ return true;
+ }
+
+ Collection<ResolvedType> declaringTypes = member.getDeclaringTypes(world);
+
+ boolean checkReturnType = true;
+ // XXX Possible enhancement? Doesn't seem to speed things up
+ // if (returnTypePattern.isStar()) {
+ // if (returnTypePattern instanceof WildTypePattern) {
+ // if (((WildTypePattern)returnTypePattern).getDimensions()==0) checkReturnType = false;
+ // }
+ // }
+
+ // Sometimes that list includes types that don't explicitly declare the member we are after -
+ // they are on the list because their supertype is on the list, that's why we use
+ // lookupMethod rather than lookupMemberNoSupers()
+ for (ResolvedType type : declaringTypes) {
+ if (declaringType.matchesStatically(type)) {
+ if (!checkReturnType) {
+ return true;
+ }
+ ResolvedMember rm = type.lookupMethod(member);
+ if (rm == null) {
+ rm = type.lookupMethodInITDs(member); // It must be in here, or we have *real* problems
+ }
+ if (rm == null) {
+ continue; // might be currently looking at the generic type and we need to continue searching in case we hit a
+ }
+ // parameterized version of this same type...
+ UnresolvedType returnTypeX = rm.getReturnType();
+ ResolvedType returnType = returnTypeX.resolve(world);
+ if (returnTypePattern.matchesStatically(returnType)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // private Collection getDeclaringTypes(Signature sig) {
+ // List l = new ArrayList();
+ // Class onType = sig.getDeclaringType();
+ // String memberName = sig.getName();
+ // if (sig instanceof FieldSignature) {
+ // Class fieldType = ((FieldSignature)sig).getFieldType();
+ // Class superType = onType;
+ // while(superType != null) {
+ // try {
+ // Field f = (superType.getDeclaredField(memberName));
+ // if (f.getType() == fieldType) {
+ // l.add(superType);
+ // }
+ // } catch (NoSuchFieldException nsf) {}
+ // superType = superType.getSuperclass();
+ // }
+ // } else if (sig instanceof MethodSignature) {
+ // Class[] paramTypes = ((MethodSignature)sig).getParameterTypes();
+ // Class superType = onType;
+ // while(superType != null) {
+ // try {
+ // superType.getDeclaredMethod(memberName,paramTypes);
+ // l.add(superType);
+ // } catch (NoSuchMethodException nsm) {}
+ // superType = superType.getSuperclass();
+ // }
+ // }
+ // return l;
+ // }
+
+ public NamePattern getName() {
+ return name;
+ }
+
+ public TypePattern getDeclaringType() {
+ return declaringType;
+ }
+
+ public MemberKind getKind() {
+ return kind;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buf.append(annotationPattern.toString());
+ buf.append(' ');
+ }
+
+ if (modifiers != ModifiersPattern.ANY) {
+ buf.append(modifiers.toString());
+ buf.append(' ');
+ }
+
+ if (kind == Member.STATIC_INITIALIZATION) {
+ buf.append(declaringType.toString());
+ buf.append(".<clinit>()");// FIXME AV - bad, cannot be parsed again
+ } else if (kind == Member.HANDLER) {
+ buf.append("handler(");
+ buf.append(parameterTypes.get(0));
+ buf.append(")");
+ } else {
+ if (!(kind == Member.CONSTRUCTOR)) {
+ buf.append(returnType.toString());
+ buf.append(' ');
+ }
+ if (declaringType != TypePattern.ANY) {
+ buf.append(declaringType.toString());
+ buf.append('.');
+ }
+ if (kind == Member.CONSTRUCTOR) {
+ buf.append("new");
+ } else {
+ buf.append(name.toString());
+ }
+ if (kind == Member.METHOD || kind == Member.CONSTRUCTOR) {
+ buf.append(parameterTypes.toString());
+ }
+ // FIXME AV - throws is not printed here, weird
+ }
+ return buf.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof SignaturePattern)) {
+ return false;
+ }
+ SignaturePattern o = (SignaturePattern) other;
+ return o.kind.equals(this.kind) && o.modifiers.equals(this.modifiers) && o.returnType.equals(this.returnType)
+ && o.declaringType.equals(this.declaringType) && o.name.equals(this.name)
+ && o.parameterTypes.equals(this.parameterTypes) && o.throwsPattern.equals(this.throwsPattern)
+ && o.annotationPattern.equals(this.annotationPattern);
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashcode == -1) {
+ hashcode = 17;
+ hashcode = 37 * hashcode + kind.hashCode();
+ hashcode = 37 * hashcode + modifiers.hashCode();
+ hashcode = 37 * hashcode + returnType.hashCode();
+ hashcode = 37 * hashcode + declaringType.hashCode();
+ hashcode = 37 * hashcode + name.hashCode();
+ hashcode = 37 * hashcode + parameterTypes.hashCode();
+ hashcode = 37 * hashcode + throwsPattern.hashCode();
+ hashcode = 37 * hashcode + annotationPattern.hashCode();
+ }
+ return hashcode;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ kind.write(s);
+ modifiers.write(s);
+ returnType.write(s);
+ declaringType.write(s);
+ name.write(s);
+ parameterTypes.write(s);
+ throwsPattern.write(s);
+ annotationPattern.write(s);
+ writeLocation(s);
+ }
+
+ public static SignaturePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ // ISignaturePattern kind should already have been read by the time this read is entered
+ MemberKind kind = MemberKind.read(s);
+ ModifiersPattern modifiers = ModifiersPattern.read(s);
+ TypePattern returnType = TypePattern.read(s, context);
+ TypePattern declaringType = TypePattern.read(s, context);
+ NamePattern name = NamePattern.read(s);
+ TypePatternList parameterTypes = TypePatternList.read(s, context);
+ ThrowsPattern throwsPattern = ThrowsPattern.read(s, context);
+
+ AnnotationTypePattern annotationPattern = AnnotationTypePattern.ANY;
+
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+ annotationPattern = AnnotationTypePattern.read(s, context);
+ }
+
+ SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
+ throwsPattern, annotationPattern);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ /**
+ * @return
+ */
+ public ModifiersPattern getModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * @return
+ */
+ public TypePatternList getParameterTypes() {
+ return parameterTypes;
+ }
+
+ /**
+ * @return
+ */
+ public TypePattern getReturnType() {
+ return returnType;
+ }
+
+ /**
+ * @return
+ */
+ public ThrowsPattern getThrowsPattern() {
+ return throwsPattern;
+ }
+
+ /**
+ * return true if last argument in params is an Object[] but the modifiers say this method was declared with varargs
+ * (Object...). We shouldn't be matching if this is the case.
+ */
+ // private boolean matchedArrayAgainstVarArgs(TypePatternList params,int modifiers) {
+ // if (params.size()>0 && (modifiers & Constants.ACC_VARARGS)!=0) {
+ // // we have at least one parameter in the pattern list, and the method has a varargs signature
+ // TypePattern lastPattern = params.get(params.size()-1);
+ // if (lastPattern.isArray() && !lastPattern.isVarArgs) return true;
+ // }
+ // return false;
+ // }
+ public AnnotationTypePattern getAnnotationPattern() {
+ return annotationPattern;
+ }
+
+ @Override
+ public boolean isStarAnnotation() {
+ return annotationPattern == AnnotationTypePattern.ANY;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public boolean isExactDeclaringTypePattern() {
+ return isExactDeclaringTypePattern;
+ }
+
+ @Override
+ public boolean isMatchOnAnyName() {
+ return getName().isAny();
+ }
+
+ @Override
+ public List<ExactTypePattern> getExactDeclaringTypes() {
+ if (declaringType instanceof ExactTypePattern) {
+ List<ExactTypePattern> l = new ArrayList<ExactTypePattern>();
+ l.add((ExactTypePattern) declaringType);
+ return l;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public boolean couldEverMatch(ResolvedType type) {
+ return declaringType.matches(type, TypePattern.STATIC).maybeTrue();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SimpleScope.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SimpleScope.java
new file mode 100644
index 000000000..119103d84
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/SimpleScope.java
@@ -0,0 +1,173 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.bridge.SourceLocation;
+import org.aspectj.weaver.IHasPosition;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+public class SimpleScope implements IScope {
+
+ private static final String[] NoStrings = new String[0];
+ private static final String[] javaLangPrefixArray = new String[] { "java.lang.", };
+
+ private String[] importedPrefixes = javaLangPrefixArray;
+ private String[] importedNames = NoStrings;
+ private World world;
+ private ResolvedType enclosingType;
+ protected FormalBinding[] bindings;
+
+ public SimpleScope(World world, FormalBinding[] bindings) {
+ super();
+ this.world = world;
+ this.bindings = bindings;
+ }
+
+ public UnresolvedType lookupType(String name, IHasPosition location) {
+ for (int i = 0; i < importedNames.length; i++) {
+ String importedName = importedNames[i];
+ // make sure we're matching against the type name rather than part of it
+ // if (importedName.endsWith("." + name)) {
+ if (importedName.endsWith(name)) {
+ return world.resolve(importedName);
+ }
+ }
+
+ // Check for a primitive
+ if (name.length() < 8 && Character.isLowerCase(name.charAt(0))) {
+ // could be a primitive
+ int len = name.length();
+ if (len == 3) {
+ if (name.equals("int")) {
+ return UnresolvedType.INT;
+ }
+ } else if (len == 4) {
+ if (name.equals("void")) {
+ return UnresolvedType.VOID;
+ } else if (name.equals("byte")) {
+ return UnresolvedType.BYTE;
+ } else if (name.equals("char")) {
+ return UnresolvedType.CHAR;
+ } else if (name.equals("long")) {
+ return UnresolvedType.LONG;
+ }
+ } else if (len == 5) {
+ if (name.equals("float")) {
+ return UnresolvedType.FLOAT;
+ } else if (name.equals("short")) {
+ return UnresolvedType.SHORT;
+ }
+ } else if (len == 6) {
+ if (name.equals("double")) {
+ return UnresolvedType.DOUBLE;
+ }
+ } else if (len == 7) {
+ if (name.equals("boolean")) {
+ return UnresolvedType.BOOLEAN;
+ }
+ }
+ }
+
+ // Is it fully qualified?
+ if (name.indexOf('.') != -1) {
+ return world.resolve(UnresolvedType.forName(name), true);
+ }
+
+ for (String importedPrefix : importedPrefixes) {
+ ResolvedType tryType = world.resolve(UnresolvedType.forName(importedPrefix + name), true);
+ if (!tryType.isMissing()) {
+ return tryType;
+ }
+ }
+
+ return world.resolve(UnresolvedType.forName(name), true);
+ }
+
+ public IMessageHandler getMessageHandler() {
+ return world.getMessageHandler();
+ }
+
+ public FormalBinding lookupFormal(String name) {
+ for (int i = 0, len = bindings.length; i < len; i++) {
+ if (bindings[i].getName().equals(name)) {
+ return bindings[i];
+ }
+ }
+ return null;
+ }
+
+ public FormalBinding getFormal(int i) {
+ return bindings[i];
+ }
+
+ public int getFormalCount() {
+ return bindings.length;
+ }
+
+ public String[] getImportedNames() {
+ return importedNames;
+ }
+
+ public String[] getImportedPrefixes() {
+ return importedPrefixes;
+ }
+
+ public void setImportedNames(String[] importedNames) {
+ this.importedNames = importedNames;
+ }
+
+ public void setImportedPrefixes(String[] importedPrefixes) {
+ this.importedPrefixes = importedPrefixes;
+ }
+
+ public static FormalBinding[] makeFormalBindings(UnresolvedType[] types, String[] names) {
+ int len = types.length;
+ FormalBinding[] bindings = new FormalBinding[len];
+ for (int i = 0; i < len; i++) {
+ bindings[i] = new FormalBinding(types[i], names[i], i);
+ }
+ return bindings;
+ }
+
+ public ISourceLocation makeSourceLocation(IHasPosition location) {
+ return new SourceLocation(ISourceLocation.NO_FILE, 0);
+ }
+
+ public void message(IMessage.Kind kind, IHasPosition location1, IHasPosition location2, String message) {
+ message(kind, location1, message);
+ message(kind, location2, message);
+ }
+
+ public void message(IMessage.Kind kind, IHasPosition location, String message) {
+ getMessageHandler().handleMessage(new Message(message, kind, null, makeSourceLocation(location)));
+ }
+
+ public void message(IMessage aMessage) {
+ getMessageHandler().handleMessage(aMessage);
+ }
+
+ public World getWorld() {
+ return world;
+ }
+
+ public ResolvedType getEnclosingType() {
+ return enclosingType;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java
new file mode 100644
index 000000000..dfb509195
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetAnnotationPointcut.java
@@ -0,0 +1,337 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * @author colyer
+ *
+ * TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code
+ * Templates
+ */
+public class ThisOrTargetAnnotationPointcut extends NameBindingPointcut {
+
+ private boolean isThis;
+ private boolean alreadyWarnedAboutDEoW = false;
+ private ExactAnnotationTypePattern annotationTypePattern;
+ private String declarationText;
+
+ private static final int thisKindSet;
+ private static final int targetKindSet;
+
+ static {
+ int thisFlags = Shadow.ALL_SHADOW_KINDS_BITS;
+ int targFlags = Shadow.ALL_SHADOW_KINDS_BITS;
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
+ if (kind.neverHasThis()) {
+ thisFlags -= kind.bit;
+ }
+ if (kind.neverHasTarget()) {
+ targFlags -= kind.bit;
+ }
+ }
+ thisKindSet = thisFlags;
+ targetKindSet = targFlags;
+ }
+
+ /**
+ *
+ */
+ public ThisOrTargetAnnotationPointcut(boolean isThis, ExactAnnotationTypePattern type) {
+ super();
+ this.isThis = isThis;
+ this.annotationTypePattern = type;
+ this.pointcutKind = ATTHIS_OR_TARGET;
+ buildDeclarationText();
+ }
+
+ public ThisOrTargetAnnotationPointcut(boolean isThis, ExactAnnotationTypePattern type, ShadowMunger munger) {
+ this(isThis, type);
+ }
+
+ public ExactAnnotationTypePattern getAnnotationTypePattern() {
+ return annotationTypePattern;
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return isThis ? thisKindSet : targetKindSet;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ ExactAnnotationTypePattern newPattern = (ExactAnnotationTypePattern) this.annotationTypePattern.parameterizeWith(
+ typeVariableMap, w);
+ if (newPattern.getAnnotationType() instanceof ResolvedType) {
+ verifyRuntimeRetention(newPattern.getResolvedAnnotationType());
+ }
+ ThisOrTargetAnnotationPointcut ret = new ThisOrTargetAnnotationPointcut(isThis,
+ (ExactAnnotationTypePattern) annotationTypePattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
+ */
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
+ */
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ if (!couldMatch(shadow)) {
+ return FuzzyBoolean.NO;
+ }
+ ResolvedType toMatchAgainst = (isThis ? shadow.getThisType() : shadow.getTargetType()).resolve(shadow.getIWorld());
+ annotationTypePattern.resolve(shadow.getIWorld());
+ if (annotationTypePattern.matchesRuntimeType(toMatchAgainst).alwaysTrue()) {
+ return FuzzyBoolean.YES;
+ } else {
+ // a subtype may match at runtime
+ return FuzzyBoolean.MAYBE;
+ }
+ }
+
+ public boolean isThis() {
+ return isThis;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings)
+ */
+ @Override
+ protected void resolveBindings(IScope scope, Bindings bindings) {
+ if (!scope.getWorld().isInJava5Mode()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(isThis ? WeaverMessages.ATTHIS_ONLY_SUPPORTED_AT_JAVA5_LEVEL
+ : WeaverMessages.ATTARGET_ONLY_SUPPORTED_AT_JAVA5_LEVEL), getSourceLocation()));
+ return;
+ }
+ annotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern.resolveBindings(scope, bindings, true);
+ // must be either a Var, or an annotation type pattern
+ // if annotationType does not have runtime retention, this is an error
+ if (annotationTypePattern.annotationType == null) {
+ // it's a formal with a binding error
+ return;
+ }
+ ResolvedType rAnnotationType = (ResolvedType) annotationTypePattern.annotationType;
+ if (rAnnotationType.isTypeVariableReference()) {
+ return; // we'll deal with this next check when the type var is actually bound...
+ }
+ verifyRuntimeRetention(rAnnotationType);
+
+ }
+
+ private void verifyRuntimeRetention(ResolvedType rAnnotationType) {
+ if (!(rAnnotationType.isAnnotationWithRuntimeRetention())) {
+ IMessage m = MessageUtil.error(WeaverMessages.format(WeaverMessages.BINDING_NON_RUNTIME_RETENTION_ANNOTATION,
+ rAnnotationType.getName()), getSourceLocation());
+ rAnnotationType.getWorld().getMessageHandler().handleMessage(m);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
+ */
+ @Override
+ protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ // Enforce rule about which designators are supported in declare
+ if (!alreadyWarnedAboutDEoW) {
+ inAspect.getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.THIS_OR_TARGET_IN_DECLARE, isThis ? "this" : "target"),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ alreadyWarnedAboutDEoW = true;
+ }
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+
+ ExactAnnotationTypePattern newType = (ExactAnnotationTypePattern) annotationTypePattern.remapAdviceFormals(bindings);
+ ThisOrTargetAnnotationPointcut ret = new ThisOrTargetAnnotationPointcut(isThis, newType, bindings.getEnclosingAdvice());
+ ret.alreadyWarnedAboutDEoW = alreadyWarnedAboutDEoW;
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
+ */
+ /**
+ * The guard here is going to be the hasAnnotation() test - if it gets through (which we cannot determine until runtime) then we
+ * must have a TypeAnnotationAccessVar in place - this means we must *always* have one in place.
+ */
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ if (!couldMatch(shadow)) {
+ return Literal.FALSE;
+ }
+ boolean alwaysMatches = match(shadow).alwaysTrue();
+ Var var = isThis ? shadow.getThisVar() : shadow.getTargetVar();
+ Var annVar = null;
+
+ // Are annotations being bound?
+ UnresolvedType annotationType = annotationTypePattern.annotationType;
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) annotationTypePattern;
+ annotationType = btp.annotationType;
+
+ annVar = isThis ? shadow.getThisAnnotationVar(annotationType) : shadow.getTargetAnnotationVar(annotationType);
+ if (annVar == null) {
+ throw new RuntimeException("Impossible!");
+ }
+
+ state.set(btp.getFormalIndex(), annVar);
+ }
+
+ if (alwaysMatches && (annVar == null)) {// change check to verify if its the 'generic' annVar that is being used
+ return Literal.TRUE;
+ } else {
+ ResolvedType rType = annotationType.resolve(shadow.getIWorld());
+ return Test.makeHasAnnotation(var, rType);
+ }
+ }
+
+ private boolean couldMatch(Shadow shadow) {
+ return isThis ? shadow.hasThis() : shadow.hasTarget();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
+ */
+ @Override
+ public List<BindingPattern> getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ List<BindingPattern> l = new ArrayList<BindingPattern>();
+ l.add((BindingPattern)annotationTypePattern);
+ return l;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
+ */
+ @Override
+ public List<BindingTypePattern> getBindingTypePatterns() {
+ return Collections.emptyList();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
+ */
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.ATTHIS_OR_TARGET);
+ s.writeBoolean(isThis);
+ annotationTypePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ boolean isThis = s.readBoolean();
+ AnnotationTypePattern type = AnnotationTypePattern.read(s, context);
+ ThisOrTargetAnnotationPointcut ret = new ThisOrTargetAnnotationPointcut(isThis, (ExactAnnotationTypePattern) type);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ThisOrTargetAnnotationPointcut)) {
+ return false;
+ }
+ ThisOrTargetAnnotationPointcut other = (ThisOrTargetAnnotationPointcut) obj;
+ return (other.annotationTypePattern.equals(this.annotationTypePattern) && (other.isThis == this.isThis));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return 17 + 37 * annotationTypePattern.hashCode() + (isThis ? 49 : 13);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ private void buildDeclarationText() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(isThis ? "@this(" : "@target(");
+ String annPatt = annotationTypePattern.toString();
+ buf.append(annPatt.startsWith("@") ? annPatt.substring(1) : annPatt);
+ buf.append(")");
+ this.declarationText = buf.toString();
+ }
+
+ @Override
+ public String toString() {
+ return this.declarationText;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java
new file mode 100644
index 000000000..a278e76c6
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java
@@ -0,0 +1,242 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * Corresponds to target or this pcd.
+ *
+ * <p>
+ * type is initially a WildTypePattern. If it stays that way, it's a this(Foo) type deal. however, the resolveBindings method may
+ * convert it to a BindingTypePattern, in which case, it's a this(foo) type deal.
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public class ThisOrTargetPointcut extends NameBindingPointcut {
+ private boolean isThis;
+ private TypePattern typePattern;
+ private String declarationText;
+
+ private static final int thisKindSet;
+ private static final int targetKindSet;
+
+ static {
+ int thisFlags = Shadow.ALL_SHADOW_KINDS_BITS;
+ int targFlags = Shadow.ALL_SHADOW_KINDS_BITS;
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
+ if (kind.neverHasThis()) {
+ thisFlags -= kind.bit;
+ }
+ if (kind.neverHasTarget()) {
+ targFlags -= kind.bit;
+ }
+ }
+ thisKindSet = thisFlags;
+ targetKindSet = targFlags;
+ }
+
+ public boolean isBinding() {
+ return (typePattern instanceof BindingTypePattern);
+ }
+
+ public ThisOrTargetPointcut(boolean isThis, TypePattern type) {
+ this.isThis = isThis;
+ this.typePattern = type;
+ this.pointcutKind = THIS_OR_TARGET;
+ this.declarationText = (isThis ? "this(" : "target(") + type + ")";
+ }
+
+ public TypePattern getType() {
+ return typePattern;
+ }
+
+ public boolean isThis() {
+ return isThis;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ ThisOrTargetPointcut ret = new ThisOrTargetPointcut(isThis, typePattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return isThis ? thisKindSet : targetKindSet;
+ }
+
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ private boolean couldMatch(Shadow shadow) {
+ return isThis ? shadow.hasThis() : shadow.hasTarget();
+ }
+
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ if (!couldMatch(shadow)) {
+ return FuzzyBoolean.NO;
+ }
+ UnresolvedType typeToMatch = isThis ? shadow.getThisType() : shadow.getTargetType();
+ // optimization for case of this(Object) or target(Object)
+ // works for an ExactTypePattern (and we know there are no annotations to match here of course)
+ if (typePattern.getExactType().equals(ResolvedType.OBJECT)) {
+ return FuzzyBoolean.YES;
+ }
+ return typePattern.matches(typeToMatch.resolve(shadow.getIWorld()), TypePattern.DYNAMIC);
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.THIS_OR_TARGET);
+ s.writeBoolean(isThis);
+ typePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ boolean isThis = s.readBoolean();
+ TypePattern type = TypePattern.read(s, context);
+ ThisOrTargetPointcut ret = new ThisOrTargetPointcut(isThis, type);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ typePattern = typePattern.resolveBindings(scope, bindings, true, true);
+
+ // look for parameterized type patterns which are not supported...
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ typePattern.traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.THIS_AND_TARGET_DONT_SUPPORT_PARAMETERS),
+ getSourceLocation()));
+ }
+ // ??? handle non-formal
+ }
+
+ @Override
+ public void postRead(ResolvedType enclosingType) {
+ typePattern.postRead(enclosingType);
+ }
+
+ @Override
+ public List<BindingPattern> getBindingAnnotationTypePatterns() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<BindingTypePattern> getBindingTypePatterns() {
+ if (typePattern instanceof BindingTypePattern) {
+ List<BindingTypePattern> l = new ArrayList<BindingTypePattern>();
+ l.add((BindingTypePattern)typePattern);
+ return l;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof ThisOrTargetPointcut)) {
+ return false;
+ }
+ ThisOrTargetPointcut o = (ThisOrTargetPointcut) other;
+ return o.isThis == this.isThis && o.typePattern.equals(this.typePattern);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + (isThis ? 0 : 1);
+ result = 37 * result + typePattern.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return declarationText;
+ }
+
+ /**
+ * Residue is the remainder of the pointcut match that couldn't be performed with the purely static information at compile time
+ * and this method returns the residue of a pointcut at a particular shadow.
+ */
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ if (!couldMatch(shadow)) {
+ return Literal.FALSE;
+ }
+
+ // if no preference is specified, just say TRUE which means no residue
+ if (typePattern == TypePattern.ANY) {
+ return Literal.TRUE;
+ }
+
+ Var var = isThis ? shadow.getThisVar() : shadow.getTargetVar();
+
+ return exposeStateForVar(var, typePattern, state, shadow.getIWorld());
+ }
+
+ @Override
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ if (isDeclare(bindings.getEnclosingAdvice())) {
+ // Enforce rule about which designators are supported in declare
+ inAspect.getWorld().showMessage(IMessage.ERROR,
+ WeaverMessages.format(WeaverMessages.THIS_OR_TARGET_IN_DECLARE, isThis ? "this" : "target"),
+ bindings.getEnclosingAdvice().getSourceLocation(), null);
+ return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
+ }
+
+ TypePattern newType = typePattern.remapAdviceFormals(bindings);
+ if (inAspect.crosscuttingMembers != null) {
+ inAspect.crosscuttingMembers.exposeType(newType.getExactType());
+ }
+
+ Pointcut ret = new ThisOrTargetPointcut(isThis, newType);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThrowsPattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThrowsPattern.java
new file mode 100644
index 000000000..93557d8c1
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/ThrowsPattern.java
@@ -0,0 +1,146 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public class ThrowsPattern extends PatternNode {
+ private TypePatternList required;
+ private TypePatternList forbidden;
+
+ public static final ThrowsPattern ANY = new ThrowsPattern(TypePatternList.EMPTY, TypePatternList.EMPTY);
+
+ public ThrowsPattern(TypePatternList required, TypePatternList forbidden) {
+ this.required = required;
+ this.forbidden = forbidden;
+ }
+
+ public TypePatternList getRequired() {
+ return required;
+ }
+
+ public TypePatternList getForbidden() {
+ return forbidden;
+ }
+
+ public String toString() {
+ if (this == ANY) {
+ return "";
+ }
+
+ String ret = "throws " + required.toString();
+ if (forbidden.size() > 0) {
+ ret = ret + " !(" + forbidden.toString() + ")";
+ }
+ return ret;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof ThrowsPattern)) {
+ return false;
+ }
+ ThrowsPattern o = (ThrowsPattern) other;
+ boolean ret = o.required.equals(this.required) && o.forbidden.equals(this.forbidden);
+ return ret;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + required.hashCode();
+ result = 37 * result + forbidden.hashCode();
+ return result;
+ }
+
+ public ThrowsPattern resolveBindings(IScope scope, Bindings bindings) {
+ if (this == ANY) {
+ return this;
+ }
+ required = required.resolveBindings(scope, bindings, false, false);
+ forbidden = forbidden.resolveBindings(scope, bindings, false, false);
+ return this;
+ }
+
+ public ThrowsPattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ ThrowsPattern ret = new ThrowsPattern(required.parameterizeWith(typeVariableMap, w), forbidden.parameterizeWith(
+ typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public boolean matches(UnresolvedType[] tys, World world) {
+ if (this == ANY) {
+ return true;
+ }
+
+ // System.out.println("matching: " + this + " with " + Arrays.asList(tys));
+
+ ResolvedType[] types = world.resolve(tys);
+ // int len = types.length;
+ for (int j = 0, lenj = required.size(); j < lenj; j++) {
+ if (!matchesAny(required.get(j), types)) {
+ return false;
+ }
+ }
+ for (int j = 0, lenj = forbidden.size(); j < lenj; j++) {
+ if (matchesAny(forbidden.get(j), types)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean matchesAny(TypePattern typePattern, ResolvedType[] types) {
+ for (int i = types.length - 1; i >= 0; i--) {
+ if (typePattern.matchesStatically(types[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static ThrowsPattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ TypePatternList required = TypePatternList.read(s, context);
+ TypePatternList forbidden = TypePatternList.read(s, context);
+ if (required.size() == 0 && forbidden.size() == 0) {
+ return ANY;
+ }
+ ThrowsPattern ret = new ThrowsPattern(required, forbidden);
+ // XXXret.readLocation(context, s);
+ return ret;
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ required.write(s);
+ forbidden.write(s);
+ // XXXwriteLocation(s);
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ forbidden.traverse(visitor, data);
+ required.traverse(visitor, data);
+ return ret;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java
new file mode 100644
index 000000000..80ffc7556
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java
@@ -0,0 +1,146 @@
+/* *******************************************************************
+ * Copyright (c) 2010 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement
+ * Nieraj Singh
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+/**
+ * A TypeCategoryTypePattern matches on the category of a type, one of class/interface/aspect/inner/anonymous/enum/annotation, and
+ * these are specified in the pointcut via isClass() isInterface() isAspect() isInner() isAnonymous() isEnum() isAnnotation().
+ *
+ * @author Andy Clement
+ * @since 1.6.9
+ */
+public class TypeCategoryTypePattern extends TypePattern {
+
+ public static final int CLASS = 1;
+ public static final int INTERFACE = 2;
+ public static final int ASPECT = 3;
+ public static final int INNER = 4;
+ public static final int ANONYMOUS = 5;
+ public static final int ENUM = 6;
+ public static final int ANNOTATION = 7;
+ public static final int FINAL = 8;
+ public static final int ABSTRACT = 9;
+
+ private int category;
+
+ private int VERSION = 1;
+
+ public TypeCategoryTypePattern(int category) {
+ super(false);
+ this.category = category;
+ }
+
+ public int getTypeCategory() {
+ return category;
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ return isRightCategory(type);
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ return isRightCategory(type);
+ }
+
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ return FuzzyBoolean.fromBoolean(isRightCategory(type));
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ return this;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof TypeCategoryTypePattern)) {
+ return false;
+ }
+ TypeCategoryTypePattern o = (TypeCategoryTypePattern) other;
+ return o.category == category;
+ }
+
+ // TODO is sourcelocation part of the identity or just a 'nice to have' - if important it should be in hashcode/equals
+ // TODO but if that is the case it needs addressing for all type patterns
+
+ @Override
+ public int hashCode() {
+ return category * 37;
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(TypePattern.TYPE_CATEGORY);
+ s.writeInt(VERSION);
+ s.writeInt(category);
+ writeLocation(s);
+ }
+
+ @SuppressWarnings("unused")
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ int version = s.readInt();
+ int category = s.readInt();
+ TypeCategoryTypePattern tp = new TypeCategoryTypePattern(category);
+ tp.readLocation(context, s);
+ return tp;
+ }
+
+ /**
+ * @return true if the supplied type is of the category specified for this type pattern
+ */
+ private boolean isRightCategory(ResolvedType type) {
+ switch (category) {
+ case CLASS:
+ return type.isClass();
+ case INTERFACE:
+ return type.isInterface();
+ case ASPECT:
+ return type.isAspect();
+ case ANONYMOUS:
+ return type.isAnonymous();
+ case INNER:
+ return type.isNested();
+ case ENUM:
+ return type.isEnum();
+ case ANNOTATION:
+ return type.isAnnotation();
+ case FINAL:
+ return Modifier.isFinal(type.getModifiers());
+ case ABSTRACT:
+ return Modifier.isAbstract(type.getModifiers());
+ }
+ return false;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePattern.java
new file mode 100644
index 000000000..2d657dee2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePattern.java
@@ -0,0 +1,360 @@
+/* *******************************************************************
+ * Copyright (c) 2002, 2010 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * Nieraj Singh
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeVariableReference;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * On creation, type pattern only contains WildTypePattern nodes, not BindingType or ExactType.
+ *
+ * <p>
+ * Then we call resolveBindings() during compilation During concretization of enclosing pointcuts, we call remapAdviceFormals
+ *
+ * @author Erik Hilsdale
+ * @author Jim Hugunin
+ */
+public abstract class TypePattern extends PatternNode {
+ public static class MatchKind {
+ private String name;
+
+ public MatchKind(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ public static final MatchKind STATIC = new MatchKind("STATIC");
+ public static final MatchKind DYNAMIC = new MatchKind("DYNAMIC");
+
+ public static final TypePattern ELLIPSIS = new EllipsisTypePattern();
+ public static final TypePattern ANY = new AnyTypePattern();
+ public static final TypePattern NO = new NoTypePattern();
+
+ protected boolean includeSubtypes;
+ protected boolean isVarArgs = false;
+ protected AnnotationTypePattern annotationPattern = AnnotationTypePattern.ANY;
+ protected TypePatternList typeParameters = TypePatternList.EMPTY;
+
+ protected TypePattern(boolean includeSubtypes, boolean isVarArgs, TypePatternList typeParams) {
+ this.includeSubtypes = includeSubtypes;
+ this.isVarArgs = isVarArgs;
+ this.typeParameters = (typeParams == null ? TypePatternList.EMPTY : typeParams);
+ }
+
+ protected TypePattern(boolean includeSubtypes, boolean isVarArgs) {
+ this(includeSubtypes, isVarArgs, null);
+ }
+
+ public AnnotationTypePattern getAnnotationPattern() {
+ return annotationPattern;
+ }
+
+ public boolean isVarArgs() {
+ return isVarArgs;
+ }
+
+ public boolean isStarAnnotation() {
+ return annotationPattern == AnnotationTypePattern.ANY;
+ }
+
+ public boolean isArray() {
+ return false;
+ }
+
+ protected TypePattern(boolean includeSubtypes) {
+ this(includeSubtypes, false);
+ }
+
+ public void setAnnotationTypePattern(AnnotationTypePattern annPatt) {
+ this.annotationPattern = annPatt;
+ }
+
+ public void setTypeParameters(TypePatternList typeParams) {
+ this.typeParameters = typeParams;
+ }
+
+ public TypePatternList getTypeParameters() {
+ return this.typeParameters;
+ }
+
+ public void setIsVarArgs(boolean isVarArgs) {
+ this.isVarArgs = isVarArgs;
+ }
+
+ // answer conservatively...
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ if (this.includeSubtypes || other.includeSubtypes) {
+ return true;
+ }
+ if (this.annotationPattern != AnnotationTypePattern.ANY) {
+ return true;
+ }
+ if (other.annotationPattern != AnnotationTypePattern.ANY) {
+ return true;
+ }
+ return false;
+ }
+
+ // XXX non-final for Not, && and ||
+ public boolean matchesStatically(ResolvedType type) {
+ if (includeSubtypes) {
+ return matchesSubtypes(type);
+ } else {
+ return matchesExactly(type);
+ }
+ }
+
+ public abstract FuzzyBoolean matchesInstanceof(ResolvedType type);
+
+ public final FuzzyBoolean matches(ResolvedType type, MatchKind kind) {
+ // FuzzyBoolean typeMatch = null;
+ // ??? This is part of gracefully handling missing references
+ if (type.isMissing()) {
+ return FuzzyBoolean.NO;
+ }
+
+ if (kind == STATIC) {
+ return FuzzyBoolean.fromBoolean(matchesStatically(type));
+ } else if (kind == DYNAMIC) {
+ // System.err.println("matching: " + this + " with " + type);
+ // typeMatch = matchesInstanceof(type);
+ // System.err.println(" got: " + ret);
+ // return typeMatch.and(annotationPattern.matches(type));
+ return matchesInstanceof(type);
+ } else {
+ throw new IllegalArgumentException("kind must be DYNAMIC or STATIC");
+ }
+ }
+
+ protected abstract boolean matchesExactly(ResolvedType type);
+
+ protected abstract boolean matchesExactly(ResolvedType type, ResolvedType annotatedType);
+
+ protected boolean matchesSubtypes(ResolvedType type) {
+ // System.out.println("matching: " + this + " to " + type);
+ if (matchesExactly(type)) {
+ return true;
+ }
+
+ // pr124808
+ Iterator<ResolvedType> typesIterator = null;
+ if (type.isTypeVariableReference()) {
+ typesIterator = ((TypeVariableReference) type).getTypeVariable().getFirstBound().resolve(type.getWorld())
+ .getDirectSupertypes();
+ } else {
+ // pr223605
+ if (type.isRawType()) {
+ type = type.getGenericType();
+ }
+ typesIterator = type.getDirectSupertypes();
+ }
+
+ for (Iterator<ResolvedType> i = typesIterator; i.hasNext();) {
+ ResolvedType superType = i.next();
+ if (matchesSubtypes(superType, type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean matchesSubtypes(ResolvedType superType, ResolvedType annotatedType) {
+ // System.out.println("matching2: " + this + " to " + superType);
+ if (matchesExactly(superType, annotatedType)) {
+ // System.out.println(" true");
+ return true;
+ }
+ // If an ITD is applied, it will be put onto the generic type, not the parameterized or raw form
+ if (superType.isParameterizedType() || superType.isRawType()) {
+ superType = superType.getGenericType();
+ }
+ // FuzzyBoolean ret = FuzzyBoolean.NO; // ??? -eh
+ for (Iterator<ResolvedType> i = superType.getDirectSupertypes(); i.hasNext();) {
+ ResolvedType superSuperType = (ResolvedType) i.next();
+ if (matchesSubtypes(superSuperType, annotatedType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public UnresolvedType resolveExactType(IScope scope, Bindings bindings) {
+ TypePattern p = resolveBindings(scope, bindings, false, true);
+ if (!(p instanceof ExactTypePattern)) {
+ return ResolvedType.MISSING;
+ }
+ return ((ExactTypePattern) p).getType();
+ }
+
+ public UnresolvedType getExactType() {
+ if (this instanceof ExactTypePattern) {
+ return ((ExactTypePattern) this).getType();
+ } else {
+ return ResolvedType.MISSING;
+ }
+ }
+
+ protected TypePattern notExactType(IScope s) {
+ s.getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.EXACT_TYPE_PATTERN_REQD), getSourceLocation()));
+ return NO;
+ }
+
+ // public boolean assertExactType(IMessageHandler m) {
+ // if (this instanceof ExactTypePattern) return true;
+ //
+ // //XXX should try harder to avoid multiple errors for one problem
+ // m.handleMessage(MessageUtil.error("exact type pattern required", getSourceLocation()));
+ // return false;
+ // }
+
+ /**
+ * This can modify in place, or return a new TypePattern if the type changes.
+ */
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
+ return this;
+ }
+
+ public void resolve(World world) {
+ annotationPattern.resolve(world);
+ }
+
+ /**
+ * return a version of this type pattern in which all type variable references have been replaced by their corresponding entry
+ * in the map.
+ */
+ public abstract TypePattern parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w);
+
+ public void postRead(ResolvedType enclosingType) {
+ }
+
+ public boolean isEllipsis() {
+ return false;
+ }
+
+ public boolean isStar() {
+ return false;
+ }
+
+ /**
+ * This is called during concretization of pointcuts, it is used by BindingTypePattern to return a new BindingTypePattern with a
+ * formal index appropiate for the advice, rather than for the lexical declaration, i.e. this handles transforamtions through
+ * named pointcuts.
+ *
+ * <pre>
+ * pointcut foo(String name): args(name);
+ * --&gt; This makes a BindingTypePattern(0) pointing to the 0th formal
+ *
+ * before(Foo f, String n): this(f) &amp;&amp; foo(n) { ... }
+ * --&gt; when resolveReferences is called on the args from the above, it
+ * will return a BindingTypePattern(1)
+ *
+ * before(Foo f): this(f) &amp;&amp; foo(*) { ... }
+ * --&gt; when resolveReferences is called on the args from the above, it
+ * will return an ExactTypePattern(String)
+ * </pre>
+ */
+ public TypePattern remapAdviceFormals(IntMap bindings) {
+ return this;
+ }
+
+ public static final byte WILD = 1;
+ public static final byte EXACT = 2;
+ public static final byte BINDING = 3;
+ public static final byte ELLIPSIS_KEY = 4;
+ public static final byte ANY_KEY = 5;
+ public static final byte NOT = 6;
+ public static final byte OR = 7;
+ public static final byte AND = 8;
+ public static final byte NO_KEY = 9;
+ public static final byte ANY_WITH_ANNO = 10;
+ public static final byte HAS_MEMBER = 11;
+ public static final byte TYPE_CATEGORY = 12;
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte key = s.readByte();
+ switch (key) {
+ case WILD:
+ return WildTypePattern.read(s, context);
+ case EXACT:
+ return ExactTypePattern.read(s, context);
+ case BINDING:
+ return BindingTypePattern.read(s, context);
+ case ELLIPSIS_KEY:
+ return ELLIPSIS;
+ case ANY_KEY:
+ return ANY;
+ case NO_KEY:
+ return NO;
+ case NOT:
+ return NotTypePattern.read(s, context);
+ case OR:
+ return OrTypePattern.read(s, context);
+ case AND:
+ return AndTypePattern.read(s, context);
+ case ANY_WITH_ANNO:
+ return AnyWithAnnotationTypePattern.read(s, context);
+ case HAS_MEMBER:
+ return HasMemberTypePattern.read(s, context);
+ case TYPE_CATEGORY:
+ return TypeCategoryTypePattern.read(s, context);
+ }
+ throw new BCException("unknown TypePattern kind: " + key);
+ }
+
+ public boolean isIncludeSubtypes() {
+ return includeSubtypes;
+ }
+
+ /**
+ * For quickly recognizing the pattern '!void'
+ */
+ public boolean isBangVoid() {
+ return false;
+ }
+
+ /**
+ * for quickly recognizing the pattern 'void'
+ */
+ public boolean isVoid() {
+ return false;
+ }
+
+ public boolean hasFailedResolution() {
+ return false;
+ }
+
+}
+
+
+
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternList.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternList.java
new file mode 100644
index 000000000..da9d6e15a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternList.java
@@ -0,0 +1,585 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvableTypeList;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
+
+public class TypePatternList extends PatternNode {
+ private TypePattern[] typePatterns;
+ int ellipsisCount = 0;
+
+ public static final TypePatternList EMPTY = new TypePatternList(new TypePattern[] {});
+
+ public static final TypePatternList ANY = new TypePatternList(new TypePattern[] { new EllipsisTypePattern() }); // can't use
+
+ // TypePattern.ELLIPSIS
+ // because of
+ // circular
+ // static
+ // dependency
+ // that
+ // introduces
+
+ public TypePatternList() {
+ typePatterns = new TypePattern[0];
+ ellipsisCount = 0;
+ }
+
+ public TypePatternList(TypePattern[] arguments) {
+ this.typePatterns = arguments;
+ for (int i = 0; i < arguments.length; i++) {
+ if (arguments[i] == TypePattern.ELLIPSIS) {
+ ellipsisCount++;
+ }
+ }
+ }
+
+ public TypePatternList(List<TypePattern> l) {
+ this((TypePattern[]) l.toArray(new TypePattern[l.size()]));
+ }
+
+ public int size() {
+ return typePatterns.length;
+ }
+
+ public TypePattern get(int index) {
+ return typePatterns[index];
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("(");
+ for (int i = 0, len = typePatterns.length; i < len; i++) {
+ TypePattern type = typePatterns[i];
+ if (i > 0) {
+ buf.append(", ");
+ }
+ if (type == TypePattern.ELLIPSIS) {
+ buf.append("..");
+ } else {
+ buf.append(type.toString());
+ }
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ /*
+ * return true iff this pattern could ever match a signature with the given number of parameters
+ */
+ public boolean canMatchSignatureWithNParameters(int numParams) {
+ if (ellipsisCount == 0) {
+ return numParams == size();
+ } else {
+ return (size() - ellipsisCount) <= numParams;
+ }
+ }
+
+ public FuzzyBoolean matches(ResolvedType[] types, TypePattern.MatchKind kind) {
+ return matches(types, kind, null);
+ }
+
+ // XXX shares much code with WildTypePattern and with NamePattern
+ /**
+ * When called with TypePattern.STATIC this will always return either FuzzyBoolean.YES or FuzzyBoolean.NO.
+ *
+ * When called with TypePattern.DYNAMIC this could return MAYBE if at runtime it would be possible for arguments of the given
+ * static types to dynamically match this, but it is not known for certain.
+ *
+ * This method will never return FuzzyBoolean.NEVER
+ */
+ public FuzzyBoolean matches(ResolvedType[] types, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
+ int nameLength = types.length;
+ int patternLength = typePatterns.length;
+
+ int nameIndex = 0;
+ int patternIndex = 0;
+
+ if (ellipsisCount == 0) {
+ if (nameLength != patternLength) {
+ return FuzzyBoolean.NO;
+ }
+ FuzzyBoolean finalReturn = FuzzyBoolean.YES;
+ while (patternIndex < patternLength) {
+ ResolvedType t = types[nameIndex];
+ FuzzyBoolean ret = null;
+ try {
+ if (parameterAnnotations != null) {
+ t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
+ }
+ ret = typePatterns[patternIndex].matches(t, kind);
+ } finally {
+ t.temporaryAnnotationTypes = null;
+ }
+ patternIndex++;
+ nameIndex++;
+ if (ret == FuzzyBoolean.NO) {
+ return ret;
+ }
+ if (ret == FuzzyBoolean.MAYBE) {
+ finalReturn = ret;
+ }
+ }
+ return finalReturn;
+ } else if (ellipsisCount == 1) {
+ if (nameLength < patternLength - 1) {
+ return FuzzyBoolean.NO;
+ }
+ FuzzyBoolean finalReturn = FuzzyBoolean.YES;
+ while (patternIndex < patternLength) {
+ TypePattern p = typePatterns[patternIndex++];
+ if (p == TypePattern.ELLIPSIS) {
+ nameIndex = nameLength - (patternLength - patternIndex);
+ } else {
+ ResolvedType t = types[nameIndex];
+ FuzzyBoolean ret = null;
+ try {
+ if (parameterAnnotations != null) {
+ t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
+ }
+ ret = p.matches(t, kind);
+ } finally {
+ t.temporaryAnnotationTypes = null;
+ }
+ nameIndex++;
+ if (ret == FuzzyBoolean.NO) {
+ return ret;
+ }
+ if (ret == FuzzyBoolean.MAYBE) {
+ finalReturn = ret;
+ }
+ }
+ }
+ return finalReturn;
+ } else {
+ // System.err.print("match(" + arguments + ", " + types + ") -> ");
+ FuzzyBoolean b = outOfStar(typePatterns, types, 0, 0, patternLength - ellipsisCount, nameLength, ellipsisCount, kind,
+ parameterAnnotations);
+ // System.err.println(b);
+ return b;
+ }
+ }
+
+ private static FuzzyBoolean outOfStar(final TypePattern[] pattern, final ResolvedType[] target, int pi, int ti, int pLeft,
+ int tLeft, final int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
+ if (pLeft > tLeft) {
+ return FuzzyBoolean.NO;
+ }
+ FuzzyBoolean finalReturn = FuzzyBoolean.YES;
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
+ if (tLeft == 0) {
+ return finalReturn;
+ }
+ if (pLeft == 0) {
+ if (starsLeft > 0) {
+ return finalReturn;
+ } else {
+ return FuzzyBoolean.NO;
+ }
+ }
+ if (pattern[pi] == TypePattern.ELLIPSIS) {
+ return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1, kind, parameterAnnotations);
+ }
+ FuzzyBoolean ret = null;
+ try {
+ if (parameterAnnotations != null) {
+ target[ti].temporaryAnnotationTypes = parameterAnnotations[ti];
+ }
+ ret = pattern[pi].matches(target[ti], kind);
+ } finally {
+ target[ti].temporaryAnnotationTypes = null;
+ }
+ if (ret == FuzzyBoolean.NO) {
+ return ret;
+ }
+ if (ret == FuzzyBoolean.MAYBE) {
+ finalReturn = ret;
+ }
+ pi++;
+ ti++;
+ pLeft--;
+ tLeft--;
+ }
+ }
+
+ private static FuzzyBoolean inStar(final TypePattern[] pattern, final ResolvedType[] target, int pi, int ti, final int pLeft,
+ int tLeft, int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
+ // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
+ TypePattern patternChar = pattern[pi];
+ while (patternChar == TypePattern.ELLIPSIS) {
+ starsLeft--;
+ patternChar = pattern[++pi];
+ }
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length)
+ if (pLeft > tLeft) {
+ return FuzzyBoolean.NO;
+ }
+
+ FuzzyBoolean ff = null;
+ try {
+ if (parameterAnnotations != null) {
+ target[ti].temporaryAnnotationTypes = parameterAnnotations[ti];
+ }
+ ff = patternChar.matches(target[ti], kind);
+ } finally {
+ target[ti].temporaryAnnotationTypes = null;
+ }
+
+ if (ff.maybeTrue()) {
+ FuzzyBoolean xx = outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft, kind,
+ parameterAnnotations);
+ if (xx.maybeTrue()) {
+ return ff.and(xx);
+ }
+ }
+ ti++;
+ tLeft--;
+ }
+ }
+
+ public FuzzyBoolean matches(ResolvableTypeList types, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
+ int nameLength = types.length;
+ int patternLength = typePatterns.length;
+
+ int nameIndex = 0;
+ int patternIndex = 0;
+
+ if (ellipsisCount == 0) {
+ if (nameLength != patternLength) {
+ return FuzzyBoolean.NO;
+ }
+ FuzzyBoolean finalReturn = FuzzyBoolean.YES;
+ while (patternIndex < patternLength) {
+ ResolvedType t = types.getResolved(nameIndex);
+ FuzzyBoolean ret = null;
+ try {
+ if (parameterAnnotations != null) {
+ t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
+ }
+ ret = typePatterns[patternIndex].matches(t, kind);
+ } finally {
+ t.temporaryAnnotationTypes = null;
+ }
+ patternIndex++;
+ nameIndex++;
+ if (ret == FuzzyBoolean.NO) {
+ return ret;
+ }
+ if (ret == FuzzyBoolean.MAYBE) {
+ finalReturn = ret;
+ }
+ }
+ return finalReturn;
+ } else if (ellipsisCount == 1) {
+ if (nameLength < patternLength - 1) {
+ return FuzzyBoolean.NO;
+ }
+ FuzzyBoolean finalReturn = FuzzyBoolean.YES;
+ while (patternIndex < patternLength) {
+ TypePattern p = typePatterns[patternIndex++];
+ if (p == TypePattern.ELLIPSIS) {
+ nameIndex = nameLength - (patternLength - patternIndex);
+ } else {
+ ResolvedType t = types.getResolved(nameIndex);
+ FuzzyBoolean ret = null;
+ try {
+ if (parameterAnnotations != null) {
+ t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
+ }
+ ret = p.matches(t, kind);
+ } finally {
+ t.temporaryAnnotationTypes = null;
+ }
+ nameIndex++;
+ if (ret == FuzzyBoolean.NO) {
+ return ret;
+ }
+ if (ret == FuzzyBoolean.MAYBE) {
+ finalReturn = ret;
+ }
+ }
+ }
+ return finalReturn;
+ } else {
+ // System.err.print("match(" + arguments + ", " + types + ") -> ");
+ FuzzyBoolean b = outOfStar(typePatterns, types, 0, 0, patternLength - ellipsisCount, nameLength, ellipsisCount, kind,
+ parameterAnnotations);
+ // System.err.println(b);
+ return b;
+ }
+ }
+
+ private static FuzzyBoolean outOfStar(final TypePattern[] pattern, ResolvableTypeList target, int pi, int ti, int pLeft,
+ int tLeft, final int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
+ if (pLeft > tLeft) {
+ return FuzzyBoolean.NO;
+ }
+ FuzzyBoolean finalReturn = FuzzyBoolean.YES;
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
+ if (tLeft == 0) {
+ return finalReturn;
+ }
+ if (pLeft == 0) {
+ if (starsLeft > 0) {
+ return finalReturn;
+ } else {
+ return FuzzyBoolean.NO;
+ }
+ }
+ if (pattern[pi] == TypePattern.ELLIPSIS) {
+ return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1, kind, parameterAnnotations);
+ }
+ FuzzyBoolean ret = null;
+ ResolvedType type = target.getResolved(ti);
+ try {
+ if (parameterAnnotations != null) {
+ type.temporaryAnnotationTypes = parameterAnnotations[ti];
+ }
+ ret = pattern[pi].matches(type, kind);
+ } finally {
+ type.temporaryAnnotationTypes = null;
+ }
+ if (ret == FuzzyBoolean.NO) {
+ return ret;
+ }
+ if (ret == FuzzyBoolean.MAYBE) {
+ finalReturn = ret;
+ }
+ pi++;
+ ti++;
+ pLeft--;
+ tLeft--;
+ }
+ }
+
+ private static FuzzyBoolean inStar(final TypePattern[] pattern, ResolvableTypeList target, int pi, int ti, final int pLeft,
+ int tLeft, int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
+ // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
+ TypePattern patternChar = pattern[pi];
+ while (patternChar == TypePattern.ELLIPSIS) {
+ starsLeft--;
+ patternChar = pattern[++pi];
+ }
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length)
+ if (pLeft > tLeft) {
+ return FuzzyBoolean.NO;
+ }
+
+ ResolvedType type = target.getResolved(ti);
+ FuzzyBoolean ff = null;
+ try {
+ if (parameterAnnotations != null) {
+ type.temporaryAnnotationTypes = parameterAnnotations[ti];
+ }
+ ff = patternChar.matches(type, kind);
+ } finally {
+ type.temporaryAnnotationTypes = null;
+ }
+
+ if (ff.maybeTrue()) {
+ FuzzyBoolean xx = outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft, kind,
+ parameterAnnotations);
+ if (xx.maybeTrue()) {
+ return ff.and(xx);
+ }
+ }
+ ti++;
+ tLeft--;
+ }
+ }
+
+ /**
+ * Return a version of this type pattern list in which all type variable references are replaced by their corresponding entry in
+ * the map
+ *
+ * @param typeVariableMap
+ * @return
+ */
+ public TypePatternList parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ TypePattern[] parameterizedPatterns = new TypePattern[typePatterns.length];
+ for (int i = 0; i < parameterizedPatterns.length; i++) {
+ parameterizedPatterns[i] = typePatterns[i].parameterizeWith(typeVariableMap, w);
+ }
+ return new TypePatternList(parameterizedPatterns);
+ }
+
+ public TypePatternList resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ for (int i = 0; i < typePatterns.length; i++) {
+ TypePattern p = typePatterns[i];
+ if (p != null) {
+ typePatterns[i] = typePatterns[i].resolveBindings(scope, bindings, allowBinding, requireExactType);
+ }
+ }
+ return this;
+ }
+
+ public TypePatternList resolveReferences(IntMap bindings) {
+ int len = typePatterns.length;
+ TypePattern[] ret = new TypePattern[len];
+ for (int i = 0; i < len; i++) {
+ ret[i] = typePatterns[i].remapAdviceFormals(bindings);
+ }
+ return new TypePatternList(ret);
+ }
+
+ public void postRead(ResolvedType enclosingType) {
+ for (int i = 0; i < typePatterns.length; i++) {
+ TypePattern p = typePatterns[i];
+ p.postRead(enclosingType);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof TypePatternList)) {
+ return false;
+ }
+ TypePatternList o = (TypePatternList) other;
+ int len = o.typePatterns.length;
+ if (len != this.typePatterns.length) {
+ return false;
+ }
+ for (int i = 0; i < len; i++) {
+ if (!this.typePatterns[i].equals(o.typePatterns[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 41;
+ for (int i = 0, len = typePatterns.length; i < len; i++) {
+ result = 37 * result + typePatterns[i].hashCode();
+ }
+ return result;
+ }
+
+ public static TypePatternList read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ short len = s.readShort();
+ TypePattern[] arguments = new TypePattern[len];
+ for (int i = 0; i < len; i++) {
+ arguments[i] = TypePattern.read(s, context);
+ }
+ TypePatternList ret = new TypePatternList(arguments);
+ if (!s.isAtLeast169()) {
+ ret.readLocation(context, s);
+ }
+ return ret;
+ }
+
+ @Override
+ public int getEnd() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public ISourceContext getSourceContext() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public ISourceLocation getSourceLocation() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public int getStart() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeShort(typePatterns.length);
+ for (int i = 0; i < typePatterns.length; i++) {
+ typePatterns[i].write(s);
+ }
+ // writeLocation(s);
+ }
+
+ public TypePattern[] getTypePatterns() {
+ return typePatterns;
+ }
+
+ public List<UnresolvedType> getExactTypes() {
+ List<UnresolvedType> ret = new ArrayList<UnresolvedType>();
+ for (int i = 0; i < typePatterns.length; i++) {
+ UnresolvedType t = typePatterns[i].getExactType();
+ if (!ResolvedType.isMissing(t)) {
+ ret.add(t);
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ @Override
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ for (int i = 0; i < typePatterns.length; i++) {
+ typePatterns[i].traverse(visitor, ret);
+ }
+ return ret;
+ }
+
+ public boolean areAllExactWithNoSubtypesAllowed() {
+ for (int i = 0; i < typePatterns.length; i++) {
+ TypePattern array_element = typePatterns[i];
+ if (!(array_element instanceof ExactTypePattern)) {
+ return false;
+ } else {
+ ExactTypePattern etp = (ExactTypePattern) array_element;
+ if (etp.isIncludeSubtypes()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public String[] maybeGetCleanNames() {
+ String[] theParamNames = new String[typePatterns.length];
+ for (int i = 0; i < typePatterns.length; i++) {
+ TypePattern string = typePatterns[i];
+ if (!(string instanceof ExactTypePattern)) {
+ return null;
+ }
+ theParamNames[i] = ((ExactTypePattern) string).getExactType().getName();
+ }
+ return theParamNames;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternQuestions.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternQuestions.java
new file mode 100644
index 000000000..d4bdf2e58
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypePatternQuestions.java
@@ -0,0 +1,106 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.ResolvedType;
+
+
+public class TypePatternQuestions {
+ private Map<Question,FuzzyBoolean> questionsAndAnswers = new HashMap<Question,FuzzyBoolean>();
+
+ public FuzzyBoolean askQuestion(TypePattern pattern, ResolvedType type,
+ TypePattern.MatchKind kind)
+ {
+ Question question = new Question(pattern, type, kind);
+ //??? should we use this table to do caching or is that a pessimization
+ //??? if we do that optimization we can also do error checking that the result
+ //??? doesn't change
+ FuzzyBoolean answer = question.ask();
+ questionsAndAnswers.put(question, answer);
+ return answer;
+ }
+
+ public Question anyChanges() {
+ for (Iterator<Map.Entry<Question,FuzzyBoolean>> i = questionsAndAnswers.entrySet().iterator(); i.hasNext(); ) {
+ Map.Entry<Question,FuzzyBoolean> entry = i.next();
+ Question question = (Question)entry.getKey();
+ FuzzyBoolean expectedAnswer = (FuzzyBoolean)entry.getValue();
+
+ FuzzyBoolean currentAnswer = question.ask();
+ //System.out.println(question + ":" + currentAnswer);
+ if (currentAnswer != expectedAnswer) {
+ return question;
+ }
+ }
+
+ return null;
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("TypePatternQuestions{");
+ for (Map.Entry<Question,FuzzyBoolean> entry: questionsAndAnswers.entrySet()) {
+ Question question = (Question)entry.getKey();
+ FuzzyBoolean expectedAnswer = (FuzzyBoolean)entry.getValue();
+ buf.append(question);
+ buf.append(":");
+ buf.append(expectedAnswer);
+ buf.append(", ");
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+
+ public class Question {
+ TypePattern pattern;
+ ResolvedType type;
+ TypePattern.MatchKind kind;
+
+ public Question(TypePattern pattern, ResolvedType type,
+ TypePattern.MatchKind kind) {
+ super();
+ this.pattern = pattern;
+ this.type = type;
+ this.kind = kind;
+ }
+
+ public FuzzyBoolean ask() {
+ return pattern.matches(type, kind);
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof Question)) return false;
+ Question o = (Question)other;
+ return o.pattern.equals(pattern) && o.type.equals(type) && o.kind == kind;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37*result + kind.hashCode();
+ result = 37*result + pattern.hashCode();
+ result = 37*result + type.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return "?(" + pattern + ", " + type + ", " + kind + ")";
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePattern.java
new file mode 100644
index 000000000..c2d4bd0ec
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePattern.java
@@ -0,0 +1,243 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+
+/**
+ * @author colyer Represents a type variable as declared as part of a type declaration, parameter declaration, or type parameter
+ * specification.
+ * <p>
+ * For example:
+ * </p>
+ * <ul>
+ * <li>&lt;T&gt; T genericMethod(T t) {...}</li>
+ * <li>static &lt;T extends Foo&gt; T staticGenericMethod(T t) {...}</li>
+ * <li>Foo&lt;T extends Bar &amp; IGoo&gt;
+ * </ul>
+ */
+public class TypeVariablePattern extends PatternNode {
+
+ private static final String anything = "?";
+
+ private String name; // eg. "T"
+ private TypePattern upperBound; // default is object unless of the form T extends Bar
+ private TypePattern[] interfaceBounds; // additional upper bounds (must be interfaces) arising from
+ // declarations of the form T extends Bar & IGoo, IDoo
+ private TypePattern lowerBound; // only set if type variable is of the form T super Bar
+
+ /**
+ * Create a named type variable with upper bound Object and no lower bounds. Use this constructor for the simple "T" case
+ */
+ public TypeVariablePattern(String variableName) {
+ this.name = variableName;
+ this.upperBound = new ExactTypePattern(UnresolvedType.OBJECT, false, false);
+ this.lowerBound = null;
+ this.interfaceBounds = null;
+ }
+
+ /**
+ * Create a named type variable with the given upper bound and no lower bounds Use this constructor for the T extends Foo case
+ *
+ * @param variableName
+ * @param upperBound
+ */
+ public TypeVariablePattern(String variableName, TypePattern upperBound) {
+ this.name = variableName;
+ this.upperBound = upperBound;
+ this.lowerBound = null;
+ this.interfaceBounds = null;
+ }
+
+ public TypeVariablePattern(String variableName, TypePattern upperLimit, TypePattern[] interfaceBounds, TypePattern lowerBound) {
+ this.name = variableName;
+ this.upperBound = upperLimit;
+ if (upperBound == null) {
+ upperBound = new ExactTypePattern(UnresolvedType.OBJECT, false, false);
+ }
+ this.interfaceBounds = interfaceBounds;
+ this.lowerBound = lowerBound;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isAnythingPattern() {
+ return name.equals(anything);
+ }
+
+ public TypePattern getRawTypePattern() {
+ return upperBound;
+ }
+
+ public TypePattern getUpperBound() {
+ return upperBound;
+ }
+
+ public boolean hasLowerBound() {
+ return (lowerBound != null);
+ }
+
+ public TypePattern getLowerBound() {
+ return lowerBound;
+ }
+
+ public boolean hasAdditionalInterfaceBounds() {
+ return (interfaceBounds != null);
+ }
+
+ public TypePattern[] getAdditionalInterfaceBounds() {
+ if (interfaceBounds != null) {
+ return interfaceBounds;
+ } else {
+ return new TypePattern[0];
+ }
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof TypeVariablePattern)) {
+ return false;
+ }
+ TypeVariablePattern other = (TypeVariablePattern) obj;
+ if (!name.equals(other.name)) {
+ return false;
+ }
+ if (!upperBound.equals(other.upperBound)) {
+ return false;
+ }
+ if (lowerBound != null) {
+ if (other.lowerBound == null) {
+ return false;
+ }
+ if (!lowerBound.equals(other.lowerBound)) {
+ return false;
+ }
+ } else {
+ if (other.lowerBound != null) {
+ return false;
+ }
+ }
+ if (interfaceBounds != null) {
+ if (other.interfaceBounds == null) {
+ return false;
+ }
+ if (interfaceBounds.length != other.interfaceBounds.length) {
+ return false;
+ }
+ for (int i = 0; i < interfaceBounds.length; i++) {
+ if (!interfaceBounds[i].equals(other.interfaceBounds[i])) {
+ return false;
+ }
+ }
+ } else {
+ if (other.interfaceBounds != null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ int hashCode = 17 + (37 * name.hashCode());
+ hashCode = hashCode * 37 + upperBound.hashCode();
+ if (lowerBound != null) {
+ hashCode = hashCode * 37 + lowerBound.hashCode();
+ }
+ if (interfaceBounds != null) {
+ for (int i = 0; i < interfaceBounds.length; i++) {
+ hashCode = 37 * hashCode + interfaceBounds[i].hashCode();
+ }
+ }
+ return hashCode;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(name);
+ sb.append(getExtendsClause());
+ if (interfaceBounds != null) {
+ sb.append(" & ");
+ for (int i = 0; i < interfaceBounds.length; i++) {
+ sb.append(interfaceBounds[i].toString());
+ if (i < interfaceBounds.length) {
+ sb.append(",");
+ }
+ }
+ }
+ if (lowerBound != null) {
+ sb.append(" super ");
+ sb.append(lowerBound.toString());
+ }
+ return sb.toString();
+ }
+
+ private String getExtendsClause() {
+ if (upperBound instanceof ExactTypePattern) {
+ ExactTypePattern bound = (ExactTypePattern) upperBound;
+ if (bound.type == UnresolvedType.OBJECT) {
+ return "";
+ }
+ }
+ return " extends " + upperBound.toString();
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeUTF(name);
+ upperBound.write(s);
+ if (interfaceBounds == null) {
+ s.writeInt(0);
+ } else {
+ s.writeInt(interfaceBounds.length);
+ for (int i = 0; i < interfaceBounds.length; i++) {
+ interfaceBounds[i].write(s);
+ }
+ }
+ s.writeBoolean(hasLowerBound());
+ if (hasLowerBound()) {
+ lowerBound.write(s);
+ }
+ writeLocation(s);
+ }
+
+ public static TypeVariablePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ TypeVariablePattern tv = null;
+ String name = s.readUTF();
+ TypePattern upperBound = TypePattern.read(s, context);
+ TypePattern[] additionalInterfaceBounds = null;
+ int numInterfaceBounds = s.readInt();
+ if (numInterfaceBounds > 0) {
+ additionalInterfaceBounds = new TypePattern[numInterfaceBounds];
+ for (int i = 0; i < additionalInterfaceBounds.length; i++) {
+ additionalInterfaceBounds[i] = TypePattern.read(s, context);
+ }
+ }
+ boolean hasLowerBound = s.readBoolean();
+ TypePattern lowerBound = null;
+ if (hasLowerBound) {
+ lowerBound = TypePattern.read(s, context);
+ }
+ tv = new TypeVariablePattern(name, upperBound, additionalInterfaceBounds, lowerBound);
+ tv.readLocation(context, s);
+ return tv;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePatternList.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePatternList.java
new file mode 100644
index 000000000..7bbe67872
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/TypeVariablePatternList.java
@@ -0,0 +1,84 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.VersionedDataInputStream;
+
+/**
+ * @author colyer A list of type variable specifications, eg. &lt;T,S&gt;
+ */
+public class TypeVariablePatternList extends PatternNode {
+
+ public static final TypeVariablePatternList EMPTY = new TypeVariablePatternList(new TypeVariablePattern[0]);
+
+ private TypeVariablePattern[] patterns;
+
+ public TypeVariablePatternList(TypeVariablePattern[] typeVars) {
+ this.patterns = typeVars;
+ }
+
+ public TypeVariablePattern[] getTypeVariablePatterns() {
+ return this.patterns;
+ }
+
+ public TypeVariablePattern lookupTypeVariable(String name) {
+ for (int i = 0; i < patterns.length; i++) {
+ if (patterns[i].getName().equals(name)) {
+ return patterns[i];
+ }
+ }
+ return null;
+ }
+
+ public boolean isEmpty() {
+ return ((patterns == null) || (patterns.length == 0));
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeInt(patterns.length);
+ for (int i = 0; i < patterns.length; i++) {
+ patterns[i].write(s);
+ }
+ writeLocation(s);
+ }
+
+ public static TypeVariablePatternList read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ TypeVariablePatternList ret = EMPTY;
+ int length = s.readInt();
+ if (length > 0) {
+ TypeVariablePattern[] patterns = new TypeVariablePattern[length];
+ for (int i = 0; i < patterns.length; i++) {
+ patterns[i] = TypeVariablePattern.read(s, context);
+ }
+ ret = new TypeVariablePatternList(patterns);
+ }
+ ret.readLocation(context, s); // redundant but safe to read location for EMPTY
+ return ret;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public Object traverse(PatternNodeVisitor visitor, Object data) {
+ Object ret = accept(visitor, data);
+ for (int i = 0; i < patterns.length; i++) {
+ patterns[i].traverse(visitor, ret);
+ }
+ return ret;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildAnnotationTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildAnnotationTypePattern.java
new file mode 100644
index 000000000..0941462d1
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildAnnotationTypePattern.java
@@ -0,0 +1,434 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.AnnotatedElement;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * @author colyer
+ * @author Andy Clement
+ */
+public class WildAnnotationTypePattern extends AnnotationTypePattern {
+
+ private TypePattern typePattern;
+ private boolean resolved = false;
+ Map<String, String> annotationValues;
+
+ public WildAnnotationTypePattern(TypePattern typePattern) {
+ super();
+ this.typePattern = typePattern;
+ this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);
+ }
+
+ public WildAnnotationTypePattern(TypePattern typePattern, Map<String, String> annotationValues) {
+ super();
+ this.typePattern = typePattern;
+ this.annotationValues = annotationValues;
+ // PVAL make the location be from start of type pattern to end of values
+ this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);
+ }
+
+ public TypePattern getTypePattern() {
+ return typePattern;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.AnnotationTypePattern#matches(org.aspectj.weaver.AnnotatedElement)
+ */
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated) {
+ return matches(annotated, null);
+ }
+
+ /**
+ * Resolve any annotation values specified, checking they are all well formed (valid names, valid values)
+ *
+ * @param annotationType the annotation type for which the values have been specified
+ * @param scope the scope within which to resolve type references (eg. Color.GREEN)
+ */
+ protected void resolveAnnotationValues(ResolvedType annotationType, IScope scope) {
+ if (annotationValues == null) {
+ return;
+ }
+ // Check any values specified are OK:
+ // - the value names are for valid annotation fields
+ // - the specified values are of the correct type
+ // - for enums, check the specified values can be resolved in the specified scope
+ Map<String,String> replacementValues = new HashMap<String,String>();
+ Set<String> keys = annotationValues.keySet();
+ ResolvedMember[] ms = annotationType.getDeclaredMethods();
+ for (String k: keys) {
+ String key = k;
+ // a trailing ! indicates the the user expressed key!=value rather than key=value as a match constraint
+ if (k.endsWith("!")) {
+ key = key.substring(0, k.length() - 1);
+ }
+ String v = annotationValues.get(k);
+ boolean validKey = false;
+ for (int i = 0; i < ms.length; i++) {
+ ResolvedMember resolvedMember = ms[i];
+ if (resolvedMember.getName().equals(key) && resolvedMember.isAbstract()) {
+ validKey = true;
+ ResolvedType t = resolvedMember.getReturnType().resolve(scope.getWorld());
+ if (t.isEnum()) {
+ // value must be an enum reference X.Y
+ int pos = v.lastIndexOf(".");
+ if (pos == -1) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "enum"), getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ } else {
+ String typename = v.substring(0, pos);
+ ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
+ v = rt.getSignature() + v.substring(pos + 1); // from 'Color.RED' to 'Lp/Color;RED'
+ replacementValues.put(k, v);
+ break;
+ }
+ } else if (t.isPrimitiveType()) {
+ if (t.getSignature().equals("I")) {
+ try {
+ int value = Integer.parseInt(v);
+ replacementValues.put(k, Integer.toString(value));
+ break;
+ } catch (NumberFormatException nfe) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "int"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ } else if (t.getSignature().equals("F")) {
+ try {
+ float value = Float.parseFloat(v);
+ replacementValues.put(k, Float.toString(value));
+ break;
+ } catch (NumberFormatException nfe) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "float"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+
+ } else if (t.getSignature().equals("Z")) {
+ if (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("false")) {
+ // is it ok !
+ } else {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "boolean"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ } else if (t.getSignature().equals("S")) {
+ try {
+ short value = Short.parseShort(v);
+ replacementValues.put(k, Short.toString(value));
+ break;
+ } catch (NumberFormatException nfe) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "short"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ } else if (t.getSignature().equals("J")) {
+ try {
+ replacementValues.put(k, Long.toString(Long.parseLong(v)));
+ break;
+ } catch (NumberFormatException nfe) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "long"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ } else if (t.getSignature().equals("D")) {
+ try {
+ replacementValues.put(k, Double.toString(Double.parseDouble(v)));
+ break;
+ } catch (NumberFormatException nfe) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "double"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ } else if (t.getSignature().equals("B")) {
+ try {
+ replacementValues.put(k, Byte.toString(Byte.parseByte(v)));
+ break;
+ } catch (NumberFormatException nfe) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "byte"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ } else if (t.getSignature().equals("C")) {
+ if (v.length() != 3) { // '?'
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "char"),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ } else {
+ replacementValues.put(k, v.substring(1, 2));
+ break;
+ }
+ } else {
+ throw new RuntimeException("Not implemented for " + t);
+ }
+ } else if (t.equals(ResolvedType.JL_STRING)) {
+ // nothing to do, it will be OK
+ } else if (t.equals(ResolvedType.JL_CLASS) || (t.isParameterizedOrGenericType() && t.getRawType().equals(ResolvedType.JL_CLASS))) {
+ String typename = v.substring(0, v.lastIndexOf('.')); // strip off '.class'
+ ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
+ if (rt.isMissing()) {
+ IMessage m = MessageUtil.error("Unable to resolve type '" + v + "' specified for value '" + k + "'",
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ replacementValues.put(k, rt.getSignature());
+ break;
+ } else {
+ if (t.isAnnotation()) {
+ if (v.indexOf("(") != -1) {
+ throw new RuntimeException(
+ "Compiler limitation: annotation values can only currently be marker annotations (no values): "
+ + v);
+ }
+ String typename = v.substring(1);
+ ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
+ if (rt.isMissing()) {
+ IMessage m = MessageUtil.error(
+ "Unable to resolve type '" + v + "' specified for value '" + k + "'", getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ replacementValues.put(k, rt.getSignature());
+ break;
+// } else if (t.isArray()) {
+ // Looks like {} aren't pseudotokens in the parser so they don't get through for our pointcut parser
+// // @Foo(value=[Foo.class])
+// String typename = v.substring(0, v.lastIndexOf('.')); // strip off '.class'
+// ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
+// if (rt.isMissing()) {
+// IMessage m = MessageUtil.error("Unable to resolve type '" + v + "' specified for value '" + k + "'",
+// getSourceLocation());
+// scope.getWorld().getMessageHandler().handleMessage(m);
+// }
+// replacementValues.put(k, rt.getSignature());
+ } else {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.UNSUPPORTED_ANNOTATION_VALUE_TYPE,t), getSourceLocation()));
+ replacementValues.put(k,"");
+ }
+ }
+ }
+ }
+ if (!validKey) {
+ IMessage m = MessageUtil.error(WeaverMessages.format(WeaverMessages.UNKNOWN_ANNOTATION_VALUE, annotationType, k),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ }
+ }
+ annotationValues.putAll(replacementValues);
+ }
+
+ @Override
+ public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
+ if (!resolved) {
+ throw new IllegalStateException("Can't match on an unresolved annotation type pattern");
+ }
+ if (annotationValues != null && !typePattern.hasFailedResolution()) {
+ // PVAL improve this restriction, would allow '*(value=Color.RED)'
+ throw new IllegalStateException("Cannot use annotationvalues with a wild annotation pattern");
+ }
+ if (isForParameterAnnotationMatch()) {
+ if (parameterAnnotations != null && parameterAnnotations.length != 0) {
+ for (int i = 0; i < parameterAnnotations.length; i++) {
+ if (typePattern.matches(parameterAnnotations[i], TypePattern.STATIC).alwaysTrue()) {
+ return FuzzyBoolean.YES;
+ }
+ }
+ }
+ } else {
+ // matches if the type of any of the annotations on the AnnotatedElement is
+ // matched by the typePattern.
+ ResolvedType[] annTypes = annotated.getAnnotationTypes();
+ if (annTypes != null && annTypes.length != 0) {
+ for (int i = 0; i < annTypes.length; i++) {
+ if (typePattern.matches(annTypes[i], TypePattern.STATIC).alwaysTrue()) {
+ return FuzzyBoolean.YES;
+ }
+ }
+ }
+ }
+ return FuzzyBoolean.NO;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.AnnotationTypePattern#resolve(org.aspectj.weaver.World)
+ */
+ @Override
+ public void resolve(World world) {
+ if (!resolved) {
+ // attempt resolution - this helps with the Spring bug where they resolve() the pointcut in no scope (SPR-5307)
+ if (typePattern instanceof WildTypePattern && (annotationValues == null || annotationValues.isEmpty())) {
+ WildTypePattern wildTypePattern = (WildTypePattern) typePattern;
+ String fullyQualifiedName = wildTypePattern.maybeGetCleanName();
+ if (fullyQualifiedName != null && fullyQualifiedName.indexOf(".") != -1) {
+ ResolvedType resolvedType = world.resolve(UnresolvedType.forName(fullyQualifiedName));
+ if (resolvedType != null && !resolvedType.isMissing()) {
+ typePattern = new ExactTypePattern(resolvedType, false, false);
+ }
+ }
+ }
+ resolved = true;
+ }
+ }
+
+ /**
+ * This can modify in place, or return a new TypePattern if the type changes.
+ */
+ @Override
+ public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
+ if (!scope.getWorld().isInJava5Mode()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ANNOTATIONS_NEED_JAVA5), getSourceLocation()));
+ return this;
+ }
+ if (resolved) {
+ return this;
+ }
+ this.typePattern = typePattern.resolveBindings(scope, bindings, false, false);
+ resolved = true;
+ if (typePattern instanceof ExactTypePattern) {
+ ExactTypePattern et = (ExactTypePattern) typePattern;
+ if (!et.getExactType().resolve(scope.getWorld()).isAnnotation()) {
+ IMessage m = MessageUtil.error(
+ WeaverMessages.format(WeaverMessages.REFERENCE_TO_NON_ANNOTATION_TYPE, et.getExactType().getName()),
+ getSourceLocation());
+ scope.getWorld().getMessageHandler().handleMessage(m);
+ resolved = false;
+ }
+ ResolvedType annotationType = et.getExactType().resolve(scope.getWorld());
+ resolveAnnotationValues(annotationType, scope);
+ ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(annotationType, annotationValues);
+ eatp.copyLocationFrom(this);
+ if (isForParameterAnnotationMatch()) {
+ eatp.setForParameterAnnotationMatch();
+ }
+ return eatp;
+ } else {
+ return this;
+ }
+ }
+
+ @Override
+ public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ WildAnnotationTypePattern ret = new WildAnnotationTypePattern(typePattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ ret.resolved = resolved;
+ return ret;
+ }
+
+ private static final byte VERSION = 1; // rev if ser. form changes
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(AnnotationTypePattern.WILD);
+ s.writeByte(VERSION);
+ typePattern.write(s);
+ writeLocation(s);
+ s.writeBoolean(isForParameterAnnotationMatch());
+ // PVAL
+ if (annotationValues == null) {
+ s.writeInt(0);
+ } else {
+ s.writeInt(annotationValues.size());
+ Set<String> key = annotationValues.keySet();
+ for (Iterator<String> keys = key.iterator(); keys.hasNext();) {
+ String k = keys.next();
+ s.writeUTF(k);
+ s.writeUTF(annotationValues.get(k));
+ }
+ }
+ }
+
+ public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ WildAnnotationTypePattern ret;
+ byte version = s.readByte();
+ if (version > VERSION) {
+ throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ");
+ }
+ TypePattern t = TypePattern.read(s, context);
+ ret = new WildAnnotationTypePattern(t);
+ ret.readLocation(context, s);
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) {
+ if (s.readBoolean()) {
+ ret.setForParameterAnnotationMatch();
+ }
+ }
+ if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160M2) {
+ int annotationValueCount = s.readInt();
+ if (annotationValueCount > 0) {
+ Map<String, String> aValues = new HashMap<String, String>();
+ for (int i = 0; i < annotationValueCount; i++) {
+ String key = s.readUTF();
+ String val = s.readUTF();
+ aValues.put(key, val);
+ }
+ ret.annotationValues = aValues;
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof WildAnnotationTypePattern)) {
+ return false;
+ }
+ WildAnnotationTypePattern other = (WildAnnotationTypePattern) obj;
+ return other.typePattern.equals(typePattern)
+ && this.isForParameterAnnotationMatch() == other.isForParameterAnnotationMatch()
+ && (annotationValues == null ? other.annotationValues == null : annotationValues.equals(other.annotationValues));
+ }
+
+ @Override
+ public int hashCode() {
+ return (((17 + 37 * typePattern.hashCode()) * 37 + (isForParameterAnnotationMatch() ? 0 : 1)) * 37)
+ + (annotationValues == null ? 0 : annotationValues.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ return "@(" + typePattern.toString() + ")";
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildChildFinder.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildChildFinder.java
new file mode 100644
index 000000000..500d281e2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildChildFinder.java
@@ -0,0 +1,68 @@
+/* *******************************************************************
+ * Copyright (c) 2019 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+/**
+ * @author Tuomas Kiviaho
+ */
+public class WildChildFinder extends AbstractPatternNodeVisitor {
+
+ private boolean wildChild;
+
+ public WildChildFinder() {
+ super();
+ }
+
+ public boolean containedWildChild() {
+ return wildChild;
+ }
+
+ @Override
+ public Object visit(WildAnnotationTypePattern node, Object data) {
+ node.getTypePattern().accept(this, data);
+ return node;
+ }
+
+ @Override
+ public Object visit(WildTypePattern node, Object data) {
+ this.wildChild = true;
+ return super.visit(node, data);
+ }
+
+ @Override
+ public Object visit(AndTypePattern node, Object data) {
+ node.getLeft().accept(this, data);
+ if (!this.wildChild) {
+ node.getRight().accept(this, data);
+ }
+ return node;
+ }
+
+ @Override
+ public Object visit(OrTypePattern node, Object data) {
+ node.getLeft().accept(this, data);
+ if (!this.wildChild) {
+ node.getRight().accept(this, data);
+ }
+ return node;
+ }
+
+ public Object visit(NotTypePattern node, Object data) {
+ node.getNegatedPattern().accept(this, data);
+ return node;
+ }
+
+ @Override
+ public Object visit(AnyWithAnnotationTypePattern node, Object data) {
+ node.getAnnotationPattern().accept(this, data);
+ return node;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildTypePattern.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildTypePattern.java
new file mode 100644
index 000000000..9081c5c02
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WildTypePattern.java
@@ -0,0 +1,1405 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.Message;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FileUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.AjAttribute;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.BoundedReferenceType;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.IHasPosition;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.TypeFactory;
+import org.aspectj.weaver.TypeVariable;
+import org.aspectj.weaver.TypeVariableReference;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.UnresolvedTypeVariableReferenceType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+
+/**
+ * The PatternParser always creates WildTypePatterns for type patterns in pointcut expressions (apart from *, which is sometimes
+ * directly turned into TypePattern.ANY). resolveBindings() tries to work out what we've really got and turn it into a type pattern
+ * that we can use for matching. This will normally be either an ExactTypePattern or a WildTypePattern.
+ *
+ * Here's how the process pans out for various generic and parameterized patterns: (see GenericsWildTypePatternResolvingTestCase)
+ *
+ * Foo where Foo exists and is generic Parser creates WildTypePattern namePatterns={Foo} resolveBindings resolves Foo to RT(Foo -
+ * raw) return ExactTypePattern(LFoo;)
+ *
+ * Foo<String> where Foo exists and String meets the bounds Parser creates WildTypePattern namePatterns = {Foo},
+ * typeParameters=WTP{String} resolveBindings resolves typeParameters to ExactTypePattern(String) resolves Foo to RT(Foo) returns
+ * ExactTypePattern(PFoo<String>; - parameterized)
+ *
+ * Foo<Str*> where Foo exists and takes one bound Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{Str*}
+ * resolveBindings resolves typeParameters to WTP{Str*} resolves Foo to RT(Foo) returns WildTypePattern(name = Foo, typeParameters =
+ * WTP{Str*} isGeneric=false)
+ *
+ * Fo*<String> Parser creates WildTypePattern namePatterns = {Fo*}, typeParameters=WTP{String} resolveBindings resolves
+ * typeParameters to ETP{String} returns WildTypePattern(name = Fo*, typeParameters = ETP{String} isGeneric=false)
+ *
+ *
+ * Foo<?>
+ *
+ * Foo<? extends Number>
+ *
+ * Foo<? extends Number+>
+ *
+ * Foo<? super Number>
+ *
+ */
+public class WildTypePattern extends TypePattern {
+ private static final String GENERIC_WILDCARD_CHARACTER = "?"; // signature of ? is *
+ private static final String GENERIC_WILDCARD_SIGNATURE_CHARACTER = "*"; // signature of ? is *
+ private NamePattern[] namePatterns;
+ private boolean failedResolution = false;
+ int ellipsisCount;
+ String[] importedPrefixes;
+ String[] knownMatches;
+ int dim;
+
+ // SECRETAPI - just for testing, turns off boundschecking temporarily...
+ public static boolean boundscheckingoff = false;
+
+ // these next three are set if the type pattern is constrained by extends or super clauses, in which case the
+ // namePatterns must have length 1
+ // TODO AMC: read/write/resolve of these fields
+ TypePattern upperBound; // extends Foo
+ TypePattern[] additionalInterfaceBounds; // extends Foo & A,B,C
+ TypePattern lowerBound; // super Foo
+
+ // if we have type parameters, these fields indicate whether we should be a generic type pattern or a parameterized
+ // type pattern. We can only tell during resolve bindings.
+ private boolean isGeneric = true;
+
+ WildTypePattern(NamePattern[] namePatterns, boolean includeSubtypes, int dim, boolean isVarArgs, TypePatternList typeParams) {
+ super(includeSubtypes, isVarArgs, typeParams);
+ this.namePatterns = namePatterns;
+ this.dim = dim;
+ ellipsisCount = 0;
+ for (int i = 0; i < namePatterns.length; i++) {
+ if (namePatterns[i] == NamePattern.ELLIPSIS) {
+ ellipsisCount++;
+ }
+ }
+ setLocation(namePatterns[0].getSourceContext(), namePatterns[0].getStart(), namePatterns[namePatterns.length - 1].getEnd());
+ }
+
+ public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim) {
+ this((NamePattern[]) names.toArray(new NamePattern[names.size()]), includeSubtypes, dim, false, TypePatternList.EMPTY);
+
+ }
+
+ public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos) {
+ this(names, includeSubtypes, dim);
+ this.end = endPos;
+ }
+
+ public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg) {
+ this(names, includeSubtypes, dim);
+ this.end = endPos;
+ this.isVarArgs = isVarArg;
+ }
+
+ public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg, TypePatternList typeParams,
+ TypePattern upperBound, TypePattern[] additionalInterfaceBounds, TypePattern lowerBound) {
+ this((NamePattern[]) names.toArray(new NamePattern[names.size()]), includeSubtypes, dim, isVarArg, typeParams);
+ this.end = endPos;
+ this.upperBound = upperBound;
+ this.lowerBound = lowerBound;
+ this.additionalInterfaceBounds = additionalInterfaceBounds;
+ }
+
+ public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg, TypePatternList typeParams) {
+ this((NamePattern[]) names.toArray(new NamePattern[names.size()]), includeSubtypes, dim, isVarArg, typeParams);
+ this.end = endPos;
+ }
+
+ public NamePattern[] getNamePatterns() {
+ return namePatterns;
+ }
+
+ public TypePattern getUpperBound() {
+ return upperBound;
+ }
+
+ public TypePattern getLowerBound() {
+ return lowerBound;
+ }
+
+ public TypePattern[] getAdditionalIntefaceBounds() {
+ return additionalInterfaceBounds;
+ }
+
+ // called by parser after parsing a type pattern, must bump dim as well as setting flag
+ @Override
+ public void setIsVarArgs(boolean isVarArgs) {
+ this.isVarArgs = isVarArgs;
+ if (isVarArgs) {
+ this.dim += 1;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
+ */
+ @Override
+ protected boolean couldEverMatchSameTypesAs(TypePattern other) {
+ if (super.couldEverMatchSameTypesAs(other)) {
+ return true;
+ }
+ // false is necessary but not sufficient
+ UnresolvedType otherType = other.getExactType();
+ if (!ResolvedType.isMissing(otherType)) {
+ if (namePatterns.length > 0) {
+ if (!namePatterns[0].matches(otherType.getName())) {
+ return false;
+ }
+ }
+ }
+ if (other instanceof WildTypePattern) {
+ WildTypePattern owtp = (WildTypePattern) other;
+ String mySimpleName = namePatterns[0].maybeGetSimpleName();
+ String yourSimpleName = owtp.namePatterns[0].maybeGetSimpleName();
+ if (mySimpleName != null && yourSimpleName != null) {
+ return (mySimpleName.startsWith(yourSimpleName) || yourSimpleName.startsWith(mySimpleName));
+ }
+ }
+ return true;
+ }
+
+ // XXX inefficient implementation
+ // we don't know whether $ characters are from nested types, or were
+ // part of the declared type name (generated code often uses $s in type
+ // names). More work required on our part to get this right...
+ public static char[][] splitNames(String s, boolean convertDollar) {
+ List<char[]> ret = new ArrayList<char[]>();
+ int startIndex = 0;
+ while (true) {
+ int breakIndex = s.indexOf('.', startIndex); // what about /
+ if (convertDollar && (breakIndex == -1)) {
+ breakIndex = s.indexOf('$', startIndex); // we treat $ like . here
+ }
+ if (breakIndex == -1) {
+ break;
+ }
+ char[] name = s.substring(startIndex, breakIndex).toCharArray();
+ ret.add(name);
+ startIndex = breakIndex + 1;
+ }
+ ret.add(s.substring(startIndex).toCharArray());
+ return ret.toArray(new char[ret.size()][]);
+ }
+
+ /**
+ * @see org.aspectj.weaver.TypePattern#matchesExactly(IType)
+ */
+ @Override
+ protected boolean matchesExactly(ResolvedType type) {
+ return matchesExactly(type, type);
+ }
+
+ @Override
+ protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
+ String targetTypeName = type.getName();
+
+ // System.err.println("match: " + targetTypeName + ", " + knownMatches); //Arrays.asList(importedPrefixes));
+ // Ensure the annotation pattern is resolved
+ annotationPattern.resolve(type.getWorld());
+
+ return matchesExactlyByName(targetTypeName, type.isAnonymous(), type.isNested()) && matchesParameters(type, STATIC)
+ && matchesBounds(type, STATIC)
+ && annotationPattern.matches(annotatedType, type.temporaryAnnotationTypes).alwaysTrue();
+ }
+
+ // we've matched against the base (or raw) type, but if this type pattern specifies parameters or
+ // type variables we need to make sure we match against them too
+ private boolean matchesParameters(ResolvedType aType, MatchKind staticOrDynamic) {
+ if (!isGeneric && typeParameters.size() > 0) {
+ if (!aType.isParameterizedType()) {
+ return false;
+ }
+ // we have to match type parameters
+ return typeParameters.matches(aType.getResolvedTypeParameters(), staticOrDynamic).alwaysTrue();
+ }
+ return true;
+ }
+
+ // we've matched against the base (or raw) type, but if this type pattern specifies bounds because
+ // it is a ? extends or ? super deal then we have to match them too.
+ private boolean matchesBounds(ResolvedType aType, MatchKind staticOrDynamic) {
+ if (!(aType instanceof BoundedReferenceType)) {
+ return true;
+ }
+ BoundedReferenceType boundedRT = (BoundedReferenceType) aType;
+ if (upperBound == null && boundedRT.getUpperBound() != null) {
+ // for upper bound, null can also match against Object - but anything else and we're out.
+ if (!boundedRT.getUpperBound().getName().equals(UnresolvedType.OBJECT.getName())) {
+ return false;
+ }
+ }
+ if (lowerBound == null && boundedRT.getLowerBound() != null) {
+ return false;
+ }
+ if (upperBound != null) {
+ // match ? extends
+ if (aType.isGenericWildcard() && boundedRT.isSuper()) {
+ return false;
+ }
+ if (boundedRT.getUpperBound() == null) {
+ return false;
+ }
+ return upperBound.matches((ResolvedType) boundedRT.getUpperBound(), staticOrDynamic).alwaysTrue();
+ }
+ if (lowerBound != null) {
+ // match ? super
+ if (!(boundedRT.isGenericWildcard() && boundedRT.isSuper())) {
+ return false;
+ }
+ return lowerBound.matches((ResolvedType) boundedRT.getLowerBound(), staticOrDynamic).alwaysTrue();
+ }
+ return true;
+ }
+
+ /**
+ * Used in conjunction with checks on 'isStar()' to tell you if this pattern represents '*' or '*[]' which are different !
+ */
+ public int getDimensions() {
+ return dim;
+ }
+
+ @Override
+ public boolean isArray() {
+ return dim > 1;
+ }
+
+ /**
+ * @param targetTypeName
+ * @return
+ */
+ private boolean matchesExactlyByName(String targetTypeName, boolean isAnonymous, boolean isNested) {
+ // we deal with parameter matching separately...
+ if (targetTypeName.indexOf('<') != -1) {
+ targetTypeName = targetTypeName.substring(0, targetTypeName.indexOf('<'));
+ }
+ // we deal with bounds matching separately too...
+ if (targetTypeName.startsWith(GENERIC_WILDCARD_CHARACTER)) {
+ targetTypeName = GENERIC_WILDCARD_CHARACTER;
+ }
+ // XXX hack
+ if (knownMatches == null && importedPrefixes == null) {
+ return innerMatchesExactly(targetTypeName, isAnonymous, isNested);
+ }
+
+ if (isNamePatternStar()) {
+ // we match if the dimensions match
+ int numDimensionsInTargetType = 0;
+ if (dim > 0) {
+ int index;
+ while ((index = targetTypeName.indexOf('[')) != -1) {
+ numDimensionsInTargetType++;
+ targetTypeName = targetTypeName.substring(index + 1);
+ }
+ if (numDimensionsInTargetType == dim) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ // if our pattern is length 1, then known matches are exact matches
+ // if it's longer than that, then known matches are prefixes of a sort
+ if (namePatterns.length == 1) {
+ if (isAnonymous) {
+ // we've already ruled out "*", and no other name pattern should match an anonymous type
+ return false;
+ }
+ for (int i = 0, len = knownMatches.length; i < len; i++) {
+ if (knownMatches[i].equals(targetTypeName)) {
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0, len = knownMatches.length; i < len; i++) {
+ String knownMatch = knownMatches[i];
+ // String knownPrefix = knownMatches[i] + "$";
+ // if (targetTypeName.startsWith(knownPrefix)) {
+ if (targetTypeName.startsWith(knownMatch) && targetTypeName.length() > knownMatch.length()
+ && targetTypeName.charAt(knownMatch.length()) == '$') {
+ int pos = lastIndexOfDotOrDollar(knownMatch);
+ if (innerMatchesExactly(targetTypeName.substring(pos + 1), isAnonymous, isNested)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ // if any prefixes match, strip the prefix and check that the rest matches
+ // assumes that prefixes have a dot at the end
+ for (int i = 0, len = importedPrefixes.length; i < len; i++) {
+ String prefix = importedPrefixes[i];
+ // System.err.println("prefix match? " + prefix + " to " + targetTypeName);
+ if (targetTypeName.startsWith(prefix)) {
+
+ if (innerMatchesExactly(targetTypeName.substring(prefix.length()), isAnonymous, isNested)) {
+ return true;
+ }
+ }
+ }
+
+ return innerMatchesExactly(targetTypeName, isAnonymous, isNested);
+ }
+
+ private int lastIndexOfDotOrDollar(String string) {
+ for (int pos = string.length() - 1; pos > -1; pos--) {
+ char ch = string.charAt(pos);
+ if (ch == '.' || ch == '$') {
+ return pos;
+ }
+ }
+ return -1;
+ }
+
+ private boolean innerMatchesExactly(String s, boolean isAnonymous, boolean convertDollar /* isNested */) {
+
+ List<char[]> ret = new ArrayList<char[]>();
+ int startIndex = 0;
+ while (true) {
+ int breakIndex = s.indexOf('.', startIndex); // what about /
+ if (convertDollar && (breakIndex == -1)) {
+ breakIndex = s.indexOf('$', startIndex); // we treat $ like . here
+ }
+ if (breakIndex == -1) {
+ break;
+ }
+ char[] name = s.substring(startIndex, breakIndex).toCharArray();
+ ret.add(name);
+ startIndex = breakIndex + 1;
+ }
+ ret.add(s.substring(startIndex).toCharArray());
+
+ int namesLength = ret.size();
+ int patternsLength = namePatterns.length;
+
+ int namesIndex = 0;
+ int patternsIndex = 0;
+
+ if ((!namePatterns[patternsLength - 1].isAny()) && isAnonymous) {
+ return false;
+ }
+
+ if (ellipsisCount == 0) {
+ if (namesLength != patternsLength) {
+ return false;
+ }
+ while (patternsIndex < patternsLength) {
+ if (!namePatterns[patternsIndex++].matches(ret.get(namesIndex++))) {
+ return false;
+ }
+ }
+ return true;
+ } else if (ellipsisCount == 1) {
+ if (namesLength < patternsLength - 1) {
+ return false;
+ }
+ while (patternsIndex < patternsLength) {
+ NamePattern p = namePatterns[patternsIndex++];
+ if (p == NamePattern.ELLIPSIS) {
+ namesIndex = namesLength - (patternsLength - patternsIndex);
+ } else {
+ if (!p.matches(ret.get(namesIndex++))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } else {
+ // System.err.print("match(\"" + Arrays.asList(namePatterns) + "\", \"" + Arrays.asList(names) + "\") -> ");
+ boolean b = outOfStar(namePatterns, ret.toArray(new char[ret.size()][]), 0, 0, patternsLength - ellipsisCount,
+ namesLength, ellipsisCount);
+ // System.err.println(b);
+ return b;
+ }
+ }
+
+ private static boolean outOfStar(final NamePattern[] pattern, final char[][] target, int pi, int ti, int pLeft, int tLeft,
+ final int starsLeft) {
+ if (pLeft > tLeft) {
+ return false;
+ }
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
+ if (tLeft == 0) {
+ return true;
+ }
+ if (pLeft == 0) {
+ return (starsLeft > 0);
+ }
+ if (pattern[pi] == NamePattern.ELLIPSIS) {
+ return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1);
+ }
+ if (!pattern[pi].matches(target[ti])) {
+ return false;
+ }
+ pi++;
+ ti++;
+ pLeft--;
+ tLeft--;
+ }
+ }
+
+ private static boolean inStar(final NamePattern[] pattern, final char[][] target, int pi, int ti, final int pLeft, int tLeft,
+ int starsLeft) {
+ // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
+ // of course, we probably can't parse multiple ..'s in a row, but this keeps the algorithm
+ // exactly parallel with that in NamePattern
+ NamePattern patternChar = pattern[pi];
+ while (patternChar == NamePattern.ELLIPSIS) {
+ starsLeft--;
+ patternChar = pattern[++pi];
+ }
+ while (true) {
+ // invariant: if (tLeft > 0) then (ti < target.length)
+ if (pLeft > tLeft) {
+ return false;
+ }
+ if (patternChar.matches(target[ti])) {
+ if (outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft)) {
+ return true;
+ }
+ }
+ ti++;
+ tLeft--;
+ }
+ }
+
+ /**
+ * @see org.aspectj.weaver.TypePattern#matchesInstanceof(IType)
+ */
+ @Override
+ public FuzzyBoolean matchesInstanceof(ResolvedType type) {
+ // XXX hack to let unmatched types just silently remain so
+ if (maybeGetSimpleName() != null) {
+ return FuzzyBoolean.NO;
+ }
+
+ type.getWorld().getMessageHandler().handleMessage(
+ new Message("can't do instanceof matching on patterns with wildcards", IMessage.ERROR, null, getSourceLocation()));
+ return FuzzyBoolean.NO;
+ }
+
+ public NamePattern extractName() {
+ if (isIncludeSubtypes() || isVarArgs() || isArray() || (typeParameters.size() > 0)) {
+ // we can't extract a name, the pattern is something like Foo+ and therefore
+ // it is not ok to treat Foo as a method name!
+ return null;
+ }
+ // System.err.println("extract from : " + Arrays.asList(namePatterns));
+ int len = namePatterns.length;
+ if (len == 1 && !annotationPattern.isAny()) {
+ return null; // can't extract
+ }
+ NamePattern ret = namePatterns[len - 1];
+ NamePattern[] newNames = new NamePattern[len - 1];
+ System.arraycopy(namePatterns, 0, newNames, 0, len - 1);
+ namePatterns = newNames;
+ // System.err.println(" left : " + Arrays.asList(namePatterns));
+ return ret;
+ }
+
+ /**
+ * Method maybeExtractName.
+ *
+ * @param string
+ * @return boolean
+ */
+ public boolean maybeExtractName(String string) {
+ int len = namePatterns.length;
+ NamePattern ret = namePatterns[len - 1];
+ String simple = ret.maybeGetSimpleName();
+ if (simple != null && simple.equals(string)) {
+ extractName();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * If this type pattern has no '.' or '*' in it, then return a simple string
+ *
+ * otherwise, this will return null;
+ */
+ public String maybeGetSimpleName() {
+ if (namePatterns.length == 1) {
+ return namePatterns[0].maybeGetSimpleName();
+ }
+ return null;
+ }
+
+ /**
+ * If this type pattern has no '*' or '..' in it
+ */
+ public String maybeGetCleanName() {
+ if (namePatterns.length == 0) {
+ throw new RuntimeException("bad name: " + namePatterns);
+ }
+ // System.out.println("get clean: " + this);
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0, len = namePatterns.length; i < len; i++) {
+ NamePattern p = namePatterns[i];
+ String simpleName = p.maybeGetSimpleName();
+ if (simpleName == null) {
+ return null;
+ }
+ if (i > 0) {
+ buf.append(".");
+ }
+ buf.append(simpleName);
+ }
+ // System.out.println(buf);
+ return buf.toString();
+ }
+
+ @Override
+ public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ NamePattern[] newNamePatterns = new NamePattern[namePatterns.length];
+ for (int i = 0; i < namePatterns.length; i++) {
+ newNamePatterns[i] = namePatterns[i];
+ }
+ if (newNamePatterns.length == 1) {
+ String simpleName = newNamePatterns[0].maybeGetSimpleName();
+ if (simpleName != null) {
+ if (typeVariableMap.containsKey(simpleName)) {
+ String newName = ((ReferenceType) typeVariableMap.get(simpleName)).getName().replace('$', '.');
+ StringTokenizer strTok = new StringTokenizer(newName, ".");
+ newNamePatterns = new NamePattern[strTok.countTokens()];
+ int index = 0;
+ while (strTok.hasMoreTokens()) {
+ newNamePatterns[index++] = new NamePattern(strTok.nextToken());
+ }
+ }
+ }
+ }
+ WildTypePattern ret = new WildTypePattern(newNamePatterns, includeSubtypes, dim, isVarArgs, typeParameters
+ .parameterizeWith(typeVariableMap, w));
+ ret.annotationPattern = this.annotationPattern.parameterizeWith(typeVariableMap, w);
+ if (additionalInterfaceBounds == null) {
+ ret.additionalInterfaceBounds = null;
+ } else {
+ ret.additionalInterfaceBounds = new TypePattern[additionalInterfaceBounds.length];
+ for (int i = 0; i < additionalInterfaceBounds.length; i++) {
+ ret.additionalInterfaceBounds[i] = additionalInterfaceBounds[i].parameterizeWith(typeVariableMap, w);
+ }
+ }
+ ret.upperBound = upperBound != null ? upperBound.parameterizeWith(typeVariableMap, w) : null;
+ ret.lowerBound = lowerBound != null ? lowerBound.parameterizeWith(typeVariableMap, w) : null;
+ ret.isGeneric = isGeneric;
+ ret.knownMatches = knownMatches;
+ ret.importedPrefixes = importedPrefixes;
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /**
+ * Need to determine if I'm really a pattern or a reference to a formal
+ *
+ * We may wish to further optimize the case of pattern vs. non-pattern
+ *
+ * We will be replaced by what we return
+ */
+ @Override
+ public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ if (isNamePatternStar()) {
+ TypePattern anyPattern = maybeResolveToAnyPattern(scope, bindings, allowBinding, requireExactType);
+ if (anyPattern != null) {
+ if (requireExactType) {
+ scope.getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
+ return NO;
+ } else {
+ return anyPattern;
+ }
+ }
+ }
+
+ TypePattern bindingTypePattern = maybeResolveToBindingTypePattern(scope, bindings, allowBinding, requireExactType);
+ if (bindingTypePattern != null) {
+ return bindingTypePattern;
+ }
+
+ annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
+
+ // resolve any type parameters
+ if (typeParameters != null && typeParameters.size() > 0) {
+ typeParameters.resolveBindings(scope, bindings, allowBinding, requireExactType);
+ isGeneric = false;
+ }
+
+ // resolve any bounds
+ if (upperBound != null) {
+ upperBound = upperBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
+ }
+ if (lowerBound != null) {
+ lowerBound = lowerBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
+ // amc - additional interface bounds only needed if we support type vars again.
+ }
+
+ String fullyQualifiedName = maybeGetCleanName();
+ if (fullyQualifiedName != null) {
+ return resolveBindingsFromFullyQualifiedTypeName(fullyQualifiedName, scope, bindings, allowBinding, requireExactType);
+ } else {
+ if (requireExactType) {
+ scope.getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
+ return NO;
+ }
+ importedPrefixes = scope.getImportedPrefixes();
+ knownMatches = preMatch(scope.getImportedNames());
+ return this; // pattern contains wildcards so can't be resolved to an ExactTypePattern...
+ // XXX need to implement behavior for Lint.invalidWildcardTypeName
+ }
+ }
+
+ private TypePattern maybeResolveToAnyPattern(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ // If there is an annotation specified we have to
+ // use a special variant of Any TypePattern called
+ // AnyWithAnnotation
+ if (annotationPattern == AnnotationTypePattern.ANY) {
+ if (dim == 0 && !isVarArgs && upperBound == null && lowerBound == null
+ && (additionalInterfaceBounds == null || additionalInterfaceBounds.length == 0)) { // pr72531
+ return TypePattern.ANY; // ??? loses source location
+ }
+ } else if (!isVarArgs) {
+ annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
+ AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(annotationPattern);
+ ret.setLocation(sourceContext, start, end);
+ return ret;
+ }
+ return null; // can't resolve to a simple "any" pattern
+ }
+
+ private TypePattern maybeResolveToBindingTypePattern(IScope scope, Bindings bindings, boolean allowBinding,
+ boolean requireExactType) {
+ String simpleName = maybeGetSimpleName();
+ if (simpleName != null) {
+ FormalBinding formalBinding = scope.lookupFormal(simpleName);
+ if (formalBinding != null) {
+ if (bindings == null) {
+ scope.message(IMessage.ERROR, this, "negation doesn't allow binding");
+ return this;
+ }
+ if (!allowBinding) {
+ scope.message(IMessage.ERROR, this, "name binding only allowed in target, this, and args pcds");
+ return this;
+ }
+
+ BindingTypePattern binding = new BindingTypePattern(formalBinding, isVarArgs);
+ binding.copyLocationFrom(this);
+ bindings.register(binding, scope);
+
+ return binding;
+ }
+ }
+ return null; // not possible to resolve to a binding type pattern
+ }
+
+ private TypePattern resolveBindingsFromFullyQualifiedTypeName(String fullyQualifiedName, IScope scope, Bindings bindings,
+ boolean allowBinding, boolean requireExactType) {
+ String originalName = fullyQualifiedName;
+ ResolvedType resolvedTypeInTheWorld = null;
+ UnresolvedType type;
+
+ // System.out.println("resolve: " + cleanName);
+ // ??? this loop has too many inefficiencies to count
+ resolvedTypeInTheWorld = lookupTypeInWorldIncludingPrefixes(scope.getWorld(), fullyQualifiedName, scope
+ .getImportedPrefixes());
+
+ if (resolvedTypeInTheWorld.isGenericWildcard()) {
+ type = resolvedTypeInTheWorld;
+ } else {
+ type = lookupTypeInScope(scope, fullyQualifiedName, this);
+ }
+ if ((type instanceof ResolvedType) && ((ResolvedType) type).isMissing()) {
+ return resolveBindingsForMissingType(resolvedTypeInTheWorld, originalName, scope, bindings, allowBinding,
+ requireExactType);
+ } else {
+ return resolveBindingsForExactType(scope, type, fullyQualifiedName, requireExactType);
+ }
+ }
+
+ private UnresolvedType lookupTypeInScope(IScope scope, String typeName, IHasPosition location) {
+ UnresolvedType type = null;
+ while (ResolvedType.isMissing(type = scope.lookupType(typeName, location))) {
+ int lastDot = typeName.lastIndexOf('.');
+ if (lastDot == -1) {
+ break;
+ }
+ typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
+ }
+ return type;
+ }
+
+ /**
+ * Searches the world for the ResolvedType with the given typeName. If one isn't found then for each of the supplied prefixes,
+ * it prepends the typeName with the prefix and searches the world for the ResolvedType with this new name. If one still isn't
+ * found then a MissingResolvedTypeWithKnownSignature is returned with the originally requested typeName (this ensures the
+ * typeName makes sense).
+ */
+ private ResolvedType lookupTypeInWorldIncludingPrefixes(World world, String typeName, String[] prefixes) {
+ ResolvedType ret = lookupTypeInWorld(world, typeName);
+ if (!ret.isMissing()) {
+ return ret;
+ }
+ ResolvedType retWithPrefix = ret;
+ int counter = 0;
+ while (retWithPrefix.isMissing() && (counter < prefixes.length)) {
+ retWithPrefix = lookupTypeInWorld(world, prefixes[counter] + typeName);
+ counter++;
+ }
+ if (!retWithPrefix.isMissing()) {
+ return retWithPrefix;
+ }
+ return ret;
+ }
+
+ private ResolvedType lookupTypeInWorld(World world, String typeName) {
+ UnresolvedType ut = UnresolvedType.forName(typeName);
+ ResolvedType ret = world.resolve(ut, true);
+ while (ret.isMissing()) {
+ int lastDot = typeName.lastIndexOf('.');
+ if (lastDot == -1) {
+ break;
+ }
+ typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
+ ret = world.resolve(UnresolvedType.forName(typeName), true);
+ }
+ return ret;
+ }
+
+ private TypePattern resolveBindingsForExactType(IScope scope, UnresolvedType aType, String fullyQualifiedName,
+ boolean requireExactType) {
+ TypePattern ret = null;
+ if (aType.isTypeVariableReference()) {
+ // we have to set the bounds on it based on the bounds of this pattern
+ ret = resolveBindingsForTypeVariable(scope, (UnresolvedTypeVariableReferenceType) aType);
+ } else if (typeParameters.size() > 0) {
+ ret = resolveParameterizedType(scope, aType, requireExactType);
+ } else if (upperBound != null || lowerBound != null) {
+ // this must be a generic wildcard with bounds
+ ret = resolveGenericWildcard(scope, aType);
+ } else {
+ if (dim != 0) {
+ aType = UnresolvedType.makeArray(aType, dim);
+ }
+ ret = new ExactTypePattern(aType, includeSubtypes, isVarArgs);
+ }
+ ret.setAnnotationTypePattern(annotationPattern);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ private TypePattern resolveGenericWildcard(IScope scope, UnresolvedType aType) {
+ if (!aType.getSignature().equals(GENERIC_WILDCARD_SIGNATURE_CHARACTER)) {
+ throw new IllegalStateException("Can only have bounds for a generic wildcard");
+ }
+ boolean canBeExact = true;
+ if ((upperBound != null) && ResolvedType.isMissing(upperBound.getExactType())) {
+ canBeExact = false;
+ }
+ if ((lowerBound != null) && ResolvedType.isMissing(lowerBound.getExactType())) {
+ canBeExact = false;
+ }
+ if (canBeExact) {
+ ResolvedType type = null;
+ if (upperBound != null) {
+ if (upperBound.isIncludeSubtypes()) {
+ canBeExact = false;
+ } else {
+ ReferenceType upper = (ReferenceType) upperBound.getExactType().resolve(scope.getWorld());
+ type = new BoundedReferenceType(upper, true, scope.getWorld());
+ }
+ } else {
+ if (lowerBound.isIncludeSubtypes()) {
+ canBeExact = false;
+ } else {
+ ReferenceType lower = (ReferenceType) lowerBound.getExactType().resolve(scope.getWorld());
+ type = new BoundedReferenceType(lower, false, scope.getWorld());
+ }
+ }
+ if (canBeExact) {
+ // might have changed if we find out include subtypes is set on one of the bounds...
+ return new ExactTypePattern(type, includeSubtypes, isVarArgs);
+ }
+ }
+
+ // we weren't able to resolve to an exact type pattern...
+ // leave as wild type pattern
+ importedPrefixes = scope.getImportedPrefixes();
+ knownMatches = preMatch(scope.getImportedNames());
+ return this;
+ }
+
+ private TypePattern resolveParameterizedType(IScope scope, UnresolvedType aType, boolean requireExactType) {
+ ResolvedType rt = aType.resolve(scope.getWorld());
+ if (!verifyTypeParameters(rt, scope, requireExactType)) {
+ return TypePattern.NO; // messages already isued
+ }
+ // Only if the type is exact *and* the type parameters are exact should we create an
+ // ExactTypePattern for this WildTypePattern
+ if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
+ TypePattern[] typePats = typeParameters.getTypePatterns();
+ UnresolvedType[] typeParameterTypes = new UnresolvedType[typePats.length];
+ for (int i = 0; i < typeParameterTypes.length; i++) {
+ typeParameterTypes[i] = ((ExactTypePattern) typePats[i]).getExactType();
+ }
+ // rt could be a parameterized type 156058
+ if (rt.isParameterizedType()) {
+ rt = rt.getGenericType();
+ }
+ ResolvedType type = TypeFactory.createParameterizedType(rt, typeParameterTypes, scope.getWorld());
+ if (isGeneric) {
+ type = type.getGenericType();
+ }
+ // UnresolvedType tx = UnresolvedType.forParameterizedTypes(aType,typeParameterTypes);
+ // UnresolvedType type = scope.getWorld().resolve(tx,true);
+ if (dim != 0) {
+ type = ResolvedType.makeArray(type, dim);
+ }
+ return new ExactTypePattern(type, includeSubtypes, isVarArgs);
+ } else {
+ // AMC... just leave it as a wild type pattern then?
+ importedPrefixes = scope.getImportedPrefixes();
+ knownMatches = preMatch(scope.getImportedNames());
+ return this;
+ }
+ }
+
+ private TypePattern resolveBindingsForMissingType(ResolvedType typeFoundInWholeWorldSearch, String nameWeLookedFor,
+ IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
+ if (requireExactType) {
+ if (!allowBinding) {
+ scope.getWorld().getMessageHandler().handleMessage(
+ MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_BIND_TYPE, nameWeLookedFor),
+ getSourceLocation()));
+ } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
+ scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
+ }
+ return NO;
+ } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
+ // Only put the lint warning out if we can't find it in the world
+ if (typeFoundInWholeWorldSearch.isMissing()) {
+ scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
+ this.failedResolution = true;
+ }
+ }
+ importedPrefixes = scope.getImportedPrefixes();
+ knownMatches = preMatch(scope.getImportedNames());
+ return this;
+ }
+
+ /**
+ * We resolved the type to a type variable declared in the pointcut designator. Now we have to create either an exact type
+ * pattern or a wild type pattern for it, with upper and lower bounds set accordingly. XXX none of this stuff gets serialized
+ * yet
+ *
+ * @param scope
+ * @param tvrType
+ * @return
+ */
+ private TypePattern resolveBindingsForTypeVariable(IScope scope, UnresolvedTypeVariableReferenceType tvrType) {
+ Bindings emptyBindings = new Bindings(0);
+ if (upperBound != null) {
+ upperBound = upperBound.resolveBindings(scope, emptyBindings, false, false);
+ }
+ if (lowerBound != null) {
+ lowerBound = lowerBound.resolveBindings(scope, emptyBindings, false, false);
+ }
+ if (additionalInterfaceBounds != null) {
+ TypePattern[] resolvedIfBounds = new TypePattern[additionalInterfaceBounds.length];
+ for (int i = 0; i < resolvedIfBounds.length; i++) {
+ resolvedIfBounds[i] = additionalInterfaceBounds[i].resolveBindings(scope, emptyBindings, false, false);
+ }
+ additionalInterfaceBounds = resolvedIfBounds;
+ }
+ if (upperBound == null && lowerBound == null && additionalInterfaceBounds == null) {
+ // no bounds to worry about...
+ ResolvedType rType = tvrType.resolve(scope.getWorld());
+ if (dim != 0) {
+ rType = ResolvedType.makeArray(rType, dim);
+ }
+ return new ExactTypePattern(rType, includeSubtypes, isVarArgs);
+ } else {
+ // we have to set bounds on the TypeVariable held by tvrType before resolving it
+ boolean canCreateExactTypePattern = true;
+ if (upperBound != null && ResolvedType.isMissing(upperBound.getExactType())) {
+ canCreateExactTypePattern = false;
+ }
+ if (lowerBound != null && ResolvedType.isMissing(lowerBound.getExactType())) {
+ canCreateExactTypePattern = false;
+ }
+ if (additionalInterfaceBounds != null) {
+ for (int i = 0; i < additionalInterfaceBounds.length; i++) {
+ if (ResolvedType.isMissing(additionalInterfaceBounds[i].getExactType())) {
+ canCreateExactTypePattern = false;
+ }
+ }
+ }
+ if (canCreateExactTypePattern) {
+ TypeVariable tv = tvrType.getTypeVariable();
+ if (upperBound != null) {
+ tv.setSuperclass(upperBound.getExactType());
+ }
+ if (additionalInterfaceBounds != null) {
+ UnresolvedType[] ifBounds = new UnresolvedType[additionalInterfaceBounds.length];
+ for (int i = 0; i < ifBounds.length; i++) {
+ ifBounds[i] = additionalInterfaceBounds[i].getExactType();
+ }
+ tv.setAdditionalInterfaceBounds(ifBounds);
+ }
+ ResolvedType rType = tvrType.resolve(scope.getWorld());
+ if (dim != 0) {
+ rType = ResolvedType.makeArray(rType, dim);
+ }
+ return new ExactTypePattern(rType, includeSubtypes, isVarArgs);
+ }
+ return this; // leave as wild type pattern then
+ }
+ }
+
+ /**
+ * When this method is called, we have resolved the base type to an exact type. We also have a set of type patterns for the
+ * parameters. Time to perform some basic checks: - can the base type be parameterized? (is it generic) - can the type parameter
+ * pattern list match the number of parameters on the base type - do all parameter patterns meet the bounds of the respective
+ * type variables If any of these checks fail, a warning message is issued and we return false.
+ *
+ * @return
+ */
+ private boolean verifyTypeParameters(ResolvedType baseType, IScope scope, boolean requireExactType) {
+ ResolvedType genericType = baseType.getGenericType();
+ if (genericType == null) {
+ // issue message "does not match because baseType.getName() is not generic"
+ scope.message(MessageUtil.warn(WeaverMessages.format(WeaverMessages.NOT_A_GENERIC_TYPE, baseType.getName()),
+ getSourceLocation()));
+ return false;
+ }
+ int minRequiredTypeParameters = typeParameters.size();
+ boolean foundEllipsis = false;
+ TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
+ for (int i = 0; i < typeParamPatterns.length; i++) {
+ if (typeParamPatterns[i] instanceof WildTypePattern) {
+ WildTypePattern wtp = (WildTypePattern) typeParamPatterns[i];
+ if (wtp.ellipsisCount > 0) {
+ foundEllipsis = true;
+ minRequiredTypeParameters--;
+ }
+ }
+ }
+ TypeVariable[] tvs = genericType.getTypeVariables();
+ if ((tvs.length < minRequiredTypeParameters) || (!foundEllipsis && minRequiredTypeParameters != tvs.length)) {
+ // issue message "does not match because wrong no of type params"
+ String msg = WeaverMessages.format(WeaverMessages.INCORRECT_NUMBER_OF_TYPE_ARGUMENTS, genericType.getName(),
+ new Integer(tvs.length));
+ if (requireExactType) {
+ scope.message(MessageUtil.error(msg, getSourceLocation()));
+ } else {
+ scope.message(MessageUtil.warn(msg, getSourceLocation()));
+ }
+ return false;
+ }
+
+ // now check that each typeParameter pattern, if exact, matches the bounds
+ // of the type variable.
+
+ // pr133307 - delay verification until type binding completion, these next few lines replace
+ // the call to checkBoundsOK
+ if (!boundscheckingoff) {
+ VerifyBoundsForTypePattern verification = new VerifyBoundsForTypePattern(scope, genericType, requireExactType,
+ typeParameters, getSourceLocation());
+ scope.getWorld().getCrosscuttingMembersSet().recordNecessaryCheck(verification);
+ }
+ // return checkBoundsOK(scope,genericType,requireExactType);
+
+ return true;
+ }
+
+ /**
+ * By capturing the verification in this class, rather than performing it in verifyTypeParameters(), we can cope with situations
+ * where the interactions between generics and declare parents would otherwise cause us problems. For example, if verifying as
+ * we go along we may report a problem which would have been fixed by a declare parents that we haven't looked at yet. If we
+ * create and store a verification object, we can verify this later when the type system is considered 'complete'
+ */
+ static class VerifyBoundsForTypePattern implements IVerificationRequired {
+
+ private final IScope scope;
+ private final ResolvedType genericType;
+ private final boolean requireExactType;
+ private TypePatternList typeParameters = TypePatternList.EMPTY;
+ private final ISourceLocation sLoc;
+
+ public VerifyBoundsForTypePattern(IScope scope, ResolvedType genericType, boolean requireExactType,
+ TypePatternList typeParameters, ISourceLocation sLoc) {
+ this.scope = scope;
+ this.genericType = genericType;
+ this.requireExactType = requireExactType;
+ this.typeParameters = typeParameters;
+ this.sLoc = sLoc;
+ }
+
+ public void verify() {
+ TypeVariable[] tvs = genericType.getTypeVariables();
+ TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
+ if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
+ for (int i = 0; i < tvs.length; i++) {
+ UnresolvedType ut = typeParamPatterns[i].getExactType();
+ boolean continueCheck = true;
+ // FIXME asc dont like this but ok temporary measure. If the type parameter
+ // is itself a type variable (from the generic aspect) then assume it'll be
+ // ok... (see pr112105) Want to break this? Run GenericAspectK test.
+ if (ut.isTypeVariableReference()) {
+ continueCheck = false;
+ }
+
+ // System.err.println("Verifying "+ut.getName()+" meets bounds for "+tvs[i]);
+ if (continueCheck && !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
+ // issue message that type parameter does not meet specification
+ String parameterName = ut.getName();
+ if (ut.isTypeVariableReference()) {
+ parameterName = ((TypeVariableReference) ut).getTypeVariable().getDisplayName();
+ }
+ String msg = WeaverMessages.format(WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS, parameterName,
+ new Integer(i + 1), tvs[i].getDisplayName(), genericType.getName());
+ if (requireExactType) {
+ scope.message(MessageUtil.error(msg, sLoc));
+ } else {
+ scope.message(MessageUtil.warn(msg, sLoc));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // pr133307 - moved to verification object
+ // public boolean checkBoundsOK(IScope scope,ResolvedType genericType,boolean requireExactType) {
+ // if (boundscheckingoff) return true;
+ // TypeVariable[] tvs = genericType.getTypeVariables();
+ // TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
+ // if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
+ // for (int i = 0; i < tvs.length; i++) {
+ // UnresolvedType ut = typeParamPatterns[i].getExactType();
+ // boolean continueCheck = true;
+ // // FIXME asc dont like this but ok temporary measure. If the type parameter
+ // // is itself a type variable (from the generic aspect) then assume it'll be
+ // // ok... (see pr112105) Want to break this? Run GenericAspectK test.
+ // if (ut.isTypeVariableReference()) {
+ // continueCheck = false;
+ // }
+ //
+ // if (continueCheck &&
+ // !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
+ // // issue message that type parameter does not meet specification
+ // String parameterName = ut.getName();
+ // if (ut.isTypeVariableReference()) parameterName = ((TypeVariableReference)ut).getTypeVariable().getDisplayName();
+ // String msg =
+ // WeaverMessages.format(
+ // WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS,
+ // parameterName,
+ // new Integer(i+1),
+ // tvs[i].getDisplayName(),
+ // genericType.getName());
+ // if (requireExactType) scope.message(MessageUtil.error(msg,getSourceLocation()));
+ // else scope.message(MessageUtil.warn(msg,getSourceLocation()));
+ // return false;
+ // }
+ // }
+ // }
+ // return true;
+ // }
+
+ @Override
+ public boolean isStar() {
+ boolean annPatternStar = annotationPattern == AnnotationTypePattern.ANY;
+ return (isNamePatternStar() && annPatternStar && dim == 0);
+ }
+
+ private boolean isNamePatternStar() {
+ return namePatterns.length == 1 && namePatterns[0].isAny();
+ }
+
+ /**
+ * @return those possible matches which I match exactly the last element of
+ */
+ private String[] preMatch(String[] possibleMatches) {
+ // if (namePatterns.length != 1) return CollectionUtil.NO_STRINGS;
+
+ List<String> ret = new ArrayList<String>();
+ for (int i = 0, len = possibleMatches.length; i < len; i++) {
+ char[][] names = splitNames(possibleMatches[i], true); // ??? not most efficient
+ if (namePatterns[0].matches(names[names.length - 1])) {
+ ret.add(possibleMatches[i]);
+ continue;
+ }
+ if (possibleMatches[i].indexOf("$") != -1) {
+ names = splitNames(possibleMatches[i], false); // ??? not most efficient
+ if (namePatterns[0].matches(names[names.length - 1])) {
+ ret.add(possibleMatches[i]);
+ }
+ }
+ }
+ return ret.toArray(new String[ret.size()]);
+ }
+
+ // public void postRead(ResolvedType enclosingType) {
+ // this.importedPrefixes = enclosingType.getImportedPrefixes();
+ // this.knownNames = prematch(enclosingType.getImportedNames());
+ // }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buf.append('(');
+ buf.append(annotationPattern.toString());
+ buf.append(' ');
+ }
+ for (int i = 0, len = namePatterns.length; i < len; i++) {
+ NamePattern name = namePatterns[i];
+ if (name == null) {
+ buf.append(".");
+ } else {
+ if (i > 0) {
+ buf.append(".");
+ }
+ buf.append(name.toString());
+ }
+ }
+ if (upperBound != null) {
+ buf.append(" extends ");
+ buf.append(upperBound.toString());
+ }
+ if (lowerBound != null) {
+ buf.append(" super ");
+ buf.append(lowerBound.toString());
+ }
+ if (typeParameters != null && typeParameters.size() != 0) {
+ buf.append("<");
+ buf.append(typeParameters.toString());
+ buf.append(">");
+ }
+ if (includeSubtypes) {
+ buf.append('+');
+ }
+ if (isVarArgs) {
+ buf.append("...");
+ }
+ if (annotationPattern != AnnotationTypePattern.ANY) {
+ buf.append(')');
+ }
+ return buf.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof WildTypePattern)) {
+ return false;
+ }
+ WildTypePattern o = (WildTypePattern) other;
+ int len = o.namePatterns.length;
+ if (len != this.namePatterns.length) {
+ return false;
+ }
+ if (this.includeSubtypes != o.includeSubtypes) {
+ return false;
+ }
+ if (this.dim != o.dim) {
+ return false;
+ }
+ if (this.isVarArgs != o.isVarArgs) {
+ return false;
+ }
+ if (this.upperBound != null) {
+ if (o.upperBound == null) {
+ return false;
+ }
+ if (!this.upperBound.equals(o.upperBound)) {
+ return false;
+ }
+ } else {
+ if (o.upperBound != null) {
+ return false;
+ }
+ }
+ if (this.lowerBound != null) {
+ if (o.lowerBound == null) {
+ return false;
+ }
+ if (!this.lowerBound.equals(o.lowerBound)) {
+ return false;
+ }
+ } else {
+ if (o.lowerBound != null) {
+ return false;
+ }
+ }
+ if (!typeParameters.equals(o.typeParameters)) {
+ return false;
+ }
+ for (int i = 0; i < len; i++) {
+ if (!o.namePatterns[i].equals(this.namePatterns[i])) {
+ return false;
+ }
+ }
+ return (o.annotationPattern.equals(this.annotationPattern));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ for (int i = 0, len = namePatterns.length; i < len; i++) {
+ result = 37 * result + namePatterns[i].hashCode();
+ }
+ result = 37 * result + annotationPattern.hashCode();
+ if (upperBound != null) {
+ result = 37 * result + upperBound.hashCode();
+ }
+ if (lowerBound != null) {
+ result = 37 * result + lowerBound.hashCode();
+ }
+ return result;
+ }
+
+ private static final byte VERSION = 1; // rev on change
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(TypePattern.WILD);
+ s.writeByte(VERSION);
+ s.writeShort(namePatterns.length);
+ for (int i = 0; i < namePatterns.length; i++) {
+ namePatterns[i].write(s);
+ }
+ s.writeBoolean(includeSubtypes);
+ s.writeInt(dim);
+ s.writeBoolean(isVarArgs);
+ typeParameters.write(s); // ! change from M2
+ // ??? storing this information with every type pattern is wasteful of .class
+ // file size. Storing it on enclosing types would be more efficient
+ FileUtil.writeStringArray(knownMatches, s);
+ FileUtil.writeStringArray(importedPrefixes, s);
+ writeLocation(s);
+ annotationPattern.write(s);
+ // generics info, new in M3
+ s.writeBoolean(isGeneric);
+ s.writeBoolean(upperBound != null);
+ if (upperBound != null) {
+ upperBound.write(s);
+ }
+ s.writeBoolean(lowerBound != null);
+ if (lowerBound != null) {
+ lowerBound.write(s);
+ }
+ s.writeInt(additionalInterfaceBounds == null ? 0 : additionalInterfaceBounds.length);
+ if (additionalInterfaceBounds != null) {
+ for (int i = 0; i < additionalInterfaceBounds.length; i++) {
+ additionalInterfaceBounds[i].write(s);
+ }
+ }
+ }
+
+ public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
+ return readTypePattern150(s, context);
+ } else {
+ return readTypePatternOldStyle(s, context);
+ }
+ }
+
+ public static TypePattern readTypePattern150(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ byte version = s.readByte();
+ if (version > VERSION) {
+ throw new BCException("WildTypePattern was written by a more recent version of AspectJ, cannot read");
+ }
+ int len = s.readShort();
+ NamePattern[] namePatterns = new NamePattern[len];
+ for (int i = 0; i < len; i++) {
+ namePatterns[i] = NamePattern.read(s);
+ }
+ boolean includeSubtypes = s.readBoolean();
+ int dim = s.readInt();
+ boolean varArg = s.readBoolean();
+ TypePatternList typeParams = TypePatternList.read(s, context);
+ WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, varArg, typeParams);
+ ret.knownMatches = FileUtil.readStringArray(s);
+ ret.importedPrefixes = FileUtil.readStringArray(s);
+ ret.readLocation(context, s);
+ ret.setAnnotationTypePattern(AnnotationTypePattern.read(s, context));
+ // generics info, new in M3
+ ret.isGeneric = s.readBoolean();
+ if (s.readBoolean()) {
+ ret.upperBound = TypePattern.read(s, context);
+ }
+ if (s.readBoolean()) {
+ ret.lowerBound = TypePattern.read(s, context);
+ }
+ int numIfBounds = s.readInt();
+ if (numIfBounds > 0) {
+ ret.additionalInterfaceBounds = new TypePattern[numIfBounds];
+ for (int i = 0; i < numIfBounds; i++) {
+ ret.additionalInterfaceBounds[i] = TypePattern.read(s, context);
+ }
+ }
+ return ret;
+ }
+
+ public static TypePattern readTypePatternOldStyle(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ int len = s.readShort();
+ NamePattern[] namePatterns = new NamePattern[len];
+ for (int i = 0; i < len; i++) {
+ namePatterns[i] = NamePattern.read(s);
+ }
+ boolean includeSubtypes = s.readBoolean();
+ int dim = s.readInt();
+ WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, false, null);
+ ret.knownMatches = FileUtil.readStringArray(s);
+ ret.importedPrefixes = FileUtil.readStringArray(s);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ public boolean hasFailedResolution() {
+ return failedResolution;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java
new file mode 100644
index 000000000..42ec11dc2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinAnnotationPointcut.java
@@ -0,0 +1,241 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * @author colyer
+ *
+ * TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code
+ * Templates
+ */
+public class WithinAnnotationPointcut extends NameBindingPointcut {
+
+ private AnnotationTypePattern annotationTypePattern;
+ private String declarationText;
+
+ /**
+ *
+ */
+ public WithinAnnotationPointcut(AnnotationTypePattern type) {
+ super();
+ this.annotationTypePattern = type;
+ this.pointcutKind = ATWITHIN;
+ buildDeclarationText();
+ }
+
+ public WithinAnnotationPointcut(AnnotationTypePattern type, ShadowMunger munger) {
+ this(type);
+ this.pointcutKind = ATWITHIN;
+ }
+
+ public AnnotationTypePattern getAnnotationTypePattern() {
+ return annotationTypePattern;
+ }
+
+ @Override
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ WithinAnnotationPointcut ret = new WithinAnnotationPointcut(this.annotationTypePattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
+ */
+ @Override
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ return annotationTypePattern.fastMatches(info.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
+ */
+ @Override
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ ResolvedType enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(), true);
+ if (enclosingType.isMissing()) {
+ shadow.getIWorld().getLint().cantFindType.signal(new String[] { WeaverMessages.format(
+ WeaverMessages.CANT_FIND_TYPE_WITHINPCD, shadow.getEnclosingType().getName()) }, shadow.getSourceLocation(),
+ new ISourceLocation[] { getSourceLocation() });
+ // IMessage msg = new Message(
+ // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_WITHINPCD,
+ // shadow.getEnclosingType().getName()),
+ // shadow.getSourceLocation(),true,new ISourceLocation[]{getSourceLocation()});
+ // shadow.getIWorld().getMessageHandler().handleMessage(msg);
+ }
+ annotationTypePattern.resolve(shadow.getIWorld());
+ return annotationTypePattern.matches(enclosingType);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings)
+ */
+ @Override
+ protected void resolveBindings(IScope scope, Bindings bindings) {
+ if (!scope.getWorld().isInJava5Mode()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ATWITHIN_ONLY_SUPPORTED_AT_JAVA5_LEVEL),
+ getSourceLocation()));
+ return;
+ }
+ annotationTypePattern = annotationTypePattern.resolveBindings(scope, bindings, true);
+ // must be either a Var, or an annotation type pattern
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
+ */
+ @Override
+ protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ ExactAnnotationTypePattern newType = (ExactAnnotationTypePattern) annotationTypePattern.remapAdviceFormals(bindings);
+ Pointcut ret = new WithinAnnotationPointcut(newType, bindings.getEnclosingAdvice());
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
+ */
+ @Override
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) annotationTypePattern;
+ UnresolvedType annotationType = btp.annotationType;
+ Var var = shadow.getWithinAnnotationVar(annotationType);
+
+ // This should not happen, we shouldn't have gotten this far
+ // if we weren't going to find the annotation
+ if (var == null) {
+ throw new BCException("Impossible! annotation=[" + annotationType + "] shadow=[" + shadow + " at "
+ + shadow.getSourceLocation() + "] pointcut is at [" + getSourceLocation() + "]");
+ }
+
+ state.set(btp.getFormalIndex(), var);
+ }
+ return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
+ }
+
+ @Override
+ public List<BindingPattern> getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ List<BindingPattern> l = new ArrayList<BindingPattern>();
+ l.add((BindingPattern)annotationTypePattern);
+ return l;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public List<BindingTypePattern> getBindingTypePatterns() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.ATWITHIN);
+ annotationTypePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationTypePattern type = AnnotationTypePattern.read(s, context);
+ WithinAnnotationPointcut ret = new WithinAnnotationPointcut(type);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof WithinAnnotationPointcut)) {
+ return false;
+ }
+ WithinAnnotationPointcut other = (WithinAnnotationPointcut) obj;
+ return other.annotationTypePattern.equals(this.annotationTypePattern);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return 17 + 19 * annotationTypePattern.hashCode();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ private void buildDeclarationText() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("@within(");
+ String annPatt = annotationTypePattern.toString();
+ buf.append(annPatt.startsWith("@") ? annPatt.substring(1) : annPatt);
+ buf.append(")");
+ this.declarationText = buf.toString();
+ }
+
+ @Override
+ public String toString() {
+ return this.declarationText;
+ }
+
+ @Override
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java
new file mode 100644
index 000000000..408c829f5
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinCodeAnnotationPointcut.java
@@ -0,0 +1,230 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.NameMangler;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * @author colyer
+ *
+ * TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code
+ * Templates
+ */
+public class WithinCodeAnnotationPointcut extends NameBindingPointcut {
+
+ private ExactAnnotationTypePattern annotationTypePattern;
+ private String declarationText;
+
+ private static final int matchedShadowKinds;
+ static {
+ int flags = Shadow.ALL_SHADOW_KINDS_BITS;
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (Shadow.SHADOW_KINDS[i].isEnclosingKind()) {
+ flags -= Shadow.SHADOW_KINDS[i].bit;
+ }
+ }
+ matchedShadowKinds = flags;
+ }
+
+ public WithinCodeAnnotationPointcut(ExactAnnotationTypePattern type) {
+ super();
+ this.annotationTypePattern = type;
+ this.pointcutKind = Pointcut.ATWITHINCODE;
+ buildDeclarationText();
+ }
+
+ public WithinCodeAnnotationPointcut(ExactAnnotationTypePattern type, ShadowMunger munger) {
+ this(type);
+ this.pointcutKind = Pointcut.ATWITHINCODE;
+ }
+
+ public ExactAnnotationTypePattern getAnnotationTypePattern() {
+ return annotationTypePattern;
+ }
+
+ public int couldMatchKinds() {
+ return matchedShadowKinds;
+ }
+
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ WithinCodeAnnotationPointcut ret = new WithinCodeAnnotationPointcut((ExactAnnotationTypePattern) this.annotationTypePattern
+ .parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
+ */
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
+ */
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ Member member = shadow.getEnclosingCodeSignature();
+ ResolvedMember rMember = member.resolve(shadow.getIWorld());
+
+ if (rMember == null) {
+ if (member.getName().startsWith(NameMangler.PREFIX)) {
+ return FuzzyBoolean.NO;
+ }
+ shadow.getIWorld().getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
+ return FuzzyBoolean.NO;
+ }
+
+ annotationTypePattern.resolve(shadow.getIWorld());
+ return annotationTypePattern.matches(rMember);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
+ * org.aspectj.weaver.patterns.Bindings)
+ */
+ protected void resolveBindings(IScope scope, Bindings bindings) {
+ if (!scope.getWorld().isInJava5Mode()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ATWITHINCODE_ONLY_SUPPORTED_AT_JAVA5_LEVEL),
+ getSourceLocation()));
+ return;
+ }
+ annotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern.resolveBindings(scope, bindings, true);
+ // must be either a Var, or an annotation type pattern
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
+ */
+ protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ ExactAnnotationTypePattern newType = (ExactAnnotationTypePattern) annotationTypePattern.remapAdviceFormals(bindings);
+ Pointcut ret = new WithinCodeAnnotationPointcut(newType, bindings.getEnclosingAdvice());
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.patterns.Pointcut#findResidue(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
+ */
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) annotationTypePattern;
+ UnresolvedType annotationType = btp.annotationType;
+ Var var = shadow.getWithinCodeAnnotationVar(annotationType);
+
+ // This should not happen, we shouldn't have gotten this far
+ // if we weren't going to find the annotation
+ if (var == null) {
+ throw new BCException("Impossible! annotation=[" + annotationType + "] shadow=[" + shadow + " at "
+ + shadow.getSourceLocation() + "] pointcut is at [" + getSourceLocation() + "]");
+ }
+
+ state.set(btp.getFormalIndex(), var);
+ }
+ if (matchInternal(shadow).alwaysTrue()) {
+ return Literal.TRUE;
+ } else {
+ return Literal.FALSE;
+ }
+ }
+
+ public List<BindingPattern> getBindingAnnotationTypePatterns() {
+ if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
+ List<BindingPattern> l = new ArrayList<BindingPattern>();
+ l.add((BindingPattern)annotationTypePattern);
+ return l;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ public List<BindingTypePattern> getBindingTypePatterns() {
+ return Collections.emptyList();
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.ATWITHINCODE);
+ annotationTypePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ AnnotationTypePattern type = AnnotationTypePattern.read(s, context);
+ WithinCodeAnnotationPointcut ret = new WithinCodeAnnotationPointcut((ExactAnnotationTypePattern) type);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof WithinCodeAnnotationPointcut)) {
+ return false;
+ }
+ WithinCodeAnnotationPointcut o = (WithinCodeAnnotationPointcut) other;
+ return o.annotationTypePattern.equals(this.annotationTypePattern);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 23 * result + annotationTypePattern.hashCode();
+ return result;
+ }
+
+ private void buildDeclarationText() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("@withincode(");
+ String annPatt = annotationTypePattern.toString();
+ buf.append(annPatt.startsWith("@") ? annPatt.substring(1) : annPatt);
+ buf.append(")");
+ this.declarationText = buf.toString();
+ }
+
+ public String toString() {
+ return this.declarationText;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinPointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinPointcut.java
new file mode 100644
index 000000000..e5461b67e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithinPointcut.java
@@ -0,0 +1,149 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+public class WithinPointcut extends Pointcut {
+ private TypePattern typePattern;
+
+ public WithinPointcut(TypePattern type) {
+ this.typePattern = type;
+ this.pointcutKind = WITHIN;
+ }
+
+ public TypePattern getTypePattern() {
+ return typePattern;
+ }
+
+ private FuzzyBoolean isWithinType(ResolvedType type) {
+ while (type != null) {
+ if (typePattern.matchesStatically(type)) {
+ return FuzzyBoolean.YES;
+ }
+ type = type.getDeclaringType();
+ }
+ return FuzzyBoolean.NO;
+ }
+
+ public int couldMatchKinds() {
+ return Shadow.ALL_SHADOW_KINDS_BITS;
+ }
+
+ @Override
+ public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
+ WithinPointcut ret = new WithinPointcut(this.typePattern.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ if (typePattern.annotationPattern instanceof AnyAnnotationTypePattern) {
+ return isWithinType(info.getType());
+ }
+ return FuzzyBoolean.MAYBE;
+ // Possible alternative implementation that fast matches even annotation patterns: '@Foo *'
+// typePattern.resolve(info.world);
+// return isWithinType(info.getType());
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ ResolvedType enclosingType = shadow.getIWorld().resolve(shadow.getEnclosingType(), true);
+ if (enclosingType.isMissing()) {
+ shadow.getIWorld().getLint().cantFindType.signal(new String[] { WeaverMessages.format(
+ WeaverMessages.CANT_FIND_TYPE_WITHINPCD, shadow.getEnclosingType().getName()) }, shadow.getSourceLocation(),
+ new ISourceLocation[] { getSourceLocation() });
+ }
+ typePattern.resolve(shadow.getIWorld());
+ return isWithinType(enclosingType);
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.WITHIN);
+ typePattern.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ TypePattern type = TypePattern.read(s, context);
+ WithinPointcut ret = new WithinPointcut(type);
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ typePattern = typePattern.resolveBindings(scope, bindings, false, false);
+
+ // look for parameterized type patterns which are not supported...
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ typePattern.traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.WITHIN_PCD_DOESNT_SUPPORT_PARAMETERS),
+ getSourceLocation()));
+ }
+ }
+
+ public void postRead(ResolvedType enclosingType) {
+ typePattern.postRead(enclosingType);
+ }
+
+ public boolean couldEverMatchSameJoinPointsAs(WithinPointcut other) {
+ return typePattern.couldEverMatchSameTypesAs(other.typePattern);
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof WithinPointcut)) {
+ return false;
+ }
+ WithinPointcut o = (WithinPointcut) other;
+ return o.typePattern.equals(this.typePattern);
+ }
+
+ public int hashCode() {
+ return typePattern.hashCode();
+ }
+
+ public String toString() {
+ return "within(" + typePattern + ")";
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
+ }
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ Pointcut ret = new WithinPointcut(typePattern);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithincodePointcut.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithincodePointcut.java
new file mode 100644
index 000000000..bb4a1e72c
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/patterns/WithincodePointcut.java
@@ -0,0 +1,141 @@
+/* *******************************************************************
+ * 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 v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.patterns;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.CompressingDataOutputStream;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+
+public class WithincodePointcut extends Pointcut {
+ private SignaturePattern signature;
+ private static final int matchedShadowKinds;
+ static {
+ int flags = Shadow.ALL_SHADOW_KINDS_BITS;
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ if (Shadow.SHADOW_KINDS[i].isEnclosingKind()) {
+ flags -= Shadow.SHADOW_KINDS[i].bit;
+ }
+ }
+ // these next two are needed for inlining of field initializers
+ flags |= Shadow.ConstructorExecution.bit;
+ flags |= Shadow.Initialization.bit;
+ matchedShadowKinds = flags;
+ }
+
+ public WithincodePointcut(SignaturePattern signature) {
+ this.signature = signature;
+ this.pointcutKind = WITHINCODE;
+ }
+
+ public SignaturePattern getSignature() {
+ return signature;
+ }
+
+ public int couldMatchKinds() {
+ return matchedShadowKinds;
+ }
+
+ public Pointcut parameterizeWith(Map typeVariableMap, World w) {
+ WithincodePointcut ret = new WithincodePointcut(signature.parameterizeWith(typeVariableMap, w));
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
+ return FuzzyBoolean.MAYBE;
+ }
+
+ protected FuzzyBoolean matchInternal(Shadow shadow) {
+ // This will not match code in local or anonymous classes as if
+ // they were withincode of the outer signature
+ return FuzzyBoolean.fromBoolean(signature.matches(shadow.getEnclosingCodeSignature(), shadow.getIWorld(), false));
+ }
+
+ public void write(CompressingDataOutputStream s) throws IOException {
+ s.writeByte(Pointcut.WITHINCODE);
+ signature.write(s);
+ writeLocation(s);
+ }
+
+ public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
+ WithincodePointcut ret = new WithincodePointcut(SignaturePattern.read(s, context));
+ ret.readLocation(context, s);
+ return ret;
+ }
+
+ public void resolveBindings(IScope scope, Bindings bindings) {
+ signature = signature.resolveBindings(scope, bindings);
+
+ // look for inappropriate use of parameterized types and tell user...
+ HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getDeclaringType().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages
+ .format(WeaverMessages.WITHINCODE_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES), getSourceLocation()));
+ }
+
+ visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
+ signature.getThrowsPattern().traverse(visitor, null);
+ if (visitor.wellHasItThen/* ? */()) {
+ scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_GENERIC_THROWABLES), getSourceLocation()));
+ }
+ }
+
+ public void postRead(ResolvedType enclosingType) {
+ signature.postRead(enclosingType);
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof WithincodePointcut)) {
+ return false;
+ }
+ WithincodePointcut o = (WithincodePointcut) other;
+ return o.signature.equals(this.signature);
+ }
+
+ public int hashCode() {
+ int result = 43;
+ result = 37 * result + signature.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return "withincode(" + signature + ")";
+ }
+
+ protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+ return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
+ }
+
+ public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ Pointcut ret = new WithincodePointcut(signature);
+ ret.copyLocationFrom(this);
+ return ret;
+ }
+
+ public Object accept(PatternNodeVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/AnnotationFinder.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/AnnotationFinder.java
new file mode 100644
index 000000000..90ce368d9
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/AnnotationFinder.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2005, 2017 Contributors.
+ *
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Member;
+
+import org.aspectj.weaver.AnnotationAJ;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+/**
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public interface AnnotationFinder {
+
+ void setClassLoader(ClassLoader annotationLoader);
+
+ void setWorld(World aWorld);
+
+ Object getAnnotation(ResolvedType annotationType, Object onObject);
+
+ Object getAnnotationFromMember(ResolvedType annotationType, Member aMember);
+
+ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember);
+
+ public String getAnnotationDefaultValue(Member onMember);
+
+ Object getAnnotationFromClass(ResolvedType annotationType, Class<?> aClass);
+
+ ResolvedType[] getAnnotations(Member onMember, boolean runtimeAnnotationsOnly);
+
+ ResolvedType[][] getParameterAnnotationTypes(Member onMember);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/GenericSignatureInformationProvider.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/GenericSignatureInformationProvider.java
new file mode 100644
index 000000000..fce972348
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/GenericSignatureInformationProvider.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import org.aspectj.weaver.UnresolvedType;
+
+/**
+ * This interface exists to support two different strategies for answering
+ * generic signature related questions on Java 5 and pre-Java 5.
+ */
+public interface GenericSignatureInformationProvider {
+
+ UnresolvedType[] getGenericParameterTypes(ReflectionBasedResolvedMemberImpl resolvedMember);
+
+ UnresolvedType getGenericReturnType(ReflectionBasedResolvedMemberImpl resolvedMember);
+
+ boolean isBridge(ReflectionBasedResolvedMemberImpl resolvedMember);
+
+ boolean isVarArgs(ReflectionBasedResolvedMemberImpl resolvedMember);
+
+ boolean isSynthetic(ReflectionBasedResolvedMemberImpl resolvedMember);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/IReflectionWorld.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/IReflectionWorld.java
new file mode 100644
index 000000000..60d90d357
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/IReflectionWorld.java
@@ -0,0 +1,19 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Ron Bodkin initial implementation
+ * ******************************************************************/
+ package org.aspectj.weaver.reflect;
+
+import org.aspectj.weaver.ResolvedType;
+
+public interface IReflectionWorld {
+ public AnnotationFinder getAnnotationFinder();
+ public ResolvedType resolve(Class aClass);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/Java14GenericSignatureInformationProvider.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/Java14GenericSignatureInformationProvider.java
new file mode 100644
index 000000000..91b32ff0e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/Java14GenericSignatureInformationProvider.java
@@ -0,0 +1,60 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import org.aspectj.weaver.UnresolvedType;
+
+/**
+ * Under JDK 1.4 or lower, we can't give generic signature info...
+ */
+public class Java14GenericSignatureInformationProvider implements
+ GenericSignatureInformationProvider {
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.reflect.GenericSignatureInformationProvider#getGenericParameterTypes(org.aspectj.weaver.reflect.ReflectionBasedResolvedMemberImpl)
+ */
+ public UnresolvedType[] getGenericParameterTypes(
+ ReflectionBasedResolvedMemberImpl resolvedMember) {
+ return resolvedMember.getParameterTypes();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.reflect.GenericSignatureInformationProvider#getGenericReturnType(org.aspectj.weaver.reflect.ReflectionBasedResolvedMemberImpl)
+ */
+ public UnresolvedType getGenericReturnType(
+ ReflectionBasedResolvedMemberImpl resolvedMember) {
+ return resolvedMember.getReturnType();
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.reflect.GenericSignatureInformationProvider#isBridge()
+ */
+ public boolean isBridge(ReflectionBasedResolvedMemberImpl resolvedMember) {
+ return false;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.reflect.GenericSignatureInformationProvider#isVarArgs()
+ */
+ public boolean isVarArgs(ReflectionBasedResolvedMemberImpl resolvedMember) {
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.reflect.GenericSignatureInformationProvider#isSynthetic()
+ */
+ public boolean isSynthetic(ReflectionBasedResolvedMemberImpl resolvedMember) {
+ return false;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/JoinPointMatchImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/JoinPointMatchImpl.java
new file mode 100644
index 000000000..69a5f4577
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/JoinPointMatchImpl.java
@@ -0,0 +1,53 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import org.aspectj.weaver.tools.JoinPointMatch;
+import org.aspectj.weaver.tools.PointcutParameter;
+
+/**
+ * @author colyer
+ * Implementation of JoinPointMatch for reflection based worlds.
+ */
+public class JoinPointMatchImpl implements JoinPointMatch {
+
+ public final static JoinPointMatch NO_MATCH = new JoinPointMatchImpl();
+ private final static PointcutParameter[] NO_BINDINGS = new PointcutParameter[0];
+
+ private boolean match;
+ private PointcutParameter[] bindings;
+
+ public JoinPointMatchImpl(PointcutParameter[] bindings) {
+ this.match = true;
+ this.bindings = bindings;
+ }
+
+ private JoinPointMatchImpl() {
+ this.match = false;
+ this.bindings = NO_BINDINGS;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.tools.JoinPointMatch#matches()
+ */
+ public boolean matches() {
+ return match;
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.tools.JoinPointMatch#getParameterBindings()
+ */
+ public PointcutParameter[] getParameterBindings() {
+ return bindings;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/PointcutParameterImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/PointcutParameterImpl.java
new file mode 100644
index 000000000..722d64839
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/PointcutParameterImpl.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import org.aspectj.weaver.tools.PointcutParameter;
+
+public class PointcutParameterImpl implements PointcutParameter {
+
+ String name;
+ Class type;
+ Object binding;
+
+ public PointcutParameterImpl(String name, Class type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public Object getBinding() {
+ return binding;
+ }
+
+ void setBinding(Object boundValue) {
+ this.binding = boundValue;
+ }
+
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegate.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegate.java
new file mode 100644
index 000000000..2aa83c957
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegate.java
@@ -0,0 +1,403 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
+import org.aspectj.weaver.AnnotationAJ;
+import org.aspectj.weaver.AnnotationTargetKind;
+import org.aspectj.weaver.ConcreteTypeMunger;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ReferenceTypeDelegate;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.SourceContextImpl;
+import org.aspectj.weaver.TypeVariable;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.WeakClassLoaderReference;
+import org.aspectj.weaver.WeaverStateInfo;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.patterns.Declare;
+import org.aspectj.weaver.patterns.PerClause;
+
+/**
+ * @author colyer A delegate for a resolved type that uses runtime type information (java.lang.reflect) to answer questions. This
+ * class uses only Java 1.4 features to answer questions. In a Java 1.5 environment use the
+ * Java5ReflectionBasedReferenceTypeDelegate subtype.
+ */
+public class ReflectionBasedReferenceTypeDelegate implements ReferenceTypeDelegate {
+
+ private static final ClassLoader bootClassLoader = new URLClassLoader(new URL[0]);// ReflectionBasedReferenceTypeDelegate.class.
+ // getClassLoader();
+
+ protected Class myClass = null;
+ protected WeakClassLoaderReference classLoaderReference = null;
+ protected World world;
+ private ReferenceType resolvedType;
+ private ResolvedMember[] fields = null;
+ private ResolvedMember[] methods = null;
+ private ResolvedType[] interfaces = null;
+
+ public ReflectionBasedReferenceTypeDelegate(Class forClass, ClassLoader aClassLoader, World inWorld, ReferenceType resolvedType) {
+ initialize(resolvedType, forClass, aClassLoader, inWorld);
+ }
+
+ /** for reflective construction only */
+ public ReflectionBasedReferenceTypeDelegate() {
+ }
+
+ public void initialize(ReferenceType aType, Class<?> aClass, ClassLoader aClassLoader, World aWorld) {
+ this.myClass = aClass;
+ this.resolvedType = aType;
+ this.world = aWorld;
+ this.classLoaderReference = new WeakClassLoaderReference((aClassLoader != null) ? aClassLoader : bootClassLoader);
+ }
+
+ public Class<?> getClazz() {
+ return this.myClass;
+ }
+
+ protected Class getBaseClass() {
+ return this.myClass;
+ }
+
+ protected World getWorld() {
+ return this.world;
+ }
+
+ public ReferenceType buildGenericType() {
+ throw new UnsupportedOperationException("Shouldn't be asking for generic type at 1.4 source level or lower");
+ }
+
+ public boolean isAspect() {
+ // we could do better than this in Java 5 by looking at the annotations
+ // on the type...
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#isAnnotationStyleAspect()
+ */
+ public boolean isAnnotationStyleAspect() {
+ // we could do better than this in Java 5 by looking at the annotations
+ // on the type...
+ return false;
+ }
+
+ public boolean isInterface() {
+ return this.myClass.isInterface();
+ }
+
+ public boolean isEnum() {
+ // cant be an enum in Java 1.4 or prior
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#isAnnotationWithRuntimeRetention ()
+ */
+ public boolean isAnnotationWithRuntimeRetention() {
+ // cant be an annotation in Java 1.4 or prior
+ return false;
+ }
+
+ public boolean isAnnotation() {
+ // cant be an annotation in Java 1.4 or prior
+ return false;
+ }
+
+ public String getRetentionPolicy() {
+ // cant be an annotation in Java 1.4 or prior
+ return null;
+ }
+
+ public boolean canAnnotationTargetType() {
+ return false;
+ }
+
+ public AnnotationTargetKind[] getAnnotationTargetKinds() {
+ return null;
+ }
+
+ public boolean isClass() {
+ return !this.myClass.isInterface() && !this.myClass.isPrimitive() && !this.myClass.isArray();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#isGeneric()
+ */
+ public boolean isGeneric() {
+ // cant be generic in 1.4
+ return false;
+ }
+
+ public boolean isAnonymous() {
+ // this isn't in < Java 1.5 but I think we are moving beyond the need to support those levels
+ return this.myClass.isAnonymousClass();
+ }
+
+ public boolean isNested() {
+ // this isn't in < Java 1.5 but I think we are moving beyond the need to support those levels
+ return this.myClass.isMemberClass();
+ }
+
+ public ResolvedType getOuterClass() {
+ // this isn't in < Java 1.5 but I think we are moving beyond the need to support those levels
+ return ReflectionBasedReferenceTypeDelegateFactory.resolveTypeInWorld(
+ myClass.getEnclosingClass(),world);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#isExposedToWeaver()
+ */
+ public boolean isExposedToWeaver() {
+ // reflection based types are never exposed to the weaver
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#hasAnnotation(org.aspectj.weaver .UnresolvedType)
+ */
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ // in Java 1.4 we cant have an annotation
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getAnnotations()
+ */
+ public AnnotationAJ[] getAnnotations() {
+ // no annotations in Java 1.4
+ return AnnotationAJ.EMPTY_ARRAY;
+ }
+
+ public boolean hasAnnotations() {
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getAnnotationTypes()
+ */
+ public ResolvedType[] getAnnotationTypes() {
+ // no annotations in Java 1.4
+ return new ResolvedType[0];
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getDeclaredFields()
+ */
+ public ResolvedMember[] getDeclaredFields() {
+ if (fields == null) {
+ Field[] reflectFields = this.myClass.getDeclaredFields();
+ ResolvedMember[] rFields = new ResolvedMember[reflectFields.length];
+ for (int i = 0; i < reflectFields.length; i++) {
+ rFields[i] = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(reflectFields[i], world);
+ }
+ this.fields = rFields;
+ }
+ return fields;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getDeclaredInterfaces()
+ */
+ public ResolvedType[] getDeclaredInterfaces() {
+ if (interfaces == null) {
+ Class[] reflectInterfaces = this.myClass.getInterfaces();
+ ResolvedType[] rInterfaces = new ResolvedType[reflectInterfaces.length];
+ for (int i = 0; i < reflectInterfaces.length; i++) {
+ rInterfaces[i] = ReflectionBasedReferenceTypeDelegateFactory.resolveTypeInWorld(reflectInterfaces[i], world);
+ }
+ this.interfaces = rInterfaces;
+ }
+ return interfaces;
+ }
+
+ public boolean isCacheable() {
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getDeclaredMethods()
+ */
+ public ResolvedMember[] getDeclaredMethods() {
+ if (methods == null) {
+ Method[] reflectMethods = this.myClass.getDeclaredMethods();
+ Constructor[] reflectCons = this.myClass.getDeclaredConstructors();
+ ResolvedMember[] rMethods = new ResolvedMember[reflectMethods.length + reflectCons.length];
+ for (int i = 0; i < reflectMethods.length; i++) {
+ rMethods[i] = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(reflectMethods[i], world);
+ }
+ for (int i = 0; i < reflectCons.length; i++) {
+ rMethods[i + reflectMethods.length] = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(
+ reflectCons[i], world);
+ }
+ this.methods = rMethods;
+ }
+ return methods;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getDeclaredPointcuts()
+ */
+ public ResolvedMember[] getDeclaredPointcuts() {
+ return new ResolvedMember[0];
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getTypeVariables()
+ */
+ public TypeVariable[] getTypeVariables() {
+ // no type variables in Java 1.4
+ return new TypeVariable[0];
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getPerClause()
+ */
+ public PerClause getPerClause() {
+ // no per clause...
+ return null;
+ }
+
+ public Collection<Declare> getDeclares() {
+ return Collections.emptySet();
+ }
+
+ public Collection<ConcreteTypeMunger> getTypeMungers() {
+ return Collections.emptySet();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getPrivilegedAccesses()
+ */
+ public Collection getPrivilegedAccesses() {
+ // no aspect members..., not used for weaving
+ return Collections.EMPTY_SET;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getModifiers()
+ */
+ public int getModifiers() {
+ return this.myClass.getModifiers();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getSuperclass()
+ */
+ public ResolvedType getSuperclass() {
+ if (this.myClass.getSuperclass() == null) {
+ if (myClass == Object.class) {
+ return null;
+ }
+ return world.resolve(UnresolvedType.OBJECT);
+ }
+ return ReflectionBasedReferenceTypeDelegateFactory.resolveTypeInWorld(this.myClass.getSuperclass(), world);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.ReferenceTypeDelegate#getWeaverState()
+ */
+ public WeaverStateInfo getWeaverState() {
+ return null;
+ }
+
+ public ReferenceType getResolvedTypeX() {
+ return this.resolvedType;
+ }
+
+ public boolean doesNotExposeShadowMungers() {
+ return false;
+ }
+
+ public String getDeclaredGenericSignature() {
+ // no generic sig in 1.4
+ return null;
+ }
+
+ public ReflectionBasedResolvedMemberImpl createResolvedMemberFor(Member aMember) {
+ return null;
+ }
+
+ public String getSourcefilename() {
+ // crappy guess..
+ return resolvedType.getName() + ".class";
+ }
+
+ public ISourceContext getSourceContext() {
+ return SourceContextImpl.UNKNOWN_SOURCE_CONTEXT;
+ }
+
+ public boolean copySourceContext() {
+ return true;
+ }
+
+ public int getCompilerVersion() {
+ return WeaverVersionInfo.getCurrentWeaverMajorVersion();
+ }
+
+ public void ensureConsistent() {
+
+ }
+
+ public boolean isWeavable() {
+ return false;
+ }
+
+ public boolean hasBeenWoven() {
+ return false;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegateFactory.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegateFactory.java
new file mode 100644
index 000000000..eee1b6f32
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedReferenceTypeDelegateFactory.java
@@ -0,0 +1,219 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.aspectj.util.LangUtil;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedMemberImpl;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+
+/**
+ * @author colyer Creates the appropriate ReflectionBasedReferenceTypeDelegate according to the VM level we are running at. Uses
+ * reflection to avoid 1.5 dependencies in 1.4 and 1.3 code base.
+ */
+public class ReflectionBasedReferenceTypeDelegateFactory {
+
+ public static ReflectionBasedReferenceTypeDelegate createDelegate(ReferenceType forReferenceType, World inWorld,
+ ClassLoader usingClassLoader) {
+ try {
+ Class c = Class.forName(forReferenceType.getName(), false, usingClassLoader);
+ if (LangUtil.is15VMOrGreater()) {
+ ReflectionBasedReferenceTypeDelegate rbrtd = create15Delegate(forReferenceType, c, usingClassLoader, inWorld);
+ if (rbrtd != null) {
+ return rbrtd; // can be null if we didn't find the class the delegate logic loads
+ }
+ }
+ return new ReflectionBasedReferenceTypeDelegate(c, usingClassLoader, inWorld, forReferenceType);
+ } catch (ClassNotFoundException cnfEx) {
+ return null;
+ }
+ }
+
+ public static ReflectionBasedReferenceTypeDelegate createDelegate(ReferenceType forReferenceType, World inWorld,
+ Class<?> clazz) {
+ if (LangUtil.is15VMOrGreater()) {
+ ReflectionBasedReferenceTypeDelegate rbrtd = create15Delegate(forReferenceType, clazz, clazz.getClassLoader(), inWorld);
+ if (rbrtd != null) {
+ return rbrtd; // can be null if we didn't find the class the delegate logic loads
+ }
+ }
+ return new ReflectionBasedReferenceTypeDelegate(clazz, clazz.getClassLoader(), inWorld, forReferenceType);
+ }
+
+ public static ReflectionBasedReferenceTypeDelegate create14Delegate(ReferenceType forReferenceType, World inWorld,
+ ClassLoader usingClassLoader) {
+ try {
+ Class c = Class.forName(forReferenceType.getName(), false, usingClassLoader);
+ return new ReflectionBasedReferenceTypeDelegate(c, usingClassLoader, inWorld, forReferenceType);
+ } catch (ClassNotFoundException cnfEx) {
+ return null;
+ }
+ }
+
+ // can return 'null' if we can't find the class
+ private static ReflectionBasedReferenceTypeDelegate create15Delegate(ReferenceType forReferenceType, Class forClass,
+ ClassLoader usingClassLoader, World inWorld) {
+ try {
+ Class delegateClass = Class.forName("org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate");
+ ReflectionBasedReferenceTypeDelegate ret = (ReflectionBasedReferenceTypeDelegate) delegateClass.newInstance();
+ ret.initialize(forReferenceType, forClass, usingClassLoader, inWorld);
+ return ret;
+ } catch (ClassNotFoundException cnfEx) {
+ throw new IllegalStateException(
+ "Attempted to create Java 1.5 reflection based delegate but org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate was not found on classpath");
+ } catch (InstantiationException insEx) {
+ throw new IllegalStateException("Attempted to create Java 1.5 reflection based delegate but InstantiationException: "
+ + insEx + " occured");
+ } catch (IllegalAccessException illAccEx) {
+ throw new IllegalStateException("Attempted to create Java 1.5 reflection based delegate but IllegalAccessException: "
+ + illAccEx + " occured");
+ }
+ }
+
+ private static GenericSignatureInformationProvider createGenericSignatureProvider(World inWorld) {
+ if (LangUtil.is15VMOrGreater()) {
+ try {
+ Class providerClass = Class.forName("org.aspectj.weaver.reflect.Java15GenericSignatureInformationProvider");
+ Constructor cons = providerClass.getConstructor(new Class[] { World.class });
+ GenericSignatureInformationProvider ret = (GenericSignatureInformationProvider) cons
+ .newInstance(new Object[] { inWorld });
+ return ret;
+ } catch (ClassNotFoundException cnfEx) {
+ // drop through and create a 14 provider...
+ // throw new
+ // IllegalStateException("Attempted to create Java 1.5 generic signature provider but org.aspectj.weaver.reflect.Java15GenericSignatureInformationProvider was not found on classpath");
+ } catch (NoSuchMethodException nsmEx) {
+ throw new IllegalStateException("Attempted to create Java 1.5 generic signature provider but: " + nsmEx
+ + " occured");
+ } catch (InstantiationException insEx) {
+ throw new IllegalStateException("Attempted to create Java 1.5 generic signature provider but: " + insEx
+ + " occured");
+ } catch (InvocationTargetException invEx) {
+ throw new IllegalStateException("Attempted to create Java 1.5 generic signature provider but: " + invEx
+ + " occured");
+ } catch (IllegalAccessException illAcc) {
+ throw new IllegalStateException("Attempted to create Java 1.5 generic signature provider but: " + illAcc
+ + " occured");
+ }
+ }
+ return new Java14GenericSignatureInformationProvider();
+ }
+
+ /**
+ * convert a java.lang.reflect.Member into a resolved member in the world
+ *
+ * @param reflectMember
+ * @param inWorld
+ * @return
+ */
+ public static ResolvedMember createResolvedMember(Member reflectMember, World inWorld) {
+ if (reflectMember instanceof Method) {
+ return createResolvedMethod((Method) reflectMember, inWorld);
+ } else if (reflectMember instanceof Constructor) {
+ return createResolvedConstructor((Constructor) reflectMember, inWorld);
+ } else {
+ return createResolvedField((Field) reflectMember, inWorld);
+ }
+ }
+
+ public static ResolvedMember createResolvedMethod(Method aMethod, World inWorld) {
+ ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.METHOD,
+ toResolvedType(aMethod.getDeclaringClass(), (IReflectionWorld) inWorld), aMethod.getModifiers(), toResolvedType(
+ aMethod.getReturnType(), (IReflectionWorld) inWorld), aMethod.getName(), toResolvedTypeArray(
+ aMethod.getParameterTypes(), inWorld), toResolvedTypeArray(aMethod.getExceptionTypes(), inWorld), aMethod);
+ if (inWorld instanceof IReflectionWorld) {
+ ret.setAnnotationFinder(((IReflectionWorld) inWorld).getAnnotationFinder());
+ }
+ ret.setGenericSignatureInformationProvider(createGenericSignatureProvider(inWorld));
+ return ret;
+ }
+
+ public static ResolvedMember createResolvedAdviceMember(Method aMethod, World inWorld) {
+ ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.ADVICE,
+ toResolvedType(aMethod.getDeclaringClass(), (IReflectionWorld) inWorld), aMethod.getModifiers(), toResolvedType(
+ aMethod.getReturnType(), (IReflectionWorld) inWorld), aMethod.getName(), toResolvedTypeArray(
+ aMethod.getParameterTypes(), inWorld), toResolvedTypeArray(aMethod.getExceptionTypes(), inWorld), aMethod);
+ if (inWorld instanceof IReflectionWorld) {
+ ret.setAnnotationFinder(((IReflectionWorld) inWorld).getAnnotationFinder());
+ }
+ ret.setGenericSignatureInformationProvider(createGenericSignatureProvider(inWorld));
+ return ret;
+ }
+
+ public static ResolvedMember createStaticInitMember(Class forType, World inWorld) {
+ return new ResolvedMemberImpl(org.aspectj.weaver.Member.STATIC_INITIALIZATION, toResolvedType(forType,
+ (IReflectionWorld) inWorld), Modifier.STATIC, UnresolvedType.VOID, "<clinit>", new UnresolvedType[0],
+ new UnresolvedType[0]);
+ }
+
+ public static ResolvedMember createResolvedConstructor(Constructor aConstructor, World inWorld) {
+ ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.CONSTRUCTOR,
+ toResolvedType(aConstructor.getDeclaringClass(), (IReflectionWorld) inWorld), aConstructor.getModifiers(),
+ // to return what BCEL returns, the return type for ctor is void
+ UnresolvedType.VOID,// toResolvedType(aConstructor.getDeclaringClass(),(IReflectionWorld)inWorld),
+ "<init>", toResolvedTypeArray(aConstructor.getParameterTypes(), inWorld), toResolvedTypeArray(
+ aConstructor.getExceptionTypes(), inWorld), aConstructor);
+ if (inWorld instanceof IReflectionWorld) {
+ ret.setAnnotationFinder(((IReflectionWorld) inWorld).getAnnotationFinder());
+ }
+ ret.setGenericSignatureInformationProvider(createGenericSignatureProvider(inWorld));
+ return ret;
+ }
+
+ public static ResolvedMember createResolvedField(Field aField, World inWorld) {
+ ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.FIELD,
+ toResolvedType(aField.getDeclaringClass(), (IReflectionWorld) inWorld), aField.getModifiers(), toResolvedType(
+ aField.getType(), (IReflectionWorld) inWorld), aField.getName(), new UnresolvedType[0], aField);
+ if (inWorld instanceof IReflectionWorld) {
+ ret.setAnnotationFinder(((IReflectionWorld) inWorld).getAnnotationFinder());
+ }
+ ret.setGenericSignatureInformationProvider(createGenericSignatureProvider(inWorld));
+ return ret;
+ }
+
+ public static ResolvedMember createHandlerMember(Class exceptionType, Class inType, World inWorld) {
+ return new ResolvedMemberImpl(org.aspectj.weaver.Member.HANDLER, toResolvedType(inType, (IReflectionWorld) inWorld),
+ Modifier.STATIC, "<catch>", "(" + inWorld.resolve(exceptionType.getName()).getSignature() + ")V");
+ }
+
+ public static ResolvedType resolveTypeInWorld(Class aClass, World aWorld) {
+ // classes that represent arrays return a class name that is the signature of the array type, ho-hum...
+ String className = aClass.getName();
+ if (aClass.isArray()) {
+ return aWorld.resolve(UnresolvedType.forSignature(className.replace('.', '/')));
+ } else {
+ return aWorld.resolve(className);
+ }
+ }
+
+ private static ResolvedType toResolvedType(Class aClass, IReflectionWorld aWorld) {
+ return aWorld.resolve(aClass);
+ }
+
+ private static ResolvedType[] toResolvedTypeArray(Class[] classes, World inWorld) {
+ ResolvedType[] ret = new ResolvedType[classes.length];
+ for (int i = 0; i < ret.length; i++) {
+ ret[i] = ((IReflectionWorld) inWorld).resolve(classes[i]);
+ }
+ return ret;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedResolvedMemberImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedResolvedMemberImpl.java
new file mode 100644
index 000000000..ba8f1330e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionBasedResolvedMemberImpl.java
@@ -0,0 +1,162 @@
+/* *******************************************************************
+ * Copyright (c) 2005, 2017 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Member;
+
+import org.aspectj.weaver.AnnotationAJ;
+import org.aspectj.weaver.MemberKind;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedMemberImpl;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+
+/**
+ * Subtype of ResolvedMemberImpl used in reflection world. Knows how to get annotations from a java.lang.reflect.Member
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class ReflectionBasedResolvedMemberImpl extends ResolvedMemberImpl {
+
+ private AnnotationFinder annotationFinder = null;
+ private GenericSignatureInformationProvider gsigInfoProvider = new Java14GenericSignatureInformationProvider();
+
+ /**
+ * If true then only runtime visible annotations have been resolved via reflection. If class retention
+ * annotations are also required (later) then the cache will have to be rebuilt using a more detailed
+ * dig into the class file.
+ */
+ private boolean onlyRuntimeAnnotationsCached;
+
+ private Member reflectMember;
+
+ public ReflectionBasedResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers,
+ UnresolvedType returnType, String name, UnresolvedType[] parameterTypes, Member reflectMember) {
+ super(kind, declaringType, modifiers, returnType, name, parameterTypes);
+ this.reflectMember = reflectMember;
+ }
+
+ public ReflectionBasedResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers,
+ UnresolvedType returnType, String name, UnresolvedType[] parameterTypes, UnresolvedType[] checkedExceptions,
+ Member reflectMember) {
+ super(kind, declaringType, modifiers, returnType, name, parameterTypes, checkedExceptions);
+ this.reflectMember = reflectMember;
+ }
+
+ public ReflectionBasedResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers,
+ UnresolvedType returnType, String name, UnresolvedType[] parameterTypes, UnresolvedType[] checkedExceptions,
+ ResolvedMember backingGenericMember, Member reflectMember) {
+ super(kind, declaringType, modifiers, returnType, name, parameterTypes, checkedExceptions, backingGenericMember);
+ this.reflectMember = reflectMember;
+ }
+
+ public ReflectionBasedResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name,
+ String signature, Member reflectMember) {
+ super(kind, declaringType, modifiers, name, signature);
+ this.reflectMember = reflectMember;
+ }
+
+ public Member getMember() {
+ return this.reflectMember;
+ }
+
+ public void setGenericSignatureInformationProvider(GenericSignatureInformationProvider gsigProvider) {
+ this.gsigInfoProvider = gsigProvider;
+ }
+
+ @Override
+ public UnresolvedType[] getGenericParameterTypes() {
+ return this.gsigInfoProvider.getGenericParameterTypes(this);
+ }
+
+ @Override
+ public UnresolvedType getGenericReturnType() {
+ return this.gsigInfoProvider.getGenericReturnType(this);
+ }
+
+ @Override
+ public boolean isSynthetic() {
+ return this.gsigInfoProvider.isSynthetic(this);
+ }
+
+ @Override
+ public boolean isVarargsMethod() {
+ return this.gsigInfoProvider.isVarArgs(this);
+ }
+
+ @Override
+ public boolean isBridgeMethod() {
+ return this.gsigInfoProvider.isBridge(this);
+ }
+
+ public void setAnnotationFinder(AnnotationFinder finder) {
+ this.annotationFinder = finder;
+ }
+
+ @Override
+ public boolean hasAnnotation(UnresolvedType ofType) {
+ boolean areRuntimeRetentionAnnotationsSufficient = false;
+ if (ofType instanceof ResolvedType) {
+ areRuntimeRetentionAnnotationsSufficient = ((ResolvedType)ofType).isAnnotationWithRuntimeRetention();
+ }
+ unpackAnnotations(areRuntimeRetentionAnnotationsSufficient);
+ return super.hasAnnotation(ofType);
+ }
+
+ @Override
+ public boolean hasAnnotations() {
+ unpackAnnotations(false);
+ return super.hasAnnotations();
+ }
+
+ @Override
+ public ResolvedType[] getAnnotationTypes() {
+ unpackAnnotations(false);
+ return super.getAnnotationTypes();
+ }
+
+ @Override
+ public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
+ unpackAnnotations(false);
+ if (annotationFinder == null || annotationTypes == null) {
+ return null;
+ }
+ for (ResolvedType type : annotationTypes) {
+ if (type.getSignature().equals(ofType.getSignature())) {
+ return annotationFinder.getAnnotationOfType(ofType, reflectMember);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getAnnotationDefaultValue() {
+ if (annotationFinder == null) {
+ return null;
+ }
+ return annotationFinder.getAnnotationDefaultValue(reflectMember);
+ }
+
+ @Override
+ public ResolvedType[][] getParameterAnnotationTypes() {
+ if (parameterAnnotationTypes == null && annotationFinder != null) {
+ parameterAnnotationTypes = annotationFinder.getParameterAnnotationTypes(reflectMember);
+ }
+ return parameterAnnotationTypes;
+ }
+
+ private void unpackAnnotations(boolean areRuntimeRetentionAnnotationsSufficient) {
+ if (annotationFinder != null && (annotationTypes == null || (!areRuntimeRetentionAnnotationsSufficient && onlyRuntimeAnnotationsCached))) {
+ annotationTypes = annotationFinder.getAnnotations(reflectMember, areRuntimeRetentionAnnotationsSufficient);
+ onlyRuntimeAnnotationsCached = areRuntimeRetentionAnnotationsSufficient;
+ }
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionFastMatchInfo.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionFastMatchInfo.java
new file mode 100644
index 000000000..eb891c3bf
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionFastMatchInfo.java
@@ -0,0 +1,42 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.patterns.FastMatchInfo;
+import org.aspectj.weaver.tools.MatchingContext;
+
+/**
+ * An implementation of FastMatchInfo that can also expose a MatchingContext.
+ *
+ * @author Adrian Colyer
+ * @since 1.5.1
+ */
+public class ReflectionFastMatchInfo extends FastMatchInfo {
+
+ private final MatchingContext context;
+
+ public ReflectionFastMatchInfo(ResolvedType type, Shadow.Kind kind, MatchingContext context, World world) {
+ super(type, kind, world);
+ this.context = context;
+ }
+
+ /**
+ * @return Returns the matching context.
+ */
+ public MatchingContext getMatchingContext() {
+ return this.context;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionShadow.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionShadow.java
new file mode 100644
index 000000000..0c6277e59
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionShadow.java
@@ -0,0 +1,366 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Var;
+import org.aspectj.weaver.tools.MatchingContext;
+
+/**
+ * @author colyer
+ *
+ */
+public class ReflectionShadow extends Shadow {
+
+ private final World world;
+ private final ResolvedType enclosingType;
+ private final ResolvedMember enclosingMember;
+ private final MatchingContext matchContext;
+ private Var thisVar = null;
+ private Var targetVar = null;
+ private Var[] argsVars = null;
+ private Var atThisVar = null;
+ private Var atTargetVar = null;
+ private Map atArgsVars = new HashMap();
+ private Map withinAnnotationVar = new HashMap();
+ private Map withinCodeAnnotationVar = new HashMap();
+ private Map annotationVar = new HashMap();
+ private AnnotationFinder annotationFinder;
+
+ public static Shadow makeExecutionShadow(World inWorld, java.lang.reflect.Member forMethod, MatchingContext withContext) {
+ Kind kind = (forMethod instanceof Method) ? Shadow.MethodExecution : Shadow.ConstructorExecution;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forMethod, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new ReflectionShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeAdviceExecutionShadow(World inWorld, java.lang.reflect.Method forMethod, MatchingContext withContext) {
+ Kind kind = Shadow.AdviceExecution;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedAdviceMember(forMethod, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new ReflectionShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, java.lang.reflect.Member withinCode,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = aMember instanceof Method ? Shadow.MethodCall : Shadow.ConstructorCall;
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, Class thisClass,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, thisClass, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(thisClass, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = aMember instanceof Method ? Shadow.MethodCall : Shadow.ConstructorCall;
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeStaticInitializationShadow(World inWorld, Class forType, MatchingContext withContext) {
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(forType, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.StaticInitialization;
+ return new ReflectionShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makePreInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) {
+ Kind kind = Shadow.PreInitialization;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new ReflectionShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) {
+ Kind kind = Shadow.Initialization;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new ReflectionShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, Class withinType, MatchingContext withContext) {
+ Kind kind = Shadow.ExceptionHandler;
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, withinType, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType, withinType, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(withinType, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, java.lang.reflect.Member withinCode,
+ MatchingContext withContext) {
+ Kind kind = Shadow.ExceptionHandler;
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType,
+ withinCode.getDeclaringClass(), inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldGetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) {
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldGet;
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldGetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, inMember, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldGet;
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldSetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) {
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldSet;
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldSetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, inMember, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldSet;
+ return new ReflectionShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public ReflectionShadow(World world, Kind kind, Member signature, Shadow enclosingShadow, ResolvedType enclosingType,
+ ResolvedMember enclosingMember, MatchingContext withContext) {
+ super(kind, signature, enclosingShadow);
+ this.world = world;
+ this.enclosingType = enclosingType;
+ this.enclosingMember = enclosingMember;
+ this.matchContext = withContext;
+ if (world instanceof IReflectionWorld) {
+ this.annotationFinder = ((IReflectionWorld) world).getAnnotationFinder();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getIWorld()
+ */
+ public World getIWorld() {
+ return world;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getThisVar()
+ */
+ public Var getThisVar() {
+ if (thisVar == null && hasThis()) {
+ thisVar = ReflectionVar.createThisVar(getThisType().resolve(world), this.annotationFinder);
+ }
+ return thisVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getTargetVar()
+ */
+ public Var getTargetVar() {
+ if (targetVar == null && hasTarget()) {
+ targetVar = ReflectionVar.createTargetVar(getThisType().resolve(world), this.annotationFinder);
+ }
+ return targetVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getEnclosingType()
+ */
+ public UnresolvedType getEnclosingType() {
+ return this.enclosingType;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getArgVar(int)
+ */
+ public Var getArgVar(int i) {
+ if (argsVars == null) {
+ this.argsVars = new Var[this.getArgCount()];
+ for (int j = 0; j < this.argsVars.length; j++) {
+ this.argsVars[j] = ReflectionVar.createArgsVar(getArgType(j).resolve(world), j, this.annotationFinder);
+ }
+ }
+ if (i < argsVars.length) {
+ return argsVars[i];
+ } else {
+ return null;
+ }
+ }
+
+ public Var getThisJoinPointVar() {
+ return null;
+ }
+
+ public Var getThisJoinPointStaticPartVar() {
+ return null;
+ }
+
+ public Var getThisEnclosingJoinPointStaticPartVar() {
+ return null;
+ }
+
+ public Var getThisAspectInstanceVar(ResolvedType aspectType) {
+ return null;
+ }
+
+ public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (annotationVar.get(annType) == null) {
+ Var v = ReflectionVar.createAtAnnotationVar(annType, this.annotationFinder);
+ annotationVar.put(annType, v);
+ }
+ return (Var) annotationVar.get(annType);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getWithinAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (withinAnnotationVar.get(annType) == null) {
+ Var v = ReflectionVar.createWithinAnnotationVar(annType, this.annotationFinder);
+ withinAnnotationVar.put(annType, v);
+ }
+ return (Var) withinAnnotationVar.get(annType);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getWithinCodeAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (withinCodeAnnotationVar.get(annType) == null) {
+ Var v = ReflectionVar.createWithinCodeAnnotationVar(annType, this.annotationFinder);
+ withinCodeAnnotationVar.put(annType, v);
+ }
+ return (Var) withinCodeAnnotationVar.get(annType);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getThisAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getThisAnnotationVar(UnresolvedType forAnnotationType) {
+ if (atThisVar == null) {
+ atThisVar = ReflectionVar.createThisAnnotationVar(forAnnotationType.resolve(world), this.annotationFinder);
+ }
+ return atThisVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getTargetAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) {
+ if (atTargetVar == null) {
+ atTargetVar = ReflectionVar.createTargetAnnotationVar(forAnnotationType.resolve(world), this.annotationFinder);
+ }
+ return atTargetVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getArgAnnotationVar(int, org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (atArgsVars.get(annType) == null) {
+ Var[] vars = new Var[getArgCount()];
+ atArgsVars.put(annType, vars);
+ }
+ Var[] vars = (Var[]) atArgsVars.get(annType);
+ if (i > (vars.length - 1))
+ return null;
+ if (vars[i] == null) {
+ vars[i] = ReflectionVar.createArgsAnnotationVar(annType, i, this.annotationFinder);
+ }
+ return vars[i];
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getEnclosingCodeSignature()
+ */
+ public Member getEnclosingCodeSignature() {
+ // XXX this code is copied from BcelShadow with one minor change...
+ if (getKind().isEnclosingKind()) {
+ return getSignature();
+ } else if (getKind() == Shadow.PreInitialization) {
+ // PreInit doesn't enclose code but its signature
+ // is correctly the signature of the ctor.
+ return getSignature();
+ } else if (enclosingShadow == null) {
+ return this.enclosingMember;
+ } else {
+ return enclosingShadow.getSignature();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getSourceLocation()
+ */
+ public ISourceLocation getSourceLocation() {
+ return null;
+ }
+
+ public MatchingContext getMatchingContext() {
+ return this.matchContext;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionVar.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionVar.java
new file mode 100644
index 000000000..59876a737
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionVar.java
@@ -0,0 +1,169 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Member;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.ast.Var;
+
+/**
+ * A variable at a reflection shadow, used by the residual tests.
+ */
+public final class ReflectionVar extends Var {
+
+ static final int THIS_VAR = 0;
+ static final int TARGET_VAR = 1;
+ static final int ARGS_VAR = 2;
+ static final int AT_THIS_VAR = 3;
+ static final int AT_TARGET_VAR = 4;
+ static final int AT_ARGS_VAR = 5;
+ static final int AT_WITHIN_VAR = 6;
+ static final int AT_WITHINCODE_VAR = 7;
+ static final int AT_ANNOTATION_VAR = 8;
+
+ private AnnotationFinder annotationFinder = null;
+
+// static {
+// try {
+// Class java15AnnotationFinder = Class.forName("org.aspectj.weaver.reflect.Java15AnnotationFinder");
+// annotationFinder = (AnnotationFinder) java15AnnotationFinder.newInstance();
+// } catch(ClassNotFoundException ex) {
+// // must be on 1.4 or earlier
+// } catch(IllegalAccessException ex) {
+// // not so good
+// throw new RuntimeException("AspectJ internal error",ex);
+// } catch(InstantiationException ex) {
+// throw new RuntimeException("AspectJ internal error",ex);
+// }
+// }
+
+ private int argsIndex = 0;
+ private int varType;
+
+ public static ReflectionVar createThisVar(ResolvedType type,AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(type,finder);
+ ret.varType = THIS_VAR;
+ return ret;
+ }
+
+ public static ReflectionVar createTargetVar(ResolvedType type, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(type,finder);
+ ret.varType = TARGET_VAR;
+ return ret;
+ }
+
+ public static ReflectionVar createArgsVar(ResolvedType type, int index, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(type,finder);
+ ret.varType = ARGS_VAR;
+ ret.argsIndex = index;
+ return ret;
+ }
+
+ public static ReflectionVar createThisAnnotationVar(ResolvedType type, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(type,finder);
+ ret.varType = AT_THIS_VAR;
+ return ret;
+ }
+
+ public static ReflectionVar createTargetAnnotationVar(ResolvedType type, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(type,finder);
+ ret.varType = AT_TARGET_VAR;
+ return ret;
+ }
+
+ public static ReflectionVar createArgsAnnotationVar(ResolvedType type, int index, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(type,finder);
+ ret.varType = AT_ARGS_VAR;
+ ret.argsIndex = index;
+ return ret;
+ }
+
+ public static ReflectionVar createWithinAnnotationVar(ResolvedType annType, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(annType,finder);
+ ret.varType = AT_WITHIN_VAR;
+ return ret;
+ }
+
+ public static ReflectionVar createWithinCodeAnnotationVar(ResolvedType annType, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(annType,finder);
+ ret.varType = AT_WITHINCODE_VAR;
+ return ret;
+ }
+
+ public static ReflectionVar createAtAnnotationVar(ResolvedType annType, AnnotationFinder finder) {
+ ReflectionVar ret = new ReflectionVar(annType,finder);
+ ret.varType = AT_ANNOTATION_VAR;
+ return ret;
+ }
+
+ private ReflectionVar(ResolvedType type,AnnotationFinder finder) {
+ super(type);
+ this.annotationFinder = finder;
+ }
+
+
+ public Object getBindingAtJoinPoint(Object thisObject, Object targetObject, Object[] args) {
+ return getBindingAtJoinPoint(thisObject,targetObject,args,null,null,null);
+ }
+ /**
+ * At a join point with the given this, target, and args, return the object to which this
+ * var is bound.
+ * @param thisObject
+ * @param targetObject
+ * @param args
+ * @return
+ */
+ public Object getBindingAtJoinPoint(
+ Object thisObject,
+ Object targetObject,
+ Object[] args,
+ Member subject,
+ Member withinCode,
+ Class withinType) {
+ switch( this.varType) {
+ case THIS_VAR: return thisObject;
+ case TARGET_VAR: return targetObject;
+ case ARGS_VAR:
+ if (this.argsIndex > (args.length - 1)) return null;
+ return args[argsIndex];
+ case AT_THIS_VAR:
+ if (annotationFinder != null) {
+ return annotationFinder.getAnnotation(getType(), thisObject);
+ } else return null;
+ case AT_TARGET_VAR:
+ if (annotationFinder != null) {
+ return annotationFinder.getAnnotation(getType(), targetObject);
+ } else return null;
+ case AT_ARGS_VAR:
+ if (this.argsIndex > (args.length - 1)) return null;
+ if (annotationFinder != null) {
+ return annotationFinder.getAnnotation(getType(), args[argsIndex]);
+ } else return null;
+ case AT_WITHIN_VAR:
+ if (annotationFinder != null) {
+ return annotationFinder.getAnnotationFromClass(getType(), withinType);
+ } else return null;
+ case AT_WITHINCODE_VAR:
+ if (annotationFinder != null) {
+ return annotationFinder.getAnnotationFromMember(getType(), withinCode);
+ } else return null;
+ case AT_ANNOTATION_VAR:
+ if (annotationFinder != null) {
+ return annotationFinder.getAnnotationFromMember(getType(), subject);
+ } else return null;
+ }
+
+ return null;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionWorld.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionWorld.java
new file mode 100644
index 000000000..c784ff288
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ReflectionWorld.java
@@ -0,0 +1,248 @@
+/* *******************************************************************
+ * Copyright (c) 2005-2017 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.aspectj.bridge.AbortException;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.util.LangUtil;
+import org.aspectj.weaver.BCException;
+import org.aspectj.weaver.IWeavingSupport;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ReferenceTypeDelegate;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.WeakClassLoaderReference;
+import org.aspectj.weaver.World;
+
+/**
+ * A ReflectionWorld is used solely for purposes of type resolution based on the runtime classpath (java.lang.reflect). It does not
+ * support weaving operations (creation of mungers etc..).
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class ReflectionWorld extends World implements IReflectionWorld {
+
+ private static Map<WeakClassLoaderReference, ReflectionWorld> rworlds = Collections.synchronizedMap(new HashMap<WeakClassLoaderReference, ReflectionWorld>());
+
+ private WeakClassLoaderReference classLoaderReference;
+ private AnnotationFinder annotationFinder;
+ private boolean mustUseOneFourDelegates = false; // for testing
+ private Map<String,Class<?>> inProgressResolutionClasses = new HashMap<String,Class<?>>();
+
+ public static ReflectionWorld getReflectionWorldFor(WeakClassLoaderReference classLoaderReference) {
+
+ // Temporarily do as before. Although the cache makes things faster it needs a bit more thought because
+ // if the world has pointcutdesignators registered then someone may inadvertently register additional
+ // ones on reusing a world (when they would be expecting a clean world). We can't automatically
+ // clear them because we don't know when they are finished with.
+ return new ReflectionWorld(classLoaderReference);
+
+ /*
+ synchronized (rworlds) {
+ // Tidyup any no longer relevant entries...
+ for (Iterator<Map.Entry<WeakClassLoaderReference, ReflectionWorld>> it = rworlds.entrySet().iterator();
+ it.hasNext();) {
+ Map.Entry<WeakClassLoaderReference, ReflectionWorld> entry = it.next();
+ if (entry.getKey().getClassLoader() == null) {
+ it.remove();
+ }
+ }
+ ReflectionWorld rworld = null;
+ if (classLoaderReference.getClassLoader() != null) {
+ rworld = rworlds.get(classLoaderReference);
+ if (rworld == null) {
+ rworld = new ReflectionWorld(classLoaderReference);
+ rworlds.put(classLoaderReference, rworld);
+ }
+ }
+ return rworld;
+ }
+ */
+ }
+
+ public static void cleanUpWorlds() {
+ synchronized (rworlds) {
+ rworlds.clear();
+ }
+ }
+
+ private ReflectionWorld() {
+ // super();
+ // this.setMessageHandler(new ExceptionBasedMessageHandler());
+ // setBehaveInJava5Way(LangUtil.is15VMOrGreater());
+ // this.classLoaderReference = new
+ // WeakClassLoaderReference(ReflectionWorld.class.getClassLoader());
+ // this.annotationFinder =
+ // makeAnnotationFinderIfAny(classLoaderReference.getClassLoader(),
+ // this);
+ }
+
+ public ReflectionWorld(WeakClassLoaderReference classloaderRef) {
+ this.setMessageHandler(new ExceptionBasedMessageHandler());
+ setBehaveInJava5Way(LangUtil.is15VMOrGreater());
+ classLoaderReference = classloaderRef;
+ annotationFinder = makeAnnotationFinderIfAny(classLoaderReference.getClassLoader(), this);
+ }
+
+ public ReflectionWorld(ClassLoader aClassLoader) {
+ super();
+ this.setMessageHandler(new ExceptionBasedMessageHandler());
+ setBehaveInJava5Way(LangUtil.is15VMOrGreater());
+ classLoaderReference = new WeakClassLoaderReference(aClassLoader);
+ annotationFinder = makeAnnotationFinderIfAny(classLoaderReference.getClassLoader(), this);
+ }
+
+ public ReflectionWorld(boolean forceUseOf14Delegates, ClassLoader aClassLoader) {
+ this(aClassLoader);
+ this.mustUseOneFourDelegates = forceUseOf14Delegates;
+ if (forceUseOf14Delegates) {
+ // Dont use 1.4 delegates and yet allow autoboxing
+ this.setBehaveInJava5Way(false);
+ }
+ }
+
+ public static AnnotationFinder makeAnnotationFinderIfAny(ClassLoader loader, World world) {
+ AnnotationFinder annotationFinder = null;
+ try {
+ if (LangUtil.is15VMOrGreater()) {
+ Class<?> java15AnnotationFinder = Class.forName("org.aspectj.weaver.reflect.Java15AnnotationFinder");
+ annotationFinder = (AnnotationFinder) java15AnnotationFinder.newInstance();
+ annotationFinder.setClassLoader(loader);
+ annotationFinder.setWorld(world);
+ }
+ } catch (ClassNotFoundException ex) {
+ // must be on 1.4 or earlier
+ } catch (IllegalAccessException ex) {
+ // not so good
+ throw new BCException("AspectJ internal error", ex);
+ } catch (InstantiationException ex) {
+ throw new BCException("AspectJ internal error", ex);
+ }
+ return annotationFinder;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoaderReference.getClassLoader();
+ }
+
+ public AnnotationFinder getAnnotationFinder() {
+ return annotationFinder;
+ }
+
+ public ResolvedType resolve(Class aClass) {
+ return resolve(this, aClass);
+ }
+
+ public static ResolvedType resolve(World world, Class<?> aClass) {
+ // classes that represent arrays return a class name that is the
+ // signature of the array type, ho-hum...
+ String className = aClass.getName();
+ if (aClass.isArray()) {
+ return world.resolve(UnresolvedType.forSignature(className.replace('.', '/')));
+ } else {
+ return world.resolve(className);
+ }
+ }
+
+ /**
+ * Resolve a type using the specified class. Normal resolution in a reflection
+ * world uses Class.forName() via the classloader (attached to this world)
+ * in order to find a named type then builds a reference type and a reference
+ * type delegate based on that. For some classes generated at runtime (e.g.
+ * proxy or lambda representation) the forName() call will not work. In those
+ * situations we should just use the clazz we have.
+ *
+ * Should the whole thing switch from using forName() to using the clazz objects?
+ * Possibly but that introduces a lot of change and we don't have a lot
+ * of test coverage for this scenario (reflection world). What we are doing
+ * right now is that this can optionally be used if the regular resolution
+ * scheme did not work.
+ *
+ * Although AspectJ is *not* multi threaded or re-entrant, Spring doesn't
+ * always respect that. There might be an issue here if two attempts are
+ * made to resolve the same thing at the same time via this method.
+ *
+ * @param clazz the class to use as the delegate for the resolved type
+ */
+ public ResolvedType resolveUsingClass(Class<?> clazz) {
+ String signature = UnresolvedType.forName(clazz.getName()).getSignature();
+ try {
+ inProgressResolutionClasses.put(signature, clazz);
+ return resolve(clazz.getName());
+ } finally {
+ inProgressResolutionClasses.remove(signature);
+ }
+ }
+
+ protected ReferenceTypeDelegate resolveDelegate(ReferenceType ty) {
+ ReferenceTypeDelegate result;
+ if (mustUseOneFourDelegates) {
+ result = ReflectionBasedReferenceTypeDelegateFactory.create14Delegate(ty, this, classLoaderReference.getClassLoader());
+ } else {
+ result = ReflectionBasedReferenceTypeDelegateFactory.createDelegate(ty, this, classLoaderReference.getClassLoader());
+ }
+ if (result == null && inProgressResolutionClasses.size() != 0) {
+ // Is it a class that cannot be loaded (i.e. it was generated) but we already know about?
+ Class<?> clazz = inProgressResolutionClasses.get(ty.getSignature());
+ if (clazz != null) {
+ result = ReflectionBasedReferenceTypeDelegateFactory.createDelegate(ty,this,clazz);
+ }
+ }
+ return result;
+ }
+
+ public static class ReflectionWorldException extends RuntimeException {
+
+ private static final long serialVersionUID = -3432261918302793005L;
+
+ public ReflectionWorldException(String message) {
+ super(message);
+ }
+ }
+
+ private static class ExceptionBasedMessageHandler implements IMessageHandler {
+
+ public boolean handleMessage(IMessage message) throws AbortException {
+ throw new ReflectionWorldException(message.toString());
+ }
+
+ public boolean isIgnoring(org.aspectj.bridge.IMessage.Kind kind) {
+ if (kind == IMessage.INFO) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void dontIgnore(org.aspectj.bridge.IMessage.Kind kind) {
+ // empty
+ }
+
+ public void ignore(org.aspectj.bridge.IMessage.Kind kind) {
+ // empty
+ }
+
+ }
+
+ public IWeavingSupport getWeavingSupport() {
+ return null;
+ }
+
+ public boolean isLoadtimeWeaving() {
+ return true;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ShadowMatchImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ShadowMatchImpl.java
new file mode 100644
index 000000000..350a77ba9
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/ShadowMatchImpl.java
@@ -0,0 +1,202 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Member;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.And;
+import org.aspectj.weaver.ast.Call;
+import org.aspectj.weaver.ast.FieldGetCall;
+import org.aspectj.weaver.ast.HasAnnotation;
+import org.aspectj.weaver.ast.ITestVisitor;
+import org.aspectj.weaver.ast.Instanceof;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Not;
+import org.aspectj.weaver.ast.Or;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.ast.Var;
+import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
+import org.aspectj.weaver.patterns.ExposedState;
+import org.aspectj.weaver.tools.DefaultMatchingContext;
+import org.aspectj.weaver.tools.JoinPointMatch;
+import org.aspectj.weaver.tools.MatchingContext;
+import org.aspectj.weaver.tools.PointcutParameter;
+import org.aspectj.weaver.tools.ShadowMatch;
+
+/**
+ * @author colyer Implementation of ShadowMatch for reflection based worlds.
+ */
+public class ShadowMatchImpl implements ShadowMatch {
+
+ private FuzzyBoolean match;
+ private ExposedState state;
+ private Test residualTest;
+ private PointcutParameter[] params;
+ private Member withinCode;
+ private Member subject;
+ private Class<?> withinType;
+ private MatchingContext matchContext = new DefaultMatchingContext();
+
+ public ShadowMatchImpl(FuzzyBoolean match, Test test, ExposedState state, PointcutParameter[] params) {
+ this.match = match;
+ this.residualTest = test;
+ this.state = state;
+ this.params = params;
+ }
+
+ public void setWithinCode(Member aMember) {
+ this.withinCode = aMember;
+ }
+
+ public void setSubject(Member aMember) {
+ this.subject = aMember;
+ }
+
+ public void setWithinType(Class<?> aClass) {
+ this.withinType = aClass;
+ }
+
+ public boolean alwaysMatches() {
+ return match.alwaysTrue();
+ }
+
+ public boolean maybeMatches() {
+ return match.maybeTrue();
+ }
+
+ public boolean neverMatches() {
+ return match.alwaysFalse();
+ }
+
+ public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
+ if (neverMatches()) {
+ return JoinPointMatchImpl.NO_MATCH;
+ }
+ if (new RuntimeTestEvaluator(residualTest, thisObject, targetObject, args, this.matchContext).matches()) {
+ return new JoinPointMatchImpl(getPointcutParameters(thisObject, targetObject, args));
+ } else {
+ return JoinPointMatchImpl.NO_MATCH;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.tools.ShadowMatch#setMatchingContext(org.aspectj.weaver.tools.MatchingContext)
+ */
+ public void setMatchingContext(MatchingContext aMatchContext) {
+ this.matchContext = aMatchContext;
+ }
+
+ private PointcutParameter[] getPointcutParameters(Object thisObject, Object targetObject, Object[] args) {
+ Var[] vars = state.vars;
+ PointcutParameterImpl[] bindings = new PointcutParameterImpl[params.length];
+ for (int i = 0; i < bindings.length; i++) {
+ bindings[i] = new PointcutParameterImpl(params[i].getName(), params[i].getType());
+ bindings[i].setBinding(((ReflectionVar) vars[i]).getBindingAtJoinPoint(thisObject, targetObject, args, subject,
+ withinCode, withinType));
+ }
+ return bindings;
+ }
+
+ private static class RuntimeTestEvaluator implements ITestVisitor {
+
+ private boolean matches = true;
+ private final Test test;
+ private final Object thisObject;
+ private final Object targetObject;
+ private final Object[] args;
+ private final MatchingContext matchContext;
+
+ public RuntimeTestEvaluator(Test aTest, Object thisObject, Object targetObject, Object[] args, MatchingContext context) {
+ this.test = aTest;
+ this.thisObject = thisObject;
+ this.targetObject = targetObject;
+ this.args = args;
+ this.matchContext = context;
+ }
+
+ public boolean matches() {
+ test.accept(this);
+ return matches;
+ }
+
+ public void visit(And e) {
+ boolean leftMatches = new RuntimeTestEvaluator(e.getLeft(), thisObject, targetObject, args, matchContext).matches();
+ if (!leftMatches) {
+ matches = false;
+ } else {
+ matches = new RuntimeTestEvaluator(e.getRight(), thisObject, targetObject, args, matchContext).matches();
+ }
+ }
+
+ public void visit(Instanceof instanceofTest) {
+ ReflectionVar v = (ReflectionVar) instanceofTest.getVar();
+ Object value = v.getBindingAtJoinPoint(thisObject, targetObject, args);
+ World world = v.getType().getWorld();
+ ResolvedType desiredType = instanceofTest.getType().resolve(world);
+ if (value == null) {
+ matches = false;
+ } else {
+ ResolvedType actualType = world.resolve(value.getClass().getName());
+ matches = desiredType.isAssignableFrom(actualType);
+ }
+ }
+
+ public void visit(MatchingContextBasedTest matchingContextTest) {
+ matches = matchingContextTest.matches(this.matchContext);
+ }
+
+ public void visit(Not not) {
+ matches = !new RuntimeTestEvaluator(not.getBody(), thisObject, targetObject, args, matchContext).matches();
+ }
+
+ public void visit(Or or) {
+ boolean leftMatches = new RuntimeTestEvaluator(or.getLeft(), thisObject, targetObject, args, matchContext).matches();
+ if (leftMatches) {
+ matches = true;
+ } else {
+ matches = new RuntimeTestEvaluator(or.getRight(), thisObject, targetObject, args, matchContext).matches();
+ }
+ }
+
+ public void visit(Literal literal) {
+ if (literal == Literal.FALSE) {
+ matches = false;
+ } else {
+ matches = true;
+ }
+ }
+
+ public void visit(Call call) {
+ throw new UnsupportedOperationException("Can't evaluate call test at runtime");
+ }
+
+ public void visit(FieldGetCall fieldGetCall) {
+ throw new UnsupportedOperationException("Can't evaluate fieldGetCall test at runtime");
+ }
+
+ public void visit(HasAnnotation hasAnnotation) {
+ ReflectionVar v = (ReflectionVar) hasAnnotation.getVar();
+ Object value = v.getBindingAtJoinPoint(thisObject, targetObject, args);
+ World world = v.getType().getWorld();
+ ResolvedType actualVarType = world.resolve(value.getClass().getName());
+ ResolvedType requiredAnnotationType = hasAnnotation.getAnnotationType().resolve(world);
+ matches = actualVarType.hasAnnotation(requiredAnnotationType);
+ }
+
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadow.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadow.java
new file mode 100644
index 000000000..c151b228e
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadow.java
@@ -0,0 +1,401 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.weaver.Member;
+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;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.Var;
+import org.aspectj.weaver.tools.MatchingContext;
+
+/**
+ * @author colyer
+ *
+ */
+public class StandardShadow extends Shadow {
+
+ private final World world;
+ private final ResolvedType enclosingType;
+ private final ResolvedMember enclosingMember;
+ private final MatchingContext matchContext;
+ private Var thisVar = null;
+ private Var targetVar = null;
+ private Var[] argsVars = null;
+ private Var atThisVar = null;
+ private Var atTargetVar = null;
+ private Map atArgsVars = new HashMap();
+ private Map withinAnnotationVar = new HashMap();
+ private Map withinCodeAnnotationVar = new HashMap();
+ private Map annotationVar = new HashMap();
+ private AnnotationFinder annotationFinder;
+
+ public static Shadow makeExecutionShadow(World inWorld, java.lang.reflect.Member forMethod, MatchingContext withContext) {
+ Kind kind = (forMethod instanceof Method) ? Shadow.MethodExecution : Shadow.ConstructorExecution;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forMethod, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeExecutionShadow(World inWorld, ResolvedMember forMethod, MatchingContext withContext) {
+ Kind kind = forMethod.getName().equals("<init>") ? Shadow.ConstructorExecution : Shadow.MethodExecution;
+ // Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forMethod, inWorld);
+ // ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new StandardShadow(inWorld, kind, forMethod, null, (ResolvedType) forMethod.getDeclaringType(), null, withContext);
+ }
+
+ public static Shadow makeAdviceExecutionShadow(World inWorld, java.lang.reflect.Method forMethod, MatchingContext withContext) {
+ Kind kind = Shadow.AdviceExecution;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedAdviceMember(forMethod, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeCallShadow(World inWorld, ResolvedMember aMember, ResolvedMember withinCode,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode, withContext);
+ // Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld);
+ // ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld);
+ // ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = !aMember.getName().equals("<init>") ? Shadow.MethodCall : Shadow.ConstructorCall;
+ return new StandardShadow(inWorld, kind, aMember, enclosingShadow, (ResolvedType) withinCode.getDeclaringType(),
+ withinCode, withContext);
+ }
+
+ public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, Class thisClass,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, thisClass, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(thisClass, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = aMember instanceof Method ? Shadow.MethodCall : Shadow.ConstructorCall;
+ return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeStaticInitializationShadow(World inWorld, Class forType, MatchingContext withContext) {
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(forType, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.StaticInitialization;
+ return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeStaticInitializationShadow(World inWorld, ResolvedType forType, MatchingContext withContext) {
+ ResolvedMember[] members = forType.getDeclaredMethods();
+ int clinit = -1;
+ for (int i = 0; i < members.length && clinit == -1; i++) {
+ if (members[i].getName().equals("<clinit>")) {
+ clinit = i;
+ }
+ }
+ // Member signature = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(forType, inWorld);
+ Kind kind = Shadow.StaticInitialization;
+ if (clinit == -1) {
+ Member clinitMember = new ResolvedMemberImpl(org.aspectj.weaver.Member.STATIC_INITIALIZATION, forType, Modifier.STATIC,
+ UnresolvedType.VOID, "<clinit>", new UnresolvedType[0], new UnresolvedType[0]);
+ return new StandardShadow(inWorld, kind, clinitMember, null, forType, null, withContext);
+ } else {
+ return new StandardShadow(inWorld, kind, members[clinit], null, forType, null, withContext);
+ }
+ }
+
+ public static Shadow makePreInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) {
+ Kind kind = Shadow.PreInitialization;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) {
+ Kind kind = Shadow.Initialization;
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld);
+ ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
+ return new StandardShadow(inWorld, kind, signature, null, enclosingType, null, withContext);
+ }
+
+ public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, Class withinType, MatchingContext withContext) {
+ Kind kind = Shadow.ExceptionHandler;
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, withinType, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType, withinType, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(withinType, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, java.lang.reflect.Member withinCode,
+ MatchingContext withContext) {
+ Kind kind = Shadow.ExceptionHandler;
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType,
+ withinCode.getDeclaringClass(), inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldGetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) {
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldGet;
+ return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldGetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, inMember, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldGet;
+ return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldSetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) {
+ Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldSet;
+ return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public static Shadow makeFieldSetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember,
+ MatchingContext withContext) {
+ Shadow enclosingShadow = makeExecutionShadow(inWorld, inMember, withContext);
+ Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
+ ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld);
+ ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
+ Kind kind = Shadow.FieldSet;
+ return new StandardShadow(inWorld, kind, signature, enclosingShadow, enclosingType, enclosingMember, withContext);
+ }
+
+ public StandardShadow(World world, Kind kind, Member signature, Shadow enclosingShadow, ResolvedType enclosingType,
+ ResolvedMember enclosingMember, MatchingContext withContext) {
+ super(kind, signature, enclosingShadow);
+ this.world = world;
+ this.enclosingType = enclosingType;
+ this.enclosingMember = enclosingMember;
+ this.matchContext = withContext;
+ if (world instanceof IReflectionWorld) {
+ this.annotationFinder = ((IReflectionWorld) world).getAnnotationFinder();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getIWorld()
+ */
+ public World getIWorld() {
+ return world;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getThisVar()
+ */
+ public Var getThisVar() {
+ if (thisVar == null && hasThis()) {
+ thisVar = ReflectionVar.createThisVar(getThisType().resolve(world), this.annotationFinder);
+ }
+ return thisVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getTargetVar()
+ */
+ public Var getTargetVar() {
+ if (targetVar == null && hasTarget()) {
+ targetVar = ReflectionVar.createTargetVar(getThisType().resolve(world), this.annotationFinder);
+ }
+ return targetVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getEnclosingType()
+ */
+ public UnresolvedType getEnclosingType() {
+ return this.enclosingType;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getArgVar(int)
+ */
+ public Var getArgVar(int i) {
+ if (argsVars == null) {
+ this.argsVars = new Var[this.getArgCount()];
+ for (int j = 0; j < this.argsVars.length; j++) {
+ this.argsVars[j] = ReflectionVar.createArgsVar(getArgType(j).resolve(world), j, this.annotationFinder);
+ }
+ }
+ if (i < argsVars.length) {
+ return argsVars[i];
+ } else {
+ return null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getThisJoinPointVar()
+ */
+ public Var getThisJoinPointVar() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Var getThisJoinPointStaticPartVar() {
+ return null;
+ }
+
+ public Var getThisEnclosingJoinPointStaticPartVar() {
+ return null;
+ }
+
+ public Var getThisAspectInstanceVar(ResolvedType aspectType) {
+ return null;
+ }
+
+ public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (annotationVar.get(annType) == null) {
+ Var v = ReflectionVar.createAtAnnotationVar(annType, this.annotationFinder);
+ annotationVar.put(annType, v);
+ }
+ return (Var) annotationVar.get(annType);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getWithinAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (withinAnnotationVar.get(annType) == null) {
+ Var v = ReflectionVar.createWithinAnnotationVar(annType, this.annotationFinder);
+ withinAnnotationVar.put(annType, v);
+ }
+ return (Var) withinAnnotationVar.get(annType);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getWithinCodeAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (withinCodeAnnotationVar.get(annType) == null) {
+ Var v = ReflectionVar.createWithinCodeAnnotationVar(annType, this.annotationFinder);
+ withinCodeAnnotationVar.put(annType, v);
+ }
+ return (Var) withinCodeAnnotationVar.get(annType);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getThisAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getThisAnnotationVar(UnresolvedType forAnnotationType) {
+ if (atThisVar == null) {
+ atThisVar = ReflectionVar.createThisAnnotationVar(forAnnotationType.resolve(world), this.annotationFinder);
+ }
+ return atThisVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getTargetAnnotationVar(org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) {
+ if (atTargetVar == null) {
+ atTargetVar = ReflectionVar.createTargetAnnotationVar(forAnnotationType.resolve(world), this.annotationFinder);
+ }
+ return atTargetVar;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getArgAnnotationVar(int, org.aspectj.weaver.UnresolvedType)
+ */
+ public Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType) {
+ ResolvedType annType = forAnnotationType.resolve(world);
+ if (atArgsVars.get(annType) == null) {
+ Var[] vars = new Var[getArgCount()];
+ atArgsVars.put(annType, vars);
+ }
+ Var[] vars = (Var[]) atArgsVars.get(annType);
+ if (i > (vars.length - 1))
+ return null;
+ if (vars[i] == null) {
+ vars[i] = ReflectionVar.createArgsAnnotationVar(annType, i, this.annotationFinder);
+ }
+ return vars[i];
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getEnclosingCodeSignature()
+ */
+ public Member getEnclosingCodeSignature() {
+ // XXX this code is copied from BcelShadow with one minor change...
+ if (getKind().isEnclosingKind()) {
+ return getSignature();
+ } else if (getKind() == Shadow.PreInitialization) {
+ // PreInit doesn't enclose code but its signature
+ // is correctly the signature of the ctor.
+ return getSignature();
+ } else if (enclosingShadow == null) {
+ return this.enclosingMember;
+ } else {
+ return enclosingShadow.getSignature();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.Shadow#getSourceLocation()
+ */
+ public ISourceLocation getSourceLocation() {
+ return null;
+ }
+
+ public MatchingContext getMatchingContext() {
+ return this.matchContext;
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadowMatchImpl.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadowMatchImpl.java
new file mode 100644
index 000000000..baeab0334
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/reflect/StandardShadowMatchImpl.java
@@ -0,0 +1,196 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.reflect;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.ast.And;
+import org.aspectj.weaver.ast.Call;
+import org.aspectj.weaver.ast.FieldGetCall;
+import org.aspectj.weaver.ast.HasAnnotation;
+import org.aspectj.weaver.ast.ITestVisitor;
+import org.aspectj.weaver.ast.Instanceof;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Not;
+import org.aspectj.weaver.ast.Or;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
+import org.aspectj.weaver.patterns.ExposedState;
+import org.aspectj.weaver.tools.DefaultMatchingContext;
+import org.aspectj.weaver.tools.JoinPointMatch;
+import org.aspectj.weaver.tools.MatchingContext;
+import org.aspectj.weaver.tools.PointcutParameter;
+import org.aspectj.weaver.tools.ShadowMatch;
+
+/**
+ * @author colyer Implementation of ShadowMatch for reflection based worlds.
+ */
+public class StandardShadowMatchImpl implements ShadowMatch {
+
+ private FuzzyBoolean match;
+ private ExposedState state;
+ private Test residualTest;
+ private PointcutParameter[] params;
+ private ResolvedMember withinCode;
+ private ResolvedMember subject;
+ private ResolvedType withinType;
+ private MatchingContext matchContext = new DefaultMatchingContext();
+
+ public StandardShadowMatchImpl(FuzzyBoolean match, Test test, ExposedState state, PointcutParameter[] params) {
+ this.match = match;
+ this.residualTest = test;
+ this.state = state;
+ this.params = params;
+ }
+
+ public void setWithinCode(ResolvedMember aMember) {
+ this.withinCode = aMember;
+ }
+
+ public void setSubject(ResolvedMember aMember) {
+ this.subject = aMember;
+ }
+
+ public void setWithinType(ResolvedType aClass) {
+ this.withinType = aClass;
+ }
+
+ public boolean alwaysMatches() {
+ return match.alwaysTrue();
+ }
+
+ public boolean maybeMatches() {
+ return match.maybeTrue();
+ }
+
+ public boolean neverMatches() {
+ return match.alwaysFalse();
+ }
+
+ public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
+ if (neverMatches())
+ return JoinPointMatchImpl.NO_MATCH;
+ if (new RuntimeTestEvaluator(residualTest, thisObject, targetObject, args, this.matchContext).matches()) {
+ return new JoinPointMatchImpl(getPointcutParameters(thisObject, targetObject, args));
+ } else {
+ return JoinPointMatchImpl.NO_MATCH;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.aspectj.weaver.tools.ShadowMatch#setMatchingContext(org.aspectj.weaver.tools.MatchingContext)
+ */
+ public void setMatchingContext(MatchingContext aMatchContext) {
+ this.matchContext = aMatchContext;
+ }
+
+ private PointcutParameter[] getPointcutParameters(Object thisObject, Object targetObject, Object[] args) {
+ // Var[] vars = state.vars;
+ // PointcutParameterImpl[] bindings = new PointcutParameterImpl[params.length];
+ // for (int i = 0; i < bindings.length; i++) {
+ // bindings[i] = new PointcutParameterImpl(params[i].getName(), params[i].getType());
+ // bindings[i].setBinding(((ReflectionVar) vars[i]).getBindingAtJoinPoint(thisObject, targetObject, args, subject,
+ // withinCode, withinType));
+ // }
+ // return bindings;
+ return null;
+ }
+
+ private static class RuntimeTestEvaluator implements ITestVisitor {
+
+ private boolean matches = true;
+ private final Test test;
+ private final Object thisObject;
+ private final Object targetObject;
+ private final Object[] args;
+ private final MatchingContext matchContext;
+
+ public RuntimeTestEvaluator(Test aTest, Object thisObject, Object targetObject, Object[] args, MatchingContext context) {
+ this.test = aTest;
+ this.thisObject = thisObject;
+ this.targetObject = targetObject;
+ this.args = args;
+ this.matchContext = context;
+ }
+
+ public boolean matches() {
+ test.accept(this);
+ return matches;
+ }
+
+ public void visit(And e) {
+ boolean leftMatches = new RuntimeTestEvaluator(e.getLeft(), thisObject, targetObject, args, matchContext).matches();
+ if (!leftMatches) {
+ matches = false;
+ } else {
+ matches = new RuntimeTestEvaluator(e.getRight(), thisObject, targetObject, args, matchContext).matches();
+ }
+ }
+
+ public void visit(Instanceof i) {
+ ReflectionVar v = (ReflectionVar) i.getVar();
+ Object value = v.getBindingAtJoinPoint(thisObject, targetObject, args);
+ World world = v.getType().getWorld();
+ ResolvedType desiredType = i.getType().resolve(world);
+ ResolvedType actualType = world.resolve(value.getClass().getName());
+ matches = desiredType.isAssignableFrom(actualType);
+ }
+
+ public void visit(MatchingContextBasedTest matchingContextTest) {
+ matches = matchingContextTest.matches(this.matchContext);
+ }
+
+ public void visit(Not not) {
+ matches = !new RuntimeTestEvaluator(not.getBody(), thisObject, targetObject, args, matchContext).matches();
+ }
+
+ public void visit(Or or) {
+ boolean leftMatches = new RuntimeTestEvaluator(or.getLeft(), thisObject, targetObject, args, matchContext).matches();
+ if (leftMatches) {
+ matches = true;
+ } else {
+ matches = new RuntimeTestEvaluator(or.getRight(), thisObject, targetObject, args, matchContext).matches();
+ }
+ }
+
+ public void visit(Literal literal) {
+ if (literal == Literal.FALSE) {
+ matches = false;
+ } else {
+ matches = true;
+ }
+ }
+
+ public void visit(Call call) {
+ throw new UnsupportedOperationException("Can't evaluate call test at runtime");
+ }
+
+ public void visit(FieldGetCall fieldGetCall) {
+ throw new UnsupportedOperationException("Can't evaluate fieldGetCall test at runtime");
+ }
+
+ public void visit(HasAnnotation hasAnnotation) {
+ ReflectionVar v = (ReflectionVar) hasAnnotation.getVar();
+ Object value = v.getBindingAtJoinPoint(thisObject, targetObject, args);
+ World world = v.getType().getWorld();
+ ResolvedType actualVarType = world.resolve(value.getClass().getName());
+ ResolvedType requiredAnnotationType = hasAnnotation.getAnnotationType().resolve(world);
+ matches = actualVarType.hasAnnotation(requiredAnnotationType);
+ }
+
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/AbstractTrace.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/AbstractTrace.java
new file mode 100644
index 000000000..52217f880
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/AbstractTrace.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.regex.Pattern;
+
+import org.aspectj.bridge.IMessage.Kind;
+
+public abstract class AbstractTrace implements Trace {
+
+ private static final Pattern packagePrefixPattern = Pattern.compile("([^.])[^.]*(\\.)");
+
+ protected Class<?> tracedClass;
+
+ private static SimpleDateFormat timeFormat;
+
+ protected AbstractTrace (Class clazz) {
+ this.tracedClass = clazz;
+ }
+
+ public abstract void enter (String methodName, Object thiz, Object[] args);
+
+ public abstract void enter(String methodName, Object thiz);
+
+ public abstract void exit(String methodName, Object ret);
+
+ public abstract void exit(String methodName, Throwable th);
+
+ /*
+ * Convenience methods
+ */
+ public void enter (String methodName) {
+ enter(methodName,null,null);
+ }
+
+ public void enter (String methodName, Object thiz, Object arg) {
+ enter(methodName,thiz,new Object[] { arg });
+ }
+
+ public void enter (String methodName, Object thiz, boolean z) {
+ enter(methodName,thiz,new Boolean(z));
+ }
+
+ public void exit (String methodName, boolean b) {
+ exit(methodName,new Boolean(b));
+ }
+
+ public void exit (String methodName, int i) {
+ exit(methodName,new Integer(i));
+ }
+
+ public void event (String methodName, Object thiz, Object arg) {
+ event(methodName,thiz,new Object[] { arg });
+ }
+
+ public void warn(String message) {
+ warn(message,null);
+ }
+
+ public void error(String message) {
+ error(message,null);
+ }
+
+ public void fatal (String message) {
+ fatal(message,null);
+ }
+
+ /*
+ * Formatting
+ */
+ protected String formatMessage(String kind, String className, String methodName, Object thiz, Object[] args) {
+ StringBuffer message = new StringBuffer();
+ Date now = new Date();
+ message.append(formatDate(now)).append(" ");
+ message.append(Thread.currentThread().getName()).append(" ");
+ message.append(kind).append(" ");
+ message.append(formatClassName(className));
+ message.append(".").append(methodName);
+ if (thiz != null) message.append(" ").append(formatObj(thiz));
+ if (args != null) message.append(" ").append(formatArgs(args));
+ return message.toString();
+ }
+
+ /**
+ * @param className full dotted class name
+ * @return short version of class name with package collapse to initials
+ */
+ private String formatClassName(String className) {
+ return packagePrefixPattern.matcher(className).replaceAll("$1.");
+ }
+
+ protected String formatMessage(String kind, String text, Throwable th) {
+ StringBuffer message = new StringBuffer();
+ Date now = new Date();
+ message.append(formatDate(now)).append(" ");
+ message.append(Thread.currentThread().getName()).append(" ");
+ message.append(kind).append(" ");
+ message.append(text);
+ if (th != null) message.append(" ").append(formatObj(th));
+ return message.toString();
+ }
+
+ private static String formatDate (Date date) {
+ if (timeFormat == null) {
+ timeFormat = new SimpleDateFormat("HH:mm:ss.SSS");
+ }
+
+ return timeFormat.format(date);
+ }
+
+ /**
+ * Format objects safely avoiding toString which can cause recursion,
+ * NullPointerExceptions or highly verbose results.
+ *
+ * @param obj parameter to be formatted
+ * @return the formatted parameter
+ */
+ protected Object formatObj(Object obj) {
+
+ /* These classes have a safe implementation of toString() */
+ if (obj == null
+ || obj instanceof String
+ || obj instanceof Number
+ || obj instanceof Boolean
+ || obj instanceof Exception
+ || obj instanceof Character
+ || obj instanceof Class
+ || obj instanceof File
+ || obj instanceof StringBuffer
+ || obj instanceof URL
+ || obj instanceof Kind
+ ) return obj;
+ else if (obj.getClass().isArray()) {
+ return formatArray(obj);
+ }
+ else if (obj instanceof Collection) {
+ return formatCollection((Collection)obj);
+ }
+ else try {
+
+ // Classes can provide an alternative implementation of toString()
+ if (obj instanceof Traceable) {
+ return ((Traceable)obj).toTraceString();
+ }
+
+ // classname@hashcode
+ else return formatClassName(obj.getClass().getName()) + "@" + Integer.toHexString(System.identityHashCode(obj));
+
+ /* Object.hashCode() can be override and may thow an exception */
+ } catch (Exception ex) {
+ return obj.getClass().getName() + "@FFFFFFFF";
+ }
+ }
+
+ protected String formatArray(Object obj) {
+ return obj.getClass().getComponentType().getName() + "[" + Array.getLength(obj) + "]";
+ }
+
+ protected String formatCollection(Collection<?> c) {
+ return c.getClass().getName() + "(" + c.size() + ")";
+ }
+
+ /**
+ * Format arguments into a comma separated list
+ *
+ * @param names array of argument names
+ * @param args array of arguments
+ * @return the formated list
+ */
+ protected String formatArgs(Object[] args) {
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < args.length; i++) {
+ sb.append(formatObj(args[i]));
+ if (i < args.length-1) sb.append(", ");
+ }
+
+ return sb.toString();
+ }
+
+ protected Object[] formatObjects(Object[] args) {
+ for (int i = 0; i < args.length; i++) {
+ args[i] = formatObj(args[i]);
+ }
+
+ return args;
+ }
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTrace.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTrace.java
new file mode 100644
index 000000000..25562c050
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTrace.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class CommonsTrace extends AbstractTrace {
+
+ private Log log;
+ private String className;
+
+ public CommonsTrace (Class clazz) {
+ super(clazz);
+ this.log = LogFactory.getLog(clazz);
+ this.className = tracedClass.getName();
+ }
+
+ public void enter(String methodName, Object thiz, Object[] args) {
+ if (log.isDebugEnabled()) {
+ log.debug(formatMessage(">", className, methodName, thiz, args));
+ }
+ }
+
+ public void enter(String methodName, Object thiz) {
+ if (log.isDebugEnabled()) {
+ log.debug(formatMessage(">", className, methodName, thiz, null));
+ }
+ }
+
+ public void exit(String methodName, Object ret) {
+ if (log.isDebugEnabled()) {
+ log.debug(formatMessage("<", className, methodName, ret, null));
+ }
+ }
+
+ public void exit(String methodName, Throwable th) {
+ if (log.isDebugEnabled()) {
+ log.debug(formatMessage("<", className, methodName, th, null));
+ }
+ }
+
+ public void exit(String methodName) {
+ if (log.isDebugEnabled()) {
+ log.debug(formatMessage("<", className, methodName, null, null));
+ }
+ }
+
+ public void event(String methodName, Object thiz, Object[] args) {
+ if (log.isDebugEnabled()) {
+ log.debug(formatMessage("-", className, methodName, thiz, args));
+ }
+ }
+
+ public void event(String methodName) {
+ if (log.isDebugEnabled()) {
+ log.debug(formatMessage("-", className, methodName, null, null));
+ }
+ }
+
+ public boolean isTraceEnabled () {
+ return log.isDebugEnabled();
+ }
+
+ public void setTraceEnabled (boolean b) {
+ }
+
+ public void debug (String message) {
+ if (log.isDebugEnabled()) {
+ log.debug(message);
+ }
+ }
+
+ public void info(String message) {
+ if (log.isInfoEnabled()) {
+ log.info(message);
+ }
+ }
+
+ public void warn (String message, Throwable th) {
+ if (log.isWarnEnabled()) {
+ log.warn(message,th);
+ }
+ }
+
+ public void error (String message, Throwable th) {
+ if (log.isErrorEnabled()) {
+ log.error(message,th);
+ }
+ }
+
+ public void fatal (String message, Throwable th) {
+ if (log.isFatalEnabled()) {
+ log.fatal(message,th);
+ }
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTraceFactory.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTraceFactory.java
new file mode 100644
index 000000000..8f9f91e98
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/CommonsTraceFactory.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import org.apache.commons.logging.LogFactory;
+//OPTIMIZE move out of main weaver for now?
+public class CommonsTraceFactory extends TraceFactory {
+
+ private LogFactory logFactory = LogFactory.getFactory();
+
+ public Trace getTrace(Class clazz) {
+ return new CommonsTrace(clazz);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ContextBasedMatcher.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ContextBasedMatcher.java
new file mode 100644
index 000000000..fc247dc90
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ContextBasedMatcher.java
@@ -0,0 +1,65 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * Pointcut expression interface for pointcut
+ * expressions returned by a
+ * PointcutDesignatorHandler. Provides an additional
+ * matching method for matching based on context
+ * information over and above that normally used
+ * by AspectJ.
+ *
+ * @see MatchingContext
+ *
+ */
+public interface ContextBasedMatcher {
+
+ /**
+ * return true iff this matcher could ever match
+ * a join point in the given type
+ * @deprecated use couldMatchJoinPointsInType(Class,MatchingContext) instead
+ */
+ boolean couldMatchJoinPointsInType(Class aClass);
+
+ /**
+ * return true iff this matcher could ever match
+ * a join point in the given type, may also use any
+ * match context information available
+ * @since 1.5.1
+ */
+ boolean couldMatchJoinPointsInType(Class aClass, MatchingContext matchContext);
+
+ /**
+ * return true if matchesStatically can ever return
+ * FuzzyBoolean.MAYBE (necessitating a per-join point test
+ * to determine matching at a given join point).
+ */
+ boolean mayNeedDynamicTest();
+
+ /**
+ * Return FuzzyBoolean.YES if a join point with the given
+ * matching context is always matched.
+ * Return FuzzyBoolean.NO if a join point with the given
+ * matching context is never matched.
+ * Return FuzzyBoolean.MAYBE if a match cannot be determined
+ * statically (whilst generating a ShadowMatch), and must
+ * be determined on a per-join point basis.
+ */
+ FuzzyBoolean matchesStatically(MatchingContext matchContext);
+
+ /**
+ * Called during processing of ShadowMatch.matchesJoinPoint
+ * when matchesStatically returned FuzzyBoolean.MAYBE.
+ */
+ boolean matchesDynamically(MatchingContext matchContext);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultMatchingContext.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultMatchingContext.java
new file mode 100644
index 000000000..fa47a87a3
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultMatchingContext.java
@@ -0,0 +1,56 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Default implementation of MatchingContext, backed
+ * by a Map.
+ */
+public class DefaultMatchingContext implements MatchingContext {
+
+ private Map contextMap = new HashMap();
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.tools.MatchingContext#hasContextParameter(java.lang.String)
+ */
+ public boolean hasContextBinding(String contextParameterName) {
+ return this.contextMap.containsKey(contextParameterName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.weaver.tools.MatchingContext#get(java.lang.String)
+ */
+ public Object getBinding(String contextParameterName) {
+ return this.contextMap.get(contextParameterName);
+ }
+
+ /**
+ * Add a context binding with the given name and value
+ * @param name
+ * @param value
+ */
+ public void addContextBinding(String name, Object value) {
+ this.contextMap.put(name, value);
+ }
+
+ /**
+ * Remove the context binding with the given name
+ * @param name
+ */
+ public void removeContextBinding(String name) {
+ this.contextMap.remove(name);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTrace.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTrace.java
new file mode 100644
index 000000000..7e2ab0d8f
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTrace.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import java.io.PrintStream;
+
+public class DefaultTrace extends AbstractTrace {
+
+ private boolean traceEnabled = false;
+ private PrintStream print = System.err;
+
+ public DefaultTrace(Class clazz) {
+ super(clazz);
+ }
+
+ public boolean isTraceEnabled() {
+ return traceEnabled;
+ }
+
+ public void setTraceEnabled(boolean b) {
+ traceEnabled = b;
+ }
+
+ public void enter(String methodName, Object thiz, Object[] args) {
+ if (traceEnabled) {
+ println(formatMessage(">", tracedClass.getName(), methodName, thiz, args));
+ }
+ }
+
+ public void enter(String methodName, Object thiz) {
+ if (traceEnabled) {
+ println(formatMessage(">", tracedClass.getName(), methodName, thiz, null));
+ }
+ }
+
+ public void exit(String methodName, Object ret) {
+ if (traceEnabled) {
+ println(formatMessage("<", tracedClass.getName(), methodName, ret, null));
+ }
+ }
+
+ public void exit(String methodName) {
+ if (traceEnabled) {
+ println(formatMessage("<", tracedClass.getName(), methodName, null, null));
+ }
+ }
+
+ public void exit(String methodName, Throwable th) {
+ if (traceEnabled) {
+ println(formatMessage("<", tracedClass.getName(), methodName, th, null));
+ }
+ }
+
+ public void event(String methodName, Object thiz, Object[] args) {
+ if (traceEnabled) {
+ println(formatMessage("-", tracedClass.getName(), methodName, thiz, args));
+ }
+ }
+
+ public void event(String methodName) {
+ if (traceEnabled) {
+ println(formatMessage("-", tracedClass.getName(), methodName, null, null));
+ }
+ }
+
+ public void debug(String message) {
+ println(formatMessage("?", message, null));
+ }
+
+ public void info(String message) {
+ println(formatMessage("I", message, null));
+ }
+
+ public void warn(String message, Throwable th) {
+ println(formatMessage("W", message, th));
+ if (th != null)
+ th.printStackTrace();
+ }
+
+ public void error(String message, Throwable th) {
+ println(formatMessage("E", message, th));
+ if (th != null)
+ th.printStackTrace();
+ }
+
+ public void fatal(String message, Throwable th) {
+ println(formatMessage("X", message, th));
+ if (th != null)
+ th.printStackTrace();
+ }
+
+ /**
+ * Template method that allows choice of destination for output
+ *
+ * @param s
+ * message to be traced
+ */
+ protected void println(String s) {
+ print.println(s);
+ }
+
+ public void setPrintStream(PrintStream printStream) {
+ this.print = printStream;
+ }
+
+ // private static boolean isTracingEnabled =
+ // getBoolean("org.aspectj.weaver.tools.tracing",false);
+ //
+ // private static boolean getBoolean (String name, boolean def) {
+ // String defaultValue = String.valueOf(def);
+ // String value = System.getProperty(name,defaultValue);
+ // return Boolean.valueOf(value).booleanValue();
+ // }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTraceFactory.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTraceFactory.java
new file mode 100644
index 000000000..c7860589a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/DefaultTraceFactory.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public class DefaultTraceFactory extends TraceFactory {
+
+ public final static String ENABLED_PROPERTY = "org.aspectj.tracing.enabled";
+ public final static String FILE_PROPERTY = "org.aspectj.tracing.file";
+
+ private boolean tracingEnabled = getBoolean(ENABLED_PROPERTY,false);
+ private PrintStream print;
+
+ public DefaultTraceFactory() {
+ String filename = System.getProperty(FILE_PROPERTY);
+ if (filename != null) {
+ File file = new File(filename);
+ try {
+ print = new PrintStream(new FileOutputStream(file));
+ }
+ catch (IOException ex) {
+ if (debug) ex.printStackTrace();
+ }
+ }
+ }
+
+ public boolean isEnabled() {
+ return tracingEnabled;
+ }
+
+ public Trace getTrace (Class clazz) {
+ DefaultTrace trace = new DefaultTrace(clazz);
+ trace.setTraceEnabled(tracingEnabled);
+ if (print != null) trace.setPrintStream(print);
+ return trace;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/FuzzyBoolean.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/FuzzyBoolean.java
new file mode 100644
index 000000000..77079c094
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/FuzzyBoolean.java
@@ -0,0 +1,37 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.tools;
+
+/**
+ * This class implements a boolean that includes a "maybe"
+ */
+public final class FuzzyBoolean {
+
+ // Note :- this implementation is not safe under serialization / deserialization
+ private String name;
+
+ public static final FuzzyBoolean YES = new FuzzyBoolean("YES");
+ public static final FuzzyBoolean NO = new FuzzyBoolean("NO");
+ public static final FuzzyBoolean MAYBE = new FuzzyBoolean("MAYBE");
+
+
+ public static final FuzzyBoolean fromBoolean(boolean b) {
+ return b ? YES : NO;
+ }
+
+ public String toString() { return name; }
+
+ private FuzzyBoolean() {}
+
+ private FuzzyBoolean(String n) { this.name = n; }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/GeneratedClassHandler.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/GeneratedClassHandler.java
new file mode 100644
index 000000000..6dd4fec18
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/GeneratedClassHandler.java
@@ -0,0 +1,30 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster, Adrian Colyer,
+ * Martin Lippert initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * Interface implemented by weaving class loaders to allow classes generated by
+ * the weaving process to be defined.
+ */
+public interface GeneratedClassHandler {
+
+ /**
+ * Accept class generated by WeavingAdaptor. The class loader should store
+ * the class definition in its local cache until called upon to load it.
+ * @param name class name
+ * @param originalBytes original class bytes
+ * @param weavedBytes woven class bytes
+ */
+ public void acceptClass (String name, byte[] originalBytes, byte[] weavedBytes);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ISupportsMessageContext.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ISupportsMessageContext.java
new file mode 100644
index 000000000..69e55b143
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ISupportsMessageContext.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import org.aspectj.bridge.IMessageContext;
+
+public interface ISupportsMessageContext {
+
+ public void setMessageContext (IMessageContext messageContext);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/JoinPointMatch.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/JoinPointMatch.java
new file mode 100644
index 000000000..588b3c0bc
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/JoinPointMatch.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * @author colyer
+ * The result of asking a ShadowMatch to match at a given join point.
+ */
+public interface JoinPointMatch {
+
+ /**
+ * True if the pointcut expression has matched at this join point, and false
+ * otherwise
+ */
+ boolean matches();
+
+ /**
+ * Get the parameter bindings at the matched join point.
+ * If the join point was not matched an empty array is returned.
+ */
+ PointcutParameter[] getParameterBindings();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/MatchingContext.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/MatchingContext.java
new file mode 100644
index 000000000..e668a30b7
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/MatchingContext.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * When extending AspectJ's pointcut parsing and
+ * matching with custom PointcutDesignatorHandlers,
+ * it may be necessary to match based on context information
+ * at a join point not exposed simply by java.lang.reflect
+ * member information or argument values. The matching context
+ * interface provides an extension point for the specification
+ * of additional shadow and join point context that can be
+ * taken into account during the matching process.
+ *
+ * @see DefaultMatchingContext
+ */
+public interface MatchingContext {
+
+ /**
+ * Returns true iff this matching context has a defined
+ * binding for the given context parameter.
+ * @param contextParameterName
+ */
+ boolean hasContextBinding(String contextParameterName);
+
+ /**
+ * returns the binding associated with the
+ * given context parameter name (or null if
+ * there is no such context).
+ * @param contextParameterName
+ * @return
+ */
+ Object getBinding(String contextParameterName);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutDesignatorHandler.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutDesignatorHandler.java
new file mode 100644
index 000000000..63f4a81e2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutDesignatorHandler.java
@@ -0,0 +1,49 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+
+/**
+ * The PointcutDesignator interface allows extension of the
+ * AspectJ pointcut language so that third-party tools integrating
+ * with AspectJ can add easily their own custom
+ * domain-specific designators and have them interoperate seamlessly
+ * with the standard AspectJ designators.
+ *
+ * A pointcut designator can only be used for matching, not for
+ * binding.
+ */
+public interface PointcutDesignatorHandler {
+
+ /**
+ * The name of this pointcut designator. For example,
+ * if this designator handles a "bean(&lt;NamePattern&gt;)
+ * format designator, this method would return "bean".
+ * @return
+ */
+ String getDesignatorName() ;
+
+ /**
+ * Parse the given expression string
+ * and return a ContextBasedMatcher that can be used
+ * for matching.
+ * @param expression the body of the pointcut expression.
+ * For example, given the expression "bean(*DAO)" the parse
+ * method will be called with the argument "*DAO".
+ * @return a pointcut expression that can be used for
+ * matching.
+ * @throws IllegalArgumentException if the expression
+ * is ill-formed.
+ */
+ ContextBasedMatcher parse(String expression);
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutExpression.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutExpression.java
new file mode 100644
index 000000000..6b598a50c
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutExpression.java
@@ -0,0 +1,204 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+
+package org.aspectj.weaver.tools;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+/**
+ * Represents an AspectJ pointcut expression and provides convenience methods to determine
+ * whether or not the pointcut matches join points specified in terms of the
+ * java.lang.reflect interfaces.
+ */
+public interface PointcutExpression {
+
+ /**
+ * Set the matching context to be used for
+ * subsequent calls to match.
+ * @see MatchingContext
+ */
+ void setMatchingContext(MatchingContext aMatchContext);
+
+ /**
+ * Determine whether or not this pointcut could ever match a join point in the given class.
+ * @param aClass the candidate class
+ * @return true iff this pointcut <i>may</i> match a join point within(aClass), and false otherwise
+ */
+ boolean couldMatchJoinPointsInType(Class aClass);
+
+ /**
+ * Returns true iff this pointcut contains any expression that might necessitate a dynamic test
+ * at some join point (e.g. args)
+ */
+ boolean mayNeedDynamicTest();
+
+ /**
+ * Determine whether or not this pointcut matches the execution of a given method.
+ * @param aMethod the method being executed
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing the execution of the method.
+ */
+ ShadowMatch matchesMethodExecution(Method aMethod );
+
+ /**
+ * Determine whether or not this pointcut matches the execution of a given constructor.
+ * @param aConstructor the constructor being executed
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing the execution of the constructor.
+ */
+ ShadowMatch matchesConstructorExecution(Constructor aConstructor);
+
+ /**
+ * Determine whether or not this pointcut matches the static initialization
+ * of the given class.
+ * @param aClass the class being statically initialized
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matchs join points representing the static initialization of the given type
+ */
+ ShadowMatch matchesStaticInitialization(Class aClass);
+
+ /**
+ * Determine whether or not this pointcut matches the execution of a given piece of advice.
+ * @param anAdviceMethod a method representing the advice being executed
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing the execution of the advice.
+ */
+ ShadowMatch matchesAdviceExecution(Method anAdviceMethod);
+
+ /**
+ * Determine whether or not this pointcut matches the initialization of an
+ * object initiated by a call to the given constructor.
+ * @param aConstructor the constructor initiating the initialization
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing initialization via the given constructor.
+ */
+ ShadowMatch matchesInitialization(Constructor aConstructor);
+
+ /**
+ * Determine whether or not this pointcut matches the pre-initialization of an
+ * object initiated by a call to the given constructor.
+ * @param aConstructor the constructor initiating the initialization
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing pre-initialization via the given constructor.
+ */
+ ShadowMatch matchesPreInitialization(Constructor aConstructor);
+
+ /**
+ * Determine whether or not this pointcut matches a method call to the given method, made during
+ * the execution of the given method or constructor.
+ * @param aMethod the method being called
+ * @param withinCode the Method or Constructor from within which the call is made
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing a call to this method during the execution of the given member.
+ */
+ ShadowMatch matchesMethodCall(Method aMethod, Member withinCode);
+
+ /**
+ * Determine whether or not this pointcut matches a method call to the given method, made outside
+ * of the scope of any method or constructor, but within the callerType (for example, during
+ * static initialization of the type).
+ * @param aMethod the method being called
+ * @param callerType the declared type of the caller
+ * @param receiverType the declared type of the recipient of the call
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing a call to this method during the execution of the given member.
+ */
+ ShadowMatch matchesMethodCall(Method aMethod, Class callerType);
+
+ /**
+ * Determine whether or not this pointcut matches a method call to the given constructor, made during
+ * the execution of the given method or constructor.
+ * @param aConstructor the constructor being called
+ * @param withinCode the Method or Constructor from within which the call is made
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing a call to this constructor during the execution of the given member.
+ */
+ ShadowMatch matchesConstructorCall(Constructor aConstructor, Member withinCode);
+
+ /**
+ * Determine whether or not this pointcut matches a method call to the given constructor, made outside
+ * of the scope of any method or constructor, but within the callerType.
+ * @param aConstructor the cosstructor being called
+ * @param callerType the declared type of the caller
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never
+ * matches join points representing a call to this constructor during the execution of the given member.
+ */
+ ShadowMatch matchesConstructorCall(Constructor aConstructor, Class callerType);
+
+ /**
+ * Determine whether or not this pointcut matches the execution of a given exception
+ * handler within the given method or constructor
+ * @param exceptionType the static type of the exception being handled
+ * @param withinCode the method or constructor in which the catch block is declared
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or
+ * never matches join points representing the handling of the given exception
+ */
+ ShadowMatch matchesHandler(Class exceptionType, Member withinCode);
+
+ /**
+ * Determine whether or not this pointcut matches the execution of a given exception
+ * handler outside of the scope of any method or constructor, but within the handling type.
+ * @param exceptionType the static type of the exception being handled
+ * @param handlingType the type in which the handler block is executing
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or
+ * never matches join points representing the handling of the given exception
+ */
+ ShadowMatch matchesHandler(Class exceptionType, Class handlingType);
+
+ /**
+ * Determine whether or not this pointcut matches a set of the given field from within the given
+ * method or constructor.
+ * @param aField the field being updated
+ * @param withinCode the Method or Constructor owning the call site
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or
+ * never matches field set join points for the given field and call site.
+ */
+ ShadowMatch matchesFieldSet(Field aField, Member withinCode);
+
+ /**
+ * Determine whether or not this pointcut matches a set of the given field outside of the
+ * scope of any method or constructor, but within the given type (for example, during
+ * static initialization).
+ * @param aField the field being updated
+ * @param withinType the type owning the call site
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or
+ * never matches field set join points for the given field and call site.
+ */
+ ShadowMatch matchesFieldSet(Field aField, Class withinType);
+
+ /**
+ * Determine whether or not this pointcut matches a get of the given field from within the given
+ * method or constructor.
+ * @param aField the field being updated
+ * @param withinCode the Method or Constructor owning the call site
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or
+ * never matches field get join points for the given field and call site.
+ */
+ ShadowMatch matchesFieldGet(Field aField, Member withinCode);
+
+ /**
+ * Determine whether or not this pointcut matches a get of the given field outside of the
+ * scope of any method or constructor, but within the given type (for example, during
+ * static initialization).
+ * @param aField the field being accessed
+ * @param withinType the type owning the call site
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or
+ * never matches field get join points for the given field and call site.
+ */
+ ShadowMatch matchesFieldGet(Field aField, Class withinType);
+
+ /**
+ * Return a string representation of this pointcut expression.
+ */
+ String getPointcutExpression();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParameter.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParameter.java
new file mode 100644
index 000000000..a0eaa108a
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParameter.java
@@ -0,0 +1,36 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * @author colyer
+ * Represents a parameter in a pointcut expression.
+ * For example pointcut pc(String s) : .....; has a PointcutParameter of
+ * name "s" and type String.
+ */
+public interface PointcutParameter {
+
+ /**
+ * The name of this parameter
+ */
+ String getName();
+
+ /**
+ * The type of the parameter
+ */
+ Class getType();
+
+ /**
+ * At a matched join point, the parameter binding.
+ */
+ Object getBinding();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParser.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParser.java
new file mode 100644
index 000000000..ca0fa3aca
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutParser.java
@@ -0,0 +1,582 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2017 Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.SourceLocation;
+import org.aspectj.weaver.BindingScope;
+import org.aspectj.weaver.IHasPosition;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.WeakClassLoaderReference;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.internal.tools.PointcutExpressionImpl;
+import org.aspectj.weaver.internal.tools.TypePatternMatcherImpl;
+import org.aspectj.weaver.patterns.AndPointcut;
+import org.aspectj.weaver.patterns.CflowPointcut;
+import org.aspectj.weaver.patterns.FormalBinding;
+import org.aspectj.weaver.patterns.IScope;
+import org.aspectj.weaver.patterns.KindedPointcut;
+import org.aspectj.weaver.patterns.NotPointcut;
+import org.aspectj.weaver.patterns.OrPointcut;
+import org.aspectj.weaver.patterns.ParserException;
+import org.aspectj.weaver.patterns.PatternParser;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.SimpleScope;
+import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
+import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+import org.aspectj.weaver.reflect.PointcutParameterImpl;
+import org.aspectj.weaver.reflect.ReflectionWorld;
+
+/**
+ * A PointcutParser can be used to build PointcutExpressions for a user-defined subset of AspectJ's pointcut language
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class PointcutParser {
+
+ private ReflectionWorld world;
+ private WeakClassLoaderReference classLoaderReference;
+ private final Set<PointcutPrimitive> supportedPrimitives;
+ private final Set<PointcutDesignatorHandler> pointcutDesignators = new HashSet<PointcutDesignatorHandler>();
+
+ /**
+ * @return a Set containing every PointcutPrimitive except if, cflow, and cflowbelow (useful for passing to PointcutParser
+ * constructor).
+ */
+ public static Set<PointcutPrimitive> getAllSupportedPointcutPrimitives() {
+ Set<PointcutPrimitive> primitives = new HashSet<PointcutPrimitive>();
+ primitives.add(PointcutPrimitive.ADVICE_EXECUTION);
+ primitives.add(PointcutPrimitive.ARGS);
+ primitives.add(PointcutPrimitive.CALL);
+ primitives.add(PointcutPrimitive.EXECUTION);
+ primitives.add(PointcutPrimitive.GET);
+ primitives.add(PointcutPrimitive.HANDLER);
+ primitives.add(PointcutPrimitive.INITIALIZATION);
+ primitives.add(PointcutPrimitive.PRE_INITIALIZATION);
+ primitives.add(PointcutPrimitive.SET);
+ primitives.add(PointcutPrimitive.STATIC_INITIALIZATION);
+ primitives.add(PointcutPrimitive.TARGET);
+ primitives.add(PointcutPrimitive.THIS);
+ primitives.add(PointcutPrimitive.WITHIN);
+ primitives.add(PointcutPrimitive.WITHIN_CODE);
+ primitives.add(PointcutPrimitive.AT_ANNOTATION);
+ primitives.add(PointcutPrimitive.AT_THIS);
+ primitives.add(PointcutPrimitive.AT_TARGET);
+ primitives.add(PointcutPrimitive.AT_ARGS);
+ primitives.add(PointcutPrimitive.AT_WITHIN);
+ primitives.add(PointcutPrimitive.AT_WITHINCODE);
+ primitives.add(PointcutPrimitive.REFERENCE);
+
+ return primitives;
+ }
+
+ /**
+ * Returns a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ * <p>
+ * When resolving types in pointcut expressions, the context classloader is used to find types.
+ * </p>
+ */
+ public static PointcutParser getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution() {
+ PointcutParser p = new PointcutParser();
+ p.setClassLoader(Thread.currentThread().getContextClassLoader());
+ return p;
+ }
+
+ /**
+ * Returns a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported
+ * pointcut primitives. The following restrictions apply:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ * <p>
+ * When resolving types in pointcut expressions, the context classloader is used to find types.
+ * </p>
+ *
+ * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
+ * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
+ */
+ public static PointcutParser getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
+ Set<PointcutPrimitive> supportedPointcutKinds) {
+ PointcutParser p = new PointcutParser(supportedPointcutKinds);
+ p.setClassLoader(Thread.currentThread().getContextClassLoader());
+ return p;
+ }
+
+ /**
+ * Returns a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ * <p>
+ * When resolving types in pointcut expressions, the given classloader is used to find types.
+ * </p>
+ */
+ public static PointcutParser getPointcutParserSupportingAllPrimitivesAndUsingSpecifiedClassloaderForResolution(
+ ClassLoader classLoader) {
+ PointcutParser p = new PointcutParser();
+ p.setClassLoader(classLoader);
+ return p;
+ }
+
+ /**
+ * Returns a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported
+ * pointcut primitives. The following restrictions apply:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ * <p>
+ * When resolving types in pointcut expressions, the given classloader is used to find types.
+ * </p>
+ *
+ * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
+ * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
+ */
+ public static PointcutParser getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
+ Set<PointcutPrimitive> supportedPointcutKinds, ClassLoader classLoader) {
+ PointcutParser p = new PointcutParser(supportedPointcutKinds);
+ p.setClassLoader(classLoader);
+ return p;
+ }
+
+ /**
+ * Create a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ */
+ protected PointcutParser() {
+ supportedPrimitives = getAllSupportedPointcutPrimitives();
+ setClassLoader(PointcutParser.class.getClassLoader());
+ }
+
+ /**
+ * Create a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported pointcut
+ * primitives. The following restrictions apply:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ *
+ * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
+ * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
+ */
+ private PointcutParser(Set<PointcutPrimitive> supportedPointcutKinds) {
+ supportedPrimitives = supportedPointcutKinds;
+ for (PointcutPrimitive pointcutPrimitive : supportedPointcutKinds) {
+ if ((pointcutPrimitive == PointcutPrimitive.IF) || (pointcutPrimitive == PointcutPrimitive.CFLOW)
+ || (pointcutPrimitive == PointcutPrimitive.CFLOW_BELOW)) {
+ throw new UnsupportedOperationException("Cannot handle if, cflow, and cflowbelow primitives");
+ }
+ }
+ setClassLoader(PointcutParser.class.getClassLoader());
+ }
+
+ protected void setWorld(ReflectionWorld aWorld) {
+ this.world = aWorld;
+ }
+
+ /**
+ * Set the classloader that this parser should use for type resolution.
+ *
+ * @param aLoader
+ */
+ protected void setClassLoader(ClassLoader aLoader) {
+ this.classLoaderReference = new WeakClassLoaderReference(aLoader);
+ world = ReflectionWorld.getReflectionWorldFor(this.classLoaderReference);
+ }
+
+ /**
+ * Set the classloader that this parser should use for type resolution.
+ *
+ * @param aLoader
+ * @param shareWorlds if true then two PointcutParsers operating using the same classloader will share a ReflectionWorld
+ */
+ protected void setClassLoader(ClassLoader aLoader, boolean shareWorlds) {
+ this.classLoaderReference = new WeakClassLoaderReference(aLoader);
+ if (shareWorlds) {
+ world = ReflectionWorld.getReflectionWorldFor(this.classLoaderReference);
+ } else {
+ world = new ReflectionWorld(classLoaderReference);
+ }
+ }
+
+ /**
+ * Set the lint properties for this parser from the given resource on the classpath.
+ *
+ * @param resourcePath path to a file containing aspectj lint properties
+ */
+ public void setLintProperties(String resourcePath) throws IOException {
+ URL url = this.classLoaderReference.getClassLoader().getResource(resourcePath);
+ InputStream is = url.openStream();
+ Properties p = new Properties();
+ p.load(is);
+ setLintProperties(p);
+ }
+
+ /**
+ * Set the lint properties for this parser from the given properties set.
+ *
+ * @param properties
+ */
+ public void setLintProperties(Properties properties) {
+ getWorld().getLint().setFromProperties(properties);
+ }
+
+ /**
+ * Register a new pointcut designator handler with this parser. This provides an extension mechansim for the integration of
+ * domain-specific pointcut designators with the AspectJ pointcut language.
+ *
+ * @param designatorHandler
+ */
+ public void registerPointcutDesignatorHandler(PointcutDesignatorHandler designatorHandler) {
+ this.pointcutDesignators.add(designatorHandler);
+ if (world != null) {
+ world.registerPointcutHandler(designatorHandler);
+ }
+ }
+
+ /**
+ * Create a pointcut parameter of the given name and type.
+ *
+ * @param name
+ * @param type
+ * @return
+ */
+ public PointcutParameter createPointcutParameter(String name, Class<?> type) {
+ return new PointcutParameterImpl(name, type);
+ }
+
+ /**
+ * Parse the given pointcut expression. A global scope is assumed for resolving any type references, and the pointcut must
+ * contain no formals (variables to be bound).
+ *
+ * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not
+ * supported by this PointcutParser.
+ * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression
+ */
+ public PointcutExpression parsePointcutExpression(String expression) throws UnsupportedPointcutPrimitiveException,
+ IllegalArgumentException {
+ return parsePointcutExpression(expression, null, new PointcutParameter[0]);
+ }
+
+ /**
+ * Parse the given pointcut expression. The pointcut is resolved as if it had been declared inside the inScope class (this
+ * allows the pointcut to contain unqualified references to other pointcuts declared in the same type for example). The pointcut
+ * may contain zero or more formal parameters to be bound at matched join points.
+ *
+ * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not
+ * supported by this PointcutParser.
+ * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression
+ */
+ public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
+ throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
+ PointcutExpressionImpl pcExpr = null;
+ try {
+ Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
+ pc = concretizePointcutExpression(pc, inScope, formalParameters);
+ validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
+ pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
+ } catch (ParserException pEx) {
+ throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
+ } catch (ReflectionWorld.ReflectionWorldException rwEx) {
+ throw new IllegalArgumentException(rwEx.getMessage());
+ }
+ return pcExpr;
+ }
+
+ protected Pointcut resolvePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters) {
+ try {
+ PatternParser parser = new PatternParser(expression);
+ parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
+ Pointcut pc = parser.parsePointcut(); // more correctly: parsePointcut(true)
+ validateAgainstSupportedPrimitives(pc, expression);
+ IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters);
+ pc = pc.resolve(resolutionScope);
+ return pc;
+ } catch (ParserException pEx) {
+ throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
+ }
+ }
+
+ protected Pointcut concretizePointcutExpression(Pointcut pc, Class<?> inScope, PointcutParameter[] formalParameters) {
+ ResolvedType declaringTypeForResolution = null;
+ if (inScope != null) {
+ declaringTypeForResolution = getWorld().resolve(inScope.getName());
+ } else {
+ declaringTypeForResolution = ResolvedType.OBJECT.resolve(getWorld());
+ }
+ IntMap arity = new IntMap(formalParameters.length);
+ for (int i = 0; i < formalParameters.length; i++) {
+ arity.put(i, i);
+ }
+ return pc.concretize(declaringTypeForResolution, declaringTypeForResolution, arity);
+ }
+
+ /**
+ * Parse the given aspectj type pattern, and return a matcher that can be used to match types using it.
+ *
+ * @param typePattern an aspectj type pattern
+ * @return a type pattern matcher that matches using the given pattern
+ * @throws IllegalArgumentException if the type pattern cannot be successfully parsed.
+ */
+ public TypePatternMatcher parseTypePattern(String typePattern) throws IllegalArgumentException {
+ try {
+ TypePattern tp = new PatternParser(typePattern).parseTypePattern();
+ tp.resolve(world);
+ return new TypePatternMatcherImpl(tp, world);
+ } catch (ParserException pEx) {
+ throw new IllegalArgumentException(buildUserMessageFromParserException(typePattern, pEx));
+ } catch (ReflectionWorld.ReflectionWorldException rwEx) {
+ throw new IllegalArgumentException(rwEx.getMessage());
+ }
+ }
+
+ private World getWorld() {
+ return world;
+ }
+
+ /* for testing */
+ Set<PointcutPrimitive> getSupportedPrimitives() {
+ return supportedPrimitives;
+ }
+
+ /* for testing */
+ IMessageHandler setCustomMessageHandler(IMessageHandler aHandler) {
+ IMessageHandler current = getWorld().getMessageHandler();
+ getWorld().setMessageHandler(aHandler);
+ return current;
+ }
+
+ private IScope buildResolutionScope(Class<?> inScope, PointcutParameter[] formalParameters) {
+ if (formalParameters == null) {
+ formalParameters = new PointcutParameter[0];
+ }
+ FormalBinding[] formalBindings = new FormalBinding[formalParameters.length];
+ for (int i = 0; i < formalBindings.length; i++) {
+ formalBindings[i] = new FormalBinding(toUnresolvedType(formalParameters[i].getType()), formalParameters[i].getName(), i);
+ }
+ if (inScope == null) {
+ return new SimpleScope(getWorld(), formalBindings);
+ } else {
+ ResolvedType inType = getWorld().resolve(inScope.getName());
+ ISourceContext sourceContext = new ISourceContext() {
+ public ISourceLocation makeSourceLocation(IHasPosition position) {
+ return new SourceLocation(new File(""), 0);
+ }
+
+ public ISourceLocation makeSourceLocation(int line, int offset) {
+ return new SourceLocation(new File(""), line);
+ }
+
+ public int getOffset() {
+ return 0;
+ }
+
+ public void tidy() {
+ }
+ };
+ return new BindingScope(inType, sourceContext, formalBindings);
+ }
+ }
+
+ private UnresolvedType toUnresolvedType(Class<?> clazz) {
+ if (clazz.isArray()) {
+ return UnresolvedType.forSignature(clazz.getName().replace('.', '/'));
+ } else {
+ return UnresolvedType.forName(clazz.getName());
+ }
+ }
+
+ private void validateAgainstSupportedPrimitives(Pointcut pc, String expression) {
+ switch (pc.getPointcutKind()) {
+ case Pointcut.AND:
+ validateAgainstSupportedPrimitives(((AndPointcut) pc).getLeft(), expression);
+ validateAgainstSupportedPrimitives(((AndPointcut) pc).getRight(), expression);
+ break;
+ case Pointcut.ARGS:
+ if (!supportedPrimitives.contains(PointcutPrimitive.ARGS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ARGS);
+ }
+ break;
+ case Pointcut.CFLOW:
+ CflowPointcut cfp = (CflowPointcut) pc;
+ if (cfp.isCflowBelow()) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW_BELOW);
+ } else {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW);
+ }
+ case Pointcut.HANDLER:
+ if (!supportedPrimitives.contains(PointcutPrimitive.HANDLER)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.HANDLER);
+ }
+ break;
+ case Pointcut.IF:
+ case Pointcut.IF_FALSE:
+ case Pointcut.IF_TRUE:
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.IF);
+ case Pointcut.KINDED:
+ validateKindedPointcut(((KindedPointcut) pc), expression);
+ break;
+ case Pointcut.NOT:
+ validateAgainstSupportedPrimitives(((NotPointcut) pc).getNegatedPointcut(), expression);
+ break;
+ case Pointcut.OR:
+ validateAgainstSupportedPrimitives(((OrPointcut) pc).getLeft(), expression);
+ validateAgainstSupportedPrimitives(((OrPointcut) pc).getRight(), expression);
+ break;
+ case Pointcut.THIS_OR_TARGET:
+ boolean isThis = ((ThisOrTargetPointcut) pc).isThis();
+ if (isThis && !supportedPrimitives.contains(PointcutPrimitive.THIS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.THIS);
+ } else if (!supportedPrimitives.contains(PointcutPrimitive.TARGET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.TARGET);
+ }
+ break;
+ case Pointcut.WITHIN:
+ if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN);
+ }
+ break;
+ case Pointcut.WITHINCODE:
+ if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN_CODE)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN_CODE);
+ }
+ break;
+ case Pointcut.ATTHIS_OR_TARGET:
+ isThis = ((ThisOrTargetAnnotationPointcut) pc).isThis();
+ if (isThis && !supportedPrimitives.contains(PointcutPrimitive.AT_THIS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_THIS);
+ } else if (!supportedPrimitives.contains(PointcutPrimitive.AT_TARGET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_TARGET);
+ }
+ break;
+ case Pointcut.ATARGS:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_ARGS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ARGS);
+ }
+ break;
+ case Pointcut.ANNOTATION:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_ANNOTATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ANNOTATION);
+ }
+ break;
+ case Pointcut.ATWITHIN:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHIN)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHIN);
+ }
+ break;
+ case Pointcut.ATWITHINCODE:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHINCODE)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHINCODE);
+ }
+ break;
+ case Pointcut.REFERENCE:
+ if (!supportedPrimitives.contains(PointcutPrimitive.REFERENCE)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.REFERENCE);
+ }
+ break;
+ case Pointcut.USER_EXTENSION:
+ // always ok...
+ break;
+ case Pointcut.NONE: // deliberate fall-through
+ default:
+ throw new IllegalArgumentException("Unknown pointcut kind: " + pc.getPointcutKind());
+ }
+ }
+
+ private void validateKindedPointcut(KindedPointcut pc, String expression) {
+ Shadow.Kind kind = pc.getKind();
+ if ((kind == Shadow.MethodCall) || (kind == Shadow.ConstructorCall)) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.CALL)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CALL);
+ }
+ } else if ((kind == Shadow.MethodExecution) || (kind == Shadow.ConstructorExecution)) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.EXECUTION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.EXECUTION);
+ }
+ } else if (kind == Shadow.AdviceExecution) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.ADVICE_EXECUTION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ADVICE_EXECUTION);
+ }
+ } else if (kind == Shadow.FieldGet) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.GET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.GET);
+ }
+ } else if (kind == Shadow.FieldSet) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.SET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.SET);
+ }
+ } else if (kind == Shadow.Initialization) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.INITIALIZATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.INITIALIZATION);
+ }
+ } else if (kind == Shadow.PreInitialization) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.PRE_INITIALIZATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.PRE_INITIALIZATION);
+ }
+ } else if (kind == Shadow.StaticInitialization) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.STATIC_INITIALIZATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.STATIC_INITIALIZATION);
+ }
+ }
+ }
+
+ private String buildUserMessageFromParserException(String pc, ParserException ex) {
+ StringBuffer msg = new StringBuffer();
+ msg.append("Pointcut is not well-formed: expecting '");
+ msg.append(ex.getMessage());
+ msg.append("'");
+ IHasPosition location = ex.getLocation();
+ msg.append(" at character position ");
+ msg.append(location.getStart());
+ msg.append("\n");
+ msg.append(pc);
+ msg.append("\n");
+ for (int i = 0; i < location.getStart(); i++) {
+ msg.append(" ");
+ }
+ for (int j = location.getStart(); j <= location.getEnd(); j++) {
+ msg.append("^");
+ }
+ msg.append("\n");
+ return msg.toString();
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutPrimitive.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutPrimitive.java
new file mode 100644
index 000000000..ae3f607ff
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/PointcutPrimitive.java
@@ -0,0 +1,50 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+
+package org.aspectj.weaver.tools;
+
+import org.aspectj.util.TypeSafeEnum;
+
+/**
+ * An enumeration of the different kinds of pointcut primitives
+ * supported by AspectJ.
+ */
+public final class PointcutPrimitive extends TypeSafeEnum {
+
+ public static final PointcutPrimitive CALL = new PointcutPrimitive("call",1);
+ public static final PointcutPrimitive EXECUTION = new PointcutPrimitive("execution",2);
+ public static final PointcutPrimitive GET = new PointcutPrimitive("get",3);
+ public static final PointcutPrimitive SET = new PointcutPrimitive("set",4);
+ public static final PointcutPrimitive INITIALIZATION = new PointcutPrimitive("initialization",5);
+ public static final PointcutPrimitive PRE_INITIALIZATION = new PointcutPrimitive("preinitialization",6);
+ public static final PointcutPrimitive STATIC_INITIALIZATION = new PointcutPrimitive("staticinitialization",7);
+ public static final PointcutPrimitive HANDLER = new PointcutPrimitive("handler",8);
+ public static final PointcutPrimitive ADVICE_EXECUTION = new PointcutPrimitive("adviceexecution",9);
+ public static final PointcutPrimitive WITHIN = new PointcutPrimitive("within",10);
+ public static final PointcutPrimitive WITHIN_CODE = new PointcutPrimitive("withincode",11);
+ public static final PointcutPrimitive CFLOW = new PointcutPrimitive("cflow",12);
+ public static final PointcutPrimitive CFLOW_BELOW = new PointcutPrimitive("cflowbelow",13);
+ public static final PointcutPrimitive IF = new PointcutPrimitive("if",14);
+ public static final PointcutPrimitive THIS = new PointcutPrimitive("this",15);
+ public static final PointcutPrimitive TARGET = new PointcutPrimitive("target",16);
+ public static final PointcutPrimitive ARGS = new PointcutPrimitive("args",17);
+ public static final PointcutPrimitive REFERENCE = new PointcutPrimitive("reference pointcut",18);
+ public static final PointcutPrimitive AT_ANNOTATION = new PointcutPrimitive("@annotation",19);
+ public static final PointcutPrimitive AT_THIS = new PointcutPrimitive("@this",20);
+ public static final PointcutPrimitive AT_TARGET = new PointcutPrimitive("@target",21);
+ public static final PointcutPrimitive AT_ARGS = new PointcutPrimitive("@args",22);
+ public static final PointcutPrimitive AT_WITHIN = new PointcutPrimitive("@within",23);
+ public static final PointcutPrimitive AT_WITHINCODE = new PointcutPrimitive("@withincode",24);
+
+ private PointcutPrimitive(String name, int key) {
+ super(name, key);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ShadowMatch.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ShadowMatch.java
new file mode 100644
index 000000000..55e2581df
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/ShadowMatch.java
@@ -0,0 +1,58 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * The result of asking a PointcutExpression to match at a shadow (method execution,
+ * handler, constructor call, and so on).
+ *
+ */
+public interface ShadowMatch {
+
+ /**
+ * True iff the pointcut expression will match any join point at this
+ * shadow (for example, any call to the given method).
+ */
+ boolean alwaysMatches();
+
+ /**
+ * True if the pointcut expression may match some join points at this
+ * shadow (for example, some calls to the given method may match, depending
+ * on the type of the caller).
+ * <p>If alwaysMatches is true, then maybeMatches is always true.</p>
+ */
+ boolean maybeMatches();
+
+ /**
+ * True iff the pointcut expression can never match any join point at this
+ * shadow (for example, the pointcut will never match a call to the given
+ * method).
+ */
+ boolean neverMatches();
+
+ /**
+ * Return the result of matching a join point at this shadow with the given
+ * this, target, and args.
+ * @param thisObject the object bound to this at the join point
+ * @param targetObject the object bound to target at the join point
+ * @param args the arguments at the join point
+ * @return
+ */
+ JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args);
+
+ /**
+ * Set a matching context to be used when matching
+ * join points.
+ * @see MatchingContext
+ */
+ void setMatchingContext(MatchingContext aMatchContext);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutExpression.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutExpression.java
new file mode 100644
index 000000000..63d908bd2
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutExpression.java
@@ -0,0 +1,233 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+
+package org.aspectj.weaver.tools;
+
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedType;
+
+/**
+ * Represents an AspectJ pointcut expression and provides convenience methods to determine whether or not the pointcut matches join
+ * points specified in terms of the java.lang.reflect interfaces.
+ */
+public interface StandardPointcutExpression {
+
+ /**
+ * Set the matching context to be used for subsequent calls to match.
+ *
+ * @see MatchingContext
+ */
+ void setMatchingContext(MatchingContext aMatchContext);
+
+ /**
+ * Determine whether or not this pointcut could ever match a join point in the given class.
+ *
+ * @param aClass the candidate class
+ * @return true iff this pointcut <i>may</i> match a join point within(aClass), and false otherwise
+ */
+ boolean couldMatchJoinPointsInType(Class aClass);
+
+ /**
+ * Returns true iff this pointcut contains any expression that might necessitate a dynamic test at some join point (e.g. args)
+ */
+ boolean mayNeedDynamicTest();
+
+ /**
+ * Determine whether or not this pointcut matches the execution of a given method.
+ *
+ * @param aMethod the method being executed
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the
+ * execution of the method.
+ */
+ ShadowMatch matchesMethodExecution(ResolvedMember aMethod);
+
+ // /**
+ // * Determine whether or not this pointcut matches the execution of a given constructor.
+ // *
+ // * @param aConstructor the constructor being executed
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the
+ // * execution of the constructor.
+ // */
+ // ShadowMatch matchesConstructorExecution(Constructor aConstructor);
+ //
+ /**
+ * Determine whether or not this pointcut matches the static initialization of the given class.
+ *
+ * @param aClass the class being statically initialized
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matchs join points representing the static
+ * initialization of the given type
+ */
+ ShadowMatch matchesStaticInitialization(ResolvedType aType);
+
+ //
+ // /**
+ // * Determine whether or not this pointcut matches the static initialization of the given class.
+ // *
+ // * @param aClass the class being statically initialized
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matchs join points representing the
+ // static
+ // * initialization of the given type
+ // */
+ // ShadowMatch matchesStaticInitialization(ResolvedType type);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches the execution of a given piece of advice.
+ // *
+ // * @param anAdviceMethod a method representing the advice being executed
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the
+ // * execution of the advice.
+ // */
+ // ShadowMatch matchesAdviceExecution(Method anAdviceMethod);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches the initialization of an object initiated by a call to the given
+ // constructor.
+ // *
+ // * @param aConstructor the constructor initiating the initialization
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing
+ // * initialization via the given constructor.
+ // */
+ // ShadowMatch matchesInitialization(Constructor aConstructor);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches the pre-initialization of an object initiated by a call to the given
+ // * constructor.
+ // *
+ // * @param aConstructor the constructor initiating the initialization
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing
+ // * pre-initialization via the given constructor.
+ // */
+ // ShadowMatch matchesPreInitialization(Constructor aConstructor);
+ //
+ /**
+ * Determine whether or not this pointcut matches a method call to the given method, made during the execution of the given
+ * method or constructor.
+ *
+ * @param aMethod the method being called
+ * @param withinCode the Method or Constructor from within which the call is made
+ * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call to
+ * this method during the execution of the given member.
+ */
+ ShadowMatch matchesMethodCall(ResolvedMember aMethod, ResolvedMember withinCode);
+
+ //
+ // /**
+ // * Determine whether or not this pointcut matches a method call to the given method, made outside of the scope of any method
+ // or
+ // * constructor, but within the callerType (for example, during static initialization of the type).
+ // *
+ // * @param aMethod the method being called
+ // * @param callerType the declared type of the caller
+ // * @param receiverType the declared type of the recipient of the call
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call
+ // to
+ // * this method during the execution of the given member.
+ // */
+ // ShadowMatch matchesMethodCall(Method aMethod, Class callerType);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches a method call to the given constructor, made during the execution of the
+ // given
+ // * method or constructor.
+ // *
+ // * @param aConstructor the constructor being called
+ // * @param withinCode the Method or Constructor from within which the call is made
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call
+ // to
+ // * this constructor during the execution of the given member.
+ // */
+ // ShadowMatch matchesConstructorCall(Constructor aConstructor, Member withinCode);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches a method call to the given constructor, made outside of the scope of any
+ // * method or constructor, but within the callerType.
+ // *
+ // * @param aConstructor the cosstructor being called
+ // * @param callerType the declared type of the caller
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing a call
+ // to
+ // * this constructor during the execution of the given member.
+ // */
+ // ShadowMatch matchesConstructorCall(Constructor aConstructor, Class callerType);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches the execution of a given exception handler within the given method or
+ // * constructor
+ // *
+ // * @param exceptionType the static type of the exception being handled
+ // * @param withinCode the method or constructor in which the catch block is declared
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the
+ // * handling of the given exception
+ // */
+ // ShadowMatch matchesHandler(Class exceptionType, Member withinCode);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches the execution of a given exception handler outside of the scope of any
+ // method
+ // * or constructor, but within the handling type.
+ // *
+ // * @param exceptionType the static type of the exception being handled
+ // * @param handlingType the type in which the handler block is executing
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches join points representing the
+ // * handling of the given exception
+ // */
+ // ShadowMatch matchesHandler(Class exceptionType, Class handlingType);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches a set of the given field from within the given method or constructor.
+ // *
+ // * @param aField the field being updated
+ // * @param withinCode the Method or Constructor owning the call site
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field set join points for the
+ // given
+ // * field and call site.
+ // */
+ // ShadowMatch matchesFieldSet(Field aField, Member withinCode);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches a set of the given field outside of the scope of any method or constructor,
+ // * but within the given type (for example, during static initialization).
+ // *
+ // * @param aField the field being updated
+ // * @param withinType the type owning the call site
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field set join points for the
+ // given
+ // * field and call site.
+ // */
+ // ShadowMatch matchesFieldSet(Field aField, Class withinType);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches a get of the given field from within the given method or constructor.
+ // *
+ // * @param aField the field being updated
+ // * @param withinCode the Method or Constructor owning the call site
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field get join points for the
+ // given
+ // * field and call site.
+ // */
+ // ShadowMatch matchesFieldGet(Field aField, Member withinCode);
+ //
+ // /**
+ // * Determine whether or not this pointcut matches a get of the given field outside of the scope of any method or constructor,
+ // * but within the given type (for example, during static initialization).
+ // *
+ // * @param aField the field being accessed
+ // * @param withinType the type owning the call site
+ // * @return a ShadowMatch indicating whether the pointcut always, sometimes, or never matches field get join points for the
+ // given
+ // * field and call site.
+ // */
+ // ShadowMatch matchesFieldGet(Field aField, Class withinType);
+
+ /**
+ * Return a string representation of this pointcut expression.
+ */
+ String getPointcutExpression();
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutParser.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutParser.java
new file mode 100644
index 000000000..e549325af
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/StandardPointcutParser.java
@@ -0,0 +1,508 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.SourceLocation;
+import org.aspectj.weaver.BindingScope;
+import org.aspectj.weaver.IHasPosition;
+import org.aspectj.weaver.ISourceContext;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.internal.tools.StandardPointcutExpressionImpl;
+import org.aspectj.weaver.internal.tools.TypePatternMatcherImpl;
+import org.aspectj.weaver.patterns.AndPointcut;
+import org.aspectj.weaver.patterns.CflowPointcut;
+import org.aspectj.weaver.patterns.FormalBinding;
+import org.aspectj.weaver.patterns.IScope;
+import org.aspectj.weaver.patterns.KindedPointcut;
+import org.aspectj.weaver.patterns.NotPointcut;
+import org.aspectj.weaver.patterns.OrPointcut;
+import org.aspectj.weaver.patterns.ParserException;
+import org.aspectj.weaver.patterns.PatternParser;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.patterns.SimpleScope;
+import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
+import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
+import org.aspectj.weaver.patterns.TypePattern;
+import org.aspectj.weaver.reflect.PointcutParameterImpl;
+import org.aspectj.weaver.reflect.ReflectionWorld;
+
+/**
+ * A PointcutParser can be used to build PointcutExpressions for a user-defined subset of AspectJ's pointcut language
+ */
+public class StandardPointcutParser {
+
+ private World world;
+ private final Set<PointcutPrimitive> supportedPrimitives;
+ private final Set<PointcutDesignatorHandler> pointcutDesignators = new HashSet<PointcutDesignatorHandler>();
+
+ /**
+ * @return a Set containing every PointcutPrimitive except if, cflow, and cflowbelow (useful for passing to PointcutParser
+ * constructor).
+ */
+ public static Set<PointcutPrimitive> getAllSupportedPointcutPrimitives() {
+ Set<PointcutPrimitive> primitives = new HashSet<PointcutPrimitive>();
+ primitives.add(PointcutPrimitive.ADVICE_EXECUTION);
+ primitives.add(PointcutPrimitive.ARGS);
+ primitives.add(PointcutPrimitive.CALL);
+ primitives.add(PointcutPrimitive.EXECUTION);
+ primitives.add(PointcutPrimitive.GET);
+ primitives.add(PointcutPrimitive.HANDLER);
+ primitives.add(PointcutPrimitive.INITIALIZATION);
+ primitives.add(PointcutPrimitive.PRE_INITIALIZATION);
+ primitives.add(PointcutPrimitive.SET);
+ primitives.add(PointcutPrimitive.STATIC_INITIALIZATION);
+ primitives.add(PointcutPrimitive.TARGET);
+ primitives.add(PointcutPrimitive.THIS);
+ primitives.add(PointcutPrimitive.WITHIN);
+ primitives.add(PointcutPrimitive.WITHIN_CODE);
+ primitives.add(PointcutPrimitive.AT_ANNOTATION);
+ primitives.add(PointcutPrimitive.AT_THIS);
+ primitives.add(PointcutPrimitive.AT_TARGET);
+ primitives.add(PointcutPrimitive.AT_ARGS);
+ primitives.add(PointcutPrimitive.AT_WITHIN);
+ primitives.add(PointcutPrimitive.AT_WITHINCODE);
+ primitives.add(PointcutPrimitive.REFERENCE);
+
+ return primitives;
+ }
+
+ /**
+ * Returns a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ * <p>
+ * When resolving types in pointcut expressions, the context classloader is used to find types.
+ * </p>
+ */
+ public static StandardPointcutParser getPointcutParserSupportingAllPrimitives(World world) {
+ StandardPointcutParser p = new StandardPointcutParser(world);
+ return p;
+ }
+
+ /**
+ * Returns a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported
+ * pointcut primitives. The following restrictions apply:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ * <p>
+ * When resolving types in pointcut expressions, the given classloader is used to find types.
+ * </p>
+ *
+ * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
+ * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
+ */
+ public static StandardPointcutParser getPointcutParserSupportingSpecifiedPrimitives(Set supportedPointcutKinds, World world) {
+ StandardPointcutParser p = new StandardPointcutParser(supportedPointcutKinds, world);
+ return p;
+ }
+
+ /**
+ * Create a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ */
+ protected StandardPointcutParser(World world) {
+ supportedPrimitives = getAllSupportedPointcutPrimitives();
+ this.world = world;
+ }
+
+ /**
+ * Create a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported pointcut
+ * primitives. The following restrictions apply:
+ * <ul>
+ * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
+ * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
+ * <li>The pointcut expression must be anonymous with no formals allowed.
+ * </ul>
+ *
+ * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
+ * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
+ */
+ private StandardPointcutParser(Set/* <PointcutPrimitives> */supportedPointcutKinds, World world) {
+ supportedPrimitives = supportedPointcutKinds;
+ for (Iterator iter = supportedPointcutKinds.iterator(); iter.hasNext();) {
+ PointcutPrimitive element = (PointcutPrimitive) iter.next();
+ if ((element == PointcutPrimitive.IF) || (element == PointcutPrimitive.CFLOW)
+ || (element == PointcutPrimitive.CFLOW_BELOW)) {
+ throw new UnsupportedOperationException("Cannot handle if, cflow, and cflowbelow primitives");
+ }
+ }
+ this.world = world;
+ }
+
+ // /**
+ // * Set the lint properties for this parser from the given resource on the classpath.
+ // *
+ // * @param resourcePath path to a file containing aspectj lint properties
+ // */
+ // public void setLintProperties(String resourcePath) throws IOException {
+ // URL url = this.classLoaderReference.getClassLoader().getResource(resourcePath);
+ // InputStream is = url.openStream();
+ // Properties p = new Properties();
+ // p.load(is);
+ // setLintProperties(p);
+ // }
+
+ /**
+ * Set the lint properties for this parser from the given properties set.
+ *
+ * @param properties
+ */
+ public void setLintProperties(Properties properties) {
+ getWorld().getLint().setFromProperties(properties);
+ }
+
+ /**
+ * Register a new pointcut designator handler with this parser. This provides an extension mechansim for the integration of
+ * domain-specific pointcut designators with the AspectJ pointcut language.
+ *
+ * @param designatorHandler
+ */
+ public void registerPointcutDesignatorHandler(PointcutDesignatorHandler designatorHandler) {
+ this.pointcutDesignators.add(designatorHandler);
+ if (world != null) {
+ world.registerPointcutHandler(designatorHandler);
+ }
+ }
+
+ /**
+ * Create a pointcut parameter of the given name and type.
+ *
+ * @param name
+ * @param type
+ * @return
+ */
+ public PointcutParameter createPointcutParameter(String name, Class type) {
+ return new PointcutParameterImpl(name, type);
+ }
+
+ /**
+ * Parse the given pointcut expression. A global scope is assumed for resolving any type references, and the pointcut must
+ * contain no formals (variables to be bound).
+ *
+ * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not
+ * supported by this PointcutParser.
+ * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression
+ */
+ public StandardPointcutExpression parsePointcutExpression(String expression) throws UnsupportedPointcutPrimitiveException,
+ IllegalArgumentException {
+ return parsePointcutExpression(expression, null, new PointcutParameter[0]);
+ }
+
+ /**
+ * Parse the given pointcut expression. The pointcut is resolved as if it had been declared inside the inScope class (this
+ * allows the pointcut to contain unqualified references to other pointcuts declared in the same type for example). The pointcut
+ * may contain zero or more formal parameters to be bound at matched join points.
+ *
+ * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not
+ * supported by this PointcutParser.
+ * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression
+ */
+ public StandardPointcutExpression parsePointcutExpression(String expression, Class inScope, PointcutParameter[] formalParameters)
+ throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
+ StandardPointcutExpressionImpl pcExpr = null;
+ try {
+ Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
+ pc = concretizePointcutExpression(pc, inScope, formalParameters);
+ validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
+ pcExpr = new StandardPointcutExpressionImpl(pc, expression, formalParameters, getWorld());
+ } catch (ParserException pEx) {
+ throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
+ } catch (ReflectionWorld.ReflectionWorldException rwEx) {
+ rwEx.printStackTrace();
+ throw new IllegalArgumentException(rwEx.getMessage());
+ }
+ return pcExpr;
+ }
+
+ protected Pointcut resolvePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters) {
+ try {
+ PatternParser parser = new PatternParser(expression);
+ parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
+ Pointcut pc = parser.parsePointcut();
+ validateAgainstSupportedPrimitives(pc, expression);
+ IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters);
+ pc = pc.resolve(resolutionScope);
+ return pc;
+ } catch (ParserException pEx) {
+ throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
+ }
+ }
+
+ protected Pointcut concretizePointcutExpression(Pointcut pc, Class<?> inScope, PointcutParameter[] formalParameters) {
+ ResolvedType declaringTypeForResolution = null;
+ if (inScope != null) {
+ declaringTypeForResolution = getWorld().resolve(inScope.getName());
+ } else {
+ declaringTypeForResolution = ResolvedType.OBJECT.resolve(getWorld());
+ }
+ IntMap arity = new IntMap(formalParameters.length);
+ for (int i = 0; i < formalParameters.length; i++) {
+ arity.put(i, i);
+ }
+ return pc.concretize(declaringTypeForResolution, declaringTypeForResolution, arity);
+ }
+
+ /**
+ * Parse the given aspectj type pattern, and return a matcher that can be used to match types using it.
+ *
+ * @param typePattern an aspectj type pattern
+ * @return a type pattern matcher that matches using the given pattern
+ * @throws IllegalArgumentException if the type pattern cannot be successfully parsed.
+ */
+ public TypePatternMatcher parseTypePattern(String typePattern) throws IllegalArgumentException {
+ try {
+ TypePattern tp = new PatternParser(typePattern).parseTypePattern();
+ tp.resolve(world);
+ return new TypePatternMatcherImpl(tp, world);
+ } catch (ParserException pEx) {
+ throw new IllegalArgumentException(buildUserMessageFromParserException(typePattern, pEx));
+ } catch (ReflectionWorld.ReflectionWorldException rwEx) {
+ throw new IllegalArgumentException(rwEx.getMessage());
+ }
+ }
+
+ private World getWorld() {
+ return world;
+ }
+
+ /* for testing */
+ Set getSupportedPrimitives() {
+ return supportedPrimitives;
+ }
+
+ /* for testing */
+ IMessageHandler setCustomMessageHandler(IMessageHandler aHandler) {
+ IMessageHandler current = getWorld().getMessageHandler();
+ getWorld().setMessageHandler(aHandler);
+ return current;
+ }
+
+ private IScope buildResolutionScope(Class inScope, PointcutParameter[] formalParameters) {
+ if (formalParameters == null) {
+ formalParameters = new PointcutParameter[0];
+ }
+ FormalBinding[] formalBindings = new FormalBinding[formalParameters.length];
+ for (int i = 0; i < formalBindings.length; i++) {
+ formalBindings[i] = new FormalBinding(toUnresolvedType(formalParameters[i].getType()), formalParameters[i].getName(), i);
+ }
+ if (inScope == null) {
+ SimpleScope ss = new SimpleScope(getWorld(), formalBindings);
+ ss.setImportedPrefixes(new String[] { "java.lang.", "java.util." });
+ return ss;
+ } else {
+ ResolvedType inType = getWorld().resolve(inScope.getName());
+ ISourceContext sourceContext = new ISourceContext() {
+ public ISourceLocation makeSourceLocation(IHasPosition position) {
+ return new SourceLocation(new File(""), 0);
+ }
+
+ public ISourceLocation makeSourceLocation(int line, int offset) {
+ return new SourceLocation(new File(""), line);
+ }
+
+ public int getOffset() {
+ return 0;
+ }
+
+ public void tidy() {
+ }
+ };
+ BindingScope bScope = new BindingScope(inType, sourceContext, formalBindings);
+ bScope.setImportedPrefixes(new String[] { "java.lang.", "java.util." });
+ return bScope;
+ }
+ }
+
+ private UnresolvedType toUnresolvedType(Class clazz) {
+ if (clazz.isArray()) {
+ return UnresolvedType.forSignature(clazz.getName().replace('.', '/'));
+ } else {
+ return UnresolvedType.forName(clazz.getName());
+ }
+ }
+
+ private void validateAgainstSupportedPrimitives(Pointcut pc, String expression) {
+ switch (pc.getPointcutKind()) {
+ case Pointcut.AND:
+ validateAgainstSupportedPrimitives(((AndPointcut) pc).getLeft(), expression);
+ validateAgainstSupportedPrimitives(((AndPointcut) pc).getRight(), expression);
+ break;
+ case Pointcut.ARGS:
+ if (!supportedPrimitives.contains(PointcutPrimitive.ARGS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ARGS);
+ }
+ break;
+ case Pointcut.CFLOW:
+ CflowPointcut cfp = (CflowPointcut) pc;
+ if (cfp.isCflowBelow()) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW_BELOW);
+ } else {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW);
+ }
+ case Pointcut.HANDLER:
+ if (!supportedPrimitives.contains(PointcutPrimitive.HANDLER)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.HANDLER);
+ }
+ break;
+ case Pointcut.IF:
+ case Pointcut.IF_FALSE:
+ case Pointcut.IF_TRUE:
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.IF);
+ case Pointcut.KINDED:
+ validateKindedPointcut(((KindedPointcut) pc), expression);
+ break;
+ case Pointcut.NOT:
+ validateAgainstSupportedPrimitives(((NotPointcut) pc).getNegatedPointcut(), expression);
+ break;
+ case Pointcut.OR:
+ validateAgainstSupportedPrimitives(((OrPointcut) pc).getLeft(), expression);
+ validateAgainstSupportedPrimitives(((OrPointcut) pc).getRight(), expression);
+ break;
+ case Pointcut.THIS_OR_TARGET:
+ boolean isThis = ((ThisOrTargetPointcut) pc).isThis();
+ if (isThis && !supportedPrimitives.contains(PointcutPrimitive.THIS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.THIS);
+ } else if (!supportedPrimitives.contains(PointcutPrimitive.TARGET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.TARGET);
+ }
+ break;
+ case Pointcut.WITHIN:
+ if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN);
+ }
+ break;
+ case Pointcut.WITHINCODE:
+ if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN_CODE)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN_CODE);
+ }
+ break;
+ case Pointcut.ATTHIS_OR_TARGET:
+ isThis = ((ThisOrTargetAnnotationPointcut) pc).isThis();
+ if (isThis && !supportedPrimitives.contains(PointcutPrimitive.AT_THIS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_THIS);
+ } else if (!supportedPrimitives.contains(PointcutPrimitive.AT_TARGET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_TARGET);
+ }
+ break;
+ case Pointcut.ATARGS:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_ARGS)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ARGS);
+ }
+ break;
+ case Pointcut.ANNOTATION:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_ANNOTATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ANNOTATION);
+ }
+ break;
+ case Pointcut.ATWITHIN:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHIN)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHIN);
+ }
+ break;
+ case Pointcut.ATWITHINCODE:
+ if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHINCODE)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHINCODE);
+ }
+ break;
+ case Pointcut.REFERENCE:
+ if (!supportedPrimitives.contains(PointcutPrimitive.REFERENCE)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.REFERENCE);
+ }
+ break;
+ case Pointcut.USER_EXTENSION:
+ // always ok...
+ break;
+ case Pointcut.NONE: // deliberate fall-through
+ default:
+ throw new IllegalArgumentException("Unknown pointcut kind: " + pc.getPointcutKind());
+ }
+ }
+
+ private void validateKindedPointcut(KindedPointcut pc, String expression) {
+ Shadow.Kind kind = pc.getKind();
+ if ((kind == Shadow.MethodCall) || (kind == Shadow.ConstructorCall)) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.CALL)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CALL);
+ }
+ } else if ((kind == Shadow.MethodExecution) || (kind == Shadow.ConstructorExecution)) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.EXECUTION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.EXECUTION);
+ }
+ } else if (kind == Shadow.AdviceExecution) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.ADVICE_EXECUTION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ADVICE_EXECUTION);
+ }
+ } else if (kind == Shadow.FieldGet) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.GET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.GET);
+ }
+ } else if (kind == Shadow.FieldSet) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.SET)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.SET);
+ }
+ } else if (kind == Shadow.Initialization) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.INITIALIZATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.INITIALIZATION);
+ }
+ } else if (kind == Shadow.PreInitialization) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.PRE_INITIALIZATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.PRE_INITIALIZATION);
+ }
+ } else if (kind == Shadow.StaticInitialization) {
+ if (!supportedPrimitives.contains(PointcutPrimitive.STATIC_INITIALIZATION)) {
+ throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.STATIC_INITIALIZATION);
+ }
+ }
+ }
+
+ private String buildUserMessageFromParserException(String pc, ParserException ex) {
+ StringBuffer msg = new StringBuffer();
+ msg.append("Pointcut is not well-formed: expecting '");
+ msg.append(ex.getMessage());
+ msg.append("'");
+ IHasPosition location = ex.getLocation();
+ msg.append(" at character position ");
+ msg.append(location.getStart());
+ msg.append("\n");
+ msg.append(pc);
+ msg.append("\n");
+ for (int i = 0; i < location.getStart(); i++) {
+ msg.append(" ");
+ }
+ for (int j = location.getStart(); j <= location.getEnd(); j++) {
+ msg.append("^");
+ }
+ msg.append("\n");
+ return msg.toString();
+ }
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Trace.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Trace.java
new file mode 100644
index 000000000..8b20032aa
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Trace.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+public interface Trace {
+
+ public void enter(String methodName, Object thiz, Object[] args);
+
+ public void enter(String methodName, Object thiz);
+
+ public void exit(String methodName, Object ret);
+
+ public void exit(String methodName, Throwable th);
+
+ public void exit(String methodName);
+
+ public void event(String methodName);
+
+ public void event(String methodName, Object thiz, Object[] args);
+
+ public void debug(String message);
+
+ public void info(String message);
+
+ public void warn(String message);
+
+ public void warn(String message, Throwable th);
+
+ public void error(String message);
+
+ public void error(String message, Throwable th);
+
+ public void fatal(String message);
+
+ public void fatal(String message, Throwable th);
+
+ public void enter(String methodName, Object thiz, Object arg);
+
+ public void enter(String methodName, Object thiz, boolean z);
+
+ public void exit(String methodName, boolean b);
+
+ public void exit(String methodName, int i);
+
+ public void event(String methodName, Object thiz, Object arg);
+
+ public boolean isTraceEnabled();
+
+ public void setTraceEnabled(boolean b);
+} \ No newline at end of file
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TraceFactory.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TraceFactory.java
new file mode 100644
index 000000000..6d819de50
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TraceFactory.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+import org.aspectj.util.LangUtil;
+
+public abstract class TraceFactory {
+
+ public final static String DEBUG_PROPERTY = "org.aspectj.tracing.debug";
+ public final static String FACTORY_PROPERTY = "org.aspectj.tracing.factory";
+ public final static String DEFAULT_FACTORY_NAME = "default";
+
+ protected static boolean debug = getBoolean(DEBUG_PROPERTY,false);
+ private static TraceFactory instance;
+
+ public Trace getTrace (Class clazz) {
+ return instance.getTrace(clazz);
+ }
+
+ public static TraceFactory getTraceFactory () {
+ return instance;
+ }
+
+ protected static boolean getBoolean(String name, boolean def) {
+ String defaultValue = String.valueOf(def);
+ String value = System.getProperty(name,defaultValue);
+ return Boolean.valueOf(value).booleanValue();
+ }
+
+ static {
+
+ /*
+ * Allow user to override default behaviour or specify their own factory
+ */
+ String factoryName = System.getProperty(FACTORY_PROPERTY);
+ if (factoryName != null) try {
+ if (factoryName.equals(DEFAULT_FACTORY_NAME)) {
+ instance = new DefaultTraceFactory();
+ }
+ else {
+ Class factoryClass = Class.forName(factoryName);
+ instance = (TraceFactory)factoryClass.newInstance();
+ }
+ }
+ catch (Throwable th) {
+ if (debug) th.printStackTrace();
+ }
+
+ /*
+ * Try to load external trace infrastructure using supplied factories
+ */
+ if (instance == null) try {
+ if (LangUtil.is15VMOrGreater()) {
+ Class factoryClass = Class.forName("org.aspectj.weaver.tools.Jdk14TraceFactory");
+ instance = (TraceFactory)factoryClass.newInstance();
+ } else {
+ Class factoryClass = Class.forName("org.aspectj.weaver.tools.CommonsTraceFactory");
+ instance = (TraceFactory)factoryClass.newInstance();
+ }
+ }
+ catch (Throwable th) {
+ if (debug) th.printStackTrace();
+ }
+
+ /*
+ * Use default trace
+ */
+ if (instance == null) {
+ instance = new DefaultTraceFactory();
+ }
+
+ if (debug) System.err.println("TraceFactory.instance=" + instance);
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Traceable.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Traceable.java
new file mode 100644
index 000000000..957786e48
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/Traceable.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster - initial implementation
+ *******************************************************************************/
+package org.aspectj.weaver.tools;
+
+public interface Traceable {
+
+ public String toTraceString ();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TypePatternMatcher.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TypePatternMatcher.java
new file mode 100644
index 000000000..be3b84025
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/TypePatternMatcher.java
@@ -0,0 +1,23 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * A compiled AspectJ type pattern that can be used to
+ * match against types at runtime.
+ */
+public interface TypePatternMatcher {
+
+ /**
+ * Does this type pattern matcher match the
+ * given type (Class).
+ */
+ public boolean matches(Class aClass);
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/UnsupportedPointcutPrimitiveException.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/UnsupportedPointcutPrimitiveException.java
new file mode 100644
index 000000000..6e0bbd661
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/UnsupportedPointcutPrimitiveException.java
@@ -0,0 +1,44 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+import org.aspectj.weaver.WeaverMessages;
+
+/**
+ * @author colyer
+ *
+ */
+public class UnsupportedPointcutPrimitiveException extends RuntimeException {
+
+ private static final long serialVersionUID = 3258689888517043251L;
+
+ private PointcutPrimitive unsupportedPrimitive;
+ private String pointcutExpression;
+
+ public UnsupportedPointcutPrimitiveException(String pcExpression, PointcutPrimitive primitive) {
+ super(WeaverMessages.format(WeaverMessages.UNSUPPORTED_POINTCUT_PRIMITIVE,pcExpression,primitive.getName()));
+ this.pointcutExpression = pcExpression;
+ this.unsupportedPrimitive = primitive;
+ }
+
+ /**
+ * @return Returns the unsupportedPrimitive.
+ */
+ public PointcutPrimitive getUnsupportedPrimitive() {
+ return unsupportedPrimitive;
+ }
+
+ public String getInvalidPointcutExpression() {
+ return pointcutExpression;
+ }
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/WeavingClassLoader.java b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/WeavingClassLoader.java
new file mode 100644
index 000000000..84987e19b
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/tools/WeavingClassLoader.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Matthew Webster, Adrian Colyer,
+ * Martin Lippert initial implementation
+ * ******************************************************************/
+
+package org.aspectj.weaver.tools;
+
+import java.net.URL;
+
+/**
+ * An interface for weaving class loaders to provide callbacks for a
+ * WeavingAdaptor.
+ */
+public interface WeavingClassLoader extends GeneratedClassHandler {
+
+ /**
+ * Returns the aspects to be used by a WeavingAdaptor to weave classes
+ * defined by the class loader.
+ * @return the aspects used for weaving classes.
+ */
+ public URL[] getAspectURLs ();
+
+}
diff --git a/org.aspectj.matcher/src/main/java/org/aspectj/weaver/weaver-messages.properties b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/weaver-messages.properties
new file mode 100644
index 000000000..2745ae9e7
--- /dev/null
+++ b/org.aspectj.matcher/src/main/java/org/aspectj/weaver/weaver-messages.properties
@@ -0,0 +1,201 @@
+#####################################################################
+# Copyright (c) 2004 Contributors.
+# All rights reserved.
+# This program and the accompanying materials are made available
+# under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Adrian Colyer - Initial version
+#####################################################################
+
+# Messages output by the AspectJ Weaver
+
+# Pointcut related messages...
+argsInDeclare=args() pointcut designator cannot be used in declare statement
+cflowInDeclare=cflow{0}() pointcut designator cannot be used in declare statement
+ifInDeclare=if() pointcut designator cannot be used in declare statement
+thisOrTargetInDeclare={0}() pointcut designator cannot be used in declare statement
+abstractPointcut={0} is abstract
+abstractPointcutNotMadeConcrete=inherited abstract {0} is not made concrete in {1}
+conflictingInheritedPointcuts=conflicting inherited pointcuts in {0}
+circularPointcutDeclaration=circular pointcut declaration involving: {0}
+cantFindPointcut=can''t find pointcut ''{0}'' on {1}
+exactTypePatternRequired=exact type pattern required
+pointcutNotVisible=pointcut ''{0}'' is not visible from type ''{1}'' - cannot override
+cantBindType=can''t bind type name ''{0}''
+wildcardTypePatternNotAllowed=wildcard type pattern not allowed, must use type name
+fieldCantBeVoid=fields cannot have a void type
+noNewArrayJoinpointsByDefault=There are no join points for array construction unless -Xjoinpoints:arrayconstruction is specified
+unsupportedPointcutPrimitive=Pointcut expression ''{0}'' contains unsupported pointcut primitive ''{1}''
+missingTypePreventsMatch="Unable to determine match at this join point because the type ''{0}'' cannot be found"
+
+# Declare parents messages...
+decpObject=can''t change the parents of java.lang.Object
+cantExtendSelf=type ''{0}''can not extend itself
+interfaceExtendClass=interface can not extend a class
+decpHierarchy=can only insert a class into hierarchy, but {0} is not a subtype of {1}
+
+# declare precedence messages...
+multipleMatchesInPrecedence=multiple matches for {0}, matches both {1} and {2}
+circularityInPrecedenceStar=circularity in declare precedence, ''*'' occurs more than once
+nonAspectTypesInPrecedence=Non-aspect types can only be specified in a declare precedence statement when subtypes are included. Non-aspect type is : {0}
+circularityInPrecedenceTwo=circularity in declare precedence, ''{0}'' matches two patterns
+
+# declare soft messages...
+notThrowable={0} is not a subtype of Throwable
+
+# itd messages...
+itdConsOnAspect=can''t declare constructor on an aspect
+returnTypeMismatch=can''t override {0} with {1} return types don''t match
+paramTypeMismatch=can''t override {0} with {1} parameter types don''t match
+visibilityReduction=can''t override {0} with {1} visibility is reduced
+cantOverrideFinalMember=can''t override final {0}
+doesntThrow=overriden method doesn't throw {0}
+overriddenStatic={0} cannot override {1}; overridden method is static
+overridingStatic={0} cannot override {1}; overriding method is static
+itdConflict=intertype declaration from {0} conflicts with intertype declaration: {1} from {2}
+itdMemberConflict=inter-type declaration from {0} conflicts with existing member: {1}
+itdNonExposedImplementor=type {0} must be accessible for weaving interface inter type declaration from aspect {1}
+itdAbstractMustBePublicOnInterface=abstract intertype method declaration ''{0}'' on interface {1} must be declared public (compiler limitation)
+
+# advice messages...
+nonVoidReturn=applying to join point that doesn''t return void: {0}
+incompatibleReturnType=incompatible return type applying to {0}
+cantThrowChecked=can''t throw checked exception ''{0}'' at this join point ''{1}''
+circularDependency=circular advice precedence: can''t determine precedence between two or more pieces of advice that apply to the same join point: {0}
+
+# aspect messages..
+missingPerClause=expected per clause on super aspect not found on {0}
+wrongPerClause=wrong kind of per clause on super, expected {0} but found {1}
+
+# Reweavable messages...
+alreadyWoven=class ''{0}'' is already woven and has not been built in reweavable mode
+reweavableMode=weaver operating in reweavable mode. Need to verify any required types exist.
+processingReweavable=processing reweavable type {0}: {1}
+missingReweavableType=type {0} is needed by reweavable type {1}
+verifiedReweavableType=successfully verified type {0} exists. Originates from {1}
+aspectNeeded=aspect {0} is needed when using type {1}
+reweavableAspectNotRegistered=aspect ''{0}'' woven into ''{1}'' must be defined to the weaver (placed on the aspectpath, or defined in an aop.xml file if using LTW).
+
+# The infamous and deserving a category all of its own...
+cantFindType=can''t find type {0}
+cantFindCoreType=can''t find critical required type {0}
+cantFindTypeWithinpcd=Unable to find type {0} whilst processing within() pointcut at this source location
+cftDuringAroundWeave=Can't find type {0} whilst applying around advice
+cftDuringAroundWeavePreinit=Can't find type {0} whilst applying around advice to preinitialization join point
+cftExceptionType=Can't find exception type {0} whilst processing advice
+cftArgType=Can't find type {0} whilst processing args() pcd
+cantFindParentType=can''t find type {0} needed to evaluate methods inherited by subtype {1}
+cantFindParentTypeNoSub=can''t find type {0} when attempting to find the set of methods it declares
+cantFindTypeFields=can''t find fields of missing type {0}
+cantFindTypeSuperclass=can''t determine superclass of missing type {0}
+cantFindTypeInterfaces=can''t determine implemented interfaces of missing type {0}
+cantFindTypeMethods=can''t determine methods of missing type {0}
+cantFindTypePointcuts=can''t determine pointcuts declared in missing type {0}
+cantFindTypeModifiers=can''t determine modifiers of missing type {0}
+cantFindTypeAnnotation=can''t determine annotations of missing type {0}
+cantFindTypeAssignable=can''t determine whether missing type {0} is an instance of {1}
+cantFindTypeCoerceable=can''t determine whether missing type {0} can be coerced from {1}
+cantFindTypeJoinPoint=can''t find type {0} whilst determining signatures of call or execution join point for {1}, this may cause a pointcut to fail to match at this join point
+cantFindTypeInterfaceMethods=can''t find type {0} whilst determining all methods of an implementing subtype, this may cause a pointcut to fail to match at a call or execution join point, or an illegal method override via an ITD to go undetected
+
+# Implementation limitations...
+decpBinaryLimitation=can''t use declare parents to change superclass of binary form ''{0}'' (implementation limitation)
+overwriteJSR45=overwriting JSR45 information for {0} (compiler limitation)
+ifInPerClause=if() pointcut designator cannot be used directly in a per clause (compiler limitation). Create a named pointcut containing the if() and refer to it
+ifLexicallyInCflow=if not supported lexically within cflow (compiler limitation)
+onlyBeforeOnHandler=Only before advice is supported on handler join points (compiler limitation)
+noAroundOnSynchronization=Around advice is not supported on the lock and unlock join points (compiler limitation)
+aroundOnPreInit=around on pre-initialization not supported (compiler limitation)
+aroundOnInit=around on initialization not supported (compiler limitation)
+aroundOnInterfaceStaticInit=around on staticinitialization of interface ''{0}'' not supported (compiler limitation)
+unsupportedAnnotationValueType=Compiler limitation: annotation value support not implemented for type {0}
+
+# Bytecode generation nasties...
+problemGeneratingMethod=problem generating method {0}.{1} : {2}
+classTooBig=The class {0} exceeds the maximum class size supported by the JVM (constant pool too big).
+
+# Classpath messages
+zipfileEntryMissing=zipfile classpath entry does not exist: {0}
+zipfileEntryInvalid=zipfile classpath entry is invalid: {0} <{1}>
+directoryEntryMissing=directory classpath entry does not exist: {0}
+outjarInInputPath=-outjar cannot be a member of -injars, -inpath or -aspectpath
+
+# Lint messages
+problemLoadingXLint=problem loading Xlint properties file: {0}, {1}
+unableToLoadXLintDefault=couldn''t load XlintDefault.properties
+errorLoadingXLintDefault=problem loading XlintDefault.properties, {0}
+invalidXLintKey=invalid Xlint key: {0}
+invalidXLintMessageKind=invalid Xlint message kind (must be one of ignore, warning, error): {0}
+
+# Binding of formals
+unboundFormalInPC=the parameter {0} is not bound in [all branches of] pointcut
+ambiguousBindingInPC=the binding of parameter {0} is ambiguous in pointcut
+ambiguousBindingInOrPC=ambiguous binding of parameter(s) {0} across ''||'' in pointcut
+negationDoesntAllowBinding=cannot bind a parameter in a negated expression
+
+# Java5
+
+# Enum
+itdcOnEnumNotAllowed=can''t make inter-type constructor declarations on enum types
+itdmOnEnumNotAllowed=can''t make inter-type method declarations on enum types
+itdfOnEnumNotAllowed=can''t make inter-type field declarations on enum types
+cantDecpOnEnumToImplInterface=can''t use declare parents to make enum type {0} implement an interface
+cantDecpOnEnumToExtendClass=can''t use declare parents to alter supertype of enum type {0}
+cantDecpToMakeEnumSupertype=can''t use declare parents to make ''java.lang.Enum'' the parent of type {0}
+
+# Annotation
+itdcOnAnnotationNotAllowed=can''t make inter-type constructor declarations on annotation types
+itdmOnAnnotationNotAllowed=can''t make inter-type method declarations on annotation types
+itdfOnAnnotationNotAllowed=can''t make inter-type field declarations on annotation types
+cantDecpOnAnnotationToImplInterface=can''t use declare parents to make annotation type {0} implement an interface
+cantDecpOnAnnotationToExtendClass=can''t use declare parents to alter supertype of annotation type {0}
+cantDecpToMakeAnnotationSupertype=can''t use declare parents to make ''java.lang.annotation.Annotation'' the parent of type {0}
+incorrectTargetForDeclareAnnotation={0} is not a valid target for annotation {1}, this annotation can only be applied to these element types {2}
+
+referenceToNonAnnotationType=Type referred to is not an annotation type: {0}
+bindingNonRuntimeRetentionAnnotation=Annotation type {0} does not have runtime retention
+noMatchBecauseSourceRetention=Failing match because annotation ''{0}'' on type ''{1}'' has SOURCE retention. Matching allowed when RetentionPolicy is CLASS or RUNTIME
+
+# Annotation value
+invalidAnnotationValue=Invalid annotation value ''{0}'', expected {1} value
+unknownAnnotationValue=The annotation ''{0}'' does not define a value named ''{1}''
+
+# Generics
+cantDecpMultipleParameterizations=Cannot declare parent {0} onto type {1} since it already has {2} in its hierarchy
+noParameterizedTypePatternInHandler=a parameterized type pattern may not be used in a handler pointcut expression
+incorrectNumberOfTypeArguments=Type pattern does not match because the wrong number of type parameters are specified: Type {0} requires {1} parameter(s)
+violatesTypeVariableBounds=Type {0} does not meet the specification for type parameter {1} ({2}) in generic type {3}
+notAGenericType=Type pattern does not match because {0} is not a generic type
+noStaticInitJPsForParameterizedTypes=no static initialization join points for parameterized types, use raw type instead
+noParameterizedTypePatternInWithin=parameterized type pattern not supported by 'within', use a raw type pattern instead
+noParameterizedTypesInThisAndTarget=parameterized types not supported for this and target pointcuts (erasure limitation)
+noParameterizedTypesInGetAndSet=can't use parameterized type patterns for the declaring type of a get or set pointcut expression (use the raw type instead)
+noInitJPsForParameterizedTypes=no [pre]initialization join points for parameterized types, use raw type instead
+noGenericThrowables=invalid throws pattern: a generic class may not be a direct or indirect subclass of Throwable
+noParameterizedDeclaringTypesWithinCode=can't use parameterized type patterns for the declaring type of a withincode pointcut expression (use the raw type instead)
+noParameterizedDeclaringTypesInExecution=can't use parameterized type patterns for the declaring type of an execution pointcut expression (use the raw type instead)
+noParameterizedDeclaringTypesInCall=can't use parameterized type patterns for the declaring type of a call pointcut expression (use the raw type instead)
+noRawTypePointcutReferences=cannot use a raw type reference to refer to a pointcut in a generic type (use a parameterized reference instead)
+
+hasMemberNotEnabled=the type pattern {0} can only be used when the -XhasMember option is set
+mustKeepOverweavingOnceStart=the type {0} was previously subject to overweaving and after that can only be woven again in overweaving mode
+
+# Java5 features used in pre-Java 5 environment
+atannotationNeedsJava5=the @annotation pointcut expression is only supported at Java 5 compliance level or above
+atwithinNeedsJava5=the @within pointcut expression is only supported at Java 5 compliance level or above
+atwithincodeNeedsJava5=the @withincode pointcut expression is only supported at Java 5 compliance level or above
+atthisNeedsJava5=the @this pointcut expression is only supported at Java 5 compliance level or above
+attargetNeedsJava5=the @target pointcut expression is only supported at Java 5 compliance level or above
+atargsNeedsJava5=the @args pointcut expression is only supported at Java 5 compliance level or above
+declareAtTypeNeedsJava5=declare @type is only supported at Java 5 compliance level or above
+declareAtMethodNeedsJava5=declare @method is only supported at Java 5 compliance level or above
+declareAtFieldNeedsJava5=declare @field is only supported at Java 5 compliance level or above
+declareAtConsNeedsJava5=declare @constructor is only supported at Java 5 compliance level or above
+annotationsRequireJava5=annotation type patterns are only supported at Java 5 compliance level or above
+
+# @AspectJ
+returningFormalNotDeclaredInAdvice=the last parameter of this advice must be named ''{0}'' to bind the returning value
+thrownFormalNotDeclaredInAdvice=the last parameter of this advice must be named ''{0}'' and be of a subtype of Throwable \ No newline at end of file