Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,93 @@
//---------------------------------------------------------------------
// <copyright file="EdmToObjectNamespaceMap.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity.Design.Common;
namespace System.Data.Entity.Design
{
/// <summary>
/// The class to hold the map entries for the mapping between Edm Namespace and the Object Namespace
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public class EdmToObjectNamespaceMap
{
private Dictionary<string, string> _map = new Dictionary<string, string>();
/// <summary>
/// this is just to keep this class from being creatable outside of this assembly
/// </summary>
internal EdmToObjectNamespaceMap()
{
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public void Add(string edmNamespace, string objectNamespace)
{
EDesignUtil.CheckStringArgument(edmNamespace, "edmNamespace");
EDesignUtil.CheckArgumentNull(objectNamespace, "objectNamespace");
_map.Add(edmNamespace, objectNamespace);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public bool Contains(string edmNamespace)
{
return _map.ContainsKey(edmNamespace);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public ICollection<string> EdmNamespaces
{
get { return _map.Keys; }
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public bool Remove(string edmNamespace)
{
return _map.Remove(edmNamespace);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public bool TryGetObjectNamespace(string edmNamespace, out string objectNamespace)
{
return _map.TryGetValue(edmNamespace, out objectNamespace);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public string this[string edmNamespace]
{
get
{
return _map[edmNamespace];
}
set
{
_map[edmNamespace] = value;
}
}
public void Clear()
{
_map.Clear();
}
public int Count
{
get { return _map.Count; }
}
internal Dictionary<string, string> AsDictionary()
{
return _map;
}
}
}

View File

@@ -0,0 +1,78 @@
//---------------------------------------------------------------------
// <copyright file="AssociationTypeEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Data;
using System.Data.Metadata.Edm;
using System.Data.EntityModel.SchemaObjectModel;
using System.Diagnostics;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// Summary description for NestedTypeEmitter.
/// </summary>
internal sealed class AssociationTypeEmitter : SchemaTypeEmitter
{
public AssociationTypeEmitter(ClientApiGenerator generator, AssociationType associationType)
: base(generator, associationType)
{
}
public override CodeTypeDeclarationCollection EmitApiClass()
{
Debug.Assert(Item.AssociationEndMembers.Count == 2, "must have exactly two ends");
AssociationEndMember end1 = Item.AssociationEndMembers[0];
AssociationEndMember end2 = Item.AssociationEndMembers[1];
Generator.CompileUnit.AssemblyCustomAttributes.Add(
AttributeEmitter.EmitSimpleAttribute(
Utils.FQAdoFrameworkDataClassesName("EdmRelationshipAttribute"),
Item.NamespaceName, //it is ok to use the c namespace because relationships aren't backed by clr objects
Item.Name,
end1.Name,
GetMultiplicityCodeExpression(end1.RelationshipMultiplicity),
GetEndTypeCodeExpression(end1),
end2.Name,
GetMultiplicityCodeExpression(end2.RelationshipMultiplicity),
GetEndTypeCodeExpression(end2)
));
// this method doesn't actually create a new type, just a new assembly level attribute for each end
return new CodeTypeDeclarationCollection();
}
private CodeTypeOfExpression GetEndTypeCodeExpression(AssociationEndMember end)
{
return new CodeTypeOfExpression(Generator.GetFullyQualifiedTypeReference(((RefType)end.TypeUsage.EdmType).ElementType));
}
private CodeExpression GetMultiplicityCodeExpression(RelationshipMultiplicity multiplicity)
{
// example:
// [System.Data.Objects.DataClasses.EdmRelationshipRoleAttribute("CustomerOrder", "Customer", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(Customer))]
string roleMultiplicity = multiplicity.ToString();
CodeExpression roleMultiplicityExpression = Emitter.EmitEnumMemberExpression(
TypeReference.AdoFrameworkMetadataEdmType("RelationshipMultiplicity"), roleMultiplicity);
return roleMultiplicityExpression;
}
internal new AssociationType Item
{
get
{
return base.Item as AssociationType;
}
}
}
}

View File

@@ -0,0 +1,403 @@
//---------------------------------------------------------------------
// <copyright file="AttributeEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.CodeDom;
using System.Diagnostics;
using System.Data.SqlTypes;
using System.Data.Metadata.Edm;
using System.Collections.Generic;
using System.Data.Entity.Design;
using System.Data.Entity.Design.Common;
using System.Data.EntityModel.SchemaObjectModel;
using System.Data.Entity.Design.SsdlGenerator;
using System.Globalization;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// Summary description for AttributeEmitter.
/// </summary>
internal sealed class AttributeEmitter
{
TypeReference _typeReference;
internal TypeReference TypeReference
{
get { return _typeReference; }
}
static readonly string AdoAttributeDataClassesNamespace = "System.Data.Objects.DataClasses";
internal AttributeEmitter(TypeReference typeReference)
{
_typeReference = typeReference;
}
/// <summary>
/// The method to be called to create the type level attributes for the ItemTypeEmitter
/// </summary>
/// <param name="emitter">The strongly typed emitter</param>
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
public void EmitTypeAttributes(EntityTypeEmitter emitter, CodeTypeDeclaration typeDecl)
{
Debug.Assert(emitter != null, "emitter should not be null");
Debug.Assert(typeDecl != null, "typeDecl should not be null");
EmitSchemaTypeAttribute(FQAdoFrameworkDataClassesName("EdmEntityTypeAttribute"), emitter, typeDecl);
CodeAttributeDeclaration attribute2 = EmitSimpleAttribute("System.Runtime.Serialization.DataContractAttribute");
AttributeEmitter.AddNamedAttributeArguments(attribute2,
"IsReference", true);
typeDecl.CustomAttributes.Add(attribute2);
CodeAttributeDeclaration attribute3 = EmitSimpleAttribute("System.Serializable");
typeDecl.CustomAttributes.Add(attribute3);
EmitKnownTypeAttributes(emitter.Item, emitter.Generator, typeDecl);
}
private void EmitKnownTypeAttributes(EdmType baseType, ClientApiGenerator generator, CodeTypeDeclaration typeDecl)
{
foreach (EdmType edmType in generator.GetDirectSubTypes(baseType))
{
Debug.Assert(edmType.BaseType == baseType, "The types must be directly derived from basetype");
CodeTypeReference subTypeRef;
if (generator.Language == LanguageOption.GenerateCSharpCode)
{
bool useGlobalPrefix = true;
subTypeRef = generator.GetFullyQualifiedTypeReference(edmType, useGlobalPrefix);
}
else
{
Debug.Assert(generator.Language == LanguageOption.GenerateVBCode, "Did you add a new language?");
subTypeRef = generator.GetLeastPossibleQualifiedTypeReference(edmType);
}
CodeAttributeDeclaration attribute = EmitSimpleAttribute("System.Runtime.Serialization.KnownTypeAttribute", new CodeTypeOfExpression(subTypeRef));
typeDecl.CustomAttributes.Add(attribute);
}
}
/// <summary>
/// The method to be called to create the type level attributes for the StructuredTypeEmitter
/// </summary>
/// <param name="emitter">The strongly typed emitter</param>
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
public void EmitTypeAttributes(StructuredTypeEmitter emitter, CodeTypeDeclaration typeDecl)
{
Debug.Assert(emitter != null, "emitter should not be null");
Debug.Assert(typeDecl != null, "typeDecl should not be null");
// nothing to do here yet
}
/// <summary>
/// The method to be called to create the type level attributes for the SchemaTypeEmitter
/// </summary>
/// <param name="emitter">The strongly typed emitter</param>
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
public void EmitTypeAttributes(SchemaTypeEmitter emitter, CodeTypeDeclaration typeDecl)
{
Debug.Assert(emitter != null, "emitter should not be null");
Debug.Assert(typeDecl != null, "typeDecl should not be null");
}
/// <summary>
/// Common way to fill out EdmTypeAttribute derived attributes
/// </summary>
/// <param name="attributeName">Unqualified name of the attribute</param>
/// <param name="emitter">The strongly typed emitter</param>
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
public void EmitSchemaTypeAttribute(string attributeName, SchemaTypeEmitter emitter, CodeTypeDeclaration typeDecl)
{
// call the shared static version
EdmType type = emitter.Item as EdmType;
Debug.Assert(type != null, "type is not an EdmType");
EmitSchemaTypeAttribute(attributeName, type, typeDecl as CodeTypeMember);
}
/// <summary>
/// Shared code for adding a EdmTypeAttribute derived attribute including parameters to a type or property
/// </summary>
/// <param name="attributeName">Unqualified name of the attribute</param>
/// <param name="type">The type or property type of the code that is having the attribute attached.</param>
/// <param name="member">The type declaration to add the attribues to.</param>
public void EmitSchemaTypeAttribute(string attributeName, EdmType type, CodeTypeMember member)
{
Debug.Assert(attributeName != null, "attributeName should not be null");
Debug.Assert(type != null, "type should not be null");
Debug.Assert(member != null, "typeDecl should not be null");
// [mappingattribute(SchemaName="namespace",TypeName="classname")
CodeAttributeDeclaration attribute = EmitSimpleAttribute(attributeName);
AttributeEmitter.AddNamedAttributeArguments(attribute,
"NamespaceName", type.NamespaceName,
"Name", type.Name);
member.CustomAttributes.Add(attribute);
}
/// <summary>
/// Emit the attributes for the new navigation property
/// </summary>
/// <param name="generator">The ClientApiGenerator instance</param>
/// <param name="targetRelationshipEnd">The relationship end that is being targeted</param>
/// <param name="propertyDecl">The property declaration to attach the attribute to.</param>
/// <param name="additionalAttributes">Additional attributes</param>
public void EmitNavigationPropertyAttributes(ClientApiGenerator generator,
RelationshipEndMember targetRelationshipEnd,
CodeMemberProperty propertyDecl,
List<CodeAttributeDeclaration> additionalAttributes)
{
CodeAttributeDeclaration attribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmRelationshipNavigationPropertyAttribute"),
targetRelationshipEnd.DeclaringType.NamespaceName,
targetRelationshipEnd.DeclaringType.Name,
targetRelationshipEnd.Name);
propertyDecl.CustomAttributes.Add(attribute);
EmitGeneratedCodeAttribute(propertyDecl);
if (additionalAttributes != null && additionalAttributes.Count > 0)
{
try
{
propertyDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
}
catch (ArgumentNullException e)
{
generator.AddError(Strings.InvalidAttributeSuppliedForProperty(propertyDecl.Name),
ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty,
EdmSchemaErrorSeverity.Error,
e);
}
}
}
//
//
// Emit
// [global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
//
// this allows FxCop to skip analysis of these methods and types, it should not be applied to partial types, only the
// generated members of partial types
//
CodeAttributeDeclaration _GeneratedCodeAttribute;
internal void EmitGeneratedCodeAttribute(CodeTypeMember member)
{
if(_GeneratedCodeAttribute == null)
{
_GeneratedCodeAttribute = EmitSimpleAttribute("System.CodeDom.Compiler.GeneratedCode",
"System.Data.Entity.Design.EntityClassGenerator",
typeof(EntityClassGenerator).Assembly.GetName().Version.ToString());
}
member.CustomAttributes.Add(_GeneratedCodeAttribute);
}
/// <summary>
/// The method to be called to create the property level attributes for the PropertyEmitter
/// </summary>
/// <param name="emitter">The strongly typed emitter</param>
/// <param name="propertyDecl">The type declaration to add the attribues to.</param>
/// <param name="additionalAttributes">Additional attributes to emit</param>
public void EmitPropertyAttributes(PropertyEmitter emitter,
CodeMemberProperty propertyDecl,
List<CodeAttributeDeclaration> additionalAttributes)
{
if (MetadataUtil.IsPrimitiveType(emitter.Item.TypeUsage.EdmType) || MetadataUtil.IsEnumerationType(emitter.Item.TypeUsage.EdmType))
{
CodeAttributeDeclaration scalarPropertyAttribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmScalarPropertyAttribute"));
if (emitter.IsKeyProperty)
{
Debug.Assert(emitter.Item.Nullable == false, "An EntityKeyProperty cannot be nullable.");
AttributeEmitter.AddNamedAttributeArguments(scalarPropertyAttribute, "EntityKeyProperty", true);
}
if (!emitter.Item.Nullable)
{
AttributeEmitter.AddNamedAttributeArguments(scalarPropertyAttribute, "IsNullable", false);
}
propertyDecl.CustomAttributes.Add(scalarPropertyAttribute);
}
else //Complex property
{
Debug.Assert(MetadataUtil.IsComplexType(emitter.Item.TypeUsage.EdmType) ||
(MetadataUtil.IsCollectionType(emitter.Item.TypeUsage.EdmType)),
"not a complex type or a collection type");
CodeAttributeDeclaration attribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmComplexPropertyAttribute"));
propertyDecl.CustomAttributes.Add(attribute);
// Have CodeDOM serialization set the properties on the ComplexObject, not the ComplexObject instance.
attribute = EmitSimpleAttribute("System.ComponentModel.DesignerSerializationVisibility");
AttributeEmitter.AddAttributeArguments(attribute,
new object[] { new CodePropertyReferenceExpression(
new CodeTypeReferenceExpression(TypeReference.ForType(
typeof(System.ComponentModel.DesignerSerializationVisibility))),"Content") });
propertyDecl.CustomAttributes.Add(attribute);
if (!MetadataUtil.IsCollectionType(emitter.Item.TypeUsage.EdmType))
{
// Non-collection complex properties also need additional serialization attributes to force them to be explicitly serialized if they are null
// If this is omitted, null complex properties do not get explicitly set to null during deserialization, which causes
// them to be lazily constructed once the property is accessed after the entity is deserialized. If the property is
// actually null during serialiation, that means the user has explicitly set it, so we need to maintain that during serialization.
// This doesn't apply to collection types because they aren't lazily constructed and don't need this extra information.
attribute = EmitSimpleAttribute("System.Xml.Serialization.XmlElement");
AttributeEmitter.AddNamedAttributeArguments(attribute, "IsNullable", true);
propertyDecl.CustomAttributes.Add(attribute);
attribute = EmitSimpleAttribute("System.Xml.Serialization.SoapElement");
AttributeEmitter.AddNamedAttributeArguments(attribute, "IsNullable", true);
propertyDecl.CustomAttributes.Add(attribute);
}
}
// serialization attribute
AddDataMemberAttribute(propertyDecl);
if (additionalAttributes != null && additionalAttributes.Count > 0)
{
try
{
propertyDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
}
catch (ArgumentNullException e)
{
emitter.Generator.AddError(Strings.InvalidAttributeSuppliedForProperty(emitter.Item.Name),
ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty,
EdmSchemaErrorSeverity.Error,
e);
}
}
EmitGeneratedCodeAttribute(propertyDecl);
}
/// <summary>
/// The method to be called to create the type level attributes for the NestedTypeEmitter
/// </summary>
/// <param name="emitter">The strongly typed emitter</param>
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
public void EmitTypeAttributes(ComplexTypeEmitter emitter, CodeTypeDeclaration typeDecl)
{
Debug.Assert(emitter != null, "emitter should not be null");
Debug.Assert(typeDecl != null, "typeDecl should not be null");
EmitSchemaTypeAttribute(FQAdoFrameworkDataClassesName("EdmComplexTypeAttribute"),
emitter, typeDecl);
CodeAttributeDeclaration attribute = EmitSimpleAttribute("System.Runtime.Serialization.DataContractAttribute");
AttributeEmitter.AddNamedAttributeArguments(attribute,
"IsReference", true);
typeDecl.CustomAttributes.Add(attribute);
CodeAttributeDeclaration attribute2 = EmitSimpleAttribute("System.Serializable");
typeDecl.CustomAttributes.Add(attribute2);
EmitKnownTypeAttributes(emitter.Item, emitter.Generator, typeDecl);
}
#region Static Methods
/// <summary>
/// Returns the name qualified with the Ado.Net EDM DataClasses Attribute namespace
/// </summary>
/// <param name="unqualifiedName"></param>
/// <returns></returns>
public static string FQAdoFrameworkDataClassesName(string unqualifiedName)
{
return AdoAttributeDataClassesNamespace + "." + unqualifiedName;
}
/// <summary>
///
/// </summary>
/// <param name="attributeType"></param>
/// <param name="arguments"></param>
/// <returns></returns>
public CodeAttributeDeclaration EmitSimpleAttribute(string attributeType, params object[] arguments)
{
CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(TypeReference.FromString(attributeType, true));
AddAttributeArguments(attribute, arguments);
return attribute;
}
/// <summary>
///
/// </summary>
/// <param name="attribute"></param>
/// <param name="arguments"></param>
public static void AddAttributeArguments(CodeAttributeDeclaration attribute, object[] arguments)
{
foreach (object argument in arguments)
{
CodeExpression expression = argument as CodeExpression;
if (expression == null)
expression = new CodePrimitiveExpression(argument);
attribute.Arguments.Add(new CodeAttributeArgument(expression));
}
}
/// <summary>
///
/// </summary>
/// <param name="attribute"></param>
/// <param name="arguments"></param>
public static void AddNamedAttributeArguments(CodeAttributeDeclaration attribute, params object[] arguments)
{
for (int i = 1; i < arguments.Length; i += 2)
{
CodeExpression expression = arguments[i] as CodeExpression;
if (expression == null)
expression = new CodePrimitiveExpression(arguments[i]);
attribute.Arguments.Add(new CodeAttributeArgument(arguments[i - 1].ToString(), expression));
}
}
/// <summary>
/// Adds an XmlIgnore attribute to the given property declaration. This is
/// used to explicitly skip certain properties during XML serialization.
/// </summary>
/// <param name="propertyDecl">the property to mark with XmlIgnore</param>
public void AddIgnoreAttributes(CodeMemberProperty propertyDecl)
{
CodeAttributeDeclaration xmlIgnoreAttribute = EmitSimpleAttribute(typeof(System.Xml.Serialization.XmlIgnoreAttribute).FullName);
CodeAttributeDeclaration soapIgnoreAttribute = EmitSimpleAttribute(typeof(System.Xml.Serialization.SoapIgnoreAttribute).FullName);
propertyDecl.CustomAttributes.Add(xmlIgnoreAttribute);
propertyDecl.CustomAttributes.Add(soapIgnoreAttribute);
}
/// <summary>
/// Adds an Browsable(false) attribute to the given property declaration.
/// This is used to explicitly avoid display property in the PropertyGrid.
/// </summary>
/// <param name="propertyDecl">the property to mark with XmlIgnore</param>
public void AddBrowsableAttribute(CodeMemberProperty propertyDecl)
{
CodeAttributeDeclaration browsableAttribute = EmitSimpleAttribute(typeof(System.ComponentModel.BrowsableAttribute).FullName, false);
propertyDecl.CustomAttributes.Add(browsableAttribute);
}
public void AddDataMemberAttribute(CodeMemberProperty propertyDecl)
{
CodeAttributeDeclaration browsableAttribute = EmitSimpleAttribute("System.Runtime.Serialization.DataMemberAttribute");
propertyDecl.CustomAttributes.Add(browsableAttribute);
}
#endregion
}
}

View File

@@ -0,0 +1,347 @@
//---------------------------------------------------------------------
// <copyright file="CommentEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Data;
using System.Data.Common.Utils;
using System.Data.EntityModel.SchemaObjectModel;
using System.Globalization;
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design;
using System.Data.Metadata.Edm;
using System.Reflection;
using System.Xml;
using System.IO;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// static helper class for emitting comments.
/// </summary>
internal static class CommentEmitter
{
#region Static Fields
private static readonly Regex LeadingBlanks = new Regex(@"^(?<LeadingBlanks>\s{1,})\S", RegexOptions.Singleline | RegexOptions.Compiled);
#endregion
#region Public Methods
/// <summary>
/// emit all the documentation comments for an element's documentation child
/// (if the element does not have a documentation child emit some standard "missing comments" comment
/// </summary>
/// <param name="element">the element whose documentation is to be displayed</param>
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
public static void EmitSummaryComments(MetadataItem item, CodeCommentStatementCollection commentCollection)
{
Debug.Assert(item != null, "item parameter is null");
Debug.Assert(commentCollection != null, "commentCollection parameter is null");
Documentation documentation = GetDocumentation(item);
string [] summaryComments = null;
if (documentation != null && !MetadataUtil.IsNullOrEmptyOrWhiteSpace(documentation.Summary))
{
// we have documentation to emit
summaryComments = GetFormattedLines(documentation.Summary, true);
}
else
{
string summaryComment;
// no summary content, so use a default
switch (item.BuiltInTypeKind)
{
case BuiltInTypeKind.EdmProperty:
summaryComment = Strings.MissingPropertyDocumentation(((EdmProperty)item).Name);
break;
case BuiltInTypeKind.ComplexType:
summaryComment = Strings.MissingComplexTypeDocumentation(((ComplexType)item).FullName);
break;
default:
{
PropertyInfo pi = item.GetType().GetProperty("FullName");
if (pi == null)
{
pi = item.GetType().GetProperty("Name");
}
object value = null;
if (pi != null)
{
value = pi.GetValue(item, null);
}
if (value != null)
{
summaryComment = Strings.MissingDocumentation(value.ToString());
}
else
{
summaryComment = Strings.MissingDocumentationNoName;
}
}
break;
}
summaryComments = new string[] { summaryComment };
}
EmitSummaryComments(summaryComments, commentCollection);
EmitOtherDocumentationComments(documentation, commentCollection);
}
private static Documentation GetDocumentation(MetadataItem item)
{
if (item is Documentation)
return (Documentation)item;
else
return item.Documentation;
}
/// <summary>
/// Emit summary comments from a string
/// </summary>
/// <param name="summaryComments">the summary comments to be emitted</param>
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
public static void EmitSummaryComments(string summaryComments, CodeCommentStatementCollection commentCollection)
{
Debug.Assert(commentCollection != null, "commentCollection parameter is null");
if (string.IsNullOrEmpty(summaryComments) || string.IsNullOrEmpty(summaryComments = summaryComments.TrimEnd()))
return;
EmitSummaryComments(SplitIntoLines(summaryComments), commentCollection);
}
/// <summary>
/// Emit some lines of comments
/// </summary>
/// <param name="commentLines">the lines of comments to emit</param>
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
/// <param name="docComment">true if the comments are 'documentation' comments</param>
public static void EmitComments(string[] commentLines, CodeCommentStatementCollection commentCollection, bool docComment)
{
Debug.Assert(commentLines != null, "commentLines parameter is null");
Debug.Assert(commentCollection != null, "commentCollection parameter is null");
foreach (string comment in commentLines)
{
commentCollection.Add(new CodeCommentStatement(comment, docComment));
}
}
/// <summary>
/// Emit documentation comments for a method parameter
/// </summary>
/// <param name="parameter">the parameter being commented</param>
/// <param name="comment">the comment text</param>
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
public static void EmitParamComments(CodeParameterDeclarationExpression parameter, string comment,
CodeCommentStatementCollection commentCollection)
{
Debug.Assert(parameter != null, "parameter parameter is null");
Debug.Assert(comment != null, "comment parameter is null");
string paramComment = string.Format(System.Globalization.CultureInfo.CurrentCulture,
"<param name=\"{0}\">{1}</param>", parameter.Name, comment);
commentCollection.Add(new CodeCommentStatement(paramComment, true));
}
/// <summary>
/// 'Format' a string of text into lines: separates in to lines on '\n', removes '\r', and removes common leading blanks.
/// </summary>
/// <param name="escapeForXml">if true characters troublesome for xml are converted to entities</param>
/// <param name="text">the text to be formatted</param>
/// <returns>the formatted lines</returns>
public static string[] GetFormattedLines(string text, bool escapeForXml)
{
#if false
if ( text.IndexOf("\n") >= 0 )
Console.WriteLine("GetFormattedText(\""+text.Replace("\n","\\n").Replace("\r","\\r")+"\","+escapeForXml+")");
#endif
Debug.Assert(!string.IsNullOrEmpty(text));
// nothing in, almost nothing out.
if (StringUtil.IsNullOrEmptyOrWhiteSpace(text))
return new string[] { "" };
// normalize CRLF and LFCRs to LFs (we just remove all the crs, assuming there are no extraneous ones) and remove trailing spaces
text = text.Replace("\r", "");
// remove leading and.or trailing line ends to get single line for:
// <documentation>
// text
// <documentation>
bool trim = false;
int start = text.IndexOf('\n');
if (start >= 0 && MetadataUtil.IsNullOrEmptyOrWhiteSpace(text, 0, start + 1))
{
++start;
trim = true;
}
else
{
start = 0;
}
int last = text.LastIndexOf('\n');
if (last > start - 1 && MetadataUtil.IsNullOrEmptyOrWhiteSpace(text, last))
{
--last;
trim = true;
}
else
{
last = text.Length - 1;
}
if (trim)
{
Debug.Assert(start <= last);
text = text.Substring(start, last - start + 1);
}
// break into lines (preversing blank lines and preping text for being in xml comments)
if (escapeForXml)
text = MetadataUtil.Entityize(text);
string[] lines = SplitIntoLines(text);
if (lines.Length == 1)
{
lines[0] = lines[0].Trim();
return lines;
}
// find the maximum leading whitespace substring (ignoring blank lines)
string leadingBlanks = null;
foreach (string line in lines)
{
// is an empty line
if (MetadataUtil.IsNullOrEmptyOrWhiteSpace(line))
continue;
// find the leading whitespace substring
Match match = LeadingBlanks.Match(line);
if (!match.Success)
{
//none, we're done
leadingBlanks = "";
break;
}
if (leadingBlanks == null)
{
// this is first non-empty line
leadingBlanks = match.Groups["LeadingBlanks"].Value;
continue;
}
// use the leadingBlanks if it matched the new one or it is a leading substring of the new one
string leadingBlanks2 = match.Groups["LeadingBlanks"].Value;
if (leadingBlanks2 == leadingBlanks || leadingBlanks2.StartsWith(leadingBlanks, StringComparison.Ordinal))
continue;
if (leadingBlanks.StartsWith(leadingBlanks2, StringComparison.OrdinalIgnoreCase))
{
// the current leading whitespace string is a leading substring of leadingBlanks. use the new one
leadingBlanks = leadingBlanks2;
continue;
}
// find longest leading common substring and use that.
int minLength = Math.Min(leadingBlanks.Length, leadingBlanks2.Length);
for (int j = 0; j < minLength; ++j)
{
if (leadingBlanks[j] != leadingBlanks2[j])
{
if (j == 0)
leadingBlanks = "";
else
leadingBlanks = leadingBlanks.Substring(0, j);
break;
}
}
// if we've reduced the leading substring to an empty string, we're done.
if (string.IsNullOrEmpty(leadingBlanks))
break;
}
// remove the leading whitespace substring and remove any trailing blanks.
int numLeadingCharsToRemove = leadingBlanks.Length;
for (int i = 0; i < lines.Length; ++i)
{
if (lines[i].Length >= numLeadingCharsToRemove)
lines[i] = lines[i].Substring(numLeadingCharsToRemove);
lines[i] = lines[i].TrimEnd();
}
return lines;
}
#endregion
#region Private Methods
/// <summary>
/// Emit the other (than Summary) documentation comments from a Documentation element
/// </summary>
/// <param name="documentation">the schema Docuementation element</param>
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
private static void EmitOtherDocumentationComments(Documentation documentation, CodeCommentStatementCollection commentCollection)
{
Debug.Assert(commentCollection != null);
if (documentation == null)
return;
if (!string.IsNullOrEmpty(documentation.LongDescription))
EmitXmlComments("LongDescription", GetFormattedLines(documentation.LongDescription, true), commentCollection);
}
/// <summary>
/// Emit the summary comments
/// </summary>
/// <param name="summaryComments"></param>
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
private static void EmitSummaryComments(string[] summaryComments, CodeCommentStatementCollection commentCollection)
{
Debug.Assert(summaryComments != null);
Debug.Assert(commentCollection != null);
EmitXmlComments("summary", summaryComments, commentCollection);
}
/// <summary>
/// emit documentation comments between xml open and close tags
/// </summary>
/// <param name="tag">the xml tag name</param>
/// <param name="summaryComments">the lines of comments to emit</param>
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
private static void EmitXmlComments(string tag, string[] summaryComments, CodeCommentStatementCollection commentCollection)
{
Debug.Assert(tag != null);
Debug.Assert(summaryComments != null);
Debug.Assert(commentCollection != null);
commentCollection.Add(new CodeCommentStatement(string.Format(CultureInfo.InvariantCulture, "<{0}>", tag), true));
EmitComments(summaryComments, commentCollection, true);
commentCollection.Add(new CodeCommentStatement(string.Format(CultureInfo.InvariantCulture, "</{0}>", tag), true));
}
/// <summary>
/// split a string into lines on '\n' chars and remove '\r' chars
/// </summary>
/// <param name="text">the string to split</param>
/// <returns>the split string</returns>
private static string[] SplitIntoLines(string text)
{
if (string.IsNullOrEmpty(text))
return new string[] { "" };
return text.Replace("\r", "").Split('\n');
}
#endregion
}
}

View File

@@ -0,0 +1,78 @@
//---------------------------------------------------------------------
// <copyright file="ComplexTypeEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Data;
using System.Data.Metadata.Edm;
using System.Data.EntityModel.SchemaObjectModel;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// Summary description for NestedTypeEmitter.
/// </summary>
internal sealed class ComplexTypeEmitter : StructuredTypeEmitter
{
#region Methods
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
/// <param name="nestedType"></param>
public ComplexTypeEmitter(ClientApiGenerator generator, ComplexType complexType)
: base(generator, complexType)
{
}
/// <summary>
/// Apply the attributes to this type.
/// </summary>
/// <param name="typeDecl">The declaration of the type that should have attributes added to it.</param>
protected override void EmitTypeAttributes( CodeTypeDeclaration typeDecl )
{
Generator.AttributeEmitter.EmitTypeAttributes( this, typeDecl );
base.EmitTypeAttributes( typeDecl );
}
#endregion
#region Protected Properties
/// <summary>
///
/// </summary>
/// <returns></returns>
protected override CodeTypeReference GetBaseType()
{
CodeTypeReference baseType = base.GetBaseType();
if (baseType == null)
{
baseType = TypeReference.ComplexTypeBaseClass;
}
return baseType;
}
protected override ReadOnlyMetadataCollection<EdmProperty> GetProperties()
{
return Item.Properties;
}
internal new ComplexType Item
{
get
{
return base.Item as ComplexType;
}
}
#endregion
}
}

View File

@@ -0,0 +1,127 @@
//---------------------------------------------------------------------
// <copyright file="Emitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Diagnostics;
using System.Data.EntityModel.SchemaObjectModel;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
///
/// </summary>
internal abstract class Emitter
{
#region Instance Fields
private ClientApiGenerator _generator = null;
#endregion
#region Static Fields
private static CodeExpression _nullExpression = null;
private static CodeExpression _thisRef = null;
/// <summary>Name of property used to get StorageContext from an Entity</summary>
private const string EntityGetContextPropertyName = "Context";
/// <summary>Name of property used to get StorageContext from a StorageSearcher</summary>
protected const string SearcherGetContextPropertyName = "Context";
#endregion
#region Protected Methods
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
protected Emitter(ClientApiGenerator generator)
{
Generator = generator;
}
/// <summary>
///
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
protected static CodeBinaryOperatorExpression EmitExpressionEqualsNull(CodeExpression expression)
{
return new CodeBinaryOperatorExpression(expression, CodeBinaryOperatorType.IdentityEquality, NullExpression);
}
protected static CodeBinaryOperatorExpression EmitExpressionDoesNotEqualNull(CodeExpression expression)
{
return new CodeBinaryOperatorExpression(expression, CodeBinaryOperatorType.IdentityInequality, NullExpression);
}
internal static CodeExpression EmitEnumMemberExpression(CodeTypeReference type, string member)
{
CodeTypeReferenceExpression typeref = new CodeTypeReferenceExpression(type);
return new CodeFieldReferenceExpression(typeref, member);
}
#endregion
#region Protected Properties
/// <summary>
///
/// </summary>
protected static CodeExpression ThisRef
{
get
{
if (_thisRef == null)
_thisRef = new CodeThisReferenceExpression();
return _thisRef;
}
}
/// <summary>
///
/// </summary>
internal ClientApiGenerator Generator
{
get
{
return _generator;
}
private set
{
_generator = value;
}
}
protected TypeReference TypeReference
{
get
{
return _generator.TypeReference;
}
}
protected AttributeEmitter AttributeEmitter
{
get { return _generator.AttributeEmitter; }
}
protected static CodeExpression NullExpression
{
get
{
if (_nullExpression == null)
_nullExpression = new CodePrimitiveExpression(null);
return _nullExpression;
}
}
#endregion
}
}

View File

@@ -0,0 +1,128 @@
//---------------------------------------------------------------------
// <copyright file="EntityTypeEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.CodeDom;
using System.Data;
using Som=System.Data.EntityModel.SchemaObjectModel;
using System.Data.Metadata.Edm;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// Summary description for ItemTypeEmitter.
/// </summary>
internal sealed class EntityTypeEmitter : StructuredTypeEmitter
{
#region Public Methods
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
/// <param name="itemType"></param>
public EntityTypeEmitter(ClientApiGenerator generator, EntityType entity)
: base(generator, entity)
{
}
#endregion
#region Protected Methods
/// <summary>
///
/// </summary>
/// <param name="typeDecl"></param>
protected override void EmitProperties(CodeTypeDeclaration typeDecl)
{
base.EmitProperties(typeDecl);
foreach ( NavigationProperty navigationProperty in Item.GetDeclaredOnlyMembers<NavigationProperty>() )
{
NavigationPropertyEmitter navigationPropertyEmitter = new NavigationPropertyEmitter(Generator, navigationProperty, UsingStandardBaseClass);
navigationPropertyEmitter.Emit(typeDecl);
}
}
public override CodeTypeDeclarationCollection EmitApiClass()
{
CodeTypeDeclarationCollection typeDecls = base.EmitApiClass();
if ( Item.KeyMembers.Count > 0 && typeDecls.Count == 1 )
{
// generate xml comments for the key properties
CodeTypeDeclaration typeDecl = typeDecls[0];
typeDecl.Comments.Add( new CodeCommentStatement( "<KeyProperties>", true ) );
foreach ( EdmMember keyProperty in Item.KeyMembers)
{
string name = keyProperty.Name;
typeDecl.Comments.Add( new CodeCommentStatement( name, true ) );
}
typeDecl.Comments.Add( new CodeCommentStatement( "</KeyProperties>", true ) );
}
return typeDecls;
}
/// <summary>
///
/// </summary>
/// <param name="typeDecl"></param>
protected override void EmitTypeAttributes(CodeTypeDeclaration typeDecl)
{
Generator.AttributeEmitter.EmitTypeAttributes( this, typeDecl );
base.EmitTypeAttributes( typeDecl );
}
/// <summary>
///
/// </summary>
/// <returns></returns>
protected override CodeTypeReference GetBaseType()
{
CodeTypeReference baseType = base.GetBaseType();
if (baseType == null)
{
baseType = TypeReference.EntityTypeBaseClass;
}
return baseType;
}
protected override ReadOnlyMetadataCollection<EdmProperty> GetProperties()
{
return Item.Properties;
}
#endregion
#region Public Properties
#endregion
#region Protected Properties
#endregion
#region Private Properties
/// <summary>
/// Gets the SchemaElement that this class is generating code for.
/// </summary>
/// <value></value>
public new EntityType Item
{
get
{
return base.Item as EntityType;
}
}
#endregion
}
}

View File

@@ -0,0 +1,406 @@
//---------------------------------------------------------------------
// <copyright file="FixUp.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Data.EntityModel.SchemaObjectModel;
using System.Data.Entity.Design;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
///
/// </summary>
internal sealed class FixUp
{
#region Internal Property
internal delegate string FixMethod(string line);
#endregion
#region Instance Fields
FixUpType m_type;
private string _class = null;
private string _method = null;
private string _property = null;
#endregion
#region static
private static readonly FixMethod[] _CSFixMethods = new FixMethod[]
{
null,
new FixMethod(CSMarkOverrideMethodAsSealed),
new FixMethod(CSMarkPropertySetAsInternal),
new FixMethod(CSMarkClassAsStatic),
new FixMethod(CSMarkPropertyGetAsPrivate),
new FixMethod(CSMarkPropertyGetAsInternal),
new FixMethod(CSMarkPropertyGetAsPublic),
new FixMethod(CSMarkPropertySetAsPrivate),
new FixMethod(CSMarkPropertySetAsPublic),
new FixMethod(CSMarkMethodAsPartial),
new FixMethod(CSMarkPropertyGetAsProtected),
new FixMethod(CSMarkPropertySetAsProtected)
};
private static readonly FixMethod[] _VBFixMethods = new FixMethod[]
{
null,
new FixMethod(VBMarkOverrideMethodAsSealed),
new FixMethod(VBMarkPropertySetAsInternal),
null, // VB doesn't support static classes (during CodeGen we added a private ctor to the class)
new FixMethod(VBMarkPropertyGetAsPrivate),
new FixMethod(VBMarkPropertyGetAsInternal),
new FixMethod(VBMarkPropertyGetAsPublic),
new FixMethod(VBMarkPropertySetAsPrivate),
new FixMethod(VBMarkPropertySetAsPublic),
new FixMethod(VBMarkMethodAsPartial),
new FixMethod(VBMarkPropertyGetAsProtected),
new FixMethod(VBMarkPropertySetAsProtected)
};
#endregion
#region Public Methods
/// <summary>
///
/// </summary>
/// <param name="fqName"></param>
/// <param name="type"></param>
public FixUp(string fqName,FixUpType type)
{
Type = type;
string[] nameParts = Utils.SplitName(fqName);
if ( type == FixUpType.MarkClassAsStatic )
{
Class = nameParts[nameParts.Length-1];
}
else
{
Class = nameParts[nameParts.Length-2];
string name = nameParts[nameParts.Length-1];
switch ( type )
{
case FixUpType.MarkAbstractMethodAsPartial:
case FixUpType.MarkOverrideMethodAsSealed:
Method = name;
break;
case FixUpType.MarkPropertyGetAsPrivate:
case FixUpType.MarkPropertyGetAsInternal:
case FixUpType.MarkPropertyGetAsPublic:
case FixUpType.MarkPropertyGetAsProtected:
case FixUpType.MarkPropertySetAsPrivate:
case FixUpType.MarkPropertySetAsInternal:
case FixUpType.MarkPropertySetAsPublic:
case FixUpType.MarkPropertySetAsProtected:
Property = name;
break;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="language"></param>
/// <param name="line"></param>
/// <returns></returns>
public string Fix(LanguageOption language, string line)
{
FixMethod method = null;
if ( language == LanguageOption.GenerateCSharpCode )
{
method = _CSFixMethods[(int)Type];
}
else if ( language == LanguageOption.GenerateVBCode )
{
method = _VBFixMethods[(int)Type];
}
if ( method != null )
{
line = method( line );
}
return line;
}
#endregion
#region Public Properties
/// <summary>
///
/// </summary>
/// <value></value>
public string Class
{
get
{
return _class;
}
private set
{
_class = value;
}
}
/// <summary>
///
/// </summary>
/// <value></value>
public string Property
{
get
{
return _property;
}
private set
{
_property = value;
}
}
/// <summary>
///
/// </summary>
/// <value></value>
public string Method
{
get
{
return _method;
}
private set
{
_method = value;
}
}
/// <summary>
///
/// </summary>
/// <value></value>
public FixUpType Type
{
get
{
return m_type;
}
private set
{
m_type = value;
}
}
#endregion
#region Private Methods
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static string CSMarkMethodAsPartial(string line)
{
line = ReplaceFirst(line, "public abstract", "partial");
return line;
}
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static string VBMarkMethodAsPartial(string line)
{
line = ReplaceFirst(line, "Public MustOverride", "Partial Private");
line += Environment.NewLine + " End Sub";
return line;
}
private static string ReplaceFirst(string line, string str1, string str2)
{
int idx = line.IndexOf(str1, StringComparison.Ordinal);
if (idx >= 0)
{
line = line.Remove(idx, str1.Length);
line = line.Insert(idx, str2);
}
return line;
}
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static string CSMarkOverrideMethodAsSealed(string line)
{
return InsertBefore(line,"override","sealed");
}
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static string VBMarkOverrideMethodAsSealed(string line)
{
return InsertBefore(line, "Overrides", "NotOverridable");
}
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static string CSMarkPropertySetAsInternal(string line)
{
return InsertBefore(line,"set","internal");
}
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static string VBMarkPropertySetAsInternal(string line)
{
return InsertBefore(line,"Set","Friend");
}
private static string CSMarkPropertyGetAsPrivate(string line)
{
return InsertBefore(line, "get", "private");
}
private static string VBMarkPropertyGetAsPrivate(string line)
{
return InsertBefore(line, "Get", "Private");
}
private static string CSMarkPropertyGetAsInternal(string line)
{
return InsertBefore(line, "get", "internal");
}
private static string VBMarkPropertyGetAsInternal(string line)
{
return InsertBefore(line, "Get", "Friend");
}
private static string CSMarkPropertySetAsProtected(string line)
{
return InsertBefore(line, "set", "protected");
}
private static string VBMarkPropertySetAsProtected(string line)
{
return InsertBefore(line, "Set", "Protected");
}
private static string CSMarkPropertyGetAsProtected(string line)
{
return InsertBefore(line, "get", "protected");
}
private static string VBMarkPropertyGetAsProtected(string line)
{
return InsertBefore(line, "Get", "Protected");
}
private static string CSMarkPropertyGetAsPublic(string line)
{
return InsertBefore(line, "get", "public");
}
private static string VBMarkPropertyGetAsPublic(string line)
{
return InsertBefore(line, "Get", "Public");
}
private static string CSMarkPropertySetAsPrivate(string line)
{
return InsertBefore(line, "set", "private");
}
private static string VBMarkPropertySetAsPrivate(string line)
{
return InsertBefore(line, "Set", "Private");
}
private static string CSMarkPropertySetAsPublic(string line)
{
return InsertBefore(line, "set", "public");
}
private static string VBMarkPropertySetAsPublic(string line)
{
return InsertBefore(line, "Set", "Public");
}
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
private static string CSMarkClassAsStatic(string line)
{
if ( IndexOfKeyword(line,"static") >= 0 )
return line;
int insertPoint = IndexOfKeyword(line,"class");
if ( insertPoint < 0 )
return line;
// nothing can be between partial and class
int partialIndex = IndexOfKeyword(line,"partial");
if ( partialIndex >= 0 )
insertPoint = partialIndex;
return line.Insert(insertPoint,"static ");
}
/// <summary>
/// Inserts one keyword before another one.
/// Does nothing if the keyword to be inserted already exists in the line OR if the keyword to insert before doesn't
/// </summary>
/// <param name="line">line of text to examine</param>
/// <param name="searchText">keyword to search for </param>
/// <param name="insertText">keyword to be inserted</param>
/// <returns>the possibly modified line line</returns>
private static string InsertBefore(string line,string searchText,string insertText)
{
if ( IndexOfKeyword(line,insertText) >= 0 )
return line;
int index = IndexOfKeyword(line,searchText);
if ( index < 0 )
return line;
return line.Insert(index,insertText+" ");
}
/// <summary>
/// Finds location of a keyword in a line.
/// keyword must be at the beginning of the line or preceeded by whitespace AND at the end of the line or followed by whitespace
/// </summary>
/// <param name="line">line to seach</param>
/// <param name="keyword">keyword to search for</param>
/// <returns>location of first character of keyword</returns>
private static int IndexOfKeyword(string line,string keyword)
{
int index = line.IndexOf(keyword,StringComparison.Ordinal);
if ( index < 0 )
return index;
int indexAfter = index+keyword.Length;
if ( (index == 0 || char.IsWhiteSpace(line,index-1)) && (indexAfter == line.Length || char.IsWhiteSpace(line,indexAfter)) )
return index;
return -1;
}
#endregion
}
}

View File

@@ -0,0 +1,41 @@
//---------------------------------------------------------------------
// <copyright file="FixUpType.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// Types of fix ups the client code generator can perform on the generated code
/// </summary>
// these values are used as indexes in the m_fixMethods list.
internal enum FixUpType
{
/// <summary>Mark an override method as final (sealed)</summary>
MarkOverrideMethodAsSealed = 1,
/// <summary>Mark a property setter as internal</summary>
MarkPropertySetAsInternal = 2,
/// <summary>Mark a class as static</summary>
MarkClassAsStatic = 3,
/// <summary>Mark a property getter as private</summary>
MarkPropertyGetAsPrivate = 4,
/// <summary>Mark a property getter as internal</summary>
MarkPropertyGetAsInternal = 5,
/// <summary>Mark a property getter as public</summary>
MarkPropertyGetAsPublic = 6,
/// <summary>Mark a property setter as private</summary>
MarkPropertySetAsPrivate = 7,
/// <summary>Mark a property setter as public</summary>
MarkPropertySetAsPublic = 8,
/// <summary>Mark a method as partial</summary>
MarkAbstractMethodAsPartial = 9,
/// <summary>Mark a property getter as protected</summary>
MarkPropertyGetAsProtected = 10,
/// <summary>Mark a property setter as protected</summary>
MarkPropertySetAsProtected = 11,
}
}

View File

@@ -0,0 +1,197 @@
//---------------------------------------------------------------------
// <copyright file="MetadataItemEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.CodeDom;
using System.Reflection;
namespace System.Data.EntityModel.Emitters
{
internal abstract class MetadataItemEmitter : Emitter
{
private MetadataItem _item;
protected MetadataItemEmitter(ClientApiGenerator generator, MetadataItem item)
:base(generator)
{
Debug.Assert(item != null, "item is null");
_item = item;
}
protected MetadataItem Item
{
get { return _item; }
}
/// <summary>
/// Emitter-specific validation here
/// </summary>
protected abstract void Validate();
#region Operations for Getting Accessibility
private const string CodeGenerationValueAccessibilityInternal = "Internal";
private const string CodeGenerationValueAccessibilityProtected = "Protected";
private const string CodeGenerationValueAccessibilityPublic = "Public";
private const string CodeGenerationValueAccessibilityPrivate = "Private";
#region Protected Block
protected static MemberAttributes AccessibilityFromGettersAndSetters(EdmMember property)
{
MemberAttributes scope = MemberAttributes.Private;
MemberAttributes getter = GetGetterAccessibility(property);
if (IsLeftMoreAccessableThanRight(getter, scope))
{
scope = getter;
}
MemberAttributes setter = GetSetterAccessibility(property);
if (IsLeftMoreAccessableThanRight(setter, scope))
{
scope = setter;
}
return scope;
}
protected static MemberAttributes GetGetterAccessibility(EdmMember item)
{
return GetAccessibilityValue(item, XmlConstants.GetterAccess);
}
protected static MemberAttributes GetSetterAccessibility(EdmMember item)
{
return GetAccessibilityValue(item, XmlConstants.SetterAccess);
}
protected static MemberAttributes GetFunctionImportAccessibility(EdmFunction item)
{
return GetAccessibilityValue(item, XmlConstants.MethodAccess);
}
protected static MemberAttributes GetEntitySetPropertyAccessibility(EntitySet item)
{
return GetAccessibilityValue(item, XmlConstants.GetterAccess);
}
protected static MemberAttributes GetEntityTypeAccessibility(EntityType item)
{
return GetAccessibilityValue(item, XmlConstants.TypeAccess);
}
protected static int GetAccessibilityRank(MemberAttributes accessibility)
{
Debug.Assert(accessibility == MemberAttributes.Private ||
accessibility == MemberAttributes.Public ||
accessibility == MemberAttributes.Assembly ||
accessibility == MemberAttributes.Family,
"this method is intended to deal with only single access attributes");
switch (accessibility)
{
case MemberAttributes.Public:
return 0;
case MemberAttributes.Assembly:
return 1;
case MemberAttributes.Family:
return 2;
default:
Debug.Assert(accessibility == MemberAttributes.Private, "did a new type get added?");
return 3;
}
}
protected static TypeAttributes GetTypeAccessibilityValue(MetadataItem item)
{
TypeAttributes accessibilty = TypeAttributes.Public;
MetadataProperty metadataProperty;
if (item.MetadataProperties.TryGetValue(Utils.GetFullyQualifiedCodeGenerationAttributeName(XmlConstants.TypeAccess), false, out metadataProperty))
{
accessibilty = GetCodeAccessibilityTypeAttribute(metadataProperty.Value.ToString());
}
return accessibilty;
}
#endregion Protected
#region Private Block
private static MemberAttributes GetAccessibilityValue(MetadataItem item, string attribute)
{
MemberAttributes accessibilty = MemberAttributes.Public;
MetadataProperty metadataProperty;
if (item.MetadataProperties.TryGetValue(Utils.GetFullyQualifiedCodeGenerationAttributeName(attribute), false, out metadataProperty))
{
accessibilty = GetCodeAccessibilityMemberAttribute(metadataProperty.Value.ToString());
}
return accessibilty;
}
private static MemberAttributes GetCodeAccessibilityMemberAttribute(string accessibility)
{
Debug.Assert(accessibility != null, "why does accessibility == null?");
switch (accessibility)
{
case CodeGenerationValueAccessibilityInternal:
return MemberAttributes.Assembly;
case CodeGenerationValueAccessibilityPrivate:
return MemberAttributes.Private;
case CodeGenerationValueAccessibilityProtected:
return MemberAttributes.Family;
default:
Debug.Assert(accessibility == CodeGenerationValueAccessibilityPublic, "found an accessibility other than " + CodeGenerationValueAccessibilityPublic);
return MemberAttributes.Public;
}
}
/// <summary>
/// Given a MemberAttribute, returns a string representation used in CSDL.
/// For e.g: MemebrAttribtue.Family is Protected in our csdl, (protected in C#, Family in VB)
/// Inverse of the method above (GetCodeAccessibilityMemberAttribute)
/// </summary>
protected static string GetAccessibilityCsdlStringFromMemberAttribute(MemberAttributes attribute)
{
switch (attribute)
{
case MemberAttributes.Assembly:
return CodeGenerationValueAccessibilityInternal;
case MemberAttributes.Private:
return CodeGenerationValueAccessibilityPrivate;
case MemberAttributes.Family:
return CodeGenerationValueAccessibilityProtected;
default:
Debug.Assert(attribute == MemberAttributes.Public, "found MemberAttribute other than " + CodeGenerationValueAccessibilityPublic);
return CodeGenerationValueAccessibilityPublic;
}
}
private static bool IsLeftMoreAccessableThanRight(MemberAttributes left, MemberAttributes right)
{
return GetAccessibilityRank(left) < GetAccessibilityRank(right);
}
private static TypeAttributes GetCodeAccessibilityTypeAttribute(string accessibility)
{
Debug.Assert(accessibility != null, "why does accessibility == null?");
if (accessibility == CodeGenerationValueAccessibilityInternal || accessibility == CodeGenerationValueAccessibilityProtected)
{
return TypeAttributes.NotPublic;
}
else
{
Debug.Assert(accessibility == CodeGenerationValueAccessibilityPublic, "found an accessibility other than " + CodeGenerationValueAccessibilityPublic);
return TypeAttributes.Public;
}
}
#endregion Private
#endregion Operations for getting Accessibility
}
}

View File

@@ -0,0 +1,189 @@
//---------------------------------------------------------------------
// <copyright file="NamespaceEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Data;
using Som = System.Data.EntityModel.SchemaObjectModel;
using System.Collections.Generic;
using System.Data.Entity.Design;
using System.Data.Metadata.Edm;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Data.Entity.Design.SsdlGenerator;
using System.Data.Entity.Design.Common;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// This class is responsible for Emitting the code to create the CLR namespace container and assembly level attributes
/// </summary>
internal sealed class NamespaceEmitter : Emitter
{
#region Static Fields
private static Pair<Type, CreateEmitter>[] EmitterCreators = new Pair<Type, CreateEmitter>[]
{
new Pair<Type,CreateEmitter>(typeof(EntityType), delegate (ClientApiGenerator generator, GlobalItem element) { return new EntityTypeEmitter(generator,(EntityType)element); }),
new Pair<Type,CreateEmitter>(typeof(ComplexType), delegate (ClientApiGenerator generator, GlobalItem element) { return new ComplexTypeEmitter(generator,(ComplexType)element); }),
new Pair<Type,CreateEmitter>(typeof(EntityContainer), delegate (ClientApiGenerator generator, GlobalItem element) { return new EntityContainerEmitter(generator,(EntityContainer)element); }),
new Pair<Type,CreateEmitter>(typeof(AssociationType), delegate (ClientApiGenerator generator, GlobalItem element) { return new AssociationTypeEmitter(generator,(AssociationType)element); }),
};
#endregion
#region Private Fields
private string _codeNamespace = null;
private string _targetFilePath = null;
#endregion
#region Public Methods
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
public NamespaceEmitter(ClientApiGenerator generator, string codeNamespace, string targetFilePath)
: base(generator)
{
_codeNamespace = codeNamespace;
_targetFilePath = targetFilePath != null ? targetFilePath : string.Empty;
}
/// <summary>
/// Creates the CodeTypeDeclarations necessary to generate the code
/// </summary>
public void Emit()
{
// it is a valid scenario for namespaceName to be empty
string namespaceName = Generator.SourceObjectNamespaceName;
// emit the namespace definition
CodeNamespace codeNamespace = new CodeNamespace( namespaceName );
// output some boiler plate comments
string comments = Strings.NamespaceComments(
System.IO.Path.GetFileName( _targetFilePath ),
DateTime.Now.ToString( System.Globalization.CultureInfo.CurrentCulture ));
CommentEmitter.EmitComments( CommentEmitter.GetFormattedLines( comments, false ), codeNamespace.Comments, false );
CompileUnit.Namespaces.Add( codeNamespace );
// Add the assembly attribute.
CodeAttributeDeclaration assemblyAttribute;
// SQLBUDT 505339: VB compiler fails if multiple assembly attributes exist in the same project.
// This adds a GUID to the assembly attribute so that each generated file will have a unique EdmSchemaAttribute in VB.
if (this.Generator.Language == System.Data.Entity.Design.LanguageOption.GenerateVBCode) //The GUID is only added in VB
{
assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute", System.Guid.NewGuid().ToString());
}
else
{
assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute");
}
CompileUnit.AssemblyCustomAttributes.Add(assemblyAttribute);
Dictionary<string, string> usedClassName = new Dictionary<string, string>(StringComparer.Ordinal);
// Emit the classes in the schema
foreach (GlobalItem element in Generator.GetSourceTypes())
{
Debug.Assert(!(element is EdmFunction), "Are you trying to emit functions now? If so add an emitter for it.");
if (AddElementNameToCache(element, usedClassName))
{
SchemaTypeEmitter emitter = CreateElementEmitter(element);
CodeTypeDeclarationCollection typeDeclaration = emitter.EmitApiClass();
if (typeDeclaration.Count > 0)
{
codeNamespace.Types.AddRange(typeDeclaration);
}
}
}
}
#endregion
#region Private Properties
/// <summary>
/// Gets the compile unit (top level codedom object)
/// </summary>
/// <value></value>
private CodeCompileUnit CompileUnit
{
get
{
return Generator.CompileUnit;
}
}
#endregion
private bool AddElementNameToCache(GlobalItem element, Dictionary<string, string> cache)
{
if (element.BuiltInTypeKind == BuiltInTypeKind.EntityContainer)
{
return TryAddNameToCache((element as EntityContainer).Name, element.BuiltInTypeKind.ToString(), cache);
}
else if (element.BuiltInTypeKind == BuiltInTypeKind.EntityType ||
element.BuiltInTypeKind == BuiltInTypeKind.ComplexType ||
element.BuiltInTypeKind == BuiltInTypeKind.AssociationType)
{
return TryAddNameToCache((element as StructuralType).Name, element.BuiltInTypeKind.ToString(), cache);
}
return true;
}
private bool TryAddNameToCache(string name, string type, Dictionary<string, string> cache)
{
if (!cache.ContainsKey(name))
{
cache.Add(name, type);
}
else
{
this.Generator.AddError(Strings.DuplicateClassName(type, name, cache[name]), ModelBuilderErrorCode.DuplicateClassName,
EdmSchemaErrorSeverity.Error, name);
return false;
}
return true;
}
/// <summary>
/// Create an Emitter for a schema type element
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private SchemaTypeEmitter CreateElementEmitter( GlobalItem element )
{
Type typeOfElement = element.GetType();
foreach ( Pair<Type, CreateEmitter> pair in EmitterCreators )
{
if ( pair.First.IsAssignableFrom( typeOfElement ) )
return pair.Second( Generator, element );
}
return null;
}
private delegate SchemaTypeEmitter CreateEmitter( ClientApiGenerator generator, GlobalItem item );
/// <summary>
/// Reponsible for relating two objects together into a pair
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
private class Pair<T1, T2>
{
public T1 First;
public T2 Second;
internal Pair( T1 first, T2 second )
{
First = first;
Second = second;
}
}
}
}

