Correct usage of the CompilerGeneratedAttribute and the GeneratedCodeAttribute
Both Code Analysis, FxCop and Code Metrics make extensive use of CompilerGeneratedAttribute and GeneratedCodeAttribute to distinguish between user-written code and tool and compiler generated code.
The following describes this behavior:
Code Analysis in Visual Studio 2005 and FxCop 1.35
- Compiler Generated. Does not raise warnings against compiler generated code. Uses an algorithm (mainly based on the name) to determine if code is compiler generated.
- Tool Generated. Raises warnings against nearly all tool generated code. Uses an algorithm to turn off particular rules against code marked with GeneratedCodeAttribute and generated by specific code generators.
Code Analysis in Visual Studio 2008 and FxCop 1.36
- Compiler Generated. Does not raise any warnings against code marked with the CompilerGeneratedAttribute. Also users an algorithm to determine if other code is compiler generated.
- Tool Generated. Does not raise warnings against code marked with the GeneratedCodeAttribute if Suppress results from generated code is turned on (the default).
Code Metrics in Visual Studio 2008
- Compiler Generated. Does not display or generate metrics for code marked with the CompilerGeneratedAttribute. Also users an algorithm to determine if other code is compiler generated.
- Tool Generated. Does not display or generate metrics for code marked with the GeneratedCodeAttribute.
Unfortunately, there are many cases of incorrect usage of these attributes both internally and externally of Microsoft, and this blog post is an attempt to make things a little clearer in the correct application of these attributes.
CompilerGenerateAttribute
This attribute is for compiler use only and indicates that a particular code element is compiler generated. This should never be used in source code whatsoever. In fact, some users believe that usage of it should be a compilation error. I tend to agree.
For example, the following is an incorrect usage of this attribute (this is not compiler generated code):
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[DebuggerNonUserCodeAttribute()]
[ CompilerGeneratedAttribute ()]
internal class Resources
{
private ResourceManager resourceMan;
private CultureInfo resourceCulture;
[SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
internal static ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
ResourceManager temp = new ResourceManager("WindowsApplication1.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
internal static CultureInfo Culture
{
get { return resourceCulture; }
set { resourceCulture = value; }
}
}
GeneratedCodeAttribute
This attribute is for use by custom tools that generate code. It should only be applied to code that is re-generated over and over and should not be used by templates that the user is expected to modify. Nor should it be applied at the type level if the type being generated is a partial class. In this situation, it should be applied only against the individual members that are contained within the generated part of the type.
For example, the following shows the incorrect usage of this attribute (it is being applied at the type level to a partial class):
[ GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0" )]
internal sealed partial class Settings : ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get { return defaultInstance; }
}
[
UserScopedSettingAttribute()]
[DebuggerNonUserCodeAttribute()]
[DefaultSettingValueAttribute("")]
public string MySetting
{
get { return ((string)(this["MySetting"])); }
set { this["MySetting"] = value; }
}
}
The following shows the correct usage of this attribute:
internal sealed partial class Settings : ApplicationSettingsBase
{
[GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0" )]
private static Settings defaultInstance = ((Settings)(ApplicationSettingsBase.Synchronized(new Settings())));
[GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
public static Settings Default
{
get { return defaultInstance; }
}
[GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
[
UserScopedSettingAttribute()]
[DebuggerNonUserCodeAttribute()]
[DefaultSettingValueAttribute("")]
public string MySetting
{
get { return ((string)(this["MySetting"])); }
set { this["MySetting"] = value; }
}
}
Unfortunately, due to the sheer number of teams within Microsoft that release tool generators and templates (there are hundreds within Visual Studio itself), it becomes impossible to track down all usages of these.
Therefore, if you encounter any incorrect usages of these attributes, free feel to head over to Microsoft Connect and tell us about it.
Comments
Anonymous
April 27, 2007
I'm still wondering what FxCop will be doing about automatic properties, which are marked with CompilerGeneratedAttribute. It's a problem that would be nicely resolved if only the generated field were marked with the attribute, leaving the property and its getter/setter methods unmarked, but that's not the last implementation that I saw. Is this sort of thing perhaps an indication that different "levels" of compiler generation flagging might be required?Anonymous
April 27, 2007
Nicole, We had a big discussion about this internally, and we came to conclusion that we are going to ignore the CompilerGeneratedAttribute for automatic properties accessors (ie analyze them). This allows us to still do dead-code analysis on unused accessors. Regards DavidAnonymous
April 27, 2007
That's very good news, but I still have to wonder whether CompilerGeneratedAttribute really belongs on automatic properties in the first place. There is a completely unambiguous mapping (aside from the specific field name used) between the code written by the developer and the generated property, so the final property doesn't seem to merit the attribute any more than, say, an automatically generated parameterless, public constructor for a class in which no instance constructor was explicitly included by the developer.Anonymous
April 27, 2007
Just to clear things up, its not the property itself that is marked with CompilerGeneratedAttribute, just the accessors. There is sometimes a blurred boundary between user written and compiler generated, and I agree with Automatic Properties, its not very clear. However, I personally believe that default constructors should be marked with the CompilerGeneratedAttribute.Anonymous
April 29, 2007
Actually, I tend to agree with you about the default constructor, so it was perhaps not exactly the best example... ;) I guess my unease about marking automatic properties with CGA boils down to the fact that all IL is essentially generated by the compiler, and there doesn't seem to be a clear delineation of what qualifies for marking with CGA. My gut is telling me that anything that has a clear mapping from the developer's original code shouldn't be marked as compiler-generated. For example, one wouldn't want to mark expansion of a using statement in a try...finally { dispose } with CGA since the developer's intent is unambiguous. It seems to me that the developer's intent with respect to all parts of an automatic property other than the generated field name is equally unambigous, so neither the setter nor the getter merit CGA.Anonymous
May 03, 2007
The Teams WIT Tools Blog on Understanding the TFS Cube. Buck Hodges on Update to "How to run tests in...Anonymous
February 28, 2008
I've upgraded from FxCop 1.35 to 1.36 and now FxCop has started to fire warnings against typed DataSetsAnonymous
June 02, 2008
All the analysis tools that come with Visual Studio 2008, allow you to suppress analysis on files that