<#
#region File and License Information
/*
<File>
<Copyright>Copyright © 2007, Daniel Vaughan. All rights reserved.</Copyright>
<License>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</License>
<Owner Name="Daniel Vaughan" Email="dbvaughan@gmail.com"/>
<CreationDate>2009-08-15 11:55:41Z</CreationDate>
<Version>2.0</Version>
</File>
*/
#endregion
#>
<#@ template language="C#" hostSpecific="true" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Globalization" #>
// ReSharper disable PossibleNullReferenceException
/*
This code was automatically generated by Daniel Vaughan's metadata generator.
Changes to this file may be lost if regeneration occurs.
http://danielvaughan.orpius.com
*/
<#
if (supportXamlBinding)
{
WriteLine("using System.Windows;");
}
#>
using System;
using System.Linq;
using System.Linq.Expressions;
<# if (supportObfuscation) { #>
namespace DanielVaughan.Metadata
{
static class ObfuscatedNameResolver
{
static readonly System.Collections.Generic.Dictionary<string, string> obfuscatedNames = new System.Collections.Generic.Dictionary<string, string>();
#if !SILVERLIGHT
static readonly System.Threading.ReaderWriterLockSlim membersLock = new System.Threading.ReaderWriterLockSlim();
public static string GetObfuscatedName(string preobfuscationName, Func<string, string> action)
{
membersLock.EnterUpgradeableReadLock();
string result;
try
{
if (!obfuscatedNames.TryGetValue(preobfuscationName, out result))
{
membersLock.EnterWriteLock();
try
{
if (!obfuscatedNames.TryGetValue(preobfuscationName, out result))
{
result = action(preobfuscationName);
obfuscatedNames[preobfuscationName] = result;
}
}
finally
{
membersLock.ExitWriteLock();
}
}
return result;
}
finally
{
membersLock.ExitUpgradeableReadLock();
}
}
#else
static readonly object membersLock = new object();
public static string GetObfuscatedName(string preobfuscationName, Func<string, string> action)
{
string result;
if (!obfuscatedNames.TryGetValue(preobfuscationName, out result))
{
lock (membersLock)
{
if (!obfuscatedNames.TryGetValue(preobfuscationName, out result))
{
result = action(preobfuscationName);
obfuscatedNames[preobfuscationName] = result;
}
}
}
return result;
}
#endif
}
}
<# } #>
<#
Process();
#>
// ReSharper restore PossibleNullReferenceException
<#+
/// <summary>
/// If <c>true</c> <see cref="System.Windows.PropertyPath"/> properties
/// will be generated for use in binding path assignment.
/// </summary>
const bool supportXamlBinding = true;
/// <summary>
/// If <c>true</c> key strings will be generated for all keys located
/// in XAML files.
/// </summary>
const bool generateXamlKeys = true;
/// <summary>
/// XAML metadata is placed into namespaces that are based on the folder structure
/// of the project. In order to avoid unintended collisions with type names, a root namespace
/// can be used. This value can be an empty string, however this is not recommended.
/// </summary>
const string xamlRootNamespace = "XamlMetadata";
/// <summary>
/// The suffix to use for output class that represent XAML files.
/// This is used along with <see cref="generatedClassPrefix"/>
/// and <see cref="generatedClassSuffix"/> to name output classes.
/// A XAML file called Window1.xaml will be represented by a class
/// called [generatedClassPrefix]Window1[generatedXamlClassSuffix][generatedClassSuffix]
/// </summary>
const string generatedXamlClassSuffix = "Xaml";
/// <summary>
/// This is experimental. Generic, out, and ref parameters are not supported.
/// If <c>true</c> <see cref="System.Windows.PropertyPath"/> member metadata
/// will be derived using expression trees.
/// Only use if obfuscation will occur.
/// </summary>
const bool supportObfuscation = false;
/// <summary>
/// The modifier to use when outputting classes.
/// </summary>
const string generatedClassAccessModifier = "public";
/// <summary>
/// The prefix to use for output class and interface names.
/// The combination of this and <see cref="generatedClassSuffix"/> provides
/// MetaGen with the ability to identify those classes etc.,
/// for which it should generated metadata, and to ignore MetaGen generated classes.
/// </summary>
const string generatedClassPrefix = "";
/// <summary>
/// The suffix to use for output class and interface names.
/// The combination of this and <see cref="generatedClassSuffix"/> provides
/// MetaGen with the ability to identify those classes etc.,
/// for which it should generated metadata, and to ignore MetaGen generated classes.
/// </summary>
const string generatedClassSuffix = "Metadata";
/// <summary>
/// The child namespace in which to place generated items.
/// If there is a class in MyNamespace namespace,
/// the metadata class will be generated
/// in the MyNamespace.[generatedClassSuffix] namespace.
/// This string can be null or empty, in which case a subnamesapce
/// will not be created, and generated output will reside
/// in the original classes namespace.
/// </summary>
const string generatedNamespace = "Metadata";
/// <summary>
/// The number of spaces to insert for a one step indent.
/// </summary>
const int tabSize = 4;
readonly Regex xClassRegex = new Regex(@"x:Key=""(?<KeyName>\w+?)""", RegexOptions.Compiled);
string projectName;
string rootNamespace;
public void Process()
{
/* Retrieve the DTE. */
IServiceProvider hostServiceProvider = (IServiceProvider)Host;
EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
/* Retrieve the project in which this template resides. */
EnvDTE.ProjectItem containingProjectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
Project project = containingProjectItem.ContainingProject;
projectName = project.FullName;
/* TODO: Get default namespace from project file. */
rootNamespace = project.Name.Replace(" ", string.Empty);
/* Build the namespace representations, which contain class etc. */
Dictionary<string, NamespaceBuilder> namespaceBuilders = new Dictionary<string, NamespaceBuilder>();
foreach (ProjectItem projectItem in project.ProjectItems)
{
ProcessProjectItem(projectItem, namespaceBuilders, string.Empty);
}
/* Finally, write them to the output. */
foreach (object item in namespaceBuilders.Values)
{
WriteLine(item.ToString());
}
}
string processingDirectory = string.Empty;
public void ProcessProjectItem(ProjectItem projectItem,
Dictionary<string, NamespaceBuilder> namespaceBuilders, string activeNamespace)
{
FileCodeModel fileCodeModel = projectItem.FileCodeModel;
if (fileCodeModel != null)
{
foreach (CodeElement codeElement in fileCodeModel.CodeElements)
{
WalkElements(codeElement, null, null, namespaceBuilders);
}
}
string activeNamespaceCopy = activeNamespace;
if (string.IsNullOrEmpty(activeNamespaceCopy))
{
if (string.IsNullOrEmpty(xamlRootNamespace))
{
activeNamespaceCopy = rootNamespace;
}
else
{
activeNamespaceCopy = string.Format("{0}.{1}",
rootNamespace, xamlRootNamespace);
}
}
if (projectItem.ProjectItems != null
&& projectItem.ProjectItems.Count > 0)
{
string fullPath = projectItem.Properties.Item("FullPath").Value.ToString();
if (System.IO.Directory.Exists(fullPath))
{
string newNamespace = projectItem.Name.Replace(" ", string.Empty);
activeNamespaceCopy += "." + newNamespace;
}
}
string itemName = projectItem.Name;
if (generateXamlKeys && itemName.EndsWith(".xaml", true, CultureInfo.InvariantCulture))
{
/* Retrieve or create the namespace builder. */
NamespaceBuilder namespaceBuilder;
if (!namespaceBuilders.TryGetValue(activeNamespaceCopy, out namespaceBuilder))
{
namespaceBuilder = new NamespaceBuilder(activeNamespaceCopy, null, 0);
namespaceBuilders[activeNamespaceCopy] = namespaceBuilder;
}
string fileName = projectItem.get_FileNames(0);
string text = System.IO.File.ReadAllText(fileName);
MatchCollection matches = xClassRegex.Matches(text);
if (matches.Count > 0)
{
string xamlMetadataClassName = ConvertProjectItemNameToTypeOrMemberName(itemName.Substring(0, itemName.Length - 4));
var classComments = new List<string> {string.Format("/// <summary>Metadata for XAML {0}</summary>", itemName)};
XamlBuilder xamlBuiler = new XamlBuilder(xamlMetadataClassName, classComments, 1);
namespaceBuilder.AddChild(xamlBuiler);
foreach (Match match in matches)
{
Group keyGroup = match.Groups["KeyName"];
string keyName = keyGroup.Value;
var keyComments = new List<string> {string.Format("/// <summary>Represents x:Key=\"{0}\"/></summary>", keyName)};
xamlBuiler.AddChild(new XamlKeyBuilder(keyName, keyComments));
}
}
}
if (projectItem.ProjectItems != null)
{
foreach (ProjectItem childItem in projectItem.ProjectItems)
{
ProcessProjectItem(childItem, namespaceBuilders, activeNamespaceCopy);
}
}
}
Regex codeNameRegex = new Regex(@"\W", RegexOptions.Compiled);
string ConvertProjectItemNameToTypeOrMemberName(string name)
{
return codeNameRegex.Replace(name, string.Empty);
}
string FormatFullNameForClassName(string fullName)
{
//string projectName = containingProjectItem.Document.FullName;
//throw new Exception(projectName);
return fullName.Replace("/", ".");
}
int indent;
public void WalkElements(CodeElement codeElement, CodeElement parent,
BuilderBase parentContainer, Dictionary<string, NamespaceBuilder> namespaceBuilders)
{
indent++;
CodeElements codeElements;
if (parentContainer == null)
{
NamespaceBuilder builder;
string name = "global";
if (!namespaceBuilders.TryGetValue(name, out builder))
{
builder = new NamespaceBuilder(name, null, 0);
namespaceBuilders[name] = builder;
}
parentContainer = builder;
}
switch (codeElement.Kind)
{
/* Process namespaces. */
case vsCMElement.vsCMElementNamespace:
{
CodeNamespace codeNamespace = (CodeNamespace)codeElement;
string name = codeNamespace.FullName;
if (!string.IsNullOrEmpty(generatedNamespace)
&& name.EndsWith(generatedNamespace))
{
break;
}
NamespaceBuilder builder;
if (!namespaceBuilders.TryGetValue(name, out builder))
{
builder = new NamespaceBuilder(name, null, 0);
namespaceBuilders[name] = builder;
}
codeElements = codeNamespace.Members;
foreach (CodeElement element in codeElements)
{
WalkElements(element, codeElement, builder, namespaceBuilders);
}
break;
}
/* Process classes */
case vsCMElement.vsCMElementClass:
{
CodeClass codeClass = (CodeClass)codeElement;
string name = codeClass.Name;
if (!string.IsNullOrEmpty(generatedNamespace)
&& codeClass.FullName.EndsWith(generatedNamespace)
|| (name.StartsWith(generatedClassPrefix) && name.EndsWith(generatedClassSuffix)))
{
break;
}
/* If obfuscation mode and the class in internal,
then break as it's not supported. */
if (supportObfuscation && codeClass.Access == vsCMAccess.vsCMAccessPrivate)
{
break;
}
List<string> comments = new List<string>();
comments.Add(string.Format("/// <summary>Metadata for class <see cref=\"{0}\"/></summary>", codeClass.FullName));
BuilderBase builder;
if (!parentContainer.Children.TryGetValue(name, out builder))
{
builder = new ClassBuilder(name, comments, indent);
parentContainer.Children[name] = builder;
}
codeElements = codeClass.Members;
if (codeElements != null)
{
foreach (CodeElement ce in codeElements)
{
WalkElements(ce, codeElement, builder, namespaceBuilders);
}
}
break;
}
/* Process interfaces. */
case vsCMElement.vsCMElementInterface:
{
CodeInterface codeInterface = (CodeInterface)codeElement;
string name = codeInterface.Name;
if (name.StartsWith(generatedClassPrefix) && name.EndsWith(generatedClassSuffix))
{
break;
}
List<string> comments = new List<string>();
string commentName = FormatTypeNameForComment(codeInterface.FullName);
comments.Add(string.Format("/// <summary>Metadata for interface <see cref=\"{0}\"/></summary>", commentName));
InterfaceBuilder builder = new InterfaceBuilder(name, comments, indent);
parentContainer.AddChild(builder);
codeElements = codeInterface.Members;
if (codeElements != null)
{
foreach (CodeElement ce in codeElements)
{
WalkElements(ce, codeElement, builder, namespaceBuilders);
}
}
break;
}
/* Process methods */
case vsCMElement.vsCMElementFunction:
{
CodeFunction codeFunction = (CodeFunction)codeElement;
if (codeFunction.Name == parentContainer.Name
|| codeFunction.Name == "ToString"
|| codeFunction.Name == "Equals"
|| codeFunction.Name == "GetHashCode"
|| codeFunction.Name == "GetType"
|| codeFunction.Name == "MemberwiseClone"
|| codeFunction.Name == "ReferenceEquals"
|| codeFunction.Name.StartsWith("~")
|| codeFunction.Name.StartsWith("operator "))
{
break;
}
var parentBuilder = (ClassBuilder)parentContainer;
parentBuilder.AddMember(codeFunction);
break;
}
/* Process properties. */
case vsCMElement.vsCMElementProperty:
{
var codeProperty = (CodeProperty)codeElement;
if (codeProperty.Name != "this")
{
var parentBuilder = (ClassBuilder)parentContainer;
parentBuilder.AddMember(codeProperty);
}
break;
}
/* Process fields. */
case vsCMElement.vsCMElementVariable:
{
var codeVariable = (CodeVariable)codeElement;
var parentBuilder = (ClassBuilder)parentContainer;
parentBuilder.AddMember(codeVariable);
break;
}
}
indent--;
}
static string FormatTypeNameForComment(string typeName)
{
return typeName.Replace('<', '{').Replace('>', '}');
}
static readonly Regex replaceGenerics = new Regex("<.*>", RegexOptions.Compiled);
static string FormatNameForProperty(string name)
{
string result = name.Replace('.', '_');
result = replaceGenerics.Replace(result, "Generic");
return result;
}
/// <summary>
/// The base class for all project item representations.
/// </summary>
public abstract class BuilderBase
{
string name;
public string Name
{
get
{
return name;
}
}
List<string> comments;
public List<string> Comments
{
get
{
return comments;
}
}
int indent;
public int Indent
{
get
{
return indent;
}
set
{
indent = value;
}
}
protected BuilderBase(string name, List<string> comments)
{
this.name = name;
this.comments = comments;
}
Dictionary<string, BuilderBase> children = new Dictionary<string, BuilderBase>();
public Dictionary<string, BuilderBase> Children
{
get
{
return children;
}
}
public virtual void AddChild(BuilderBase obj)
{
if (children.ContainsKey(obj.Name))
{
return;
}
children.Add(obj.Name, obj);
}
public override int GetHashCode()
{
return Name != null ? Name.GetHashCode() : 0;
}
}
/// <summary>
/// Represents a namespace within a project and is a container
/// for classes.
/// </summary>
public sealed class NamespaceBuilder : BuilderBase
{
public NamespaceBuilder(string name, List<string> comments, int indent)
: base(name, comments)
{
}
public override string ToString()
{
string indentString = string.Empty.PadLeft(Indent);
StringBuilder sb = new StringBuilder();
bool global = Name == "global";
if (!global)
{
sb.Append("namespace ");
sb.Append(Name);
if (!string.IsNullOrEmpty(generatedNamespace))
{
sb.Append('.');
sb.AppendLine(generatedNamespace);
}
else
{
sb.AppendLine();
}
sb.AppendLine("{");
}
foreach (BuilderBase item in Children.Values)
{
item.Indent = Indent + tabSize;
sb.AppendLine(item.ToString());
}
if (!global)
{
sb.AppendLine("}");
}
return sb.ToString();
}
}
/// <summary>
/// Represents a class within a project.
/// </summary>
class XamlBuilder : BuilderBase
{
Dictionary<string, PropertyPathBuilder> propertyPaths = new Dictionary<string, PropertyPathBuilder>();
public XamlBuilder(string name, List<string> comments, int indent)
: base(name, comments)
{
}
public void AddXClassKeyName(string keyName)
{
if (Children.ContainsKey(keyName))
{
return; /* An overload. */
}
string formattedTypeName = FormatTypeNameForComment(keyName);
string comment = string.Format("/// <summary>Refers to Key <see cref=\"{0}\"/></summary>", formattedTypeName);
var comments = new List<string> { comment };
var builder = new XamlKeyBuilder(keyName, comments);
Children.Add(keyName, builder);
}
public override string ToString()
{
string indent1 = string.Empty.PadLeft(Indent);
string indent2 = string.Empty.PadLeft(Indent + tabSize);
StringBuilder sb = new StringBuilder();
/* Write comments. */
foreach (string line in Comments)
{
sb.Append(indent1);
sb.AppendLine(line);
}
sb.Append(indent1);
sb.Append("public");
sb.Append(" static class ");
sb.Append(generatedClassPrefix);
sb.Append(Name);
sb.Append(generatedXamlClassSuffix);
sb.AppendLine(generatedClassSuffix);
sb.Append(indent1);
sb.AppendLine("{");
//sb.Append(indent2);
//sb.AppendLine("public static class KeyNames");
//sb.Append(indent2);
//sb.AppendLine("{");
foreach (BuilderBase item in Children.Values)
{
item.Indent = Indent + 8;
sb.Append(item.ToString());
sb.AppendLine();
}
//sb.Append(indent2);
//sb.AppendLine("}");
sb.AppendLine();
foreach (PropertyPathBuilder item in propertyPaths.Values)
{
item.Indent = Indent + 4;
sb.Append(item.ToString());
sb.AppendLine();
}
sb.Append(indent1);
sb.AppendLine("}");
return sb.ToString();
}
}
public sealed class XamlKeyBuilder : MemberBuilder
{
public XamlKeyBuilder(string keyName, List<string> comments)
: base(keyName, comments)
{
}
protected override void AppendObfuscatedPropertyContent(StringBuilder sb)
{
sb.Append("NotSupportedYet");
}
public override string ToString()
{
string indent = string.Empty.PadLeft(Indent);
StringBuilder sb = new StringBuilder();
foreach (string line in Comments)
{
sb.Append(indent);
sb.AppendLine(line);
}
string cleanedName = FormatNameForProperty(Name);
if (!supportObfuscation)
{
sb.Append(indent);
sb.AppendFormat("public static string {0}Key {{ get {{ return \"{1}\"; }} }}",
cleanedName, cleanedName);
sb.AppendLine();
return sb.ToString();
}
string indent2 = string.Empty.PadLeft(Indent + tabSize);
string indent3 = string.Empty.PadLeft(Indent + 2 * tabSize);
sb.Append(indent);
sb.Append("public static string ");
sb.Append(cleanedName);
sb.AppendLine("Key");
sb.Append(indent);
sb.AppendLine("{");
sb.Append(indent2);
sb.AppendLine("get");
sb.Append(indent2);
sb.AppendLine("{");
AppendObfuscatedPropertyContent(sb);
sb.Append(indent2);
sb.AppendLine("}");
sb.Append(indent);
sb.AppendLine("}");
return sb.ToString();
}
}
/// <summary>
/// Represents a class within a project.
/// </summary>
class ClassBuilder : BuilderBase
{
Dictionary<string, PropertyPathBuilder> propertyPaths = new Dictionary<string, PropertyPathBuilder>();
public ClassBuilder(string name, List<string> comments, int indent)
: base(name, comments)
{
}
public void AddMember(CodeFunction codeMember)
{
string memberName = codeMember.Name;
if (Children.ContainsKey(memberName))
{
return; /* An overload. */
}
string formattedTypeName = FormatTypeNameForComment(codeMember.FullName);
string comment = string.Format("/// <summary>Refers to method <see cref=\"{0}\"/></summary>", formattedTypeName);
var comments = new List<string> { comment };
var builder = new MethodBuilder(codeMember, comments);
Children.Add(memberName, builder);
}
public void AddMember(CodeProperty codeMember)
{
string memberName = codeMember.Name;
if (Children.ContainsKey(memberName))
{
return; /* An overload. */
}
string formattedTypeName = FormatTypeNameForComment(codeMember.FullName);
string comment = string.Format("/// <summary>Refers to property <see cref=\"{0}\"/></summary>", formattedTypeName);
var comments = new List<string> { comment };
var builder = new PropertyBuilder(codeMember, comments);
Children.Add(memberName, builder);
if (supportXamlBinding)
{
var pathBuilder = new PropertyPathBuilder(codeMember, comments);
propertyPaths.Add(memberName, pathBuilder);
}
}
public void AddMember(CodeVariable codeMember)
{
string memberName = codeMember.Name;
if (Children.ContainsKey(memberName))
{
return; /* An overload. */
}
string formattedTypeName = FormatTypeNameForComment(codeMember.FullName);
string comment = string.Format("/// <summary>Refers to field <see cref=\"{0}\"/></summary>", formattedTypeName);
var comments = new List<string> { comment };
var builder = new FieldBuilder(codeMember, comments);
Children.Add(memberName, builder);
}
public override string ToString()
{
string indent1 = string.Empty.PadLeft(Indent);
string indent2 = string.Empty.PadLeft(Indent + tabSize);
StringBuilder sb = new StringBuilder();
/* Write comments. */
foreach (string line in Comments)
{
sb.Append(indent1);
sb.AppendLine(line);
}
sb.Append(indent1);
sb.Append(generatedClassAccessModifier);
sb.Append(" static class ");
sb.Append(generatedClassPrefix);
sb.Append(Name);
sb.AppendLine(generatedClassSuffix);
sb.Append(indent1);
sb.AppendLine("{");
sb.Append(indent2);
//sb.AppendLine("public static class MemberNames");
//sb.Append(indent2);
//sb.AppendLine("{");
foreach (BuilderBase item in Children.Values)
{
item.Indent = Indent + tabSize;
sb.Append(item.ToString());
sb.AppendLine();
}
//sb.Append(indent2);
//sb.AppendLine("}");
sb.AppendLine();
foreach (PropertyPathBuilder item in propertyPaths.Values)
{
item.Indent = Indent + 4;
sb.Append(item.ToString());
sb.AppendLine();
}
sb.Append(indent1);
sb.AppendLine("}");
return sb.ToString();
}
}
/// <summary>
/// Represents an interface within a project.
/// </summary>
sealed class InterfaceBuilder : ClassBuilder
{
public InterfaceBuilder(string name, List<string> comments, int indent)
: base(name, comments, indent)
{
}
}
/// <summary>
/// Represents a property, method, or field.
/// </summary>
public abstract class MemberBuilder : BuilderBase
{
public MemberBuilder(string name, List<string> comments)
: base(name, comments)
{
}
protected abstract void AppendObfuscatedPropertyContent(StringBuilder sb);
public override string ToString()
{
string indent = string.Empty.PadLeft(Indent);
string indent2 = string.Empty.PadLeft(Indent + tabSize);
StringBuilder sb = new StringBuilder();
foreach (string line in Comments)
{
sb.Append(indent);
sb.AppendLine(line);
}
sb.Append(indent);
string cleanedName = FormatNameForProperty(Name);
if (supportObfuscation)
{
sb.Append("public static string ");
sb.AppendLine(cleanedName);
sb.Append(indent);
sb.AppendLine("{");
sb.Append(indent2);
sb.AppendLine("get");
sb.Append(indent2);
sb.AppendLine("{");
/* Output property content. */
AppendObfuscatedPropertyContent(sb);
sb.AppendLine();
sb.Append(indent2);
sb.AppendLine("}");
sb.Append(indent);
sb.Append("}");
}
else
{
sb.AppendFormat("public const string {0} = \"{1}\";", cleanedName, Name);
}
sb.AppendLine();
return sb.ToString();
}
}
public sealed class MethodBuilder : MemberBuilder
{
CodeFunction codeMember;
public MethodBuilder(CodeFunction codeMember, List<string> comments)
: base(codeMember.Name, comments)
{
this.codeMember = codeMember;
}
protected override void AppendObfuscatedPropertyContent(StringBuilder sb)
{
string indent3 = string.Empty.PadLeft(Indent + 2 * tabSize);
string indent4 = string.Empty.PadLeft(Indent + 3 * tabSize);
string indent5 = string.Empty.PadLeft(Indent + 4 * tabSize);
bool usesGenerics = false;
foreach (CodeParameter codeParameter in codeMember.Parameters)
{
if (codeParameter.FullName.Contains("<"))
{
usesGenerics = true;
}
}
if (usesGenerics || codeMember.Access != vsCMAccess.vsCMAccessPublic
&& codeMember.Access != vsCMAccess.vsCMAccessProject)
{
sb.Append(indent3);
sb.AppendFormat("return \"{0}\";", Name);
return;
}
List<string> parameters = new List<string>(codeMember.Parameters.Count);
foreach (CodeParameter parameter in codeMember.Parameters)
{
parameters.Add(parameter.Type.AsFullName);
}
var returnType = codeMember.Type.AsFullName;
bool isAction = string.IsNullOrEmpty(returnType);
bool hasParameters = parameters.Count > 0;
sb.Append(indent3);
sb.Append("return ");
sb.Append("DanielVaughan.Metadata.ObfuscatedNameResolver.GetObfuscatedName(\"");
sb.Append(codeMember.FullName);
sb.AppendLine("\",");
sb.Append(indent4);
sb.AppendLine("x => {");
sb.Append(indent5);
if (isAction)
{
sb.Append("Expression<Action");
}
else
{
sb.Append("Expression<Func");
}
if (hasParameters || !isAction)
{
sb.Append('<');
}
StringBuilder parameterBuilder = new StringBuilder();
parameterBuilder.Append('(');
if (hasParameters)
{
int parametersCount = parameters.Count;
for (int i = 0; i < parametersCount; i++)
{
parameterBuilder.Append("p");
parameterBuilder.Append(i);
string parameter = parameters[i];
sb.Append(parameter);
if (i < parametersCount - 1)
{
sb.Append(',');
parameterBuilder.Append(',');
}
}
if (parametersCount > 0 && !string.IsNullOrEmpty(returnType))
{
sb.Append(',');
}
}
parameterBuilder.Append(')');
string signatureParameters = parameterBuilder.ToString();
if (!isAction) /* Returns a value, therefore always close Func type list. */
{
sb.Append(returnType);
sb.Append('>');
}
else if (hasParameters) /* void return type with parameter list. */
{
sb.Append('>');
}
string dictionaryKey = codeMember.FullName.Substring(0, codeMember.FullName.LastIndexOf('.'));
/* Static members don't require a default instance for the expression. */
if (codeMember.IsShared)
{
sb.Append("> expression = () => ");
sb.Append(dictionaryKey);
sb.Append(".");
}
else
{
sb.Append("> expression = ");
sb.Append(signatureParameters);
sb.Append(" => default(");
sb.Append(dictionaryKey);
sb.Append(").");
}
sb.Append(Name);
sb.Append(signatureParameters);
sb.AppendLine(";");
sb.Append(indent5);
sb.AppendLine("var body = (MethodCallExpression)expression.Body;");
sb.Append(indent5);
sb.AppendLine("return body.Method.Name;");
sb.Append(indent4);
sb.AppendLine("});");
}
}
public sealed class PropertyBuilder : MemberBuilder
{
readonly CodeProperty codeMember;
public PropertyBuilder(CodeProperty codeMember, List<string> comments)
: base(codeMember.Name, comments)
{
this.codeMember = codeMember;
}
protected override void AppendObfuscatedPropertyContent(StringBuilder sb)
{
string indent3 = string.Empty.PadLeft(Indent + 2 * tabSize);
string indent4 = string.Empty.PadLeft(Indent + 3 * tabSize);
string indent5 = string.Empty.PadLeft(Indent + 4 * tabSize);
if (codeMember.Access != vsCMAccess.vsCMAccessPublic
&& codeMember.Access != vsCMAccess.vsCMAccessProject)
{
sb.Append(indent3);
sb.AppendFormat("return \"{0}\";", Name);
return;
}
var returnType = codeMember.Type.AsFullName;
sb.Append(indent3);
sb.Append("return ");
sb.Append("DanielVaughan.Metadata.ObfuscatedNameResolver.GetObfuscatedName(\"");
sb.Append(codeMember.FullName);
sb.AppendLine("\",");
sb.Append(indent4);
sb.AppendLine("x => {");
sb.Append(indent5);
sb.Append("Expression<Func<");
sb.Append(returnType);
string dictionaryKey = codeMember.FullName.Substring(0, codeMember.FullName.LastIndexOf('.'));
/* Static members don't require a default instance for the expression. */
if (IsStatic(codeMember))
{
sb.Append(">> expression = () => ");
sb.Append(dictionaryKey);
sb.Append(".");
}
else
{
sb.Append(">> expression = () => default(");
sb.Append(dictionaryKey);
sb.Append(").");
}
sb.Append(Name);
sb.AppendLine(";");
sb.Append(indent5);
sb.AppendLine("var body = (MemberExpression)expression.Body;");
sb.Append(indent5);
sb.AppendLine("return body.Member.Name;");
sb.Append(indent4);
sb.AppendLine("});");
}
}
/// <summary>
/// Determines whether the specified code element is static.
/// See this article: http://msdn.microsoft.com/en-us/magazine/cc163757.aspx
/// </summary>
/// <param name="codeElement">The code element.</param>
/// <returns>
/// <c>true</c> if the specified code element is static; otherwise, <c>false</c>.
/// </returns>
static bool IsStatic(CodeProperty codeElement)
{
if (codeElement.Getter != null)
{
return codeElement.Getter.IsShared;
}
if (codeElement.Setter != null)
{
return codeElement.Setter.IsShared;
}
return false;
}
public sealed class FieldBuilder : MemberBuilder
{
CodeVariable codeMember;
public FieldBuilder(CodeVariable codeMember, List<string> comments)
: base(codeMember.Name, comments)
{
this.codeMember = codeMember;
}
protected override void AppendObfuscatedPropertyContent(StringBuilder sb)
{
string indent3 = string.Empty.PadLeft(Indent + 2 * tabSize);
if (codeMember.Access != vsCMAccess.vsCMAccessPublic
&& codeMember.Access != vsCMAccess.vsCMAccessProject)
{
/* Obfuscated field names that are not public or internal are not supported. */
sb.Append(indent3);
sb.AppendFormat("return \"{0}\";", Name);
return;
}
string indent4 = string.Empty.PadLeft(Indent + 3 * tabSize);
string indent5 = string.Empty.PadLeft(Indent + 4 * tabSize);
var returnType = codeMember.Type.AsFullName;
sb.Append(indent3);
sb.Append("return ");
sb.Append("DanielVaughan.Metadata.ObfuscatedNameResolver.GetObfuscatedName(\"");
sb.Append(codeMember.FullName);
sb.AppendLine("\",");
sb.Append(indent4);
sb.AppendLine("x => {");
sb.Append(indent5);
sb.Append("Expression<Func<");
sb.Append(returnType);
string dictionaryKey = codeMember.FullName.Substring(0, codeMember.FullName.LastIndexOf('.'));
/* Static members don't require a default instance for the expression. */
if (codeMember.IsShared)
{
sb.Append(">> expression = () => ");
sb.Append(dictionaryKey);
sb.Append(".");
}
else
{
sb.Append(">> expression = () => default(");
sb.Append(dictionaryKey);
sb.Append(").");
}
sb.Append(Name);
sb.AppendLine(";");
sb.Append(indent5);
sb.AppendLine("var body = (MemberExpression)expression.Body;");
sb.Append(indent5);
sb.AppendLine("return body.Member.Name;");
sb.Append(indent4);
sb.AppendLine("});");
}
}
/// <summary>
/// Represents a property, method, or field.
/// </summary>
public sealed class PropertyPathBuilder : MemberBuilder
{
CodeProperty codeMember;
public PropertyPathBuilder(CodeProperty codeMember, List<string> comments)
: base(codeMember.Name, comments)
{
this.codeMember = codeMember;
}
protected override void AppendObfuscatedPropertyContent(StringBuilder sb)
{
string indent3 = string.Empty.PadLeft(Indent + 2 * tabSize);
string indent4 = string.Empty.PadLeft(Indent + 3 * tabSize);
string indent5 = string.Empty.PadLeft(Indent + 4 * tabSize);
if (codeMember.Access != vsCMAccess.vsCMAccessPublic
&& codeMember.Access != vsCMAccess.vsCMAccessProject)
{
/* Obfuscated field names that are not public or internal are not supported. */
sb.Append(indent3);
sb.AppendFormat("return new PropertyPath(\"{1}\");",
Name, Name);
return;
}
var returnType = codeMember.Type.AsFullName;
sb.Append(indent3);
sb.Append("return new PropertyPath(");
sb.Append("DanielVaughan.Metadata.ObfuscatedNameResolver.GetObfuscatedName(\"");
sb.Append(codeMember.FullName);
sb.AppendLine("\",");
sb.Append(indent4);
sb.AppendLine("x => {");
sb.Append(indent5);
sb.Append("Expression<Func<");
sb.Append(returnType);
string dictionaryKey = codeMember.FullName.Substring(0, codeMember.FullName.LastIndexOf('.'));
/* Static members don't require a default instance for the expression. */
if (IsStatic(codeMember))
{
sb.Append(">> expression = () => ");
sb.Append(dictionaryKey);
sb.Append(".");
}
else
{
sb.Append(">> expression = () => default(");
sb.Append(dictionaryKey);
sb.Append(").");
}
sb.Append(Name);
sb.AppendLine(";");
sb.Append(indent5);
sb.AppendLine("var body = (MemberExpression)expression.Body;");
sb.Append(indent5);
sb.AppendLine("return body.Member.Name;");
sb.Append(indent4);
sb.AppendLine("}));");
}
public override string ToString()
{
string indent = string.Empty.PadLeft(Indent);
StringBuilder sb = new StringBuilder();
foreach (string line in Comments)
{
sb.Append(indent);
sb.AppendLine(line);
}
string cleanedName = FormatNameForProperty(Name);
if (!supportObfuscation)
{
sb.Append(indent);
sb.AppendFormat("public static PropertyPath {0}Path {{ get {{ return new PropertyPath(\"{1}\"); }} }}",
cleanedName, cleanedName);
sb.AppendLine();
return sb.ToString();
}
string indent2 = string.Empty.PadLeft(Indent + tabSize);
string indent3 = string.Empty.PadLeft(Indent + 2 * tabSize);
sb.Append(indent);
sb.Append("public static PropertyPath ");
sb.Append(cleanedName);
sb.AppendLine("Path");
sb.Append(indent);
sb.AppendLine("{");
sb.Append(indent2);
sb.AppendLine("get");
sb.Append(indent2);
sb.AppendLine("{");
AppendObfuscatedPropertyContent(sb);
sb.Append(indent2);
sb.AppendLine("}");
sb.Append(indent);
sb.AppendLine("}");
return sb.ToString();
}
}
#>