📄 codegenerator.cs
字号:
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision: 1317 $</version>
// </file>
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.NRefactory.Parser.AST;
namespace ICSharpCode.SharpDevelop.Refactoring
{
/// <summary>
/// Provides code generation facilities.
/// </summary>
public abstract class CodeGenerator
{
#region DOM -> NRefactory conversion (static)
public static TypeReference ConvertType(IReturnType returnType, ClassFinder context)
{
if (returnType == null) return TypeReference.Null;
if (returnType is NullReturnType) return TypeReference.Null;
TypeReference typeRef;
if (context != null && CanUseShortTypeName(returnType, context))
typeRef = new TypeReference(returnType.Name);
else
typeRef = new TypeReference(returnType.FullyQualifiedName);
while (returnType.ArrayDimensions > 0) {
int[] rank = typeRef.RankSpecifier ?? new int[0];
Array.Resize(ref rank, rank.Length + 1);
rank[rank.Length - 1] = returnType.ArrayDimensions - 1;
typeRef.RankSpecifier = rank;
returnType = returnType.ArrayElementType;
}
if (returnType.TypeArguments != null) {
foreach (IReturnType typeArgument in returnType.TypeArguments) {
typeRef.GenericTypes.Add(ConvertType(typeArgument, context));
}
}
return typeRef;
}
/// <summary>
/// Returns true if the short name of a type is valid in the given context.
/// Returns false for primitive types because they should be passed around using their
/// fully qualified names to allow the ambience or output visitor to use the intrinsic
/// type name.
/// </summary>
public static bool CanUseShortTypeName(IReturnType returnType, ClassFinder context)
{
switch (returnType.FullyQualifiedName) {
case "System.Void":
case "System.String":
case "System.Char":
case "System.Boolean":
case "System.Single":
case "System.Double":
case "System.Decimal":
case "System.Byte":
case "System.SByte":
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.UInt16":
case "System.UInt32":
case "System.UInt64":
return false;
}
int typeArgumentCount = (returnType.TypeArguments != null) ? returnType.TypeArguments.Count : 0;
IReturnType typeInTargetContext = context.SearchType(returnType.Name, typeArgumentCount);
return typeInTargetContext != null && typeInTargetContext.FullyQualifiedName == returnType.FullyQualifiedName;
}
public static Modifier ConvertModifier(ModifierEnum m)
{
return (Modifier)m;
}
public static ParamModifier ConvertModifier(ParameterModifiers m)
{
return (ParamModifier)m;
}
public static List<ParameterDeclarationExpression> ConvertParameters(IList<IParameter> parameters, ClassFinder targetContext)
{
List<ParameterDeclarationExpression> l = new List<ParameterDeclarationExpression>(parameters.Count);
foreach (IParameter p in parameters) {
ParameterDeclarationExpression pd = new ParameterDeclarationExpression(ConvertType(p.ReturnType, targetContext),
p.Name,
ConvertModifier(p.Modifiers));
pd.Attributes = ConvertAttributes(p.Attributes, targetContext);
l.Add(pd);
}
return l;
}
public static List<AttributeSection> ConvertAttributes(IList<IAttribute> attributes, ClassFinder targetContext)
{
AttributeSection sec = new AttributeSection(null, null);
foreach (IAttribute att in attributes) {
sec.Attributes.Add(new ICSharpCode.NRefactory.Parser.AST.Attribute(att.Name, null, null));
}
List<AttributeSection> resultList = new List<AttributeSection>(1);
if (sec.Attributes.Count > 0)
resultList.Add(sec);
return resultList;
}
public static List<TemplateDefinition> ConvertTemplates(IList<ITypeParameter> l, ClassFinder targetContext)
{
List<TemplateDefinition> o = new List<TemplateDefinition>(l.Count);
foreach (ITypeParameter p in l) {
TemplateDefinition td = new TemplateDefinition(p.Name, ConvertAttributes(p.Attributes, targetContext));
foreach (IReturnType rt in p.Constraints) {
td.Bases.Add(ConvertType(rt, targetContext));
}
o.Add(td);
}
return o;
}
public static BlockStatement CreateNotImplementedBlock()
{
BlockStatement b = new BlockStatement();
b.AddChild(new ThrowStatement(new ObjectCreateExpression(new TypeReference("NotImplementedException"), null)));
return b;
}
public static ParametrizedNode ConvertMember(IMethod m, ClassFinder targetContext)
{
if (m.IsConstructor) {
return new ConstructorDeclaration(m.Name,
ConvertModifier(m.Modifiers),
ConvertParameters(m.Parameters, targetContext),
ConvertAttributes(m.Attributes, targetContext));
} else {
MethodDeclaration md;
md = new MethodDeclaration(m.Name,
ConvertModifier(m.Modifiers),
ConvertType(m.ReturnType, targetContext),
ConvertParameters(m.Parameters, targetContext),
ConvertAttributes(m.Attributes, targetContext));
md.Templates = ConvertTemplates(m.TypeParameters, targetContext);
md.Body = CreateNotImplementedBlock();
return md;
}
}
public static AttributedNode ConvertMember(IMember m, ClassFinder targetContext)
{
if (m == null)
throw new ArgumentNullException("m");
if (m is IProperty)
return ConvertMember((IProperty)m, targetContext);
else if (m is IMethod)
return ConvertMember((IMethod)m, targetContext);
else if (m is IEvent)
return ConvertMember((IEvent)m, targetContext);
else if (m is IField)
return ConvertMember((IField)m, targetContext);
else
throw new ArgumentException("Unknown member: " + m.GetType().FullName);
}
public static AttributedNode ConvertMember(IProperty p, ClassFinder targetContext)
{
if (p.IsIndexer) {
IndexerDeclaration md;
md = new IndexerDeclaration(ConvertType(p.ReturnType, targetContext),
ConvertParameters(p.Parameters, targetContext),
ConvertModifier(p.Modifiers),
ConvertAttributes(p.Attributes, targetContext));
md.Parameters = ConvertParameters(p.Parameters, targetContext);
if (p.CanGet) md.GetRegion = new PropertyGetRegion(CreateNotImplementedBlock(), null);
if (p.CanSet) md.SetRegion = new PropertySetRegion(CreateNotImplementedBlock(), null);
return md;
} else {
PropertyDeclaration md;
md = new PropertyDeclaration(p.Name,
ConvertType(p.ReturnType, targetContext),
ConvertModifier(p.Modifiers),
ConvertAttributes(p.Attributes, targetContext));
md.Parameters = ConvertParameters(p.Parameters, targetContext);
if (p.CanGet) md.GetRegion = new PropertyGetRegion(CreateNotImplementedBlock(), null);
if (p.CanSet) md.SetRegion = new PropertySetRegion(CreateNotImplementedBlock(), null);
return md;
}
}
public static FieldDeclaration ConvertMember(IField f, ClassFinder targetContext)
{
TypeReference type = ConvertType(f.ReturnType, targetContext);
FieldDeclaration fd = new FieldDeclaration(ConvertAttributes(f.Attributes, targetContext),
type, ConvertModifier(f.Modifiers));
fd.Fields.Add(new VariableDeclaration(f.Name, null, type));
return fd;
}
public static EventDeclaration ConvertMember(IEvent e, ClassFinder targetContext)
{
return new EventDeclaration(ConvertType(e.ReturnType, targetContext),
e.Name,
ConvertModifier(e.Modifiers),
ConvertAttributes(e.Attributes, targetContext),
null);
}
#endregion
#region Code generation / insertion
public virtual void InsertCodeAfter(IMember member, IDocument document, params AbstractNode[] nodes)
{
if (member is IMethodOrProperty) {
InsertCodeAfter(((IMethodOrProperty)member).BodyRegion.EndLine, document,
GetIndentation(document, member.Region.BeginLine), nodes);
} else {
InsertCodeAfter(member.Region.EndLine, document,
GetIndentation(document, member.Region.BeginLine), nodes);
}
}
public virtual void InsertCodeAtEnd(DomRegion region, IDocument document, params AbstractNode[] nodes)
{
InsertCodeAfter(region.EndLine - 1, document,
GetIndentation(document, region.BeginLine) + '\t', nodes);
}
public virtual void InsertCodeInClass(IClass c, IDocument document, int targetLine, params AbstractNode[] nodes)
{
InsertCodeAfter(targetLine, document,
GetIndentation(document, c.Region.BeginLine) + '\t', false, nodes);
}
protected string GetIndentation(IDocument document, int line)
{
LineSegment lineSegment = document.GetLineSegment(line - 1);
string lineText = document.GetText(lineSegment.Offset, lineSegment.Length);
return lineText.Substring(0, lineText.Length - lineText.TrimStart().Length);
}
/// <summary>
/// Generates code for <paramref name="nodes"/> and inserts it into <paramref name="document"/>
/// after the line <paramref name="insertLine"/>.
/// </summary>
protected void InsertCodeAfter(int insertLine, IDocument document, string indentation, params AbstractNode[] nodes)
{
InsertCodeAfter(insertLine, document, indentation, true, nodes);
}
/// <summary>
/// Generates code for <paramref name="nodes"/> and inserts it into <paramref name="document"/>
/// after the line <paramref name="insertLine"/>.
/// </summary>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -