コード例 #1
0
 public abstract ImmutableDictionary <string, string> Generate(CodeIndexerService codeIndexerService);
コード例 #2
0
        public override ImmutableDictionary <string, string> Generate(CodeIndexerService codeIndexerService)
        {
            var usings = new List <string>();

            var theClasses = _settings.BaseClasses.SelectMany(theClassName =>
            {
                var theClass = codeIndexerService.GetClassDeclaration(theClassName);
                var theClassSemanticModel = codeIndexerService.GetSemanticModel(theClass.SyntaxTree);
                var theClassSymbol        = theClassSemanticModel.GetDeclaredSymbol(theClass);

                return(codeIndexerService.GetAllClassDeclarations().Where(classDecl =>
                {
                    var usingStatementSyntaxes = Utilities.GetDescendantsOfType <UsingDirectiveSyntax>(classDecl.SyntaxTree.GetRoot());
                    usings.AddRange(usingStatementSyntaxes
                                    .Select(us => us.ToString() + "\n"));
                    var aClassSymbol = codeIndexerService.GetSemanticModel(classDecl.SyntaxTree).GetDeclaredSymbol(classDecl);
                    return Utilities.IsBaseClass(aClassSymbol, theClassSymbol);
                }));
            }).ToImmutableDictionary(x => x.Identifier.Text);

            var extensionMethods = new List <string>();

            extensionMethods.Add($"namespace {_settings.Namespace} {{\n");
            extensionMethods.Add($"public static class {_settings.ExtensionMethodName}Extensions {{\n");

            var constructors = new List <Tuple <ClassDeclarationSyntax, ConstructorDeclarationSyntax, SemanticModel> >();

            foreach (var aClass in theClasses.Values)
            {
                var aClassSemanticModel = codeIndexerService.GetSemanticModel(aClass.SyntaxTree);
                usings.Add($"using {aClassSemanticModel.GetDeclaredSymbol(aClass).ContainingNamespace};\n");

                foreach (var constructor in aClass.Members.OfType <ConstructorDeclarationSyntax>().Where(constructor => constructor.Modifiers.Any(SyntaxKind.PublicKeyword)))
                {
                    constructors.Add(Tuple.Create(aClass, constructor, aClassSemanticModel));
                }
            }

            var memberDeduplicationService = new MemberDeduplicationService();
            var deduplicatedConstructors   = memberDeduplicationService.DeduplicateMembers(constructors, x => x.Item3.GetDeclaredSymbol(x.Item2));

            foreach (var deduplicatedMember in deduplicatedConstructors)
            {
                var(aClass, constructor, aClassSemanticModel) = deduplicatedMember.Value;

                var constructorArguments = string.Join(", ",
                                                       constructor.ParameterList.Parameters.Select(parameter => parameter.Identifier.Text));

                var parameters = string.Join(", ",
                                             constructor.ParameterList.Parameters.Select(parameter =>
                                                                                         $"{parameter.Type} {parameter.Identifier.Text}"));

                usings.AddRange(constructor.ParameterList.Parameters
                                .Select(parameter => aClassSemanticModel.GetSymbolInfo(parameter.Type).Symbol)
                                .Where(symbol => symbol != null)
                                .Select(symbol => $"using {symbol.ContainingNamespace};\n"));

                var theInterface = aClass.BaseList.Types.First(type =>
                {
                    var symbol = aClassSemanticModel.GetSymbolInfo(type.Type).Symbol as INamedTypeSymbol;
                    return(symbol.TypeKind == TypeKind.Interface);
                });

                var typeArgs = string.Join(", ",
                                           aClass.TypeParameterList.Parameters.Select(parameter => parameter.Identifier.Text));
                if (!string.IsNullOrWhiteSpace(typeArgs))
                {
                    typeArgs = $"<{typeArgs}>";
                }

                extensionMethods.Add($"public static {theInterface.Type} {_settings.ExtensionMethodName}{typeArgs}(this {parameters}) {{\n");
                extensionMethods.Add($"return new {aClass.Identifier}{typeArgs}({constructorArguments});");
                extensionMethods.Add("}\n");
            }

            extensionMethods.Add("}\n}\n");

            return(ImmutableDictionary <string, string> .Empty
                   .Add($"{_settings.ExtensionMethodName}Extensions.g.cs",
                        string.Join("", usings.Distinct().OrderBy(x => x).Concat(extensionMethods))));
        }