View File

@@ -0,0 +1,364 @@
//---------------------------------------------------------------------
// <copyright file="NavigationPropertyEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Data;
using System.Collections.Generic;
using System.Data.Entity.Design;
using Som=System.Data.EntityModel.SchemaObjectModel;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Data.Entity.Design.SsdlGenerator;
using System.Data.Entity.Design.Common;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// Summary description for NavigationPropertyEmitter.
/// </summary>
internal sealed class NavigationPropertyEmitter : PropertyEmitterBase
{
private const string ValuePropertyName = "Value";
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
/// <param name="navigationProperty"></param>
public NavigationPropertyEmitter(ClientApiGenerator generator, NavigationProperty navigationProperty, bool declaringTypeUsesStandardBaseType)
: base(generator, navigationProperty, declaringTypeUsesStandardBaseType)
{
}
/// <summary>
/// Generate the navigation property
/// </summary>
/// <param name="typeDecl">The type to add the property to.</param>
protected override void EmitProperty(CodeTypeDeclaration typeDecl)
{
EmitNavigationProperty(typeDecl);
}
/// <summary>
/// Generate the navigation property specified
/// </summary>
/// <param name="typeDecl">The type to add the property to.</param>
private void EmitNavigationProperty( CodeTypeDeclaration typeDecl )
{
// create a regular property
CodeMemberProperty property = EmitNavigationProperty(Item.ToEndMember, false);
typeDecl.Members.Add(property);
if (Item.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many)
{
// create a ref property
property = EmitNavigationProperty(Item.ToEndMember, true);
typeDecl.Members.Add(property);
}
}
/// <summary>
/// Generate a navigation property
/// </summary>
/// <param name="target">the other end</param>
/// <param name="referenceProperty">True to emit Reference navigation property</param>
/// <returns>the generated property</returns>
private CodeMemberProperty EmitNavigationProperty(RelationshipEndMember target, bool referenceProperty)
{
CodeTypeReference typeRef = GetReturnType(target, referenceProperty);
// raise the PropertyGenerated event
PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item,
null, // no backing field
typeRef);
this.Generator.RaisePropertyGeneratedEvent(eventArgs);
// [System.ComponentModel.Browsable(false)]
// public TargetType TargetName
// public EntityReference<TargetType> TargetName
// or
// public EntityCollection<targetType> TargetNames
CodeMemberProperty property = new CodeMemberProperty();
if (referenceProperty)
{
AttributeEmitter.AddBrowsableAttribute(property);
Generator.AttributeEmitter.EmitGeneratedCodeAttribute(property);
}
else
{
Generator.AttributeEmitter.EmitNavigationPropertyAttributes(Generator, target, property, eventArgs.AdditionalAttributes);
// Only reference navigation properties are currently currently supported with XML serialization
// and thus we should use the XmlIgnore and SoapIgnore attributes on other property types.
AttributeEmitter.AddIgnoreAttributes(property);
}
AttributeEmitter.AddDataMemberAttribute(property);
CommentEmitter.EmitSummaryComments(Item, property.Comments);
property.Name = Item.Name;
if (referenceProperty)
{
property.Name += "Reference";
if (IsNameAlreadyAMemberName(Item.DeclaringType, property.Name, Generator.LanguageAppropriateStringComparer))
{
Generator.AddError(Strings.GeneratedNavigationPropertyNameConflict(Item.Name, Item.DeclaringType.Name, property.Name),
ModelBuilderErrorCode.GeneratedNavigationPropertyNameConflict,
EdmSchemaErrorSeverity.Error, Item.DeclaringType.FullName, property.Name);
}
}
if (eventArgs.ReturnType != null && !eventArgs.ReturnType.Equals(typeRef))
{
property.Type = eventArgs.ReturnType;
}
else
{
property.Type = typeRef;
}
property.Attributes = MemberAttributes.Final;
CodeMethodInvokeExpression getMethod = EmitGetMethod(target);
CodeExpression getReturnExpression;
property.Attributes |= AccessibilityFromGettersAndSetters(Item);
// setup the accessibility of the navigation property setter and getter
MemberAttributes propertyAccessibility = property.Attributes & MemberAttributes.AccessMask;
PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name),
PropertyEmitter.GetGetterAccessibility(Item), propertyAccessibility, true);
PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name),
PropertyEmitter.GetSetterAccessibility(Item), propertyAccessibility, false);
if (target.RelationshipMultiplicity != RelationshipMultiplicity.Many)
{
// insert user-supplied Set code here, before the assignment
//
List<CodeStatement> additionalSetStatements = eventArgs.AdditionalSetStatements;
if (additionalSetStatements != null && additionalSetStatements.Count > 0)
{
try
{
property.SetStatements.AddRange(additionalSetStatements.ToArray());
}
catch (ArgumentNullException ex)
{
Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name),
ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty,
EdmSchemaErrorSeverity.Error,
ex);
}
}
CodeExpression valueRef = new CodePropertySetValueReferenceExpression();
if(typeRef != eventArgs.ReturnType)
{
// we need to cast to the actual type
valueRef = new CodeCastExpression(typeRef, valueRef);
}
if (referenceProperty)
{
// get
// return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName");
getReturnExpression = getMethod;
// set
// if (value != null)
// {
// ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<TTargetEntity>"CSpaceQualifiedRelationshipName", "TargetRoleName", value);
// }
CodeMethodReferenceExpression initReferenceMethod = new CodeMethodReferenceExpression();
initReferenceMethod.MethodName = "InitializeRelatedReference";
initReferenceMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target)));
initReferenceMethod.TargetObject = new CodePropertyReferenceExpression(
new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef),
"RelationshipManager");
// relationships aren't backed by types so we won't map the namespace
// or we can't find the relationship again later
string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName;
property.SetStatements.Add(
new CodeConditionStatement(
EmitExpressionDoesNotEqualNull(valueRef),
new CodeExpressionStatement(
new CodeMethodInvokeExpression(
initReferenceMethod, new CodeExpression[] {
new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name), valueRef}))));
}
else
{
CodePropertyReferenceExpression valueProperty = new CodePropertyReferenceExpression(getMethod, ValuePropertyName);
// get
// return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value;
getReturnExpression = valueProperty;
// set
// ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value = value;
property.SetStatements.Add(
new CodeAssignStatement(valueProperty, valueRef));
}
}
else
{
// get
// return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName");
getReturnExpression = getMethod;
// set
// if (value != null)
// {
// ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<TTargetEntity>"CSpaceQualifiedRelationshipName", "TargetRoleName", value);
// }
CodeExpression valueRef = new CodePropertySetValueReferenceExpression();
CodeMethodReferenceExpression initCollectionMethod = new CodeMethodReferenceExpression();
initCollectionMethod.MethodName = "InitializeRelatedCollection";
initCollectionMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target)));
initCollectionMethod.TargetObject = new CodePropertyReferenceExpression(
new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef),
"RelationshipManager");
// relationships aren't backed by types so we won't map the namespace
// or we can't find the relationship again later
string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName;
property.SetStatements.Add(
new CodeConditionStatement(
EmitExpressionDoesNotEqualNull(valueRef),
new CodeExpressionStatement(
new CodeMethodInvokeExpression(
initCollectionMethod, new CodeExpression[] {
new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name), valueRef}))));
}
// if additional Get statements were specified by the event subscriber, insert them now
//
List<CodeStatement> additionalGetStatements = eventArgs.AdditionalGetStatements;
if (additionalGetStatements != null && additionalGetStatements.Count > 0)
{
try
{
property.GetStatements.AddRange(additionalGetStatements.ToArray());
}
catch (ArgumentNullException ex)
{
Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name),
ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty,
EdmSchemaErrorSeverity.Error,
ex);
}
}
property.GetStatements.Add(new CodeMethodReturnStatement(getReturnExpression));
return property;
}
internal static bool IsNameAlreadyAMemberName(StructuralType type, string generatedPropertyName, StringComparison comparison)
{
foreach (EdmMember member in type.Members)
{
if (member.DeclaringType == type &&
member.Name.Equals(generatedPropertyName, comparison))
{
return true;
}
}
return false;
}
private string GetFullyQualifiedPropertyName(string propertyName)
{
return Item.DeclaringType.FullName + "." + propertyName;
}
/// <summary>
/// Gives the SchemaElement back cast to the most
/// appropriate type
/// </summary>
private new NavigationProperty Item
{
get
{
return base.Item as NavigationProperty;
}
}
/// <summary>
/// Get the return type for the get method, given the target end
/// </summary>
/// <param name="target"></param>
/// <param name="referenceMethod">true if the is the return type for a reference property</param>
/// <returns>the return type for a target</returns>
private CodeTypeReference GetReturnType(RelationshipEndMember target, bool referenceMethod)
{
CodeTypeReference returnType = Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target));
if (referenceMethod)
{
returnType = TypeReference.AdoFrameworkGenericDataClass("EntityReference", returnType);
}
else if (target.RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
returnType = TypeReference.AdoFrameworkGenericDataClass("EntityCollection", returnType);
}
return returnType;
}
private static EntityTypeBase GetEntityType(RelationshipEndMember endMember)
{
Debug.Assert(endMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "not a reference type");
EntityTypeBase type = ((RefType)endMember.TypeUsage.EdmType).ElementType;
return type;
}
/// <summary>
/// Emit the GetRelatedCollection or GetRelatedReference methods
/// </summary>
/// <param name="target">Target end of the relationship</param>
/// <returns>Expression to invoke the appropriate method</returns>
private CodeMethodInvokeExpression EmitGetMethod(RelationshipEndMember target)
{
// ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TargetType>("CSpaceQualifiedRelationshipName", "TargetRoleName");
// or
// ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<TargetType>("CSpaceQualifiedRelationshipName", "TargetRoleName");
CodeMethodReferenceExpression getMethod = new CodeMethodReferenceExpression();
if (target.RelationshipMultiplicity != RelationshipMultiplicity.Many)
getMethod.MethodName = "GetRelatedReference";
else
getMethod.MethodName = "GetRelatedCollection";
getMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target)));
getMethod.TargetObject = new CodePropertyReferenceExpression(
new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef),
"RelationshipManager");
// relationships aren't backed by types so we won't map the namespace
// or we can't find the relationship again later
string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName;
return new CodeMethodInvokeExpression(
getMethod, new CodeExpression[] { new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name)});
}
}
}

