*/
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
- */
- 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);
-
- if (!formalBinding.getType().resolve(scope.getWorld()).isEnum()) {
- scope.message(IMessage.ERROR, this, "The field within the annotation must be an Enum. '" + formalBinding.getType()
- + "' is not an Enum (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;
- for (int i = 0; i < annotationFields.length; i++) {
- ResolvedMember resolvedMember = annotationFields[i];
- if (resolvedMember.getReturnType().equals(formalBinding.getType())) {
- if (field != null) {
- scope.message(IMessage.ERROR, this, "The field type '" + formalBinding.getType() + "' is ambiguous for annotation type '"
- + theAnnotationType.getName() + "'");
- }
- field = resolvedMember;
- }
- }
- 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);
- bindings.register(binding, scope);
- binding.resolveBinding(scope.getWorld());
- return binding;
- }
-
- public void write(DataOutputStream 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;
- }
-
- // ---
-
- public Object accept(PatternNodeVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-
- 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));
- }
-
- 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
-
- public FuzzyBoolean fastMatches(AnnotatedElement annotated) {
- throw new BCException("unimplemented");
- }
-
- public UnresolvedType getAnnotationType() {
- throw new BCException("unimplemented");
- }
-
- public Map getAnnotationValues() {
- throw new BCException("unimplemented");
- }
-
- public ResolvedType getResolvedAnnotationType() {
- throw new BCException("unimplemented");
- }
-
-
- public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
- throw new BCException("unimplemented");
- }
-
- public FuzzyBoolean matches(AnnotatedElement annotated) {
- throw new BCException("unimplemented");
- }
-
- public FuzzyBoolean matchesRuntimeType(AnnotatedElement annotated) {
- throw new BCException("unimplemented");
- }
-
- public AnnotationTypePattern parameterizeWith(Map typeVariableMap, World w) {
- throw new BCException("unimplemented");
- }
-
- public void resolve(World world) {
- throw new BCException("unimplemented");
- }
-
- 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();
- }
+ 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());
+
+ if (!(formalBindingType.isEnum() || formalBindingType.getSignature().equals("Ljava/lang/String;"))) {
+ scope.message(IMessage.ERROR, this, "The field within the annotation must be an enum or string. '"
+ + 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;
+ for (int i = 0; i < annotationFields.length; i++) {
+ ResolvedMember resolvedMember = annotationFields[i];
+ if (resolvedMember.getReturnType().equals(formalBinding.getType())) {
+ if (field != null) {
+ scope.message(IMessage.ERROR, this, "The field type '" + formalBinding.getType()
+ + "' is ambiguous for annotation type '" + theAnnotationType.getName() + "'");
+ }
+ field = resolvedMember;
+ }
+ }
+ 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);
+ bindings.register(binding, scope);
+ binding.resolveBinding(scope.getWorld());
+ return binding;
+ }
+
+ @Override
+ public void write(DataOutputStream 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();
+ }
}