/// <summary> /// Locals are given slots when their declarations are encountered. We only need give slots /// to local variables, out parameters, and the "this" variable of a struct constructs. /// Other variables are not given slots, and are therefore not tracked by the analysis. This /// returns -1 for a variable that is not tracked, for fields of structs that have the same /// assigned status as the container, and for structs that (recursively) contain no data members. /// We do not need to track references to /// variables that occur before the variable is declared, as those are reported in an /// earlier phase as "use before declaration". That allows us to avoid giving slots to local /// variables before processing their declarations. /// </summary> protected int VariableSlot(Symbol symbol, int containingSlot = 0) { containingSlot = DescendThroughTupleRestFields(ref symbol, containingSlot, forceContainingSlotsToExist: false); int slot; return((_variableSlot.TryGetValue(new VariableIdentifier(symbol, containingSlot), out slot)) ? slot : -1); }
protected virtual LabelSymbol GetDagNodeLabel(BoundDecisionDagNode dag) { if (!_dagNodeLabels.TryGetValue(dag, out LabelSymbol? label)) { _dagNodeLabels.Add(dag, label = dag is BoundLeafDecisionDagNode d ? d.Label : _factory.GenerateLabel("dagNode")); } return(label); }
public void AddThrow(TypeSymbol type, SyntaxNode syntax) { PooledHashSet <SyntaxNode> nodes; if (!ThrowLocations.TryGetValue(type, out nodes)) { nodes = PooledHashSet <SyntaxNode> .GetInstance(); ThrowLocations.Add(type, nodes); } nodes.Add(syntax); }
public int AssignLocalOrdinal(SynthesizedLocalKind localKind, int syntaxOffset) { #if !DEBUG // Optimization (avoid growing the dictionary below): // User-defined locals have to have a distinct syntax offset, thus ordinal is always 0. if (localKind == SynthesizedLocalKind.UserDefined) { return(0); } #endif int ordinal; long key = MakeKey(localKind, syntaxOffset); // Group by syntax offset and kind. // Variables associated with the same syntax and kind will be assigned different ordinals. if (_lazyMap == null) { _lazyMap = PooledDictionary <long, int> .GetInstance(); ordinal = 0; } else if (!_lazyMap.TryGetValue(key, out ordinal)) { ordinal = 0; } _lazyMap[key] = ordinal + 1; Debug.Assert(ordinal == 0 || localKind != SynthesizedLocalKind.UserDefined); return(ordinal); }
private void LowerWhenClause(BoundWhenDecisionDagNode whenClause) { // This node is used even when there is no when clause, to record bindings. In the case that there // is no when clause, whenClause.WhenExpression and whenClause.WhenFalse are null, and the syntax for this // node is the case clause. // We need to assign the pattern variables in the code where they are in scope, so we produce a branch // to the section where they are in scope and evaluate the when clause there. var whenTrue = (BoundLeafDecisionDagNode)whenClause.WhenTrue; LabelSymbol labelToSectionScope = GetDagNodeLabel(whenClause); // We need the section syntax to get the section builder from the map. Unfortunately this is a bit awkward SyntaxNode sectionSyntax = whenClause.Syntax is SwitchLabelSyntax l ? l.Parent : whenClause.Syntax; bool foundSectionBuilder = _switchArms.TryGetValue(sectionSyntax, out ArrayBuilder <BoundStatement> sectionBuilder); Debug.Assert(foundSectionBuilder); sectionBuilder.Add(_factory.Label(labelToSectionScope)); foreach (BoundPatternBinding binding in whenClause.Bindings) { BoundExpression left = _localRewriter.VisitExpression(binding.VariableAccess); // Since a switch does not add variables to the enclosing scope, the pattern variables // are locals even in a script and rewriting them should have no effect. Debug.Assert(left.Kind == BoundKind.Local && left == binding.VariableAccess); BoundExpression right = _tempAllocator.GetTemp(binding.TempContainingValue); if (left != right) { sectionBuilder.Add(_factory.Assignment(left, right)); } } var whenFalse = whenClause.WhenFalse; var trueLabel = GetDagNodeLabel(whenTrue); if (whenClause.WhenExpression != null && whenClause.WhenExpression.ConstantValue != ConstantValue.True) { _factory.Syntax = whenClause.Syntax; BoundStatement conditionalGoto = _factory.ConditionalGoto(_localRewriter.VisitExpression(whenClause.WhenExpression), trueLabel, jumpIfTrue: true); // Only add instrumentation (such as a sequence point) if the node is not compiler-generated. if (IsSwitchStatement && !whenClause.WhenExpression.WasCompilerGenerated && _localRewriter.Instrument) { conditionalGoto = _localRewriter._instrumenter.InstrumentSwitchWhenClauseConditionalGotoBody(whenClause.WhenExpression, conditionalGoto); } sectionBuilder.Add(conditionalGoto); Debug.Assert(whenFalse != null); // We hide the jump back into the decision dag, as it is not logically part of the when clause BoundStatement jump = _factory.Goto(GetDagNodeLabel(whenFalse)); sectionBuilder.Add(IsSwitchStatement ? _factory.HiddenSequencePoint(jump) : jump); } else { Debug.Assert(whenFalse == null); sectionBuilder.Add(_factory.Goto(trueLabel)); } }
public BoundExpression GetTemp(BoundDagTemp dagTemp) { if (!_map.TryGetValue(dagTemp, out BoundExpression result)) { LocalSymbol temp = _factory.SynthesizedLocal(dagTemp.Type, syntax: _node, kind: SynthesizedLocalKind.SwitchCasePatternMatching); result = _factory.Local(temp); _map.Add(dagTemp, result); _temps.Add(temp); } return(result); }
public BoundExpression GetTemp(BoundDagTemp dagTemp) { if (!_map.TryGetValue(dagTemp, out BoundExpression result)) { var kind = _generateSequencePoints ? SynthesizedLocalKind.SwitchCasePatternMatching : SynthesizedLocalKind.LoweringTemp; LocalSymbol temp = _factory.SynthesizedLocal(dagTemp.Type, syntax: _node, kind: kind); result = _factory.Local(temp); _map.Add(dagTemp, result); _temps.Add(temp); } return(result); }
public override BoundNode VisitLocal(BoundLocal node) { if (!node.LocalSymbol.SynthesizedKind.IsLongLived()) { LocalSymbol longLived; if (_tempSubstitution.TryGetValue(node.LocalSymbol, out longLived)) { return(node.Update(longLived, node.ConstantValueOpt, node.Type)); } } return(base.VisitLocal(node)); }
public ES_TypeTag?CheckTypeExists(ArrayPointer <byte> name, ES_TypeTag?ignoredType) { if (ignoredType != ES_TypeTag.Class && ClassBuilders.TryGetValue(name, out var _)) { return(ES_TypeTag.Class); } if (ignoredType != ES_TypeTag.Struct && StructBuilders.TryGetValue(name, out var _)) { return(ES_TypeTag.Struct); } if (ignoredType != ES_TypeTag.Enum && EnumBuilders.TryGetValue(name, out var _)) { return(ES_TypeTag.Enum); } if (ignoredType != ES_TypeTag.Function && NamespaceData.functions.TryGetValue(name, out var _)) { return(ES_TypeTag.Function); } return(null); }
private void LowerWhenClause(BoundWhenDecisionDagNode whenClause) { // This node is used even when there is no when clause, to record bindings. In the case that there // is no when clause, whenClause.WhenExpression and whenClause.WhenFalse are null, and the syntax for this // node is the case clause. // We need to assign the pattern variables in the code where they are in scope, so we produce a branch // to the section where they are in scope and evaluate the when clause there. var whenTrue = (BoundLeafDecisionDagNode)whenClause.WhenTrue; LabelSymbol labelToSectionScope = GetDagNodeLabel(whenClause); // We need the section syntax to get the section builder from the map. Unfortunately this is a bit awkward SyntaxNode sectionSyntax = whenClause.Syntax is SwitchLabelSyntax l ? l.Parent : whenClause.Syntax; bool foundSectionBuilder = _switchArms.TryGetValue(sectionSyntax, out ArrayBuilder <BoundStatement>?sectionBuilder); Debug.Assert(foundSectionBuilder && sectionBuilder is { });
/// <summary> /// This is where we calculate <see cref="Scope.CanMergeWithParent"/>. /// <see cref="Scope.CanMergeWithParent"/> is always true unless we jump from after /// the beginning of a scope, to a point in between the beginning of the parent scope, and the beginning of the scope /// </summary> /// <param name="jumpTarget"></param> private void CheckCanMergeWithParent(LabelSymbol jumpTarget) { // since forward jumps can never effect Scope.SemanticallySafeToMergeIntoParent // if we have not yet seen the jumpTarget, this is a forward jump, and can be ignored if (_scopesAfterLabel.TryGetValue(jumpTarget, out var scopesAfterLabel)) { foreach (var scope in scopesAfterLabel) { // this jump goes from a point after the beginning of the scope (as we have already visited or started visiting the scope), // to a point in between the beginning of the parent scope, and the beginning of the scope, so it is not safe to move // variables in the scope to the parent scope. scope.CanMergeWithParent = false; } // Prevent us repeating this process for all scopes if another jumps goes to the same label scopesAfterLabel.Clear(); } }
static void AddPlatformsAndVersionCountFromGuardMethods(INamedTypeSymbol operatingSystemType, PooledDictionary <string, int> knownPlatforms) { var methods = operatingSystemType.GetMembers().OfType <IMethodSymbol>(); foreach (var m in methods) { if (m.IsStatic && m.ReturnType.SpecialType == SpecialType.System_Boolean && NameAndParametersValid(m)) { var(platformName, versionPartsCount) = ExtractPlatformAndVersionCount(m); if (!knownPlatforms.TryGetValue(platformName, out var count) || versionPartsCount > count) { knownPlatforms[platformName] = versionPartsCount; // only keep highest count } } } }
private void ParseBlock(UDMFParsedMapData dataClass, string ident, ParserInfo.BlockInfo?info) { UDMFToken tok = scanner.Scan(); if (tok.Type != UDMFTokenType.BROPEN) { Errors.Add(new UDMFParseError("Unexpected token '" + tok.Text.ToString().Replace("\n", "") + "' found. Expected " + UDMFToken.TokenTypeToString(UDMFTokenType.BROPEN), 0x1001, tok)); return; } IUDMFBlock block; if (info != null) { block = (IUDMFBlock)Activator.CreateInstance(info.Value.BlockType); info.Value.Delegates.Getter(dataClass).AddBlock(block); } else { var newBlock = new UDMFUnknownBlock(); block = newBlock; if (!unknownBlocksPooled.TryGetValue(ident, out var unknownBlocksList)) { unknownBlocksList = new CL_PooledList <UDMFUnknownBlock> (); unknownBlocksPooled.Add(ident, unknownBlocksList); } unknownBlocksList.Add(newBlock); } ParseExpr_List(block, info); tok = scanner.Scan(); if (tok.Type != UDMFTokenType.BRCLOSE) { Errors.Add(new UDMFParseError("Unexpected token '" + tok.Text.ToString().Replace("\n", "") + "' found. Expected " + UDMFToken.TokenTypeToString(UDMFTokenType.BRCLOSE), 0x1001, tok)); return; } }
public bool TryGetKey(TValue value, out TKey key) => ToKey.TryGetValue(value, out key);
public bool TryGetValue(TKey key, out TValue value) => ToValue.TryGetValue(key, out value);
private async Task AnalyzeDeclaringReference(CompilationEvent.SymbolDeclared symbolEvent, SyntaxReference decl, Action <Diagnostic> addDiagnostic, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; var syntax = await decl.GetSyntaxAsync(); var endedAnalyzers = ArrayBuilder <ICodeBlockEndedAnalyzer> .GetInstance(); endedAnalyzers.AddRange(CodeBlockEndedAnalyzers); var nodeAnalyzers = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance(); nodeAnalyzers.AddRange(Analyzers.OfType <ISyntaxNodeAnalyzer <TSyntaxKind> >()); foreach (var da in CodeBlockStartedAnalyzers) { // Catch Exception from da.OnCodeBlockStarted ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnError, cancellationToken, () => { var blockStatefulAnalyzer = da.OnCodeBlockStarted(syntax, symbol, symbolEvent.SemanticModel(decl), addDiagnostic, cancellationToken); var endedAnalyzer = blockStatefulAnalyzer as ICodeBlockEndedAnalyzer; if (endedAnalyzer != null) { endedAnalyzers.Add(endedAnalyzer); } var nodeAnalyzer = blockStatefulAnalyzer as ISyntaxNodeAnalyzer <TSyntaxKind>; if (nodeAnalyzer != null) { nodeAnalyzers.Add(nodeAnalyzer); } }); } PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > nodeAnalyzersByKind = null; foreach (var nodeAnalyzer in nodeAnalyzers) { // Catch Exception from nodeAnalyzer.SyntaxKindsOfInterest try { foreach (var kind in nodeAnalyzer.SyntaxKindsOfInterest) { if (nodeAnalyzersByKind == null) { nodeAnalyzersByKind = PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > .GetInstance(); } ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (!nodeAnalyzersByKind.TryGetValue(kind, out analyzersForKind)) { nodeAnalyzersByKind.Add(kind, analyzersForKind = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance()); } analyzersForKind.Add(nodeAnalyzer); } } catch (Exception e) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(nodeAnalyzer, e)); } } nodeAnalyzers.Free(); SemanticModel semanticModel = (nodeAnalyzersByKind != null || endedAnalyzers.Any()) ? symbolEvent.SemanticModel(decl) : null; if (nodeAnalyzersByKind != null) { semanticModel = symbolEvent.SemanticModel(decl); foreach (var child in syntax.DescendantNodesAndSelf()) { ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (nodeAnalyzersByKind.TryGetValue(GetKind(child), out analyzersForKind)) { foreach (var analyzer in analyzersForKind) { // Catch Exception from analyzer.AnalyzeNode ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { analyzer.AnalyzeNode(child, semanticModel, addDiagnostic, cancellationToken); }); } } } foreach (var b in nodeAnalyzersByKind.Values) { b.Free(); } nodeAnalyzersByKind.Free(); } foreach (var a in endedAnalyzers) { // Catch Exception from a.OnCodeBlockEnded ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { a.OnCodeBlockEnded(syntax, symbol, semanticModel, addDiagnostic, cancellationToken); }); } endedAnalyzers.Free(); }
private void ResolveAndBindMissingAssemblies( TCompilation compilation, ImmutableArray <AssemblyData> explicitAssemblies, ImmutableArray <PEModule> explicitModules, ImmutableArray <MetadataReference> explicitReferences, ImmutableArray <ResolvedReference> explicitReferenceMap, MetadataReferenceResolver resolver, MetadataImportOptions importOptions, bool supersedeLowerVersions, [In, Out] ArrayBuilder <AssemblyReferenceBinding[]> referenceBindings, [In, Out] Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName, out ImmutableArray <AssemblyData> allAssemblies, out ImmutableArray <MetadataReference> metadataReferences, out ImmutableArray <ResolvedReference> resolvedReferences, DiagnosticBag resolutionDiagnostics) { Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt); Debug.Assert(referenceBindings.Count == explicitAssemblies.Length); Debug.Assert(explicitReferences.Length == explicitReferenceMap.Length); // -1 for assembly being built: int totalReferencedAssemblyCount = explicitAssemblies.Length - 1; var implicitAssemblies = ArrayBuilder <AssemblyData> .GetInstance(); // tracks identities we already asked the resolver to resolve: var requestedIdentities = PooledHashSet <AssemblyIdentity> .GetInstance(); PooledDictionary <AssemblyIdentity, PortableExecutableReference> previouslyResolvedAssembliesOpt = null; // Avoid resolving previously resolved missing references. If we call to the resolver again we would create new assembly symbols for them, // which would not match the previously created ones. As a result we would get duplicate PE types and conversion errors. var previousScriptCompilation = compilation.ScriptCompilationInfo?.PreviousScriptCompilation; if (previousScriptCompilation != null) { previouslyResolvedAssembliesOpt = PooledDictionary <AssemblyIdentity, PortableExecutableReference> .GetInstance(); foreach (var entry in previousScriptCompilation.GetBoundReferenceManager().GetImplicitlyResolvedAssemblyReferences()) { previouslyResolvedAssembliesOpt.Add(entry.Key, entry.Value); } } var metadataReferencesBuilder = ArrayBuilder <MetadataReference> .GetInstance(); Dictionary <MetadataReference, MergedAliases> lazyAliasMap = null; // metadata references and corresponding bindings of their references, used to calculate a fixed point: var referenceBindingsToProcess = ArrayBuilder <(MetadataReference, ArraySegment <AssemblyReferenceBinding>)> .GetInstance(); // collect all missing identities, resolve the assemblies and bind their references against explicit definitions: GetInitialReferenceBindingsToProcess(explicitModules, explicitReferences, explicitReferenceMap, referenceBindings, totalReferencedAssemblyCount, referenceBindingsToProcess); // NB: includes the assembly being built: int explicitAssemblyCount = explicitAssemblies.Length; try { while (referenceBindingsToProcess.Count > 0) { var referenceAndBindings = referenceBindingsToProcess.Pop(); var requestingReference = referenceAndBindings.Item1; var bindings = referenceAndBindings.Item2; foreach (var binding in bindings) { // only attempt to resolve unbound references (regardless of version difference of the bound ones) if (binding.IsBound) { continue; } if (!requestedIdentities.Add(binding.ReferenceIdentity)) { continue; } PortableExecutableReference resolvedReference; if (previouslyResolvedAssembliesOpt == null || !previouslyResolvedAssembliesOpt.TryGetValue(binding.ReferenceIdentity, out resolvedReference)) { resolvedReference = resolver.ResolveMissingAssembly(requestingReference, binding.ReferenceIdentity); if (resolvedReference == null) { continue; } } var data = ResolveMissingAssembly(binding.ReferenceIdentity, resolvedReference, importOptions, resolutionDiagnostics); if (data == null) { continue; } // The resolver may return different version than we asked for, so it may happen that // it returns the same identity for two different input identities (e.g. if a higher version // of an assembly is available than what the assemblies reference: "A, v1" -> "A, v3" and "A, v2" -> "A, v3"). // If such case occurs merge the properties (aliases) of the resulting references in the same way we do // during initial explicit references resolution. // -1 for assembly being built: int index = explicitAssemblyCount - 1 + metadataReferencesBuilder.Count; var existingReference = TryAddAssembly(data.Identity, resolvedReference, index, resolutionDiagnostics, Location.None, assemblyReferencesBySimpleName, supersedeLowerVersions); if (existingReference != null) { MergeReferenceProperties(existingReference, resolvedReference, resolutionDiagnostics, ref lazyAliasMap); continue; } metadataReferencesBuilder.Add(resolvedReference); implicitAssemblies.Add(data); var referenceBinding = data.BindAssemblyReferences(explicitAssemblies, IdentityComparer); referenceBindings.Add(referenceBinding); referenceBindingsToProcess.Push((resolvedReference, new ArraySegment <AssemblyReferenceBinding>(referenceBinding))); } } if (implicitAssemblies.Count == 0) { Debug.Assert(lazyAliasMap == null); resolvedReferences = ImmutableArray <ResolvedReference> .Empty; metadataReferences = ImmutableArray <MetadataReference> .Empty; allAssemblies = explicitAssemblies; return; } // Rebind assembly references that were initially missing. All bindings established above // are against explicitly specified references. allAssemblies = explicitAssemblies.AddRange(implicitAssemblies); for (int bindingsIndex = 0; bindingsIndex < referenceBindings.Count; bindingsIndex++) { var referenceBinding = referenceBindings[bindingsIndex]; for (int i = 0; i < referenceBinding.Length; i++) { var binding = referenceBinding[i]; // We don't rebind references bound to a non-matching version of a reference that was explicitly // specified, even if we have a better version now. if (binding.IsBound) { continue; } // We only need to resolve against implicitly resolved assemblies, // since we already resolved against explicitly specified ones. referenceBinding[i] = ResolveReferencedAssembly( binding.ReferenceIdentity, allAssemblies, explicitAssemblyCount, IdentityComparer); } } UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblyCount, implicitAssemblies); metadataReferences = metadataReferencesBuilder.ToImmutable(); resolvedReferences = ToResolvedAssemblyReferences(metadataReferences, lazyAliasMap, explicitAssemblyCount); } finally { implicitAssemblies.Free(); requestedIdentities.Free(); referenceBindingsToProcess.Free(); metadataReferencesBuilder.Free(); previouslyResolvedAssembliesOpt?.Free(); } }
private static TaintedDataConfig Create(Compilation compilation) { WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation); using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourceSymbolMapBuilder = PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance(); using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizerSymbolMapBuilder = PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance(); using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > > sinkSymbolMapBuilder = PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > > .GetInstance(); // For tainted data rules with the same set of sources, we'll reuse the same TaintedDataSymbolMap<SourceInfo> instance. // Same for sanitizers. using PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourcesToSymbolMap = PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance(); using PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizersToSymbolMap = PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance(); // Build a mapping of (sourceSet, sanitizerSet) -> (sinkKinds, sinkSet), so we'll reuse the same TaintedDataSymbolMap<SinkInfo> instance. using PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> sourceSanitizersToSinks = PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> .GetInstance(); // Using LazyThreadSafetyMode.ExecutionAndPublication to avoid instantiating multiple times. foreach (SinkKind sinkKind in Enum.GetValues(typeof(SinkKind))) { ImmutableHashSet <SourceInfo> sources = GetSourceInfos(sinkKind); if (!sourcesToSymbolMap.TryGetValue(sources, out Lazy <TaintedDataSymbolMap <SourceInfo> > lazySourceSymbolMap)) { lazySourceSymbolMap = new Lazy <TaintedDataSymbolMap <SourceInfo> >( () => { return(new TaintedDataSymbolMap <SourceInfo>(wellKnownTypeProvider, sources)); }, LazyThreadSafetyMode.ExecutionAndPublication); sourcesToSymbolMap.Add(sources, lazySourceSymbolMap); } sourceSymbolMapBuilder.Add(sinkKind, lazySourceSymbolMap); ImmutableHashSet <SanitizerInfo> sanitizers = GetSanitizerInfos(sinkKind); if (!sanitizersToSymbolMap.TryGetValue(sanitizers, out Lazy <TaintedDataSymbolMap <SanitizerInfo> > lazySanitizerSymbolMap)) { lazySanitizerSymbolMap = new Lazy <TaintedDataSymbolMap <SanitizerInfo> >( () => { return(new TaintedDataSymbolMap <SanitizerInfo>(wellKnownTypeProvider, sanitizers)); }, LazyThreadSafetyMode.ExecutionAndPublication); sanitizersToSymbolMap.Add(sanitizers, lazySanitizerSymbolMap); } sanitizerSymbolMapBuilder.Add(sinkKind, lazySanitizerSymbolMap); ImmutableHashSet <SinkInfo> sinks = GetSinkInfos(sinkKind); if (!sourceSanitizersToSinks.TryGetValue((sources, sanitizers), out (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)sinksPair)) { sinksPair = (ImmutableHashSet.CreateBuilder <SinkKind>(), ImmutableHashSet.CreateBuilder <SinkInfo>()); sourceSanitizersToSinks.Add((sources, sanitizers), sinksPair); } sinksPair.SinkKinds.Add(sinkKind); sinksPair.SinkInfos.UnionWith(sinks); } foreach (KeyValuePair <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> kvp in sourceSanitizersToSinks) { ImmutableHashSet <SinkInfo> sinks = kvp.Value.SinkInfos.ToImmutable(); Lazy <TaintedDataSymbolMap <SinkInfo> > lazySinkSymbolMap = new Lazy <TaintedDataSymbolMap <SinkInfo> >( () => { return(new TaintedDataSymbolMap <SinkInfo>(wellKnownTypeProvider, sinks)); }, LazyThreadSafetyMode.ExecutionAndPublication); foreach (SinkKind sinkKind in kvp.Value.SinkKinds) { sinkSymbolMapBuilder.Add(sinkKind, lazySinkSymbolMap); } } return(new TaintedDataConfig( wellKnownTypeProvider, sourceSymbolMapBuilder.ToImmutableDictionary(), sanitizerSymbolMapBuilder.ToImmutableDictionary(), sinkSymbolMapBuilder.ToImmutableDictionary())); }
private static void ProcessBody <TSyntaxKind>( SemanticModel semanticModel, ImmutableArray <IDiagnosticAnalyzer> analyzers, ICodeBlockStartedAnalyzer[] bodyAnalyzers, ISymbol symbol, SyntaxNode syntax, CancellationToken cancellationToken, Action <Diagnostic> addDiagnostic, AnalyzerOptions analyzerOptions, bool continueOnError, Func <SyntaxNode, TSyntaxKind> getKind) { var endedAnalyzers = ArrayBuilder <ICodeBlockEndedAnalyzer> .GetInstance(); PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > nodeAnalyzersByKind = null; foreach (var a in bodyAnalyzers) { // Catch Exception from a.OnCodeBlockStarted ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { var analyzer = a.OnCodeBlockStarted(syntax, symbol, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); if (analyzer != null && analyzer != a) { endedAnalyzers.Add(analyzer); } }); } foreach (var nodeAnalyzer in endedAnalyzers.Concat(analyzers).OfType <ISyntaxNodeAnalyzer <TSyntaxKind> >()) { // Catch Exception from nodeAnalyzer.SyntaxKindsOfInterest try { foreach (var kind in nodeAnalyzer.SyntaxKindsOfInterest) { if (nodeAnalyzersByKind == null) { nodeAnalyzersByKind = PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > .GetInstance(); } ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (!nodeAnalyzersByKind.TryGetValue(kind, out analyzersForKind)) { nodeAnalyzersByKind.Add(kind, analyzersForKind = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance()); } analyzersForKind.Add(nodeAnalyzer); } } catch (Exception e) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(nodeAnalyzer, e)); } } if (nodeAnalyzersByKind != null) { foreach (var child in syntax.DescendantNodesAndSelf()) { ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (nodeAnalyzersByKind.TryGetValue(getKind(child), out analyzersForKind)) { foreach (var analyzer in analyzersForKind) { // Catch Exception from analyzer.AnalyzeNode ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { analyzer.AnalyzeNode(child, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); }); } } } foreach (var b in nodeAnalyzersByKind.Values) { b.Free(); } nodeAnalyzersByKind.Free(); } foreach (var a in endedAnalyzers.Concat(analyzers.OfType <ICodeBlockEndedAnalyzer>())) { // Catch Exception from a.OnCodeBlockEnded ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { a.OnCodeBlockEnded(syntax, symbol, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); }); } endedAnalyzers.Free(); }
private static TBlockAnalysisData RunCore( ImmutableArray <BasicBlock> blocks, DataFlowAnalyzer <TBlockAnalysisData> analyzer, int firstBlockOrdinal, int lastBlockOrdinal, TBlockAnalysisData initialAnalysisData, ArrayBuilder <BasicBlock> unreachableBlocksToVisit, SortedSet <int> outOfRangeBlocksToVisit, PooledDictionary <ControlFlowRegion, bool> continueDispatchAfterFinally, PooledHashSet <ControlFlowRegion> dispatchedExceptionsFromRegions, CancellationToken cancellationToken) { var toVisit = new SortedSet <int>(); var firstBlock = blocks[firstBlockOrdinal]; analyzer.SetCurrentAnalysisData(firstBlock, initialAnalysisData, cancellationToken); toVisit.Add(firstBlock.Ordinal); var processedBlocks = PooledHashSet <BasicBlock> .GetInstance(); TBlockAnalysisData resultAnalysisData = default; do { cancellationToken.ThrowIfCancellationRequested(); BasicBlock current; if (toVisit.Count > 0) { var min = toVisit.Min; toVisit.Remove(min); current = blocks[min]; } else { int index; current = null; for (index = 0; index < unreachableBlocksToVisit.Count; index++) { var unreachableBlock = unreachableBlocksToVisit[index]; if (unreachableBlock.Ordinal >= firstBlockOrdinal && unreachableBlock.Ordinal <= lastBlockOrdinal) { current = unreachableBlock; break; } } if (current == null) { continue; } unreachableBlocksToVisit.RemoveAt(index); if (processedBlocks.Contains(current)) { // Already processed from a branch from another unreachable block. continue; } analyzer.SetCurrentAnalysisData(current, analyzer.GetEmptyAnalysisData(), cancellationToken); } if (current.Ordinal < firstBlockOrdinal || current.Ordinal > lastBlockOrdinal) { outOfRangeBlocksToVisit.Add(current.Ordinal); continue; } if (current.Ordinal == current.EnclosingRegion.FirstBlockOrdinal) { // We are revisiting first block of a region, so we need to again dispatch exceptions from region. dispatchedExceptionsFromRegions.Remove(current.EnclosingRegion); } TBlockAnalysisData fallThroughAnalysisData = analyzer.AnalyzeBlock(current, cancellationToken); bool fallThroughSuccessorIsReachable = true; if (current.ConditionKind != ControlFlowConditionKind.None) { TBlockAnalysisData conditionalSuccessorAnalysisData; (fallThroughAnalysisData, conditionalSuccessorAnalysisData) = analyzer.AnalyzeConditionalBranch(current, fallThroughAnalysisData, cancellationToken); bool conditionalSuccesorIsReachable = true; if (current.BranchValue.ConstantValue.HasValue && current.BranchValue.ConstantValue.Value is bool constant) { if (constant == (current.ConditionKind == ControlFlowConditionKind.WhenTrue)) { fallThroughSuccessorIsReachable = false; } else { conditionalSuccesorIsReachable = false; } } if (conditionalSuccesorIsReachable || analyzer.AnalyzeUnreachableBlocks) { FollowBranch(current, current.ConditionalSuccessor, conditionalSuccessorAnalysisData); } } else { fallThroughAnalysisData = analyzer.AnalyzeNonConditionalBranch(current, fallThroughAnalysisData, cancellationToken); } if (fallThroughSuccessorIsReachable || analyzer.AnalyzeUnreachableBlocks) { ControlFlowBranch branch = current.FallThroughSuccessor; FollowBranch(current, branch, fallThroughAnalysisData); if (current.EnclosingRegion.Kind == ControlFlowRegionKind.Finally && current.Ordinal == lastBlockOrdinal) { continueDispatchAfterFinally[current.EnclosingRegion] = branch.Semantics != ControlFlowBranchSemantics.Throw && branch.Semantics != ControlFlowBranchSemantics.Rethrow && current.FallThroughSuccessor.Semantics == ControlFlowBranchSemantics.StructuredExceptionHandling; } } if (current.Ordinal == lastBlockOrdinal) { resultAnalysisData = fallThroughAnalysisData; } // We are using very simple approach: // If try block is reachable, we should dispatch an exception from it, even if it is empty. // To simplify implementation, we dispatch exception from every reachable basic block and rely // on dispatchedExceptionsFromRegions cache to avoid doing duplicate work. DispatchException(current.EnclosingRegion); processedBlocks.Add(current); }while (toVisit.Count != 0 || unreachableBlocksToVisit.Count != 0); return(resultAnalysisData); // Local functions. void FollowBranch(BasicBlock current, ControlFlowBranch branch, TBlockAnalysisData currentAnalsisData) { if (branch == null) { return; } switch (branch.Semantics) { case ControlFlowBranchSemantics.None: case ControlFlowBranchSemantics.ProgramTermination: case ControlFlowBranchSemantics.StructuredExceptionHandling: case ControlFlowBranchSemantics.Error: Debug.Assert(branch.Destination == null); return; case ControlFlowBranchSemantics.Throw: case ControlFlowBranchSemantics.Rethrow: Debug.Assert(branch.Destination == null); StepThroughFinally(current.EnclosingRegion, destinationOrdinal: lastBlockOrdinal, ref currentAnalsisData); return; case ControlFlowBranchSemantics.Regular: case ControlFlowBranchSemantics.Return: Debug.Assert(branch.Destination != null); if (StepThroughFinally(current.EnclosingRegion, branch.Destination.Ordinal, ref currentAnalsisData)) { var destination = branch.Destination; var currentDestinationData = analyzer.GetCurrentAnalysisData(destination); var mergedAnalysisData = analyzer.Merge(currentDestinationData, currentAnalsisData, cancellationToken); // We need to analyze the destination block if both the following conditions are met: // 1. Either the current block is reachable both destination and current are non-reachable // 2. Either the new analysis data for destination has changed or destination block hasn't // been processed. if ((current.IsReachable || !destination.IsReachable) && (!analyzer.IsEqual(currentDestinationData, mergedAnalysisData) || !processedBlocks.Contains(destination))) { analyzer.SetCurrentAnalysisData(destination, mergedAnalysisData, cancellationToken); toVisit.Add(branch.Destination.Ordinal); } } return; default: throw ExceptionUtilities.UnexpectedValue(branch.Semantics); } } // Returns whether we should proceed to the destination after finallies were taken care of. bool StepThroughFinally(ControlFlowRegion region, int destinationOrdinal, ref TBlockAnalysisData currentAnalysisData) { while (!region.ContainsBlock(destinationOrdinal)) { Debug.Assert(region.Kind != ControlFlowRegionKind.Root); ControlFlowRegion enclosing = region.EnclosingRegion; if (region.Kind == ControlFlowRegionKind.Try && enclosing.Kind == ControlFlowRegionKind.TryAndFinally) { Debug.Assert(enclosing.NestedRegions[0] == region); Debug.Assert(enclosing.NestedRegions[1].Kind == ControlFlowRegionKind.Finally); if (!StepThroughSingleFinally(enclosing.NestedRegions[1], ref currentAnalysisData)) { // The point that continues dispatch is not reachable. Cancel the dispatch. return(false); } } region = enclosing; } return(true); } // Returns whether we should proceed with dispatch after finally was taken care of. bool StepThroughSingleFinally(ControlFlowRegion @finally, ref TBlockAnalysisData currentAnalysisData) { Debug.Assert(@finally.Kind == ControlFlowRegionKind.Finally); var previousAnalysisData = analyzer.GetCurrentAnalysisData(blocks[@finally.FirstBlockOrdinal]); var mergedAnalysisData = analyzer.Merge(previousAnalysisData, currentAnalysisData, cancellationToken); if (!analyzer.IsEqual(previousAnalysisData, mergedAnalysisData)) { // For simplicity, we do a complete walk of the finally/filter region in isolation // to make sure that the resume dispatch point is reachable from its beginning. // It could also be reachable through invalid branches into the finally and we don't want to consider // these cases for regular finally handling. currentAnalysisData = RunCore(blocks, analyzer, @finally.FirstBlockOrdinal, @finally.LastBlockOrdinal, mergedAnalysisData, unreachableBlocksToVisit, outOfRangeBlocksToVisit: toVisit, continueDispatchAfterFinally, dispatchedExceptionsFromRegions, cancellationToken); } if (!continueDispatchAfterFinally.TryGetValue(@finally, out bool dispatch)) { dispatch = false; continueDispatchAfterFinally.Add(@finally, false); } return(dispatch); } void DispatchException(ControlFlowRegion fromRegion) { do { if (!dispatchedExceptionsFromRegions.Add(fromRegion)) { return; } ControlFlowRegion enclosing = fromRegion.Kind == ControlFlowRegionKind.Root ? null : fromRegion.EnclosingRegion; if (fromRegion.Kind == ControlFlowRegionKind.Try) { switch (enclosing.Kind) { case ControlFlowRegionKind.TryAndFinally: Debug.Assert(enclosing.NestedRegions[0] == fromRegion); Debug.Assert(enclosing.NestedRegions[1].Kind == ControlFlowRegionKind.Finally); var currentAnalysisData = analyzer.GetCurrentAnalysisData(blocks[fromRegion.FirstBlockOrdinal]); if (!StepThroughSingleFinally(enclosing.NestedRegions[1], ref currentAnalysisData)) { // The point that continues dispatch is not reachable. Cancel the dispatch. return; } break; case ControlFlowRegionKind.TryAndCatch: Debug.Assert(enclosing.NestedRegions[0] == fromRegion); DispatchExceptionThroughCatches(enclosing, startAt: 1); break; default: throw ExceptionUtilities.UnexpectedValue(enclosing.Kind); } } else if (fromRegion.Kind == ControlFlowRegionKind.Filter) { // If filter throws, dispatch is resumed at the next catch with an original exception Debug.Assert(enclosing.Kind == ControlFlowRegionKind.FilterAndHandler); ControlFlowRegion tryAndCatch = enclosing.EnclosingRegion; Debug.Assert(tryAndCatch.Kind == ControlFlowRegionKind.TryAndCatch); int index = tryAndCatch.NestedRegions.IndexOf(enclosing, startIndex: 1); if (index > 0) { DispatchExceptionThroughCatches(tryAndCatch, startAt: index + 1); fromRegion = tryAndCatch; continue; } throw ExceptionUtilities.Unreachable; } fromRegion = enclosing; }while (fromRegion != null); } void DispatchExceptionThroughCatches(ControlFlowRegion tryAndCatch, int startAt) { // For simplicity, we do not try to figure out whether a catch clause definitely // handles all exceptions. Debug.Assert(tryAndCatch.Kind == ControlFlowRegionKind.TryAndCatch); Debug.Assert(startAt > 0); Debug.Assert(startAt <= tryAndCatch.NestedRegions.Length); for (int i = startAt; i < tryAndCatch.NestedRegions.Length; i++) { ControlFlowRegion @catch = tryAndCatch.NestedRegions[i]; switch (@catch.Kind) { case ControlFlowRegionKind.Catch: toVisit.Add(@catch.FirstBlockOrdinal); break; case ControlFlowRegionKind.FilterAndHandler: BasicBlock entryBlock = blocks[@catch.FirstBlockOrdinal]; Debug.Assert(@catch.NestedRegions[0].Kind == ControlFlowRegionKind.Filter); Debug.Assert(entryBlock.Ordinal == @catch.NestedRegions[0].FirstBlockOrdinal); toVisit.Add(entryBlock.Ordinal); break; default: throw ExceptionUtilities.UnexpectedValue(@catch.Kind); } } } }
public bool TryGetValue(TKey key, out TValue value) { Debug.Assert(!IsDisposed); return(_coreAnalysisData.TryGetValue(key, out value)); }
protected void AddStoredItemsFoldout() { if (!Application.isPlaying) { return; } this.showStored = EditorGUILayout.Foldout(this.showStored, "Stored Items"); if (!this.showStored) { return; } EditorGUI.indentLevel++; var entityStore = this.target as EntityStore; using (var storedIds = ListPool <string> .Get()) { entityStore.GetAllStoredKeys(storedIds); var defaultColor = GUI.color; var defaultContentColor = GUI.contentColor; var now = DateTimeOffset.Now; foreach (var id in storedIds) { var foldoutStyle = EditorStyles.foldout; ResolveStatus loadStatus; if (!entityStore.GetResolveStatus(id, out loadStatus)) { continue; } if (!string.IsNullOrEmpty(loadStatus.resolveError)) { GUI.color = ERROR; GUI.contentColor = ERROR; } else if (loadStatus.isResolveInProgress) { GUI.color = IN_PROGRESS; GUI.contentColor = IN_PROGRESS; } else if (loadStatus.IsExpiredAt(now)) { GUI.color = EXPIRED; GUI.contentColor = EXPIRED; foldoutStyle = new GUIStyle(foldoutStyle); foldoutStyle.normal.textColor = EXPIRED; } else { GUI.color = loadStatus.hasResolved ? defaultColor : NONE; GUI.contentColor = GUI.color; } bool showingDetails = false; m_isExpandedById.TryGetValue(id, out showingDetails); var foldoutString = this.foldoutStringDelegate != null? this.foldoutStringDelegate(id) : id; var showDetails = EditorGUILayout.Foldout(showingDetails, new GUIContent(foldoutString), foldoutStyle); if (showDetails != showingDetails) { m_isExpandedById[id] = showDetails; } if (!showDetails) { continue; } if (!string.IsNullOrEmpty(loadStatus.resolveError)) { EditorGUILayout.LabelField("error", loadStatus.resolveError); } else if (loadStatus.isResolveInProgress) { EditorGUILayout.LabelField("loading for ", (DateTimeOffset.Now - loadStatus.updatedAt).TotalSeconds + "secs"); GUI.color = IN_PROGRESS; } else if (loadStatus.IsExpiredAt(now)) { EditorGUILayout.LabelField("expired at", loadStatus.timestamp.AddSeconds(loadStatus.maxAgeSecs).ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss.fff")); } else { GUI.color = loadStatus.hasResolved ? defaultColor : NONE; } if (loadStatus.hasResolved) { EditorGUILayout.LabelField("timestamp", loadStatus.timestamp.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss.fff")); EditorGUILayout.LabelField("max age", loadStatus.maxAgeSecs.ToString()); } if (this.foldoutPropsDelegate != null) { using (var props = ListPool <KeyValuePair <string, string> > .Get()) { this.foldoutPropsDelegate(id, props); foreach (var p in props) { EditorGUILayout.LabelField(new GUIContent(p.Key), new GUIContent(p.Value), EditorStyles.wordWrappedLabel ); } } } else { try { object data; if (entityStore.GetDataAsObject(id, out data)) { EditorGUILayout.TextArea(JsonUtility.ToJson(data, true)); } } catch (Exception e) { Debug.LogError(e); } } GUI.contentColor = defaultContentColor; EditorGUILayout.Separator(); } EditorGUI.indentLevel--; } }
#pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member because of nullability attributes. https://github.com/dotnet/roslyn/issues/42552 public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) #pragma warning restore CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member because of nullability attributes. { Debug.Assert(!IsDisposed); return(_coreAnalysisData.TryGetValue(key, out value)); }