View File

@@ -0,0 +1,28 @@
//---------------------------------------------------------------------
// <copyright file="PrivateMemberPrefixId.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
namespace System.Data.EntityModel.Emitters
{
internal enum PrivateMemberPrefixId
{
Field,
IntializeMethod,
PropertyInfoProperty,
PropertyInfoField,
// add additional members here
Count
}
}

View File

@@ -0,0 +1,105 @@
//---------------------------------------------------------------------
// <copyright file="PropertyEmitterBase.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Data.Entity.Design.SsdlGenerator;
using System.Data.Entity.Design.Common;
namespace System.Data.EntityModel.Emitters
{
internal abstract class PropertyEmitterBase : MetadataItemEmitter
{
private bool _declaringTypeUsesStandardBaseType;
protected PropertyEmitterBase(ClientApiGenerator generator, MetadataItem item, bool declaringTypeUsesStandardBaseType)
:base(generator, item)
{
Debug.Assert(item != null, "item is null");
_declaringTypeUsesStandardBaseType = declaringTypeUsesStandardBaseType;
}
/// <summary>
/// This is where the derived classes supply their emit logic.
/// </summary>
/// <param name="typeDecl">The CodeDom representation of the type that the property is being added to.</param>
protected abstract void EmitProperty(CodeTypeDeclaration typeDecl);
/// <summary>
/// Validation logic specific to property emitters
/// </summary>
protected override void Validate()
{
VerifyGetterAndSetterAccessibilityCompatability();
Generator.VerifyLanguageCaseSensitiveCompatibilityForProperty(Item as EdmMember);
}
/// <summary>
/// The compiler ensures accessibility on a Setter/Getter is more restrictive than on the Property.
/// However accessibility modifiers are not well ordered. Internal and Protected don't go well together
/// because neither is more restrictive than others.
/// </summary>
private void VerifyGetterAndSetterAccessibilityCompatability()
{
if (PropertyEmitter.GetGetterAccessibility(Item) == MemberAttributes.Assembly
&& PropertyEmitter.GetSetterAccessibility(Item) == MemberAttributes.Family)
{
Generator.AddError(System.Data.Entity.Design.Strings.GeneratedPropertyAccessibilityConflict(Item.Name, "Internal", "Protected"),
ModelBuilderErrorCode.GeneratedPropertyAccessibilityConflict,
EdmSchemaErrorSeverity.Error, Item.DeclaringType.FullName, Item.Name);
}
else if (PropertyEmitter.GetGetterAccessibility(Item) == MemberAttributes.Family
&& PropertyEmitter.GetSetterAccessibility(Item) == MemberAttributes.Assembly)
{
Generator.AddError(System.Data.Entity.Design.Strings.GeneratedPropertyAccessibilityConflict(Item.Name, "Protected", "Internal"),
ModelBuilderErrorCode.GeneratedPropertyAccessibilityConflict,
EdmSchemaErrorSeverity.Error, Item.DeclaringType.FullName, Item.Name);
}
}
/// <summary>
/// Main method for Emitting property code.
/// </summary>
/// <param name="typeDecl">The CodeDom representation of the type that the property is being added to.</param>
public void Emit(CodeTypeDeclaration typeDecl)
{
Validate();
EmitProperty(typeDecl);
}
protected bool AncestorClassDefinesName(string name)
{
if (_declaringTypeUsesStandardBaseType && Utils.DoesTypeReserveMemberName(Item.DeclaringType, name, Generator.LanguageAppropriateStringComparer))
{
return true;
}
StructuralType baseType = Item.DeclaringType.BaseType as StructuralType;
if (baseType != null && baseType.Members.Contains(name))
{
return true;
}
return false;
}
public new EdmMember Item
{
get
{
return base.Item as EdmMember;
}
}
}
}

View File

@@ -0,0 +1,168 @@
//---------------------------------------------------------------------
// <copyright file="SchemaTypeEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Data.EntityModel.SchemaObjectModel;
using Som = System.Data.EntityModel.SchemaObjectModel;
using System.Data.Metadata.Edm;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.Data.Entity.Design;
using System.Data.Entity.Design.SsdlGenerator;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
///
/// </summary>
internal abstract class SchemaTypeEmitter : MetadataItemEmitter
{
#region Public Methods
public abstract CodeTypeDeclarationCollection EmitApiClass();
#endregion
#region Protected Methods
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
/// <param name="schemaType"></param>
protected SchemaTypeEmitter(ClientApiGenerator generator, MetadataItem item)
: base(generator, item)
{
}
/// <summary>
///
/// </summary>
/// <param name="typeDecl"></param>
protected virtual void EmitTypeAttributes( CodeTypeDeclaration typeDecl )
{
Generator.AttributeEmitter.EmitTypeAttributes( this, typeDecl );
}
/// <summary>
/// Emitter-specific validation: for SchemaTypeEmitter-derived classes, we
/// check the EdmItemCollection for other entities that have the same name
/// but differ in case
/// </summary>
protected override void Validate()
{
Generator.VerifyLanguageCaseSensitiveCompatibilityForType(Item);
}
/// <summary>
/// Add attributes to a type's CustomAttributes collection
/// </summary>
/// <param name="itemName">The name of the type</param>
/// <param name="typeDecl">The type to annotate</param>
/// <param name="additionalAttributes">The additional attributes</param>
protected void EmitTypeAttributes(string itemName, CodeTypeDeclaration typeDecl,
List<CodeAttributeDeclaration> additionalAttributes)
{
if (additionalAttributes != null && additionalAttributes.Count > 0)
{
try
{
typeDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
}
catch (ArgumentNullException e)
{
Generator.AddError(Strings.InvalidAttributeSuppliedForType(itemName),
ModelBuilderErrorCode.InvalidAttributeSuppliedForType,
EdmSchemaErrorSeverity.Error,
e);
}
}
EmitTypeAttributes(typeDecl);
}
/// <summary>
/// Add interfaces to the type's list of BaseTypes
/// </summary>
/// <param name="itemName">The name of the type</param>
/// <param name="typeDecl">The type whose list of base types needs to be extended</param>
/// <param name="additionalInterfaces">The interfaces to add to the list of base types</param>
protected void AddInterfaces(string itemName,
CodeTypeDeclaration typeDecl,
List<Type> additionalInterfaces)
{
if (additionalInterfaces != null)
{
try
{
foreach (Type interfaceType in additionalInterfaces)
{
typeDecl.BaseTypes.Add(new CodeTypeReference(interfaceType));
}
}
catch (ArgumentNullException e)
{
Generator.AddError(Strings.InvalidInterfaceSuppliedForType(itemName),
ModelBuilderErrorCode.InvalidInterfaceSuppliedForType,
EdmSchemaErrorSeverity.Error,
e);
}
}
}
/// <summary>
/// Add interfaces to the type's list of BaseTypes
/// </summary>
/// <param name="itemName">The name of the type</param>
/// <param name="typeDecl">The type to which members need to be added</param>
/// <param name="additionalMembers">The members to add</param>
protected void AddMembers(string itemName, CodeTypeDeclaration typeDecl,
List<CodeTypeMember> additionalMembers)
{
if (additionalMembers != null && additionalMembers.Count > 0)
{
try
{
typeDecl.Members.AddRange(additionalMembers.ToArray());
}
catch (ArgumentNullException e)
{
Generator.AddError(Strings.InvalidMemberSuppliedForType(itemName),
ModelBuilderErrorCode.InvalidMemberSuppliedForType,
EdmSchemaErrorSeverity.Error,
e);
}
}
}
#endregion
#region Protected Properties
/// <summary>
/// Gets the element that code is being emitted for.
/// </summary>
internal new GlobalItem Item
{
get
{
return base.Item as GlobalItem;
}
}
internal void SetTypeVisibility(CodeTypeDeclaration typeDecl)
{
typeDecl.TypeAttributes &= ~System.Reflection.TypeAttributes.VisibilityMask;
typeDecl.TypeAttributes |= GetTypeAccessibilityValue(Item);
}
#endregion
}
}

