public EmitterContext(SemanticModel semanticModel) { this.SemanticModel = semanticModel; this.DataFlowAnalyzer = new(semanticModel); this.VariablesToInline = InlineDependencyVisitor.GetVariablesToInline(semanticModel); this.ResourceDependencies = ResourceDependencyVisitor.GetResourceDependencies(semanticModel); }
public EmitterContext(SemanticModel semanticModel, EmitterSettings settings) { Settings = settings; SemanticModel = semanticModel; DataFlowAnalyzer = new(semanticModel); VariablesToInline = InlineDependencyVisitor.GetVariablesToInline(semanticModel); ResourceDependencies = ResourceDependencyVisitor.GetResourceDependencies(semanticModel); FunctionVariables = FunctionVariableGeneratorVisitor.GetFunctionVariables(semanticModel).ToImmutableDictionary(); }
public static ImmutableHashSet <VariableSymbol> GetVariablesToInline(SemanticModel.SemanticModel model) { var visitor = new InlineDependencyVisitor(model); visitor.Visit(model.Root.Syntax); return(visitor.shouldInlineCache .Where(kvp => kvp.Value) .Select(kvp => kvp.Key) .ToImmutableHashSet()); }
/// <summary> /// Checks if the specified variable needs to be inlined due to runtime limitations. In cases where the inlining is caused by accessing a variable that must be inlined, /// the variable access chain is returned. Otherwise, an empty chain is returned. /// </summary> /// <param name="model">The semantic model</param> /// <param name="variable">The variable to check</param> /// <param name="variableAccessChain">The variable access chain that leads to inlining or empty if not available.</param> public static bool ShouldInlineVariable(SemanticModel model, VariableDeclarationSyntax variable, out ImmutableArray <string> variableAccessChain) { variableAccessChain = ImmutableArray <string> .Empty; if (model.GetSymbolInfo(variable) is not VariableSymbol variableSymbol) { // we have errors - assume this is not meant to be inlined return(false); } var visitor = new InlineDependencyVisitor(model, variable); visitor.Visit(variable); if (!visitor.shouldInlineCache.TryGetValue(variableSymbol, out var shouldInline) || shouldInline != Decision.Inline) { return(false); } variableAccessChain = visitor.capturedSequence?.Reverse().ToImmutableArray() ?? ImmutableArray <string> .Empty; return(true); }
public override void VisitForSyntax(ForSyntax syntax) { // save previous property loop count on the call stack var previousPropertyLoopCount = this.propertyLoopCount; switch (this.IsLoopAllowedHere(syntax)) { case false: // this loop was used incorrectly this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).ForExpressionsNotSupportedHere()); break; case true when this.activeLoopCapableTopLevelDeclaration is VariableDeclarationSyntax variable && InlineDependencyVisitor.ShouldInlineVariable(this.semanticModel, variable, out var variableChain): // this is a loop variable that has a dependency on functions that are not supported in JSON variables // we are initially blocking this because not all cases can be generated in the JSON // unable to get a detailed variable dependency chain // log a generic error instead and put it on the "for" keyword this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).VariableLoopsRuntimeDependencyNotAllowed(variableChain)); break; case null: // this is a property loop this.propertyLoopCount += 1; if (this.propertyLoopCount > MaximumNestedPropertyLoopCount) { // too many property loops this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).TooManyPropertyForExpressions()); } break; } // visit children base.VisitForSyntax(syntax); // restore previous property loop count this.propertyLoopCount = previousPropertyLoopCount; }