// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using CSharpBinding.FormattingStrategy; using CSharpBinding.Parser; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor.CodeCompletion; namespace CSharpBinding.Completion { /// /// Item for 'override' completion. /// class OverrideCompletionData : EntityCompletionData { protected readonly int declarationBegin; protected readonly CSharpTypeResolveContext contextAtCaret; public OverrideCompletionData(int declarationBegin, IMember m, CSharpTypeResolveContext contextAtCaret) : base(m) { this.declarationBegin = declarationBegin; this.contextAtCaret = contextAtCaret; var ambience = new CSharpAmbience(); ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList | ConversionFlags.ShowParameterList | ConversionFlags.ShowParameterNames; this.CompletionText = ambience.ConvertEntity(m); } public override void Complete(CompletionContext context) { if (declarationBegin > context.StartOffset) { base.Complete(context); return; } TypeSystemAstBuilder b = new TypeSystemAstBuilder(new CSharpResolver(contextAtCaret)); b.ShowTypeParameterConstraints = false; b.GenerateBody = true; var entityDeclaration = b.ConvertEntity(this.Entity); entityDeclaration.Modifiers &= ~(Modifiers.Virtual | Modifiers.Abstract); entityDeclaration.Modifiers |= Modifiers.Override; if (!this.Entity.IsAbstract) { // modify body to call the base method if (this.Entity.SymbolKind == SymbolKind.Method) { var baseCall = new BaseReferenceExpression().Invoke(this.Entity.Name, ParametersToExpressions(this.Entity)); var body = entityDeclaration.GetChildByRole(Roles.Body); body.Statements.Clear(); if (((IMethod)this.Entity).ReturnType.IsKnownType(KnownTypeCode.Void)) body.Statements.Add(new ExpressionStatement(baseCall)); else body.Statements.Add(new ReturnStatement(baseCall)); } else if (this.Entity.SymbolKind == SymbolKind.Indexer || this.Entity.SymbolKind == SymbolKind.Property) { Expression baseCall; if (this.Entity.SymbolKind == SymbolKind.Indexer) baseCall = new BaseReferenceExpression().Indexer(ParametersToExpressions(this.Entity)); else baseCall = new BaseReferenceExpression().Member(this.Entity.Name); var getterBody = entityDeclaration.GetChildByRole(PropertyDeclaration.GetterRole).Body; if (!getterBody.IsNull) { getterBody.Statements.Clear(); getterBody.Add(new ReturnStatement(baseCall.Clone())); } var setterBody = entityDeclaration.GetChildByRole(PropertyDeclaration.SetterRole).Body; if (!setterBody.IsNull) { setterBody.Statements.Clear(); setterBody.Add(new AssignmentExpression(baseCall.Clone(), new IdentifierExpression("value"))); } } } var document = context.Editor.Document; StringWriter w = new StringWriter(); var formattingOptions = FormattingOptionsFactory.CreateSharpDevelop(); var segmentDict = SegmentTrackingOutputFormatter.WriteNode(w, entityDeclaration, formattingOptions, context.Editor.Options); using (document.OpenUndoGroup()) { string newText = w.ToString().TrimEnd(); document.Replace(declarationBegin, context.EndOffset - declarationBegin, newText); var throwStatement = entityDeclaration.Descendants.FirstOrDefault(n => n is ThrowStatement); if (throwStatement != null) { var segment = segmentDict[throwStatement]; context.Editor.Select(declarationBegin + segment.Offset, segment.Length); } CSharpFormatterHelper.Format(context.Editor, declarationBegin, newText.Length, formattingOptions); } } IEnumerable ParametersToExpressions(IEntity entity) { foreach (var p in ((IParameterizedMember)entity).Parameters) { if (p.IsRef || p.IsOut) yield return new DirectionExpression(p.IsOut ? FieldDirection.Out : FieldDirection.Ref, new IdentifierExpression(p.Name)); else yield return new IdentifierExpression(p.Name); } } } }