private void GetPartialCompilationState( SolutionState solution, DocumentId id, out ProjectState inProgressProject, out Compilation inProgressCompilation, CancellationToken cancellationToken) { var state = ReadState(); var compilation = state.Compilation?.GetValueOrNull(cancellationToken); // check whether we can bail out quickly for typing case var inProgressState = state as InProgressState; // all changes left for this document is modifying the given document. // we can use current state as it is since we will replace the document with latest document anyway. if (inProgressState != null && compilation != null && inProgressState.IntermediateProjects.All(t => IsTouchDocumentActionForDocument(t.action, id))) { inProgressProject = ProjectState; inProgressCompilation = compilation; SolutionLogger.UseExistingPartialProjectState(); return; } inProgressProject = inProgressState != null?inProgressState.IntermediateProjects.First().state : this.ProjectState; // if we already have a final compilation we are done. if (compilation != null && state is FinalState) { inProgressCompilation = compilation; SolutionLogger.UseExistingFullProjectState(); return; } // 1) if we have an in-progress compilation use it. // 2) If we don't, then create a simple empty compilation/project. // 3) then, make sure that all it's p2p refs and whatnot are correct. if (compilation == null) { inProgressProject = inProgressProject.RemoveAllDocuments(); inProgressCompilation = CreateEmptyCompilation(); } else { inProgressCompilation = compilation; } // first remove all project from the project and compilation. inProgressProject = inProgressProject.WithProjectReferences(ImmutableArray.Create <ProjectReference>()); // Now add in back a consistent set of project references. For project references // try to get either a CompilationReference or a SkeletonReference. This ensures // that the in-progress project only reports a reference to another project if it // could actually get a reference to that project's metadata. var metadataReferences = new List <MetadataReference>(); var newProjectReferences = new List <ProjectReference>(); metadataReferences.AddRange(this.ProjectState.MetadataReferences); var metadataReferenceToProjectId = new Dictionary <MetadataReference, ProjectId>(); foreach (var projectReference in this.ProjectState.ProjectReferences) { var referencedProject = solution.GetProjectState(projectReference.ProjectId); if (referencedProject != null) { if (referencedProject.IsSubmission) { var previousScriptCompilation = solution.GetCompilationAsync(projectReference.ProjectId, cancellationToken).WaitAndGetResult(cancellationToken); // previous submission project must support compilation: RoslynDebug.Assert(previousScriptCompilation != null); inProgressCompilation = inProgressCompilation.WithScriptCompilationInfo(inProgressCompilation.ScriptCompilationInfo.WithPreviousScriptCompilation(previousScriptCompilation)); } else { // get the latest metadata for the partial compilation of the referenced project. var metadata = solution.GetPartialMetadataReference(projectReference, this.ProjectState); if (metadata == null) { // if we failed to get the metadata, check to see if we previously had existing metadata and reuse it instead. var inProgressCompilationNotRef = inProgressCompilation; metadata = inProgressCompilationNotRef.ExternalReferences.FirstOrDefault( r => solution.GetProjectState(inProgressCompilationNotRef.GetAssemblyOrModuleSymbol(r) as IAssemblySymbol)?.Id == projectReference.ProjectId); } if (metadata != null) { newProjectReferences.Add(projectReference); metadataReferences.Add(metadata); metadataReferenceToProjectId.Add(metadata, projectReference.ProjectId); } } } } inProgressProject = inProgressProject.AddProjectReferences(newProjectReferences); inProgressCompilation = UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(inProgressCompilation, metadataReferences, metadataReferenceToProjectId); SolutionLogger.CreatePartialProjectState(); }
internal override GreenNode SetAnnotations(SyntaxAnnotation[]?annotations) { RoslynDebug.Assert(GetType() == typeof(SyntaxToken)); return(new SyntaxToken(Kind, FullWidth, GetDiagnostics(), annotations)); }
public EventSymbol(Symbols.EventSymbol underlying) { RoslynDebug.Assert(underlying is object); _underlying = underlying; }
protected override void AnalyzeDiagnosticAnalyzer(SymbolAnalysisContext symbolContext) { var namedType = (INamedTypeSymbol)symbolContext.Symbol; if (namedType.IsAbstract) { return; } // 1) MissingDiagnosticAnalyzerAttributeRule: DiagnosticAnalyzer has no DiagnosticAnalyzerAttribute. // 2) AddLanguageSupportToAnalyzerRule: For analyzer supporting only one of C# or VB languages, detect if it can support the other language. var hasAttribute = false; SyntaxNode?attributeSyntax = null; bool supportsCSharp = false; bool supportsVB = false; var namedTypeAttributes = namedType.GetApplicableAttributes(_attributeUsageAttribute); foreach (AttributeData attribute in namedTypeAttributes) { if (attribute.AttributeClass.DerivesFrom(DiagnosticAnalyzerAttribute)) { // Bail out for the case where analyzer type derives from a sub-type in different assembly, and the sub-type has the diagnostic analyzer attribute. if (attribute.ApplicationSyntaxReference == null) { return; } hasAttribute = true; // The attribute constructor's signature is "(string, params string[])", // so process both string arguments and string[] arguments. foreach (TypedConstant arg in attribute.ConstructorArguments) { CheckLanguage(arg, ref supportsCSharp, ref supportsVB); if (arg.Kind == TypedConstantKind.Array) { foreach (TypedConstant element in arg.Values) { CheckLanguage(element, ref supportsCSharp, ref supportsVB); } } } attributeSyntax = attribute.ApplicationSyntaxReference.GetSyntax(symbolContext.CancellationToken); } } if (!hasAttribute) { Diagnostic diagnostic = namedType.CreateDiagnostic(MissingDiagnosticAnalyzerAttributeRule); symbolContext.ReportDiagnostic(diagnostic); } else if (supportsCSharp ^ supportsVB) { RoslynDebug.Assert(attributeSyntax != null); // If the analyzer assembly doesn't reference either C# or VB CodeAnalysis assemblies, // then the analyzer is pretty likely a language-agnostic analyzer. Compilation compilation = symbolContext.Compilation; string compilationTypeNameToCheck = supportsCSharp ? CSharpCompilationFullName : BasicCompilationFullName; INamedTypeSymbol?compilationType = compilation.GetOrCreateTypeByMetadataName(compilationTypeNameToCheck); if (compilationType == null) { string missingLanguage = supportsCSharp ? LanguageNames.VisualBasic : LanguageNames.CSharp; Diagnostic diagnostic = attributeSyntax.CreateDiagnostic(AddLanguageSupportToAnalyzerRule, namedType.Name, missingLanguage); symbolContext.ReportDiagnostic(diagnostic); } } }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { compilationContext.RegisterOperationBlockAction(operationBlockContext => { var owningSymbol = operationBlockContext.OwningSymbol; if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockContext.Options, AlwaysTrueFalseOrNullRule, operationBlockContext.Compilation, operationBlockContext.CancellationToken)) { return; } var processedOperationRoots = new HashSet <IOperation>(); foreach (var operationRoot in operationBlockContext.OperationBlocks) { static bool ShouldAnalyze(IOperation op) => (op as IBinaryOperation)?.IsComparisonOperator() == true || (op as IInvocationOperation)?.TargetMethod.ReturnType.SpecialType == SpecialType.System_Boolean || op.Kind == OperationKind.Coalesce || op.Kind == OperationKind.ConditionalAccess || op.Kind == OperationKind.IsNull || op.Kind == OperationKind.IsPattern; if (operationRoot.HasAnyOperationDescendant(ShouldAnalyze)) { // Skip duplicate analysis from operation blocks for constructor initializer and body. if (!processedOperationRoots.Add(operationRoot.GetRoot())) { // Already processed. continue; } var cfg = operationBlockContext.GetControlFlowGraph(operationRoot); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockContext.Compilation); var valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider, operationBlockContext.Options, AlwaysTrueFalseOrNullRule, PointsToAnalysisKind.Complete, operationBlockContext.CancellationToken, out var copyAnalysisResultOpt, out var pointsToAnalysisResult); if (valueContentAnalysisResult == null || pointsToAnalysisResult == null) { continue; } foreach (var operation in cfg.DescendantOperations()) { // Skip implicit operations. // However, 'IsNull' operations are compiler generated operations corresponding to // non-implicit conditional access operations, so we should not skip them. if (operation.IsImplicit && operation.Kind != OperationKind.IsNull) { continue; } switch (operation.Kind) { case OperationKind.BinaryOperator: var binaryOperation = (IBinaryOperation)operation; PredicateValueKind predicateKind = GetPredicateKind(binaryOperation); if (predicateKind != PredicateValueKind.Unknown && (!(binaryOperation.LeftOperand is IBinaryOperation leftBinary) || GetPredicateKind(leftBinary) == PredicateValueKind.Unknown) && (!(binaryOperation.RightOperand is IBinaryOperation rightBinary) || GetPredicateKind(rightBinary) == PredicateValueKind.Unknown)) { ReportAlwaysTrueFalseOrNullDiagnostic(operation, predicateKind); } break; case OperationKind.Invocation: case OperationKind.IsPattern: predicateKind = GetPredicateKind(operation); if (predicateKind != PredicateValueKind.Unknown) { ReportAlwaysTrueFalseOrNullDiagnostic(operation, predicateKind); } break; case OperationKind.IsNull: // '{0}' is always/never '{1}'. Remove or refactor the condition(s) to avoid dead code. predicateKind = GetPredicateKind(operation); DiagnosticDescriptor rule; switch (predicateKind) { case PredicateValueKind.AlwaysTrue: rule = AlwaysTrueFalseOrNullRule; break; case PredicateValueKind.AlwaysFalse: rule = NeverNullRule; break; default: continue; } var originalOperation = operationRoot.SemanticModel.GetOperation(operation.Syntax, operationBlockContext.CancellationToken); if (originalOperation is IAssignmentOperation || originalOperation is IVariableDeclaratorOperation) { // Skip compiler generated IsNull operation for assignment/variable declaration within a using. continue; } var arg1 = operation.Syntax.ToString(); var arg2 = operation.Language == LanguageNames.VisualBasic ? "Nothing" : "null"; var diagnostic = operation.CreateDiagnostic(rule, arg1, arg2); operationBlockContext.ReportDiagnostic(diagnostic); break; } } PredicateValueKind GetPredicateKind(IOperation operation) { Debug.Assert(operation.Kind == OperationKind.BinaryOperator || operation.Kind == OperationKind.Invocation || operation.Kind == OperationKind.IsNull || operation.Kind == OperationKind.IsPattern); RoslynDebug.Assert(pointsToAnalysisResult != null); RoslynDebug.Assert(valueContentAnalysisResult != null); if (operation is IBinaryOperation binaryOperation && binaryOperation.IsComparisonOperator() || operation.Type?.SpecialType == SpecialType.System_Boolean) { PredicateValueKind predicateKind = pointsToAnalysisResult.GetPredicateKind(operation); if (predicateKind != PredicateValueKind.Unknown) { return(predicateKind); } if (copyAnalysisResultOpt != null) { predicateKind = copyAnalysisResultOpt.GetPredicateKind(operation); if (predicateKind != PredicateValueKind.Unknown) { return(predicateKind); } } predicateKind = valueContentAnalysisResult.GetPredicateKind(operation); if (predicateKind != PredicateValueKind.Unknown) { return(predicateKind); } } return(PredicateValueKind.Unknown); } void ReportAlwaysTrueFalseOrNullDiagnostic(IOperation operation, PredicateValueKind predicateKind) { Debug.Assert(predicateKind != PredicateValueKind.Unknown); // '{0}' is always '{1}'. Remove or refactor the condition(s) to avoid dead code. var arg1 = operation.Syntax.ToString(); var arg2 = predicateKind == PredicateValueKind.AlwaysTrue ? (operation.Language == LanguageNames.VisualBasic ? "True" : "true") : (operation.Language == LanguageNames.VisualBasic ? "False" : "false"); var diagnostic = operation.CreateDiagnostic(AlwaysTrueFalseOrNullRule, arg1, arg2); operationBlockContext.ReportDiagnostic(diagnostic); } } }
internal PEEventSymbol( PEModuleSymbol moduleSymbol, PENamedTypeSymbol containingType, EventDefinitionHandle handle, PEMethodSymbol addMethod, PEMethodSymbol removeMethod, MultiDictionary <string, PEFieldSymbol> privateFieldNameToSymbols ) { RoslynDebug.Assert((object)moduleSymbol != null); RoslynDebug.Assert((object)containingType != null); Debug.Assert(!handle.IsNil); RoslynDebug.Assert((object)addMethod != null); RoslynDebug.Assert((object)removeMethod != null); _addMethod = addMethod; _removeMethod = removeMethod; _handle = handle; _containingType = containingType; EventAttributes mdFlags = 0; EntityHandle eventType = default(EntityHandle); try { var module = moduleSymbol.Module; module.GetEventDefPropsOrThrow(handle, out _name, out mdFlags, out eventType); } catch (BadImageFormatException mrEx) { _name = _name ?? string.Empty; _lazyCachedUseSiteInfo.Initialize( new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, this) ); if (eventType.IsNil) { _eventTypeWithAnnotations = TypeWithAnnotations.Create( new UnsupportedMetadataTypeSymbol(mrEx) ); } } TypeSymbol originalEventType = _eventTypeWithAnnotations.Type; if (!_eventTypeWithAnnotations.HasType) { var metadataDecoder = new MetadataDecoder(moduleSymbol, containingType); originalEventType = metadataDecoder.GetTypeOfToken(eventType); const int targetSymbolCustomModifierCount = 0; var typeSymbol = DynamicTypeDecoder.TransformType( originalEventType, targetSymbolCustomModifierCount, handle, moduleSymbol ); typeSymbol = NativeIntegerTypeDecoder.TransformType( typeSymbol, handle, moduleSymbol ); // We start without annotation (they will be decoded below) var type = TypeWithAnnotations.Create(typeSymbol); // Decode nullable before tuple types to avoid converting between // NamedTypeSymbol and TupleTypeSymbol unnecessarily. // The containing type is passed to NullableTypeDecoder.TransformType to determine access // because the event does not have explicit accessibility in metadata. type = NullableTypeDecoder.TransformType( type, handle, moduleSymbol, accessSymbol: _containingType, nullableContext: _containingType ); type = TupleTypeDecoder.DecodeTupleTypesIfApplicable(type, handle, moduleSymbol); _eventTypeWithAnnotations = type; } // IsWindowsRuntimeEvent checks the signatures, so we just have to check the accessors. bool isWindowsRuntimeEvent = IsWindowsRuntimeEvent; bool callMethodsDirectly = isWindowsRuntimeEvent ? !DoModifiersMatch(_addMethod, _removeMethod) : !DoSignaturesMatch(moduleSymbol, originalEventType, _addMethod, _removeMethod); if (callMethodsDirectly) { _flags |= Flags.CallMethodsDirectly; } else { _addMethod.SetAssociatedEvent(this, MethodKind.EventAdd); _removeMethod.SetAssociatedEvent(this, MethodKind.EventRemove); PEFieldSymbol?associatedField = GetAssociatedField( privateFieldNameToSymbols, isWindowsRuntimeEvent ); if ((object?)associatedField != null) { _associatedFieldOpt = associatedField; associatedField.SetAssociatedEvent(this); } } if ((mdFlags & EventAttributes.SpecialName) != 0) { _flags |= Flags.IsSpecialName; } if ((mdFlags & EventAttributes.RTSpecialName) != 0) { _flags |= Flags.IsRuntimeSpecialName; } }
public static void ReportNoLocationDiagnostic( this Compilation compilation, DiagnosticDescriptor rule, Action <Diagnostic> addDiagnostic, ImmutableDictionary <string, string?>?properties, params object[] args) { var effectiveSeverity = GetEffectiveSeverity(); if (!effectiveSeverity.HasValue) { // Disabled rule return; } if (effectiveSeverity.Value != rule.DefaultSeverity) { #pragma warning disable RS0030 // The symbol 'DiagnosticDescriptor.DiagnosticDescriptor.#ctor' is banned in this project: Use 'DiagnosticDescriptorHelper.Create' instead rule = new DiagnosticDescriptor(rule.Id, rule.Title, rule.MessageFormat, rule.Category, effectiveSeverity.Value, rule.IsEnabledByDefault, rule.Description, rule.HelpLinkUri, rule.CustomTags.ToArray()); #pragma warning restore RS0030 } var diagnostic = Diagnostic.Create(rule, Location.None, properties, args); addDiagnostic(diagnostic); return; DiagnosticSeverity?GetEffectiveSeverity() { // Microsoft.CodeAnalysis version >= 3.7 exposes options through 'CompilationOptions.SyntaxTreeOptionsProvider.TryGetDiagnosticValue' // Microsoft.CodeAnalysis version 3.3 - 3.7 exposes options through 'SyntaxTree.DiagnosticOptions'. This API is deprecated in 3.7. var syntaxTreeOptionsProvider = s_compilationOptionsSyntaxTreeOptionsProviderProperty?.GetValue(compilation.Options); var syntaxTreeOptionsProviderTryGetDiagnosticValueMethod = syntaxTreeOptionsProvider?.GetType().GetRuntimeMethods().FirstOrDefault(m => m.Name == "TryGetDiagnosticValue"); if (syntaxTreeOptionsProviderTryGetDiagnosticValueMethod == null && s_syntaxTreeDiagnosticOptionsProperty == null) { return(rule.DefaultSeverity); } ReportDiagnostic?overriddenSeverity = null; foreach (var tree in compilation.SyntaxTrees) { ReportDiagnostic?configuredValue = null; // Prefer 'CompilationOptions.SyntaxTreeOptionsProvider', if available. if (s_compilationOptionsSyntaxTreeOptionsProviderProperty != null) { if (syntaxTreeOptionsProviderTryGetDiagnosticValueMethod != null) { // public abstract bool TryGetDiagnosticValue(SyntaxTree tree, string diagnosticId, out ReportDiagnostic severity); // public abstract bool TryGetDiagnosticValue(SyntaxTree tree, string diagnosticId, CancellationToken cancellationToken, out ReportDiagnostic severity); object?[] parameters; if (syntaxTreeOptionsProviderTryGetDiagnosticValueMethod.GetParameters().Length == 3) { parameters = new object?[] { tree, rule.Id, null }; } else { parameters = new object?[] { tree, rule.Id, CancellationToken.None, null }; } if (syntaxTreeOptionsProviderTryGetDiagnosticValueMethod.Invoke(syntaxTreeOptionsProvider, parameters) is true && parameters.Last() is ReportDiagnostic value) { configuredValue = value; } } } else { RoslynDebug.Assert(s_syntaxTreeDiagnosticOptionsProperty != null); var options = (ImmutableDictionary <string, ReportDiagnostic>)s_syntaxTreeDiagnosticOptionsProperty.GetValue(tree) !; if (options.TryGetValue(rule.Id, out var value)) { configuredValue = value; } } if (configuredValue == null) { continue; } if (configuredValue == ReportDiagnostic.Suppress) { // Any suppression entry always wins. return(null); } if (overriddenSeverity == null) { overriddenSeverity = configuredValue; } else if (overriddenSeverity.Value.IsLessSevereThan(configuredValue.Value)) { // Choose the most severe value for conflicts. overriddenSeverity = configuredValue; } } return(overriddenSeverity.HasValue ? overriddenSeverity.Value.ToDiagnosticSeverity() : rule.DefaultSeverity); } }
public async Task <Document> AddImportsAsync( Document document, IEnumerable <TextSpan> spans, Strategy strategy, bool safe, OptionSet?options, CancellationToken cancellationToken) { options ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var addImportsService = document.GetRequiredLanguageService <IAddImportsService>(); var generator = document.GetRequiredLanguageService <SyntaxGenerator>(); // Create a simple interval tree for simplification spans. var spansTree = new SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>(new TextSpanIntervalIntrospector(), spans); var nodes = root.DescendantNodesAndSelf().Where(IsInSpan); var(importDirectivesToAdd, namespaceSymbols, context, model, newRoot) = strategy switch { Strategy.AddImportsFromSymbolAnnotations => await GetImportDirectivesFromAnnotatedNodesAsync(document, nodes, root, addImportsService, generator, cancellationToken).ConfigureAwait(false), Strategy.AddImportsFromSyntaxes => await GetImportDirectivesFromSyntaxesAsync(document, nodes, root, addImportsService, generator, cancellationToken).ConfigureAwait(false), _ => throw new InvalidEnumArgumentException(nameof(strategy), (int)strategy, typeof(Strategy)), }; // If the previous call provided a new root, use it. root = newRoot ?? root; if (importDirectivesToAdd.Length == 0) { return(document.WithSyntaxRoot(root)); //keep any added simplifier annotations } if (safe) { // Mark the context with an annotation. // This will allow us to find it after we have called MakeSafeToAddNamespaces. var annotation = new SyntaxAnnotation(); RoslynDebug.Assert(context is object); document = document.WithSyntaxRoot(root.ReplaceNode(context, context.WithAdditionalAnnotations(annotation))); root = (await document.GetSyntaxRootAsync().ConfigureAwait(false)) !; model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(model); // Make Safe to add namespaces document = document.WithSyntaxRoot( MakeSafeToAddNamespaces(root, namespaceSymbols, model, document.Project.Solution.Workspace, cancellationToken)); root = (await document.GetSyntaxRootAsync().ConfigureAwait(false)) !; model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(model); // Find the context. It might be null if we have removed the context in the process of complexifying the tree. context = root.DescendantNodesAndSelf().FirstOrDefault(x => x.HasAnnotation(annotation)) ?? root; } model ??= await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var placeSystemNamespaceFirst = options.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, document.Project.Language); root = addImportsService.AddImports(model.Compilation, root, context, importDirectivesToAdd, generator, placeSystemNamespaceFirst, cancellationToken); return(document.WithSyntaxRoot(root)); bool IsInSpan(SyntaxNode node) => spansTree.HasIntervalThatOverlapsWith(node.FullSpan.Start, node.FullSpan.Length); }
internal ImmutableArray <TypeParameterConstraintClause> BindTypeParameterConstraintClauses( Symbol containingSymbol, ImmutableArray <TypeParameterSymbol> typeParameters, TypeParameterListSyntax typeParameterList, SyntaxList <TypeParameterConstraintClauseSyntax> clauses, ref IReadOnlyDictionary <TypeParameterSymbol, bool> isValueTypeOverride, DiagnosticBag diagnostics, bool isForOverride = false) { Debug.Assert(this.Flags.Includes(BinderFlags.GenericConstraintsClause)); RoslynDebug.Assert((object)containingSymbol != null); Debug.Assert((containingSymbol.Kind == SymbolKind.NamedType) || (containingSymbol.Kind == SymbolKind.Method)); Debug.Assert(typeParameters.Length > 0); Debug.Assert(clauses.Count > 0); int n = typeParameters.Length; // Create a map from type parameter name to ordinal. // No need to report duplicate names since duplicates // are reported when the type parameters are bound. var names = new Dictionary <string, int>(n, StringOrdinalComparer.Instance); foreach (var typeParameter in typeParameters) { var name = typeParameter.Name; if (!names.ContainsKey(name)) { names.Add(name, names.Count); } } // An array of constraint clauses, one for each type parameter, indexed by ordinal. var results = ArrayBuilder <TypeParameterConstraintClause?> .GetInstance(n, fillWithValue : null); var syntaxNodes = ArrayBuilder <ArrayBuilder <TypeConstraintSyntax>?> .GetInstance(n, fillWithValue : null); // Bind each clause and add to the results. foreach (var clause in clauses) { var name = clause.Name.Identifier.ValueText; RoslynDebug.Assert(name is object); int ordinal; if (names.TryGetValue(name, out ordinal)) { Debug.Assert(ordinal >= 0); Debug.Assert(ordinal < n); (TypeParameterConstraintClause constraintClause, ArrayBuilder <TypeConstraintSyntax>?typeConstraintNodes) = this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, diagnostics); if (results[ordinal] == null) { results[ordinal] = constraintClause; syntaxNodes[ordinal] = typeConstraintNodes; } else { // "A constraint clause has already been specified for type parameter '{0}'. ..." diagnostics.Add(ErrorCode.ERR_DuplicateConstraintClause, clause.Name.Location, name); typeConstraintNodes?.Free(); } } else { // Unrecognized type parameter. Don't bother binding the constraints // (the ": I<U>" in "where U : I<U>") since that will lead to additional // errors ("type or namespace 'U' could not be found") if the type // parameter is referenced in the constraints. // "'{1}' does not define type parameter '{0}'" diagnostics.Add(ErrorCode.ERR_TyVarNotFoundInConstraint, clause.Name.Location, name, containingSymbol.ConstructedFrom()); } } // Add default values for type parameters without constraint clauses. for (int i = 0; i < n; i++) { if (results[i] == null) { results[i] = GetDefaultTypeParameterConstraintClause(typeParameterList.Parameters[i], isForOverride); } } TypeParameterConstraintClause.AdjustConstraintTypes(containingSymbol, typeParameters, results, ref isValueTypeOverride); RemoveInvalidConstraints(typeParameters, results !, syntaxNodes, diagnostics); foreach (var typeConstraintsSyntaxes in syntaxNodes) { typeConstraintsSyntaxes?.Free(); } syntaxNodes.Free(); return(results.ToImmutableAndFree() !); }
/// <summary> /// Given a ISymbol, returns the renameable locations for a given symbol. /// </summary> public static async Task <ImmutableArray <RenameLocation> > GetRenamableDefinitionLocationsAsync( ISymbol referencedSymbol, ISymbol originalSymbol, Solution solution, CancellationToken cancellationToken) { var shouldIncludeSymbol = await ShouldIncludeSymbolAsync(referencedSymbol, originalSymbol, solution, false, cancellationToken).ConfigureAwait(false); if (!shouldIncludeSymbol) { return(ImmutableArray <RenameLocation> .Empty); } // Namespaces are definitions and references all in one. Since every definition // location is also a reference, we'll ignore it's definitions. if (referencedSymbol.Kind == SymbolKind.Namespace) { return(ImmutableArray <RenameLocation> .Empty); } var results = ArrayBuilder <RenameLocation> .GetInstance(); // If the original symbol was an alias, then the definitions will just be the // location of the alias, always if (originalSymbol.Kind == SymbolKind.Alias) { var location = originalSymbol.Locations.Single(); AddRenameLocationIfNotGenerated(location); return(results.ToImmutableAndFree()); } var isRenamableAccessor = await IsPropertyAccessorOrAnOverrideAsync(referencedSymbol, solution, cancellationToken).ConfigureAwait(false); foreach (var location in referencedSymbol.Locations) { if (location.IsInSource) { AddRenameLocationIfNotGenerated(location, isRenamableAccessor); } } // If we're renaming a named type, we'll also have to find constructors and // destructors declarations that match the name if (referencedSymbol.Kind == SymbolKind.NamedType && referencedSymbol.Locations.All(l => l.IsInSource)) { var firstLocation = referencedSymbol.Locations[0]; var syntaxFacts = solution.GetRequiredDocument(firstLocation.SourceTree !) .GetRequiredLanguageService <ISyntaxFactsService>(); var namedType = (INamedTypeSymbol)referencedSymbol; foreach (var method in namedType.GetMembers().OfType <IMethodSymbol>()) { if (!method.IsImplicitlyDeclared && (method.MethodKind == MethodKind.Constructor || method.MethodKind == MethodKind.StaticConstructor || method.MethodKind == MethodKind.Destructor)) { foreach (var location in method.Locations) { if (location.IsInSource) { var token = location.FindToken(cancellationToken); if (!syntaxFacts.IsReservedOrContextualKeyword(token) && token.ValueText == referencedSymbol.Name) { AddRenameLocationIfNotGenerated(location); } } } } } } return(results.ToImmutableAndFree()); void AddRenameLocationIfNotGenerated(Location location, bool isRenamableAccessor = false) { RoslynDebug.Assert(location.IsInSource); var document = solution.GetRequiredDocument(location.SourceTree); // If the location is in a source generated file, we won't rename it. Our assumption in this case is we // have cascaded to this symbol from our original source symbol, and the generator will update this file // based on the renamed symbol. if (document is not SourceGeneratedDocument) { results.Add(new RenameLocation(location, document.Id, isRenamableAccessor: isRenamableAccessor)); } } }
// Both hash computations below use the FNV-1a algorithm (http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function). internal static int GetHashCode(byte[] x) { RoslynDebug.Assert(x != null); return(Hash.GetFNVHashCode(x)); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics); analysisContext.EnableConcurrentExecution(); analysisContext.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { if (!compilationStartAnalysisContext.Compilation.TryGetOrCreateTypeByMetadataName( WellKnownTypeNames.NewtonsoftJsonTypeNameHandling, out INamedTypeSymbol? typeNameHandlingSymbol)) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IFieldReferenceOperation fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; if (IsOtherThanNone(fieldReferenceOperation)) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic(Rule)); } }, OperationKind.FieldReference); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IAssignmentOperation assignmentOperation = (IAssignmentOperation)operationAnalysisContext.Operation; if (!typeNameHandlingSymbol.Equals(assignmentOperation.Target.Type)) { return; } // Find the topmost operation with non-zero (not None), unless we find an operation that would've // been flagged by the FieldReference callback above. foreach (IOperation childOperation in assignmentOperation.Value.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsOtherThanNone(fieldReferenceOperation)) { return; } if (childOperation.ConstantValue.HasValue && childOperation.ConstantValue.Value is int integerValue && integerValue != 0) { operationAnalysisContext.ReportDiagnostic(childOperation.CreateDiagnostic(Rule)); return; } } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment); return; bool IsOtherThanNone(IFieldReferenceOperation fieldReferenceOperation) { RoslynDebug.Assert(typeNameHandlingSymbol != null); if (!typeNameHandlingSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { return(false); } return(fieldReferenceOperation.Field.Name != "None"); }; }); }
private void TrackBulkFileOperations() { RoslynDebug.AssertNotNull(_workspace); // we will pause whatever ambient work loads we have that are tied to IGlobalOperationNotificationService // such as solution crawler, pre-emptive remote host synchronization and etc. any background work users didn't // explicitly asked for. // // this should give all resources to BulkFileOperation. we do same for things like build, // debugging, wait dialog and etc. BulkFileOperation is used for things like git branch switching and etc. var globalNotificationService = _workspace.Services.GetRequiredService <IGlobalOperationNotificationService>(); // BulkFileOperation can't have nested events. there will be ever only 1 events (Begin/End) // so we only need simple tracking. var gate = new object(); GlobalOperationRegistration?localRegistration = null; BulkFileOperation.End += (s, a) => { StopBulkFileOperationNotification(); }; BulkFileOperation.Begin += (s, a) => { StartBulkFileOperationNotification(); }; void StartBulkFileOperationNotification() { RoslynDebug.Assert(gate != null); RoslynDebug.Assert(globalNotificationService != null); lock (gate) { // this shouldn't happen, but we are using external component // so guarding us from them if (localRegistration != null) { FatalError.ReportWithoutCrash(new InvalidOperationException("BulkFileOperation already exist")); return; } localRegistration = globalNotificationService.Start("BulkFileOperation"); } } void StopBulkFileOperationNotification() { RoslynDebug.Assert(gate != null); lock (gate) { // this can happen if BulkFileOperation was already in the middle // of running. to make things simpler, decide to not use IsInProgress // which we need to worry about race case. if (localRegistration == null) { return; } localRegistration.Dispose(); localRegistration = null; } } }
internal CommandLineParser(CommonMessageProvider messageProvider, bool isScriptCommandLineParser) { RoslynDebug.Assert(messageProvider != null); _messageProvider = messageProvider; IsScriptCommandLineParser = isScriptCommandLineParser; }
private static void AnalyzeSymbol( SymbolAnalysisContext context, INamedTypeSymbol?iCollectionType, INamedTypeSymbol?gCollectionType, INamedTypeSymbol?iEnumerableType, INamedTypeSymbol?gEnumerableType, INamedTypeSymbol?iListType, INamedTypeSymbol?gListType) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; // FxCop compat: only fire on externally visible types by default. if (!namedTypeSymbol.MatchesConfiguredVisibility(context.Options, Rule, context.CancellationToken)) { return; } var allInterfacesStatus = default(CollectionsInterfaceStatus); foreach (var @interface in namedTypeSymbol.AllInterfaces) { var originalDefinition = @interface.OriginalDefinition; if (originalDefinition.Equals(iCollectionType)) { allInterfacesStatus.ICollectionPresent = true; } else if (originalDefinition.Equals(iEnumerableType)) { allInterfacesStatus.IEnumerablePresent = true; } else if (originalDefinition.Equals(iListType)) { allInterfacesStatus.IListPresent = true; } else if (originalDefinition.Equals(gCollectionType)) { allInterfacesStatus.GenericICollectionPresent = true; } else if (originalDefinition.Equals(gEnumerableType)) { allInterfacesStatus.GenericIEnumerablePresent = true; } else if (originalDefinition.Equals(gListType)) { allInterfacesStatus.GenericIListPresent = true; } } INamedTypeSymbol?missingInterface; INamedTypeSymbol?implementedInterface; if (allInterfacesStatus.GenericIListPresent) { // Implemented IList<T>, meaning has all 3 generic interfaces. Nothing can be wrong. return; } else if (allInterfacesStatus.IListPresent) { // Implemented IList but not IList<T>. missingInterface = gListType; implementedInterface = iListType; } else if (allInterfacesStatus.GenericICollectionPresent) { // Implemented ICollection<T>, and doesn't have an inherit of IList. Nothing can be wrong return; } else if (allInterfacesStatus.ICollectionPresent) { // Implemented ICollection but not ICollection<T> missingInterface = gCollectionType; implementedInterface = iCollectionType; } else if (allInterfacesStatus.GenericIEnumerablePresent) { // Implemented IEnumerable<T>, and doesn't have an inherit of ICollection. Nothing can be wrong return; } else if (allInterfacesStatus.IEnumerablePresent) { // Implemented IEnumerable, but not IEnumerable<T> missingInterface = gEnumerableType; implementedInterface = iEnumerableType; } else { // No collections implementation, nothing can be wrong. return; } RoslynDebug.Assert(missingInterface != null && implementedInterface != null); context.ReportDiagnostic(Diagnostic.Create(Rule, namedTypeSymbol.Locations.First(), namedTypeSymbol.Name, implementedInterface.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), missingInterface.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat))); }
/// <summary> /// Zero or more named arguments that specify values for fields and properties of the attribute. /// </summary> public ImmutableArray <Cci.IMetadataNamedArgument> GetNamedArguments(EmitContext context) { // Perform fixup Cci.ITypeReference stringType = context.Module.GetPlatformType( Cci.PlatformType.SystemString, context ); #if DEBUG // Must have exactly 1 named argument. var namedArgs = _sourceAttribute.GetNamedArguments(context); Debug.Assert(namedArgs.Length == 1); // Named argument must be 'File' property of string type var fileArg = namedArgs.First(); Debug.Assert(fileArg.ArgumentName == FilePropertyName); Debug.Assert( context.Module.IsPlatformType(fileArg.Type, Cci.PlatformType.SystemString) ); // Named argument value must be a non-empty string Debug.Assert(fileArg.ArgumentValue is MetadataConstant); var fileName = (string?)((MetadataConstant)fileArg.ArgumentValue).Value; Debug.Assert(!String.IsNullOrEmpty(fileName)); // PermissionSetAttribute type must have a writable public string type property member 'Hex' ISymbol iSymbol = _sourceAttribute.GetType(context).GetInternalSymbol() !.GetISymbol(); Debug.Assert( ((INamedTypeSymbol)iSymbol) .GetMembers(HexPropertyName) .Any( member => member.Kind == SymbolKind.Property && ((IPropertySymbol)member).Type.SpecialType == SpecialType.System_String ) ); #endif string hexFileContent; // Read the file contents at the resolved file path into a byte array. // May throw PermissionSetFileReadException, which is handled in Compilation.Emit. var resolver = context.Module.CommonCompilation.Options.XmlReferenceResolver; // If the resolver isn't available we won't get here since we had to use it to resolve the path. RoslynDebug.Assert(resolver != null); try { using (Stream stream = resolver.OpenReadChecked(_resolvedPermissionSetFilePath)) { // Convert the byte array contents into a string in hexadecimal format. hexFileContent = ConvertToHex(stream); } } catch (IOException e) { throw new PermissionSetFileReadException(e.Message, _resolvedPermissionSetFilePath); } // Synthesize a named attribute argument "Hex = hexFileContent". return(ImmutableArray.Create <Cci.IMetadataNamedArgument>( new HexPropertyMetadataNamedArgument( stringType, new MetadataConstant(stringType, hexFileContent) ) )); }
private static bool TryGetReleaseTrackingData( ImmutableArray <AdditionalText> additionalTexts, CancellationToken cancellationToken, [NotNullWhen(returnValue: true)] out ReleaseTrackingData?shippedData, [NotNullWhen(returnValue: true)] out ReleaseTrackingData?unshippedData, out List <Diagnostic>?invalidFileDiagnostics) { if (!TryGetReleaseTrackingFiles(additionalTexts, cancellationToken, out var shippedText, out var unshippedText)) { // TODO: Report a diagnostic that both must be specified if either shippedText or unshippedText is non-null. shippedData = shippedText != null ? ReleaseTrackingData.Default : null; unshippedData = unshippedText != null ? ReleaseTrackingData.Default : null; invalidFileDiagnostics = null; return(false); } var diagnostics = new List <Diagnostic>(); using var reportedInvalidLines = PooledHashSet <TextLine> .GetInstance(); shippedData = ReadReleaseTrackingData(shippedText.Path, shippedText.GetText(cancellationToken), OnDuplicateEntryInRelease, OnInvalidEntry, isShippedFile: true); unshippedData = ReadReleaseTrackingData(unshippedText.Path, unshippedText.GetText(cancellationToken), OnDuplicateEntryInRelease, OnInvalidEntry, isShippedFile: false); invalidFileDiagnostics = diagnostics; return(invalidFileDiagnostics.Count == 0); // Local functions. void OnDuplicateEntryInRelease(string ruleId, Version currentVersion, string path, SourceText sourceText, TextLine line) { if (!reportedInvalidLines.Add(line)) { // Already reported. return; } RoslynDebug.Assert(diagnostics != null); // Rule '{0}' has more then one entry for release '{1}' in analyzer release file '{2}'. string arg1 = ruleId; string arg2 = currentVersion == UnshippedVersion ? "unshipped" : currentVersion.ToString(); string arg3 = Path.GetFileName(path); LinePositionSpan linePositionSpan = sourceText.Lines.GetLinePositionSpan(line.Span); Location location = Location.Create(path, line.Span, linePositionSpan); var diagnostic = Diagnostic.Create(RemoveDuplicateEntriesForAnalyzerReleaseRule, location, arg1, arg2, arg3); diagnostics.Add(diagnostic); } void OnInvalidEntry(TextLine line, InvalidEntryKind invalidEntryKind, string path, SourceText sourceText) { RoslynDebug.Assert(diagnostics != null); RoslynDebug.Assert(reportedInvalidLines != null); if (!reportedInvalidLines.Add(line)) { // Already reported. return; } var rule = invalidEntryKind switch { // Analyzer release file '{0}' has a missing or invalid release header '{1}'. InvalidEntryKind.Header => InvalidHeaderInAnalyzerReleasesFileRule, // Analyzer release file '{0}' has an entry with one or more 'Undetected' fields that need to be manually filled in '{1}'. InvalidEntryKind.UndetectedField => InvalidUndetectedEntryInAnalyzerReleasesFileRule, // Analyzer release file '{0}' has an invalid entry '{1}'. InvalidEntryKind.Other => InvalidEntryInAnalyzerReleasesFileRule, _ => throw new NotImplementedException(), }; string arg1 = Path.GetFileName(path); string arg2 = line.ToString(); LinePositionSpan linePositionSpan = sourceText.Lines.GetLinePositionSpan(line.Span); Location location = Location.Create(path, line.Span, linePositionSpan); var diagnostic = Diagnostic.Create(rule, location, arg1, arg2); diagnostics.Add(diagnostic); } }
protected void AdjustFlagsAndWidth(GreenNode node) { RoslynDebug.Assert(node != null, "PERF: caller must ensure that node!=null, we do not want to re-check that here."); this.flags |= (node.flags & NodeFlags.InheritMask); _fullWidth += node._fullWidth; }
private FloatingValueSet(IValueSet <TFloating> numbers, bool hasNaN) { RoslynDebug.Assert(numbers is NumericValueSet <TFloating, TFloatingTC>); (_numbers, _hasNaN) = (numbers, hasNaN); }
public WrappedEventSymbol(EventSymbol underlyingEvent) { RoslynDebug.Assert((object)underlyingEvent != null); _underlyingEvent = underlyingEvent; }
public bool TryCreateForTupleElements(ITupleOperation tupleOperation, [NotNullWhen(returnValue: true)] out ImmutableArray <AnalysisEntity> elementEntities) { if (_tupleElementEntitiesMap.TryGetValue(tupleOperation, out elementEntities)) { return(!elementEntities.IsDefault); } try { elementEntities = default; if (tupleOperation.Type?.IsTupleType != true || _getPointsToAbstractValueOpt == null) { return(false); } var tupleType = (INamedTypeSymbol)tupleOperation.Type; if (tupleType.TupleElements.IsDefault) { return(false); } PointsToAbstractValue instanceLocation = _getPointsToAbstractValueOpt(tupleOperation); var underlyingValueTupleType = tupleType.GetUnderlyingValueTupleTypeOrThis(); AnalysisEntity?parentEntity = null; if (tupleOperation.TryGetParentTupleOperation(out var parentTupleOperationOpt, out var elementOfParentTupleContainingTuple) && TryCreateForTupleElements(parentTupleOperationOpt, out var parentTupleElementEntities)) { Debug.Assert(parentTupleOperationOpt.Elements.Length == parentTupleElementEntities.Length); for (int i = 0; i < parentTupleOperationOpt.Elements.Length; i++) { if (parentTupleOperationOpt.Elements[i] == elementOfParentTupleContainingTuple) { parentEntity = parentTupleElementEntities[i]; instanceLocation = parentEntity.InstanceLocation; break; } } RoslynDebug.Assert(parentEntity != null); } else { parentEntity = AnalysisEntity.Create(underlyingValueTupleType, ImmutableArray <AbstractIndex> .Empty, underlyingValueTupleType, instanceLocation, parentOpt: null); } Debug.Assert(parentEntity.InstanceLocation == instanceLocation); var builder = ArrayBuilder <AnalysisEntity> .GetInstance(tupleType.TupleElements.Length); foreach (var field in tupleType.TupleElements) { var tupleFieldName = field.CorrespondingTupleField.Name; var mappedValueTupleField = underlyingValueTupleType.GetMembers(tupleFieldName).OfType <IFieldSymbol>().FirstOrDefault(); if (mappedValueTupleField == null) { builder.Free(); return(false); } builder.Add(AnalysisEntity.Create(mappedValueTupleField, indices: ImmutableArray <AbstractIndex> .Empty, type: mappedValueTupleField.Type, instanceLocation, parentEntity)); } elementEntities = builder.ToImmutableAndFree(); return(true); }
private static void UpdateLocation( SemanticModel semanticModel, INamedTypeSymbol interfaceType, SyntaxEditor editor, ISyntaxFactsService syntaxFacts, Location location, CancellationToken cancellationToken) { var identifierName = location.FindNode(getInnermostNodeForTie: true, cancellationToken); if (identifierName == null || !syntaxFacts.IsIdentifierName(identifierName)) { return; } var node = syntaxFacts.IsNameOfMemberAccessExpression(identifierName) || syntaxFacts.IsMemberBindingExpression(identifierName.Parent) ? identifierName.Parent : identifierName; RoslynDebug.Assert(node is object); if (syntaxFacts.IsInvocationExpression(node.Parent)) { node = node.Parent; } var operation = semanticModel.GetOperation(node, cancellationToken); var instance = operation switch { IMemberReferenceOperation memberReference => memberReference.Instance, IInvocationOperation invocation => invocation.Instance, _ => null, }; if (instance == null) { return; } if (instance.IsImplicit) { if (instance is IInstanceReferenceOperation instanceReference && instanceReference.ReferenceKind != InstanceReferenceKind.ContainingTypeInstance) { return; } // Accessing the member not off of <dot>. i.e just plain `Goo()`. Replace with // ((IGoo)this).Goo(); var generator = editor.Generator; editor.ReplaceNode( identifierName, generator.MemberAccessExpression( generator.AddParentheses(generator.CastExpression(interfaceType, generator.ThisExpression())), identifierName.WithoutTrivia()).WithTriviaFrom(identifierName)); } else { // Accessing the member like `x.Goo()`. Replace with `((IGoo)x).Goo()` editor.ReplaceNode( instance.Syntax, (current, g) => g.AddParentheses( g.CastExpression(interfaceType, current.WithoutTrivia())).WithTriviaFrom(current)); } }
protected virtual bool FileExists(string fullPath) { RoslynDebug.Assert(fullPath != null); RoslynDebug.Assert(PathUtilities.IsAbsolute(fullPath)); return(File.Exists(fullPath)); }
internal ValidTargetsStringLocalizableErrorArgument(string[] targetResourceIds) { RoslynDebug.Assert(targetResourceIds != null); _targetResourceIds = targetResourceIds; }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { if (!compilationStartAnalysisContext.Compilation.TryGetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemSecurityAuthenticationSslProtocols, out INamedTypeSymbol? sslProtocolsSymbol)) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IFieldReferenceOperation fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; if (IsReferencingSslProtocols( fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardcodedOkayProtocol)) { if (isDeprecatedProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( DeprecatedRule, fieldReferenceOperation.Field.Name)); } else if (isHardcodedOkayProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( HardcodedRule, fieldReferenceOperation.Field.Name)); } } }, OperationKind.FieldReference); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IOperation?valueOperation; switch (operationAnalysisContext.Operation) { case IAssignmentOperation assignmentOperation: // Make sure this is an assignment operation for a SslProtocols value. if (!sslProtocolsSymbol.Equals(assignmentOperation.Target.Type)) { return; } valueOperation = assignmentOperation.Value; break; case IArgumentOperation argumentOperation: if (!sslProtocolsSymbol.Equals(argumentOperation.Type)) { return; } valueOperation = argumentOperation.Value; break; case IReturnOperation returnOperation: if (returnOperation.ReturnedValue == null || !sslProtocolsSymbol.Equals(returnOperation.ReturnedValue.Type)) { return; } valueOperation = returnOperation.ReturnedValue; break; case IVariableInitializerOperation variableInitializerOperation: if (variableInitializerOperation.Value == null || !sslProtocolsSymbol.Equals(variableInitializerOperation.Value.Type)) { return; } valueOperation = variableInitializerOperation.Value; break; default: Debug.Fail("Unhandled IOperation " + operationAnalysisContext.Operation.Kind); return; } // Find the topmost operation with a bad bit set, unless we find an operation that would've been // flagged by the FieldReference callback above. IOperation?foundDeprecatedOperation = null; bool foundDeprecatedReference = false; IOperation?foundHardcodedOperation = null; bool foundHardcodedReference = false; foreach (IOperation childOperation in valueOperation.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsReferencingSslProtocols( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardcodedOkayProtocol)) { if (isDeprecatedProtocol) { foundDeprecatedReference = true; } else if (isHardcodedOkayProtocol) { foundHardcodedReference = true; } if (foundDeprecatedReference && foundHardcodedReference) { return; } } if (childOperation.ConstantValue.HasValue && childOperation.ConstantValue.Value is int integerValue) { if (foundDeprecatedOperation == null && // Only want the first. (integerValue & UnsafeBits) != 0) { foundDeprecatedOperation = childOperation; } if (foundHardcodedOperation == null && // Only want the first. (integerValue & HardcodedBits) != 0) { foundHardcodedOperation = childOperation; } } } if (foundDeprecatedOperation != null && !foundDeprecatedReference) { operationAnalysisContext.ReportDiagnostic( foundDeprecatedOperation.CreateDiagnostic( DeprecatedRule, foundDeprecatedOperation.ConstantValue)); } if (foundHardcodedOperation != null && !foundHardcodedReference) { operationAnalysisContext.ReportDiagnostic( foundHardcodedOperation.CreateDiagnostic( HardcodedRule, foundHardcodedOperation.ConstantValue)); } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment, OperationKind.Argument, OperationKind.Return, OperationKind.VariableInitializer); return; // Local function(s). bool IsReferencingSslProtocols( IFieldReferenceOperation fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardcodedOkayProtocol) { RoslynDebug.Assert(sslProtocolsSymbol != null); if (sslProtocolsSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { if (HardcodedSslProtocolsMetadataNames.Contains(fieldReferenceOperation.Field.Name)) { isHardcodedOkayProtocol = true; isDeprecatedProtocol = false; } else if (fieldReferenceOperation.Field.Name == "None") { isHardcodedOkayProtocol = false; isDeprecatedProtocol = false; } else { isDeprecatedProtocol = true; isHardcodedOkayProtocol = false; } return(true); } else { isHardcodedOkayProtocol = false; isDeprecatedProtocol = false; return(false); } } }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemNetSecurityProtocolType, out var securityProtocolTypeTypeSymbol) || !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemNetServicePointManager, out var servicePointManagerTypeSymbol)) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; // Make sure we're not inside an &= assignment like: // ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11) // cuz &= is at worst, disabling protocol versions. if (IsReferencingSecurityProtocolType( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardCodedOkayProtocol) && null == fieldReferenceOperation.GetAncestor <ICompoundAssignmentOperation>( OperationKind.CompoundAssignment, IsAndEqualsServicePointManagerAssignment)) { if (isDeprecatedProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( DeprecatedRule, fieldReferenceOperation.Field.Name)); } else if (isHardCodedOkayProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( HardCodedRule, fieldReferenceOperation.Field.Name)); } } }, OperationKind.FieldReference); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var assignmentOperation = (IAssignmentOperation)operationAnalysisContext.Operation; // Make sure this is an assignment operation for a SecurityProtocolType, and not // an assignment like: // ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11) // cuz &= is at worst, disabling protocol versions. if (!securityProtocolTypeTypeSymbol.Equals(assignmentOperation.Target.Type) || (assignmentOperation is ICompoundAssignmentOperation compoundAssignmentOperation && IsAndEqualsServicePointManagerAssignment(compoundAssignmentOperation))) { return; } // Find the topmost operation with a bad bit set, unless we find an operation that would've been // flagged by the FieldReference callback above. IOperation?foundDeprecatedOperation = null; bool foundDeprecatedReference = false; IOperation?foundHardCodedOperation = null; bool foundHardCodedReference = false; foreach (IOperation childOperation in assignmentOperation.Value.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsReferencingSecurityProtocolType( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardCodedOkayProtocol)) { if (isDeprecatedProtocol) { foundDeprecatedReference = true; } else if (isHardCodedOkayProtocol) { foundHardCodedReference = true; } if (foundDeprecatedReference && foundHardCodedReference) { return; } } if (childOperation.ConstantValue.HasValue && childOperation.ConstantValue.Value is int integerValue) { if (foundDeprecatedOperation == null && // Only want the first. (integerValue & UnsafeBits) != 0) { foundDeprecatedOperation = childOperation; } if (foundHardCodedOperation == null && // Only want the first. (integerValue & HardCodedBits) != 0) { foundHardCodedOperation = childOperation; } } } if (foundDeprecatedOperation != null && !foundDeprecatedReference) { operationAnalysisContext.ReportDiagnostic( foundDeprecatedOperation.CreateDiagnostic( DeprecatedRule, foundDeprecatedOperation.ConstantValue)); } if (foundHardCodedOperation != null && !foundHardCodedReference) { operationAnalysisContext.ReportDiagnostic( foundHardCodedOperation.CreateDiagnostic( HardCodedRule, foundHardCodedOperation.ConstantValue)); } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment); return; // Local function(s). bool IsReferencingSecurityProtocolType( IFieldReferenceOperation fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardCodedOkayProtocol) { RoslynDebug.Assert(securityProtocolTypeTypeSymbol != null); if (securityProtocolTypeTypeSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { if (HardCodedSafeProtocolMetadataNames.Contains(fieldReferenceOperation.Field.Name)) { isHardCodedOkayProtocol = true; isDeprecatedProtocol = false; } else if (fieldReferenceOperation.Field.Name == SystemDefaultName) { isHardCodedOkayProtocol = false; isDeprecatedProtocol = false; } else { isDeprecatedProtocol = true; isHardCodedOkayProtocol = false; } return(true); } else { isHardCodedOkayProtocol = false; isDeprecatedProtocol = false; return(false); } } bool IsAndEqualsServicePointManagerAssignment(ICompoundAssignmentOperation compoundAssignmentOperation) { RoslynDebug.Assert(servicePointManagerTypeSymbol != null); return(compoundAssignmentOperation.OperatorKind == BinaryOperatorKind.And && compoundAssignmentOperation.Target is IPropertyReferenceOperation targetPropertyReference && targetPropertyReference.Instance == null && servicePointManagerTypeSymbol.Equals(targetPropertyReference.Property.ContainingType) && targetPropertyReference.Property.MetadataName == "SecurityProtocol"); } }); }
internal MetadataLocation(IModuleSymbolInternal module) { RoslynDebug.Assert(module != null); _module = module; }
internal CodeAnalysisResourcesLocalizableErrorArgument(string targetResourceId) { RoslynDebug.Assert(targetResourceId != null); _targetResourceId = targetResourceId; }
public ArrayTypeSymbol(Symbols.ArrayTypeSymbol underlying, CodeAnalysis.NullableAnnotation nullableAnnotation) : base(nullableAnnotation) { RoslynDebug.Assert(underlying is object); _underlying = underlying; }
/// <summary> /// Get local functions declared immediately in scope designated by the node. /// </summary> internal virtual ImmutableArray <LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode scopeDesignator) { RoslynDebug.Assert(Next is object); return(this.Next.GetDeclaredLocalFunctionsForScope(scopeDesignator)); }