Example #1
0
 static Compilation CreateCoreCompilation()
 {
     return(CSharpCompilation.Create(
                "FunctionCompletion",
                references: new[] {
         RoslynHelpers.GetReference(typeof(string).Assembly.Location),
     }
                ));
 }
Example #2
0
        public static (Location codeBehindLocation, List <Location> incorrectCodeBehindLocations, List <Location> lazinatorObjectLocationsExcludingCodeBehind) CategorizeLocations(LazinatorConfig config, INamedTypeSymbol lazinatorObject, List <Location> mainTypeLocations)
        {
            string generatedCodeFileExtension = config?.GeneratedCodeFileExtension ?? ".laz.cs";
            bool   useFullyQualifiedNames     = (config?.UseFullyQualifiedNames ?? false) || lazinatorObject.ContainingType != null || lazinatorObject.IsGenericType;
            string correctCodeBehindName      = RoslynHelpers.GetEncodableVersionOfIdentifier(lazinatorObject, useFullyQualifiedNames) + generatedCodeFileExtension;
            var    nonGeneratedLocations      = mainTypeLocations.Where(x => !x.SourceTree.FilePath.EndsWith(generatedCodeFileExtension)).ToList();
            var    codeBehindLocations        = mainTypeLocations.Where(x => x.SourceTree.FilePath.EndsWith(generatedCodeFileExtension)).ToList();
            IEnumerable <Location> possiblyCorrectCodeBehindLocations = mainTypeLocations.Where(x => x.SourceTree.FilePath.EndsWith(correctCodeBehindName));
            Location        codeBehindLocation           = possiblyCorrectCodeBehindLocations.FirstOrDefault();
            List <Location> incorrectCodeBehindLocations = codeBehindLocations.Where(x => x != codeBehindLocation).ToList();

            return(codeBehindLocation, incorrectCodeBehindLocations, nonGeneratedLocations);
        }
        private MatrixTransformAnalysisReportScript InitializeScript(ReportOutExportType?outExportType, string reportScriptId)
        {
            var scriptFilePath = CheckFileExistsInCurrentFolderOrScriptsFolder("Script.cs");

            var scriptClassText = File.ReadAllText(scriptFilePath);

            var classCode = RoslynHelpers.GetMethodText(scriptClassText, nameof(Script.ExecuteScript));

            var script = outExportType.HasValue ? new MatrixTransformAnalysisReportScript() : new ReportScriptMock(SetupScript);

            script.Id   = reportScriptId ?? DefaultScriptId;
            script.Code = classCode;

            return(script);
        }
Example #4
0
        private LazinatorPairInformation GetLazinatorPairInfo(Compilation compilation, INamedTypeSymbol namedType)
        {
            INamedTypeSymbol lazinatorObjectType;
            INamedTypeSymbol namedInterfaceType;

            SearchForLazinatorObjectAndNamedInterface(compilation, namedType, out lazinatorObjectType, out namedInterfaceType);
            if (namedInterfaceType != null && lazinatorObjectType != null)
            {
                var lazinatorAttribute = RoslynHelpers.GetKnownAttributes <CloneLazinatorAttribute>(namedInterfaceType).FirstOrDefault();
                if (lazinatorAttribute != null && lazinatorAttribute.Autogenerate)
                {
                    var lazinatorPairInfo = GetLazinatorPairInfo(compilation, lazinatorObjectType, namedInterfaceType);
                    return(lazinatorPairInfo);
                }
            }

            return(null);
        }
Example #5
0
        public static MSBuildValueKind ConvertType(ITypeSymbol type)
        {
            if (type is IArrayTypeSymbol arr)
            {
                return(ConvertType(arr.ElementType) | MSBuildValueKind.List);
            }

            string fullTypeName = RoslynHelpers.GetFullName(type);

            switch (fullTypeName)
            {
            case "System.String":
                return(MSBuildValueKind.String);

            case "System.Boolean":
                return(MSBuildValueKind.Bool);

            case "System.Int32":
            case "System.UInt32":
            case "System.Int62":
            case "System.UInt64":
                return(MSBuildValueKind.Int);

            case "System.Char":
                return(MSBuildValueKind.Char);

            case "System.Float":
            case "System.Double":
                return(MSBuildValueKind.Float);

            case "Microsoft.Build.Framework.ITaskItem":
                return(MSBuildValueKind.UnknownItem);

            case "System.Object":
                return(MSBuildValueKind.Object);

            case "System.DateTime":
                return(MSBuildValueKind.DateTime);
            }

            return(MSBuildValueKind.Unknown);
        }
