Browse Source

implemented more methods in CSharpCodeGenerator + Tests and added back SuppressMessageCommand

newNRvisualizers
Siegfried Pammer 13 years ago
parent
commit
4802c70556
  1. 124
      src/AddIns/Analysis/CodeAnalysis/Src/SuppressMessageCommand.cs
  2. 81
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpCodeGenerator.cs
  3. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs
  4. 1
      src/AddIns/BackendBindings/CSharpBinding/Tests/CSharpBinding.Tests.csproj
  5. 340
      src/AddIns/BackendBindings/CSharpBinding/Tests/CSharpCodeGeneratorTests.cs
  6. 2
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/AbstractEventHandlerService.cs
  7. 2
      src/Main/Base/Project/Refactoring/ICodeGenerator.cs

124
src/AddIns/Analysis/CodeAnalysis/Src/SuppressMessageCommand.cs

@ -7,8 +7,12 @@ using System.IO; @@ -7,8 +7,12 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Documents;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
@ -25,57 +29,42 @@ namespace ICSharpCode.CodeAnalysis @@ -25,57 +29,42 @@ namespace ICSharpCode.CodeAnalysis
FxCopTaskTag tag = t.Tag as FxCopTaskTag;
if (tag == null)
continue;
throw new NotImplementedException();
/*CodeGenerator codegen = tag.ProjectContent.Language.CodeGenerator;
if (codegen == null)
continue;
FilePosition p;
ICodeGenerator gen = tag.Project.CodeGenerator;
ICompilation compilation;
if (t.FileName != null)
compilation = SD.ParserService.GetCompilationForFile(t.FileName);
else
compilation = SD.ParserService.GetCompilation(tag.Project);
IAttribute attribute = CreateSuppressAttribute(compilation, tag);
if (tag.MemberName == null)
p = GetAssemblyAttributeInsertionPosition(tag.ProjectContent);
gen.AddAssemblyAttribute(attribute);
else
p = GetPosition(tag.ProjectContent, tag.TypeName, tag.MemberName);
if (p.CompilationUnit == null || p.FileName == null || p.Line <= 0)
continue;
IViewContent viewContent = FileService.OpenFile(p.FileName);
ITextEditorProvider provider = viewContent as ITextEditorProvider;
if (provider == null)
continue;
IDocument document = provider.TextEditor.Document;
if (p.Line >= document.TotalNumberOfLines)
continue;
IDocumentLine line = document.GetLine(p.Line);
StringBuilder indentation = new StringBuilder();
for (int i = line.Offset; i < document.TextLength; i++) {
char c = document.GetCharAt(i);
if (c == ' ' || c == '\t')
indentation.Append(c);
else
break;
}
string code = codegen.GenerateCode(CreateSuppressAttribute(p.CompilationUnit, tag), indentation.ToString());
if (!code.EndsWith("\n")) code += Environment.NewLine;
document.Insert(line.Offset, code);
provider.TextEditor.JumpTo(p.Line, p.Column);
TaskService.Remove(t);
ParserService.ParseViewContent(viewContent);*/
gen.AddAttribute(GetEntity(compilation, tag.TypeName, tag.MemberName), attribute);
}
}
internal static DomRegion GetPosition(ICompilation compilation, string className, string memberName)
{
IEntity entity = GetEntity(compilation, className, memberName);
return entity == null ? DomRegion.Empty : entity.Region;
}
static IEntity GetEntity(ICompilation compilation, string className, string memberName)
{
var typeName = new TopLevelTypeName(className);
ITypeDefinition type = compilation.MainAssembly.GetTypeDefinition(typeName);
if (type != null) {
if (string.IsNullOrEmpty(memberName))
return type.Region;
return type;
IMember m = GetMember(type, memberName);
if (m != null)
return m.Region;
return m;
return type.Region;
return type;
}
return DomRegion.Empty;
return null;
}
static IMember GetMember(ITypeDefinition type, string memberName)
@ -84,62 +73,25 @@ namespace ICSharpCode.CodeAnalysis @@ -84,62 +73,25 @@ namespace ICSharpCode.CodeAnalysis
return type.GetMembers(m => m.ReflectionName == fullName).FirstOrDefault();
}
/*
FilePosition GetAssemblyAttributeInsertionPosition(IProjectContent pc)
{
FilePosition best = FilePosition.Empty;
foreach (IAttribute attrib in pc.GetAssemblyAttributes()) {
ICompilationUnit cu = attrib.CompilationUnit;
if (cu != null && !attrib.Region.IsEmpty) {
var newPos = new FilePosition(cu, attrib.Region.BeginLine, attrib.Region.BeginColumn);
if (IsBetterAssemblyAttributeInsertionPosition(newPos, best)) {
best = newPos;
}
}
}
return best;
}
const string FullAttributeName = "System.Diagnostics.CodeAnalysis.SuppressMessageAttribute";
bool IsBetterAssemblyAttributeInsertionPosition(FilePosition a, FilePosition b)
static IAttribute CreateSuppressAttribute(ICompilation compilation, FxCopTaskTag tag)
{
if (b.IsEmpty)
return true;
bool aIsAssemblyInfo = "AssemblyInfo".Equals(Path.GetFileNameWithoutExtension(a.FileName), StringComparison.OrdinalIgnoreCase);
bool bIsAssemblyInfo = "AssemblyInfo".Equals(Path.GetFileNameWithoutExtension(b.FileName), StringComparison.OrdinalIgnoreCase);
if (aIsAssemblyInfo && !bIsAssemblyInfo)
return true;
if (!aIsAssemblyInfo && bIsAssemblyInfo)
return false;
return a.Line > b.Line;
}*/
const string NamespaceName = "System.Diagnostics.CodeAnalysis";
const string AttributeName = "SuppressMessage";
/*
static Ast.AbstractNode CreateSuppressAttribute(ICompilationUnit cu, FxCopTaskTag tag)
{
//System.Diagnostics.CodeAnalysis.SuppressMessageAttribute
bool importedCodeAnalysis = CheckImports(cu);
// [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId:="fileIdentifier"]
Ast.Attribute a = new Ast.Attribute {
Name = importedCodeAnalysis ? AttributeName : NamespaceName + "." + AttributeName,
PositionalArguments = {
new Ast.PrimitiveExpression(tag.Category, tag.Category),
new Ast.PrimitiveExpression(tag.CheckID, tag.CheckID)
}
};
IType attributeType = compilation.FindType(new FullTypeName(FullAttributeName));
IType stringType = compilation.FindType(KnownTypeCode.String);
KeyValuePair<IMember, ResolveResult>[] namedArgs = null;
if (tag.MessageID != null) {
a.NamedArguments.Add(new Ast.NamedArgumentExpression("MessageId",
new Ast.PrimitiveExpression(tag.MessageID, tag.MessageID)));
IMember messageId = attributeType.GetProperties(p => p.Name == "MessageId").FirstOrDefault();
namedArgs = new[] { new KeyValuePair<IMember, ResolveResult>(messageId, new ConstantResolveResult(stringType, tag.MessageID)) };
}
return new Ast.AttributeSection {
AttributeTarget = tag.MemberName == null ? "assembly" : null,
Attributes = { a }
};
}*/
return new DefaultAttribute(
attributeType, new[] {
new ConstantResolveResult(stringType, tag.Category),
new ConstantResolveResult(stringType, tag.CheckID)
}, namedArgs);
}
}
}

