static Compilation CreateCoreCompilation() { return(CSharpCompilation.Create( "FunctionCompletion", references: new[] { RoslynHelpers.GetReference(typeof(string).Assembly.Location), } )); }
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); }
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); }
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); }
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))); }
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;")); }
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... } }
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); }
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; } } }