Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix.Test/UnitTests.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix.Test/UnitTests.cs	(revision 14934)
+++ 	(revision )
@@ -1,52 +1,0 @@
-﻿using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
-using TestHelper;
-using PersistenceCodeFix;
-
-namespace PersistenceCodeFix.Test {
-  [TestClass]
-  public class UnitTest : CodeFixVerifier {
-
-    //No diagnostics expected to show up
-    [TestMethod]
-    public void TestMethod1() {
-      var test = @"";
-
-      VerifyCSharpDiagnostic(test);
-    }
-
-    //Diagnostic and CodeFix both triggered and checked for
-    [TestMethod]
-    public void TestMethod2() {
-      var test = @"
-    namespace ConsoleApplication1 {
-      
-      [Item(""XXX""), NonDiscoverable]
-      class TypeName {   
-        class InnerClass {   
-        }
-      }
-    }";
-
-
-      var fixtest = @"
-    namespace ConsoleApplication1 {
-        [StorableType(Guid = ""XXX"")]
-        class TypeName {   
-        }
-    }";
-      VerifyCSharpFix(test, fixtest);
-    }
-
-    protected override CodeFixProvider GetCSharpCodeFixProvider() {
-      return new PersistenceCodeFixProvider();
-    }
-
-    protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() {
-      return new MissingStorableTypeAnalyzer();
-    }
-  }
-}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/DiagnosticIds.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/DiagnosticIds.cs	(revision 14985)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/DiagnosticIds.cs	(revision 14985)
@@ -0,0 +1,5 @@
+﻿namespace PersistenceCodeFix {
+  public enum DiagnosticCategory {
+    Persistence
+  }
+}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableConstructor/MissingStorableConstructorAnalyzer.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableConstructor/MissingStorableConstructorAnalyzer.cs	(revision 14985)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableConstructor/MissingStorableConstructorAnalyzer.cs	(revision 14985)
@@ -0,0 +1,39 @@
+﻿using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace PersistenceCodeFix {
+  [DiagnosticAnalyzer(LanguageNames.CSharp)]
+  public sealed class MissingStorableConstructorAnalyzer : DiagnosticAnalyzer {
+    public const string DiagnosticId = "MissingStorableConstructor";
+
+    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.MissingStorableConstructorAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
+    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.MissingStorableConstructorAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
+    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.MissingStorableConstructorAnalyzerDescription), Resources.ResourceManager, typeof(Resources));
+    private const string Category = nameof(DiagnosticCategory.Persistence);
+
+    private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
+
+    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
+
+    public override void Initialize(AnalysisContext context) {
+      context.RegisterSymbolAction(AnalyzeNamedType, SymbolKind.NamedType);
+    }
+
+    private static void AnalyzeNamedType(SymbolAnalysisContext context) {
+      var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
+      if (namedTypeSymbol.IsStatic) return;
+      if (namedTypeSymbol.TypeKind == TypeKind.Delegate || namedTypeSymbol.TypeKind == TypeKind.Enum) return;
+
+      var attr = context.Symbol.GetAttributes();
+      if (attr.Any(a => a.AttributeClass.Name == "StorableTypeAttribute")) {
+        var ctors = namedTypeSymbol.InstanceConstructors;
+        if (!ctors.Any(x => x.GetAttributes().Any(y => y.AttributeClass.Name == "StorableConstructorAttribute"))) {
+          var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);
+          context.ReportDiagnostic(diagnostic);
+        }
+      }
+    }
+  }
+}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableConstructor/MissingStorableConstructorFix.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableConstructor/MissingStorableConstructorFix.cs	(revision 14985)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableConstructor/MissingStorableConstructorFix.cs	(revision 14985)
@@ -0,0 +1,127 @@
+﻿using System;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+
+
+namespace PersistenceCodeFix {
+  [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(MissingStorableConstructorFix)), Shared]
+  public sealed class MissingStorableConstructorFix : CodeFixProvider {
+    private const string title = "Add storable constructor";
+
+    public sealed override ImmutableArray<string> FixableDiagnosticIds {
+      get { return ImmutableArray.Create(MissingStorableConstructorAnalyzer.DiagnosticId); }
+    }
+
+    public sealed override FixAllProvider GetFixAllProvider() {
+      return WellKnownFixAllProviders.BatchFixer;
+    }
+
+    public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) {
+      var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+      var diagnostic = context.Diagnostics.First();
+      var diagnosticSpan = diagnostic.Location.SourceSpan;
+      var baseTypeDecl = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<BaseTypeDeclarationSyntax>().First();
+
+      context.RegisterCodeFix(
+        CodeAction.Create(
+          title: title,
+          createChangedDocument: c => AddStorableConstructor(context.Document, baseTypeDecl, c),
+          equivalenceKey: title),
+        diagnostic);
+    }
+
+    private static async Task<Document> AddStorableConstructor(Document document, BaseTypeDeclarationSyntax baseTypeDecl, CancellationToken cancellationToken) {
+      // create new attribute list
+      var attrList = SyntaxFactory.AttributeList();
+      attrList = attrList.AddAttributes(
+        SyntaxFactory.Attribute(
+          SyntaxFactory.IdentifierName("StorableConstructor")));
+
+      // check ctor visibility
+      var visibility = SyntaxFactory.Token(
+        baseTypeDecl.Modifiers.Any(x => x.IsKind(SyntaxKind.SealedKeyword))
+          ? SyntaxKind.PrivateKeyword
+          : SyntaxKind.ProtectedKeyword);
+
+      // create ctor parameters
+      var paramList = SyntaxFactory.ParameterList();
+      paramList = paramList.AddParameters(
+        SyntaxFactory.Parameter(
+          SyntaxFactory.Identifier("deserializing"))
+            .WithType(SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BoolKeyword))));
+
+      // create initializer args
+      var initArgs = SyntaxFactory.ArgumentList();
+      initArgs = initArgs.AddArguments(
+        SyntaxFactory.Argument(
+          SyntaxFactory.IdentifierName("deserializing")));
+
+      // create initializer
+      var initializer = SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, initArgs);
+
+      // create new ctor
+      var storableCtor = SyntaxFactory.ConstructorDeclaration(baseTypeDecl.Identifier)
+        .WithAttributeLists(SyntaxFactory.List(new[] { attrList }))
+        .WithModifiers(SyntaxFactory.TokenList(visibility))
+        .WithParameterList(paramList)
+        .WithInitializer(initializer)
+        .WithBody(SyntaxFactory.Block());
+
+      BaseTypeDeclarationSyntax newBaseTypeDecl;
+
+      // add new ctor
+      switch (baseTypeDecl.Kind()) {
+        case SyntaxKind.ClassDeclaration:
+          var classDecl = (ClassDeclarationSyntax)baseTypeDecl;
+          var classMembers = classDecl.Members;
+          classMembers = InsertIntoMembers(classMembers, storableCtor);
+          newBaseTypeDecl = classDecl.WithMembers(classMembers);
+          break;
+        case SyntaxKind.StructDeclaration:
+          var structDecl = (StructDeclarationSyntax)baseTypeDecl;
+          var structMembers = structDecl.Members;
+          structMembers = InsertIntoMembers(structMembers, storableCtor);
+          newBaseTypeDecl = structDecl.WithMembers(structMembers);
+          break;
+        default: throw new NotSupportedException();
+      }
+
+      var root = await document.GetSyntaxRootAsync(cancellationToken);
+      var newRoot = root.ReplaceNode(baseTypeDecl, newBaseTypeDecl.WithAdditionalAnnotations(Formatter.Annotation));
+
+      return document.WithSyntaxRoot(newRoot);
+    }
+
+    private static SyntaxList<MemberDeclarationSyntax> InsertIntoMembers(SyntaxList<MemberDeclarationSyntax> members, MemberDeclarationSyntax storableCtor) {
+      if (!members.Any()) return members.Add(storableCtor);
+
+      var firstCtor = members.FirstOrDefault(x => x.IsKind(SyntaxKind.ConstructorDeclaration));
+      if (firstCtor != null) {
+        storableCtor = storableCtor.WithLeadingTrivia(firstCtor.GetLeadingTrivia());
+        int index = members.IndexOf(firstCtor);
+        members = members.Insert(index++, storableCtor);
+        members = members.RemoveAt(index);
+        members = members.Insert(index, firstCtor.WithoutLeadingTrivia());
+      } else {
+        var lastMember = members.Last();
+        storableCtor = storableCtor.WithTrailingTrivia(lastMember.GetTrailingTrivia());
+        int index = members.IndexOf(lastMember);
+        members = members.Insert(index, storableCtor);
+        members = members.RemoveAt(index + 1);
+        members = members.Insert(index, lastMember.WithoutTrailingTrivia());
+      }
+
+      return members;
+    }
+  }
+}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableType/MissingStorableTypeAnalyzer.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableType/MissingStorableTypeAnalyzer.cs	(revision 14985)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableType/MissingStorableTypeAnalyzer.cs	(revision 14985)
@@ -0,0 +1,36 @@
+﻿using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace PersistenceCodeFix {
+  [DiagnosticAnalyzer(LanguageNames.CSharp)]
+  public sealed class MissingStorableTypeAnalyzer : DiagnosticAnalyzer {
+    public const string DiagnosticId = "MissingStorableType";
+
+    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.MissingStorableTypeAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
+    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.MissingStorableTypeAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
+    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.MissingStorableTypeAnalyzerDescription), Resources.ResourceManager, typeof(Resources));
+    private const string Category = nameof(DiagnosticCategory.Persistence);
+
+    private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Info, isEnabledByDefault: true, description: Description);
+
+    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
+
+    public override void Initialize(AnalysisContext context) {
+      context.RegisterSymbolAction(AnalyzeNamedType, SymbolKind.NamedType);
+    }
+
+    private static void AnalyzeNamedType(SymbolAnalysisContext context) {
+      var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
+      if (namedTypeSymbol.IsStatic) return;
+      if (namedTypeSymbol.TypeKind == TypeKind.Delegate) return;
+
+      var attr = context.Symbol.GetAttributes();
+      if (!attr.Any(a => a.AttributeClass.Name == "StorableTypeAttribute")) {
+        var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);
+        context.ReportDiagnostic(diagnostic);
+      }
+    }
+  }
+}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableType/MissingStorableTypeFix.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableType/MissingStorableTypeFix.cs	(revision 14985)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/MissingStorableType/MissingStorableTypeFix.cs	(revision 14985)
@@ -0,0 +1,116 @@
+﻿using System;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+
+namespace PersistenceCodeFix {
+  [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(MissingStorableTypeFix)), Shared]
+  public sealed class MissingStorableTypeFix : CodeFixProvider {
+    private const string title = "Add StorableType attribute";
+
+    public sealed override ImmutableArray<string> FixableDiagnosticIds {
+      get { return ImmutableArray.Create(MissingStorableTypeAnalyzer.DiagnosticId); }
+    }
+
+    public sealed override FixAllProvider GetFixAllProvider() {
+      return WellKnownFixAllProviders.BatchFixer;
+    }
+
+    public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) {
+      var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+      var diagnostic = context.Diagnostics.First();
+      var diagnosticSpan = diagnostic.Location.SourceSpan;
+      var baseTypeDecl = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<BaseTypeDeclarationSyntax>().First();
+
+      context.RegisterCodeFix(
+        CodeAction.Create(
+          title: title,
+          createChangedDocument: c => AddStorableTypeAttribute(context.Document, baseTypeDecl, c),
+          equivalenceKey: title),
+        diagnostic);
+    }
+
+    private static async Task<Document> AddStorableTypeAttribute(Document document, BaseTypeDeclarationSyntax baseTypeDecl, CancellationToken cancellationToken) {
+      // create new identifier
+      var name = SyntaxFactory.IdentifierName("StorableType");
+
+      // create guid arg
+      var guid = Guid.NewGuid();
+      var guidArg = SyntaxFactory.AttributeArgument(
+        SyntaxFactory.LiteralExpression(
+          SyntaxKind.StringLiteralExpression,
+          SyntaxFactory.Literal(guid.ToString())
+        ));
+
+      var attrArgs = SyntaxFactory.AttributeArgumentList();
+      attrArgs = attrArgs.AddArguments(guidArg);
+
+      // create new attribute
+      var attrDecl = SyntaxFactory.Attribute(name)
+        .WithArgumentList(attrArgs)
+        .WithAdditionalAnnotations(Formatter.Annotation);
+
+      // create new attribute list
+      var attrList = SyntaxFactory.AttributeList();
+      attrList = attrList.AddAttributes(attrDecl);
+
+      BaseTypeDeclarationSyntax newBaseTypeDecl;
+
+      // add new attribute list
+      switch (baseTypeDecl.Kind()) {
+        case SyntaxKind.ClassDeclaration:
+          var classDecl = (ClassDeclarationSyntax)baseTypeDecl;
+          var classAttrLists = classDecl.AttributeLists;
+          classAttrLists = AddToAttributeLists(classAttrLists, attrList);
+          newBaseTypeDecl = classDecl.WithAttributeLists(classAttrLists);
+          break;
+        case SyntaxKind.StructDeclaration:
+          var structDecl = (StructDeclarationSyntax)baseTypeDecl;
+          var structAttrLists = structDecl.AttributeLists;
+          structAttrLists = AddToAttributeLists(structAttrLists, attrList);
+          newBaseTypeDecl = structDecl.WithAttributeLists(structAttrLists);
+          break;
+        case SyntaxKind.EnumDeclaration:
+          var enumDecl = (EnumDeclarationSyntax)baseTypeDecl;
+          var enumAttrLists = enumDecl.AttributeLists;
+          enumAttrLists = AddToAttributeLists(enumAttrLists, attrList);
+          newBaseTypeDecl = enumDecl.WithAttributeLists(enumAttrLists);
+          break;
+        case SyntaxKind.InterfaceDeclaration:
+          var interfaceDecl = (InterfaceDeclarationSyntax)baseTypeDecl;
+          var interfaceAttrLists = interfaceDecl.AttributeLists;
+          interfaceAttrLists = AddToAttributeLists(interfaceAttrLists, attrList);
+          newBaseTypeDecl = interfaceDecl.WithAttributeLists(interfaceAttrLists);
+          break;
+        default: throw new NotSupportedException();
+      }
+
+      newBaseTypeDecl = newBaseTypeDecl.WithAdditionalAnnotations(Formatter.Annotation);
+
+      var root = await document.GetSyntaxRootAsync(cancellationToken) as CompilationUnitSyntax;
+      var newRoot = root.ReplaceNode(baseTypeDecl, newBaseTypeDecl);
+
+      // add using of HeuristicLab.Persistence if the document does not already have it 
+      var oldUsings = root.Usings;
+      if (oldUsings.All(x => x.Name.WithoutTrivia().ToString() != "HeuristicLab.Persistence")) {
+        var persistenceUsing = SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("HeuristicLab.Persistence"));
+        newRoot = newRoot.WithUsings(oldUsings.Add(persistenceUsing));
+      }
+
+      return document.WithSyntaxRoot(newRoot);
+    }
+
+    private static SyntaxList<AttributeListSyntax> AddToAttributeLists(SyntaxList<AttributeListSyntax> attrLists, AttributeListSyntax attrList) {
+      return attrLists == null ? SyntaxFactory.List(new[] { attrList }) : attrLists.Add(attrList);
+    }
+  }
+}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/ObsoleteStorableClass/ObsoleteStorableClassAnalyzer.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/ObsoleteStorableClass/ObsoleteStorableClassAnalyzer.cs	(revision 14985)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/ObsoleteStorableClass/ObsoleteStorableClassAnalyzer.cs	(revision 14985)
@@ -0,0 +1,34 @@
+﻿using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace PersistenceCodeFix {
+  [DiagnosticAnalyzer(LanguageNames.CSharp)]
+  public sealed class ObsoleteStorableClassAnalyzer : DiagnosticAnalyzer {
+    public const string DiagnosticId = "ObsoleteStorableClass";
+
+    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.ObsoleteStorableClassAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
+    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.ObsoleteStorableClassAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
+    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.ObsoleteStorableClassAnalyzerDescription), Resources.ResourceManager, typeof(Resources));
+    private const string Category = nameof(DiagnosticCategory.Persistence);
+
+    private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
+
+    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
+
+    public override void Initialize(AnalysisContext context) {
+      context.RegisterSyntaxNodeAction(AnalyzeAttribute, SyntaxKind.Attribute);
+    }
+
+    private static void AnalyzeAttribute(SyntaxNodeAnalysisContext context) {
+      var attributeSyntax = (AttributeSyntax)context.Node;
+      string attrName = attributeSyntax.Name.ToString();
+      if (attrName != "StorableClass") return;
+
+      var diagnostic = Diagnostic.Create(Rule, attributeSyntax.GetLocation(), attrName);
+      context.ReportDiagnostic(diagnostic);
+    }
+  }
+}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/ObsoleteStorableClass/ObsoleteStorableClassFix.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/ObsoleteStorableClass/ObsoleteStorableClassFix.cs	(revision 14985)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Analyzers/ObsoleteStorableClass/ObsoleteStorableClassFix.cs	(revision 14985)
@@ -0,0 +1,94 @@
+﻿using System;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Formatting;
+
+namespace PersistenceCodeFix {
+  [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ObsoleteStorableClassFix)), Shared]
+  public sealed class ObsoleteStorableClassFix : CodeFixProvider {
+    private const string title = "Change to StorableType attribute";
+
+    public sealed override ImmutableArray<string> FixableDiagnosticIds {
+      get { return ImmutableArray.Create(ObsoleteStorableClassAnalyzer.DiagnosticId); }
+    }
+
+    public sealed override FixAllProvider GetFixAllProvider() {
+      return WellKnownFixAllProviders.BatchFixer;
+    }
+
+    public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) {
+      var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+      var diagnostic = context.Diagnostics.First();
+      var diagnosticSpan = diagnostic.Location.SourceSpan;
+      var attributeSyntax = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<AttributeSyntax>().First();
+
+      context.RegisterCodeFix(
+        CodeAction.Create(
+          title: title,
+          createChangedDocument: c => ChangeToStorableTypeAttribute(context.Document, attributeSyntax, c),
+          equivalenceKey: title),
+        diagnostic);
+    }
+
+    private static async Task<Document> ChangeToStorableTypeAttribute(Document document, AttributeSyntax attrDecl, CancellationToken cancellationToken) {
+      var oldAttrArgs = attrDecl.ArgumentList;
+
+      // create new identifier
+      var name = SyntaxFactory.IdentifierName("StorableType")
+        .WithLeadingTrivia(attrDecl.Name.GetLeadingTrivia());
+
+      // create guid arg
+      var guid = Guid.NewGuid();
+      var guidArg = SyntaxFactory.AttributeArgument(
+        SyntaxFactory.LiteralExpression(
+          SyntaxKind.StringLiteralExpression,
+          SyntaxFactory.Literal(guid.ToString())
+        ));
+
+      var newAttrArgs = SyntaxFactory.AttributeArgumentList();
+      if (oldAttrArgs != null) {
+        // preserve old trivia
+        newAttrArgs = oldAttrArgs.WithArguments(newAttrArgs.Arguments);
+
+        // add old args
+        foreach (var arg in oldAttrArgs.Arguments)
+          newAttrArgs = newAttrArgs.AddArguments(arg);
+
+        // add trailing trivia to name only if there is an old argument list
+        // otherwise add it after the new argument list ...
+        name = name.WithTrailingTrivia(attrDecl.Name.GetTrailingTrivia());
+      } else {
+        // ... here
+        newAttrArgs = newAttrArgs.WithTrailingTrivia(attrDecl.Name.GetTrailingTrivia());
+      }
+      newAttrArgs = newAttrArgs.AddArguments(guidArg);
+
+      // rename attr, add old trivia and format
+      var newAttrDecl = attrDecl
+        .WithName(name)
+        .WithArgumentList(newAttrArgs)
+        .WithAdditionalAnnotations(Formatter.Annotation);
+
+      var root = await document.GetSyntaxRootAsync(cancellationToken) as CompilationUnitSyntax;
+      var newRoot = root.ReplaceNode(attrDecl, newAttrDecl);
+
+      // add using of HeuristicLab.Persistence if the document does not already have it 
+      var oldUsings = root.Usings;
+      if (oldUsings.All(x => x.Name.WithoutTrivia().ToString() != "HeuristicLab.Persistence")) {
+        var persistenceUsing = SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("HeuristicLab.Persistence"));
+        newRoot = newRoot.WithUsings(oldUsings.Add(persistenceUsing));
+      }
+
+      return document.WithSyntaxRoot(newRoot);
+    }
+  }
+}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/CodeFixProvider.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/CodeFixProvider.cs	(revision 14934)
+++ 	(revision )
@@ -1,158 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Composition;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Formatting;
-using Microsoft.CodeAnalysis.Rename;
-using Microsoft.CodeAnalysis.Text;
-
-
-namespace PersistenceCodeFix {
-  [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(PersistenceCodeFixProvider)), Shared]
-  public class PersistenceCodeFixProvider : CodeFixProvider {
-    private const string title = "Convert to Persistence-4.0";
-
-    public sealed override ImmutableArray<string> FixableDiagnosticIds {
-      get { return ImmutableArray.Create(MissingStorableTypeAnalyzer.DiagnosticId); }
-    }
-
-    public sealed override FixAllProvider GetFixAllProvider() {
-      // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
-      return WellKnownFixAllProviders.BatchFixer;
-    }
-
-    public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) {
-      var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
-
-      var diagnostic = context.Diagnostics.First();
-      var diagnosticSpan = diagnostic.Location.SourceSpan;
-
-      // Find the type declaration identified by the diagnostic.
-      var typeDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<BaseTypeDeclarationSyntax>().First();
-
-      // Register a code action that will invoke the fix.
-      context.RegisterCodeFix(
-        CodeAction.Create(
-          title: title,
-          createChangedSolution: c => AddStorableTypeAttribute(context.Document, typeDeclaration, c),
-          equivalenceKey: title),
-        diagnostic);
-    }
-
-
-    private async Task<Solution> AddStorableTypeAttribute(Document document, BaseTypeDeclarationSyntax typeDecl, CancellationToken cancellationToken) {
-      var newGuid = Guid.NewGuid();
-      var attributeLists = typeDecl.AttributeLists.ToDictionary(l => l, l => (AttributeListSyntax)null);
-      bool renamed = false;
-      AttributeListSyntax newAttrList = null;
-      SyntaxList<AttributeListSyntax> oldAttrList;
-
-      foreach (var kvp in attributeLists.ToArray()) {
-        var newList = SyntaxFactory.AttributeList();
-        foreach (var attr in kvp.Key.Attributes) {
-          if (attr.Name.WithoutTrivia().ToString() == "StorableClass") {
-            // rename
-            var guidArgument = SyntaxFactory.AttributeArgument(
-                SyntaxFactory.LiteralExpression(
-                  SyntaxKind.StringLiteralExpression,
-                  SyntaxFactory.Literal(newGuid.ToString())));
-
-            // collect existing arguments (if any) and append the GUID argument
-            var argumentList = new List<AttributeArgumentSyntax>();
-            if (attr.ArgumentList != null) argumentList.AddRange(attr.ArgumentList.Arguments);
-            argumentList.Add(guidArgument);
-
-            newList = newList.WithAttributes(
-              newList.Attributes.Add(
-                attr.WithName(SyntaxFactory.IdentifierName("StorableType"))
-                .WithLeadingTrivia(attr.GetLeadingTrivia())
-                .WithTrailingTrivia(attr.GetTrailingTrivia())
-                .WithArgumentList(SyntaxFactory.AttributeArgumentList(
-                SyntaxFactory.SeparatedList<AttributeArgumentSyntax>(argumentList)))));
-
-            renamed = true;
-          } else {
-            newList = newList.WithAttributes(newList.Attributes.Add(attr));
-          }
-        }
-
-        attributeLists[kvp.Key] = newList
-          .WithLeadingTrivia(kvp.Key.GetLeadingTrivia())
-          .WithTrailingTrivia(kvp.Key.GetTrailingTrivia());
-      }
-
-      if (!renamed) {
-        oldAttrList = typeDecl.AttributeLists;
-
-
-        newAttrList = SyntaxFactory.AttributeList(
-          SyntaxFactory.SingletonSeparatedList<AttributeSyntax>(
-            SyntaxFactory.Attribute(
-                SyntaxFactory.IdentifierName("StorableType"))
-              .WithArgumentList(
-                SyntaxFactory.AttributeArgumentList(
-                  SyntaxFactory.SingletonSeparatedList<AttributeArgumentSyntax>(
-                    SyntaxFactory.AttributeArgument(
-                        SyntaxFactory.LiteralExpression(
-                          SyntaxKind.StringLiteralExpression,
-                          SyntaxFactory.Literal(newGuid.ToString())))
-                      )))));
-
-      } else {
-        oldAttrList = SyntaxFactory.List(attributeLists.Values);
-      }
-
-      BaseTypeDeclarationSyntax newTypeDecl;
-      var classDecl = typeDecl as ClassDeclarationSyntax;
-      var structDecl = typeDecl as StructDeclarationSyntax;
-      var interfaceDecl = typeDecl as InterfaceDeclarationSyntax;
-      var enumDecl = typeDecl as EnumDeclarationSyntax;
-      if (classDecl != null) {
-        if (newAttrList != null) newTypeDecl = classDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList.Add(newAttrList));
-        else newTypeDecl = classDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList);
-      } else if (structDecl != null) {
-        if (newAttrList != null) newTypeDecl = structDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList.Add(newAttrList));
-        else newTypeDecl = structDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList);
-      } else if (interfaceDecl != null) {
-        if (newAttrList != null) newTypeDecl = interfaceDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList.Add(newAttrList));
-        else newTypeDecl = interfaceDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList);
-      } else if (enumDecl != null) {
-        if (newAttrList != null) newTypeDecl = enumDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList.Add(newAttrList));
-        else newTypeDecl = enumDecl.WithoutLeadingTrivia().WithoutTrailingTrivia().WithAttributeLists(oldAttrList);
-      } else throw new NotSupportedException();
-
-
-      var root = await document.GetSyntaxRootAsync(cancellationToken);
-
-      var oldUsings = (root as CompilationUnitSyntax).Usings;
-
-
-      var newRoot = root
-        .ReplaceNode(typeDecl, newTypeDecl
-          .WithAdditionalAnnotations(Formatter.Annotation)
-          .WithLeadingTrivia(typeDecl.GetLeadingTrivia())
-          .WithTrailingTrivia(typeDecl.GetTrailingTrivia())
-        ) as CompilationUnitSyntax;
-
-
-      // add using HeuristicLab.Persistence if something was changed or added and the document does already contain the using directive 
-      if ((newAttrList != null || renamed) &&
-        oldUsings.All(sn => sn.Name.WithoutTrivia().ToString() != "HeuristicLab.Persistence")) {
-        var newUsing = SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("HeuristicLab.Persistence"));
-        newRoot = newRoot.WithUsings(oldUsings.Add(newUsing));
-      }
-
-      return document
-        .WithSyntaxRoot(newRoot)
-        .Project.Solution;
-    }
-  }
-}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/DiagnosticAnalyzer.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/DiagnosticAnalyzer.cs	(revision 14934)
+++ 	(revision )
@@ -1,41 +1,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
-using System.Threading;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Diagnostics;
-
-namespace PersistenceCodeFix {
-  [DiagnosticAnalyzer(LanguageNames.CSharp)]
-  public class MissingStorableTypeAnalyzer : DiagnosticAnalyzer {
-    public const string DiagnosticId = "MissingStorableType";
-
-    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.MissingStorableTypeAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
-    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.MissingStorableTypeAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
-    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.MissingStorableTypeAnalyzerDescription), Resources.ResourceManager, typeof(Resources));
-    private const string Category = "Persistence";
-
-    private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
-
-    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
-
-    public override void Initialize(AnalysisContext context) {
-      context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
-    }
-
-    private static void AnalyzeSymbol(SymbolAnalysisContext context) {
-      var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
-      if (namedTypeSymbol.IsStatic) return;
-      if (namedTypeSymbol.TypeKind == TypeKind.Delegate) return;// don't trigger action for delegate types
-
-      var attr = context.Symbol.GetAttributes();
-      if (!attr.Any(a => a.AttributeClass.Name == "StorableTypeAttribute")) {
-        var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);
-        context.ReportDiagnostic(diagnostic);
-      }
-    }
-  }
-}
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix.csproj
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix.csproj	(revision 14934)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix.csproj	(revision 14985)
@@ -35,6 +35,11 @@
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="CodeFixProvider.cs" />
-    <Compile Include="DiagnosticAnalyzer.cs" />
+    <Compile Include="Analyzers\DiagnosticIds.cs" />
+    <Compile Include="Analyzers\MissingStorableConstructor\MissingStorableConstructorAnalyzer.cs" />
+    <Compile Include="Analyzers\MissingStorableConstructor\MissingStorableConstructorFix.cs" />
+    <Compile Include="Analyzers\ObsoleteStorableClass\ObsoleteStorableClassAnalyzer.cs" />
+    <Compile Include="Analyzers\ObsoleteStorableClass\ObsoleteStorableClassFix.cs" />
+    <Compile Include="Analyzers\MissingStorableType\MissingStorableTypeAnalyzer.cs" />
+    <Compile Include="Analyzers\MissingStorableType\MissingStorableTypeFix.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Resources.Designer.cs">
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Resources.Designer.cs
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Resources.Designer.cs	(revision 14934)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Resources.Designer.cs	(revision 14985)
@@ -63,4 +63,31 @@
         
         /// <summary>