81
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpCodeGenerator.cs

@ -7,6 +7,7 @@ using System.Linq; @@ -7,6 +7,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Media.Animation;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
@ -29,10 +30,10 @@ namespace CSharpBinding.Refactoring @@ -29,10 +30,10 @@ namespace CSharpBinding.Refactoring
/// </summary>
public class CSharpCodeGenerator : ICodeGenerator
{
CSharpProject project;
IProject project;
ProjectEntityModelContext model;
public CSharpCodeGenerator(CSharpProject project)
public CSharpCodeGenerator(IProject project)
{
if (project == null)
throw new ArgumentNullException("project");
@ -42,15 +43,22 @@ namespace CSharpBinding.Refactoring @@ -42,15 +43,22 @@ namespace CSharpBinding.Refactoring
public void AddAttribute(IEntity target, IAttribute attribute)
{
var view = SD.FileService.OpenFile(new FileName(target.Region.FileName), false);
var editor = view.GetRequiredService<ITextEditor>();
var context = SDRefactoringContext.Create(editor, CancellationToken.None);
var node = context.RootNode.GetNodeAt<EntityDeclaration>(target.Region.Begin);
var resolver = context.GetResolverStateBefore(node);
var builder = new TypeSystemAstBuilder(resolver);
editor.Document.Insert(editor.Document.GetOffset(target.BodyRegion.Begin),
PrintAst(builder.ConvertAttribute(attribute)));
AddAttribute(target.Region, attribute);
}
public void AddAssemblyAttribute(IAttribute attribute)
{
// FIXME : will fail if there are no assembly attributes
ICompilation compilation = SD.ParserService.GetCompilation(project);
IAttribute target = compilation.MainAssembly.AssemblyAttributes.LastOrDefault();
if (target == null)
throw new InvalidOperationException("no assembly attributes found, cannot continue!");
AddAttribute(target.Region, attribute, "assembly");
}
public void AddReturnTypeAttribute(IMethod target, IAttribute attribute)
{
AddAttribute(target.Region, attribute, "return");
}
public void InsertEventHandler(ITypeDefinition target, string name, IEvent eventDefinition, bool jumpTo)
@ -69,25 +77,52 @@ namespace CSharpBinding.Refactoring @@ -69,25 +77,52 @@ namespace CSharpBinding.Refactoring
var view = SD.FileService.OpenFile(new FileName(match.Region.FileName), jumpTo);
var editor = view.GetRequiredService<ITextEditor>();
var context = SDRefactoringContext.Create(editor, CancellationToken.None);
var last = match.Members.LastOrDefault() ?? (IUnresolvedEntity)match;
var context = SDRefactoringContext.Create(editor.FileName, editor.Document, last.BodyRegion.End, CancellationToken.None);
IEntity last = (IEntity)target.GetMembers().LastOrDefault() ?? (IEntity)target;
var node = context.RootNode.GetNodeAt<EntityDeclaration>(last.Region.Begin);
var resolver = context.GetResolverStateAfter(node);
var builder = new TypeSystemAstBuilder(resolver);
var delegateDecl = builder.ConvertEntity(eventDefinition.ReturnType.GetDefinition()) as DelegateDeclaration;
if (delegateDecl == null) return;
var decl = new MethodDeclaration() {
ReturnType = delegateDecl.ReturnType.Clone(),
Name = name,
Body = new BlockStatement() {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
};
var param = delegateDecl.Parameters.Select(p => p.Clone()).OfType<ParameterDeclaration>().ToArray();
decl.Parameters.AddRange(param);
#warning implement code generation!
string eventHandler = "<generated code>";
editor.Document.Insert(editor.Document.GetOffset(target.Region.End), eventHandler);
using (Script script = context.StartScript()) {
// FIXME : will not work properly if there are no members.
if (last == match) {
throw new NotImplementedException();
// TODO InsertWithCursor not implemented!
//script.InsertWithCursor("Insert event handler", Script.InsertPosition.End, decl).RunSynchronously();
} else {
script.InsertAfter(node, decl);
}
}
}
string PrintAst(AstNode node)
void AddAttribute(DomRegion region, IAttribute attribute, string target = "")
{
StringBuilder sb = new StringBuilder();
CSharpOutputVisitor visitor = new CSharpOutputVisitor(new StringWriter(sb), FormattingOptionsFactory.CreateSharpDevelop());
node.AcceptVisitor(visitor);
return sb.ToString();
var view = SD.FileService.OpenFile(new FileName(region.FileName), false);
var editor = view.GetRequiredService<ITextEditor>();
var context = SDRefactoringContext.Create(editor.FileName, editor.Document, region.Begin, CancellationToken.None);
var node = context.RootNode.GetNodeAt<AstNode>(region.Begin);
if (node is ICSharpCode.NRefactory.CSharp.Attribute) node = node.Parent;
var resolver = context.GetResolverStateBefore(node);
var builder = new TypeSystemAstBuilder(resolver);
using (Script script = context.StartScript()) {
var attr = new AttributeSection();
attr.AttributeTarget = target;
attr.Attributes.Add(builder.ConvertAttribute(attribute));
script.InsertBefore(node, attr);
}
}
}
}

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs

@ -47,7 +47,7 @@ namespace CSharpBinding.Refactoring @@ -47,7 +47,7 @@ namespace CSharpBinding.Refactoring
// create dummy refactoring context
resolver = new CSharpAstResolver(compilation, new SyntaxTree());
}
var context = new SDRefactoringContext(textSource, resolver, new TextLocation(0, 0), 0, 0, cancellationToken);
var context = new SDRefactoringContext(textSource, resolver, location, 0, 0, cancellationToken);
return context;
}

1
src/AddIns/BackendBindings/CSharpBinding/Tests/CSharpBinding.Tests.csproj

@ -69,6 +69,7 @@ @@ -69,6 +69,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CSharpCodeGeneratorTests.cs" />
<Compile Include="CSharpFormattingTests.cs" />
<Compile Include="RegistrationTests.cs" />
<Compile Include="MockTextEditor.cs" />

340
src/AddIns/BackendBindings/CSharpBinding/Tests/CSharpCodeGeneratorTests.cs

@ -0,0 +1,340 @@ @@ -0,0 +1,340 @@
// 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 CSharpBinding.Completion;
using CSharpBinding.Parser;
using CSharpBinding.Refactoring;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using System;
using System.Linq;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Workbench;
using NUnit.Framework;
using Rhino.Mocks;
namespace CSharpBinding.Tests
{
[TestFixture]
public class CSharpCodeGeneratorTests
{
string program = @"using System;
using System.Reflection;
[assembly: AssemblyTitle(""CSharpBinding.Tests"")]
class MySimpleAttribute : Attribute {}
class TargetClass
{
void TargetA()
{
}
public int TargetB { get; set; }
public int TargetC_ {
get {
return 0;
}
}
}
interface TargetInterface
{
}
";
MockTextEditor textEditor;
CSharpCodeGenerator gen;
static readonly IUnresolvedAssembly Corlib = new CecilLoader().LoadAssemblyFile(typeof(object).Assembly.Location);
[SetUp]
public void SetUp()
{
SD.InitializeForUnitTests();
textEditor = new MockTextEditor();
textEditor.Document.Text = program;
var parseInfo = textEditor.CreateParseInformation();
IProject project = MockRepository.GenerateStrictMock<IProject>();
var pc = new CSharpProjectContent().AddOrUpdateFiles(parseInfo.UnresolvedFile);
pc = pc.AddAssemblyReferences(new[] { Corlib });
var compilation = pc.CreateCompilation();
SD.Services.AddService(typeof(IParserService), MockRepository.GenerateStrictMock<IParserService>());
SD.ParserService.Stub(p => p.GetCachedParseInformation(textEditor.FileName)).Return(parseInfo);
SD.ParserService.Stub(p => p.GetCompilation(project)).Return(compilation);
SD.ParserService.Stub(p => p.GetCompilationForFile(textEditor.FileName)).Return(compilation);
SD.ParserService.Stub(p => p.Parse(textEditor.FileName, textEditor.Document)).WhenCalled(
i => {
var syntaxTree = new CSharpParser().Parse(textEditor.Document, textEditor.FileName);
i.ReturnValue = new CSharpFullParseInformation(syntaxTree.ToTypeSystem(), null, syntaxTree);
}).Return(parseInfo); // fake Return to make it work
SD.Services.AddService(typeof(IFileService), MockRepository.GenerateStrictMock<IFileService>());
IViewContent view = MockRepository.GenerateStrictMock<IViewContent>();
view.Stub(v => v.GetService(typeof(ITextEditor))).Return(textEditor);
SD.FileService.Stub(f => f.OpenFile(textEditor.FileName, false)).Return(view);
gen = new CSharpCodeGenerator(project);
}
[TearDown]
public void TearDown()
{
SD.TearDownForUnitTests();
}
[Test]
public void AddSimpleAttributeToClass()
{
var compilation = SD.ParserService.GetCompilationForFile(textEditor.FileName);
var entity = FindEntity<ITypeDefinition>("TargetClass");
var attribute = compilation.FindType(new FullTypeName("MySimpleAttribute"));
gen.AddAttribute(entity, new DefaultAttribute(attribute));
Assert.AreEqual(@"using System;
using System.Reflection;
[assembly: AssemblyTitle(""CSharpBinding.Tests"")]
class MySimpleAttribute : Attribute {}
[MySimple]
class TargetClass
{
void TargetA()
{
}
public int TargetB { get; set; }
public int TargetC_ {
get {
return 0;
}
}
}
interface TargetInterface
{
}
", textEditor.Document.Text);
}
[Test]
public void AddSimpleAttributeToMethod()
{
var compilation = SD.ParserService.GetCompilationForFile(textEditor.FileName);
var entity = FindEntity<IMethod>("TargetA");
var attribute = compilation.FindType(new FullTypeName("MySimpleAttribute"));
gen.AddAttribute(entity, new DefaultAttribute(attribute));
Assert.AreEqual(@"using System;
using System.Reflection;
[assembly: AssemblyTitle(""CSharpBinding.Tests"")]
class MySimpleAttribute : Attribute {}
class TargetClass
{
[MySimple]
void TargetA()
{
}
public int TargetB { get; set; }
public int TargetC_ {
get {
return 0;
}
}
}
interface TargetInterface
{
}
", textEditor.Document.Text);
}
[Test]
public void AddSimpleAttributeToInterface()
{
var compilation = SD.ParserService.GetCompilationForFile(textEditor.FileName);
var entity = FindEntity<ITypeDefinition>("TargetInterface");
var attribute = compilation.FindType(new FullTypeName("MySimpleAttribute"));
gen.AddAttribute(entity, new DefaultAttribute(attribute));
Assert.AreEqual(@"using System;
using System.Reflection;
[assembly: AssemblyTitle(""CSharpBinding.Tests"")]
class MySimpleAttribute : Attribute {}
class TargetClass
{
void TargetA()
{
}
public int TargetB { get; set; }
public int TargetC_ {
get {
return 0;
}
}
}
[MySimple]
interface TargetInterface
{
}
", textEditor.Document.Text);
}
[Test]
public void AddSimpleAttributeToProperty()
{
var compilation = SD.ParserService.GetCompilationForFile(textEditor.FileName);
var entity = FindEntity<IProperty>("TargetB");
var attribute = compilation.FindType(new FullTypeName("MySimpleAttribute"));
gen.AddAttribute(entity, new DefaultAttribute(attribute));
Assert.AreEqual(@"using System;
using System.Reflection;
[assembly: AssemblyTitle(""CSharpBinding.Tests"")]
class MySimpleAttribute : Attribute {}
class TargetClass
{
void TargetA()
{
}
[MySimple]
public int TargetB { get; set; }
public int TargetC_ {
get {
return 0;
}
}
}
interface TargetInterface
{
}
", textEditor.Document.Text);
}
[Test]
public void AddSimpleAttributeToPropertyGetter()
{
var compilation = SD.ParserService.GetCompilationForFile(textEditor.FileName);
var entity = FindEntity<IProperty>("TargetC_");
Assert.IsTrue(entity.CanGet);
var attribute = compilation.FindType(new FullTypeName("MySimpleAttribute"));
gen.AddAttribute(entity.Getter, new DefaultAttribute(attribute));
Assert.AreEqual(@"using System;
using System.Reflection;
[assembly: AssemblyTitle(""CSharpBinding.Tests"")]
class MySimpleAttribute : Attribute {}
class TargetClass
{
void TargetA()
{
}
public int TargetB { get; set; }
public int TargetC_ {
[MySimple]
get {
return 0;
}
}
}
interface TargetInterface
{
}
", textEditor.Document.Text);
}
[Test]
[Ignore("The C# parser provides empty location info for AttributeSections.")]
public void AddSimpleAssemblyAttribute()
{
var compilation = SD.ParserService.GetCompilationForFile(textEditor.FileName);
var attribute = compilation.FindType(new FullTypeName("MySimpleAttribute"));
gen.AddAssemblyAttribute(new DefaultAttribute(attribute));
Assert.AreEqual(@"using System;
using System.Reflection;
[assembly: MySimple]
[assembly: AssemblyTitle(""CSharpBinding.Tests"")]
class MySimpleAttribute : Attribute {}
[MySimple]
class TargetClass
{
void TargetA()
{
}
public int TargetB { get; set; }
public int TargetC_ {
get {
return 0;
}
}
}
interface TargetInterface
{
}
", textEditor.Document.Text);
}
T FindEntity<T>(string targetClass) where T : IEntity
{
var compilation = SD.ParserService.GetCompilationForFile(textEditor.FileName);
var parseInfo = SD.ParserService.Parse(textEditor.FileName, textEditor.Document);
int i = textEditor.Document.IndexOf(targetClass, 0, textEditor.Document.TextLength, StringComparison.Ordinal);
Assert.Greater(i, -1);
TextLocation location = textEditor.Document.GetLocation(i);
var member = parseInfo.UnresolvedFile.GetMember(location);
var type = parseInfo.UnresolvedFile.GetInnermostTypeDefinition(location);
var context = new SimpleTypeResolveContext(compilation.MainAssembly);
var rt = type.Resolve(context).GetDefinition();
if (member != null) {
return (T)member.CreateResolved(context.WithCurrentTypeDefinition(rt));
}
return (T)rt;
}
}
}

2
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/AbstractEventHandlerService.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.WpfDesign.AddIn @@ -44,7 +44,7 @@ namespace ICSharpCode.WpfDesign.AddIn
if (xamlContext != null) {
string className = xamlContext.ClassName;
if (!string.IsNullOrEmpty(className)) {
return compilation.FindType(Type.GetType(className));
return compilation.FindType(new FullTypeName(className));
}
}
return null;

2
src/Main/Base/Project/Refactoring/ICodeGenerator.cs

@ -13,6 +13,8 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -13,6 +13,8 @@ namespace ICSharpCode.SharpDevelop.Refactoring
public interface ICodeGenerator
{
void AddAttribute(IEntity target, IAttribute attribute);
void AddAssemblyAttribute(IAttribute attribute);
void AddReturnTypeAttribute(IMethod target, IAttribute attribute);
void InsertEventHandler(ITypeDefinition target, string name, IEvent eventDefinition, bool jumpTo);
}
}

Loading…
Cancel
Save