diff options
Diffstat (limited to 'main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring')
15 files changed, 2321 insertions, 1205 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerationService.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerationService.cs index 18cb6df5f9..a28f8a3750 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerationService.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerationService.cs @@ -1,62 +1,62 @@ +//// +//// CSharpCodeGenerationService.cs +//// +//// Author: +//// Mike Krüger <mkrueger@xamarin.com> +//// +//// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) +//// +//// Permission is hereby granted, free of charge, to any person obtaining a copy +//// of this software and associated documentation files (the "Software"), to deal +//// in the Software without restriction, including without limitation the rights +//// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//// copies of the Software, and to permit persons to whom the Software is +//// furnished to do so, subject to the following conditions: +//// +//// The above copyright notice and this permission notice shall be included in +//// all copies or substantial portions of the Software. +//// +//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +//// THE SOFTWARE. +//using System; +//using ICSharpCode.NRefactory.CSharp; +//using ICSharpCode.NRefactory.TypeSystem; +//using ICSharpCode.NRefactory.CSharp.Refactoring; +//using System.Linq; +//using Atk; +//using Gdk; // -// CSharpCodeGenerationService.cs +//namespace MonoDevelop.CSharp.Refactoring +//{ +// public class CSharpCodeGenerationService : DefaultCodeGenerationService +// { +// public override EntityDeclaration GenerateMemberImplementation (RefactoringContext context, IMember member, bool explicitImplementation) +// { +// var result = base.GenerateMemberImplementation (context, member, explicitImplementation); +// if (CSharpCodeGenerator.IsMonoTouchModelMember (member)) { +// var m = result as MethodDeclaration; +// if (m != null) { +// for (int i = CSharpCodeGenerator.MonoTouchComments.Length - 1; i >= 0; i--) { +// m.Body.InsertChildBefore (m.Body.Statements.First (), new Comment (CSharpCodeGenerator.MonoTouchComments [i]), Roles.Comment); +// } +// } // -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.CSharp.Refactoring; -using System.Linq; -using Atk; -using Gdk; - -namespace MonoDevelop.CSharp.Refactoring -{ - public class CSharpCodeGenerationService : DefaultCodeGenerationService - { - public override EntityDeclaration GenerateMemberImplementation (RefactoringContext context, IMember member, bool explicitImplementation) - { - var result = base.GenerateMemberImplementation (context, member, explicitImplementation); - if (CSharpCodeGenerator.IsMonoTouchModelMember (member)) { - var m = result as MethodDeclaration; - if (m != null) { - for (int i = CSharpCodeGenerator.MonoTouchComments.Length - 1; i >= 0; i--) { - m.Body.InsertChildBefore (m.Body.Statements.First (), new Comment (CSharpCodeGenerator.MonoTouchComments [i]), Roles.Comment); - } - } - - var p = result as PropertyDeclaration; - if (p != null) { - for (int i = CSharpCodeGenerator.MonoTouchComments.Length - 1; i >= 0; i--) { - if (!p.Getter.IsNull) - p.Getter.Body.InsertChildBefore (p.Getter.Body.Statements.First (), new Comment (CSharpCodeGenerator.MonoTouchComments [i]), Roles.Comment); - if (!p.Setter.IsNull) - p.Setter.Body.InsertChildBefore (p.Setter.Body.Statements.First (), new Comment (CSharpCodeGenerator.MonoTouchComments [i]), Roles.Comment); - } - } - } - return result; - } - } -} +// var p = result as PropertyDeclaration; +// if (p != null) { +// for (int i = CSharpCodeGenerator.MonoTouchComments.Length - 1; i >= 0; i--) { +// if (!p.Getter.IsNull) +// p.Getter.Body.InsertChildBefore (p.Getter.Body.Statements.First (), new Comment (CSharpCodeGenerator.MonoTouchComments [i]), Roles.Comment); +// if (!p.Setter.IsNull) +// p.Setter.Body.InsertChildBefore (p.Setter.Body.Statements.First (), new Comment (CSharpCodeGenerator.MonoTouchComments [i]), Roles.Comment); +// } +// } +// } +// return result; +// } +// } +//} diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerator.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerator.cs index 5f6cd6b4f5..6a2f2bdbc7 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerator.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpCodeGenerator.cs @@ -1,5 +1,5 @@ // -// CSharpCodecs +// CSharpCodeGenerator.cs // // Author: // Mike Krüger <mkrueger@novell.com> @@ -23,358 +23,405 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. + using System; -using ICSharpCode.NRefactory.CSharp; -using System.Text; -using MonoDevelop.CSharp.Formatting; -using System.Collections.Generic; using System.Linq; -using MonoDevelop.Ide; -using ICSharpCode.NRefactory.TypeSystem; using MonoDevelop.Ide.TypeSystem; -using ICSharpCode.NRefactory.CSharp.Resolver; -using ICSharpCode.NRefactory; -using Mono.TextEditor; -using ICSharpCode.NRefactory.CSharp.TypeSystem; -using MonoDevelop.Projects.Policies; -using Mono.Cecil; -using Mono.Cecil.Cil; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Ast; -using ICSharpCode.NRefactory.PatternMatching; -using ICSharpCode.NRefactory.TypeSystem.Implementation; - +using Microsoft.CodeAnalysis; +using System.Text; +using MonoDevelop.Ide.Editor; +using MonoDevelop.Ide; +using System.Collections.Generic; +using MonoDevelop.CSharp.Formatting; +using Microsoft.CodeAnalysis.Options; namespace MonoDevelop.CSharp.Refactoring { - class CSharpCodeGenerator : CodeGenerator + class CSharpCodeGenerator // : CodeGenerator { - static CSharpAmbience ambience = new CSharpAmbience (); - - CSharpFormattingPolicy policy; - - public MonoDevelop.CSharp.Formatting.CSharpFormattingPolicy Policy { - get { - if (policy == null) { - var types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (MonoDevelop.CSharp.Formatting.CSharpFormatter.MimeType); - if (PolicyParent != null) - policy = PolicyParent.Get<CSharpFormattingPolicy> (types); - if (policy == null) { - - policy = MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<CSharpFormattingPolicy> (types); - } - } - return this.policy; - } - } - - public override PolicyContainer PolicyParent { - get { - return base.PolicyParent; - } - set { - base.PolicyParent = value; - var types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (MonoDevelop.CSharp.Formatting.CSharpFormatter.MimeType); - policy = value.Get<CSharpFormattingPolicy> (types); - } - } - - +// static CSharpAmbience ambience = new CSharpAmbience (); +// +// CSharpFormattingPolicy policy; +// +// public MonoDevelop.CSharp.Formatting.CSharpFormattingPolicy Policy { +// get { +// if (policy == null) { +// var types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (MonoDevelop.CSharp.Formatting.CSharpFormatter.MimeType); +// if (PolicyParent != null) +// policy = PolicyParent.Get<CSharpFormattingPolicy> (types); +// if (policy == null) { +// +// policy = MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<CSharpFormattingPolicy> (types); +// } +// } +// return this.policy; +// } +// } +// +// public override PolicyContainer PolicyParent { +// get { +// return base.PolicyParent; +// } +// set { +// base.PolicyParent = value; +// var types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (MonoDevelop.CSharp.Formatting.CSharpFormatter.MimeType); +// policy = value.Get<CSharpFormattingPolicy> (types); +// } +// } +// +// class CodeGenerationOptions { public bool ExplicitDeclaration { get; set; } - public ITypeDefinition ImplementingType { get; set; } - public IUnresolvedTypeDefinition Part { get; set; } + public ITypeSymbol ImplementingType { get; set; } + public Location Part { get; set; } + + public TextEditor Editor { get; set; } + public DocumentContext DocumentContext { get; set; } - public MonoDevelop.Ide.Gui.Document Document { get; set; } + public bool CreateProtocolMember { get; set; } + + public SemanticModel SemanticModel { + get { + var model = DocumentContext.ParsedDocument.GetAst<SemanticModel> (); + return model; + } + } public string GetShortType (string ns, string name, int typeArguments = 0) { - if (Document == null || Document.ParsedDocument == null) + if (DocumentContext == null || Editor == null || SemanticModel == null || DocumentContext.ParsedDocument == null) return ns + "." + name; - var typeDef = new GetClassTypeReference (ns, name, typeArguments).Resolve (Document.Compilation.TypeResolveContext); - if (typeDef == null) + + var model = DocumentContext.ParsedDocument.GetAst<SemanticModel> (); + + if (model == null) return ns + "." + name; - var file = Document.ParsedDocument.ParsedFile as CSharpUnresolvedFile; - var csResolver = file.GetResolver (Document.Compilation, Document.Editor.Caret.Location); - var builder = new ICSharpCode.NRefactory.CSharp.Refactoring.TypeSystemAstBuilder (csResolver); - return OutputNode (Document, builder.ConvertType (typeDef)); + + var type = model.Compilation.GetTypeByMetadataName (ns + "." + name); + if (type == null) + return ns + "." + name; + + + return type.ToMinimalDisplayString (model, Editor.CaretOffset); } } - - public override string WrapInRegions (string regionName, string text) + + static void AppendLine (StringBuilder sb) { - StringBuilder result = new StringBuilder (); - AppendIndent (result); - result.Append ("#region "); - result.Append (regionName); - AppendLine (result); - result.Append (text); - AppendLine (result); - AppendIndent (result); - result.Append ("#endregion"); - return result.ToString (); + sb.AppendLine (); } - void AppendObsoleteAttribute (StringBuilder result, CodeGenerationOptions options, IEntity entity) - { - string reason; - if (!entity.IsObsolete (out reason)) - return; +// public override string WrapInRegions (string regionName, string text) +// { +// StringBuilder result = new StringBuilder (); +// AppendIndent (result); +// result.Append ("#region "); +// result.Append (regionName); +// AppendLine (result); +// result.Append (text); +// AppendLine (result); +// AppendIndent (result); +// result.Append ("#endregion"); +// return result.ToString (); +// } - var implementingType = options.Part; - var loc = implementingType.Region.End; - - var pf = implementingType.UnresolvedFile; - var file = pf as CSharpUnresolvedFile; + static void AppendObsoleteAttribute (StringBuilder result, CodeGenerationOptions options, ISymbol entity) + { + // TODO: Roslyn port +// string reason; +// if (!entity.IsObsolete (out reason)) +// return; +// +// var implementingType = options.Part; +// var loc = implementingType.Region.End; +// +// var pf = implementingType.UnresolvedFile; +// var file = pf as CSharpUnresolvedFile; +// +// result.Append ("["); +// var obsoleteRef = ReflectionHelper.ParseReflectionName ("System.ObsoleteAttribute"); +// var resolvedType = obsoleteRef.Resolve (options.ImplementingType.Compilation); +// var shortType = resolvedType.Kind != TypeKind.Unknown ? CreateShortType (options.ImplementingType.Compilation, file, loc, resolvedType) : null; +// var text = shortType != null ? shortType.ToString () : "System.Obsolete"; +// if (text.EndsWith ("Attribute", StringComparison.Ordinal)) +// text = text.Substring (0, text.Length - "Attribute".Length); +// result.Append (text); +// if (!string.IsNullOrEmpty (reason)) { +// result.Append (" (\""); +// result.Append (reason); +// result.Append ("\")"); +// } +// result.Append ("]"); +// result.AppendLine (); + } +// +// public override CodeGeneratorMemberResult CreateMemberImplementation (ITypeDefinition implementingType, +// IUnresolvedTypeDefinition part, +// IUnresolvedMember member, +// bool explicitDeclaration) +// { +// SetIndentTo (part); +// var options = new CodeGenerationOptions () { +// ExplicitDeclaration = explicitDeclaration, +// ImplementingType = implementingType, +// Part = part +// }; +// ITypeResolveContext ctx; +// +// var doc = IdeApp.Workbench.GetDocument (part.Region.FileName); +// ctx = new CSharpTypeResolveContext (implementingType.Compilation.MainAssembly, null, implementingType, null); +// options.Document = doc; +// +// if (member is IUnresolvedMethod) +// return GenerateCode ((IMethod) ((IUnresolvedMethod)member).CreateResolved (ctx), options); +// if (member is IUnresolvedProperty) +// return GenerateCode ((IProperty) ((IUnresolvedProperty)member).CreateResolved (ctx), options); +// if (member is IUnresolvedField) +// return GenerateCode ((IField) ((IUnresolvedField)member).CreateResolved (ctx), options); +// if (member is IUnresolvedEvent) +// return GenerateCode ((IEvent) ((IUnresolvedEvent)member).CreateResolved (ctx), options); +// throw new NotSupportedException ("member " + member + " is not supported."); +// } + + public static CodeGeneratorMemberResult CreateOverridenMemberImplementation (DocumentContext document, TextEditor editor, ITypeSymbol implementingType, Location part, ISymbol member, bool explicitDeclaration) + { + var options = new CodeGenerationOptions { + ExplicitDeclaration = explicitDeclaration, + ImplementingType = implementingType, + Part = part, + DocumentContext = document, + Editor = editor + }; - result.Append ("["); - var obsoleteRef = ReflectionHelper.ParseReflectionName ("System.ObsoleteAttribute"); - var resolvedType = obsoleteRef.Resolve (options.ImplementingType.Compilation); - var shortType = resolvedType.Kind != TypeKind.Unknown ? CreateShortType (options.ImplementingType.Compilation, file, loc, resolvedType) : null; - var text = shortType != null ? shortType.ToString () : "System.Obsolete"; - if (text.EndsWith ("Attribute", StringComparison.Ordinal)) - text = text.Substring (0, text.Length - "Attribute".Length); - result.Append (text); - if (!string.IsNullOrEmpty (reason)) { - result.Append (" (\""); - result.Append (reason); - result.Append ("\")"); - } - result.Append ("]"); - result.AppendLine (); + if (member is IMethodSymbol) + return GenerateCode ((IMethodSymbol)member, options); + if (member is IPropertySymbol) + return GenerateCode ((IPropertySymbol)member, options); + if (member is IFieldSymbol) + return GenerateCode ((IFieldSymbol)member, options); + if (member is IEventSymbol) + return GenerateCode ((IEventSymbol)member, options); + throw new NotSupportedException ("member " + member + " is not supported."); } - - public override CodeGeneratorMemberResult CreateMemberImplementation (ITypeDefinition implementingType, - IUnresolvedTypeDefinition part, - IUnresolvedMember member, - bool explicitDeclaration) + + public static CodeGeneratorMemberResult CreateProtocolMemberImplementation (DocumentContext document, TextEditor editor, ITypeSymbol implementingType, Location part, ISymbol member, bool explicitDeclaration) { - SetIndentTo (part); - var options = new CodeGenerationOptions () { + // SetIndentTo (part); + var options = new CodeGenerationOptions { ExplicitDeclaration = explicitDeclaration, ImplementingType = implementingType, - Part = part + Part = part, + DocumentContext = document, + Editor = editor, + CreateProtocolMember = true }; - ITypeResolveContext ctx; - - var doc = IdeApp.Workbench.GetDocument (part.Region.FileName); - ctx = new CSharpTypeResolveContext (implementingType.Compilation.MainAssembly, null, implementingType, null); - options.Document = doc; - if (member is IUnresolvedMethod) - return GenerateCode ((IMethod) ((IUnresolvedMethod)member).CreateResolved (ctx), options); - if (member is IUnresolvedProperty) - return GenerateCode ((IProperty) ((IUnresolvedProperty)member).CreateResolved (ctx), options); - if (member is IUnresolvedField) - return GenerateCode ((IField) ((IUnresolvedField)member).CreateResolved (ctx), options); - if (member is IUnresolvedEvent) - return GenerateCode ((IEvent) ((IUnresolvedEvent)member).CreateResolved (ctx), options); + if (member is IMethodSymbol) + return GenerateCode ((IMethodSymbol)member, options); + if (member is IPropertySymbol) + return GenerateCode ((IPropertySymbol)member, options); + if (member is IFieldSymbol) + return GenerateCode ((IFieldSymbol)member, options); + if (member is IEventSymbol) + return GenerateCode ((IEventSymbol)member, options); throw new NotSupportedException ("member " + member + " is not supported."); } - - public override CodeGeneratorMemberResult CreateMemberImplementation (ITypeDefinition implementingType, - IUnresolvedTypeDefinition part, - IMember member, - bool explicitDeclaration) + + public static CodeGeneratorMemberResult CreatePartialMemberImplementation (DocumentContext document, TextEditor editor, ITypeSymbol implementingType, Location part, ISymbol member, bool explicitDeclaration) { - SetIndentTo (part); - var options = new CodeGenerationOptions () { + var options = new CodeGenerationOptions { ExplicitDeclaration = explicitDeclaration, ImplementingType = implementingType, Part = part, - Document = IdeApp.Workbench.GetDocument (part.Region.FileName) + DocumentContext = document, + Editor = editor }; - if (member is IMethod) - return GenerateCode ((IMethod)member, options); - if (member is IProperty) - return GenerateCode ((IProperty)member, options); - if (member is IField) - return GenerateCode ((IField)member, options); - if (member is IEvent) - return GenerateCode ((IEvent)member, options); + + if (member is IMethodSymbol) + return GeneratePartialCode ((IMethodSymbol)member, options); throw new NotSupportedException ("member " + member + " is not supported."); } - - void AppendBraceStart (StringBuilder result, BraceStyle braceStyle) - { - switch (braceStyle) { - case BraceStyle.BannerStyle: - case BraceStyle.EndOfLine: - result.Append (" {"); - AppendLine (result); - break; - case BraceStyle.EndOfLineWithoutSpace: - result.Append ("{"); - AppendLine (result); - break; - case BraceStyle.NextLine: - AppendLine (result); - AppendIndent (result); - result.Append ("{"); - AppendLine (result); - break; - case BraceStyle.NextLineShifted: - AppendLine (result); - result.Append (GetIndent (IndentLevel + 1)); - result.Append ("{"); - AppendLine (result); - break; - case BraceStyle.NextLineShifted2: - AppendLine (result); - result.Append (GetIndent (IndentLevel + 1)); - result.Append ("{"); - AppendLine (result); - IndentLevel++; - break; - default: - goto case BraceStyle.NextLine; - } - IndentLevel++; - } - - void AppendBraceEnd (StringBuilder result, BraceStyle braceStyle) - { - switch (braceStyle) { - case BraceStyle.EndOfLineWithoutSpace: - case BraceStyle.NextLine: - case BraceStyle.EndOfLine: - IndentLevel --; - AppendIndent (result); - result.Append ("}"); - break; - case BraceStyle.BannerStyle: - case BraceStyle.NextLineShifted: - AppendIndent (result); - result.Append ("}"); - IndentLevel--; - break; - case BraceStyle.NextLineShifted2: - IndentLevel--; - AppendIndent (result); - result.Append ("}"); - IndentLevel--; - break; - default: - goto case BraceStyle.NextLine; - } - } - - void AppendIndent (StringBuilder result) - { - result.Append (GetIndent (IndentLevel)); - } - - void AppendReturnType (StringBuilder result, CodeGenerationOptions options, IType type) +// +// void AppendBraceStart (StringBuilder result, BraceStyle braceStyle) +// { +// switch (braceStyle) { +// case BraceStyle.BannerStyle: +// case BraceStyle.EndOfLine: +// result.Append (" {"); +// AppendLine (result); +// break; +// case BraceStyle.EndOfLineWithoutSpace: +// result.Append ("{"); +// AppendLine (result); +// break; +// case BraceStyle.NextLine: +// AppendLine (result); +// AppendIndent (result); +// result.Append ("{"); +// AppendLine (result); +// break; +// case BraceStyle.NextLineShifted: +// AppendLine (result); +// result.Append (GetIndent (IndentLevel + 1)); +// result.Append ("{"); +// AppendLine (result); +// break; +// case BraceStyle.NextLineShifted2: +// AppendLine (result); +// result.Append (GetIndent (IndentLevel + 1)); +// result.Append ("{"); +// AppendLine (result); +// IndentLevel++; +// break; +// default: +// goto case BraceStyle.NextLine; +// } +// IndentLevel++; +// } +// +// void AppendBraceEnd (StringBuilder result, BraceStyle braceStyle) +// { +// switch (braceStyle) { +// case BraceStyle.EndOfLineWithoutSpace: +// case BraceStyle.NextLine: +// case BraceStyle.EndOfLine: +// IndentLevel --; +// AppendIndent (result); +// result.Append ("}"); +// break; +// case BraceStyle.BannerStyle: +// case BraceStyle.NextLineShifted: +// AppendIndent (result); +// result.Append ("}"); +// IndentLevel--; +// break; +// case BraceStyle.NextLineShifted2: +// IndentLevel--; +// AppendIndent (result); +// result.Append ("}"); +// IndentLevel--; +// break; +// default: +// goto case BraceStyle.NextLine; +// } +// } +// +// void AppendIndent (StringBuilder result) +// { +// result.Append (GetIndent (IndentLevel)); +// } +// + static void AppendReturnType (StringBuilder result, CodeGenerationOptions options, ITypeSymbol type) { if (type == null) throw new ArgumentNullException ("type"); - var implementingType = options.Part; - var loc = implementingType.Region.End; - - var pf = implementingType.UnresolvedFile; - var file = pf as CSharpUnresolvedFile; - var resolved = type; - if (resolved.Kind == TypeKind.Unknown) { - result.Append (type.FullName); - return; - } - var def = type.GetDefinition (); - if (def != null) { - using (var stringWriter = new System.IO.StringWriter ()) { - var formatter = new TextWriterTokenWriter (stringWriter); - stringWriter.NewLine = EolMarker; - var visitor = new CSharpOutputVisitor (formatter, FormattingOptionsFactory.CreateMono ()); - var shortType = CreateShortType (def.Compilation, file, loc, resolved); - shortType.AcceptVisitor (visitor); - - var typeString = stringWriter.ToString (); - if (typeString.StartsWith ("global::")) - typeString = typeString.Substring ("global::".Length); - result.Append (typeString); - } - } else { - result.Append (new ICSharpCode.NRefactory.CSharp.CSharpAmbience ().ConvertType (type)); - } - } - - /* - void ResolveReturnTypes () - { - returnType = member.ReturnType; - foreach (IUsing u in unit.Usings) { - foreach (KeyValuePair<string, IReturnType> alias in u.Aliases) { - if (alias.Key == member.ReturnType.FullName) { - returnType = alias.Value; - return; - } - } - } - }*/ + result.Append (type.ToMinimalDisplayString (options.SemanticModel, options.Part.SourceSpan.Start)); - - CodeGeneratorMemberResult GenerateCode (IField field, CodeGenerationOptions options) +// var implementingType = options.Part; +// var loc = implementingType.Region.End; +// +// var pf = implementingType.UnresolvedFile; +// var file = pf as CSharpUnresolvedFile; +// var resolved = type; +// if (resolved.Kind == TypeKind.Unknown) { +// result.Append (type.FullName); +// return; +// } +// var def = type.GetDefinition (); +// if (def != null) { +// using (var stringWriter = new System.IO.StringWriter ()) { +// var formatter = new TextWriterTokenWriter (stringWriter); +// stringWriter.NewLine = EolMarker; +// var visitor = new CSharpOutputVisitor (formatter, FormattingOptionsFactory.CreateMono ()); +// var shortType = CreateShortType (def.Compilation, file, loc, resolved); +// shortType.AcceptVisitor (visitor); +// +// var typeString = stringWriter.ToString (); +// if (typeString.StartsWith ("global::")) +// typeString = typeString.Substring ("global::".Length); +// result.Append (typeString); +// } +// } else { +// result.Append (new ICSharpCode.NRefactory.CSharp.CSharpAmbience ().ConvertType (type)); +// } + } +// +// /* +// void ResolveReturnTypes () +// { +// returnType = member.ReturnType; +// foreach (IUsing u in unit.Usings) { +// foreach (KeyValuePair<string, IReturnType> alias in u.Aliases) { +// if (alias.Key == member.ReturnType.FullName) { +// returnType = alias.Value; +// return; +// } +// } +// } +// }*/ +// +// + static CodeGeneratorMemberResult GenerateCode (IFieldSymbol field, CodeGenerationOptions options) { StringBuilder result = new StringBuilder (); AppendIndent (result); AppendModifiers (result, options, field); result.Append (" "); - AppendReturnType (result, options, field.ReturnType); + AppendReturnType (result, options, field.Type); result.Append (" "); result.Append (CSharpAmbience.FilterName (field.Name)); result.Append (";"); return new CodeGeneratorMemberResult (result.ToString (), -1, -1); } + + static void AppendIndent (StringBuilder result) + { + + } - CodeGeneratorMemberResult GenerateCode (IEvent evt, CodeGenerationOptions options) + static CodeGeneratorMemberResult GenerateCode (IEventSymbol evt, CodeGenerationOptions options) { StringBuilder result = new StringBuilder (); AppendObsoleteAttribute (result, options, evt); AppendModifiers (result, options, evt); result.Append ("event "); - AppendReturnType (result, options, evt.ReturnType); + AppendReturnType (result, options, evt.Type); result.Append (" "); if (options.ExplicitDeclaration) { - result.Append (ambience.GetString (evt.DeclaringTypeDefinition, OutputFlags.IncludeGenerics)); + AppendReturnType (result, options, evt.ContainingType); result.Append ("."); } + result.Append (CSharpAmbience.FilterName (evt.Name)); if (options.ExplicitDeclaration) { - AppendBraceStart (result, Policy.EventBraceStyle); + result.Append ("{"); AppendIndent (result); - result.Append ("add"); - AppendBraceStart (result, Policy.EventAddBraceStyle); + result.Append ("add {"); AppendIndent (result); result.Append ("// TODO"); AppendLine (result); - AppendBraceEnd (result, Policy.EventAddBraceStyle); - + result.Append ("}"); + AppendIndent (result); - result.Append ("remove"); - AppendBraceStart (result, Policy.EventRemoveBraceStyle); + result.Append ("remove {"); AppendIndent (result); result.Append ("// TODO"); AppendLine (result); - - AppendBraceEnd (result, Policy.EventRemoveBraceStyle); - AppendBraceEnd (result, Policy.EventBraceStyle); + result.Append ("}}"); } else { result.Append (";"); } return new CodeGeneratorMemberResult (result.ToString ()); } - void AppendNotImplementedException (StringBuilder result, CodeGenerationOptions options, - out int bodyStartOffset, out int bodyEndOffset) + static void AppendNotImplementedException (StringBuilder result, CodeGenerationOptions options, out int bodyStartOffset, out int bodyEndOffset) { AppendIndent (result); bodyStartOffset = result.Length; result.Append ("throw new "); result.Append (options.GetShortType ("System", "NotImplementedException")); - // AppendReturnType (result, options.ImplementingType, options.Ctx.GetTypeDefinition (typeof (System.NotImplementedException))); - if (Policy.BeforeMethodCallParentheses) - result.Append (" "); result.Append ("();"); bodyEndOffset = result.Length; AppendLine (result); @@ -385,7 +432,7 @@ namespace MonoDevelop.CSharp.Refactoring " see http://docs.xamarin.com/guides/ios/application_fundamentals/delegates,_protocols,_and_events" }; - void AppendMonoTouchTodo (StringBuilder result, CodeGenerationOptions options, out int bodyStartOffset, out int bodyEndOffset) + static void AppendMonoTouchTodo (StringBuilder result, CodeGenerationOptions options, out int bodyStartOffset, out int bodyEndOffset) { AppendIndent (result); bodyStartOffset = result.Length; @@ -395,34 +442,31 @@ namespace MonoDevelop.CSharp.Refactoring } result.Append ("throw new "); result.Append (options.GetShortType ("System", "NotImplementedException")); - - if (Policy.BeforeMethodCallParentheses) - result.Append (" "); result.Append ("();"); bodyEndOffset = result.Length; AppendLine (result); } - CodeGeneratorMemberResult GenerateCode (IMethod method, CodeGenerationOptions options) + static CodeGeneratorMemberResult GenerateCode (IMethodSymbol method, CodeGenerationOptions options) { int bodyStartOffset = -1, bodyEndOffset = -1; - StringBuilder result = new StringBuilder (); + var result = new StringBuilder (); AppendObsoleteAttribute (result, options, method); AppendModifiers (result, options, method); - if (method.IsPartial) - result.Append ("partial "); + // if (method.IsPartial) + // result.Append ("partial "); AppendReturnType (result, options, method.ReturnType); result.Append (" "); if (options.ExplicitDeclaration) { - AppendReturnType (result, options, method.DeclaringType); + AppendReturnType (result, options, method.ContainingType); result.Append ("."); } result.Append (CSharpAmbience.FilterName (method.Name)); - if (method.TypeParameters.Count > 0) { + if (method.TypeParameters.Length > 0) { result.Append ("<"); - for (int i = 0; i < method.TypeParameters.Count; i++) { + for (int i = 0; i < method.TypeParameters.Length; i++) { if (i > 0) result.Append (", "); var p = method.TypeParameters [i]; @@ -430,86 +474,82 @@ namespace MonoDevelop.CSharp.Refactoring } result.Append (">"); } - if (Policy.BeforeMethodDeclarationParentheses) - result.Append (" "); result.Append ("("); - AppendParameterList (result, options, method.Parameters); + AppendParameterList (result, options, method.Parameters, true); result.Append (")"); - + var typeParameters = method.TypeParameters; - - // This should also check the types are in the correct mscorlib - Func<IType, bool> validBaseType = t => t.FullName != "System.Object" && t.FullName != "System.ValueType"; - bool isFromInterface = method.DeclaringType != null && method.DeclaringTypeDefinition.Kind == TypeKind.Interface; + // // This should also check the types are in the correct mscorlib + // Func<IType, bool> validBaseType = t => t.FullName != "System.Object" && t.FullName != "System.ValueType"; + // + // bool isFromInterface = method.DeclaringType != null && method.DeclaringTypeDefinition.Kind == TypeKind.Interface; + // + // if (!options.ExplicitDeclaration && isFromInterface && typeParameters.Any (p => p.HasDefaultConstructorConstraint || p.HasReferenceTypeConstraint || p.HasValueTypeConstraint || p.DirectBaseTypes.Any (validBaseType))) { + // result.Append (" where "); + // int typeParameterCount = 0; + // foreach (var p in typeParameters) { + // if (typeParameterCount != 0) + // result.Append (", "); + // + // typeParameterCount++; + // result.Append (CSharpAmbience.FilterName (p.Name)); + // result.Append (" : "); + // int constraintCount = 0; + // + // if (p.HasDefaultConstructorConstraint) { + // result.Append ("new ()"); + // constraintCount++; + // } + // + // if (p.HasValueTypeConstraint) { + // if (constraintCount != 0) + // result.Append (", "); + // result.Append ("struct"); + // constraintCount++; + // } + // + // if (p.HasReferenceTypeConstraint) { + // if (constraintCount != 0) + // result.Append (", "); + // result.Append ("class"); + // constraintCount++; + // } + // // bool hadInterfaces = false; + // foreach (var c in p.DirectBaseTypes.Where (validBaseType)) { + // if (constraintCount != 0) + // result.Append (", "); + // constraintCount++; + // AppendReturnType (result, options, c); + // // if (c.Kind == TypeKind.Interface) + // // hadInterfaces = true; + // } + // } + // } - if (!options.ExplicitDeclaration && isFromInterface && typeParameters.Any (p => p.HasDefaultConstructorConstraint || p.HasReferenceTypeConstraint || p.HasValueTypeConstraint || p.DirectBaseTypes.Any (validBaseType))) { - result.Append (" where "); - int typeParameterCount = 0; - foreach (var p in typeParameters) { - if (typeParameterCount != 0) - result.Append (", "); - - typeParameterCount++; - result.Append (CSharpAmbience.FilterName (p.Name)); - result.Append (" : "); - int constraintCount = 0; - - if (p.HasDefaultConstructorConstraint) { - result.Append ("new ()"); - constraintCount++; - } - - if (p.HasValueTypeConstraint) { - if (constraintCount != 0) - result.Append (", "); - result.Append ("struct"); - constraintCount++; - } - - if (p.HasReferenceTypeConstraint) { - if (constraintCount != 0) - result.Append (", "); - result.Append ("class"); - constraintCount++; - } - // bool hadInterfaces = false; - foreach (var c in p.DirectBaseTypes.Where (validBaseType)) { - if (constraintCount != 0) - result.Append (", "); - constraintCount++; - AppendReturnType (result, options, c); - // if (c.Kind == TypeKind.Interface) - // hadInterfaces = true; - } - } - } - - if (options.ImplementingType.Kind == TypeKind.Interface) { + if (options.ImplementingType.TypeKind == TypeKind.Interface) { result.Append (";"); } else { - AppendBraceStart (result, Policy.MethodBraceStyle); - if (method.Name == "ToString" && (method.Parameters == null || method.Parameters.Count == 0) && method.ReturnType != null/* && method.ReturnType.FullName == "System.String"*/) { + result.Append ("{"); + if (method.Name == "ToString" && method.Parameters.Length == 0 && method.ReturnType != null/* && method.ReturnType.FullName == "System.String"*/) { AppendIndent (result); bodyStartOffset = result.Length; result.Append ("return string.Format"); - if (Policy.BeforeMethodDeclarationParentheses) - result.Append (" "); result.Append ("(\"["); result.Append (options.ImplementingType.Name); - if (options.ImplementingType.Properties.Any ()) + if (options.ImplementingType.GetMembers ().OfType<IPropertySymbol> ().Any ()) result.Append (": "); int i = 0; - var properties = new List<IProperty> (); + var properties = new List<IPropertySymbol> (); - foreach (IProperty property in options.ImplementingType.Properties) { + foreach (var property in options.ImplementingType.GetMembers ().OfType<IPropertySymbol> ()) { if (properties.Any (p => p.Name == property.Name)) continue; properties.Add (property); } - foreach (IProperty property in properties) { - if (property.IsStatic || !property.IsPublic) + foreach (var property in properties) { + if (property.IsStatic || property.DeclaredAccessibility != Accessibility.Public) continue; if (i > 0) result.Append (", "); @@ -519,8 +559,8 @@ namespace MonoDevelop.CSharp.Refactoring result.Append ("}"); } result.Append ("]\""); - foreach (IProperty property in properties) { - if (property.IsStatic || !property.IsPublic) + foreach (var property in properties) { + if (property.IsStatic || property.DeclaredAccessibility != Accessibility.Public) continue; result.Append (", "); result.Append (property.Name); @@ -530,72 +570,60 @@ namespace MonoDevelop.CSharp.Refactoring AppendLine (result); } else if (IsMonoTouchModelMember (method)) { AppendMonoTouchTodo (result, options, out bodyStartOffset, out bodyEndOffset); - } else if (method.IsAbstract || !(method.IsVirtual || method.IsOverride) || method.DeclaringTypeDefinition.Kind == TypeKind.Interface) { + } else if (method.IsAbstract || !(method.IsVirtual || method.IsOverride) || method.ContainingType.TypeKind == TypeKind.Interface) { AppendNotImplementedException (result, options, out bodyStartOffset, out bodyEndOffset); } else { bool skipBody = false; // Analyze if the body consists just of a single throw instruction // See: Bug 1373 - overriding [Model] class methods shouldn't insert base.Methods // TODO: Extend this to user defined code. - try { - if (method.Region.FileName == null) { - var asm = AssemblyDefinition.ReadAssembly (method.ParentAssembly.UnresolvedAssembly.Location); - foreach (var type in asm.MainModule.Types) { - if (type.FullName != method.DeclaringType.FullName) - continue; - foreach (var m in type.Resolve ().Methods) { - if (m.HasBody && m.Name == method.Name) { - var context = new DecompilerContext (asm.MainModule); - - context.CurrentType = type; - - context.Settings = new DecompilerSettings () { - AnonymousMethods = true, - AutomaticEvents = true, - AutomaticProperties = true, - ForEachStatement = true, - LockStatement = true - }; - - var astBuilder = new AstBuilder (context); - astBuilder.AddMethod (m); - - astBuilder.RunTransformations (o => false); - - var visitor = new ThrowsExceptionVisitor (); - astBuilder.SyntaxTree.AcceptVisitor (visitor); - skipBody = visitor.Throws; - if (skipBody) - break; - } - } - if (skipBody) - break; - } - } - } catch (Exception) { - } + // try { + // if (method.Region.FileName == null) { + // var asm = AssemblyDefinition.ReadAssembly (method.ParentAssembly.UnresolvedAssembly.Location); + // foreach (var type in asm.MainModule.Types) { + // if (type.FullName != method.DeclaringType.FullName) + // continue; + // foreach (var m in type.Resolve ().Methods) { + // if (m.HasBody && m.Name == method.Name) { + // var context = new DecompilerContext (asm.MainModule); + // + // context.CurrentType = type; + // + // context.Settings = new DecompilerSettings () { + // AnonymousMethods = true, + // AutomaticEvents = true, + // AutomaticProperties = true, + // ForEachStatement = true, + // LockStatement = true + // }; + // + // var astBuilder = new AstBuilder (context); + // astBuilder.AddMethod (m); + // + // astBuilder.RunTransformations (o => false); + // + // var visitor = new ThrowsExceptionVisitor (); + // astBuilder.SyntaxTree.AcceptVisitor (visitor); + // skipBody = visitor.Throws; + // if (skipBody) + // break; + // } + // } + // if (skipBody) + // break; + // } + // } + // } catch (Exception) { + // } AppendIndent (result); bodyStartOffset = result.Length; if (!skipBody) { - if (method.ReturnType.ReflectionName != typeof(void).FullName) + if (method.ReturnType.SpecialType != SpecialType.System_Void) result.Append ("return "); result.Append ("base."); result.Append (CSharpAmbience.FilterName (method.Name)); - if (Policy.BeforeMethodCallParentheses) - result.Append (" "); result.Append ("("); - for (int i = 0; i < method.Parameters.Count; i++) { - if (i > 0) - result.Append (", "); - - var p = method.Parameters [i]; - if (p.IsOut) - result.Append ("out "); - if (p.IsRef) - result.Append ("ref "); - result.Append (CSharpAmbience.FilterName (p.Name)); - } + AppendParameterList (result, options, method.Parameters, false); result.Append (");"); } else { result.Append ("throw new System.NotImplementedException ();"); @@ -603,114 +631,141 @@ namespace MonoDevelop.CSharp.Refactoring bodyEndOffset = result.Length; AppendLine (result); } - AppendBraceEnd (result, Policy.MethodBraceStyle); + result.Append ("}"); } return new CodeGeneratorMemberResult (result.ToString (), bodyStartOffset, bodyEndOffset); } - - class ThrowsExceptionVisitor : DepthFirstAstVisitor + + + static CodeGeneratorMemberResult GeneratePartialCode (IMethodSymbol method, CodeGenerationOptions options) { - public bool Throws = false; - - public override void VisitBlockStatement (BlockStatement blockStatement) - { - if (blockStatement.Statements.Count == 1 && blockStatement.Statements.First () is ThrowStatement) - Throws = true; + int bodyStartOffset = -1, bodyEndOffset = -1; + var result = new StringBuilder (); + AppendObsoleteAttribute (result, options, method); + result.Append ("partial "); + AppendReturnType (result, options, method.ReturnType); + result.Append (" "); + if (options.ExplicitDeclaration) { + AppendReturnType (result, options, method.ContainingType); + result.Append ("."); } + + result.Append (CSharpAmbience.FilterName (method.Name)); + if (method.TypeParameters.Length > 0) { + result.Append ("<"); + for (int i = 0; i < method.TypeParameters.Length; i++) { + if (i > 0) + result.Append (", "); + var p = method.TypeParameters [i]; + result.Append (CSharpAmbience.FilterName (p.Name)); + } + result.Append (">"); + } + result.Append ("("); + AppendParameterList (result, options, method.Parameters, true); + result.Append (")"); + + var typeParameters = method.TypeParameters; + result.AppendLine ("{"); + bodyStartOffset = result.Length; + AppendLine (result); + bodyEndOffset = result.Length; + result.AppendLine ("}"); + return new CodeGeneratorMemberResult (result.ToString (), bodyStartOffset, bodyEndOffset); } - - void AppendParameterList (StringBuilder result, CodeGenerationOptions options, IList<IParameter> parameters) + +// class ThrowsExceptionVisitor : DepthFirstAstVisitor +// { +// public bool Throws = false; +// +// public override void VisitBlockStatement (BlockStatement blockStatement) +// { +// if (blockStatement.Statements.Count == 1 && blockStatement.Statements.First () is ThrowStatement) +// Throws = true; +// } +// } + + static void AppendParameterList (StringBuilder result, CodeGenerationOptions options, IList<IParameterSymbol> parameters, bool asParameterList) { for (int i = 0; i < parameters.Count; i++) { if (i > 0) result.Append (", "); var p = parameters[i]; - if (p.IsOut) - result.Append ("out "); - if (p.IsRef) - result.Append ("ref "); - if (p.IsParams) - result.Append ("params "); - AppendReturnType (result, options, p.Type); - result.Append (" "); + if (asParameterList) { + if (p.RefKind == RefKind.Out) + result.Append ("out "); + if (p.RefKind == RefKind.Ref) + result.Append ("ref "); + if (p.IsParams) + result.Append ("params "); + AppendReturnType (result, options, p.Type); + result.Append (" "); + } result.Append (CSharpAmbience.FilterName (p.Name)); - if (p.ConstantValue != null) { + if (p.HasExplicitDefaultValue) { result.Append (" = "); - if (p.Type.Kind == TypeKind.Enum) { - bool found = false; - foreach (var literal in GetEnumLiterals(p.Type)) { - if (literal.ConstantValue.Equals (p.ConstantValue)) { - AppendReturnType (result, options, p.Type); - result.Append ("."+ literal.Name); - found = true; - break; - } - } - if (!found) { + if (p.ExplicitDefaultValue is Enum) { + var name = Enum.GetName (p.ExplicitDefaultValue.GetType (), p.ExplicitDefaultValue); + if (name != null) + { + AppendReturnType (result, options, p.Type); + result.Append ("."+ name); + } else { result.Append ("("); AppendReturnType (result, options, p.Type); - result.Append (")" + p.ConstantValue); + result.Append (")" + p.ExplicitDefaultValue); } - } else if (p.ConstantValue is char) { - result.Append ("'" + p.ConstantValue + "'"); - } else if (p.ConstantValue is string) { - result.Append ("\"" + CSharpTextEditorIndentation.ConvertToStringLiteral ((string)p.ConstantValue) + "\""); - } else if (p.ConstantValue is bool) { - result.Append ((bool)p.ConstantValue ? "true" : "false"); + } else if (p.ExplicitDefaultValue is char) { + result.Append ("'" + p.ExplicitDefaultValue + "'"); + } else if (p.ExplicitDefaultValue is string) { + result.Append ("\"" + CSharpTextEditorIndentation.ConvertToStringLiteral ((string)p.ExplicitDefaultValue) + "\""); + } else if (p.ExplicitDefaultValue is bool) { + result.Append ((bool)p.ExplicitDefaultValue ? "true" : "false"); } else { - result.Append (p.ConstantValue); + result.Append (p.ExplicitDefaultValue); } } } } - public IEnumerable<IField> GetEnumLiterals(IType type) + public static IEnumerable<string> GetEnumLiterals(Type type) { - if (type.Kind != TypeKind.Enum) - throw new ArgumentException ("Type is no enum."); - foreach (var field in type.GetFields (f => f.IsConst && f.IsPublic)) - yield return field; + return Enum.GetNames (type); } - static string GetModifiers (ITypeDefinition implementingType, IUnresolvedTypeDefinition implementingPart, IMember member) + static string GetModifiers (ITypeSymbol implementingType, Location implementingPart, ISymbol member) { StringBuilder result = new StringBuilder (); - if (member.IsPublic || (member.DeclaringType != null && member.DeclaringTypeDefinition.Kind == TypeKind.Interface)) { + if (member.DeclaredAccessibility == Accessibility.Public || (member.ContainingType != null && member.ContainingType.TypeKind == TypeKind.Interface)) { result.Append ("public "); - } else if (member.IsProtectedOrInternal) { - if (IdeApp.Workbench.ActiveDocument != null && member.DeclaringTypeDefinition.ParentAssembly != implementingType.ParentAssembly) { + } else if (member.DeclaredAccessibility == Accessibility.ProtectedOrInternal) { + if (IdeApp.Workbench.ActiveDocument != null && member.ContainingAssembly != implementingType.ContainingAssembly) { result.Append ("protected "); } else { result.Append ("internal protected "); } - } else if (member.IsProtectedAndInternal) { - if (IdeApp.Workbench.ActiveDocument != null && member.DeclaringTypeDefinition.ParentAssembly != implementingType.ParentAssembly) { - result.Append ("protected "); - } else { - result.Append ("protected internal "); - } - } else if (member.IsProtected) { + } else if (member.DeclaredAccessibility == Accessibility.Protected) { result.Append ("protected "); - } else if (member.IsInternal) { + } else if (member.DeclaredAccessibility == Accessibility.Internal) { result.Append ("internal "); } - + if (member.IsStatic) result.Append ("static "); - + return result.ToString (); } - void AppendModifiers (StringBuilder result, CodeGenerationOptions options, IMember member) + static void AppendModifiers (StringBuilder result, CodeGenerationOptions options, ISymbol member) { - AppendIndent (result); - if (options.ExplicitDeclaration || options.ImplementingType.Kind == TypeKind.Interface) - return; + //AppendIndent (result); + //if (options.ExplicitDeclaration || options.ImplementingType.Kind == TypeKind.Interface) + // return; result.Append (GetModifiers (options.ImplementingType, options.Part, member)); bool isFromInterface = false; - if (member.DeclaringType != null && member.DeclaringTypeDefinition.Kind == TypeKind.Interface) { + if (member.ContainingType != null && member.ContainingType.TypeKind == TypeKind.Interface) { isFromInterface = true; // TODO: Type system conversion. // if (options.ImplementingType != null) { @@ -724,51 +779,58 @@ namespace MonoDevelop.CSharp.Refactoring // } // } } + if (member is IMethodSymbol) { + var method = (IMethodSymbol)member; + if (!options.CreateProtocolMember) + result.Append ("override "); + if (method.IsAsync) + result.Append ("async "); + } - if (!isFromInterface && member.IsOverridable) - result.Append ("override "); - if (member is IMethod && ((IMethod)member).IsAsync) - result.Append ("async "); + if (member is IPropertySymbol) { + if (!options.CreateProtocolMember) + result.Append ("override "); + } } - CodeGeneratorMemberResult GenerateCode (IProperty property, CodeGenerationOptions options) + static CodeGeneratorMemberResult GenerateCode (IPropertySymbol property, CodeGenerationOptions options) { var regions = new List<CodeGeneratorBodyRegion> (); var result = new StringBuilder (); AppendObsoleteAttribute (result, options, property); AppendModifiers (result, options, property); - AppendReturnType (result, options, property.ReturnType); + AppendReturnType (result, options, property.Type); result.Append (" "); if (property.IsIndexer) { result.Append ("this["); - AppendParameterList (result, options, property.Parameters); + AppendParameterList (result, options, property.Parameters, true); result.Append ("]"); } else { - if (options.ExplicitDeclaration) { - result.Append (ambience.GetString (property.DeclaringType, OutputFlags.IncludeGenerics)); - result.Append ("."); - } +// if (options.ExplicitDeclaration) { +// result.Append (ambience.GetString (property.DeclaringType, OutputFlags.IncludeGenerics)); +// result.Append ("."); +// } result.Append (CSharpAmbience.FilterName (property.Name)); } - AppendBraceStart (result, Policy.PropertyBraceStyle); - if (property.CanGet) { + result.AppendLine (" {"); + if (property.GetMethod != null) { int bodyStartOffset, bodyEndOffset; AppendIndent (result); result.Append ("get"); - if (options.ImplementingType.Kind == TypeKind.Interface) { + if (options.ImplementingType.TypeKind == TypeKind.Interface) { result.AppendLine (";"); } else { - AppendBraceStart (result, Policy.PropertyGetBraceStyle); + result.AppendLine (" {"); if (IsMonoTouchModelMember (property)) { AppendMonoTouchTodo (result, options, out bodyStartOffset, out bodyEndOffset); - } else if (property.IsAbstract || property.DeclaringTypeDefinition.Kind == TypeKind.Interface) { + } else if (property.IsAbstract || property.ContainingType.TypeKind == TypeKind.Interface) { AppendNotImplementedException (result, options, out bodyStartOffset, out bodyEndOffset); } else { AppendIndent (result); bodyStartOffset = result.Length; - if (property.SymbolKind == SymbolKind.Indexer) { + if (property.IsIndexer) { result.Append ("return base["); - if (property.Parameters.Count > 0) + if (property.Parameters.Length > 0) result.Append (CSharpAmbience.FilterName (property.Parameters.First ().Name)); result.Append ("];"); } else { @@ -779,30 +841,30 @@ namespace MonoDevelop.CSharp.Refactoring bodyEndOffset = result.Length; AppendLine (result); } - AppendBraceEnd (result, Policy.PropertyGetBraceStyle); + result.Append ("}"); AppendLine (result); regions.Add (new CodeGeneratorBodyRegion (bodyStartOffset, bodyEndOffset)); } } - if (property.CanSet) { + if (property.SetMethod != null) { int bodyStartOffset, bodyEndOffset; AppendIndent (result); result.Append ("set"); - if (options.ImplementingType.Kind == TypeKind.Interface) { + if (options.ImplementingType.TypeKind == TypeKind.Interface) { result.AppendLine (";"); } else { - AppendBraceStart (result, Policy.PropertyGetBraceStyle); + result.AppendLine (" {"); if (IsMonoTouchModelMember (property)) { AppendMonoTouchTodo (result, options, out bodyStartOffset, out bodyEndOffset); - } else if (property.IsAbstract || property.DeclaringTypeDefinition.Kind == TypeKind.Interface) { + } else if (property.IsAbstract || property.ContainingType.TypeKind == TypeKind.Interface) { AppendNotImplementedException (result, options, out bodyStartOffset, out bodyEndOffset); } else { AppendIndent (result); bodyStartOffset = result.Length; - if (property.SymbolKind == SymbolKind.Indexer) { + if (property.IsIndexer) { result.Append ("base["); - if (property.Parameters.Count > 0) + if (property.Parameters.Length > 0) result.Append (CSharpAmbience.FilterName (property.Parameters.First ().Name)); result.Append ("] = value;"); } else { @@ -813,241 +875,126 @@ namespace MonoDevelop.CSharp.Refactoring bodyEndOffset = result.Length; AppendLine (result); } - AppendBraceEnd (result, Policy.PropertyGetBraceStyle); + result.Append ("}"); AppendLine (result); regions.Add (new CodeGeneratorBodyRegion (bodyStartOffset, bodyEndOffset)); } } - AppendBraceEnd (result, Policy.PropertyBraceStyle); + result.Append ("}"); return new CodeGeneratorMemberResult (result.ToString (), regions); } - - internal static bool IsMonoTouchModelMember (IMember member) + + internal static bool IsMonoTouchModelMember (ISymbol member) { - if (member == null || member.DeclaringType == null) + if (member == null || member.ContainingType == null) return false; - return member.DeclaringTypeDefinition.Attributes.Any (attr => attr.AttributeType != null && attr.AttributeType.ReflectionName == "MonoTouch.Foundation.ModelAttribute"); - } - - public override string CreateFieldEncapsulation (IUnresolvedTypeDefinition implementingType, IField field, string propertyName, Accessibility modifiers, bool readOnly) - { - SetIndentTo (implementingType); - StringBuilder result = new StringBuilder (); - AppendIndent (result); - -// if (modifiers != MonoDevelop.Projects.Dom.Modifiers.None) { -// switch (modifiers) { -// } -// result.Append (ambience.GetString (modifiers)); -// result.Append (" "); + return member.ContainingType.GetAttributes().Any (attr => attr.AttributeClass.MetadataName == "MonoTouch.Foundation.ModelAttribute"); + } + +//// public override string CreateFieldEncapsulation (IUnresolvedTypeDefinition implementingType, IField field, string propertyName, Accessibility modifiers, bool readOnly) +//// { +//// SetIndentTo (implementingType); +//// StringBuilder result = new StringBuilder (); +//// AppendIndent (result); +//// +////// if (modifiers != MonoDevelop.Projects.Dom.Modifiers.None) { +////// switch (modifiers) { +////// } +////// result.Append (ambience.GetString (modifiers)); +////// result.Append (" "); +////// } +//// var options = new CodeGenerationOptions () { +//// ImplementingType = field.DeclaringTypeDefinition, +//// Part = implementingType +//// }; +//// result.Append ("public "); +//// AppendReturnType (result, options, field.ReturnType); +//// result.Append (" "); +//// result.Append (propertyName); +//// AppendBraceStart (result, Policy.PropertyBraceStyle); +//// AppendIndent (result); +//// +//// result.Append ("get"); +//// AppendBraceStart (result, Policy.PropertyGetBraceStyle); +//// AppendIndent (result); +//// result.Append ("return this."); +//// result.Append (CSharpAmbience.FilterName (field.Name)); +//// result.Append (";"); +//// AppendLine (result); +//// AppendBraceEnd (result, Policy.PropertyGetBraceStyle); +//// AppendLine (result); +//// +//// if (!readOnly) { +//// AppendIndent (result); +//// result.Append ("set"); +//// AppendBraceStart (result, Policy.PropertyGetBraceStyle); +//// AppendIndent (result); +//// result.Append (CSharpAmbience.FilterName (field.Name)); +//// result.Append (" = value;"); +//// AppendLine (result); +//// AppendBraceEnd (result, Policy.PropertyGetBraceStyle); +//// AppendLine (result); +//// } +//// +//// AppendBraceEnd (result, Policy.PropertyBraceStyle); +//// return result.ToString (); +//// } +// +// int CountBlankLines (IReadonlyTextDocument doc, int startLine) +// { +// int result = 0; +// IDocumentLine line; +// while ((line = doc.GetLine (startLine + result)) != null && doc.GetLineIndent (line).Length == line.Length) { +// result++; // } - var options = new CodeGenerationOptions () { - ImplementingType = field.DeclaringTypeDefinition, - Part = implementingType - }; - result.Append ("public "); - AppendReturnType (result, options, field.ReturnType); - result.Append (" "); - result.Append (propertyName); - AppendBraceStart (result, Policy.PropertyBraceStyle); - AppendIndent (result); - - result.Append ("get"); - AppendBraceStart (result, Policy.PropertyGetBraceStyle); - AppendIndent (result); - result.Append ("return this."); - result.Append (CSharpAmbience.FilterName (field.Name)); - result.Append (";"); - AppendLine (result); - AppendBraceEnd (result, Policy.PropertyGetBraceStyle); - AppendLine (result); - - if (!readOnly) { - AppendIndent (result); - result.Append ("set"); - AppendBraceStart (result, Policy.PropertyGetBraceStyle); - AppendIndent (result); - result.Append (CSharpAmbience.FilterName (field.Name)); - result.Append (" = value;"); - AppendLine (result); - AppendBraceEnd (result, Policy.PropertyGetBraceStyle); - AppendLine (result); - } - - AppendBraceEnd (result, Policy.PropertyBraceStyle); - return result.ToString (); - } - - int CountBlankLines (MonoDevelop.Ide.Gui.Document doc, int startLine) - { - int result = 0; - DocumentLine line; - while ((line = doc.Editor.GetLine (startLine + result)) != null && doc.Editor.GetLineIndent (line).Length == line.Length) { - result++; - } - - return result; - } - - static bool InsertUsingAfter (AstNode node) - { - return node is NewLineNode && IsCommentOrUsing (node.GetNextSibling (s => !(s is NewLineNode))) || - IsCommentOrUsing (node) || (node is PreProcessorDirective); - } +// +// return result; +// } +// +// static bool InsertUsingAfter (AstNode node) +// { +// return node is NewLineNode && IsCommentOrUsing (node.GetNextSibling (s => !(s is NewLineNode))) || +// IsCommentOrUsing (node) || (node is PreProcessorDirective); +// } +// +// static bool IsCommentOrUsing (AstNode node) +// { +// return node is ICSharpCode.NRefactory.CSharp.Comment || +// node is UsingDeclaration || +// node is UsingAliasDeclaration; +// } +// - static bool IsCommentOrUsing (AstNode node) - { - return node is ICSharpCode.NRefactory.CSharp.Comment || - node is UsingDeclaration || - node is UsingAliasDeclaration; - } - - static AstNode SearchUsingInsertionPoint (AstNode parent) - { - var node = parent.FirstChild; - while (true) { - var next = node.NextSibling; - if (!InsertUsingAfter (next)) - break; - node = next; - } - return node; - } - - public override void AddGlobalNamespaceImport (MonoDevelop.Ide.Gui.Document doc, string nsName) - { - var parsedDocument = doc.ParsedDocument; - var unit = parsedDocument.GetAst<SyntaxTree> (); - if (unit == null) - return; - - var policy = doc.Project != null ? doc.Project.Policies.Get <CSharpFormattingPolicy> () : null; - if (policy == null) - policy = Policy; - - var node = SearchUsingInsertionPoint (unit); - - var text = new StringBuilder (); - int lines = 0; - - if (InsertUsingAfter (node)) { - lines = policy.BlankLinesBeforeUsings + 1; - while (lines-- > 0) { - text.Append (doc.Editor.EolMarker); - } - } - - text.Append ("using "); - text.Append (nsName); - text.Append (";"); - - int offset = 0; - if (node != null) { - var loc = InsertUsingAfter (node) ? node.EndLocation : node.StartLocation; - offset = Math.Max (0, doc.Editor.LocationToOffset (loc)); - } - - lines = policy.BlankLinesAfterUsings; - lines -= CountBlankLines (doc, doc.Editor.OffsetToLineNumber (offset) + 1); - if (lines > 0) - text.Append (doc.Editor.EolMarker); - while (lines-- > 0) { - text.Append (doc.Editor.EolMarker); - } - doc.Editor.Insert (offset, text.ToString ()); - doc.Editor.Document.CommitUpdateAll (); - } - - public override void AddLocalNamespaceImport (MonoDevelop.Ide.Gui.Document doc, string nsName, TextLocation caretLocation) - { - var parsedDocument = doc.ParsedDocument; - var unit = parsedDocument.GetAst<SyntaxTree> (); - if (unit == null) - return; - - var nsDecl = unit.GetNodeAt<NamespaceDeclaration> (caretLocation); - if (nsDecl == null) { - AddGlobalNamespaceImport (doc, nsName); - return; - } - - var policy = doc.Project != null ? doc.Project.Policies.Get <CSharpFormattingPolicy> () : null; - if (policy == null) - policy = Policy; - - - var node = SearchUsingInsertionPoint (nsDecl); - - var text = new StringBuilder (); - int lines = 0; - - if (InsertUsingAfter (node)) { - lines = policy.BlankLinesBeforeUsings + 1; - while (lines-- > 0) { - text.Append (doc.Editor.EolMarker); - } - } - - string indent = doc.Editor.GetLineIndent (nsDecl.StartLocation.Line) + "\t"; - text.Append (indent); - text.Append ("using "); - text.Append (nsName); - text.Append (";"); - - int offset; - TextLocation loc; - if (node != null) { - loc = InsertUsingAfter (node) ? node.EndLocation : node.StartLocation; - } else { - loc = nsDecl.LBraceToken.EndLocation; - } - offset = doc.Editor.LocationToOffset (loc); - - lines = policy.BlankLinesAfterUsings; - lines -= CountBlankLines (doc, doc.Editor.OffsetToLineNumber (offset) + 1); - if (lines > 0) - text.Append (doc.Editor.EolMarker); - while (lines-- > 0) { - text.Append (doc.Editor.EolMarker); - } - - doc.Editor.Insert (offset, text.ToString ()); - } - - public override string GetShortTypeString (MonoDevelop.Ide.Gui.Document doc, IType type) - { - var shortType = CreateShortType (doc.Compilation, doc.ParsedDocument.ParsedFile as CSharpUnresolvedFile, doc.Editor.Caret.Location, type); - return OutputNode (doc, shortType); - } - - static string OutputNode (MonoDevelop.Ide.Gui.Document doc, AstNode node) - { - using (var stringWriter = new System.IO.StringWriter ()) { -// formatter.Indentation = indentLevel; - var formatter = new TextWriterTokenWriter (stringWriter); - stringWriter.NewLine = doc.Editor.EolMarker; - - var visitor = new CSharpOutputVisitor (formatter, doc.GetFormattingOptions ()); - node.AcceptVisitor (visitor); - return stringWriter.ToString (); - } - } - - - public AstType CreateShortType (ICompilation compilation, CSharpUnresolvedFile parsedFile, TextLocation loc, IType fullType) - { - var csResolver = parsedFile.GetResolver (compilation, loc); - var builder = new ICSharpCode.NRefactory.CSharp.Refactoring.TypeSystemAstBuilder (csResolver); - return builder.ConvertType (fullType); - } - - public override void CompleteStatement (MonoDevelop.Ide.Gui.Document doc) - { - var fixer = new ConstructFixer (doc.GetFormattingOptions (), doc.Editor.CreateNRefactoryTextEditorOptions ()); - int newOffset; - if (fixer.TryFix (doc.Editor.Document, doc.Editor.Caret.Offset, out newOffset)) { - doc.Editor.Caret.Offset = newOffset; - } - } +// +// static string OutputNode (TextEditor editor, DocumentContext context, AstNode node) +// { +// using (var stringWriter = new System.IO.StringWriter ()) { +//// formatter.Indentation = indentLevel; +// var formatter = new TextWriterTokenWriter (stringWriter); +// stringWriter.NewLine = editor.EolMarker; +// +// var visitor = new CSharpOutputVisitor (formatter, null /* TODO: BROKEN DUE ROSLYN PORT (note: that code should be unused) */ ); +// node.AcceptVisitor (visitor); +// return stringWriter.ToString (); +// } +// } +// +// +// public AstType CreateShortType (ICompilation compilation, CSharpUnresolvedFile parsedFile, TextLocation loc, IType fullType) +// { +// var csResolver = parsedFile.GetResolver (compilation, loc); +// var builder = new ICSharpCode.NRefactory.CSharp.Refactoring.TypeSystemAstBuilder (csResolver); +// return builder.ConvertType (fullType); +// } +// +// public override void CompleteStatement (MonoDevelop.Ide.Gui.Document doc) +// { +// // TODO: BROKEN DUE ROSLYN PORT - needs to be ported to NR6 +//// var fixer = new ConstructFixer (doc.GetFormattingOptions (), doc.Editor.CreateNRefactoryTextEditorOptions ()); +//// int newOffset; +//// if (fixer.TryFix (new DocumentWrapper (doc.Editor), doc.Editor.CaretOffset, out newOffset)) { +//// doc.Editor.CaretOffset = newOffset; +//// } +// } } -}
\ No newline at end of file +} diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpFeaturesTextEditorExtension.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpFeaturesTextEditorExtension.cs new file mode 100644 index 0000000000..af2f724aab --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpFeaturesTextEditorExtension.cs @@ -0,0 +1,120 @@ +// +// RenameTextEditorExtension.cs +// +// Author: +// Mike Krüger <mkrueger@novell.com> +// +// Copyright (c) 2011 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Ide.Commands; +using MonoDevelop.Components.Commands; +using MonoDevelop.Ide.Gui.Content; +using MonoDevelop.Ide; +using MonoDevelop.Ide.Editor.Extension; +using MonoDevelop.Core; +using MonoDevelop.Refactoring.Rename; +using ICSharpCode.NRefactory6.CSharp.Features.GotoDefinition; +using System.Threading; +using Microsoft.CodeAnalysis; +using MonoDevelop.Refactoring; + +namespace MonoDevelop.CSharp.Refactoring +{ + sealed class CSharpFeaturesTextEditorExtension : TextEditorExtension + { + public override bool IsValidInContext (MonoDevelop.Ide.Editor.DocumentContext context) + { + return context.Name != null && context.Name.EndsWith (".cs", FilePath.PathComparison); + } + + [CommandUpdateHandler(EditCommands.Rename)] + public void RenameCommand_Update(CommandInfo ci) + { + new RenameHandler ().UpdateCommandInfo (ci); + } + + [CommandHandler (EditCommands.Rename)] + public void RenameCommand () + { + new RenameHandler ().Run (Editor, DocumentContext); + } + + [CommandUpdateHandler(RefactoryCommands.GotoDeclaration)] + public void GotoDeclaration_Update(CommandInfo ci) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null) + return; + if (doc.ParsedDocument == null || doc.ParsedDocument.GetAst<SemanticModel> () == null) { + ci.Enabled = false; + } + var info = RefactoringSymbolInfo.GetSymbolInfoAsync (doc, doc.Editor.CaretOffset).Result; + ci.Enabled = info.Symbol != null; + } + + [CommandHandler (RefactoryCommands.GotoDeclaration)] + public void GotoDeclaration () + { + GoToDefinitionService.TryGoToDefinition (base.DocumentContext.AnalysisDocument, Editor.CaretOffset, default(CancellationToken)); + } + + static readonly FindReferencesHandler findReferencesHandler = new FindReferencesHandler (); + [CommandUpdateHandler(RefactoryCommands.FindReferences)] + public void FindReferences_Update(CommandInfo ci) + { + findReferencesHandler.Update (ci); + } + + [CommandHandler (RefactoryCommands.FindReferences)] + public void FindReferences () + { + findReferencesHandler.Run (null); + } + + static readonly FindAllReferencesHandler findAllReferencesHandler = new FindAllReferencesHandler (); + [CommandUpdateHandler(RefactoryCommands.FindAllReferences)] + public void FindAllReferencesHandler_Update(CommandInfo ci) + { + findAllReferencesHandler.Update (ci); + } + + [CommandHandler (RefactoryCommands.FindAllReferences)] + public void FindAllReferences() + { + findAllReferencesHandler.Run (null); + } + + static readonly FindDerivedSymbolsHandler findDerivedSymbolsHandler = new FindDerivedSymbolsHandler (); + [CommandUpdateHandler(RefactoryCommands.FindDerivedClasses)] + public void FindDerivedClasses_Update(CommandInfo ci) + { + findDerivedSymbolsHandler.Update (ci); + } + + [CommandHandler (RefactoryCommands.FindDerivedClasses)] + public void FindDerivedClasses () + { + findDerivedSymbolsHandler.Run (null); + } + + } +} + diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpReferenceFinder.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpReferenceFinder.cs deleted file mode 100644 index e8e1278ee1..0000000000 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CSharpReferenceFinder.cs +++ /dev/null @@ -1,359 +0,0 @@ -// -// CSharpReferenceFinder.cs -// -// Author: -// Mike Krüger <mkrueger@novell.com> -// -// Copyright (c) 2011 Xamarin Inc. (http://xamarin.com) -// Copyright (c) 2011 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Collections.Generic; - -using MonoDevelop.Core; -using MonoDevelop.Ide; -using MonoDevelop.CSharp.Resolver; -using MonoDevelop.Ide.FindInFiles; -using System.Linq; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.CSharp.Resolver; -using System.IO; -using MonoDevelop.Ide.TypeSystem; -using ICSharpCode.NRefactory.Semantics; -using Mono.TextEditor; -using ICSharpCode.NRefactory.CSharp.TypeSystem; -using System.Threading; - -namespace MonoDevelop.CSharp.Refactoring -{ - using MonoDevelop.Projects; - class CSharpReferenceFinder : ReferenceFinder - { - ICSharpCode.NRefactory.CSharp.Resolver.FindReferences refFinder = new ICSharpCode.NRefactory.CSharp.Resolver.FindReferences (); - List<object> searchedMembers; - List<FilePath> files = new List<FilePath> (); - List<Tuple<FilePath, MonoDevelop.Ide.Gui.Document>> openDocuments = new List<Tuple<FilePath, MonoDevelop.Ide.Gui.Document>> (); - - string memberName; - string keywordName; - - public CSharpReferenceFinder () - { - IncludeDocumentation = true; - } - - public void SetSearchedMembers (IEnumerable<object> members) - { - searchedMembers = new List<object> (members); - var firstMember = searchedMembers.FirstOrDefault (); - if (firstMember is INamedElement) { - var namedElement = (INamedElement)firstMember; - var name = namedElement.Name; - if (namedElement is IMethod && (((IMethod)namedElement).IsConstructor | ((IMethod)namedElement).IsDestructor)) - name = ((IMethod)namedElement).DeclaringType.Name; - memberName = name; - - keywordName = CSharpAmbience.NetToCSharpTypeName (namedElement.FullName); - if (keywordName == namedElement.FullName) - keywordName = null; - } - if (firstMember is string) - memberName = firstMember.ToString (); - if (firstMember is IVariable) - memberName = ((IVariable)firstMember).Name; - if (firstMember is ITypeParameter) - memberName = ((ITypeParameter)firstMember).Name; - if (firstMember is INamespace) - memberName = ((INamespace)firstMember).Name; - } - - void SetPossibleFiles (IEnumerable<FilePath> files) - { - foreach (var file in files) { - var openDocument = IdeApp.Workbench.GetDocument (file); - if (openDocument == null) { - this.files.Add (file); - } else { - this.openDocuments.Add (Tuple.Create (file, openDocument)); - } - } - } - - MemberReference GetReference (Project project, ResolveResult result, AstNode node, SyntaxTree syntaxTree, string fileName, Mono.TextEditor.TextEditorData editor) - { - AstNode originalNode = node; - if (result == null) - return null; - - object valid = null; - if (result is MethodGroupResolveResult) { - valid = ((MethodGroupResolveResult)result).Methods.FirstOrDefault ( - m => searchedMembers.Any (member => member is IMethod && ((IMethod)member).Region == m.Region)); - } else if (result is MemberResolveResult) { - var foundMember = ((MemberResolveResult)result).Member; - valid = searchedMembers.FirstOrDefault ( - member => member is IMember && ((IMember)member).Region == foundMember.Region); - } else if (result is NamespaceResolveResult) { - var ns = ((NamespaceResolveResult)result).Namespace; - valid = searchedMembers.FirstOrDefault (n => n is INamespace && ns.FullName.StartsWith (((INamespace)n).FullName, StringComparison.Ordinal)); - if (!(node is NamespaceDeclaration)) - goto skip; - } else if (result is LocalResolveResult) { - var ns = ((LocalResolveResult)result).Variable; - valid = searchedMembers.FirstOrDefault (n => n is IVariable && ((IVariable)n).Region == ns.Region); - } else if (result is TypeResolveResult) { - valid = searchedMembers.FirstOrDefault (n => n is IType); - } - if (node is ConstructorInitializer) - return null; - if (node is ObjectCreateExpression) - node = ((ObjectCreateExpression)node).Type; - if (node is IndexerDeclaration) - node = ((IndexerDeclaration)node).ThisToken; - - if (node is InvocationExpression) - node = ((InvocationExpression)node).Target; - - if (node is MemberReferenceExpression) - node = ((MemberReferenceExpression)node).MemberNameToken; - - if (node is SimpleType) - node = ((SimpleType)node).IdentifierToken; - - if (node is MemberType) - node = ((MemberType)node).MemberNameToken; - - if (node is NamespaceDeclaration) { - var nsd = ((NamespaceDeclaration)node); - node = nsd.NamespaceName; - if (node == null) - return null; - } - - if (node is TypeDeclaration && (searchedMembers.First () is IType)) - node = ((TypeDeclaration)node).NameToken; - if (node is DelegateDeclaration) - node = ((DelegateDeclaration)node).NameToken; - - if (node is EntityDeclaration && (searchedMembers.First () is IMember)) - node = ((EntityDeclaration)node).NameToken; - - if (node is ParameterDeclaration && (searchedMembers.First () is IParameter)) - node = ((ParameterDeclaration)node).NameToken; - if (node is ConstructorDeclaration) - node = ((ConstructorDeclaration)node).NameToken; - if (node is DestructorDeclaration) - node = ((DestructorDeclaration)node).NameToken; - if (node is NamedArgumentExpression) - node = ((NamedArgumentExpression)node).NameToken; - if (node is NamedExpression) - node = ((NamedExpression)node).NameToken; - if (node is VariableInitializer) - node = ((VariableInitializer)node).NameToken; - - if (node is IdentifierExpression) { - node = ((IdentifierExpression)node).IdentifierToken; - } - - skip: - - var region = new DomRegion (fileName, node.StartLocation, node.EndLocation); - - var length = node is PrimitiveType ? keywordName.Length : node.EndLocation.Column - node.StartLocation.Column; - if (valid == null) - valid = searchedMembers.FirstOrDefault (); - var reference = new CSharpMemberReference (project, originalNode, syntaxTree, valid, region, editor.LocationToOffset (region.Begin), length); - - reference.ReferenceUsageType = GetUsage (originalNode); - return reference; - } - - // same logic than the extract method analyzation, unfortunately it's not reusable in this context - // we need to do it bottom up here. - ReferenceUsageType GetUsage (AstNode node) - { - if (node.Parent is UnaryOperatorExpression) { - var unaryOperatorExpression = (UnaryOperatorExpression)node.Parent; - if (unaryOperatorExpression.Operator == UnaryOperatorType.Increment || - unaryOperatorExpression.Operator == UnaryOperatorType.Decrement || - unaryOperatorExpression.Operator == UnaryOperatorType.PostIncrement || - unaryOperatorExpression.Operator == UnaryOperatorType.PostDecrement) { - return ReferenceUsageType.ReadWrite; - } - } else if (node.Parent is DirectionExpression) { - var de = (DirectionExpression)node.Parent; - if (de.FieldDirection == FieldDirection.Ref) - return ReferenceUsageType.ReadWrite; - if (de.FieldDirection == FieldDirection.Out) - return ReferenceUsageType.Write; - } else if (node.Parent is AssignmentExpression) { - var ae = (AssignmentExpression)node.Parent; - if (ae.Left == node) - return ReferenceUsageType.Write; - } else if (node is VariableInitializer) { - return ReferenceUsageType.Write; - } else if (node is ParameterDeclaration) { - return ReferenceUsageType.Write; - } else if (node.Parent is ForeachStatement) { - if (node.Role == Roles.Identifier) - return ReferenceUsageType.Write; - } - return ReferenceUsageType.Read; - } - - public class CSharpMemberReference : MemberReference - { - public SyntaxTree SyntaxTree { - get; - private set; - } - - public AstNode AstNode { - get; - private set; - } - - public Project Project { - get; - private set; - } - - public CSharpMemberReference (Project project, AstNode astNode, SyntaxTree syntaxTree, object entity, DomRegion region, int offset, int length) : base (entity, region, offset, length) - { - this.Project = project; - this.AstNode = astNode; - this.SyntaxTree = syntaxTree; - } - } - - bool IsNodeValid (object searchedMember, AstNode node) - { - if (searchedMember is IField && node is FieldDeclaration) - return false; - return true; - } - - public IEnumerable<MemberReference> FindInDocument (MonoDevelop.Ide.Gui.Document doc, CancellationToken token = default (CancellationToken)) - { - if (string.IsNullOrEmpty (memberName)) - return Enumerable.Empty<MemberReference> (); - var editor = doc.Editor; - var parsedDocument = doc.ParsedDocument; - if (parsedDocument == null) - return Enumerable.Empty<MemberReference> (); - var unit = parsedDocument.GetAst<SyntaxTree> (); - var file = parsedDocument.ParsedFile as CSharpUnresolvedFile; - var result = new List<MemberReference> (); - - foreach (var obj in searchedMembers) { - if (obj is IVariable && !(obj is IParameter) && !(obj is IField)) { - refFinder.FindLocalReferences ((IVariable)obj, file, unit, doc.Compilation, (astNode, r) => { - if (IsNodeValid (obj, astNode)) - result.Add (GetReference (doc.Project, r, astNode, unit, editor.FileName, editor)); - }, token); - } else if (obj is ISymbol) { - var sym = (ISymbol)obj; - - // May happen for anonymous types since empty constructors are always generated. - // But there is no declaring type definition for them - we filter out this case. - if (sym.SymbolKind == SymbolKind.Constructor && ((IEntity)sym).DeclaringTypeDefinition == null) - continue; - refFinder.FindReferencesInFile (refFinder.GetSearchScopes (sym), file, unit, doc.Compilation, (astNode, r) => { - if (IsNodeValid (obj, astNode)) - result.Add (GetReference (doc.Project, r, astNode, unit, editor.FileName, editor)); - }, token); - } - } - return result; - } - - public override IEnumerable<MemberReference> FindReferences (Project project, IProjectContent content, IEnumerable<FilePath> possibleFiles, ProgressMonitor monitor, IEnumerable<object> members) - { - if (content == null) - throw new ArgumentNullException ("content", "Project content not set."); - SetPossibleFiles (possibleFiles); - SetSearchedMembers (members); - var scopes = searchedMembers.Select (e => e is INamespace ? refFinder.GetSearchScopes ((INamespace)e) : refFinder.GetSearchScopes ((ISymbol)e)); - var compilation = project != null ? TypeSystemService.GetCompilation (project) : content.CreateCompilation (); - List<MemberReference> refs = new List<MemberReference> (); - foreach (var opendoc in openDocuments) { - foreach (var newRef in FindInDocument (opendoc.Item2)) { - if (newRef == null || refs.Any (r => r.FileName == newRef.FileName && r.Region == newRef.Region)) - continue; - refs.Add (newRef); - } - } - foreach (var file in files) { - if (monitor != null) - monitor.Step (1); - string text; - try { - if (!File.Exists (file)) - continue; - text = Mono.TextEditor.Utils.TextFileUtility.ReadAllText (file); - } catch (Exception e) { - LoggingService.LogError ("Exception while file reading.", e); - continue; - } - if (memberName != null && text.IndexOf (memberName, StringComparison.Ordinal) < 0 && - (keywordName == null || text.IndexOf (keywordName, StringComparison.Ordinal) < 0)) - continue; - using (var editor = TextEditorData.CreateImmutable (text)) { - editor.Document.FileName = file; - var unit = new CSharpParser ().Parse (editor); - if (unit == null) - continue; - - var storedFile = content.GetFile (file); - var parsedFile = storedFile as CSharpUnresolvedFile; - - if (parsedFile == null && storedFile is ParsedDocumentDecorator) { - parsedFile = ((ParsedDocumentDecorator)storedFile).ParsedFile as CSharpUnresolvedFile; - } - - if (parsedFile == null) { - // for fallback purposes - should never happen. - parsedFile = unit.ToTypeSystem (); - content = content.AddOrUpdateFiles (parsedFile); - compilation = content.CreateCompilation (); - } - foreach (var scope in scopes) { - refFinder.FindReferencesInFile ( - scope, - parsedFile, - unit, - compilation, - (astNode, result) => { - var newRef = GetReference (project, result, astNode, unit, file, editor); - if (newRef == null || refs.Any (r => r.FileName == newRef.FileName && r.Region == newRef.Region)) - return; - refs.Add (newRef); - }, - CancellationToken.None - ); - } - } - } - return refs; - } - } -} - diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CodeGenerationService.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CodeGenerationService.cs new file mode 100644 index 0000000000..8f911641af --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/CodeGenerationService.cs @@ -0,0 +1,302 @@ +// +// CodeGenerationService.cs +// +// Author: +// mkrueger <mkrueger@novell.com> +// +// Copyright (c) 2011 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using MonoDevelop.Core; +using System.CodeDom; +using MonoDevelop.Projects; +using System.CodeDom.Compiler; +using MonoDevelop.Ide.TypeSystem; +using MonoDevelop.Ide; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp; +using ICSharpCode.NRefactory6.CSharp; +using MonoDevelop.Ide.Editor; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; +using System.Threading; +using Gtk; +using MonoDevelop.Ide.CodeFormatting; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using MonoDevelop.CSharp.Formatting; +using MonoDevelop.Ide.Gui.Content; + +namespace MonoDevelop.Refactoring +{ + public static class CodeGenerationService + { + // public static IUnresolvedMember AddCodeDomMember (MonoDevelop.Projects.Project project, IUnresolvedTypeDefinition type, CodeTypeMember newMember) + // { + // bool isOpen; + // var data = TextFileProvider.Instance.GetTextEditorData (type.Region.FileName, out isOpen); + // var parsedDocument = TypeSystemService.ParseFile (data.FileName, data.MimeType, data.Text); + // + // var insertionPoints = GetInsertionPoints (data, parsedDocument, type); + // + // var suitableInsertionPoint = GetSuitableInsertionPoint (insertionPoints, type, newMember); + // + // var dotNetProject = project as DotNetProject; + // if (dotNetProject == null) { + // LoggingService.LogError ("Only .NET projects are supported."); + // return null; + // } + // + // var generator = dotNetProject.LanguageBinding.GetCodeDomProvider (); + // StringWriter sw = new StringWriter (); + // var options = new CodeGeneratorOptions (); + // options.IndentString = data.GetLineIndent (type.Region.BeginLine) + "\t"; + // if (newMember is CodeMemberMethod) + // options.BracingStyle = "C"; + // generator.GenerateCodeFromMember (newMember, sw, options); + // + // var code = sw.ToString (); + // if (!string.IsNullOrEmpty (code)) + // suitableInsertionPoint.Insert (data, code); + // if (!isOpen) { + // try { + // File.WriteAllText (type.Region.FileName, data.Text); + // } catch (Exception e) { + // LoggingService.LogError (string.Format ("Failed to write file '{0}'.", type.Region.FileName), e); + // MessageService.ShowError (GettextCatalog.GetString ("Failed to write file '{0}'.", type.Region.FileName)); + // } + // } + // var newDocument = TypeSystemService.ParseFile (data.FileName, data.MimeType, data.Text); + // return newDocument.ParsedFile.GetMember (suitableInsertionPoint.Location.Line, int.MaxValue); + // } + + public static async Task AddNewMember (Projects.Project project, ITypeSymbol type, Location part, SyntaxNode newMember, CancellationToken cancellationToken = default(CancellationToken)) + { + if (project == null) + throw new ArgumentNullException (nameof (project)); + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (newMember == null) + throw new ArgumentNullException (nameof (newMember)); + if (!type.IsDefinedInSource ()) + throw new ArgumentException ("The given type needs to be defined in source code.", nameof (type)); + + + var ws = TypeSystemService.GetWorkspace (project.ParentSolution); + var projectId = ws.GetProjectId (project); + var docId = ws.GetDocumentId (projectId, part.SourceTree.FilePath); + + var document = ws.GetDocument (docId, cancellationToken); + + var root = await document.GetSyntaxRootAsync (cancellationToken).ConfigureAwait (false); + var typeDecl = (ClassDeclarationSyntax)root.FindNode (part.SourceSpan); + + // for some reason the reducer doesn't reduce this + var systemVoid = newMember.DescendantNodesAndSelf ().OfType<QualifiedNameSyntax> ().FirstOrDefault (ma => ma.ToString () == "System.Void"); + + if (systemVoid != null) newMember = newMember.ReplaceNode (systemVoid, SyntaxFactory.ParseTypeName ("void")); + + var newRoot = root.ReplaceNode (typeDecl, typeDecl.AddMembers ((MemberDeclarationSyntax)newMember.WithAdditionalAnnotations (Simplifier.Annotation, Formatter.Annotation))); + document = document.WithSyntaxRoot (newRoot); + var policy = project.Policies.Get<CSharpFormattingPolicy> ("text/x-csharp"); + var textPolicy = project.Policies.Get<TextStylePolicy> ("text/x-csharp"); + var projectOptions = policy.CreateOptions (textPolicy); + + document = await Formatter.FormatAsync (document, Formatter.Annotation, projectOptions, cancellationToken).ConfigureAwait (false); + document = await Simplifier.ReduceAsync (document, Simplifier.Annotation, projectOptions, cancellationToken).ConfigureAwait (false); + var text = await document.GetTextAsync (cancellationToken).ConfigureAwait (false); + var newSolution = ws.CurrentSolution.WithDocumentText (docId, text); + ws.TryApplyChanges (newSolution); + } + + readonly static SyntaxAnnotation insertedMemberAnnotation = new SyntaxAnnotation ("INSERTION_ANNOTATAION"); + public static async Task InsertMemberWithCursor (string operation, Projects.Project project, ITypeSymbol type, Location part, SyntaxNode newMember, CancellationToken cancellationToken = default(CancellationToken)) + { + if (operation == null) + throw new ArgumentNullException (nameof (operation)); + if (project == null) + throw new ArgumentNullException (nameof (project)); + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (newMember == null) + throw new ArgumentNullException (nameof (newMember)); + var ws = TypeSystemService.GetWorkspace (project.ParentSolution); + var projectId = ws.GetProjectId (project); + var docId = ws.GetDocumentId (projectId, part.SourceTree.FilePath); + + var document = ws.GetDocument (docId, cancellationToken); + + var root = await document.GetSyntaxRootAsync (cancellationToken).ConfigureAwait (false); + var typeDecl = (ClassDeclarationSyntax)root.FindNode (part.SourceSpan); + + // for some reason the reducer doesn't reduce this + var systemVoid = newMember.DescendantNodesAndSelf ().OfType<QualifiedNameSyntax> ().FirstOrDefault (ma => ma.ToString () == "System.Void"); + + if (systemVoid != null) newMember = newMember.ReplaceNode (systemVoid, SyntaxFactory.ParseTypeName ("void")); + + var newRoot = root.ReplaceNode (typeDecl, typeDecl.AddMembers ((MemberDeclarationSyntax)newMember.WithAdditionalAnnotations (Simplifier.Annotation, Formatter.Annotation, insertedMemberAnnotation))); + var doc = IdeApp.Workbench.OpenDocument (part.SourceTree.FilePath, project, true); + + var policy = project.Policies.Get<CSharpFormattingPolicy> ("text/x-csharp"); + var textPolicy = project.Policies.Get<TextStylePolicy> ("text/x-csharp"); + var projectOptions = policy.CreateOptions (textPolicy); + + document = document.WithSyntaxRoot (newRoot); + document = await Formatter.FormatAsync (document, Formatter.Annotation, projectOptions, cancellationToken).ConfigureAwait (false); + document = await Simplifier.ReduceAsync (document, Simplifier.Annotation, projectOptions, cancellationToken).ConfigureAwait (false); + + root = await document.GetSyntaxRootAsync (cancellationToken).ConfigureAwait (false); + + var node = root.GetAnnotatedNodes (insertedMemberAnnotation).Single (); + + Application.Invoke (delegate { + var insertionPoints = InsertionPointService.GetInsertionPoints ( + doc.Editor, + doc.UpdateParseDocument (), + type, + part + ); + var options = new InsertionModeOptions ( + operation, + insertionPoints, + async point => { + if (!point.Success) + return; + var text = node.ToString (); + point.InsertionPoint.Insert (doc.Editor, doc, text); + } + ); + + doc.Editor.StartInsertionMode (options); + }); + } + + //public static Task<bool> InsertMemberWithCursor (string operation, ITypeSymbol type, Location part, SyntaxNode newMember, bool implementExplicit = false) + //{ + // //TODO: Add dialog for inserting position + // AddNewMember (type, part, newMember, implementExplicit); + // return Task.FromResult (true); + //} + // + // public static int CalculateBodyIndentLevel (IUnresolvedTypeDefinition declaringType) + // { + // if (declaringType == null) + // return 0; + // int indentLevel = 1; + // while (declaringType.DeclaringTypeDefinition != null) { + // indentLevel++; + // declaringType = declaringType.DeclaringTypeDefinition; + // } + // var file = declaringType.UnresolvedFile as CSharpUnresolvedFile; + // if (file == null) + // return indentLevel; + // var scope = file.GetUsingScope (declaringType.Region.Begin); + // while (scope != null && !string.IsNullOrEmpty (scope.NamespaceName)) { + // indentLevel++; + // // skip virtual scopes. + // while (scope.Parent != null && scope.Parent.Region == scope.Region) + // scope = scope.Parent; + // scope = scope.Parent; + // } + // return indentLevel; + // } + public static MonoDevelop.Ide.TypeSystem.CodeGenerator CreateCodeGenerator (this Ide.Gui.Document doc) + { + return MonoDevelop.Ide.TypeSystem.CodeGenerator.CreateGenerator (doc); + } + + + // public static MonoDevelop.Ide.TypeSystem.CodeGenerator CreateCodeGenerator (this ITextDocument data, ICompilation compilation) + // { + // return MonoDevelop.Ide.TypeSystem.CodeGenerator.CreateGenerator (data, compilation); + // } + // + // static IUnresolvedTypeDefinition GetMainPart (IType t) + // { + // return t.GetDefinition ().Parts.First (); + // } + + + public static void AddAttribute (INamedTypeSymbol cls, string name, params object [] parameters) + { + if (cls == null) + throw new ArgumentNullException ("cls"); + bool isOpen; + string fileName = cls.Locations.First ().SourceTree.FilePath; + var buffer = TextFileProvider.Instance.GetTextEditorData (fileName, out isOpen); + + + var code = new StringBuilder (); + int pos = cls.Locations.First ().SourceSpan.Start; + var line = buffer.GetLineByOffset (pos); + code.Append (buffer.GetLineIndent (line)); + code.Append ("["); + code.Append (name); + if (parameters != null && parameters.Length > 0) { + code.Append ("("); + for (int i = 0; i < parameters.Length; i++) { + if (i > 0) + code.Append (", "); + code.Append (parameters [i]); + } + code.Append (")"); + } + code.Append ("]"); + code.AppendLine (); + + buffer.InsertText (line.Offset, code.ToString ()); + + if (!isOpen) { + File.WriteAllText (fileName, buffer.Text); + } + } + + public static ITypeSymbol AddType (DotNetProject project, string folder, string namspace, ClassDeclarationSyntax type) + { + if (project == null) + throw new ArgumentNullException (nameof (project)); + if (folder == null) + throw new ArgumentNullException (nameof (folder)); + if (namspace == null) + throw new ArgumentNullException (nameof (namspace)); + if (type == null) + throw new ArgumentNullException (nameof (type)); + var ns = SyntaxFactory.NamespaceDeclaration (SyntaxFactory.ParseName (namspace)).WithMembers (new SyntaxList<MemberDeclarationSyntax> () { type }); + + string fileName = project.LanguageBinding.GetFileName (Path.Combine (folder, type.Identifier.ToString ())); + using (var sw = new StreamWriter (fileName)) { + sw.WriteLine (ns.ToString ()); + } + FileService.NotifyFileChanged (fileName); + var roslynProject = TypeSystemService.GetCodeAnalysisProject (project); + var id = TypeSystemService.GetDocumentId (roslynProject.Id, fileName); + if (id == null) + return null; + var model = roslynProject.GetDocument (id).GetSemanticModelAsync ().Result; + var typeSyntax = model.SyntaxTree.GetCompilationUnitRoot ().ChildNodes ().First ().ChildNodes ().First () as ClassDeclarationSyntax; + return model.GetDeclaredSymbol (typeSyntax); + } + } +} diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/ExtractMethodCommandHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/ExtractMethodCommandHandler.cs new file mode 100644 index 0000000000..f4cd6ae7d0 --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/ExtractMethodCommandHandler.cs @@ -0,0 +1,113 @@ +// +// ExtractMethodCommandHandler.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Components.Commands; +using ICSharpCode.NRefactory6.CSharp.ExtractMethod; +using MonoDevelop.Ide; +using ICSharpCode.NRefactory6.CSharp; +using System.Threading; +using Microsoft.CodeAnalysis.Text; +using System.Linq; +using MonoDevelop.Refactoring; +using MonoDevelop.Core; +using System.Threading.Tasks; + +namespace MonoDevelop.CSharp.Refactoring +{ + class ExtractMethodCommandHandler : CommandHandler + { + public static async Task<bool> IsValid (MonoDevelop.Ide.Gui.Document doc, CancellationToken cancellationToken = default(CancellationToken)) + { + if (doc == null) + return false; + if (doc.Editor == null || !doc.Editor.IsSomethingSelected) + return false; + var ad = doc.AnalysisDocument; + if (ad == null) + return false; + var selectionRange = doc.Editor.SelectionRange; + try { + var selection = new CSharpSelectionValidator (await SemanticDocument.CreateAsync (ad, cancellationToken).ConfigureAwait (false), new TextSpan (selectionRange.Offset, selectionRange.Length), doc.GetOptionSet ()); + var result = await selection.GetValidSelectionAsync (cancellationToken).ConfigureAwait (false); + return result.ContainsValidContext; + } catch (Exception) { + return false; + } + } + + protected async override void Update (CommandInfo info) + { + var doc = IdeApp.Workbench.ActiveDocument; + info.Enabled = await IsValid (doc); + } + + public async static Task Run (MonoDevelop.Ide.Gui.Document doc) + { + if (!doc.Editor.IsSomethingSelected) + return; + var ad = doc.AnalysisDocument; + if (ad == null) + return; + try { + var selectionRange = doc.Editor.SelectionRange; + var token = default(CancellationToken); + var selection = new CSharpSelectionValidator (await SemanticDocument.CreateAsync (ad, token).ConfigureAwait (false), new TextSpan (selectionRange.Offset, selectionRange.Length), doc.GetOptionSet ()); + var result = await selection.GetValidSelectionAsync (token).ConfigureAwait (false); + if (!result.ContainsValidContext) + return; + var extractor = new CSharpMethodExtractor ((CSharpSelectionResult)result); + var extractionResult = await extractor.ExtractMethodAsync (token).ConfigureAwait (false); + var changes = await extractionResult.Document.GetTextChangesAsync (ad, token); + using (var undo = doc.Editor.OpenUndoGroup ()) { + foreach (var change in changes.OrderByDescending (ts => ts.Span.Start)) { + doc.Editor.ReplaceText (change.Span.Start, change.Span.Length, change.NewText); + } + // hack to remove the redundant private modifier. + if (doc.Editor.GetTextAt (extractionResult.MethodDeclarationNode.SpanStart, "private ".Length) == "private ") { + doc.Editor.RemoveText (extractionResult.MethodDeclarationNode.SpanStart, "private ".Length); + } + } + doc.UpdateParseDocument (); + var info = RefactoringSymbolInfo.GetSymbolInfoAsync (doc, extractionResult.InvocationNameToken.Span.Start).Result; + var sym = info.DeclaredSymbol ?? info.Symbol; + if (sym != null) + new MonoDevelop.Refactoring.Rename.RenameRefactoring ().Rename (sym); + } + catch (Exception e) { + LoggingService.LogError ("Error while extracting method", e); + } + } + + protected async override void Run () + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null) + return; + await Run (doc); + } + } +} + diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindDerivedSymbolsHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindDerivedSymbolsHandler.cs new file mode 100644 index 0000000000..bfa67762ff --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindDerivedSymbolsHandler.cs @@ -0,0 +1,109 @@ +// +// FindDerivedSymbolsHandler.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Ide; +using MonoDevelop.Ide.FindInFiles; +using MonoDevelop.Ide.TypeSystem; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MonoDevelop.Projects; +using System.Threading; +using MonoDevelop.Core; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.FindSymbols; +using ICSharpCode.NRefactory6.CSharp; +using MonoDevelop.Components.Commands; +using MonoDevelop.Refactoring; + +namespace MonoDevelop.CSharp.Refactoring +{ + class FindDerivedSymbolsHandler + { + public static bool CanFindDerivedSymbols (ISymbol symbol, out string description) + { + if (symbol.Kind == SymbolKind.NamedType) { + var type = (ITypeSymbol)symbol; + description = type.TypeKind == TypeKind.Interface ? GettextCatalog.GetString ("Find Implementing Types") : GettextCatalog.GetString ("Find Derived Types"); + return !type.IsStatic && !type.IsSealed; + } + if (symbol.ContainingType != null && symbol.ContainingType.TypeKind == TypeKind.Interface) { + description = GettextCatalog.GetString ("Find Implementing Symbols"); + } else { + description = GettextCatalog.GetString ("Find Derived Symbols"); + } + return symbol.IsVirtual || symbol.IsAbstract || symbol.IsOverride; + } + + public static void FindDerivedSymbols (ISymbol symbol) + { + Task.Run (delegate { + using (var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true)) { + IEnumerable<ISymbol> task; + + if (symbol.ContainingType != null && symbol.ContainingType.TypeKind == TypeKind.Interface) { + task = SymbolFinder.FindImplementationsAsync (symbol, TypeSystemService.Workspace.CurrentSolution).Result; + } else if (symbol.Kind == SymbolKind.NamedType) { + var type = (INamedTypeSymbol)symbol; + if (type.TypeKind == TypeKind.Interface) { + task = SymbolFinder.FindImplementationsAsync (symbol, TypeSystemService.Workspace.CurrentSolution).Result; + } else { + task = type.FindDerivedClassesAsync (TypeSystemService.Workspace.CurrentSolution).Result.Cast<ISymbol> (); + } + } else { + task = SymbolFinder.FindOverridesAsync (symbol, TypeSystemService.Workspace.CurrentSolution).Result; + } + foreach (var foundSymbol in task) { + foreach (var loc in foundSymbol.Locations) + monitor.ReportResult (new MemberReference (foundSymbol, loc.SourceTree.FilePath, loc.SourceSpan.Start, loc.SourceSpan.Length)); + } + } + }); + } + + public async void Update (CommandInfo info) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null || doc.ParsedDocument == null) { + info.Enabled = false; + return; + } + var rinfo = await RefactoringSymbolInfo.GetSymbolInfoAsync (doc, doc.Editor.CaretOffset); + info.Enabled = rinfo.DeclaredSymbol != null; + } + + public async void Run (object data) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null) + return; + var info = await RefactoringSymbolInfo.GetSymbolInfoAsync (doc, doc.Editor.CaretOffset); + if (info.DeclaredSymbol != null) + FindDerivedSymbols (info.DeclaredSymbol); + } + } +} + diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindExtensionMethodHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindExtensionMethodHandler.cs new file mode 100644 index 0000000000..a6035056dd --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindExtensionMethodHandler.cs @@ -0,0 +1,94 @@ +// +// FindExtensionMethodHandler.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using MonoDevelop.Ide; +using MonoDevelop.Ide.FindInFiles; +using MonoDevelop.Ide.TypeSystem; +using MonoDevelop.Core; +using Microsoft.CodeAnalysis; + +namespace MonoDevelop.CSharp.Refactoring +{ + class FindExtensionMethodHandler + { + public static bool CanFindExtensionMethods (ISymbol declaredSymbol, out string description) + { +// var tr = new ICSharpCode.NRefactory.CSharp.CSharpParser ().ParseTypeReference ("global::Thing<int>.Done<string>") as MemberType; +// Console.WriteLine (tr.Target); +// + description = GettextCatalog.GetString ("Find Extension Methods"); +// return declaredSymbol.Kind == SymbolKind.NamedType; + return false; + } + + public static void FindExtensionMethods (ISymbol declaredSymbol) + { + /* using (var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true)) { + var solution = TypeSystemService.Workspace.CurrentSolution; + foreach (var project in solution.Projects) { + var comp = project.GetCompilationAsync ().Result; + foreach (var type in comp.) + + } + } + declaredSymbo*/ + } + + +// public void Run () +// { +// using (var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true)) { +// foreach (var project in IdeApp.ProjectOperations.CurrentSelectedSolution.GetAllProjects ()) { +// var comp = TypeSystemService.GetCompilation (project); +// foreach (var type in comp.MainAssembly.GetAllTypeDefinitions ()) { +// if (!type.IsStatic) +// continue; +// foreach (var method in type.GetMethods (m => m.IsStatic)) { +// if (!method.IsExtensionMethod) +// continue; +// IType[] ifTypes; +// var typeDef = comp.Import (entity); +// if (typeDef == null) +// continue; +// if (!CSharpResolver.IsEligibleExtensionMethod (typeDef, method, true, out ifTypes)) +// continue; +// +// var tf = TextFileProvider.Instance.GetReadOnlyTextEditorData (method.Region.FileName); +// var start = tf.LocationToOffset (method.Region.Begin); +// tf.SearchRequest.SearchPattern = method.Name; +// var sr = tf.SearchForward (start); +// if (sr != null) +// start = sr.Offset; +// monitor.ReportResult (new MemberReference (method, method.Region.FileName, start, method.Name.Length)); +// } +// } +// } +// } +// } + } +} + diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindMemberOverloadsHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindMemberOverloadsHandler.cs new file mode 100644 index 0000000000..b318f7994c --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindMemberOverloadsHandler.cs @@ -0,0 +1,74 @@ +// +// FindMemberOverloadsHandler.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Linq; +using MonoDevelop.Ide; +using MonoDevelop.Ide.FindInFiles; +using Microsoft.CodeAnalysis; +using MonoDevelop.Core; + +namespace MonoDevelop.CSharp.Refactoring +{ + static class FindMemberOverloadsHandler + { + public static bool CanFindMemberOverloads (ISymbol symbol, out string description) + { + switch (symbol.Kind) { + case SymbolKind.Method: + description = GettextCatalog.GetString ("Find Method Overloads"); + return symbol.ContainingType.GetMembers (symbol.Name).OfType<IMethodSymbol> ().Count () > 1; + case SymbolKind.Property: + description = GettextCatalog.GetString ("Find Indexer Overloads"); + return symbol.ContainingType.GetMembers ().OfType<IPropertySymbol> () .Where (p => p.IsIndexer).Count () > 1; + default: + description = null; + return false; + } + } + + public static void FindOverloads (ISymbol symbol) + { + using (var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true)) { + switch (symbol.Kind) { + case SymbolKind.Method: + foreach (var method in symbol.ContainingType.GetMembers (symbol.Name).OfType<IMethodSymbol> ()) { + foreach (var loc in method.Locations) + monitor.ReportResult (new MemberReference (method, loc.SourceTree.FilePath, loc.SourceSpan.Start, loc.SourceSpan.Length)); + } + break; + case SymbolKind.Property: + foreach (var property in symbol.ContainingType.GetMembers ().OfType<IPropertySymbol> () .Where (p => p.IsIndexer)) { + foreach (var loc in property.Locations) + monitor.ReportResult (new MemberReference (property, loc.SourceTree.FilePath, loc.SourceSpan.Start, loc.SourceSpan.Length)); + } + break; + + } + } + } + } +} + diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindReferencesHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindReferencesHandler.cs new file mode 100644 index 0000000000..4b702126e5 --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/FindReferencesHandler.cs @@ -0,0 +1,156 @@ +// +// FindReferencesHandler.cs +// +// Author: +// Mike Krüger <mkrueger@novell.com> +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Threading; +using MonoDevelop.Components.Commands; +using MonoDevelop.Core; +using MonoDevelop.Ide; +using MonoDevelop.Refactoring; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis; +using MonoDevelop.Ide.TypeSystem; +using MonoDevelop.Ide.FindInFiles; +using MonoDevelop.Ide.Tasks; +using System.Threading.Tasks; + +namespace MonoDevelop.CSharp.Refactoring +{ + class FindReferencesHandler + { + public static void FindRefs (ISymbol symbol) + { + var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true); + var solution = TypeSystemService.Workspace.CurrentSolution; + ThreadPool.QueueUserWorkItem (delegate { + try { + foreach (var loc in symbol.Locations) { + if (!loc.IsInSource) + continue; + var sr = new SearchResult (new FileProvider (loc.SourceTree.FilePath), loc.SourceSpan.Start, loc.SourceSpan.Length); + monitor.ReportResult (sr); + } + + foreach (var mref in SymbolFinder.FindReferencesAsync (symbol, solution).Result) { + foreach (var loc in mref.Locations) { + var sr = new SearchResult (new FileProvider (loc.Document.FilePath), loc.Location.SourceSpan.Start, loc.Location.SourceSpan.Length); + monitor.ReportResult (sr); + } + } + } catch (Exception ex) { + if (monitor != null) + monitor.ReportError ("Error finding references", ex); + else + LoggingService.LogError ("Error finding references", ex); + } finally { + if (monitor != null) + monitor.Dispose (); + } + }); + } + + public void Update (CommandInfo info) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null || doc.ParsedDocument == null) { + info.Enabled = false; + return; + } + var pd = doc.ParsedDocument.GetAst<SemanticModel> (); + info.Enabled = pd != null; + } + + public void Run (object data) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null) + return; + + var info = RefactoringSymbolInfo.GetSymbolInfoAsync (doc, doc.Editor.CaretOffset).Result; + var sym = info.Symbol ?? info.DeclaredSymbol; + if (sym != null) + FindRefs (sym); + } + } + + class FindAllReferencesHandler + { + public static void FindRefs (ISymbol obj, Compilation compilation) + { + var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true); + var solution = TypeSystemService.Workspace.CurrentSolution; + ThreadPool.QueueUserWorkItem (delegate { + try { + foreach (var simSym in SymbolFinder.FindSimilarSymbols (obj, compilation)) { + foreach (var loc in simSym.Locations) { + var sr = new SearchResult (new FileProvider (loc.SourceTree.FilePath), loc.SourceSpan.Start, loc.SourceSpan.Length); + monitor.ReportResult (sr); + } + + foreach (var mref in SymbolFinder.FindReferencesAsync (simSym, solution).Result) { + foreach (var loc in mref.Locations) { + var sr = new SearchResult (new FileProvider (loc.Document.FilePath), loc.Location.SourceSpan.Start, loc.Location.SourceSpan.Length); + monitor.ReportResult (sr); + } + } + } + } catch (Exception ex) { + if (monitor != null) + monitor.ReportError ("Error finding references", ex); + else + LoggingService.LogError ("Error finding references", ex); + } finally { + if (monitor != null) + monitor.Dispose (); + } + }); + } + + public void Update (CommandInfo info) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null || doc.ParsedDocument == null) { + info.Enabled = false; + return; + } + var pd = doc.ParsedDocument.GetAst<SemanticModel> (); + info.Enabled = pd != null; + } + + public void Run (object data) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null) + return; + + var info = RefactoringSymbolInfo.GetSymbolInfoAsync (doc, doc.Editor.CaretOffset).Result; + var sym = info.Symbol ?? info.DeclaredSymbol; + var semanticModel = doc.ParsedDocument.GetAst<SemanticModel> (); + if (sym != null) + FindRefs (sym, semanticModel.Compilation); + } + } +} diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/GotoBaseDeclarationHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/GotoBaseDeclarationHandler.cs new file mode 100644 index 0000000000..ea42862a3e --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/GotoBaseDeclarationHandler.cs @@ -0,0 +1,111 @@ +// +// GotoBaseDeclarationHandler.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using Microsoft.CodeAnalysis; +using MonoDevelop.Ide; +using System.Linq; +using MonoDevelop.Core; + +namespace MonoDevelop.CSharp.Refactoring +{ + static class GotoBaseDeclarationHandler + { + public static string GetDescription (ISymbol symbol) + { + if (symbol == null) + throw new ArgumentNullException ("symbol"); + switch (symbol.Kind) { + case SymbolKind.NamedType: + return GettextCatalog.GetString ("Go to _Base Type"); + case SymbolKind.Property: + var property = (IPropertySymbol)symbol; + return property.OverriddenProperty != null ? GettextCatalog.GetString ("Go to _Base Property") : GettextCatalog.GetString ("Go to _Interface Property"); + case SymbolKind.Event: + var evt = (IEventSymbol)symbol; + return evt.OverriddenEvent != null ? GettextCatalog.GetString ("Go to _Base Event") : GettextCatalog.GetString ("Go to _Interface Event"); + case SymbolKind.Method: + var method = (IMethodSymbol)symbol; + return method.OverriddenMethod != null ? GettextCatalog.GetString ("Go to _Base Method") : GettextCatalog.GetString ("Go to _Interface Method"); + } + return GettextCatalog.GetString ("Go to _Base Symbol"); + } + + public static bool CanGotoBase (ISymbol symbol) + { + if (symbol == null) + return false; + switch (symbol.Kind) { + case SymbolKind.NamedType: + return true; + case SymbolKind.Property: + var property = (IPropertySymbol)symbol; + return property.OverriddenProperty != null || property.ExplicitInterfaceImplementations.Length > 0; + case SymbolKind.Event: + var evt = (IEventSymbol)symbol; + return evt.OverriddenEvent != null || evt.ExplicitInterfaceImplementations.Length > 0; + case SymbolKind.Method: + var method = (IMethodSymbol)symbol; + return method.OverriddenMethod != null || method.ExplicitInterfaceImplementations.Length > 0; + } + return false; + } + + public static void GotoBase (MonoDevelop.Ide.Gui.Document doc, ISymbol symbol) + { + if (doc == null) + throw new ArgumentNullException ("doc"); + if (symbol == null) + throw new ArgumentNullException ("symbol"); + switch (symbol.Kind) { + case SymbolKind.NamedType: + IdeApp.ProjectOperations.JumpToDeclaration (((ITypeSymbol)symbol).BaseType, doc.Project); + break; + case SymbolKind.Property: + var property = (IPropertySymbol)symbol; + if (property.OverriddenProperty != null) + IdeApp.ProjectOperations.JumpToDeclaration (property.OverriddenProperty, doc.Project); + else + IdeApp.ProjectOperations.JumpToDeclaration (property.ExplicitInterfaceImplementations.First (), doc.Project); + break; + case SymbolKind.Event: + var evt = (IEventSymbol)symbol; + if (evt.OverriddenEvent != null) + IdeApp.ProjectOperations.JumpToDeclaration (evt.OverriddenEvent, doc.Project); + else + IdeApp.ProjectOperations.JumpToDeclaration (evt.ExplicitInterfaceImplementations.First (), doc.Project); + break; + case SymbolKind.Method: + var method = (IMethodSymbol)symbol; + if (method.OverriddenMethod != null) + IdeApp.ProjectOperations.JumpToDeclaration (method.OverriddenMethod, doc.Project); + else + IdeApp.ProjectOperations.JumpToDeclaration (method.ExplicitInterfaceImplementations.First (), doc.Project); + break; + } + } + } +} + diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/GotoDeclarationHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/GotoDeclarationHandler.cs new file mode 100644 index 0000000000..abc70cb939 --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/GotoDeclarationHandler.cs @@ -0,0 +1,109 @@ +// +// GotoDeclarationHandler.cs +// +// Author: +// Mike Krüger <mkrueger@novell.com> +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using MonoDevelop.Core; +using MonoDevelop.Ide.Gui; +using MonoDevelop.Components.Commands; +using MonoDevelop.Refactoring; +using MonoDevelop.Ide; +using Microsoft.CodeAnalysis; +using System.Collections.Immutable; +using System.Threading.Tasks; +using MonoDevelop.Ide.Editor; +using System.Threading; +using System; +using Microsoft.CodeAnalysis.CSharp; +using ICSharpCode.NRefactory6.CSharp.Features.GotoDefinition; +using Mono.Posix; +using MonoDevelop.Ide.TypeSystem; +using System.Collections.Generic; + +namespace MonoDevelop.CSharp.Refactoring +{ + class GotoDeclarationHandler : CommandHandler + { + static GotoDeclarationHandler () + { + GoToDefinitionService.TryNavigateToSymbol = delegate(ISymbol symbol, Microsoft.CodeAnalysis.Project project, bool usePreviewTab) { + IdeApp.ProjectOperations.JumpToDeclaration (symbol, TypeSystemService.GetMonoProject (project)); + return true; + }; + + GoToDefinitionService.TryNavigateToSpan = delegate(Workspace workspace, DocumentId documentId, Microsoft.CodeAnalysis.Text.TextSpan textSpan, bool usePreviewTab) { + var project = workspace.CurrentSolution.GetProject (documentId.ProjectId); + if (project == null) + return false; + + IdeApp.Workbench.OpenDocument (new FileOpenInformation (project.GetDocument (documentId).FilePath, TypeSystemService.GetMonoProject (project)) { + Offset = textSpan.Start + }); + return true; + }; + + GoToDefinitionService.DisplayMultiple = delegate(IEnumerable<Tuple<Solution, ISymbol, Location>> list) { + using (var monitor = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor (true, true)) { + foreach (var part in list) + monitor.ReportResult (GetJumpTypePartSearchResult (part.Item2, part.Item3)); + } + }; + } + + static MonoDevelop.Ide.FindInFiles.SearchResult GetJumpTypePartSearchResult (Microsoft.CodeAnalysis.ISymbol part, Microsoft.CodeAnalysis.Location location) + { + var provider = new MonoDevelop.Ide.FindInFiles.FileProvider (location.SourceTree.FilePath); + var doc = TextEditorFactory.CreateNewDocument (); + doc.Text = provider.ReadString (); + int position = location.SourceSpan.Start; + while (position + part.Name.Length < doc.Length) { + if (doc.GetTextAt (position, part.Name.Length) == part.Name) + break; + position++; + } + return new MonoDevelop.Ide.FindInFiles.SearchResult (provider, position, part.Name.Length); + } + + protected override void Run (object data) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null) + return; + Run (doc); + } + + public static void Run (MonoDevelop.Ide.Gui.Document doc) + { + GoToDefinitionService.TryGoToDefinition (doc.AnalysisDocument, doc.Editor.CaretOffset, default(CancellationToken)); + } + + public static void JumpToDeclaration (MonoDevelop.Ide.Gui.Document doc, RefactoringSymbolInfo info) + { + if (info.Symbol != null) + IdeApp.ProjectOperations.JumpToDeclaration (info.Symbol, doc.Project); + if (info.CandidateSymbols.Length > 0) + IdeApp.ProjectOperations.JumpToDeclaration (info.CandidateSymbols[0], doc.Project); + } + } +} diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/HelperMethods.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/HelperMethods.cs index 17de3d3aaa..20374b3452 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/HelperMethods.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/HelperMethods.cs @@ -1,76 +1,91 @@ -// -// HelperMethods.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2011 Xamarin Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using Mono.TextEditor; -using ICSharpCode.NRefactory.CSharp; -using MonoDevelop.Ide.Gui; -using MonoDevelop.Refactoring; - -namespace MonoDevelop.CSharp.Refactoring -{ - static class HelperMethods - { - public static TextReplaceChange GetRemoveNodeChange (this TextEditorData editor, AstNode n) - { - var change = new TextReplaceChange (); - change.FileName = editor.FileName; - change.Offset = editor.LocationToOffset (n.StartLocation); - change.RemovedChars = editor.LocationToOffset (n.EndLocation) - change.Offset; - - // remove EOL, when line is empty - var line = editor.GetLineByOffset (change.Offset); - if (line != null && line.Length == change.RemovedChars) - change.RemovedChars += line.DelimiterLength; - return change; - } - - public static ICSharpCode.NRefactory.CSharp.TextEditorOptions CreateNRefactoryTextEditorOptions (this TextEditorData doc) - { - return new ICSharpCode.NRefactory.CSharp.TextEditorOptions () { - TabsToSpaces = doc.TabsToSpaces, - TabSize = doc.Options.TabSize, - IndentSize = doc.Options.IndentationSize, - ContinuationIndent = doc.Options.IndentationSize, - LabelIndent = -doc.Options.IndentationSize, - EolMarker = doc.EolMarker, - IndentBlankLines = doc.Options.IndentStyle != IndentStyle.Virtual, - WrapLineLength = doc.Options.RulerColumn - }; - } - - public static void RemoveNode (this TextEditorData editor, AstNode n) - { - var change = editor.GetRemoveNodeChange (n); - editor.Remove (change.Offset, change.RemovedChars); - } - public static void Replace (this TextEditorData editor, AstNode n, AstNode replaceWith) - { - var change = editor.GetRemoveNodeChange (n); - editor.Replace (change.Offset, change.RemovedChars, replaceWith.ToString ()); - } - } -} - +//// +//// HelperMethods.cs +//// +//// Author: +//// Mike Krüger <mkrueger@xamarin.com> +//// +//// Copyright (c) 2011 Xamarin Inc. +//// +//// Permission is hereby granted, free of charge, to any person obtaining a copy +//// of this software and associated documentation files (the "Software"), to deal +//// in the Software without restriction, including without limitation the rights +//// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//// copies of the Software, and to permit persons to whom the Software is +//// furnished to do so, subject to the following conditions: +//// +//// The above copyright notice and this permission notice shall be included in +//// all copies or substantial portions of the Software. +//// +//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +//// THE SOFTWARE. +//using System; +//using ICSharpCode.NRefactory.CSharp; +//using MonoDevelop.Ide.Gui; +//using MonoDevelop.Refactoring; +//using MonoDevelop.Ide.Editor; +// +//namespace MonoDevelop.CSharp.Refactoring +//{ +// static class HelperMethods +// { +// public static TextReplaceChange GetRemoveNodeChange (this IReadonlyTextDocument editor, AstNode n) +// { +// var change = new TextReplaceChange (); +// change.FileName = editor.FileName; +// change.Offset = editor.LocationToOffset (n.StartLocation); +// change.RemovedChars = editor.LocationToOffset (n.EndLocation) - change.Offset; +// +// // remove EOL, when line is empty +// var line = editor.GetLineByOffset (change.Offset); +// if (line != null && line.Length == change.RemovedChars) +// change.RemovedChars += line.DelimiterLength; +// return change; +// } +// +// public static ICSharpCode.NRefactory.CSharp.TextEditorOptions CreateNRefactoryTextEditorOptions (this IReadonlyTextDocument doc, MonoDevelop.CSharp.Formatting.CSharpFormattingPolicy policy, MonoDevelop.Ide.Gui.Content.TextStylePolicy textPolicy) +// { +// return new ICSharpCode.NRefactory.CSharp.TextEditorOptions () { +// TabsToSpaces = textPolicy.TabsToSpaces, +// TabSize = textPolicy.TabWidth, +// IndentSize = textPolicy.IndentWidth, +// ContinuationIndent = textPolicy.IndentWidth, +// LabelIndent = -textPolicy.IndentWidth, +// EolMarker = doc.GetEolMarker (), +// IndentBlankLines = DefaultSourceEditorOptions.Instance.IndentStyle != IndentStyle.Virtual, +// WrapLineLength = DefaultSourceEditorOptions.Instance.RulerColumn +// }; +// } +// +// public static ICSharpCode.NRefactory.CSharp.TextEditorOptions CreateNRefactoryTextEditorOptions (this TextEditor doc) +// { +// return new ICSharpCode.NRefactory.CSharp.TextEditorOptions () { +// TabsToSpaces = doc.Options.TabsToSpaces, +// TabSize = doc.Options.TabSize, +// IndentSize = doc.Options.IndentationSize, +// ContinuationIndent = doc.Options.IndentationSize, +// LabelIndent = -doc.Options.IndentationSize, +// EolMarker = doc.EolMarker, +// IndentBlankLines = doc.Options.IndentStyle != IndentStyle.Virtual, +// WrapLineLength = doc.Options.RulerColumn +// }; +// } +// +// public static void RemoveNode (this ITextDocument editor, AstNode n) +// { +// var change = editor.GetRemoveNodeChange (n); +// editor.RemoveText (change.Offset, change.RemovedChars); +// } +// +// public static void Replace (this ITextDocument editor, AstNode n, AstNode replaceWith) +// { +// var change = editor.GetRemoveNodeChange (n); +// editor.ReplaceText (change.Offset, change.RemovedChars, replaceWith.ToString ()); +// } +// } +//} +// diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/RefactoryCommands.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/RefactoryCommands.cs new file mode 100644 index 0000000000..db00f7d3c4 --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/RefactoryCommands.cs @@ -0,0 +1,229 @@ +// +// RefactoryCommands.cs +// +// Author: +// Lluis Sanchez Gual +// +// Copyright (C) 2006 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +using MonoDevelop.Core; +using MonoDevelop.Ide.Gui; +using MonoDevelop.Components.Commands; +using MonoDevelop.Ide; +using System.Linq; +using Microsoft.CodeAnalysis; +using MonoDevelop.Ide.Editor; +using MonoDevelop.CodeActions; +using MonoDevelop.CodeIssues; +using MonoDevelop.CSharp.Refactoring; +using MonoDevelop.Refactoring; + +namespace MonoDevelop.CSharp.Refactoring +{ + sealed class CurrentRefactoryOperationsHandler : CommandHandler + { + protected override void Run (object dataItem) + { + var del = (Action) dataItem; + if (del != null) + del (); + } + + static CommandInfoSet CreateFixMenu (TextEditor editor, DocumentContext ctx, CodeActionContainer container) + { + if (editor == null) + throw new ArgumentNullException ("editor"); + if (ctx == null) + throw new ArgumentNullException ("ctx"); + if (container == null) + throw new ArgumentNullException ("container"); + var result = new CommandInfoSet (); + result.Text = GettextCatalog.GetString ("Fix"); + foreach (var diagnostic in container.CodeFixActions) { + var info = new CommandInfo (diagnostic.CodeAction.Title); + result.CommandInfos.Add (info, new Action (new CodeActionEditorExtension.ContextActionRunner (diagnostic.CodeAction, editor, ctx).Run)); + } + if (result.CommandInfos.Count == 0) + return result; + bool firstDiagnosticOption = true; + foreach (var fix in container.DiagnosticsAtCaret) { + + var inspector = BuiltInCodeDiagnosticProvider.GetCodeDiagnosticDescriptor (fix.Id); + if (inspector == null) + continue; + + if (firstDiagnosticOption) { + result.CommandInfos.AddSeparator (); + firstDiagnosticOption = false; + } + + var label = GettextCatalog.GetString ("_Options for \"{0}\"", fix.GetMessage ()); + var subMenu = new CommandInfoSet (); + subMenu.Text = label; + +// if (inspector.CanSuppressWithAttribute) { +// var menuItem = new FixMenuEntry (GettextCatalog.GetString ("_Suppress with attribute"), +// delegate { +// +// inspector.SuppressWithAttribute (Editor, DocumentContext, GetTextSpan (fix.Item2)); +// }); +// subMenu.Add (menuItem); +// } + + if (inspector.CanDisableWithPragma) { + var info = new CommandInfo (GettextCatalog.GetString ("_Suppress with #pragma")); + subMenu.CommandInfos.Add (info, new Action (() => inspector.DisableWithPragma (editor, ctx, fix.Location.SourceSpan))); + } + + var configInfo = new CommandInfo (GettextCatalog.GetString ("_Configure Rule")); + subMenu.CommandInfos.Add (configInfo, new Action (() => { + IdeApp.Workbench.ShowGlobalPreferencesDialog (null, "C#", dialog => { + var panel = dialog.GetPanel<CodeIssuePanel> ("C#"); + if (panel == null) + return; + panel.Widget.SelectCodeIssue (inspector.IdString); + }); + })); + + result.CommandInfos.Add (subMenu); + } + + return result; + } + + protected override void Update (CommandArrayInfo ainfo) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null || doc.ParsedDocument == null) + return; + var semanticModel = doc.ParsedDocument.GetAst<SemanticModel> (); + if (semanticModel == null) + return; + var info = RefactoringSymbolInfo.GetSymbolInfoAsync (doc, doc.Editor.CaretOffset).Result; + bool added = false; + + var ext = doc.GetContent<CodeActionEditorExtension> (); + + if (ext != null && !ext.GetCurrentFixes ().IsEmpty) { + var fixMenu = CreateFixMenu (doc.Editor, doc, ext.GetCurrentFixes ()); + if (fixMenu.CommandInfos.Count > 0) { + ainfo.Add (fixMenu, null); + added = true; + } + } + var ciset = new CommandInfoSet (); + ciset.Text = GettextCatalog.GetString ("Refactor"); + + bool canRename = RenameHandler.CanRename (info.Symbol ?? info.DeclaredSymbol); + if (canRename) { + ciset.CommandInfos.Add (IdeApp.CommandService.GetCommandInfo (MonoDevelop.Ide.Commands.EditCommands.Rename), new Action (delegate { + new MonoDevelop.Refactoring.Rename.RenameRefactoring ().Rename (info.Symbol ?? info.DeclaredSymbol); + })); + added = true; + } + bool first = true; + if (ext != null) { + foreach (var fix in ext.GetCurrentFixes ().CodeRefactoringActions) { + if (added & first && ciset.CommandInfos.Count > 0) + ciset.CommandInfos.AddSeparator (); + var info2 = new CommandInfo (fix.CodeAction.Title); + ciset.CommandInfos.Add (info2, new Action (new CodeActionEditorExtension.ContextActionRunner (fix.CodeAction, doc.Editor, doc).Run)); + added = true; + first = false; + } + } + + if (ciset.CommandInfos.Count > 0) { + ainfo.Add (ciset, null); + added = true; + } + + if (IdeApp.ProjectOperations.CanJumpToDeclaration (info.Symbol) || info.Symbol == null && IdeApp.ProjectOperations.CanJumpToDeclaration (info.CandidateSymbols.FirstOrDefault ())) { + var type = (info.Symbol ?? info.CandidateSymbols.FirstOrDefault ()) as INamedTypeSymbol; + if (type != null && type.Locations.Length > 1) { + var declSet = new CommandInfoSet (); + declSet.Text = GettextCatalog.GetString ("_Go to Declaration"); + foreach (var part in type.Locations) { + var loc = part.GetLineSpan (); + declSet.CommandInfos.Add (string.Format (GettextCatalog.GetString ("{0}, Line {1}"), FormatFileName (part.SourceTree.FilePath), loc.StartLinePosition.Line + 1), new Action (() => IdeApp.ProjectOperations.JumpTo (type, part, doc.Project))); + } + ainfo.Add (declSet); + } else { + ainfo.Add (IdeApp.CommandService.GetCommandInfo (RefactoryCommands.GotoDeclaration), new Action (() => GotoDeclarationHandler.Run (doc))); + } + added = true; + } + + + if (info.DeclaredSymbol != null && GotoBaseDeclarationHandler.CanGotoBase (info.DeclaredSymbol)) { + ainfo.Add (GotoBaseDeclarationHandler.GetDescription (info.DeclaredSymbol), new Action (() => GotoBaseDeclarationHandler.GotoBase (doc, info.DeclaredSymbol))); + added = true; + } + + var sym = info.Symbol ?? info.DeclaredSymbol; + if (doc.HasProject && sym != null) { + ainfo.Add (IdeApp.CommandService.GetCommandInfo (RefactoryCommands.FindReferences), new System.Action (() => FindReferencesHandler.FindRefs (sym))); + try { + if (Microsoft.CodeAnalysis.FindSymbols.SymbolFinder.FindSimilarSymbols (sym, semanticModel.Compilation).Count () > 1) + ainfo.Add (IdeApp.CommandService.GetCommandInfo (RefactoryCommands.FindAllReferences), new System.Action (() => FindAllReferencesHandler.FindRefs (info.Symbol, semanticModel.Compilation))); + } catch (Exception) { + // silently ignore roslyn bug. + } + } + added = true; + + if (info.DeclaredSymbol != null) { + string description; + if (FindDerivedSymbolsHandler.CanFindDerivedSymbols (info.DeclaredSymbol, out description)) { + ainfo.Add (description, new Action (() => FindDerivedSymbolsHandler.FindDerivedSymbols (info.DeclaredSymbol))); + added = true; + } + + if (FindMemberOverloadsHandler.CanFindMemberOverloads (info.DeclaredSymbol, out description)) { + ainfo.Add (description, new Action (() => FindMemberOverloadsHandler.FindOverloads (info.DeclaredSymbol))); + added = true; + } + + if (FindExtensionMethodHandler.CanFindExtensionMethods (info.DeclaredSymbol, out description)) { + ainfo.Add (description, new Action (() => FindExtensionMethodHandler.FindExtensionMethods (info.DeclaredSymbol))); + added = true; + } + } + } + + static string FormatFileName (string fileName) + { + if (fileName == null) + return null; + char[] seperators = { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; + int idx = fileName.LastIndexOfAny (seperators); + if (idx > 0) + idx = fileName.LastIndexOfAny (seperators, idx - 1); + if (idx > 0) + return "..." + fileName.Substring (idx); + return fileName; + } + } +} diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/RenameHandler.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/RenameHandler.cs new file mode 100644 index 0000000000..7f38f5d085 --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/RenameHandler.cs @@ -0,0 +1,96 @@ +// +// RenameHandler.cs +// +// Author: +// Mike Krüger <mkrueger@novell.com> +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using MonoDevelop.Components.Commands; +using MonoDevelop.Ide.Gui; +using MonoDevelop.Ide.Gui.Content; +using MonoDevelop.Ide; +using MonoDevelop.Core; +using Microsoft.CodeAnalysis; +using MonoDevelop.Ide.Editor; +using System.Linq; +using ICSharpCode.NRefactory6.CSharp; +using MonoDevelop.Refactoring; +using MonoDevelop.Refactoring.Rename; + +namespace MonoDevelop.CSharp.Refactoring +{ + class RenameHandler : CommandHandler + { + public void UpdateCommandInfo (CommandInfo ci) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null) + return; + if (doc.ParsedDocument == null || doc.ParsedDocument.GetAst<SemanticModel> () == null) { + ci.Enabled = false; + } + var info = RefactoringSymbolInfo.GetSymbolInfoAsync (doc, doc.Editor.CaretOffset).Result; + var sym = info.DeclaredSymbol ?? info.Symbol; + if (!CanRename (sym)) + ci.Bypass = true; + } + + internal static bool CanRename (ISymbol symbol) + { + if (symbol == null || symbol.IsDefinedInMetadata ()) + return false; + switch (symbol.Kind) { + case SymbolKind.Local: + case SymbolKind.Parameter: + case SymbolKind.NamedType: + case SymbolKind.Namespace: + case SymbolKind.Method: + case SymbolKind.Field: + case SymbolKind.Property: + case SymbolKind.Event: + case SymbolKind.Label: + case SymbolKind.TypeParameter: + case SymbolKind.RangeVariable: + return true; + } + return false; + } + + protected override void Run (object data) + { + var doc = IdeApp.Workbench.ActiveDocument; + if (doc == null || doc.FileName == FilePath.Null) + return; + Run (doc.Editor, doc); + } + + internal void Run (TextEditor editor, DocumentContext ctx) + { + var info = RefactoringSymbolInfo.GetSymbolInfoAsync (ctx, editor.CaretOffset).Result; + var sym = info.DeclaredSymbol ?? info.Symbol; + if (!CanRename (sym)) + return; + new RenameRefactoring ().Rename (sym); + } + } +} |