Beispiel #1
0
        public override ImmutableDictionary <string, string> Generate(CodeIndexerService codeIndexerService)
        {
            var result = new Dictionary <string, string>();

            var theClass = codeIndexerService.GetClassDeclaration(_settings.BaseClass);
            var theClassSemanticModel = codeIndexerService.GetSemanticModel(theClass.SyntaxTree);

            var baseInterfaceName = theClass.BaseList.Types.Select(baseType =>
            {
                var key = baseType.Type.ToString();
                if (key.Contains("<"))
                {
                    key = key.Substring(0, key.IndexOf('<'));
                }

                if (codeIndexerService.TryGetInterfaceDeclaration(key, out var _))
                {
                    return(key);
                }

                return("");
            }).First(str => !string.IsNullOrWhiteSpace(str));
            var baseInterface       = codeIndexerService.GetInterfaceDeclaration(baseInterfaceName);
            var baseInterfaceSymbol = codeIndexerService.GetSymbol(baseInterface);

            var subInterfaces = new List <InterfaceDeclarationSyntax>();

            foreach (var interfaceDeclaration in codeIndexerService.GetAllInterfaceDeclarations())
            {
                if (Utilities.IsBaseInterface(codeIndexerService.GetSymbol(interfaceDeclaration), baseInterfaceSymbol))
                {
                    subInterfaces.Add(interfaceDeclaration);
                }
            }

            if (subInterfaces.Contains(baseInterface))
            {
                subInterfaces.Remove(baseInterface);
            }

            var delegateMemberService      = new DelegateMemberService();
            var memberDeduplicationService = new MemberDeduplicationService();

            var constructors = theClass.Members.OfType <ConstructorDeclarationSyntax>()
                               .ToImmutableList();
            var baseInterfaces = Utilities.GetBaseInterfaces(theClassSemanticModel.GetDeclaredSymbol(theClass));
            var baseMembers    = baseInterfaces.SelectMany(baseInterface => baseInterface.GetMembers());
            var baseMemberExplicitImplementationProfiles =
                baseMembers.Select(baseMember => memberDeduplicationService.GetExplicitImplementationProfile(baseMember)).Distinct().ToImmutableHashSet();
            var baseMemberImplementationProfiles =
                baseMembers.Select(baseMember => memberDeduplicationService.GetImplementationProfile(baseMember)).Distinct().ToImmutableHashSet();

            foreach (var subInterface in subInterfaces)
            {
                var usings          = new List <string>();
                var classDefinition = new List <string>();

                var subClassName = subInterface.Identifier.Text.Substring(1);
                foreach (var modifier in _settings.ClassNameModifiers)
                {
                    subClassName = Regex.Replace(subClassName, modifier.Search ?? "", modifier.Replace ?? "");
                }

                if (_settings.ClassNameBlacklist.Any(classNameBlacklistItem =>
                                                     Regex.IsMatch(subClassName, classNameBlacklistItem)))
                {
                    continue;
                }

                if (!_settings.ClassNameWhitelist.All(classNameWhitelistItem =>
                                                      Regex.IsMatch(subClassName, classNameWhitelistItem)))
                {
                    continue;
                }

                usings.AddRange(Utilities.GetDescendantsOfType <UsingDirectiveSyntax>(subInterface.SyntaxTree.GetRoot())
                                .Select(us => $"using {us.Name};\n"));
                usings.AddRange(Utilities.GetDescendantsOfType <UsingDirectiveSyntax>(theClass.SyntaxTree.GetRoot())
                                .Select(us => $"using {us.Name};\n"));

                classDefinition.Add($"\nnamespace {_settings.Namespace} {{\n");
                var subInterfaceTypeArgs =
                    string.Join(", ", subInterface.TypeParameterList.Parameters.Select(p => p.Identifier));
                if (!string.IsNullOrWhiteSpace(subInterfaceTypeArgs))
                {
                    subInterfaceTypeArgs = $"<{subInterfaceTypeArgs}>";
                }
                classDefinition.Add($"public class {subClassName}{theClass.TypeParameterList} : {theClass.Identifier}{theClass.TypeParameterList}, {subInterface.Identifier}{subInterfaceTypeArgs} {{\n");

                var stuffAddedForSubInterface =
                    Utilities.GetBaseInterfaces(codeIndexerService.GetSemanticModel(subInterface.SyntaxTree).GetDeclaredSymbol(subInterface))
                    .Except(Utilities.GetBaseInterfaces(theClassSemanticModel.GetDeclaredSymbol(theClass)));

                var adaptedParameter             = constructors.First().ParameterList.Parameters.First();
                var desiredAdaptedBaseInterfaces = Utilities
                                                   .GetBaseInterfaces(
                    theClassSemanticModel.GetSymbolInfo(adaptedParameter.Type).Symbol as INamedTypeSymbol)
                                                   .Concat(stuffAddedForSubInterface).Select(x => x.ToString()).ToImmutableHashSet();
                var adaptedParameterTypeArgs = "";
                var tmp = adaptedParameter.Type.ToString();
                if (tmp.Contains("<"))
                {
                    adaptedParameterTypeArgs = tmp.Substring(tmp.IndexOf('<'));
                }

                if (_settings.AllowDifferentTypeParameters)
                {
                    desiredAdaptedBaseInterfaces = desiredAdaptedBaseInterfaces.Select(Utilities.GetWithoutTypeArguments).ToImmutableHashSet();
                }

                InterfaceDeclarationSyntax bestAdaptedInterface = null;

                foreach (var iface in codeIndexerService.GetAllInterfaceDeclarations())
                {
                    var ifaceBaseInterfaces = Utilities
                                              .GetBaseInterfaces(codeIndexerService.GetSemanticModel(iface.SyntaxTree)
                                                                 .GetDeclaredSymbol(iface))
                                              .Select(x => x.ToString()).ToImmutableHashSet();

                    if (_settings.AllowDifferentTypeParameters)
                    {
                        ifaceBaseInterfaces = ifaceBaseInterfaces.Select(Utilities.GetWithoutTypeArguments).ToImmutableHashSet();
                    }

                    //if (iface.Identifier == subInterface.Identifier)
                    if (subInterface.Identifier.Text == "IDisposableDictionary")
                    {
                        int a       = 3;
                        var union   = ifaceBaseInterfaces.Union(desiredAdaptedBaseInterfaces);
                        var except1 = ifaceBaseInterfaces.Except(desiredAdaptedBaseInterfaces);
                        var except2 = desiredAdaptedBaseInterfaces.Except(ifaceBaseInterfaces);
                    }

                    if (desiredAdaptedBaseInterfaces.Count == ifaceBaseInterfaces.Count)
                    {
                        if (ifaceBaseInterfaces.All(ifaceBaseInterface =>
                                                    desiredAdaptedBaseInterfaces.Contains(ifaceBaseInterface)))
                        {
                            bestAdaptedInterface = iface;
                            break;
                        }
                    }
                }

                classDefinition.Add(
                    $"private readonly {bestAdaptedInterface.Identifier}{adaptedParameterTypeArgs} _adapted;\n");

                foreach (var constructor in constructors)
                {
                    var constructorParameters    = new List <string>();
                    var baseConstructorArguments = new List <string>();

                    constructorParameters.Add(
                        $"{bestAdaptedInterface.Identifier}{adaptedParameterTypeArgs} adapted");
                    baseConstructorArguments.Add("adapted");

                    for (var i = 1; i < constructor.ParameterList.Parameters.Count; i++)
                    {
                        var parameter = constructor.ParameterList.Parameters[i];
                        constructorParameters.Add($"{parameter.Type} {parameter.Identifier}");
                        baseConstructorArguments.Add(parameter.Identifier.ToString());
                    }

                    classDefinition.Add($"public {subClassName}(");
                    classDefinition.Add(string.Join(", ", constructorParameters));
                    classDefinition.Add(") : base(" + string.Join(", ", baseConstructorArguments) + ") {\n");
                    classDefinition.Add("_adapted = adapted;");
                    classDefinition.Add("}\n");
                }

                foreach (var member in memberDeduplicationService.GetDeduplicatedMembers(codeIndexerService.GetSemanticModel(bestAdaptedInterface.SyntaxTree).GetDeclaredSymbol(bestAdaptedInterface)))
                {
                    if (member.Duplicates.All(duplicate => baseMemberImplementationProfiles.Contains(memberDeduplicationService.GetImplementationProfile(duplicate))))
                    {
                        continue;
                    }

                    usings.AddRange(member.Duplicates.SelectMany(duplicate => duplicate.DeclaringSyntaxReferences).SelectMany(syntaxRef =>
                    {
                        var root            = syntaxRef.SyntaxTree.GetRoot();
                        var usingDirectives = Utilities.GetDescendantsOfType <UsingDirectiveSyntax>(root);
                        return(usingDirectives.Select(usingDirective => $"{usingDirective}\n"));
                    }));

                    var sourceCodeBuilder = new StringBuilder();
                    var shouldOverride    = member.Duplicates.Any(duplicate => duplicate.ContainingType.TypeKind == TypeKind.Class);
                    delegateMemberService.DelegateMember(member.Value, "_adapted", null, member.ImplementExplicitly, sourceCodeBuilder, usings, DelegateType.DelegateObject, shouldOverride);
                    classDefinition.Add(sourceCodeBuilder + "\n");
                }

                classDefinition.Add("}\n}\n");
                result[subClassName + ".g.cs"] = string.Join("", usings.Distinct().Concat(classDefinition));
            }

            return(result.ToImmutableDictionary());
        }