コード例 #3
0
        public override ImmutableDictionary <string, string> Generate(CodeIndexerService codeIndexerService)
        {
            var combinations = Utilities.CalcCombinationsOfOneFromEach(_settings.InterfaceNameModifiers.Select(x => x.Values));
            var interfaces   = new Dictionary <string, ImmutableDictionary <string, TypeParameter> >();

            var results = new Dictionary <string, string>();

            foreach (var combination in combinations)
            {
                if (!GetName(combination, out var name))
                {
                    continue;
                }

                var withSimpleTypeNames = PreExistingInterfacesWithSimpleTypeNames();
                var matchingPreExisting = withSimpleTypeNames.FirstOrDefault(preExistingInterface => preExistingInterface.simpleTypeName == name);
                if (matchingPreExisting.simpleTypeName != null)
                {
                    var genericParams = new Dictionary <string, TypeParameter>();

                    if (codeIndexerService.TryGetInterfaceDeclaration(name, out var value))
                    {
                        var index = 0;
                        foreach (var param in value.TypeParameterList.Parameters)
                        {
                            var variance = TypeParameterVariance.None;
                            if (param.AttributeLists.Any(SyntaxKind.OutKeyword))
                            {
                                variance = TypeParameterVariance.Out;
                            }

                            if (param.AttributeLists.Any(SyntaxKind.InKeyword))
                            {
                                variance = TypeParameterVariance.In;
                            }

                            genericParams.Add(param.Identifier.Text, new TypeParameter(variance, index));
                            index++;
                        }
                    }
                    else if (matchingPreExisting.withTypeParameters.Contains("<"))
                    {
                        var matchingPreExistingTypeParameters = matchingPreExisting
                                                                .withTypeParameters
                                                                .Substring(matchingPreExisting.withTypeParameters.IndexOf('<')).Trim('<', '>').Split(',')
                                                                .Select(typeParameter => typeParameter.Trim());

                        var index = 0;
                        foreach (var typeParameter in matchingPreExistingTypeParameters)
                        {
                            if (typeParameter.Contains(" "))
                            {
                                var words = typeParameter.Split(' ');
                                if (words[0] == "in")
                                {
                                    genericParams.Add(words[1], new TypeParameter(TypeParameterVariance.In, index));
                                }
                                else if (words[0] == "out")
                                {
                                    genericParams.Add(words[1], new TypeParameter(TypeParameterVariance.Out, index));
                                }
                                else
                                {
                                    throw new ArgumentException($"Unknown type parameter variance {words[0]}");
                                }
                            }
                            else
                            {
                                genericParams.Add(typeParameter, new TypeParameter(TypeParameterVariance.None, index));
                            }

                            index++;
                        }
                    }

                    interfaces.Add(name, genericParams.ToImmutableDictionary());
                }
                else
                {
                    var baseInterfaces = new List <string>();
                    for (var i = 0; i < combination.Count; i++)
                    {
                        if (combination[i] == _settings.InterfaceNameModifiers[i].Values[0])
                        {
                            continue;
                        }

                        var subCombination = combination.ToList();
                        subCombination[i] = _settings.InterfaceNameModifiers[i].Values[0];

                        if (!GetName(subCombination, out var baseName))
                        {
                            continue;
                        }

                        baseInterfaces.Add(baseName);
                    }

                    var usings = new StringBuilder();

                    var baseList = "";
                    if (baseInterfaces.Count > 0)
                    {
                        var preExistingInterfacesWithSimpleTypeNames = PreExistingInterfacesWithSimpleTypeNames();

                        foreach (var baseInterface in baseInterfaces)
                        {
                            var matchingBaseInterface = preExistingInterfacesWithSimpleTypeNames.FirstOrDefault(pre =>
                                                                                                                pre.simpleTypeName == baseInterface);
                            if (matchingBaseInterface.simpleTypeName == null)
                            {
                                continue;
                            }
                            if (matchingBaseInterface.withTypeParameters.Contains("."))
                            {
                                var theNamespace = matchingBaseInterface.withTypeParameters.Substring(0, matchingBaseInterface.withTypeParameters.LastIndexOf('.'));
                                usings.AppendLine($"using {theNamespace};");
                            }
                        }

                        var joinedBaseInterfaces = string.Join(", ",
                                                               baseInterfaces.Select(baseInterface =>
                        {
                            var baseInterfaceTypeArguments = string.Join(", ", interfaces[baseInterface].OrderBy(kvp =>
                                                                                                                 kvp.Value.Index).Select(kvp => kvp.Key));
                            if (string.IsNullOrWhiteSpace(baseInterfaceTypeArguments))
                            {
                                return(baseInterface);
                            }
                            else
                            {
                                return($"{baseInterface}<{baseInterfaceTypeArguments}>");
                            }
                        }));
                        baseList = $" : {joinedBaseInterfaces}";
                    }

                    var baseInterfacesTypeParameters = interfaces.Where(iface => baseInterfaces.Any(baseInterface => baseInterface == iface.Key)).Select(x => x.Value).ToImmutableList();
                    interfaces.Add(name, Aggregate(baseInterfacesTypeParameters));
                    var genericParams = string.Join(", ", interfaces[name].OrderBy(x => x.Value.Index).Select(ConvertToString));

                    if (!string.IsNullOrWhiteSpace(genericParams))
                    {
                        genericParams = $"<{genericParams}>";
                    }

                    results.Add($"{name}.g.cs", $"{usings}\nnamespace {_settings.Namespace} {{\npublic interface {name}{genericParams}{baseList} {{\n}}\n}}");
                }
            }

            return(results.ToImmutableDictionary());
        }
コード例 #4
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());
        }
コード例 #5
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());
        }