internal static IEnumerable<ISymbol> GetDeclaredSymbols(SemanticModel semanticModel, MemberDeclarationSyntax memberDeclaration, CancellationToken cancellationToken) { if (memberDeclaration is FieldDeclarationSyntax) { return ((FieldDeclarationSyntax)memberDeclaration).Declaration.Variables.Select( v => semanticModel.GetDeclaredSymbol(v, cancellationToken)); } return SpecializedCollections.SingletonEnumerable( semanticModel.GetDeclaredSymbol(memberDeclaration, cancellationToken)); }
protected override bool TryInitializeState( Document document, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken, out INamedTypeSymbol classType, out INamedTypeSymbol abstractClassType) { var baseClassNode = node as TypeSyntax; if (baseClassNode != null && baseClassNode.Parent is BaseTypeSyntax && baseClassNode.Parent.IsParentKind(SyntaxKind.BaseList) && ((BaseTypeSyntax)baseClassNode.Parent).Type == baseClassNode) { if (baseClassNode.Parent.Parent.IsParentKind(SyntaxKind.ClassDeclaration)) { abstractClassType = model.GetTypeInfo(baseClassNode, cancellationToken).Type as INamedTypeSymbol; cancellationToken.ThrowIfCancellationRequested(); if (abstractClassType.IsAbstractClass()) { var classDecl = baseClassNode.Parent.Parent.Parent as ClassDeclarationSyntax; classType = model.GetDeclaredSymbol(classDecl, cancellationToken) as INamedTypeSymbol; return classType != null && abstractClassType != null; } } } classType = null; abstractClassType = null; return false; }
protected static void VerifyModelForDeclarationPatternDuplicateInSameScope(SemanticModel model, DeclarationPatternSyntax decl) { var symbol = model.GetDeclaredSymbol(decl); Assert.Equal(decl.Identifier.ValueText, symbol.Name); Assert.Equal(decl, symbol.DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Equal(LocalDeclarationKind.PatternVariable, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)decl)); Assert.NotEqual(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText)); var type = ((LocalSymbol)symbol).Type; if (!decl.Type.IsVar || !type.IsErrorType()) { Assert.Equal(type, model.GetSymbolInfo(decl.Type).Symbol); } }
internal override Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, CancellationToken cancellationToken) { var actions = ImmutableArray.CreateBuilder<CodeAction>(); // Fix 1: Add a NonSerialized attribute to the field var fieldNode = GetFieldDeclarationNode(nodeToFix); if (fieldNode != null) { var generator = SyntaxGenerator.GetGenerator(document); var codeAction = new MyDocumentCodeAction(FxCopFixersResources.AddNonSerializedAttribute, async ct => await AddNonSerializedAttribute(document, model, root, fieldNode, generator).ConfigureAwait(false)); actions.Add(codeAction); // Fix 2: If the type of the field is defined in source, then add the serializable attribute to the type. var fieldSymbol = model.GetDeclaredSymbol(nodeToFix, cancellationToken) as IFieldSymbol; var type = fieldSymbol.Type; if (type.Locations.Any(l => l.IsInSource)) { var typeCodeAction = new MySolutionCodeAction(FxCopFixersResources.AddSerializableAttribute, async ct => await AddSerializableAttributeToType(document, model, generator, type, cancellationToken).ConfigureAwait(false)); actions.Add(typeCodeAction); } } return Task.FromResult<IEnumerable<CodeAction>>(actions.ToImmutable()); }
internal async override Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, CancellationToken cancellationToken) { IEnumerable<CodeAction> actions = null; // Fix 1: Add a NonSerialized attribute to the field var fieldNode = GetFieldDeclarationNode(nodeToFix); if (fieldNode != null) { var attr = CodeGenerationSymbolFactory.CreateAttributeData(WellKnownTypes.NonSerializedAttribute(model.Compilation)); var newNode = CodeGenerator.AddAttributes(fieldNode, document.Project.Solution.Workspace, SpecializedCollections.SingletonEnumerable(attr)).WithAdditionalAnnotations(Formatting.Formatter.Annotation); var newDocument = document.WithSyntaxRoot(root.ReplaceNode(fieldNode, newNode)); var codeAction = CodeAction.Create(FxCopFixersResources.AddNonSerializedAttribute, newDocument); actions = SpecializedCollections.SingletonEnumerable(codeAction); // Fix 2: If the type of the field is defined in source, then add the serializable attribute to the type. var fieldSymbol = model.GetDeclaredSymbol(nodeToFix) as IFieldSymbol; var type = fieldSymbol.Type; if (type.Locations.Any(l => l.IsInSource)) { var typeDeclNode = type.DeclaringSyntaxReferences.First().GetSyntax(); var serializableAttr = CodeGenerationSymbolFactory.CreateAttributeData(WellKnownTypes.SerializableAttribute(model.Compilation)); var newTypeDeclNode = CodeGenerator.AddAttributes(typeDeclNode, document.Project.Solution.Workspace, SpecializedCollections.SingletonEnumerable(serializableAttr)).WithAdditionalAnnotations(Formatting.Formatter.Annotation); var documentContainingNode = document.Project.Solution.GetDocument(typeDeclNode.SyntaxTree); var docRoot = await documentContainingNode.GetSyntaxRootAsync(cancellationToken); var newDocumentContainingNode = documentContainingNode.WithSyntaxRoot(docRoot.ReplaceNode(typeDeclNode, newTypeDeclNode)); var typeCodeAction = CodeAction.Create(FxCopFixersResources.AddSerializableAttribute, newDocumentContainingNode.Project.Solution); actions = actions.Concat(typeCodeAction); } } return actions; }
private static bool CanRemoveTypeFromParameter( SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { // We reduce any the parameters that are contained inside ParameterList if (node != null && node.IsParentKind(SyntaxKind.ParameterList) && node.Parent.IsParentKind(SyntaxKind.ParenthesizedLambdaExpression)) { var parameterSyntax = (ParameterSyntax)node; if (parameterSyntax.Type != null) { var annotation = new SyntaxAnnotation(); var newParameterSyntax = parameterSyntax.WithType(null).WithAdditionalAnnotations(annotation); var oldLambda = node.FirstAncestorOrSelf<ParenthesizedLambdaExpressionSyntax>(); var newLambda = oldLambda.ReplaceNode(parameterSyntax, newParameterSyntax); var speculationAnalyzer = new SpeculationAnalyzer(oldLambda, newLambda, semanticModel, cancellationToken); newParameterSyntax = (ParameterSyntax)speculationAnalyzer.ReplacedExpression.GetAnnotatedNodesAndTokens(annotation).First(); var oldSymbol = semanticModel.GetDeclaredSymbol(parameterSyntax, cancellationToken); var newSymbol = speculationAnalyzer.SpeculativeSemanticModel.GetDeclaredSymbol(newParameterSyntax, cancellationToken); if (oldSymbol != null && newSymbol != null && oldSymbol.Type == newSymbol.Type) { return !speculationAnalyzer.ReplacementChangesSemantics(); } } } return false; }
public static ISymbol GetDeclaredOriginalSymbol(SyntaxNode syntaxNode, SemanticModel semanticModel, SemanticModel preportSemanticModel = null) { if (semanticModel == null && preportSemanticModel == null) { return(null); } var symbol = semanticModel?.GetDeclaredSymbol(syntaxNode); if (symbol == null && preportSemanticModel != null) { try { symbol = preportSemanticModel.GetDeclaredSymbol(syntaxNode); } catch (Exception) { //When looking for a symbol, and the semantic model is not passed, this generates an error. //We don't log this error because this is an expected behavior when there's no previous semantic models } } return(symbol); }
protected static void VerifyModelForDeclarationPattern( SemanticModel model, SingleVariableDesignationSyntax designation, bool isShadowed, params IdentifierNameSyntax[] references) { var symbol = model.GetDeclaredSymbol(designation); Assert.Equal(designation.Identifier.ValueText, symbol.Name); Assert.Equal(designation, symbol.DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Equal(LocalDeclarationKind.PatternVariable, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)designation)); var other = model.LookupSymbols(designation.SpanStart, name: designation.Identifier.ValueText).Single(); if (isShadowed) { Assert.NotEqual(symbol, other); } else { Assert.Same(symbol, other); } Assert.True(model.LookupNames(designation.SpanStart).Contains(designation.Identifier.ValueText)); var decl = (DeclarationPatternSyntax)designation.Parent; Assert.True(SyntaxFacts.IsInNamespaceOrTypeContext(decl.Type)); Assert.True(SyntaxFacts.IsInTypeOnlyContext(decl.Type)); var local = ((SourceLocalSymbol)symbol); var type = local.Type; if (type.IsErrorType()) { Assert.Null(model.GetSymbolInfo(decl.Type).Symbol); } else { Assert.Equal(type, model.GetSymbolInfo(decl.Type).Symbol); } foreach (var reference in references) { Assert.Same(symbol, model.GetSymbolInfo(reference).Symbol); Assert.Same(symbol, model.LookupSymbols(reference.SpanStart, name: designation.Identifier.ValueText).Single()); Assert.True(model.LookupNames(reference.SpanStart).Contains(designation.Identifier.ValueText)); } }
private static SyntaxNode RemoveFlagsAttribute(Workspace workspace, SemanticModel model, SyntaxNode enumTypeSyntax, INamedTypeSymbol flagsAttributeType, CancellationToken cancellationToken) { var enumType = model.GetDeclaredSymbol(enumTypeSyntax) as INamedTypeSymbol; Contract.ThrowIfNull(enumType); var flagsAttribute = enumType.GetAttributes().First(a => a.AttributeClass == flagsAttributeType); return CodeGenerator.RemoveAttribute(enumTypeSyntax, workspace, flagsAttribute, CodeGenerationOptions.Default, cancellationToken); }
internal override Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, Diagnostic diagnostic, CancellationToken cancellationToken) { var classSymbol = (INamedTypeSymbol)model.GetDeclaredSymbol(nodeToFix, cancellationToken); var instanceConstructors = classSymbol.InstanceConstructors.Where(t => t.DeclaredAccessibility == Accessibility.Public).Select(t => GetDeclaration(t)).Where(d => d != null).ToList(); var generator = SyntaxGenerator.GetGenerator(document); var newRoot = root.ReplaceNodes(instanceConstructors, (original, rewritten) => generator.WithAccessibility(original, Accessibility.Protected)); return Task.FromResult(document.WithSyntaxRoot(newRoot)); }
private static SyntaxNode RemoveFlagsAttribute(Workspace workspace, SemanticModel model, SyntaxNode enumTypeSyntax, INamedTypeSymbol flagsAttributeType, CancellationToken cancellationToken) { var enumType = model.GetDeclaredSymbol(enumTypeSyntax, cancellationToken) as INamedTypeSymbol; Debug.Assert(enumType != null); var flagsAttribute = enumType.GetAttributes().First(a => a.AttributeClass == flagsAttributeType); var attributeNode = flagsAttribute.ApplicationSyntaxReference.GetSyntax(cancellationToken); var generator = SyntaxGenerator.GetGenerator(workspace, enumTypeSyntax.Language); return generator.RemoveNode(enumTypeSyntax, attributeNode); }
private ReferenceRewriter( SemanticModel semanticModel, VariableDeclaratorSyntax variableDeclarator, ExpressionSyntax expressionToInline, CancellationToken cancellationToken) { _semanticModel = semanticModel; _localSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator, cancellationToken); _variableDeclarator = variableDeclarator; _expressionToInline = expressionToInline; _cancellationToken = cancellationToken; }
internal override Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, string diagnosticId, CancellationToken cancellationToken) { var classSymbol = (INamedTypeSymbol)model.GetDeclaredSymbol(nodeToFix); var instanceConstructors = classSymbol.InstanceConstructors.Where(t => t.DeclaredAccessibility == Accessibility.Public).Select(t => t.DeclaringSyntaxReferences[0].GetSyntax()); var workspace = document.Project.Solution.Workspace; Func<SyntaxNode, SyntaxNode, SyntaxNode> replacementForNodes = (constructorNode, dummy) => { var newSyntax = CodeGenerator.UpdateDeclarationAccessibility(constructorNode, workspace, Accessibility.Protected, cancellationToken: cancellationToken).WithAdditionalAnnotations(Formatter.Annotation); return newSyntax; }; return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNodes(instanceConstructors, replacementForNodes))); }
internal static ISymbol GetDeclaredSymbolSafe(this SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) { if (node == null) { return(null); } var semanticModelFor = semanticModel.SemanticModelFor(node); if (semanticModelFor != null) { return(semanticModelFor.GetDeclaredSymbol(node, cancellationToken)); } return(semanticModel?.GetDeclaredSymbol(node, cancellationToken)); }
protected async Task<SyntaxNode> ConvertMethodToAsync(Document document, SemanticModel semanticModel, SyntaxNode methodNode, CancellationToken cancellationToken) { var methodSymbol = semanticModel.GetDeclaredSymbol(methodNode, cancellationToken) as IMethodSymbol; if (methodSymbol.ReturnsVoid) { return AddAsyncKeyword(methodNode); } var returnType = methodSymbol.ReturnType; var compilation = semanticModel.Compilation; var taskSymbol = compilation.GetTypeByMetadataName(SystemThreadingTasksTask); var genericTaskSymbol = compilation.GetTypeByMetadataName(SystemThreadingTasksTaskT); if (taskSymbol == null) { return null; } if (returnType is IErrorTypeSymbol) { // The return type of the method will not bind. This could happen for a lot of reasons. // The type may not actually exist or the user could just be missing a using/import statement. // We're going to try and see if there are any known types that have the same name as // our return type, and then check if those are convertible to Task. If they are then // we assume the user just has a missing using. If they are not, we wrap the return // type in a generic Task. var typeName = returnType.Name; var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>(); var results = await SymbolFinder.FindDeclarationsAsync( document.Project, typeName, ignoreCase: syntaxFacts.IsCaseSensitive, filter: SymbolFilter.Type, cancellationToken: cancellationToken).ConfigureAwait(false); if (results.OfType<ITypeSymbol>().Any(s => DoesConversionExist(compilation, s, taskSymbol))) { return AddAsyncKeyword(methodNode); } return AddAsyncKeywordAndTaskReturnType(methodNode, returnType, genericTaskSymbol); } if (DoesConversionExist(compilation, returnType, taskSymbol)) { return AddAsyncKeyword(methodNode); } return AddAsyncKeywordAndTaskReturnType(methodNode, returnType, genericTaskSymbol); }
private IList<INamespaceSymbol> GetExistingNamespaces( SemanticModel semanticModel, NamespaceDeclarationSyntax namespaceDeclaration, CancellationToken cancellationToken) { var q = from u in namespaceDeclaration.Usings let symbol = semanticModel.GetSymbolInfo(u.Name, cancellationToken).Symbol as INamespaceSymbol where symbol != null && !symbol.IsGlobalNamespace select symbol; var usingImports = q.ToList(); var namespaceSymbol = semanticModel.GetDeclaredSymbol(namespaceDeclaration, cancellationToken) as INamespaceSymbol; var namespaceImports = GetContainingNamespacesAndThis(namespaceSymbol).ToList(); var outerNamespaces = this.GetExistingNamespaces(semanticModel, namespaceDeclaration.Parent, cancellationToken); return outerNamespaces.Concat(namespaceImports).Concat(usingImports) .Distinct() .OrderBy(INamespaceSymbolExtensions.CompareNamespaces) .ToList(); }
internal async override Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, Diagnostic diagnostic, CancellationToken cancellationToken) { var symbol = model.GetDeclaredSymbol(nodeToFix, cancellationToken); var generator = SyntaxGenerator.GetGenerator(document); // There was no constructor and so the diagnostic was on the type. Generate a serlialization ctor. if (symbol.Kind == SymbolKind.NamedType) { var typeSymbol = symbol as INamedTypeSymbol; var throwStatement = generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))); var ctorDecl = generator.ConstructorDeclaration( typeSymbol.Name, new[] { generator.ParameterDeclaration("serializationInfo", generator.TypeExpression(WellKnownTypes.SerializationInfo(model.Compilation))), generator.ParameterDeclaration("streamingContext", generator.TypeExpression(WellKnownTypes.StreamingContext(model.Compilation))) }, typeSymbol.IsSealed ? Accessibility.Private : Accessibility.Protected, statements: new[] { throwStatement }); var editor = SymbolEditor.Create(document.Project.Solution); await editor.EditOneDeclarationAsync(typeSymbol, nodeToFix.GetLocation(), (e, d) => e.AddMember(d, ctorDecl), cancellationToken); return editor.GetChangedDocuments().First(); } else if (symbol.Kind == SymbolKind.Method) { // There is a serialization constructor but with incorrect accessibility. Set that right. var methodSymbol = symbol as IMethodSymbol; // This would be constructor and can have only one definition. Debug.Assert(methodSymbol.IsConstructor() && methodSymbol.DeclaringSyntaxReferences.Count() == 1); var declaration = await methodSymbol.DeclaringSyntaxReferences.First().GetSyntaxAsync(cancellationToken); var newAccessibility = methodSymbol.ContainingType.IsSealed ? Accessibility.Private : Accessibility.Protected; var newDecl = generator.WithAccessibility(declaration, newAccessibility); return document.WithSyntaxRoot(root.ReplaceNode(declaration, newDecl)); } return document; }
internal async override Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, string diagnosticId, CancellationToken cancellationToken) { var syntaxFactoryService = document.GetLanguageService<SyntaxGenerator>(); var symbol = model.GetDeclaredSymbol(nodeToFix); // There was no constructor and so the diagnostic was on the type. Generate a serlialization ctor. if (symbol.Kind == SymbolKind.NamedType) { var typeSymbol = symbol as INamedTypeSymbol; var throwStatement = syntaxFactoryService.CreateThrowNotImplementedStatementBlock(model.Compilation); var parameters = ImmutableArray.Create( CodeGenerationSymbolFactory.CreateParameterSymbol(WellKnownTypes.SerializationInfo(model.Compilation), "serializationInfo"), CodeGenerationSymbolFactory.CreateParameterSymbol(WellKnownTypes.StreamingContext(model.Compilation), "streamingContext")); var ctorSymbol = CodeGenerationSymbolFactory.CreateConstructorSymbol(null, typeSymbol.IsSealed ? Accessibility.Private : Accessibility.Protected, new SymbolModifiers(), typeSymbol.Name, parameters, throwStatement); return await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, typeSymbol, ctorSymbol).ConfigureAwait(false); } else if (symbol.Kind == SymbolKind.Method) { // There is a serialization constructor but with incorrect accessibility. Set that right. var methodSymbol = symbol as IMethodSymbol; // This would be constructor and can have only one definition. Debug.Assert(methodSymbol.IsConstructor() && methodSymbol.DeclaringSyntaxReferences.Count() == 1); var declaration = await methodSymbol.DeclaringSyntaxReferences.First().GetSyntaxAsync(cancellationToken); var newAccessibility = methodSymbol.ContainingType.IsSealed ? Accessibility.Private : Accessibility.Protected; var newDecl = CodeGenerator.UpdateDeclarationAccessibility(declaration, document.Project.Solution.Workspace, newAccessibility, cancellationToken: cancellationToken); return document.WithSyntaxRoot(root.ReplaceNode(declaration, newDecl)); } return document; }
public async override Task RegisterCodeFixesAsync(CodeFixContext context) { context.CancellationToken.ThrowIfCancellationRequested(); var rootTask = context.Document.GetSyntaxRootAsync(context.CancellationToken); var semanticModelTask = context.Document.GetSemanticModelAsync(context.CancellationToken); await Task.WhenAll(rootTask, semanticModelTask).ConfigureAwait(false); var root = rootTask.Result; SemanticModel semanticModel = semanticModelTask.Result; if (!(root?.FindNode(context.Span) is ClassDeclarationSyntax dacNode)) { return; } INamedTypeSymbol dacTypeSymbol = semanticModel?.GetDeclaredSymbol(dacNode, context.CancellationToken); if (dacTypeSymbol == null || dacTypeSymbol.MemberNames.Contains(TypeNames.ReferentialIntegrity.PrimaryKeyClassName)) { return; } var pxContext = new PXContext(semanticModel.Compilation, codeAnalysisSettings: null); if (pxContext.ReferentialIntegritySymbols.PrimaryKeyOf == null) { return; } var codeActionTitle = nameof(Resources.PX1033Fix).GetLocalized().ToString(); var codeAction = CodeAction.Create(codeActionTitle, cancellation => AddPrimaryKeyDeclarationToDacAsync(context.Document, root, dacNode, pxContext, dacTypeSymbol, cancellation), equivalenceKey: codeActionTitle); context.RegisterCodeFix(codeAction, context.Diagnostics); }
protected override bool TryInitializeState( Document document, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken, out SyntaxNode classOrStructDecl, out INamedTypeSymbol classOrStructType, out IEnumerable<INamedTypeSymbol> interfaceTypes) { if (!cancellationToken.IsCancellationRequested) { var interfaceNode = node as TypeSyntax; if (interfaceNode != null && interfaceNode.Parent is BaseTypeSyntax && interfaceNode.Parent.IsParentKind(SyntaxKind.BaseList) && ((BaseTypeSyntax)interfaceNode.Parent).Type == interfaceNode) { if (interfaceNode.Parent.Parent.IsParentKind(SyntaxKind.ClassDeclaration) || interfaceNode.Parent.Parent.IsParentKind(SyntaxKind.StructDeclaration)) { var interfaceSymbolInfo = model.GetSymbolInfo(interfaceNode, cancellationToken); if (interfaceSymbolInfo.CandidateReason != CandidateReason.WrongArity) { var interfaceType = interfaceSymbolInfo.GetAnySymbol() as INamedTypeSymbol; cancellationToken.ThrowIfCancellationRequested(); if (interfaceType != null && interfaceType.TypeKind == TypeKind.Interface) { classOrStructDecl = interfaceNode.Parent.Parent.Parent as TypeDeclarationSyntax; classOrStructType = model.GetDeclaredSymbol(classOrStructDecl, cancellationToken) as INamedTypeSymbol; interfaceTypes = SpecializedCollections.SingletonEnumerable(interfaceType); return interfaceTypes != null && classOrStructType != null; } } } } } classOrStructDecl = null; classOrStructType = null; interfaceTypes = null; return false; }
private static void VerifyModelForDeconstructionField(SemanticModel model, SingleVariableDesignationSyntax decl, params IdentifierNameSyntax[] references) { var field = (FieldSymbol)model.GetDeclaredSymbol(decl); Assert.Equal(decl.Identifier.ValueText, field.Name); Assert.Equal(SymbolKind.Field, ((FieldSymbol)field).Kind); Assert.Same(field, model.GetDeclaredSymbol((SyntaxNode)decl)); Assert.Same(field, model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.Equal(Accessibility.Private, field.DeclaredAccessibility); Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText)); foreach (var reference in references) { Assert.Same(field, model.GetSymbolInfo(reference).Symbol); Assert.Same(field, model.LookupSymbols(reference.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.True(model.LookupNames(reference.SpanStart).Contains(decl.Identifier.ValueText)); Assert.Equal(field.Type, model.GetTypeInfo(reference).Type); } }
private void TestAnonymousTypePropertySymbol(SemanticModel model, SyntaxNode node, string name) { Assert.NotNull(node); var symbol = model.GetDeclaredSymbol(node); Assert.NotNull(symbol); Assert.Equal(name, symbol.ToTestDisplayString()); }
static Action AnalyzeActionMethod( Compilation compilation, SemanticModel semanticModel, MethodDeclarationSyntax actionMethodDeclaration, Dictionary <string, Compilation> referencedSymbols) { // Get some symbols by full name. var httpGetSymbol = compilation.GetTypeByMetadataName("System.Web.Http.HttpGetAttribute"); var httpPostSymbol = compilation.GetTypeByMetadataName("System.Web.Http.HttpPostAttribute"); var httpPutSymbol = compilation.GetTypeByMetadataName("System.Web.Http.HttpPutAttribute"); var httpDeleteSymbol = compilation.GetTypeByMetadataName("System.Web.Http.HttpDeleteAttribute"); var routeSymbol = compilation.GetTypeByMetadataName("System.Web.Http.RouteAttribute"); var fromBodySymbol = compilation.GetTypeByMetadataName("System.Web.Http.FromBodyAttribute"); var fromUriSymbol = compilation.GetTypeByMetadataName("System.Web.Http.FromUriAttribute"); var methodSymbol = semanticModel.GetDeclaredSymbol(actionMethodDeclaration); var action = new Action { DocumentationCommentId = methodSymbol.GetDocumentationCommentId(), Name = methodSymbol.Name, BodyParameters = new List <Parameter>(), QueryParameters = new List <Parameter>(), RouteParameters = new List <Parameter>(), Examples = new List <Example>(), Results = new List <Result>() }; // Go through the method's XML comments. var methodCommentsXml = methodSymbol.GetDocumentationCommentXml(); var parameterNotes = new Dictionary <string, XElement>(); if (!string.IsNullOrWhiteSpace(methodCommentsXml)) { var methodCommentsRoot = XElement.Parse(methodCommentsXml); var summary = methodCommentsRoot.Element("summary"); if (summary != null) { foreach (var cref in summary.GetCrefs()) { if (!referencedSymbols.ContainsKey(cref)) { referencedSymbols.Add(cref, compilation); } } action.Summary = summary.ToMarkup(); } var remarks = methodCommentsRoot.Element("remarks"); if (remarks != null) { foreach (var cref in remarks.GetCrefs()) { if (!referencedSymbols.ContainsKey(cref)) { referencedSymbols.Add(cref, compilation); } } action.Remarks = remarks.ToMarkup(); } var returns = methodCommentsRoot.Element("returns"); if (returns != null) { foreach (var cref in returns.GetCrefs()) { if (!referencedSymbols.ContainsKey(cref)) { referencedSymbols.Add(cref, compilation); } } action.Returns = returns.ToMarkup(); } foreach (var example in methodCommentsRoot.Elements("example")) { action.Examples.Add(new Example { Label = example.Attribute("label").Value, Content = string .Concat(example.Nodes()) .NormalizeCodeIndentation() }); } parameterNotes = methodCommentsRoot .Elements("param") .ToDictionary( p => p.Attribute("name").Value, p => p); } var methodName = actionMethodDeclaration.Identifier.ValueText; var routeKeys = Enumerable.Empty <string>(); // Go through the method's attributes. foreach (var attributeList in actionMethodDeclaration.AttributeLists) { foreach (var attribute in attributeList.Attributes) { // For each attribute, try to pull a recognized value. var attributeTypeInfo = semanticModel.GetTypeInfo(attribute); if (attributeTypeInfo.Type.MetadataName == httpGetSymbol.MetadataName) { action.Method = "GET"; } else if (attributeTypeInfo.Type.MetadataName == httpPostSymbol.MetadataName) { action.Method = "POST"; } else if (attributeTypeInfo.Type.MetadataName == httpPutSymbol.MetadataName) { action.Method = "PUT"; } else if (attributeTypeInfo.Type.MetadataName == httpDeleteSymbol.MetadataName) { action.Method = "DELETE"; } else if (attributeTypeInfo.Type.MetadataName == routeSymbol.MetadataName) { var routeArgument = attribute .ArgumentList .Arguments .Single() .Expression as LiteralExpressionSyntax; action.Route = routeArgument.Token.ValueText; routeKeys = Regex .Matches(action.Route, "(?<={)[^}]+(?=})") .Cast <Match>() .Select(m => m.Value) .ToList(); } } } // Go through parameters foreach (var parameter in actionMethodDeclaration.ParameterList.Parameters) { var predefinedType = parameter.Type as PredefinedTypeSyntax; //var typeName = predefinedType != null ? // predefinedType.Keyword.ValueText : // (parameter.Type as SimpleNameSyntax).Identifier.ValueText; var typeInfo = semanticModel.GetTypeInfo(parameter.Type); var documentCommentId = typeInfo.Type.GetDocumentationCommentId(); if (!string.IsNullOrWhiteSpace(documentCommentId) && !referencedSymbols.ContainsKey(documentCommentId)) { referencedSymbols.Add(documentCommentId, compilation); } var parameterType = semanticModel.GetTypeInfo(parameter.Type); var parameterName = parameter.Identifier.ValueText; var fromBody = false; var fromUri = false; foreach (var attributeList in parameter.AttributeLists) { foreach (var attribute in attributeList.Attributes) { var attributeTypeInfo = semanticModel.GetTypeInfo(attribute); if (attributeTypeInfo.Type.MetadataName == fromBodySymbol.MetadataName) { fromBody = true; } else if (attributeTypeInfo.Type.MetadataName == fromUriSymbol.MetadataName) { fromUri = true; } } } var outParameter = new Parameter { Key = parameterName, TypeName = typeInfo.Type.ToTypeDisplayName(), TypeDocumentCommentId = typeInfo.Type.GetDocumentationCommentId(), Optional = false, // TODO: not this Notes = parameterNotes.ContainsKey(parameterName) ? parameterNotes[parameterName].ToMarkup() : null }; if (routeKeys.Contains(parameterName)) { action.RouteParameters.Add(outParameter); } else if (fromUri || parameterType.Type.IsValueType) { action.QueryParameters.Add(outParameter); } else if (fromBody || !parameterType.Type.IsValueType) { action.BodyParameters.Add(outParameter); } } var returnStatements = actionMethodDeclaration .DescendantNodes() .OfType <ReturnStatementSyntax>() .ToList(); foreach (var returnStatement in returnStatements) { var resultMethodInvocation = returnStatement .DescendantNodes() .OfType <InvocationExpressionSyntax>() .First(); var invokedMethodSymbol = semanticModel .GetSymbolInfo(resultMethodInvocation.Expression) .Symbol as IMethodSymbol; var argumentSyntax = resultMethodInvocation .ArgumentList .Arguments .SingleOrDefault(); var result = new Result { Kind = invokedMethodSymbol.Name }; if (argumentSyntax != null) { var l = argumentSyntax.DescendantNodes().First(); var literalExpression = l as LiteralExpressionSyntax; if (literalExpression != null) { result.ArgumentText = ScrubArgumentText(literalExpression.Token.ValueText); } var argumentSymbol = semanticModel.GetSymbolInfo(argumentSyntax); var argumentTypeInfo = semanticModel.GetTypeInfo(argumentSyntax.Expression); var typeName = argumentTypeInfo.Type.Name; result.ArgumentType = argumentTypeInfo.Type.ToDisplayString(); } action.Results.Add(result); } return(action); }
public static void AnalyzeLocalDeclarationStatement(SyntaxNodeAnalysisContext context) { var localDeclaration = (LocalDeclarationStatementSyntax)context.Node; if (localDeclaration.ContainsDiagnostics) { return; } if (localDeclaration.SpanOrTrailingTriviaContainsDirectives()) { return; } if (localDeclaration.IsConst) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration); if (!localInfo.Success) { return; } SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(localDeclaration.NextStatement()); if (!assignmentInfo.Success) { return; } if (assignmentInfo.Statement.ContainsDiagnostics) { return; } if (assignmentInfo.Statement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (!(assignmentInfo.Left is IdentifierNameSyntax identifierName)) { return; } string name = identifierName.Identifier.ValueText; if (!string.Equals(localInfo.IdentifierText, name, StringComparison.Ordinal)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; if (!(semanticModel.GetSymbol(identifierName, cancellationToken) is ILocalSymbol localSymbol)) { return; } if (!localSymbol.Equals(semanticModel.GetDeclaredSymbol(localInfo.Declarator, cancellationToken))) { return; } ExpressionSyntax value = localInfo.Value; if (value != null) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken); if (typeSymbol == null) { return; } if (!semanticModel.IsDefaultValue(typeSymbol, value, cancellationToken)) { return; } if (IsReferenced(localSymbol, assignmentInfo.Right, semanticModel, cancellationToken)) { return; } } context.ReportDiagnostic(DiagnosticDescriptors.MergeLocalDeclarationWithAssignment, localInfo.Identifier); if (value != null) { context.ReportNode(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, localInfo.Initializer); context.ReportToken(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, assignmentInfo.OperatorToken); } context.ReportToken(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, localDeclaration.SemicolonToken); context.ReportNode(DiagnosticDescriptors.MergeLocalDeclarationWithAssignmentFadeOut, assignmentInfo.Left); }
private static IEnumerable<INamedTypeSymbol> GetTypesInFile(SemanticModel semanticModel, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.NavigationBar_ItemService_GetTypesInFile_CSharp, cancellationToken)) { var types = new HashSet<INamedTypeSymbol>(); var nodesToVisit = new Stack<SyntaxNode>(); nodesToVisit.Push(semanticModel.SyntaxTree.GetRoot(cancellationToken)); while (!nodesToVisit.IsEmpty()) { if (cancellationToken.IsCancellationRequested) { return SpecializedCollections.EmptyEnumerable<INamedTypeSymbol>(); } var node = nodesToVisit.Pop(); var type = node.TypeSwitch( (BaseTypeDeclarationSyntax t) => semanticModel.GetDeclaredSymbol(t, cancellationToken), (EnumDeclarationSyntax e) => semanticModel.GetDeclaredSymbol(e, cancellationToken), (DelegateDeclarationSyntax d) => semanticModel.GetDeclaredSymbol(d, cancellationToken)); if (type != null) { types.Add((INamedTypeSymbol)type); } if (node is BaseMethodDeclarationSyntax || node is BasePropertyDeclarationSyntax || node is BaseFieldDeclarationSyntax || node is StatementSyntax || node is ExpressionSyntax) { // quick bail out to prevent us from creating every nodes exist in current file continue; } foreach (var child in node.ChildNodes()) { nodesToVisit.Push(child); } } return types; } }
private static void VerifyModelForDeclarationPatternDuplicateInSameScope(SemanticModel model, DeclarationPatternSyntax decl) { var symbol = model.GetDeclaredSymbol(decl); Assert.Equal(decl.Identifier.ValueText, symbol.Name); Assert.Equal(LocalDeclarationKind.PatternVariable, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)decl)); Assert.NotEqual(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText)); }
internal static Accessibility GetDeclaredAccessibility(this BasePropertyDeclarationSyntax syntax, SemanticModel semanticModel, CancellationToken cancellationToken) { if (syntax == null) { throw new ArgumentNullException(nameof(syntax)); } if (semanticModel == null) { throw new ArgumentNullException(nameof(semanticModel)); } AccessLevel accessLevel = GetAccessLevel(syntax.Modifiers); if (accessLevel != AccessLevel.NotSpecified) { return(accessLevel.ToAccessibility()); } PropertyDeclarationSyntax propertyDeclarationSyntax = syntax as PropertyDeclarationSyntax; if (propertyDeclarationSyntax != null) { if (propertyDeclarationSyntax.ExplicitInterfaceSpecifier == null) { return(Accessibility.Private); } else { return(Accessibility.Public); } } IndexerDeclarationSyntax indexerDeclarationSyntax = syntax as IndexerDeclarationSyntax; if (indexerDeclarationSyntax != null) { if (indexerDeclarationSyntax.ExplicitInterfaceSpecifier == null) { return(Accessibility.Private); } else { return(Accessibility.Public); } } EventDeclarationSyntax eventDeclarationSyntax = syntax as EventDeclarationSyntax; if (eventDeclarationSyntax != null) { if (eventDeclarationSyntax.ExplicitInterfaceSpecifier == null) { return(Accessibility.Private); } else { return(Accessibility.Public); } } ISymbol declaredSymbol = semanticModel.GetDeclaredSymbol(syntax, cancellationToken); return(declaredSymbol?.DeclaredAccessibility ?? Accessibility.NotApplicable); }
private static void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context) { var property = (PropertyDeclarationSyntax)context.Node; if (property.ContainsDiagnostics) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IFieldSymbol fieldSymbol = null; AccessorDeclarationSyntax getter = null; AccessorDeclarationSyntax setter = null; ArrowExpressionClauseSyntax expressionBody = property.ExpressionBody; if (expressionBody != null) { IdentifierNameSyntax identifierName = GetIdentifierNameFromExpression(expressionBody.Expression); if (identifierName != null) { fieldSymbol = GetBackingFieldSymbol(identifierName, semanticModel, cancellationToken); } } else { getter = property.Getter(); if (getter != null) { setter = property.Setter(); if (setter != null) { fieldSymbol = GetBackingFieldSymbol(getter, setter, semanticModel, cancellationToken); } else { IdentifierNameSyntax identifierName = GetIdentifierNameFromGetter(getter); if (identifierName != null) { fieldSymbol = GetBackingFieldSymbol(identifierName, semanticModel, cancellationToken); } } } } if (fieldSymbol == null) { return; } var variableDeclarator = (VariableDeclaratorSyntax)fieldSymbol.GetSyntax(cancellationToken); if (variableDeclarator.SyntaxTree != property.SyntaxTree) { return; } if (variableDeclarator.IsParentKind(SyntaxKind.VariableDeclaration) && variableDeclarator.Parent.Parent is FieldDeclarationSyntax fieldDeclaration && fieldDeclaration.AttributeLists.Any()) { return; } if (!CheckPreprocessorDirectives(property)) { return; } if (!CheckPreprocessorDirectives(variableDeclarator)) { return; } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(property, cancellationToken); if (propertySymbol?.IsStatic != fieldSymbol.IsStatic) { return; } if (!propertySymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty) { return; } if (!SymbolEqualityComparer.Default.Equals(propertySymbol.Type, fieldSymbol.Type)) { return; } if (!SymbolEqualityComparer.Default.Equals(propertySymbol.ContainingType, fieldSymbol.ContainingType)) { return; } if (setter == null && propertySymbol.IsOverride && propertySymbol.OverriddenProperty?.SetMethod != null) { return; } cancellationToken.ThrowIfCancellationRequested(); foreach (AttributeData attributeData in fieldSymbol.GetAttributes()) { if (attributeData.AttributeClass.HasMetadataName(MetadataNames.System_NonSerializedAttribute)) { return; } } if (HasStructLayoutAttributeWithExplicitKind(propertySymbol.ContainingType)) { return; } if (!IsFixableBackingField(property, propertySymbol, fieldSymbol, semanticModel, cancellationToken)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseAutoProperty, property.Identifier); if (property.ExpressionBody != null) { DiagnosticHelpers.ReportNode(context, DiagnosticRules.UseAutoPropertyFadeOut, property.ExpressionBody); } else { if (getter != null) { FadeOut(getter); } if (setter != null) { FadeOut(setter); } } void FadeOut(AccessorDeclarationSyntax accessor) { BlockSyntax body = accessor.Body; if (body != null) { switch (body.Statements[0]) { case ReturnStatementSyntax returnStatement: { DiagnosticHelpers.ReportToken(context, DiagnosticRules.UseAutoPropertyFadeOut, returnStatement.ReturnKeyword); DiagnosticHelpers.ReportNode(context, DiagnosticRules.UseAutoPropertyFadeOut, returnStatement.Expression); break; } case ExpressionStatementSyntax expressionStatement: { DiagnosticHelpers.ReportNode(context, DiagnosticRules.UseAutoPropertyFadeOut, expressionStatement.Expression); break; } } CSharpDiagnosticHelpers.ReportBraces(context, DiagnosticRules.UseAutoPropertyFadeOut, body); } else { DiagnosticHelpers.ReportNode(context, DiagnosticRules.UseAutoPropertyFadeOut, accessor.ExpressionBody); } } }
public DisposableChecker(ClassDeclarationSyntax classDeclaration, SemanticModel semanticModel) { this.classDeclaration = classDeclaration; this.semanticModel = semanticModel; this.classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration); }
protected override void ProcessBlock(Block block, out HashSet <ISymbol> assignedInBlock, out HashSet <ISymbol> usedInBlock) { assignedInBlock = new HashSet <ISymbol>(); // Kill (The set of variables that are assigned a value.) usedInBlock = new HashSet <ISymbol>(); // Gen (The set of variables that are used before any assignment.) var assignmentLhs = new HashSet <SyntaxNode>(); foreach (var instruction in block.Instructions.Reverse()) { switch (instruction.Kind()) { case SyntaxKind.IdentifierName: ProcessIdentifier(instruction, assignedInBlock, usedInBlock, assignmentLhs); break; case SyntaxKind.SimpleAssignmentExpression: ProcessSimpleAssignment(instruction, assignedInBlock, usedInBlock, assignmentLhs); break; case SyntaxKind.VariableDeclarator: ProcessVariableDeclarator((VariableDeclaratorSyntax)instruction, assignedInBlock, usedInBlock); break; case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.QueryExpression: CollectAllCapturedLocal(instruction); break; default: break; } } if (block.Instructions.Any()) { return; } // Variable declaration in a foreach statement is not a VariableDeclarator, so handling it separately: if (block is BinaryBranchBlock foreachBlock && foreachBlock.BranchingNode.IsKind(SyntaxKind.ForEachStatement)) { var foreachNode = (ForEachStatementSyntax)foreachBlock.BranchingNode; ProcessVariableInForeach(foreachNode, assignedInBlock, usedInBlock); } // Keep alive the variables declared and used in the using statement until the UsingFinalizerBlock if (block is UsingEndBlock usingFinalizerBlock) { var disposableSymbols = usingFinalizerBlock.Identifiers .Select(i => semanticModel.GetDeclaredSymbol(i.Parent) ?? semanticModel.GetSymbolInfo(i.Parent).Symbol) .WhereNotNull(); foreach (var disposableSymbol in disposableSymbols) { usedInBlock.Add(disposableSymbol); } } }
MethodDeclarationSyntax RewriteMethod(MethodDeclarationSyntax inMethodSyntax, SemanticModel semanticModel) { var inMethodSymbol = semanticModel.GetDeclaredSymbol(inMethodSyntax); //Log.LogMessage("Method {0}: {1}", inMethodInfo.Symbol.Name, inMethodInfo.Symbol.); var outMethodName = inMethodSyntax.Identifier.Text + "Async"; _log.Debug(" Rewriting method {0} to {1}", inMethodSymbol.Name, outMethodName); // Visit all method invocations inside the method, rewrite them to async if needed var rewriter = new MethodInvocationRewriter(_log, semanticModel, _excludedTypes, _cancellationTokenSymbol, GenerateConfigureAwait); var outMethod = (MethodDeclarationSyntax)rewriter.Visit(inMethodSyntax); // Method signature outMethod = outMethod .WithIdentifier(SyntaxFactory.Identifier(outMethodName)) .WithAttributeLists(new SyntaxList <AttributeListSyntax>()) .WithModifiers(inMethodSyntax.Modifiers .Add(SyntaxFactory.Token(SyntaxKind.AsyncKeyword)) //.Remove(SyntaxFactory.Token(SyntaxKind.OverrideKeyword)) //.Remove(SyntaxFactory.Token(SyntaxKind.NewKeyword)) ) // Insert the cancellation token into the parameter list at the right place .WithParameterList(SyntaxFactory.ParameterList(inMethodSyntax.ParameterList.Parameters.Insert( inMethodSyntax.ParameterList.Parameters.TakeWhile(p => p.Default == null && !p.Modifiers.Any(m => m.IsKind(SyntaxKind.ParamsKeyword))).Count(), SyntaxFactory.Parameter( SyntaxFactory.List <AttributeListSyntax>(), SyntaxFactory.TokenList(), SyntaxFactory.ParseTypeName("CancellationToken"), SyntaxFactory.Identifier("cancellationToken"), null )))); // Transform return type adding Task<> var returnType = inMethodSyntax.ReturnType.ToString(); outMethod = outMethod.WithReturnType(SyntaxFactory.ParseTypeName( returnType == "void" ? "Task" : $"Task<{returnType}>") ); // Remove the override and new attributes. Seems like the clean .Remove above doesn't work... for (var i = 0; i < outMethod.Modifiers.Count;) { var text = outMethod.Modifiers[i].Text; if (text == "override" || text == "new") { outMethod = outMethod.WithModifiers(outMethod.Modifiers.RemoveAt(i)); continue; } i++; } var attr = inMethodSymbol.GetAttributes().Single(a => a.AttributeClass.Name == "RewriteAsyncAttribute"); if (attr.ConstructorArguments.Length > 0 && (bool)attr.ConstructorArguments[0].Value) { outMethod = outMethod.AddModifiers(SyntaxFactory.Token(SyntaxKind.OverrideKeyword)); } return(outMethod); }
private static ReduceIfNestingAnalysisResult AnalyzeCore( IfStatementSyntax ifStatement, SemanticModel semanticModel, SyntaxKind jumpKind, ReduceIfNestingOptions options, CancellationToken cancellationToken = default(CancellationToken)) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); if (!statementsInfo.Success) { return(Fail(ifStatement)); } SyntaxNode node = statementsInfo.Parent; SyntaxNode parent = node.Parent; SyntaxKind parentKind = parent.Kind(); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; if (statementsInfo.IsParentSwitchSection || parentKind == SyntaxKind.SwitchSection) { SyntaxNode switchSection = (statementsInfo.IsParentSwitchSection) ? node : parent; if (!options.AllowSwitchSection()) { return(Fail(switchSection)); } if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(switchSection)); } if (!IsFixableJumpStatement(statements.Last(), ref jumpKind)) { return(Fail(switchSection)); } if (!options.AllowNestedFix() && IsNestedFix(switchSection.Parent, semanticModel, options, cancellationToken)) { return(Fail(switchSection)); } return(Success(jumpKind, switchSection)); } if (parentKind.Is( SyntaxKind.ForStatement, SyntaxKind.ForEachStatement, SyntaxKind.DoStatement, SyntaxKind.WhileStatement)) { if (!options.AllowLoop()) { return(Fail(parent)); } StatementSyntax lastStatement = statements.Last(); if (ifStatement == lastStatement) { jumpKind = SyntaxKind.ContinueStatement; } else { if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(parent)); } if (!IsFixableJumpStatement(lastStatement, ref jumpKind)) { return(Fail(parent)); } } if (!options.AllowNestedFix() && IsNestedFix(parent.Parent, semanticModel, options, cancellationToken)) { return(Fail(parent)); } return(Success(jumpKind, parent)); } if (!IsFixable(ifStatement, statements, ref jumpKind)) { return(Fail(node)); } switch (parentKind) { case SyntaxKind.ConstructorDeclaration: case SyntaxKind.DestructorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { jumpKind = SyntaxKind.ReturnStatement; } else if (jumpKind != SyntaxKind.ReturnStatement) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.GetAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.MethodDeclaration: { var methodDeclaration = (MethodDeclarationSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (methodDeclaration.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (methodDeclaration.Modifiers.Contains(SyntaxKind.AsyncKeyword) && semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .OriginalDefinition .IsIEnumerableOrIEnumerableOfT() == true && methodDeclaration.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.LocalFunctionStatement: { var localFunction = (LocalFunctionStatementSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (localFunction.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (localFunction.Modifiers.Contains(SyntaxKind.AsyncKeyword) && semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)? .ReturnType .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)? .ReturnType .OriginalDefinition .IsIEnumerableOrIEnumerableOfT() == true && localFunction.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: { var anonymousFunction = (AnonymousFunctionExpressionSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (!(semanticModel.GetSymbol(anonymousFunction, cancellationToken) is IMethodSymbol methodSymbol)) { return(Fail(parent)); } if (methodSymbol.ReturnsVoid) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (anonymousFunction.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword && methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)) { return(Success(SyntaxKind.ReturnStatement, parent)); } break; } case SyntaxKind.IfStatement: { ifStatement = (IfStatementSyntax)parent; if (ifStatement.Parent is ElseClauseSyntax elseClause) { if (ifStatement.Else != null) { return(Fail(parent)); } if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement.GetTopmostIf(), semanticModel, jumpKind, options, cancellationToken)); } else { if (!IsFixable(ifStatement)) { return(Fail(parent)); } if (!options.AllowNestedFix()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement, semanticModel, jumpKind, options, cancellationToken)); } } case SyntaxKind.ElseClause: { if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } var elseClause = (ElseClauseSyntax)parent; return(AnalyzeCore(elseClause.GetTopmostIf(), semanticModel, jumpKind, options, cancellationToken)); } } return(Fail(parent)); }
/// <summary> /// Analyzes the project and returns information about the diagnostics in it. /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task <ImmutableList <DocumentationDiagnostic> > GetDiagnosticsAsync() { var diagnostics = ImmutableList.CreateBuilder <DocumentationDiagnostic>(); var syntaxTrees = _analyzerCompilation.SyntaxTrees; foreach (var syntaxTree in syntaxTrees) { var match = _diagnosticPathRegex.Match(syntaxTree.FilePath); if (!match.Success) { continue; } string shortName = match.Groups["name"].Value; string noCodeFixReason = null; // Check if this syntax tree represents a diagnostic SyntaxNode syntaxRoot = await syntaxTree.GetRootAsync().ConfigureAwait(false); SemanticModel semanticModel = _analyzerCompilation.GetSemanticModel(syntaxTree); SyntaxNode classSyntaxNode = syntaxRoot.DescendantNodes().FirstOrDefault(x => x.IsKind(SyntaxKind.ClassDeclaration)); if (classSyntaxNode == null) { continue; } INamedTypeSymbol classSymbol = semanticModel.GetDeclaredSymbol(classSyntaxNode) as INamedTypeSymbol; if (!InheritsFrom(classSymbol, _diagnosticAnalyzerTypeSymbol)) { continue; } if (classSymbol.IsAbstract) { continue; } IEnumerable <DiagnosticDescriptor> descriptorInfos = GetDescriptor(classSymbol); foreach (var descriptorInfo in descriptorInfos) { var(codeFixStatus, fixAllStatus) = GetCodeFixAndFixAllStatus(descriptorInfo.Id, classSymbol, out noCodeFixReason); string status = GetStatus(classSymbol, syntaxRoot, semanticModel, descriptorInfo); if (descriptorInfo.CustomTags.Contains(WellKnownDiagnosticTags.NotConfigurable)) { continue; } var diagnostic = new DocumentationDiagnostic { Id = descriptorInfo.Id, Category = descriptorInfo.Category, Severity = descriptorInfo.DefaultSeverity.ToString(), Status = status, Name = shortName, Title = descriptorInfo.Title.ToString(), HelpLink = descriptorInfo.HelpLinkUri, CodeFixStatus = codeFixStatus, FixAllStatus = fixAllStatus, NoCodeFixReason = noCodeFixReason, }; diagnostics.Add(diagnostic); } } return(diagnostics.ToImmutable()); }
public static IEnumerable <ExpressionSyntax> GetNonNewObjectReturnsForPropertyGet( PropertyDeclarationSyntax propertyDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState1) { var propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration); if (propertySymbol.GetMethod == null) { yield break; } if (!propertySymbol.ReturnsByRef && IsCompleteValueType(propertySymbol.Type)) { yield break; } List <ExpressionSyntax> returnExpressions; if (propertyDeclaration.AccessorList != null) { var getAccessor = propertyDeclaration.AccessorList.Accessors.FirstOrNoValue(x => x.Keyword.Kind() == SyntaxKind.GetKeyword); if (getAccessor.HasNoValue) { yield break; } var getAccessorValue = getAccessor.GetValue(); returnExpressions = getAccessorValue.ExpressionBody != null ? new List <ExpressionSyntax>() { getAccessorValue.ExpressionBody.Expression } : getAccessor.GetValue() .DescendantNodes() .OfType <ReturnStatementSyntax>() .Select(x => x.Expression) .ToList(); } else if (propertyDeclaration.ExpressionBody != null) { returnExpressions = new List <ExpressionSyntax>() { propertyDeclaration.ExpressionBody.Expression }; } else { yield break; } foreach (var expression in returnExpressions) { if (!Utils.IsNewlyCreatedObject(semanticModel, expression, knownSymbols, RecursiveIsNewlyCreatedObjectState.Empty(), recursiveState1)) { yield return(expression); } } }
private static void VerifyModelForOutField( SemanticModel model, DeclarationExpressionSyntax decl, bool duplicate, params IdentifierNameSyntax[] references) { var variableDesignationSyntax = GetVariableDesignation(decl); var symbol = model.GetDeclaredSymbol(variableDesignationSyntax); Assert.Equal(decl.Identifier().ValueText, symbol.Name); Assert.Equal(SymbolKind.Field, symbol.Kind); Assert.Equal(variableDesignationSyntax, symbol.DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)variableDesignationSyntax)); var symbols = model.LookupSymbols(decl.SpanStart, name: decl.Identifier().ValueText); var names = model.LookupNames(decl.SpanStart); if (duplicate) { Assert.True(symbols.Count() > 1); Assert.Contains(symbol, symbols); } else { Assert.Same(symbol, symbols.Single()); } Assert.Contains(decl.Identifier().ValueText, names); var local = (FieldSymbol)symbol; var typeSyntax = decl.Type(); Assert.True(SyntaxFacts.IsInNamespaceOrTypeContext(typeSyntax)); Assert.True(SyntaxFacts.IsInTypeOnlyContext(typeSyntax)); if (typeSyntax.IsVar && local.Type.IsErrorType()) { Assert.Null(model.GetSymbolInfo(typeSyntax).Symbol); } else { Assert.Equal(local.Type, model.GetSymbolInfo(typeSyntax).Symbol); } var declarator = decl.Ancestors().OfType<VariableDeclaratorSyntax>().FirstOrDefault(); var inFieldDeclaratorArgumentlist = declarator != null && declarator.Parent.Parent.Kind() != SyntaxKind.LocalDeclarationStatement && (declarator.ArgumentList?.Contains(decl)).GetValueOrDefault(); if (inFieldDeclaratorArgumentlist) { Assert.Null(model.GetSymbolInfo(decl).Symbol); Assert.Null(model.GetSymbolInfo(decl).Symbol); } else { Assert.Same(symbol, model.GetSymbolInfo(decl).Symbol); Assert.Same(symbol, model.GetSymbolInfo(decl).Symbol); } Assert.Null(model.GetDeclaredSymbol(decl)); foreach (var reference in references) { var referenceInfo = model.GetSymbolInfo(reference); symbols = model.LookupSymbols(reference.SpanStart, name: decl.Identifier().ValueText); if (duplicate) { Assert.Null(referenceInfo.Symbol); Assert.Contains(symbol, referenceInfo.CandidateSymbols); Assert.True(symbols.Count() > 1); Assert.Contains(symbol, symbols); } else { Assert.Same(symbol, referenceInfo.Symbol); Assert.Same(symbol, symbols.Single()); Assert.Equal(local.Type, model.GetTypeInfo(reference).Type); } Assert.True(model.LookupNames(reference.SpanStart).Contains(decl.Identifier().ValueText)); } if (!inFieldDeclaratorArgumentlist) { var dataFlowParent = (ExpressionSyntax)decl.Parent.Parent.Parent; if (model.IsSpeculativeSemanticModel) { Assert.Throws<NotSupportedException>(() => model.AnalyzeDataFlow(dataFlowParent)); } else { var dataFlow = model.AnalyzeDataFlow(dataFlowParent); if (dataFlow.Succeeded) { Assert.False(dataFlow.VariablesDeclared.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.AlwaysAssigned.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.WrittenInside.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.DataFlowsIn.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.ReadInside.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.DataFlowsOut.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.ReadOutside.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.WrittenOutside.Contains(symbol, ReferenceEqualityComparer.Instance)); } } } }
private static void AnalyzeWhileStatement(SyntaxNodeAnalysisContext context) { var whileStatement = (WhileStatementSyntax)context.Node; ExpressionSyntax condition = whileStatement.Condition; if (condition.IsMissing) { return; } if (!condition.IsSingleLine()) { return; } StatementSyntax statement = whileStatement.Statement; if (!(statement is BlockSyntax block)) { return; } SyntaxList <StatementSyntax> innerStatements = block.Statements; if (innerStatements.Count <= 1) { return; } ExpressionSyntax incrementedExpression = GetIncrementedExpression(innerStatements.Last()); if (!incrementedExpression.IsKind(SyntaxKind.IdentifierName)) { return; } SyntaxList <StatementSyntax> outerStatements = SyntaxInfo.StatementListInfo(whileStatement).Statements; int index = outerStatements.IndexOf(whileStatement); if (index <= 0) { return; } SingleLocalDeclarationStatementInfo localInfo = GetLocalInfo(outerStatements[index - 1]); if (!localInfo.Success) { return; } if (index > 1) { SingleLocalDeclarationStatementInfo localInfo2 = GetLocalInfo(outerStatements[index - 2]); if (localInfo2.Success) { ExpressionSyntax incrementedExpression2 = GetIncrementedExpression(innerStatements[innerStatements.Count - 2]); if (incrementedExpression2 is IdentifierNameSyntax identifierName2 && string.Equals(localInfo2.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal)) { return; } } } var identifierName = (IdentifierNameSyntax)incrementedExpression; if (!string.Equals(localInfo.Identifier.ValueText, identifierName.Identifier.ValueText, StringComparison.Ordinal)) { return; } if (ContainsContinueStatement()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ISymbol symbol = semanticModel.GetDeclaredSymbol(localInfo.Declarator, cancellationToken); if (symbol?.Kind != SymbolKind.Local) { return; } if (IsLocalVariableReferencedAfterWhileStatement()) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseForStatementInsteadOfWhileStatement, whileStatement.WhileKeyword); bool ContainsContinueStatement() { ContainsContinueStatementWalker walker = ContainsContinueStatementWalker.GetInstance(); walker.ContainsContinueStatement = false; var containsContinueStatement = false; foreach (StatementSyntax innerStatement in innerStatements) { walker.Visit(innerStatement); if (walker.ContainsContinueStatement) { containsContinueStatement = true; break; } } ContainsContinueStatementWalker.Free(walker); return(containsContinueStatement); } bool IsLocalVariableReferencedAfterWhileStatement() { ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(symbol, semanticModel, cancellationToken); walker.VisitList(outerStatements, index + 1); return(ContainsLocalOrParameterReferenceWalker.GetResultAndFree(walker)); } }
private static void VerifyModelForOutVarDuplicateInSameScope(SemanticModel model, DeclarationExpressionSyntax decl) { var variableDesignationSyntax = GetVariableDesignation(decl); var symbol = model.GetDeclaredSymbol(variableDesignationSyntax); Assert.Equal(decl.Identifier().ValueText, symbol.Name); Assert.Equal(variableDesignationSyntax, symbol.DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Equal(LocalDeclarationKind.RegularVariable, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)variableDesignationSyntax)); Assert.NotEqual(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier().ValueText).Single()); Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier().ValueText)); var local = (SourceLocalSymbol)symbol; if (decl.Type().IsVar && local.IsVar && local.Type.IsErrorType()) { Assert.Null(model.GetSymbolInfo(decl.Type()).Symbol); } else { Assert.Equal(local.Type, model.GetSymbolInfo(decl.Type()).Symbol); } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveVirtualModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassUnsealed) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddModifierAbstract) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberReadOnly) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSealedModifier)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxNode node = token.Parent; if (!CSharpFacts.CanHaveModifiers(node.Kind())) { node = node.FirstAncestor(f => CSharpFacts.CanHaveModifiers(f.Kind())); } Debug.Assert(node != null, $"{nameof(node)} is null"); if (node == null) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.ModifierIsNotValidForThisItem: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } SyntaxTokenList modifiers = SyntaxInfo.ModifierListInfo(node).Modifiers; if (modifiers.Contains(token)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token); break; } else if (IsInterfaceMemberOrExplicitInterfaceImplementation(node)) { ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, modifiers, f => { switch (f.Kind()) { case SyntaxKind.PublicKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.InternalKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.StaticKeyword: case SyntaxKind.VirtualKeyword: case SyntaxKind.OverrideKeyword: case SyntaxKind.AbstractKeyword: { return(true); } } return(false); }); } else if (node.IsKind(SyntaxKind.IndexerDeclaration)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword); } else if (node.IsKind(SyntaxKind.PropertyDeclaration)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword); } break; } case CompilerDiagnosticIdentifiers.MoreThanOneProtectionModifier: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token); } break; } case CompilerDiagnosticIdentifiers.AccessibilityModifiersMayNotBeUsedOnAccessorsInInterface: case CompilerDiagnosticIdentifiers.AccessModifiersAreNotAllowedOnStaticConstructors: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node); } break; } case CompilerDiagnosticIdentifiers.ModifiersCannotBePlacedOnEventAccessorDeclarations: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node); } break; } case CompilerDiagnosticIdentifiers.OnlyMethodsClassesStructsOrInterfacesMayBePartial: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword); } break; } case CompilerDiagnosticIdentifiers.ClassCannotBeBothStaticAndSealed: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword, additionalKey: nameof(SyntaxKind.SealedKeyword)); break; } case CompilerDiagnosticIdentifiers.FieldCanNotBeBothVolatileAndReadOnly: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } var fieldDeclaration = (FieldDeclarationSyntax)node; ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.VolatileKeyword, additionalKey: nameof(SyntaxKind.VolatileKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, additionalKey: nameof(SyntaxKind.ReadOnlyKeyword)); break; } case CompilerDiagnosticIdentifiers.NewProtectedMemberDeclaredInSealedClass: case CompilerDiagnosticIdentifiers.StaticClassesCannotContainProtectedMembers: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrPrivate); } break; } case CompilerDiagnosticIdentifiers.VirtualOrAbstractmembersCannotBePrivate: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected); } break; } case CompilerDiagnosticIdentifiers.AbstractPropertiesCannotHavePrivateAccessors: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node, additionalKey: CodeFixIdentifiers.RemoveInvalidModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected); } break; } case CompilerDiagnosticIdentifiers.StaticMemberCannotBeMarkedOverrideVirtualOrAbstract: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } if (!node.IsParentKind(SyntaxKind.ClassDeclaration) || !((ClassDeclarationSyntax)node.Parent).Modifiers.Contains(SyntaxKind.StaticKeyword)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword)); } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword, additionalKey: nameof(SyntaxKind.OverrideKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: nameof(SyntaxKind.VirtualKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword, additionalKey: nameof(SyntaxKind.AbstractKeyword)); break; } case CompilerDiagnosticIdentifiers.AsyncModifierCanOnlyBeUsedInMethodsThatHaveBody: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword); } break; } case CompilerDiagnosticIdentifiers.PartialMethodCannotHaveAccessModifiersOrVirtualAbstractOverrideNewSealedOrExternModifiers: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, f => { switch (f.Kind()) { case SyntaxKind.PublicKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.InternalKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.VirtualKeyword: case SyntaxKind.AbstractKeyword: case SyntaxKind.OverrideKeyword: case SyntaxKind.NewKeyword: case SyntaxKind.SealedKeyword: case SyntaxKind.ExternKeyword: { return(true); } } return(false); }); break; } case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeStatic: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier)) { AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier)) { var methodDeclaration = (MethodDeclarationSyntax)node; ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters.First(); SyntaxToken modifier = parameter.Modifiers.Find(SyntaxKind.ThisKeyword); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, parameter, modifier, additionalKey: CodeFixIdentifiers.RemoveThisModifier); } break; } case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeDefinedInNonGenericStaticClass: { if (!node.IsKind(SyntaxKind.ClassDeclaration)) { return; } var classDeclaration = (ClassDeclarationSyntax)node; if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) && !classDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword)) { AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier)) { IEnumerable <ParameterSyntax> thisParameters = classDeclaration.Members .Where(f => f.IsKind(SyntaxKind.MethodDeclaration)) .Cast <MethodDeclarationSyntax>() .Select(f => f.ParameterList?.Parameters.FirstOrDefault()) .Where(f => f?.Modifiers.Contains(SyntaxKind.ThisKeyword) == true); ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, thisParameters, SyntaxKind.ThisKeyword, title: "Remove 'this' modifier from extension methods", additionalKey: CodeFixIdentifiers.RemoveThisModifier); } break; } case CompilerDiagnosticIdentifiers.NoDefiningDeclarationFoundForImplementingDeclarationOfPartialMethod: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword); } break; } case CompilerDiagnosticIdentifiers.MethodHasParameterModifierThisWhichIsNotOnFirstParameter: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, token.Parent, token); } break; } case CompilerDiagnosticIdentifiers.CannotDeclareInstanceMembersInStaticClass: case CompilerDiagnosticIdentifiers.StaticClassesCannotHaveInstanceConstructors: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier)) { AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic)) { var classDeclaration = (ClassDeclarationSyntax)node.Parent; ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, classDeclaration, classDeclaration.Modifiers.Find(SyntaxKind.StaticKeyword), title: "Make containing class non-static", additionalKey: CodeFixIdentifiers.MakeContainingClassNonStatic); } break; } case CompilerDiagnosticIdentifiers.ElementsDefinedInNamespaceCannotBeExplicitlyDeclaredAsPrivateProtectedOrProtectedInternal: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternal); } break; } case CompilerDiagnosticIdentifiers.NamespaceAlreadyContainsDefinition: case CompilerDiagnosticIdentifiers.TypeAlreadyContainsDefinition: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier)) { break; } if (!node.IsKind( SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration, SyntaxKind.MethodDeclaration)) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetDeclaredSymbol(node, context.CancellationToken); ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences; if (syntaxReferences.Length <= 1) { break; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, ImmutableArray.CreateRange(syntaxReferences, f => f.GetSyntax(context.CancellationToken)), SyntaxKind.PartialKeyword); break; } case CompilerDiagnosticIdentifiers.NoSuitableMethodFoundToOverride: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword); } break; } case CompilerDiagnosticIdentifiers.AsyncMethodsCannotHaveRefOrOutParameters: case CompilerDiagnosticIdentifiers.IteratorsCannotHaveRefOrOutParameters: case CompilerDiagnosticIdentifiers.ReadOnlyFieldCannotBePassedAsRefOrOutValue: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.RefKeyword, additionalKey: nameof(SyntaxKind.RefKeyword)); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OutKeyword, additionalKey: nameof(SyntaxKind.OutKeyword)); } break; } case CompilerDiagnosticIdentifiers.CannotHaveInstancePropertyOrFieldInitializersInStruct: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier)) { AddStaticModifier(context, diagnostic, node); } break; } case CompilerDiagnosticIdentifiers.MemberMustDeclareBodyBecauseItIsNotMarkedAbstractExternOrPartial: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddModifierAbstract) && node.Kind() == SyntaxKind.MethodDeclaration && (node.Parent as ClassDeclarationSyntax)?.Modifiers.Contains(SyntaxKind.AbstractKeyword) == true) { ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword); } break; } case CompilerDiagnosticIdentifiers.NewVirtualMemberInSealedClass: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveVirtualModifier)) { ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: CodeFixIdentifiers.RemoveVirtualModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassUnsealed) && node.Parent is ClassDeclarationSyntax classDeclaration) { ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, classDeclaration, SyntaxKind.SealedKeyword, title: "Make containing class unsealed", additionalKey: CodeFixIdentifiers.MakeContainingClassUnsealed); } break; } case CompilerDiagnosticIdentifiers.InstanceFieldsOfReadOnlyStructsMustBeReadOnly: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberReadOnly)) { break; } ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.ReadOnlyKeyword); break; } case CompilerDiagnosticIdentifiers.MemberCannotBeSealedBecauseItIsNotOverride: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSealedModifier)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (semanticModel.GetDiagnostic( CompilerDiagnosticIdentifiers.MemberHidesInheritedMemberToMakeCurrentMethodOverrideThatImplementationAddOverrideKeyword, CSharpUtility.GetIdentifier(node).Span, context.CancellationToken) != null) { break; } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword); break; } } } }
private static ImmutableArray <ISymbol> GetConstructorParameterSymbols(BaseMethodDeclarationSyntax node, SemanticModel semanticModel) => node.ParameterList.Parameters .Select(syntax => (ISymbol)semanticModel.GetDeclaredSymbol(syntax)) .ToImmutableArray();
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out EnumDeclarationSyntax enumDeclaration)) { return; } Document document = context.Document; foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.AddNewLineBeforeEnumMember: { CodeAction codeAction = CodeAction.Create( "Add newline", cancellationToken => AddNewLineBeforeEnumMemberRefactoring.RefactorAsync(document, enumDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SortEnumMembers: { CodeAction codeAction = CodeAction.Create( $"Sort '{enumDeclaration.Identifier}' members", cancellationToken => SortEnumMembersAsync(document, enumDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.EnumShouldDeclareExplicitValues: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); INamedTypeSymbol enumSymbol = semanticModel.GetDeclaredSymbol(enumDeclaration, context.CancellationToken); EnumSymbolInfo enumInfo = EnumSymbolInfo.Create(enumSymbol); ImmutableArray <ulong> values = enumInfo .Fields .Where(f => f.HasValue && ((EnumMemberDeclarationSyntax)f.Symbol.GetSyntax(context.CancellationToken)).EqualsValue != null) .Select(f => f.Value) .ToImmutableArray(); Optional <ulong> optional = FlagsUtility <ulong> .Instance.GetUniquePowerOfTwo(values); if (!optional.HasValue || !ConvertHelpers.CanConvert(optional.Value, enumSymbol.EnumUnderlyingType.SpecialType)) { return; } bool isFlags = enumSymbol.HasAttribute(MetadataNames.System_FlagsAttribute); CodeAction codeAction = CodeAction.Create( "Declare explicit values", ct => DeclareExplicitValueAsync(document, enumDeclaration, enumSymbol, isFlags, useBitShift: false, values, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); if (isFlags) { CodeAction codeAction2 = CodeAction.Create( "Declare explicit values (and use '<<' operator)", ct => DeclareExplicitValueAsync(document, enumDeclaration, enumSymbol, isFlags, useBitShift: true, values, semanticModel, ct), GetEquivalenceKey(diagnostic, "BitShift")); context.RegisterCodeFix(codeAction2, diagnostic); } break; } case DiagnosticIdentifiers.UseBitShiftOperator: { CodeAction codeAction = CodeAction.Create( "Use '<<' operator", ct => UseBitShiftOperatorAsync(document, enumDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public void Execute(SourceGeneratorContext context) { context.AddSource("MemberAccessAttributes", SourceText.From(attributeText, Encoding.UTF8)); if (!(context.SyntaxReceiver is SyntaxReceiver receiver)) { return; } CSharpParseOptions options = (CSharpParseOptions)((CSharpCompilation)context.Compilation).SyntaxTrees[0].Options; Compilation compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(attributeText, Encoding.UTF8), options)); if (!(compilation.GetTypeByMetadataName("MemberAccess.ByIndexAttribute") is { } indexAttributeSymbol)) { return; } if (!(compilation.GetTypeByMetadataName("MemberAccess.ByNameAttribute") is { } nameAttributeSymbol)) { return; } if (!(compilation.GetTypeByMetadataName("MemberAccess.EnumerateAttribute") is { } enumerateAttributeSymbol)) { return; } var buffer = new StringBuilder(); foreach (var r in receiver.CandidateMethods) { SemanticModel model = compilation.GetSemanticModel(r.SyntaxTree); var flag = getMemberAccessAttribute(model, r); if (flag == Flag.None) { continue; } if (r.ParameterList is not { } list) { continue; } if (model.GetDeclaredSymbol(r) is not { } s) { continue; } var generatedSource = generate(s, list, flag); var filename = getFilename(s); context.AddSource(filename, SourceText.From(generatedSource, Encoding.UTF8)); } string getFilename(INamedTypeSymbol type) { buffer.Clear(); foreach (var part in type.ContainingNamespace.ToDisplayParts()) { if (part.Symbol is { Name: var name } && !string.IsNullOrEmpty(name)) { buffer.Append(name); buffer.Append('_'); } }
public override void VisitToken(SyntaxToken token) { VisitTriviaList(token.LeadingTrivia); if (token.Text == "Foo") { Console.WriteLine(); } IEnumerable <ColorizedWord> r = null; if (token.IsKeyword()) { r = Col(token.Text, "Keyword"); } else if (token.IsKind(SyntaxKind.StringLiteralToken)) { r = Col(token.Text, "StringLiteral"); } else if (token.IsKind(SyntaxKind.CharacterLiteralToken)) { r = Col(token.Text, "StringLiteral"); } else if (token.IsKind(SyntaxKind.IdentifierToken) && token.Parent is TypeParameterSyntax) { r = Col(token.Text, "UserType"); } else if (token.IsKind(SyntaxKind.IdentifierToken) && token.Parent is SimpleNameSyntax) { var name = token.Parent as SimpleNameSyntax; ISymbol symbol = null; try { symbol = sm?.GetSymbolInfo(name).Symbol; } catch (NullReferenceException) { } // https://github.com/dotnet/roslyn/issues/10023 this might throw NRE, even though it shouldn't... if (symbol?.Kind == SymbolKind.NamedType || symbol?.Kind == SymbolKind.TypeParameter) { r = Col(token.Text, "UserType"); } else if (symbol?.Kind == SymbolKind.Namespace || symbol?.Kind == SymbolKind.Parameter || symbol?.Kind == SymbolKind.Local || symbol?.Kind == SymbolKind.Field || symbol?.Kind == SymbolKind.Property) { r = Col(token.Text, "PlainText"); } else if (name.Identifier.Text == "var") { r = Col(token.Text, "Keyword"); } else if (new[] { "C", "T", "U", "V" }.Contains(name.Identifier.Text)) { r = Col(token.Text, "UserType"); } } else if (token.IsKind(SyntaxKind.IdentifierToken) && token.Parent is DeclarationStatementSyntax) { var name = token.Parent as DeclarationStatementSyntax; var symbol = sm.GetDeclaredSymbol(name); if (symbol?.Kind == SymbolKind.NamedType) { r = Col(token.Text, "UserType"); } } if (r == null) { if ((token.Parent as EnumStatementSyntax)?.Identifier == token) { r = Col(token.Text, "UserType"); } else if ((token.Parent as GenericNameSyntax)?.Identifier == token) { if ((token.Parent.Parent as InvocationExpressionSyntax)?.Expression == token.Parent || // e.g. "G<X>(1)" (token.Parent.Parent.Parent as InvocationExpressionSyntax)?.Expression == token.Parent.Parent) // e.g. e.G<X>(1) { r = Col(token.Text, "PlainText"); } else // all other G<A> will assume that G is a type { r = Col(token.Text, "UserType"); } } else if (token.Parent.IsKind(SyntaxKind.GenericName)) { if (token.Parent.Parent.IsKind(SyntaxKind.SimpleAsClause) || // e.g. "dim x As HashSet" the HashSet token.Parent.Parent.IsKind(SyntaxKind.ObjectCreationExpression)) // e.g. "dim x As New HashSet" or "dim x = New HashSet" { r = Col(token.Text, "UserType"); } } else if (token.Parent.IsKind(SyntaxKind.IdentifierName)) { if (token.Parent.Parent.IsKind(SyntaxKind.Parameter) || token.Parent.Parent.IsKind(SyntaxKind.Attribute) || token.Parent.Parent.IsKind(SyntaxKind.CatchStatement) || token.Parent.Parent.IsKind(SyntaxKind.ObjectCreationExpression) || token.Parent.Parent.IsKind(SyntaxKind.SubStatement) || token.Parent.Parent.IsKind(SyntaxKind.FunctionStatement) || token.Parent.Parent.IsKind(SyntaxKind.InheritsStatement) || // e.g. "public sealed class BuilderRouteHandler IRouteHandler" IRouteHandler in this case token.Parent.Parent.IsKind(SyntaxKind.GetTypeExpression) || // e.g. "GetType(BaseBuilder);" BaseBuilder in this case token.Parent.Parent.IsKind(SyntaxKind.SimpleAsClause) || // e.g. "private DbProviderFactory dbProviderFactory;" Or "DbConnection connection = dbProviderFactory.CreateConnection();" token.Parent.Parent.IsKind(SyntaxKind.TypeArgumentList)) // e.g. "DbTypes = New Dictionary();" DbType in this case { r = Col(token.Text, "UserType"); } else if ((token.Parent.Parent as CastExpressionSyntax)?.Type == token.Parent || // e.g. "(Foo)x" the Foo (token.Parent.Parent as TypeConstraintSyntax)?.Type == token.Parent || // e.g. "where T:Foo" the Foo (token.Parent.Parent as ArrayTypeSyntax)?.ElementType == token.Parent) // e.g. "Foo[]" the Foo { r = Col(token.Text, "UserType"); } else if ((token.Parent.Parent.IsKind(SyntaxKind.ForEachStatement) && token.GetNextToken().Kind() != SyntaxKind.CloseParenToken) //|| (token.Parent.Parent.Parent.IsKind(SyntaxKind.CaseSwitchLabel) && token.GetPreviousToken().Kind() != SyntaxKind.DotToken) //|| (token.Parent.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression) && token.Parent.Parent.Parent.IsKind(SyntaxKind.Argument) && !token.GetPreviousToken().IsKind(SyntaxKind.DotToken) && token.Text.Length > 0 && !char.IsLower(token.Text[0])) // e.g. "DbTypes.Add("int", DbType.Int32);" DbType in this case || (token.Parent.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression) && !token.GetPreviousToken().IsKind(SyntaxKind.DotToken) && token.Text.Length > 0 && !char.IsLower(token.Text[0]))) { r = Col(token.Text, "UserType"); } } } if (r == null && !string.IsNullOrEmpty(token.Text)) // Empty comes from EndOfFile, OmmittedToken, ... { r = Col(token.Text, "PlainText"); } if (r != null) { Words.AddRange(r); } VisitTriviaList(token.TrailingTrivia); }
public static string GetMemberName <TDeclaration>(this IExpressionBodyHandler <TDeclaration> handler, TDeclaration declaration, SemanticModel semanticModel) where TDeclaration : MemberDeclarationSyntax => semanticModel.GetDeclaredSymbol(declaration)?.Name ?? handler.GetIdentifierName(declaration);
public static async Task <Solution> RefactorAsync( Document document, PropertyDeclarationSyntax propertyDeclaration, CancellationToken cancellationToken) { SyntaxToken propertyIdentifier = propertyDeclaration.Identifier.WithoutTrivia(); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken); ISymbol fieldSymbol = GetFieldSymbol(propertyDeclaration, semanticModel, cancellationToken); var variableDeclarator = (VariableDeclaratorSyntax)await fieldSymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false); var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent; var fieldDeclaration = (FieldDeclarationSyntax)variableDeclaration.Parent; bool isSingleDeclarator = variableDeclaration.Variables.Count == 1; Solution solution = document.Solution(); foreach (DocumentReferenceInfo info in await SyntaxFinder.FindReferencesByDocumentAsync(fieldSymbol, solution, allowCandidate: false, cancellationToken: cancellationToken).ConfigureAwait(false)) { ImmutableArray <SyntaxNode> nodes = info.References; if (propertyDeclaration.SyntaxTree == info.SyntaxTree) { nodes = nodes.Add(propertyDeclaration); if (isSingleDeclarator) { nodes = nodes.Add(fieldDeclaration); } else { nodes = nodes.Add(variableDeclarator); } } SyntaxNode newRoot = info.Root.ReplaceNodes(nodes, (node, rewrittenNode) => { switch (node.Kind()) { case SyntaxKind.IdentifierName: { return(CreateNewExpression(node, propertyIdentifier, propertySymbol) .WithTriviaFrom(node) .WithFormatterAnnotation()); } case SyntaxKind.PropertyDeclaration: { return(CreateAutoProperty(propertyDeclaration, variableDeclarator.Initializer)); } case SyntaxKind.VariableDeclarator: case SyntaxKind.FieldDeclaration: { return(node.WithAdditionalAnnotations(_removeAnnotation)); } default: { Debug.Fail(node.ToString()); return(node); } } }); SyntaxNode nodeToRemove = newRoot.GetAnnotatedNodes(_removeAnnotation).FirstOrDefault(); if (nodeToRemove != null) { newRoot = newRoot.RemoveNode(nodeToRemove, SyntaxRemoveOptions.KeepUnbalancedDirectives); } solution = solution.WithDocumentSyntaxRoot(info.Document.Id, newRoot); } return(solution); }
private static void AssertInfoForDeclarationExpressionSyntax(SemanticModel model, DeclarationExpressionSyntax decl) { var symbolInfo = model.GetSymbolInfo(decl); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Equal(symbolInfo, ((CSharpSemanticModel)model).GetSymbolInfo(decl)); var typeInfo = model.GetTypeInfo(decl); Assert.Null(typeInfo.Type); Assert.Null(typeInfo.ConvertedType); Assert.Equal(typeInfo, ((CSharpSemanticModel)model).GetTypeInfo(decl)); var conversion = model.ClassifyConversion(decl, model.Compilation.ObjectType, false); Assert.False(conversion.Exists); Assert.Equal(conversion, model.ClassifyConversion(decl, model.Compilation.ObjectType, true)); Assert.Equal(conversion, ((CSharpSemanticModel)model).ClassifyConversion(decl, model.Compilation.ObjectType, false)); Assert.Equal(conversion, ((CSharpSemanticModel)model).ClassifyConversion(decl, model.Compilation.ObjectType, true)); Assert.Equal(conversion, model.ClassifyConversion(decl.Position, decl, model.Compilation.ObjectType, false)); Assert.Equal(conversion, model.ClassifyConversion(decl.Position, decl, model.Compilation.ObjectType, true)); Assert.Equal(conversion, ((CSharpSemanticModel)model).ClassifyConversion(decl.Position, decl, model.Compilation.ObjectType, false)); Assert.Equal(conversion, ((CSharpSemanticModel)model).ClassifyConversion(decl.Position, decl, model.Compilation.ObjectType, true)); Assert.Null(model.GetDeclaredSymbol(decl)); }
private static void ExtractVariableDeclarationsBeforeUsing(SemanticModel semanticModel, List <StatementSyntax> beforeUsing, List <StatementSyntax> insideUsing, List <SyntaxNode> nodesToRemove, CancellationToken ct) { var inUsingDataFlow = semanticModel.AnalyzeDataFlow(insideUsing.First(), insideUsing.Last()); var declaredVariablesUsedOutside = inUsingDataFlow.ReadOutside.Union(inUsingDataFlow.WrittenOutside) .Distinct() .Intersect(inUsingDataFlow.VariablesDeclared) .Select(x => new { Symbol = x, Declarator = (VariableDeclaratorSyntax)x.DeclaringSyntaxReferences[0].GetSyntax(ct) }) .ToArray(); for (var i = 0; i < insideUsing.Count; i++) { var stmt = insideUsing[i]; var localDeclarationStmt = stmt as LocalDeclarationStatementSyntax; if (localDeclarationStmt == null) { continue; } nodesToRemove.Add(localDeclarationStmt); var declaredVariables = localDeclarationStmt.Declaration .Variables.Select(x => new { Symbol = semanticModel.GetDeclaredSymbol(x), Declarator = x }) .ToArray(); var variablesToMove = declaredVariables .Intersect(declaredVariablesUsedOutside) .ToArray(); if (!variablesToMove.Any()) { continue; } var reducedLocalDeclaration = localDeclarationStmt.RemoveNodes(variablesToMove.Select(x => x.Declarator), SyntaxRemoveOptions.AddElasticMarker); if (reducedLocalDeclaration.Declaration.Variables.Any()) { insideUsing[i] = reducedLocalDeclaration; } else { insideUsing.RemoveAt(i); i--; } foreach (var needAssignment in variablesToMove.Where(x => x.Declarator.Initializer != null)) { insideUsing.Insert(i + 1, needAssignment.Declarator.InitializerAsAssignment()); } beforeUsing.Add(SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( localDeclarationStmt.Declaration.Type, SyntaxFactory.SeparatedList(variablesToMove.Select(x => x.Declarator.WithInitializer(null))) ) ) .WithAdditionalAnnotations(Formatter.Annotation) ); } }
protected override IEnumerable <CodeAction> GetActions(Document document, SemanticModel semanticModel, SyntaxNode root, TextSpan span, VariableDeclaratorSyntax node, CancellationToken cancellationToken) { var variableDeclaration = node.GetAncestor <VariableDeclarationSyntax>(); var localDeclaration = node.GetAncestor <LocalDeclarationStatementSyntax>(); if (node.Initializer == null || node.Parent.Parent != null && node.Parent.Parent.IsKind(SyntaxKind.UsingStatement)) { yield break; } var symbol = semanticModel.GetDeclaredSymbol(node) as ILocalSymbol; if (symbol == null) { yield break; } if (!symbol.Type.ImplementsSpecialTypeInterface(SpecialType.System_IDisposable)) { yield break; } var containingBlock = node.GetAncestor <BlockSyntax>(); yield return(CodeActionFactory.Create(span, DiagnosticSeverity.Info, "Put inside 'using'", ct => { var insideUsing = containingBlock.Statements.SkipWhile(x => x != localDeclaration).Skip(1).ToList(); ReduceUsingBlock(semanticModel, insideUsing, symbol); var nodesToRemove = new List <SyntaxNode>(insideUsing); var beforeUsing = new List <StatementSyntax>(); if (insideUsing.Any()) { ExtractVariableDeclarationsBeforeUsing(semanticModel, beforeUsing, insideUsing, nodesToRemove, ct); } if (IsEndingWithDispose(semanticModel, insideUsing, symbol)) { nodesToRemove.Add(insideUsing.Last()); insideUsing.RemoveAt(insideUsing.Count - 1); } var usingVariableDeclaration = SyntaxFactory.VariableDeclaration(variableDeclaration.Type.WithoutTrivia(), SyntaxFactory.SingletonSeparatedList(node)); var usingNode = SyntaxFactory.UsingStatement(usingVariableDeclaration, null, SyntaxFactory.Block(insideUsing)) .WithAdditionalAnnotations(Formatter.Annotation) .WithPrependedLeadingTrivia(variableDeclaration.GetLeadingTrivia()); var newRoot = root.TrackNodes(nodesToRemove.Concat(localDeclaration)); newRoot = newRoot.RemoveNodes(newRoot.GetCurrentNodes <SyntaxNode>(nodesToRemove), SyntaxRemoveOptions.AddElasticMarker); newRoot = newRoot.InsertNodesAfter(newRoot.GetCurrentNode(localDeclaration), beforeUsing.Concat(usingNode)); if (localDeclaration.Declaration.Variables.Count > 1) { var remainingVariables = localDeclaration.Declaration.Variables.Except(new[] { node }); newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(localDeclaration), localDeclaration.WithDeclaration(localDeclaration.Declaration.WithVariables(SyntaxFactory.SeparatedList(remainingVariables))) .WithAdditionalAnnotations(Formatter.Annotation)); } else { newRoot = newRoot.RemoveNode(newRoot.GetCurrentNode(localDeclaration), SyntaxRemoveOptions.AddElasticMarker); } return Task.FromResult(document.WithSyntaxRoot(newRoot)); })); }
private static async Task <Document> RefactorAsync( Document document, SyntaxNode node, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); switch (node) { case MethodDeclarationSyntax methodDeclaration: { IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken); UseAsyncAwaitRewriter rewriter = UseAsyncAwaitRewriter.Create(methodSymbol); var newNode = (MethodDeclarationSyntax)rewriter.VisitMethodDeclaration(methodDeclaration); newNode = ModifierList <MethodDeclarationSyntax> .Instance.Insert(newNode, SyntaxKind.AsyncKeyword); return(await document.ReplaceNodeAsync(methodDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } case LocalFunctionStatementSyntax localFunction: { IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(localFunction, cancellationToken); UseAsyncAwaitRewriter rewriter = UseAsyncAwaitRewriter.Create(methodSymbol); var newBody = (BlockSyntax)rewriter.VisitBlock(localFunction.Body); LocalFunctionStatementSyntax newNode = localFunction.WithBody(newBody); newNode = ModifierList <LocalFunctionStatementSyntax> .Instance.Insert(newNode, SyntaxKind.AsyncKeyword); return(await document.ReplaceNodeAsync(localFunction, newNode, cancellationToken).ConfigureAwait(false)); } case SimpleLambdaExpressionSyntax lambda: { var methodSymbol = (IMethodSymbol)semanticModel.GetSymbol(lambda, cancellationToken); UseAsyncAwaitRewriter rewriter = UseAsyncAwaitRewriter.Create(methodSymbol); var newBody = (BlockSyntax)rewriter.VisitBlock((BlockSyntax)lambda.Body); SimpleLambdaExpressionSyntax newNode = lambda .WithBody(newBody) .WithAsyncKeyword(Token(SyntaxKind.AsyncKeyword)); return(await document.ReplaceNodeAsync(lambda, newNode, cancellationToken).ConfigureAwait(false)); } case ParenthesizedLambdaExpressionSyntax lambda: { var methodSymbol = (IMethodSymbol)semanticModel.GetSymbol(lambda, cancellationToken); UseAsyncAwaitRewriter rewriter = UseAsyncAwaitRewriter.Create(methodSymbol); var newBody = (BlockSyntax)rewriter.VisitBlock((BlockSyntax)lambda.Body); ParenthesizedLambdaExpressionSyntax newNode = lambda .WithBody(newBody) .WithAsyncKeyword(Token(SyntaxKind.AsyncKeyword)); return(await document.ReplaceNodeAsync(lambda, newNode, cancellationToken).ConfigureAwait(false)); } case AnonymousMethodExpressionSyntax anonymousMethod: { var methodSymbol = (IMethodSymbol)semanticModel.GetSymbol(anonymousMethod, cancellationToken); UseAsyncAwaitRewriter rewriter = UseAsyncAwaitRewriter.Create(methodSymbol); var newBody = (BlockSyntax)rewriter.VisitBlock((BlockSyntax)anonymousMethod.Body); AnonymousMethodExpressionSyntax newNode = anonymousMethod .WithBody(newBody) .WithAsyncKeyword(Token(SyntaxKind.AsyncKeyword)); return(await document.ReplaceNodeAsync(anonymousMethod, newNode, cancellationToken).ConfigureAwait(false)); } } throw new InvalidOperationException(); }
private static void VerifyModelForDeconstruction(SemanticModel model, SingleVariableDesignationSyntax decl, LocalDeclarationKind kind, params IdentifierNameSyntax[] references) { var symbol = model.GetDeclaredSymbol(decl); Assert.Equal(decl.Identifier.ValueText, symbol.Name); Assert.Equal(kind, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)decl)); Assert.Same(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText)); var local = (SourceLocalSymbol)symbol; var typeSyntax = GetTypeSyntax(decl); if (local.IsVar && local.Type.IsErrorType()) { Assert.Null(model.GetSymbolInfo(typeSyntax).Symbol); } else { if (typeSyntax != null) { Assert.Equal(local.Type, model.GetSymbolInfo(typeSyntax).Symbol); } } foreach (var reference in references) { Assert.Same(symbol, model.GetSymbolInfo(reference).Symbol); Assert.Same(symbol, model.LookupSymbols(reference.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.True(model.LookupNames(reference.SpanStart).Contains(decl.Identifier.ValueText)); Assert.Equal(local.Type, model.GetTypeInfo(reference).Type); } }
public static void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context) { var property = (PropertyDeclarationSyntax)context.Node; if (property.ContainsDiagnostics) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IFieldSymbol fieldSymbol = null; AccessorDeclarationSyntax getter = null; AccessorDeclarationSyntax setter = null; ArrowExpressionClauseSyntax expressionBody = property.ExpressionBody; if (expressionBody != null) { fieldSymbol = GetBackingFieldSymbol(expressionBody, semanticModel, cancellationToken); } else { getter = property.Getter(); if (getter != null) { setter = property.Setter(); if (setter != null) { fieldSymbol = GetBackingFieldSymbol(getter, setter, semanticModel, cancellationToken); } else { fieldSymbol = GetBackingFieldSymbol(getter, semanticModel, cancellationToken); } } } if (fieldSymbol == null) { return; } var variableDeclarator = (VariableDeclaratorSyntax)fieldSymbol.GetSyntax(cancellationToken); if (variableDeclarator.SyntaxTree != property.SyntaxTree) { return; } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(property, cancellationToken); if (propertySymbol == null) { return; } if (!propertySymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty) { return; } if (propertySymbol.IsStatic != fieldSymbol.IsStatic) { return; } if (!propertySymbol.Type.Equals(fieldSymbol.Type)) { return; } if (propertySymbol.ContainingType?.Equals(fieldSymbol.ContainingType) != true) { return; } if (setter == null && propertySymbol.IsOverride && propertySymbol.OverriddenProperty?.SetMethod != null) { return; } if (HasStructLayoutAttributeWithExplicitKind(propertySymbol.ContainingType, context.Compilation)) { return; } if (IsBackingFieldUsedInRefOrOutArgument(context, fieldSymbol, property)) { return; } if (!CheckPreprocessorDirectives(property, variableDeclarator)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UseAutoProperty, property.Identifier); if (property.ExpressionBody != null) { context.ReportNode(DiagnosticDescriptors.UseAutoPropertyFadeOut, property.ExpressionBody); } else { if (getter != null) { FadeOutBodyOrExpressionBody(context, getter); } if (setter != null) { FadeOutBodyOrExpressionBody(context, setter); } } }
private static void VerifyModelNotSupported( SemanticModel model, DeclarationExpressionSyntax decl, params IdentifierNameSyntax[] references) { var variableDeclaratorSyntax = GetVariableDesignation(decl); Assert.Null(model.GetDeclaredSymbol(variableDeclaratorSyntax)); Assert.Null(model.GetDeclaredSymbol((SyntaxNode)variableDeclaratorSyntax)); var identifierText = decl.Identifier().ValueText; Assert.False(model.LookupSymbols(decl.SpanStart, name: identifierText).Any()); Assert.False(model.LookupNames(decl.SpanStart).Contains(identifierText)); Assert.Null(model.GetSymbolInfo(decl.Type()).Symbol); Assert.Null(model.GetSymbolInfo(decl).Symbol); Assert.Null(model.GetTypeInfo(decl).Type); Assert.Null(model.GetDeclaredSymbol(decl)); VerifyModelNotSupported(model, references); }
public ISymbol GetDeclaredSymbol(SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken) { var location = token.GetLocation(); var q = from node in token.GetAncestors<SyntaxNode>() let symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken) where symbol != null && symbol.Locations.Contains(location) select symbol; return q.FirstOrDefault(); }
private static void VerifyModelForOutVar( SemanticModel model, DeclarationExpressionSyntax decl, bool isDelegateCreation, bool isExecutableCode, bool isShadowed, bool verifyDataFlow = true, params IdentifierNameSyntax[] references) { var variableDeclaratorSyntax = GetVariableDesignation(decl); var symbol = model.GetDeclaredSymbol(variableDeclaratorSyntax); Assert.NotNull(symbol); Assert.Equal(decl.Identifier().ValueText, symbol.Name); Assert.Equal(variableDeclaratorSyntax, symbol.DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Equal(LocalDeclarationKind.RegularVariable, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)variableDeclaratorSyntax)); if (isShadowed) { Assert.NotEqual(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier().ValueText).Single()); } else { Assert.Same(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier().ValueText).Single()); } Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier().ValueText)); var local = (SourceLocalSymbol)symbol; var typeSyntax = decl.Type(); Assert.True(SyntaxFacts.IsInNamespaceOrTypeContext(typeSyntax)); Assert.True(SyntaxFacts.IsInTypeOnlyContext(typeSyntax)); if (typeSyntax.IsVar && local.IsVar && local.Type.IsErrorType()) { Assert.Null(model.GetSymbolInfo(typeSyntax).Symbol); } else { Assert.Equal(local.Type, model.GetSymbolInfo(typeSyntax).Symbol); } Assert.Same(symbol, model.GetSymbolInfo(decl).Symbol); Assert.Equal(local.Type, model.GetTypeInfo(decl).Type); Assert.Null(model.GetDeclaredSymbol(decl)); foreach (var reference in references) { Assert.Same(symbol, model.GetSymbolInfo(reference).Symbol); Assert.Same(symbol, model.LookupSymbols(reference.SpanStart, name: decl.Identifier().ValueText).Single()); Assert.True(model.LookupNames(reference.SpanStart).Contains(decl.Identifier().ValueText)); Assert.Equal(local.Type, model.GetTypeInfo(reference).Type); } if (verifyDataFlow) { VerifyDataFlow(model, decl, isDelegateCreation, isExecutableCode, references, symbol); } }
private static async Task <Document> DeclareExplicitValueAsync( Document document, EnumDeclarationSyntax enumDeclaration, INamedTypeSymbol enumSymbol, bool isFlags, bool useBitShift, ImmutableArray <ulong> values, SemanticModel semanticModel, CancellationToken cancellationToken) { List <ulong> reservedValues = values.ToList(); SeparatedSyntaxList <EnumMemberDeclarationSyntax> members = enumDeclaration.Members; SeparatedSyntaxList <EnumMemberDeclarationSyntax> newMembers = members; for (int i = 0; i < members.Count; i++) { if (members[i].EqualsValue == null) { IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(members[i], cancellationToken); ulong?value = null; if (isFlags) { Optional <ulong> optional = FlagsUtility <ulong> .Instance.GetUniquePowerOfTwo(reservedValues); if (optional.HasValue && ConvertHelpers.CanConvert(optional.Value, enumSymbol.EnumUnderlyingType.SpecialType)) { value = optional.Value; } } else { value = SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, enumSymbol); } if (value != null) { reservedValues.Add(value.Value); ExpressionSyntax expression; if (useBitShift && value.Value > 1) { var power = (int)Math.Log(Convert.ToDouble(value.Value), 2); expression = LeftShiftExpression(NumericLiteralExpression(1), NumericLiteralExpression(power)); } else { expression = NumericLiteralExpression(value.Value, enumSymbol.EnumUnderlyingType.SpecialType); } EqualsValueClauseSyntax equalsValue = EqualsValueClause(expression); EnumMemberDeclarationSyntax newMember = members[i].WithEqualsValue(equalsValue); newMembers = newMembers.ReplaceAt(i, newMember); } } } EnumDeclarationSyntax newEnumDeclaration = enumDeclaration.WithMembers(newMembers); return(await document.ReplaceNodeAsync(enumDeclaration, newEnumDeclaration, cancellationToken).ConfigureAwait(false)); }
private static void VerifyModelForDeclarationPattern(SemanticModel model, DeclarationPatternSyntax decl, params IdentifierNameSyntax[] references) { var symbol = model.GetDeclaredSymbol(decl); Assert.Equal(decl.Identifier.ValueText, symbol.Name); Assert.Equal(LocalDeclarationKind.PatternVariable, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)decl)); Assert.Same(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText)); foreach (var reference in references) { Assert.Same(symbol, model.GetSymbolInfo(reference).Symbol); Assert.Same(symbol, model.LookupSymbols(reference.SpanStart, name: decl.Identifier.ValueText).Single()); Assert.True(model.LookupNames(reference.SpanStart).Contains(decl.Identifier.ValueText)); } }
public virtual async Task <IList <DtoRules> > GetProjectAllDtoRules(Project project, IList <Project> allSourceProjects = null) { if (project == null) { throw new ArgumentNullException(nameof(project)); } IList <DtoRules> allDtoRules = new List <DtoRules>(); foreach (Document doc in project.Documents) { if (!doc.SupportsSemanticModel) { continue; } SemanticModel semanticModel = await doc.GetSemanticModelAsync(); SyntaxNode root = await doc.GetSyntaxRootAsync(); List <ClassDeclarationSyntax> allDtoRulesClasses = new List <ClassDeclarationSyntax>(); foreach (ClassDeclarationSyntax classDeclarationSyntax in root.DescendantNodes() .OfType <ClassDeclarationSyntax>()) { if (classDeclarationSyntax.BaseList == null) { continue; } bool isDtoRules = classDeclarationSyntax.BaseList.Types.Select(t => t.Type) .Select(t => semanticModel.GetSymbolInfo(t).Symbol?.OriginalDefinition?.ToString()) .Any(t => t == "Bit.Owin.DtoRules.DtoRules<TDto>"); if (isDtoRules == true) { isDtoRules = semanticModel.GetDeclaredSymbol(classDeclarationSyntax) .GetAttributes() .Any(att => att.AttributeClass.Name == "AutoGenerateAttribute"); } if (isDtoRules == true) { allDtoRulesClasses.Add(classDeclarationSyntax); } } if (!allDtoRulesClasses.Any()) { continue; } foreach (ClassDeclarationSyntax dtoRulesClassDec in allDtoRulesClasses) { INamedTypeSymbol dtoRuleSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(dtoRulesClassDec); DtoRules dtoRules = new DtoRules { DtoRulesSymbol = dtoRuleSymbol, Name = dtoRuleSymbol.Name, ClassDeclaration = dtoRulesClassDec, DtoSymbol = (dtoRuleSymbol.BaseType.TypeArguments).ExtendedSingle($"Looking for dto of {dtoRuleSymbol.Name}"), DtoRulesDocument = doc, SemanticModel = semanticModel, ClassSyntaxTree = dtoRulesClassDec.SyntaxTree }; dtoRules.ClassRootNode = (CompilationUnitSyntax)dtoRules.ClassSyntaxTree.GetRoot(); allDtoRules.Add(dtoRules); } } return(allDtoRules); }
private static void VerifySpeculativeSemanticModelForMethodBody(BlockSyntax blockStatement, SemanticModel speculativeModel) { var localDecl = (LocalDeclarationStatementSyntax)blockStatement.Statements[0]; var declarator = localDecl.Declaration.Variables.First(); var local = speculativeModel.GetDeclaredSymbol(declarator); Assert.NotNull(local); Assert.Equal("z", local.Name); Assert.Equal(SymbolKind.Local, local.Kind); Assert.Equal("Int32", ((LocalSymbol)local).Type.Name); var typeInfo = speculativeModel.GetTypeInfo(localDecl.Declaration.Type); Assert.NotNull(typeInfo.Type); Assert.Equal("Int32", typeInfo.Type.Name); var call = (InvocationExpressionSyntax)((ExpressionStatementSyntax)blockStatement.Statements[1]).Expression; var arg = call.ArgumentList.Arguments[0].Expression; var info = speculativeModel.GetSymbolInfo(arg); Assert.NotNull(info.Symbol); Assert.Equal("z", info.Symbol.Name); Assert.Equal(SymbolKind.Local, info.Symbol.Kind); // Shouldn't bind to local y in the original method as we are replacing the method body. var call2 = (InvocationExpressionSyntax)((ExpressionStatementSyntax)((BlockSyntax)blockStatement).Statements[2]).Expression; var arg2 = call2.ArgumentList.Arguments[0].Expression; var info2 = speculativeModel.GetSymbolInfo(arg2); Assert.Null(info2.Symbol); }
/// <summary> /// 一つのメソッド定義を解析 /// </summary> /// <param name="methodBlock">メソッド定義</param> /// <param name="model">セマンティックモデル</param> /// <param name="nameSpace">呼び出し元クラスの属する名前空間</param> /// <param name="className">呼び出し元クラス名</param> /// <param name="indent">インデント(省略可能)</param> private static ClassMethodInfo GetMethodDeclaration(MethodDeclarationSyntax methodBlock, SemanticModel model, string nameSpace, string className) { StringBuilder str = new StringBuilder(); try { var symbol = model.GetDeclaredSymbol(methodBlock); str.Append("Method Declaration: "); str.Append("\t"); if (symbol != null) { str.Append(symbol.ContainingType); } else { str.Append(nameSpace + "." + className); } str.Append("\t"); str.Append(methodBlock.Identifier.Text); str.Append(methodBlock.ParameterList); str.Append("\t"); string modifier = methodBlock.Modifiers.ToString(); str.Append(modifier); str.Append("\t"); int lineCount = 0; using (StringReader sReader = new StringReader(methodBlock.WithoutTrivia().ToFullString())) { string line; while ((line = sReader.ReadLine()) != null) { if (line != string.Empty && !string.IsNullOrWhiteSpace(line) && !line.Trim().StartsWith("//")) { lineCount++; } } } str.Append(lineCount); //Console.WriteLine((indent ?? string.Empty) + str); IEnumerable <ClassMethodInfo> children = GetCallingMethods(methodBlock, model, nameSpace, className); ClassMethodInfo result = new ClassMethodInfo(); result.ClassName = symbol.ContainingType.ToString(); result.MethodName = symbol.OriginalDefinition.ToString(); result.LineCount = lineCount; result.Children.AddRange(children); return(result); } catch (Exception ex) { List <string> errorReport = new List <string>(); errorReport.Add($"AnalyzingNamespace: {nameSpace}"); errorReport.Add($"AnalyzingClass: {className}"); errorReport.Add($"AnalyzingMethod: {methodBlock.Identifier.Text}"); WriteExceptionLog(new ApplicationException("[" + string.Join(",", errorReport) + "]", ex)); } return(null); }
public void Execute(GeneratorExecutionContext context) { #if DEBUG //if (!Debugger.IsAttached) Debugger.Launch(); #endif if (!(context.Compilation is CSharpCompilation compilation)) { return; } if (!(context.ParseOptions is CSharpParseOptions parseOptions)) { return; } // check if required types exists. if (!(compilation.GetTypeByMetadataName("System.ReadOnlySpan`1") is { } readOnlySpanSymbol)) { return; } if (!(compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.Unsafe") is { } unsafeSymbol)) { return; } if (!(compilation.GetTypeByMetadataName("System.Runtime.InteropServices.MemoryMarshal") is { } memoryMarshalSymbol)) { return; } SourceText attributeSourceText = constractSourceText(new PrimitiveStaticDataAttributeTemplate().TransformText()); context.AddSource(PrimitiveStaticDataAttributeTemplate.TypeFullName, attributeSourceText); try { compilation = compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(attributeSourceText, options: parseOptions)); INamedTypeSymbol attrSymbol = compilation.GetTypeByMetadataName(PrimitiveStaticDataAttributeTemplate.TypeFullName) !; var candidateMethodSyntaxes = compilation. SyntaxTrees. SelectMany(tree => tree.GetRoot().DescendantNodes()). OfType <MethodDeclarationSyntax>(). Where(method => method.IsExtendedPartial() && method.Modifiers.Any(SyntaxKind.StaticKeyword) && method.AttributeLists.Count > 0 && method.ParentNodes().OfType <TypeDeclarationSyntax>().All(type => type.Modifiers.Any(SyntaxKind.PartialKeyword))); foreach (var methodSyntax in candidateMethodSyntaxes) { SemanticModel semantic = compilation.GetSemanticModel(methodSyntax.SyntaxTree); if (!(semantic.GetDeclaredSymbol(methodSyntax) is { } methodSymbol) || methodSymbol.MethodKind != MethodKind.Ordinary || methodSymbol.PartialImplementationPart is not null || !equalsSymbol(methodSymbol.ReturnType.OriginalDefinition, readOnlySpanSymbol)) { continue; } var returnSpanType = (INamedTypeSymbol)methodSymbol.ReturnType; if (!isPrimitiveType(returnSpanType.TypeArguments[0])) { continue; } foreach (AttributeData attr in methodSymbol.GetReturnTypeAttributes()) { if (!equalsSymbol(attr.AttributeClass, attrSymbol) || attr.ConstructorArguments.Length < 1) { continue; } TypedConstant arg1 = attr.ConstructorArguments[0]; bool argIsSingleByteValues = false; IArrayTypeSymbol arraySymbol; object[] values = default !;
protected static void VerifyModelForDeclarationField( SemanticModel model, SingleVariableDesignationSyntax designation, bool duplicate, params IdentifierNameSyntax[] references) { var symbol = model.GetDeclaredSymbol(designation); Assert.Equal(designation.Identifier.ValueText, symbol.Name); Assert.Equal(SymbolKind.Field, symbol.Kind); Assert.Equal(designation, symbol.DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)designation)); var symbols = model.LookupSymbols(designation.SpanStart, name: designation.Identifier.ValueText); var names = model.LookupNames(designation.SpanStart); if (duplicate) { Assert.True(symbols.Count() > 1); Assert.Contains(symbol, symbols); } else { Assert.Same(symbol, symbols.Single()); } Assert.Contains(designation.Identifier.ValueText, names); var local = (IFieldSymbol)symbol; switch (designation.Parent) { case DeclarationPatternSyntax decl: var typeSyntax = decl.Type; Assert.True(SyntaxFacts.IsInNamespaceOrTypeContext(typeSyntax)); Assert.True(SyntaxFacts.IsInTypeOnlyContext(typeSyntax)); var type = local.Type; if (typeSyntax.IsVar && type.IsErrorType()) { Assert.Null(model.GetSymbolInfo(typeSyntax).Symbol); } else { Assert.Equal(type, model.GetSymbolInfo(typeSyntax).Symbol); } AssertTypeInfo(model, decl.Type, type); break; case var parent: Assert.True(parent is VarPatternSyntax); break; } var declarator = designation.Ancestors().OfType <VariableDeclaratorSyntax>().FirstOrDefault(); var inFieldDeclaratorArgumentlist = declarator != null && declarator.Parent.Parent.Kind() != SyntaxKind.LocalDeclarationStatement && (declarator.ArgumentList?.Contains(designation)).GetValueOrDefault(); // this is a declaration site, not a use site. Assert.Null(model.GetSymbolInfo(designation).Symbol); Assert.Null(model.GetSymbolInfo(designation).Symbol); foreach (var reference in references) { var referenceInfo = model.GetSymbolInfo(reference); symbols = model.LookupSymbols(reference.SpanStart, name: designation.Identifier.ValueText); if (duplicate) { Assert.Null(referenceInfo.Symbol); Assert.Contains(symbol, referenceInfo.CandidateSymbols); Assert.True(symbols.Count() > 1); Assert.Contains(symbol, symbols); } else { Assert.Same(symbol, referenceInfo.Symbol); Assert.Same(symbol, symbols.Single()); Assert.Equal(local.Type, model.GetTypeInfo(reference).Type); } Assert.True(model.LookupNames(reference.SpanStart).Contains(designation.Identifier.ValueText)); } if (!inFieldDeclaratorArgumentlist) { var dataFlowParent = designation.FirstAncestorOrSelf <ExpressionSyntax>(); if (model.IsSpeculativeSemanticModel) { Assert.Throws <NotSupportedException>(() => model.AnalyzeDataFlow(dataFlowParent)); } else { var dataFlow = model.AnalyzeDataFlow(dataFlowParent); if (dataFlow.Succeeded) { Assert.False(dataFlow.VariablesDeclared.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.AlwaysAssigned.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.WrittenInside.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.DataFlowsIn.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.ReadInside.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.DataFlowsOut.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.ReadOutside.Contains(symbol, ReferenceEqualityComparer.Instance)); Assert.False(dataFlow.WrittenOutside.Contains(symbol, ReferenceEqualityComparer.Instance)); } } } }