+        ///   Looks up a localized string similar to All StorableTypes should have a storable constructor.
+        /// </summary>
+        internal static string MissingStorableConstructorAnalyzerDescription {
+            get {
+                return ResourceManager.GetString("MissingStorableConstructorAnalyzerDescription", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Type &apos;{0}&apos; has no storable constructor.
+        /// </summary>
+        internal static string MissingStorableConstructorAnalyzerMessageFormat {
+            get {
+                return ResourceManager.GetString("MissingStorableConstructorAnalyzerMessageFormat", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Missing storable constructor.
+        /// </summary>
+        internal static string MissingStorableConstructorAnalyzerTitle {
+            get {
+                return ResourceManager.GetString("MissingStorableConstructorAnalyzerTitle", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to All types should be marked with a StorableType attribute.
         /// </summary>
@@ -81,5 +108,5 @@
         
         /// <summary>
-        ///   Looks up a localized string similar to Missing StorableTypeAttribute.
+        ///   Looks up a localized string similar to Missing StorableType attribute.
         /// </summary>
         internal static string MissingStorableTypeAnalyzerTitle {
@@ -88,4 +115,31 @@
             }
         }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The StorableClass attribute is obsolete; Use the StorableType attribute instead.
+        /// </summary>
+        internal static string ObsoleteStorableClassAnalyzerDescription {
+            get {
+                return ResourceManager.GetString("ObsoleteStorableClassAnalyzerDescription", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Type &apos;{0}&apos; should be marked as StorableType instead of StorableClass.
+        /// </summary>
+        internal static string ObsoleteStorableClassAnalyzerMessageFormat {
+            get {
+                return ResourceManager.GetString("ObsoleteStorableClassAnalyzerMessageFormat", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Obsolete StorableClass attribute.
+        /// </summary>
+        internal static string ObsoleteStorableClassAnalyzerTitle {
+            get {
+                return ResourceManager.GetString("ObsoleteStorableClassAnalyzerTitle", resourceCulture);
+            }
+        }
     }
 }
Index: trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Resources.resx
===================================================================
--- trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Resources.resx	(revision 14934)
+++ trunk/tools/PersistenceCodeFix/PersistenceCodeFix/PersistenceCodeFix/Resources.resx	(revision 14985)
@@ -118,4 +118,13 @@
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
+  <data name="MissingStorableConstructorAnalyzerDescription" xml:space="preserve">
+    <value>All StorableTypes should have a storable constructor</value>
+  </data>
+  <data name="MissingStorableConstructorAnalyzerMessageFormat" xml:space="preserve">
+    <value>Type '{0}' has no storable constructor</value>
+  </data>
+  <data name="MissingStorableConstructorAnalyzerTitle" xml:space="preserve">
+    <value>Missing storable constructor</value>
+  </data>
   <data name="MissingStorableTypeAnalyzerDescription" xml:space="preserve">
     <value>All types should be marked with a StorableType attribute</value>
@@ -125,5 +134,14 @@
   </data>
   <data name="MissingStorableTypeAnalyzerTitle" xml:space="preserve">
-    <value>Missing StorableTypeAttribute</value>
+    <value>Missing StorableType attribute</value>
+  </data>
+  <data name="ObsoleteStorableClassAnalyzerDescription" xml:space="preserve">
+    <value>The StorableClass attribute is obsolete; Use the StorableType attribute instead</value>
+  </data>
+  <data name="ObsoleteStorableClassAnalyzerMessageFormat" xml:space="preserve">
+    <value>Type '{0}' should be marked as StorableType instead of StorableClass</value>
+  </data>
+  <data name="ObsoleteStorableClassAnalyzerTitle" xml:space="preserve">
+    <value>Obsolete StorableClass attribute</value>
   </data>
 </root>