View File

@@ -0,0 +1,312 @@
//---------------------------------------------------------------------
// <copyright file="StructuredTypeEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.CodeDom;
using System.Data;
using System.Data.EntityModel.SchemaObjectModel;
using Som = System.Data.EntityModel.SchemaObjectModel;
using System.Data.Entity.Design;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Reflection;
using System.Data.Objects.DataClasses;
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design.SsdlGenerator;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// Summary description for StructuredTypeEmitter.
/// </summary>
internal abstract class StructuredTypeEmitter : SchemaTypeEmitter
{
#region Public Methods
private bool _usingStandardBaseClass = true;
/// <summary>
///
/// </summary>
/// <returns></returns>
public override CodeTypeDeclarationCollection EmitApiClass()
{
Validate(); // emitter-specific validation
CodeTypeReference baseType = this.GetBaseType();
// raise the TypeGenerated event
TypeGeneratedEventArgs eventArgs = new TypeGeneratedEventArgs(Item, baseType);
this.Generator.RaiseTypeGeneratedEvent(eventArgs);
// public [abstract] partial class ClassName
CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(Item.Name);
typeDecl.IsPartial = true;
typeDecl.TypeAttributes = System.Reflection.TypeAttributes.Class;
if (Item.Abstract)
{
typeDecl.TypeAttributes |= System.Reflection.TypeAttributes.Abstract;
}
SetTypeVisibility(typeDecl);
EmitTypeAttributes(Item.Name, typeDecl, eventArgs.AdditionalAttributes);
// : baseclass
AssignBaseType(typeDecl, baseType, eventArgs.BaseType);
AddInterfaces(Item.Name, typeDecl, eventArgs.AdditionalInterfaces);
CommentEmitter.EmitSummaryComments(Item, typeDecl.Comments);
// Since abstract types cannot be instantiated, skip the factory method for abstract types
if ( (typeDecl.TypeAttributes & System.Reflection.TypeAttributes.Abstract) == 0)
EmitFactoryMethod(typeDecl);
EmitProperties(typeDecl);
// additional members, if provided by the event subscriber
this.AddMembers(Item.Name, typeDecl, eventArgs.AdditionalMembers);
CodeTypeDeclarationCollection typeDecls = new CodeTypeDeclarationCollection();
typeDecls.Add(typeDecl);
return typeDecls;
}
#endregion
#region Protected Methods
/// <summary>
///
/// </summary>
/// <returns></returns>
protected virtual CodeTypeReference GetBaseType()
{
if (Item.BaseType == null)
return null;
return Generator.GetLeastPossibleQualifiedTypeReference(Item.BaseType);
}
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
/// <param name="structuredType"></param>
protected StructuredTypeEmitter(ClientApiGenerator generator, StructuralType structuralType)
: base(generator, structuralType)
{
}
/// <summary>
///
/// </summary>
/// <param name="typeDecl"></param>
protected override void EmitTypeAttributes(CodeTypeDeclaration typeDecl)
{
Generator.AttributeEmitter.EmitTypeAttributes(this, typeDecl);
base.EmitTypeAttributes(typeDecl);
}
/// <summary>
///
/// </summary>
/// <param name="typeDecl"></param>
protected virtual void EmitProperties(CodeTypeDeclaration typeDecl)
{
foreach (EdmProperty property in Item.GetDeclaredOnlyMembers<EdmProperty>())
{
PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, _usingStandardBaseClass);
propertyEmitter.Emit(typeDecl);
}
}
protected abstract ReadOnlyMetadataCollection<EdmProperty> GetProperties();
/// <summary>
/// Emit static factory method which creates an instance of the class and initializes
/// non-nullable properties (taken as arguments)
/// </summary>
/// <param name="typeDecl"></param>
protected virtual void EmitFactoryMethod(CodeTypeDeclaration typeDecl)
{
// build list of non-nullable properties
ReadOnlyMetadataCollection<EdmProperty> properties = GetProperties();
List<EdmProperty> parameters = new List<EdmProperty>(properties.Count);
foreach (EdmProperty property in properties)
{
bool include = IncludeFieldInFactoryMethod(property);
if (include)
{
parameters.Add(property);
}
}
// if there are no parameters, we don't emit anything (1 is for the null element)
// nor do we emit everything if this is the Ref propertied ctor and the parameter list is the same as the many parametered ctor
if (parameters.Count < 1)
{
return;
}
CodeMemberMethod method = new CodeMemberMethod();
Generator.AttributeEmitter.EmitGeneratedCodeAttribute(method);
CodeTypeReference typeRef = TypeReference.FromString(Item.Name);
UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService(Generator.IsLanguageCaseSensitive, name => Utils.FixParameterName(name));
string instanceName = uniqueIdentifierService.AdjustIdentifier(Item.Name);
// public static Class CreateClass(...)
method.Attributes = MemberAttributes.Static|MemberAttributes.Public;
method.Name = "Create" + Item.Name;
if (NavigationPropertyEmitter.IsNameAlreadyAMemberName(Item, method.Name, Generator.LanguageAppropriateStringComparer))
{
Generator.AddError(Strings.GeneratedFactoryMethodNameConflict(method.Name, Item.Name),
ModelBuilderErrorCode.GeneratedFactoryMethodNameConflict,
EdmSchemaErrorSeverity.Error, Item.FullName);
}
method.ReturnType = typeRef;
// output method summary comments
CommentEmitter.EmitSummaryComments(Strings.FactoryMethodSummaryComment(Item.Name), method.Comments);
// Class class = new Class();
CodeVariableDeclarationStatement createNewInstance = new CodeVariableDeclarationStatement(
typeRef, instanceName, new CodeObjectCreateExpression(typeRef));
method.Statements.Add(createNewInstance);
CodeVariableReferenceExpression instanceRef = new CodeVariableReferenceExpression(instanceName);
// iterate over the properties figuring out which need included in the factory method
foreach (EdmProperty property in parameters)
{
// CreateClass( ... , propType propName ...)
PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, UsingStandardBaseClass);
CodeTypeReference propertyTypeReference = propertyEmitter.PropertyType;
String parameterName = uniqueIdentifierService.AdjustIdentifier(propertyEmitter.PropertyName);
CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression(
propertyTypeReference, parameterName);
CodeArgumentReferenceExpression paramRef = new CodeArgumentReferenceExpression(paramDecl.Name);
method.Parameters.Add(paramDecl);
// add comment describing the parameter
CommentEmitter.EmitParamComments(paramDecl, Strings.FactoryParamCommentGeneral(propertyEmitter.PropertyName), method.Comments);
CodeExpression newPropertyValue;
if (MetadataUtil.IsComplexType(propertyEmitter.Item.TypeUsage.EdmType))
{
List<CodeExpression> complexVerifyParameters = new List<CodeExpression>();
complexVerifyParameters.Add(paramRef);
complexVerifyParameters.Add(new CodePrimitiveExpression(propertyEmitter.PropertyName));
newPropertyValue =
new CodeMethodInvokeExpression(
PropertyEmitter.CreateEdmStructuralObjectRef(TypeReference),
Utils.VerifyComplexObjectIsNotNullName,
complexVerifyParameters.ToArray());
}
else
{
newPropertyValue = paramRef;
}
// Scalar property:
// Property = param;
// Complex property:
// Property = StructuralObject.VerifyComplexObjectIsNotNull(param, propertyName);
method.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(instanceRef, propertyEmitter.PropertyName), newPropertyValue));
}
// return class;
method.Statements.Add(new CodeMethodReturnStatement(instanceRef));
// actually add the method to the class
typeDecl.Members.Add(method);
}
#endregion
#region Protected Properties
internal new StructuralType Item
{
get
{
return base.Item as StructuralType;
}
}
protected bool UsingStandardBaseClass
{
get { return _usingStandardBaseClass; }
}
#endregion
#region Private Methods
/// <summary>
///
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private bool IncludeFieldInFactoryMethod(EdmProperty property)
{
if (property.Nullable)
{
return false;
}
if (PropertyEmitter.HasDefault(property))
{
return false;
}
if ((PropertyEmitter.GetGetterAccessibility(property) != MemberAttributes.Public &&
PropertyEmitter.GetSetterAccessibility(property) != MemberAttributes.Public) ||
// declared in a sub type, but not setter accessbile from this type
(Item != property.DeclaringType && PropertyEmitter.GetSetterAccessibility(property) == MemberAttributes.Private)
)
{
return false;
}
return true;
}
private void AssignBaseType(CodeTypeDeclaration typeDecl,
CodeTypeReference baseType,
CodeTypeReference eventReturnedBaseType)
{
if (eventReturnedBaseType != null && !eventReturnedBaseType.Equals(baseType))
{
_usingStandardBaseClass = false;
typeDecl.BaseTypes.Add(eventReturnedBaseType);
}
else
{
if (baseType != null)
{
typeDecl.BaseTypes.Add(baseType);
}
}
}
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More