private static void AnalyzeCall(SyntaxNodeAnalysisContext context, ISymbol migratableAttributeType) { var ct = context.CancellationToken; var typeDeclaration = (TypeDeclarationSyntax)context.Node; var attribute = MigrationHashHelper.GetAttribute(typeDeclaration, migratableAttributeType, context.SemanticModel, ct); if (attribute == null) { return; } var typeSymbol = context.SemanticModel.GetDeclaredSymbol(typeDeclaration, ct); var verifier = new MigrationMethodVerifier(CanAssign(context)); var migrationMethods = MigrationHashHelper.GetMigrationMethods(typeSymbol); var invalidMethods = verifier.VerifyMigrationMethods(migrationMethods) .Where(x => x.Result != VerificationResultEnum.Ok); foreach (var x in invalidMethods) { var method = typeSymbol.GetMembers() .First(sy => sy.Name == x.Method.Name); Debug.Assert(method.Locations.Length == 1, "Method has multiple locations."); var diagnostic = Diagnostic.Create(Rule, method.Locations[0], method.Name, typeSymbol.Name, x.Result); context.ReportDiagnostic(diagnostic); } }
public void VerifyMigrationMethodShouldWork() { var method = typeof(TypeWithMigrationMethod0).GetMethod("Migrate_0", BindingFlags.NonPublic | BindingFlags.Static); var verificationResult = new MigrationMethodVerifier(VersionMemberName.CanAssign) .VerifyMigrationMethodSignature(VersionMemberName.GetMigrationMethod(method), null); verificationResult.Should().Be(VerificationResultEnum.Ok); }
/// <summary> /// Try to migrate the serialized data to a newer version using migration methods from type unserializedDataType. /// </summary> /// <param name="serializedData"></param> /// <param name="unserializedDataType"></param> /// <param name="serializer"></param> /// <returns></returns> public Tuple <TSerializedData, bool> TryMigrate(TSerializedData serializedData, Type unserializedDataType, JsonSerializer serializer) { if (serializedData == null) { throw new ArgumentNullException(nameof(serializedData)); } if (unserializedDataType == null) { throw new ArgumentNullException(nameof(unserializedDataType)); } var migrationSettings = unserializedDataType.GetTypeInfo().GetCustomAttribute <MigratableAttribute>(); if (migrationSettings == null) { return(Tuple.Create(serializedData, false)); } var version = _VersionExtractor.GetVersion(serializedData); var allMigrationMethods = VersionMemberName .GetMigrationMethods(unserializedDataType) .ToList(); var maxSupportedVersion = allMigrationMethods.LastOrDefault()?.ToVersion ?? 0; if (version > maxSupportedVersion) { throw new DataVersionTooHighException($"Trying to load data type '{unserializedDataType.FullName}' from json data " + $"at version {version}." + $" However current software only supports version {maxSupportedVersion}." + " Please update your installation with a newwer version."); } var migrationMethods = allMigrationMethods .SkipWhile(m => m.ToVersion <= version) .ToList(); var migrated = migrationMethods.Count > 0; try { serializedData = migrationMethods .Select(m => unserializedDataType.GetTypeInfo().GetDeclaredMethod(m.Name)) .Aggregate(serializedData, (data, method) => ExecuteMigration(method, data, serializer)); } catch (Exception e) { var migrationMethodVerifier = new MigrationMethodVerifier(VersionMemberName.CanAssign); var invalidMethod = migrationMethodVerifier.VerifyMigrationMethods(allMigrationMethods); foreach (var method in invalidMethod) { method.ThrowIfInvalid(e); } // Exception doesn't come from invalid migration methods -> rethrow throw; } _VersionExtractor.SetVersion(serializedData, maxSupportedVersion); return(Tuple.Create(serializedData, migrated)); }