Beispiel #2
0
        public override ImmutableDictionary <string, string> Generate(CodeIndexerService codeIndexerService)
        {
            var results = new Dictionary <string, string>();

            foreach (var iface in _settings.InterfacesToImplement)
            {
                var interfaceDeclaration = codeIndexerService.GetInterfaceDeclaration(iface);

                var className         = $"Anonymous{iface.Substring(1)}";
                var sourceCodeBuilder = new StringBuilder();

                var typeParameters = interfaceDeclaration.TypeParameterList.Parameters.Select(tps => tps.Identifier.Text).ToImmutableList();
                var genericParams  = "";
                if (typeParameters.Count > 0)
                {
                    genericParams = $"<{string.Join(", ", typeParameters)}>";
                }

                var usings = new List <string>();

                sourceCodeBuilder.AppendLine(
                    $"namespace {_settings.Namespace} {{\npublic class {className}{genericParams} : {iface}{genericParams} {{");

                var semanticModel            = codeIndexerService.GetSemanticModel(interfaceDeclaration.SyntaxTree);
                var delegateMemberCandidates = new List <MemberToBeDelegated>();
                var candidateParameters      = new List <Parameter>();
                GetInterfacesToImplementWith(semanticModel.GetDeclaredSymbol(interfaceDeclaration), candidateParameters, delegateMemberCandidates);

                var delegateMemberService        = new DelegateMemberService();
                var memberDeduplicationService   = new MemberDeduplicationService();
                var deduplicatedDelegatedMembers = memberDeduplicationService
                                                   .DeduplicateMembers(delegateMemberCandidates, delegated => delegated.Member).ToImmutableList();
                var parameters = candidateParameters.Where(candidateParameter =>
                                                           deduplicatedDelegatedMembers.Any(deduplicatedDelegatedMember =>
                                                                                            deduplicatedDelegatedMember.Value.MemberName == candidateParameter.MemberName))
                                 .ToImmutableList();
                var getEnumerator = deduplicatedDelegatedMembers.FirstOrDefault(delegateMemberCandidate =>
                                                                                delegateMemberCandidate.Value.Member.Name == "GetEnumerator");

                foreach (var baseInterface in Utilities.GetBaseInterfaces(semanticModel.GetDeclaredSymbol(interfaceDeclaration)))
                {
                    var newUsing =
                        $"using {string.Join(".", baseInterface.ContainingNamespace.ConstituentNamespaces)};";
                    if (!newUsing.Contains("global namespace"))
                    {
                        usings.Add(newUsing);
                    }
                }

                foreach (var usingDirective in Utilities.GetBaseInterfaces(semanticModel.GetDeclaredSymbol(interfaceDeclaration))
                         .SelectMany(symbol => symbol.DeclaringSyntaxReferences).Select(syntaxRef => syntaxRef.SyntaxTree)
                         .SelectMany(syntaxTree => Utilities.GetDescendantsOfType <UsingDirectiveSyntax>(syntaxTree.GetRoot())))
                {
                    var newUsing = usingDirective.ToString();
                    if (!newUsing.Contains("global namespace"))
                    {
                        usings.Add(newUsing);
                    }
                }

                var parameterString = string.Join(", ", parameters
                                                  .OrderBy(parameter => parameter.DelegateType).ThenBy(parameter => parameter.ParameterName)
                                                  .Select(parameter => $"{parameter.Type} {parameter.ParameterName}"));

                sourceCodeBuilder.AppendLine(string.Join("\n", parameters
                                                         .OrderBy(parameter => parameter.DelegateType).ThenBy(parameter => parameter.ParameterName)
                                                         .Select(parameter => parameter.ToMemberDeclaration())));

                sourceCodeBuilder.AppendLine($"public {className}({parameterString}) {{");

                var memberAssignments = parameters
                                        .Select(parameter => $"{parameter.MemberName} = {parameter.ParameterName};");
                sourceCodeBuilder.AppendLine(string.Join("\n", memberAssignments));
                sourceCodeBuilder.AppendLine("}");

                foreach (var deduplicatedMember in deduplicatedDelegatedMembers)
                {
                    delegateMemberService.DelegateMember(deduplicatedMember.Value.Member, deduplicatedMember.Value.MemberName, deduplicatedMember.Value.SetMemberName, deduplicatedMember.ImplementExplicitly, sourceCodeBuilder, usings, deduplicatedMember.Value.Type, null);
                }

                if (getEnumerator != null)
                {
                    sourceCodeBuilder.AppendLine("IEnumerator IEnumerable.GetEnumerator() {");
                    sourceCodeBuilder.Append($"return {getEnumerator.Value.MemberName}.GetEnumerator();");
                    sourceCodeBuilder.AppendLine("}");
                }

                sourceCodeBuilder.AppendLine("}\n}\n");

                usings = usings.Distinct().OrderBy(x => x).ToList();

                var filePath = $"{className}.g.cs";
                results.Add(filePath, $"{string.Join("\n",usings)}\n{sourceCodeBuilder}");
            }

            return(results.ToImmutableDictionary());
        }