BOO-999
[boo.git] / src / Boo.Lang.Compiler / Steps / CheckAttributesUsage.cs
blob4a84edd336eff083a5587fd5ee484c64b0d5d6fa
1 #region license
2 // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #endregion
30 namespace Boo.Lang.Compiler.Steps
32 using System;
33 using System.Reflection;
34 using System.Collections.Generic;
35 using Boo.Lang.Compiler;
36 using Boo.Lang.Compiler.Ast;
37 using Boo.Lang.Compiler.TypeSystem;
40 public class CheckAttributesUsage: AbstractVisitorCompilerStep
42 override public void Run()
44 Visit(CompileUnit);
47 override public void LeaveMemberReferenceExpression(MemberReferenceExpression node)
49 OnReferenceExpression(node);
52 override public void OnAttribute(Boo.Lang.Compiler.Ast.Attribute node)
54 Type attrType = AttributeType(node);
55 if (attrType == null) return;
57 // check allowed attribute usage(s)
58 System.Attribute[] usages = System.Attribute.GetCustomAttributes(attrType, typeof(AttributeUsageAttribute));
59 if (usages.Length == 0) return;
61 //only one AttributeUsage is allowed anyway
62 AttributeUsageAttribute usage = (AttributeUsageAttribute)usages[0];
63 if (AttributeTargets.All != usage.ValidOn)
65 AttributeTargets? target = TargetFor(node);
66 if (target.HasValue && !IsValid(usage, target.Value))
68 Errors.Add(
69 CompilerErrorFactory.InvalidAttributeTarget(node, attrType, usage.ValidOn));
72 if (!usage.AllowMultiple)
74 INodeWithAttributes m = node.ParentNode as INodeWithAttributes;
75 foreach (Boo.Lang.Compiler.Ast.Attribute mAttr in m.Attributes)
77 if (mAttr == node) continue;
78 IExternalEntity mAttrEnt = TypeSystemServices.GetOptionalEntity(mAttr) as IExternalEntity;
79 if (null != mAttrEnt && mAttrEnt.MemberInfo.DeclaringType == attrType)
80 Errors.Add(
81 CompilerErrorFactory.MultipleAttributeUsage(node, attrType));
85 // handle special compiler-supported attributes
86 //TODO: ObsoleteAttribute
89 private static AttributeTargets? TargetFor(Ast.Attribute node)
91 if (node.ParentNode is Method)
93 AttributeCollection returnTypeAttributes = ((Method)node.ParentNode).ReturnTypeAttributes;
94 if (returnTypeAttributes.ContainsNode(node))
96 return AttributeTargets.ReturnValue;
99 AttributeTargets target;
100 if (NodeUsageTargets().TryGetValue(node.ParentNode.GetType(), out target))
102 return target;
104 return null;
107 private static Dictionary<Type, AttributeTargets> NodeUsageTargets()
109 if (null == _nodesUsageTargets) SetupNodesUsageTargetsDictionary();
110 return _nodesUsageTargets;
113 private static bool IsValid(AttributeUsageAttribute usage, AttributeTargets target)
115 return target == (usage.ValidOn & target);
118 private static Type AttributeType(Ast.Attribute node)
120 IExternalEntity attr = TypeSystemServices.GetOptionalEntity(node) as IExternalEntity;
121 if (null == attr) return null;
122 return attr.MemberInfo.DeclaringType;
125 override public void OnReferenceExpression(ReferenceExpression node)
127 IExternalEntity member = TypeSystemServices.GetOptionalEntity(node) as IExternalEntity;
128 if (member == null) {//extract to OnInternalReferenceExpression
129 OnInternalReferenceExpression(node);
130 return;
133 System.Attribute[] attributes = System.Attribute.GetCustomAttributes(member.MemberInfo, typeof(ObsoleteAttribute));
134 foreach (ObsoleteAttribute attr in attributes)
136 if (attr.IsError)
137 Errors.Add(
138 CompilerErrorFactory.Obsolete(node, member.ToString(), attr.Message));
139 else
140 Warnings.Add(
141 CompilerWarningFactory.Obsolete(node, member.ToString(), attr.Message));
145 protected void OnInternalReferenceExpression(ReferenceExpression node)
149 private static Dictionary<Type, AttributeTargets> _nodesUsageTargets = null;
151 private static void SetupNodesUsageTargetsDictionary()
153 _nodesUsageTargets = new Dictionary<Type, AttributeTargets>();
154 _nodesUsageTargets.Add(typeof(Assembly), AttributeTargets.Assembly);
155 _nodesUsageTargets.Add(typeof(Ast.Module), AttributeTargets.Assembly);
156 _nodesUsageTargets.Add(typeof(ClassDefinition), AttributeTargets.Class);
157 _nodesUsageTargets.Add(typeof(StructDefinition), AttributeTargets.Struct);
158 _nodesUsageTargets.Add(typeof(EnumDefinition), AttributeTargets.Enum);
159 _nodesUsageTargets.Add(typeof(Constructor), AttributeTargets.Constructor);
160 _nodesUsageTargets.Add(typeof(Method), AttributeTargets.Method);
161 _nodesUsageTargets.Add(typeof(Property), AttributeTargets.Property);
162 _nodesUsageTargets.Add(typeof(Field), AttributeTargets.Field);
163 _nodesUsageTargets.Add(typeof(Ast.Event), AttributeTargets.Event);
164 _nodesUsageTargets.Add(typeof(InterfaceDefinition), AttributeTargets.Interface);
165 _nodesUsageTargets.Add(typeof(ParameterDeclaration), AttributeTargets.Parameter);
166 _nodesUsageTargets.Add(typeof(CallableDefinition), AttributeTargets.Delegate);
167 _nodesUsageTargets.Add(typeof(GenericParameterDeclaration), AttributeTargets.GenericParameter);