Example #6
0
        private static CliDescriptor?GetCli <T>(string code)
            where T : SyntaxNode
        {
            var tree              = CSharpSyntaxTree.ParseText(code);
            var compilation       = GetCompilation(tree);
            var warningsAndErrors = compilation.GetDiagnostics().Where(x => x.Severity.HasFlag(DiagnosticSeverity.Error) || x.Severity.HasFlag(DiagnosticSeverity.Warning));

            warningsAndErrors.Should().NotHaveWarningsOrErrors();
            var rootCommand = tree.GetRoot().DescendantNodes()
                              .OfType <T>()
                              .FirstOrDefault();

            if (rootCommand is null)
            {
                return(null);
            }
            var semanticModels = new Dictionary <ISymbol, SemanticModel>();
            var symbol         = RoslynHelpers.GetSymbol(rootCommand, compilation, semanticModels);

            return(symbol is null
                   ? null
                   : RoslynDescriptorFactory.GetCliDescriptor(symbol, semanticModels[symbol]));
        }
        /// <summary>
        /// Generates an observable declaration that wraps a event.
        /// </summary>
        /// <param name="eventDetails">The details of the event to wrap.</param>
        /// <param name="dataObjectName">The name of the item where the event is stored.</param>
        /// <param name="prefix">A prefix to append to the name.</param>
        /// <returns>The property declaration.</returns>
        protected static PropertyDeclarationSyntax?GenerateEventWrapperObservable(IEventSymbol eventDetails, string dataObjectName, string?prefix)
        {
            prefix ??= string.Empty;

            // Create "Observable.FromEvent" for our method.
            var(expressionBody, observableEventArgType) = GenerateFromEventExpression(eventDetails, dataObjectName);

            if (observableEventArgType == null || expressionBody == null)
            {
                return(null);
            }

            var modifiers = eventDetails.IsStatic
                ? new[] { SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword }
                : new[] { SyntaxKind.PublicKeyword };

            var attributes = RoslynHelpers.GenerateObsoleteAttributeList(eventDetails);

            // Produces for static: public static global::System.IObservable<(argType1, argType2)> EventName => (contents of expression body)
            // Produces for instance: public global::System.IObservable<(argType1, argType2)> EventName => (contents of expression body)
            return(PropertyDeclaration(observableEventArgType, prefix + eventDetails.Name, attributes, modifiers, expressionBody, 2)
                   .WithLeadingTrivia(XmlSyntaxFactory.GenerateSummarySeeAlsoComment("Gets an observable which signals when the {0} event triggers.", eventDetails.ConvertToDocument()))
                   .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
        }
Example #8
0
        public void ReplaceNodesWithLiteralAsync()
        {
            var code       = @"
class X
{
int orgVarName1;
object orgVarName2;
}";
            var testHelper = new TestHelper(code);

            var variables = RoslynHelpers.GetSyntaxNodesAndTokens(
                testHelper.Document.GetSyntaxRootAsync()
                .Result.DescendantNodesAndSelf()
                .OfType <VariableDeclaratorSyntax>());

            var newSolution = testHelper.Workspace.CurrentSolution.ReplaceNodesWithLiteralAsync(variables, "newName", CancellationToken.None)
                              .Result;

            var newDoc  = newSolution.GetDocument(testHelper.Document.Id);
            var newtext = newDoc.GetSyntaxTreeAsync().Result.ToString();

            Assert.IsTrue(newtext.Contains("int newName;"));
            Assert.IsTrue(newtext.Contains("object newName;"));
        }
Example #9
0
        private void SearchStartingFromInterface(Compilation compilation, INamedTypeSymbol namedType, out INamedTypeSymbol lazinatorObjectType, out INamedTypeSymbol namedInterfaceType)
        {
            lazinatorObjectType = null;
            namedInterfaceType  = null;
            // If this is a Lazinator interface and we can find the Lazinator class, we'll consider doing an analysis.
            if (namedType.HasAttributeOfType <CloneLazinatorAttribute>())
            {
                // find candidate matching classes
                // maybe another approach would be to use SymbolFinder, but we can't load the Solution in the code analyzer. var implementations = SymbolFinder.FindImplementationsAsync(namedType, ... See https://stackoverflow.com/questions/23203206/roslyn-current-workspace-in-diagnostic-with-code-fix-project for a possible workaround
                IEnumerable <ISymbol> candidates = compilation.GetSymbolsWithName(name => RoslynHelpers.GetNameWithoutGenericArity(name) == RoslynHelpers.GetNameWithoutGenericArity(namedType.MetadataName).Substring(1), SymbolFilter.Type);
                lazinatorObjectType = candidates.OfType <INamedTypeSymbol>().FirstOrDefault(x => namedType.GetFullNamespacePlusSimpleName() == x.GetTopLevelInterfaceImplementingAttribute(_lazinatorAttributeType).GetFullNamespacePlusSimpleName());

                if (lazinatorObjectType != null)
                {
                    namedInterfaceType = namedType;
                }
                // Note: A more comprehensive, but slower approach would be to use context.Compilation.GlobalNamespace...
            }
        }
Example #10
0
        public static async Task <Solution> AttemptFixGenerateLazinatorCodeBehind(Document originalDocument, LazinatorPairInformation lazinatorPairInformation, CancellationToken cancellationToken)
        {
            var             originalSolution = originalDocument.Project.Solution;
            LazinatorConfig config           = lazinatorPairInformation.LoadLazinatorConfig();

            var semanticModel = await originalDocument.GetSemanticModelAsync(cancellationToken);

            LazinatorCompilation generator = null;

            if (!RecycleLazinatorCompilation || _LastLazinatorCompilation == null)
            {
                generator = new LazinatorCompilation(semanticModel.Compilation, lazinatorPairInformation.LazinatorObject.Name, lazinatorPairInformation.LazinatorObject.GetFullMetadataName(), config);
                if (RecycleLazinatorCompilation)
                {
                    _LastLazinatorCompilation = generator;
                }
            }
            else
            {
                generator = _LastLazinatorCompilation;
                generator.Initialize(semanticModel.Compilation, lazinatorPairInformation.LazinatorObject.Name, lazinatorPairInformation.LazinatorObject.GetFullMetadataName());
            }
            var d          = new ObjectDescription(generator.ImplementingTypeSymbol, generator, originalDocument.FilePath);
            var codeBehind = d.GetCodeBehind();

            string fileExtension      = config?.GeneratedCodeFileExtension ?? ".laz.cs";
            var    project            = originalDocument.Project;
            string codeBehindFilePath = null;
            string codeBehindName     = null;

            string[] codeBehindFolders      = null;
            bool     useFullyQualifiedNames = (config?.UseFullyQualifiedNames ?? false) || generator.ImplementingTypeSymbol.ContainingType != null || generator.ImplementingTypeSymbol.IsGenericType;

            codeBehindName = RoslynHelpers.GetEncodableVersionOfIdentifier(generator.ImplementingTypeSymbol, useFullyQualifiedNames) + fileExtension;

            string[] GetFolders(string fileName)
            {
                return(fileName.Split('\\', '/').Where(x => !x.Contains(".cs") && !x.Contains(".csproj")).ToArray());
            }

            if (config?.GeneratedCodePath == null)
            { // use short form of name in same location as original code
                codeBehindFilePath = originalDocument.FilePath;
                codeBehindFolders  = GetFolders(codeBehindFilePath).Skip(GetFolders(originalDocument.Project.FilePath).Count()).ToArray();
            }
            else
            { // we have a config file specifying a common directory
                codeBehindFilePath = config.GeneratedCodePath;
                if (!codeBehindFilePath.EndsWith("\\"))
                {
                    codeBehindFilePath += "\\";
                }
                codeBehindFolders = config.RelativeGeneratedCodePath.Split('\\', '/');
            }
            codeBehindFilePath = System.IO.Path.GetDirectoryName(codeBehindFilePath);
            while (codeBehindFilePath.EndsWith(".cs"))
            {
                var lastSlash = codeBehindFilePath.IndexOfAny(new char[] { '\\', '/' });
                if (lastSlash >= 0)
                {
                    codeBehindFilePath = codeBehindFilePath.Substring(0, lastSlash);
                }
            }
            while (codeBehindFilePath.EndsWith("\\"))
            {
                codeBehindFilePath = codeBehindFilePath.Substring(0, codeBehindFilePath.Length - 1);
            }
            codeBehindFilePath += "\\" + codeBehindName;

            Solution revisedSolution;

            if (lazinatorPairInformation.CodeBehindLocation == null)
            { // The file does not already exist
              // codeBehindFilePath = System.IO.Path.GetDirectoryName(codeBehindFilePath); // omit file name
                Document documentToAdd = project.AddDocument(codeBehindName, codeBehind, codeBehindFolders, codeBehindFilePath);
                //if (config.GeneratedCodePath != null)
                //    documentToAdd = documentToAdd.WithFolders(codeBehindFolders);
                revisedSolution = documentToAdd.Project.Solution;
            }
            else
            { // the file does already exist
                var currentDocumentWithCode = originalSolution.GetDocument(lazinatorPairInformation.CodeBehindLocation.SourceTree);
                var replacementDocument     = currentDocumentWithCode.WithText(SourceText.From(codeBehind));
                revisedSolution = originalSolution.WithDocumentText(currentDocumentWithCode.Id, SourceText.From(codeBehind));
            }
            revisedSolution = await AddAnnotationToIndicateSuccess(revisedSolution, true);

            return(revisedSolution);
        }
Example #11
0
        private void SetPropertiesIncludingInherited(INamedTypeSymbol interfaceSymbol)
        {
            List <PropertyWithDefinitionInfo> propertiesWithLevel = Container.Compilation.PropertiesForType[LazinatorCompilation.TypeSymbolToString(interfaceSymbol)];

            foreach (var unofficialProperty in GetUnofficialProperties(interfaceSymbol))
            {
                if (!propertiesWithLevel.Any(x => x.Property.MetadataName == unofficialProperty.PropertySymbol.MetadataName))
                {
                    propertiesWithLevel.Add(new PropertyWithDefinitionInfo(unofficialProperty.PropertySymbol, PropertyWithDefinitionInfo.Level.IsDefinedThisLevel)
                    {
                        PropertyAccessibility = unofficialProperty.PropertyAccessibility
                    });
                }
            }
            foreach (var baseType in Container.GetBaseLazinatorObjects())
            {
                List <IPropertySymbol> additionalProperties;
                bool baseTypeIsIndexed = Container.Compilation.TypeToExclusiveInterface.ContainsKey(LazinatorCompilation.TypeSymbolToString(baseType.ILazinatorTypeSymbol));
                if (baseTypeIsIndexed)
                {
                    var baseExclusiveInterface = Container.Compilation.TypeToExclusiveInterface[LazinatorCompilation.TypeSymbolToString(baseType.ILazinatorTypeSymbol)];
                    additionalProperties = Container.Compilation.PropertiesForType[baseExclusiveInterface].Select(x => x.Property).ToList();
                }
                else
                {
                    additionalProperties = new List <IPropertySymbol>();
                }
                foreach (var baseProperty in additionalProperties)
                {
                    if (!propertiesWithLevel.Any(x => x.Property.MetadataName == baseProperty.MetadataName))
                    {
                        propertiesWithLevel.Add(new PropertyWithDefinitionInfo(baseProperty, PropertyWithDefinitionInfo.Level.IsDefinedLowerLevelButNotInInterface)
                        {
                            DerivationKeyword = "override "
                        });
                    }
                }
                // now, unofficial properties
                var baseUnofficialProperties = GetUnofficialProperties(baseType.InterfaceTypeSymbol);
                foreach (var unofficialProperty in baseUnofficialProperties)
                {
                    if (!propertiesWithLevel.Any(x => x.Property.MetadataName == unofficialProperty.PropertySymbol.MetadataName))
                    {
                        propertiesWithLevel.Add(new PropertyWithDefinitionInfo(unofficialProperty.PropertySymbol, PropertyWithDefinitionInfo.Level.IsDefinedLowerLevelButNotInInterface)
                        {
                            DerivationKeyword = "override ", PropertyAccessibility = unofficialProperty.PropertyAccessibility
                        });
                    }
                }
            }
            var firstProblem = propertiesWithLevel.FirstOrDefault(x => !RoslynHelpers.ParentAndChildShareNullabilityContext(NullableContextSetting, x.Property.GetNullableContextForSymbol(Compilation, true)));

            if (firstProblem != null)
            {
                throw new LazinatorCodeGenException($"Lazinator requires properties of an interface to have the same nullability context as the interface itself. {NamedTypeSymbol} has nullability context {NullableContextSetting} while {firstProblem.Property} has nullability context {firstProblem.Property.GetNullableContextForSymbol(Compilation, true)}");
            }

            var orderedPropertiesWithLevel = propertiesWithLevel.Select(x => new { propertyWithLevel = x, description = new PropertyDescription(x.Property, Container, NullableContextSetting, x.DerivationKeyword, x.PropertyAccessibility, false) })
                                             .OrderByDescending(x => x.description.PropertyType == LazinatorPropertyType.PrimitiveType || x.description.PropertyType == LazinatorPropertyType.PrimitiveTypeNullable) // primitive properties are always first (but will only be redefined if defined abstractly below)
                                             .ThenBy(x => x.propertyWithLevel.LevelInfo == PropertyWithDefinitionInfo.Level.IsDefinedThisLevel)
                                             .ThenBy(x => x.description.RelativeOrder)
                                             .ThenBy(x => x.description.PropertyName).ToList();
            var last = orderedPropertiesWithLevel.LastOrDefault();

            if (last != null)
            {
                last.description.IsLast = true;
            }

            // A property that ends with "_Dirty" is designed to track dirtiness of another property. We will thus treat it specially.
            var dirtyPropertiesWithLevel = propertiesWithLevel.Where(x => x.Property.Name.EndsWith("_Dirty")).ToList();

            if (dirtyPropertiesWithLevel.Any(x => (x.Property.Type as INamedTypeSymbol)?.Name != "Boolean"))
            {
                throw new LazinatorCodeGenException($"Property ending with _Dirty must be of type bool.");
            }
            PropertiesIncludingInherited = new List <PropertyDescription>();
            PropertiesToDefineThisLevel  = new List <PropertyDescription>();
            PropertiesInherited          = new List <PropertyDescription>();

            foreach (var orderedProperty in orderedPropertiesWithLevel)
            {
                if (orderedProperty.propertyWithLevel.LevelInfo ==
                    PropertyWithDefinitionInfo.Level.IsDefinedInLowerLevelInterface)
                {
                    orderedProperty.description.IsDefinedInLowerLevelInterface = true;
                    orderedProperty.description.DerivationKeyword = "override ";
                }

                if (!dirtyPropertiesWithLevel.Any(x => x.Property.Name == orderedProperty.propertyWithLevel.Property.Name))
                { // this is not itself a "_Dirty" property, though it may have a corresponding _Dirty property.
                    PropertiesIncludingInherited.Add(orderedProperty.description);
                    if (orderedProperty.propertyWithLevel.LevelInfo == PropertyWithDefinitionInfo.Level.IsDefinedThisLevel ||
                        (
                            !Container.IsAbstract  // if we have two consecutive abstract classes, we don't want to repeat the abstract properties
                            &&
                            !Container.GetBaseLazinatorObjects().Any(x => !x.IsAbstract && x.PropertiesToDefineThisLevel.Any(y => y.PropertyName == orderedProperty.description.PropertyName)))
                        )
                    {
                        PropertiesToDefineThisLevel.Add(orderedProperty.description);
                    }
                    else
                    {
                        PropertiesInherited.Add(orderedProperty.description);
                    }
                }
            }

            // for each _dirty property, set TrackDirtinessNonSerialized on the corresponding property.
            foreach (var dirtyWithLevel in dirtyPropertiesWithLevel)
            {
                var match = PropertiesIncludingInherited.SingleOrDefault(x => x.PropertyName + "_Dirty" == dirtyWithLevel.Property.Name);
                if (match == null)
                {
                    throw new LazinatorCodeGenException(
                              $"Property ending with _Dirty must have a corresponding property without the ending.");
                }
                if (!match.IsNonLazinatorType)
                {
                    throw new LazinatorCodeGenException(
                              $"Property ending with _Dirty must correspond to a nonserialized property without the ending (not to a Lazinator or primitive type).");
                }
                match.TrackDirtinessNonSerialized = true;
                match = PropertiesToDefineThisLevel.SingleOrDefault(x => x.PropertyName + "_Dirty" == dirtyWithLevel.Property.Name);
                if (match != null)
                {
                    match.TrackDirtinessNonSerialized = true;
                }
            }
        }