Skip to content

Add SymbolVisitor<TArgument, TResult> #55183

@siegfriedpammer

Description

@siegfriedpammer

Background and Motivation

In order to avoid shared state and allowing parallel invocations of the same visitor, it would be nice to be able to use a SymbolVisitor<TArgument, TResult>. We already have a similar pattern with OperationVisitor.

Proposed API

namespace Microsoft.CodeAnalysis
{
+    public abstract class SymbolVisitor<TArgument, TResult>
+    {
+        public virtual TResult? Visit(ISymbol? symbol, TArgument argument)
+        {
+            if (symbol != null)
+            {
+                return symbol.Accept(this, argument);
+            }
+
+            return default(TResult);
+        }
+
+        public virtual TResult? DefaultVisit(ISymbol symbol, TArgument argument)
+        {
+            return default(TResult);
+        }
+
+        public virtual TResult? VisitAlias(IAliasSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitArrayType(IArrayTypeSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitAssembly(IAssemblySymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitDiscard(IDiscardSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitDynamicType(IDynamicTypeSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitEvent(IEventSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitField(IFieldSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitLabel(ILabelSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitLocal(ILocalSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitMethod(IMethodSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitModule(IModuleSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitNamedType(INamedTypeSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitNamespace(INamespaceSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitParameter(IParameterSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitPointerType(IPointerTypeSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitProperty(IPropertySymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitRangeVariable(IRangeVariableSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+
+        public virtual TResult? VisitTypeParameter(ITypeParameterSymbol symbol, TArgument argument)
+        {
+            return DefaultVisit(symbol, argument);
+        }
+    }

	public interface ISymbol : IEquatable<ISymbol?>
    {
		// ...
        void Accept(SymbolVisitor visitor);

        TResult? Accept<TResult>(SymbolVisitor<TResult> visitor);

+        TResult? Accept<TArgument, TResult>(SymbolVisitor<TArgument, TResult> visitor, TArgument argument);
		// ...
    }
}

Usage Examples

      var result = symbol.Accept(new GenerateIdVisitor(), new GeneratorContext());

Alternative Designs

It would be possible to implement a visitor based on dynamic invocation, however, I think this is not the optimal solution.

Risks

none I can think of

Metadata

Metadata

Assignees

Labels

Area-CompilersConcept-APIThis issue involves adding, removing, clarification, or modification of an API.Feature Requestapi-approvedAPI was approved in API review, it can be implementedhelp wantedThe issue is "up for grabs" - add a comment if you are interested in working on it

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions