public static IEnumerable <SyntaxNode> Find(SyntaxNode node) { var syntaxWalker = new SyntaxWalker(); syntaxWalker.Visit(node); return(syntaxWalker.FoundNodes); }
public static SyntaxWalker GetInstance() { SyntaxWalker walker = _cachedInstance; if (walker != null) { Debug.Assert(walker.Expressions == null || walker.Expressions.Count == 0); _cachedInstance = null; return(walker); } return(new SyntaxWalker()); }
public static SyntaxWalker GetInstance() { SyntaxWalker walker = _cachedInstance; if (walker != null) { _cachedInstance = null; return(walker); } else { return(new SyntaxWalker()); } }
public static SyntaxWalker GetInstance() { SyntaxWalker walker = _cachedInstance; if (walker != null) { Debug.Assert(walker.Parameters.Count == 0); Debug.Assert(walker.SemanticModel == null); Debug.Assert(walker.CancellationToken == default); _cachedInstance = null; return(walker); } return(new SyntaxWalker()); }
private static void AnalyzeBlock(SyntaxNodeAnalysisContext context, BlockSyntax body) { if (body == null) { return; } SyntaxWalker walker = SyntaxWalker.GetInstance(); walker.VisitBlock(body); if (walker.Expressions?.Count > 0) { foreach (ExpressionSyntax expression in walker.Expressions) { ReportDiagnostic(context, expression); } } SyntaxWalker.Free(walker); }
/// <summary> /// Run the given visitors on the specified file. /// </summary> public static void VisitFile(string path, SyntaxWalker[] visitors) { var tree = SyntaxTree.ParseFile(path); var root = (CompilationUnitSyntax)tree.GetRoot(); foreach (var visitor in visitors) { visitor.Visit(root); } }
private static void Analyze( SyntaxNodeAnalysisContext context, SyntaxNode declaration, ParameterListSyntax parameterList, CSharpSyntaxNode bodyOrExpressionBody) { if (parameterList == null) { return; } if (bodyOrExpressionBody == null) { return; } if (!parameterList.Parameters.Any()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(declaration, cancellationToken); SyntaxWalker walker = null; foreach (IParameterSymbol parameter in methodSymbol.Parameters) { cancellationToken.ThrowIfCancellationRequested(); ITypeSymbol type = parameter.Type; if (type.Kind == SymbolKind.ErrorType) { continue; } if (CSharpFacts.IsSimpleType(type.SpecialType)) { continue; } if (!type.IsReadOnlyStruct()) { if (parameter.RefKind == RefKind.In && type.TypeKind == TypeKind.Struct) { var parameterSyntax = (ParameterSyntax)parameter.GetSyntax(cancellationToken); Debug.Assert(parameterSyntax.Modifiers.Contains(SyntaxKind.InKeyword), ""); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.DoNotPassNonReadOnlyStructByReadOnlyReference, parameterSyntax.Identifier); } continue; } if (parameter.RefKind != RefKind.None) { continue; } if (walker == null) { if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true)) { break; } walker = SyntaxWalker.GetInstance(); } else if (walker.Parameters.ContainsKey(parameter.Name)) { walker.Parameters.Clear(); break; } walker.Parameters.Add(parameter.Name, parameter); } if (walker == null) { return; } if (walker.Parameters.Count > 0) { walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; if (bodyOrExpressionBody is BlockSyntax body) { walker.VisitBlock(body); } else { walker.VisitArrowExpressionClause((ArrowExpressionClauseSyntax)bodyOrExpressionBody); } if (walker.Parameters.Count > 0 && !IsReferencedAsMethodGroup()) { foreach (KeyValuePair <string, IParameterSymbol> kvp in walker.Parameters) { if (kvp.Value.GetSyntaxOrDefault(cancellationToken) is ParameterSyntax parameter) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.MakeParameterRefReadOnly, parameter.Identifier); } } } } SyntaxWalker.Free(walker); bool IsReferencedAsMethodGroup() { switch (declaration.Kind()) { case SyntaxKind.MethodDeclaration: return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.Parent, methodSymbol, semanticModel, cancellationToken)); case SyntaxKind.LocalFunctionStatement: return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.FirstAncestor <MemberDeclarationSyntax>(), methodSymbol, semanticModel, cancellationToken)); default: return(false); } } }
public static void Free(SyntaxWalker walker) { walker.Reset(); _cachedInstance = walker; }
public static void Free(SyntaxWalker walker) { walker.Expressions?.Clear(); _cachedInstance = walker; }
private static void Analyze( SyntaxNodeAnalysisContext context, SyntaxNode declaration, ParameterListSyntax parameterList, CSharpSyntaxNode bodyOrExpressionBody) { if (parameterList == null) { return; } if (bodyOrExpressionBody == null) { return; } if (!parameterList.Parameters.Any()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(declaration, cancellationToken); SyntaxWalker walker = null; foreach (IParameterSymbol parameter in methodSymbol.Parameters) { cancellationToken.ThrowIfCancellationRequested(); if (parameter.RefKind == RefKind.None) { ITypeSymbol type = parameter.Type; //TODO: ITypeSymbol.IsReadOnly, https://github.com/dotnet/roslyn/issues/23792 if (type.IsReadOnlyStruct()) { if (walker == null) { if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true)) { return; } walker = SyntaxWalker.GetInstance(); } walker.Parameters.Add(parameter.Name, parameter); } } } if (walker == null) { return; } walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; if (bodyOrExpressionBody is BlockSyntax body) { walker.VisitBlock(body); } else { walker.VisitArrowExpressionClause((ArrowExpressionClauseSyntax)bodyOrExpressionBody); } foreach (KeyValuePair <string, IParameterSymbol> kvp in walker.Parameters) { if (kvp.Value.GetSyntaxOrDefault(cancellationToken) is ParameterSyntax parameter) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.MakeParameterRefReadOnly, parameter.Identifier); } } SyntaxWalker.Free(walker); }
public void Process() { // 일단 이 모드에서는 input files만 받는다, output directory는 generated // 0. g.cs는 있는데 input이 없는 경우 삭제 ClearOrphanSources(); // 1. input은 작업디렉토리에 영향을 받아야 하고, relative만 받는다.. Program.cs A\Sample.cs, FullyQualified면 에러 var stubTree = GenerateStub(); var infos = new List <(string OutputFile, SyntaxTree Tree)>(); foreach (var inputFile in inputFiles) { if (!VerifyInputFilePath(inputFile)) { continue; } string outputFile = MakeOutputFilePath(inputFile); var text = fileProvider.ReadAllText(inputFile); var tree = CSharpSyntaxTree.ParseText(text); infos.Add((outputFile, tree)); } var refs = refAssemblyFiles.Select(refAssemblyFile => MetadataReference.CreateFromFile(refAssemblyFile)); var compilation = CSharpCompilation.Create(null, infos.Select(info => info.Tree).Prepend(stubTree), refs); var typeDeclGeneratorsInfo = new Dictionary <TypeDeclarationSyntax, List <IGenerator> >(); // 1. Collection Phase foreach (var tree in infos.Select(info => info.Tree).Prepend(stubTree)) { var model = compilation.GetSemanticModel(tree); // type declaration에 대해서 generator들에게 처리할 기회를 준다 foreach (var typeDecl in tree.GetRoot().DescendantNodes().OfType <TypeDeclarationSyntax>()) { var relatedGenerators = new List <IGenerator>(); foreach (var generator in generators) { // phase2에서 처리할 bool bWillGenerateMembers = generator.HandleTypeDecl(typeDecl, model); if (bWillGenerateMembers) { relatedGenerators.Add(generator); } } if (relatedGenerators.Count != 0) { typeDeclGeneratorsInfo.Add(typeDecl, relatedGenerators); } } } // 2. Generation Phase foreach (var info in infos) { var model = compilation.GetSemanticModel(info.Tree); var walker = new SyntaxWalker(model, typeDeclGeneratorsInfo); walker.Visit(info.Tree.GetRoot()); if (walker.NeedSave) { Debug.Assert(walker.CompilationUnitSyntax != null); SaveOrSkip(info.OutputFile, @$ "#nullable enable {walker.CompilationUnitSyntax}"); }