public static SerializerTypeAnalyzer Create(WellKnownTypes wellKnownTypes) => new SerializerTypeAnalyzer( wellKnownTypes.CopierMethodAttribute, wellKnownTypes.SerializerMethodAttribute, wellKnownTypes.DeserializerMethodAttribute, wellKnownTypes.SerializerAttribute);
public SerializerGenerator(CodeGeneratorOptions options, WellKnownTypes wellKnownTypes) { this.options = options; this.wellKnownTypes = wellKnownTypes; }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { var iDisposable = WellKnownTypes.IDisposable(compilationContext.Compilation); if (iDisposable == null) { return; } var iCollection = WellKnownTypes.ICollection(compilationContext.Compilation); var genericICollection = WellKnownTypes.GenericICollection(compilationContext.Compilation); var disposeOwnershipTransferLikelyTypes = GetDisposeOwnershipTransferLikelyTypes(compilationContext.Compilation); compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { bool hasDisposableCreation = false; operationBlockStartContext.RegisterOperationAction(operationContext => { if (!hasDisposableCreation && operationContext.Operation.Type.IsDisposable(iDisposable)) { hasDisposableCreation = true; } }, OperationKind.ObjectCreation, OperationKind.TypeParameterObjectCreation, OperationKind.DynamicObjectCreation, OperationKind.Invocation); operationBlockStartContext.RegisterOperationBlockEndAction(operationBlockEndContext => { if (!hasDisposableCreation || !(operationBlockEndContext.OwningSymbol is IMethodSymbol containingMethod)) { return; } foreach (var operationRoot in operationBlockEndContext.OperationBlocks) { IBlockOperation topmostBlock = operationRoot.GetTopmostParentBlock(); if (topmostBlock != null) { var cfg = ControlFlowGraph.Create(topmostBlock); var nullAnalysisResult = NullAnalysis.GetOrComputeResult(cfg, containingMethod.ContainingType); var pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod.ContainingType, nullAnalysisResult); var disposeAnalysisResult = DisposeAnalysis.GetOrComputeResult(cfg, iDisposable, iCollection, genericICollection, disposeOwnershipTransferLikelyTypes, containingMethod.ContainingType, pointsToAnalysisResult, nullAnalysisResult); ImmutableDictionary <AbstractLocation, DisposeAbstractValue> disposeDataAtExit = disposeAnalysisResult[cfg.Exit].InputData; foreach (var kvp in disposeDataAtExit) { AbstractLocation location = kvp.Key; DisposeAbstractValue disposeValue = kvp.Value; if (disposeValue.Kind == DisposeAbstractValueKind.NotDisposed || ((disposeValue.Kind == DisposeAbstractValueKind.Disposed || disposeValue.Kind == DisposeAbstractValueKind.MaybeDisposed) && disposeValue.DisposingOperations.Count > 0 && disposeValue.DisposingOperations.All(d => d.IsInsideCatchClause()))) { Debug.Assert(location.CreationOpt != null); // CA2000: In method '{0}', call System.IDisposable.Dispose on object created by '{1}' before all references to it are out of scope. var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = location.CreationOpt.Syntax.ToString(); var diagnostic = location.CreationOpt.Syntax.CreateDiagnostic(Rule, arg1, arg2); operationBlockEndContext.ReportDiagnostic(diagnostic); } } break; } } }); }); }); }
public override void Initialize(AnalysisContext context) { // TODO: Consider making this analyzer thread-safe. //context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationStartContext => { INamedTypeSymbol eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') INamedTypeSymbol onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol obsoleteAttribute = WellKnownTypes.ObsoleteAttribute(compilationStartContext.Compilation); ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore = ImmutableHashSet.Create( conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute, obsoleteAttribute); ImmutableHashSet <INamedTypeSymbol> exceptionsToSkip = ImmutableHashSet.Create( WellKnownTypes.NotImplementedException(compilationStartContext.Compilation), WellKnownTypes.NotSupportedException(compilationStartContext.Compilation)); UnusedParameterDictionary unusedMethodParameters = new ConcurrentDictionary <IMethodSymbol, ISet <IParameterSymbol> >(); ISet <IMethodSymbol> methodsUsedAsDelegates = new HashSet <IMethodSymbol>(); // Create a list of functions to exclude from analysis. We assume that any function that is used in an IMethodBindingExpression // cannot have its signature changed, and add it to the list of methods to be excluded from analysis. compilationStartContext.RegisterOperationAction(operationContext => { var methodBinding = (IMethodReferenceOperation)operationContext.Operation; methodsUsedAsDelegates.Add(methodBinding.Method.OriginalDefinition); }, OperationKind.MethodReference); compilationStartContext.RegisterOperationBlockStartAction(startOperationBlockContext => { // We only care about methods. if (startOperationBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. var method = (IMethodSymbol)startOperationBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, extern methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsExtern || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMember() || method.IsFinalizer()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (eventsArgSymbol != null && method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && method.Parameters[1].Type.Inherits(eventsArgSymbol)) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Ignore methods that were used as delegates if (methodsUsedAsDelegates.Contains(method)) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method, unusedMethodParameters, exceptionsToSkip); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationAction(analyzer.AnalyzeOperation, OperationKind.ParameterReference); // Register an end action to add unused parameters to the unusedMethodParameters dictionary startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }); // Register a compilation end action to filter all methods used as delegates and report any diagnostics compilationStartContext.RegisterCompilationEndAction(compilationAnalysisContext => { // Report diagnostics for unused parameters. var unusedParameters = unusedMethodParameters.Where(kvp => !methodsUsedAsDelegates.Contains(kvp.Key)).SelectMany(kvp => kvp.Value); foreach (var parameter in unusedParameters) { var diagnostic = Diagnostic.Create(Rule, parameter.Locations[0], parameter.Name, parameter.ContainingSymbol.Name); compilationAnalysisContext.ReportDiagnostic(diagnostic); } }); }); }
internal NamedTypeSymbol GetWellKnownType(WellKnownType type) { return(this.GetTypeByMetadataName(WellKnownTypes.GetMetadataName(type))); }
internal static bool IsOrleansShallowCopyable(WellKnownTypes wellKnownTypes, ITypeSymbol type) { var root = new HashSet <ITypeSymbol>(); return(IsOrleansShallowCopyable(wellKnownTypes, type, root)); }
public sealed 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 compilation = compilationStartAnalysisContext.Compilation; var serializableAttributeTypeSymbol = WellKnownTypes.SerializableAttribute(compilation); if (serializableAttributeTypeSymbol == null) { return; } var nonSerializedAttribute = WellKnownTypes.NonSerializedAttribute(compilation); var visitedType = new ConcurrentDictionary <ITypeSymbol, bool>(); var pointerFields = new ConcurrentDictionary <IFieldSymbol, bool>(); compilationStartAnalysisContext.RegisterSymbolAction( (SymbolAnalysisContext symbolAnalysisContext) => { LookForSerializationWithPointerFields((ITypeSymbol)symbolAnalysisContext.Symbol, null); }, SymbolKind.NamedType); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { foreach (var pointerField in pointerFields.Keys) { var associatedSymbol = pointerField.AssociatedSymbol; compilationAnalysisContext.ReportDiagnostic( pointerField.CreateDiagnostic( Rule, associatedSymbol == null ? pointerField.Name : associatedSymbol.Name)); } }); // Look for serialization of a type with valid pointer fields directly and indirectly. // // typeSymbol: The symbol of the type to be analyzed // relatedFieldSymbol: When relatedFieldSymbol is null, traverse all descendants of typeSymbol to // find pointer fields; otherwise, traverse to find if relatedFieldSymbol is a pointer field void LookForSerializationWithPointerFields(ITypeSymbol typeSymbol, IFieldSymbol relatedFieldSymbol) { if (typeSymbol is IPointerTypeSymbol pointerTypeSymbol) { // If the field is a valid pointer. if (pointerTypeSymbol.PointedAtType.TypeKind == TypeKind.Struct || pointerTypeSymbol.PointedAtType.TypeKind == TypeKind.Pointer) { pointerFields.TryAdd(relatedFieldSymbol, true); } } else if (typeSymbol is INamedTypeSymbol namedTypeSymbol) { // If it is defined in source and not visited, // mark it as visited and analyze all fields of it. if (namedTypeSymbol.IsInSource() && namedTypeSymbol.HasAttribute(serializableAttributeTypeSymbol) && visitedType.TryAdd(namedTypeSymbol, true)) { // Get all the fields can be serialized. var fields = namedTypeSymbol.GetMembers().OfType <IFieldSymbol>().Where(s => (nonSerializedAttribute == null || !s.HasAttribute(nonSerializedAttribute)) && !s.IsStatic); foreach (var field in fields) { LookForSerializationWithPointerFields(field.Type, field); } } // If it is a generic type, analyze all type arguments of it. if (namedTypeSymbol.IsGenericType) { foreach (var arg in namedTypeSymbol.TypeArguments) { LookForSerializationWithPointerFields(arg, relatedFieldSymbol); } } } else if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol) { LookForSerializationWithPointerFields(arrayTypeSymbol.ElementType, relatedFieldSymbol); } } }); }
public void Execute(GeneratorExecutionContext context) { var cancellationToken = context.CancellationToken; var compilation = context.Compilation; Action <Diagnostic> reportDiagnostic = context.ReportDiagnostic; if (!WellKnownTypes.TryCreate(compilation, reportDiagnostic, out var wellKnownTypes)) { return; } var registrationCalculator = new RegistrationCalculator(compilation, wellKnownTypes, reportDiagnostic, cancellationToken); foreach (var syntaxTree in context.Compilation.SyntaxTrees) { cancellationToken.ThrowIfCancellationRequested(); var semanticModel = context.Compilation.GetSemanticModel(syntaxTree); var modules = syntaxTree.GetRoot(cancellationToken).DescendantNodesAndSelf().OfType <ClassDeclarationSyntax>() .Select(x => semanticModel.GetDeclaredSymbol(x, cancellationToken)) .OfType <INamedTypeSymbol>() .Select(x => { var isContainer = x.AllInterfaces.Any(x => x.OriginalDefinition.Equals(wellKnownTypes.IContainer, SymbolEqualityComparer.Default) || x.OriginalDefinition.Equals(wellKnownTypes.IAsyncContainer, SymbolEqualityComparer.Default)); return(type: x, isContainer); }) .Where(x => x.isContainer || x.type.GetAttributes().Any(x => x.AttributeClass is { } attribute&& (attribute.Equals(wellKnownTypes.RegisterAttribute, SymbolEqualityComparer.Default) || attribute.Equals(wellKnownTypes.RegisterModuleAttribute, SymbolEqualityComparer.Default) || attribute.Equals(wellKnownTypes.RegisterFactoryAttribute, SymbolEqualityComparer.Default) || attribute.Equals(wellKnownTypes.RegisterDecoratorAttribute, SymbolEqualityComparer.Default))) || x.type.GetMembers().Any(x => x.GetAttributes().Any(x => x.AttributeClass is { } attribute&& (attribute.Equals(wellKnownTypes.FactoryAttribute, SymbolEqualityComparer.Default) || attribute.Equals(wellKnownTypes.InstanceAttribute, SymbolEqualityComparer.Default) || attribute.Equals(wellKnownTypes.DecoratorFactoryAttribute, SymbolEqualityComparer.Default) || attribute.Equals(wellKnownTypes.FactoryOfAttribute, SymbolEqualityComparer.Default))))); foreach (var module in modules) { if (!module.type.IsInternal() && !module.type.IsPublic()) { reportDiagnostic(ModuleNotPublicOrInternal( module.type, ((TypeDeclarationSyntax)module.type.DeclaringSyntaxReferences[0].GetSyntax()).Identifier.GetLocation())); } cancellationToken.ThrowIfCancellationRequested(); if (module.isContainer) { var file = ContainerGenerator.GenerateContainerImplementations( module.type, registrationCalculator.GetContainerRegistrations(module.type), wellKnownTypes, reportDiagnostic, cancellationToken); var source = CSharpSyntaxTree.ParseText(SourceText.From(file, Encoding.UTF8)).GetRoot().NormalizeWhitespace().SyntaxTree.GetText(); context.AddSource( GenerateNameHint(module.type), source); } else { registrationCalculator.ValidateModuleRegistrations(module.type); } } } }
public GrainReferenceGenerator(CodeGeneratorOptions options, WellKnownTypes wellKnownTypes) { this.options = options; this.wellKnownTypes = wellKnownTypes; }
public sealed 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 compilation = compilationStartAnalysisContext.Compilation; var serializableAttributeTypeSymbol = WellKnownTypes.SerializableAttribute(compilation); if (serializableAttributeTypeSymbol == null) { return; } var nonSerializedAttribute = WellKnownTypes.NonSerializedAttribute(compilation); if (nonSerializedAttribute == null) { return; } var forwardGraph = new ConcurrentDictionary <ISymbol, ConcurrentDictionary <ISymbol, bool> >(); var invertedGraph = new ConcurrentDictionary <ISymbol, ConcurrentDictionary <ISymbol, bool> >(); // It keeps the out Degree of every vertex in the invertedGraph, which is corresponding to the in Degree of the vertex in forwardGraph. var inDegree = new ConcurrentDictionary <ISymbol, int>(); // It Keeps the out degree of every vertex in the forwardGraph, which is corresponding to the in Degree of the vertex in invertedGraph. var outDegree = new ConcurrentDictionary <ISymbol, int>(); compilationStartAnalysisContext.RegisterSymbolAction( (SymbolAnalysisContext symbolAnalysisContext) => { DrawGraph(symbolAnalysisContext.Symbol as ITypeSymbol); }, SymbolKind.NamedType); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { ModifyDegree(inDegree, forwardGraph); ModifyDegree(outDegree, invertedGraph); // If the degree of a vertex is greater than 0 both in the forward graph and inverted graph after topological sorting, // the vertex must belong to a loop. var leftVertices = inDegree.Where(s => s.Value > 0).Select(s => s.Key).ToImmutableHashSet(); var invertedLeftVertices = outDegree.Where(s => s.Value > 0).Select(s => s.Key).ToImmutableHashSet(); var verticesInLoop = leftVertices.Intersect(invertedLeftVertices); foreach (var vertex in verticesInLoop) { if (vertex is IFieldSymbol fieldInLoop) { var associatedSymbol = fieldInLoop.AssociatedSymbol; compilationAnalysisContext.ReportDiagnostic( fieldInLoop.CreateDiagnostic( Rule, associatedSymbol == null ? vertex.Name : associatedSymbol.Name)); } } }); // Traverse from point to its descendants, save the information into a directed graph. // // point: The initial point void DrawGraph(ITypeSymbol point) { // If the point has been visited, return; // otherwise, add it to the graph and mark it as visited. if (!AddPointToBothGraphs(point)) { return; } foreach (var associatedTypePoint in GetAssociatedTypes(point)) { if (associatedTypePoint == null || associatedTypePoint.Equals(point)) { continue; } AddLineToBothGraphs(point, associatedTypePoint); DrawGraph(associatedTypePoint); } if (point.IsInSource() && point.HasAttribute(serializableAttributeTypeSymbol)) { var fieldPoints = point.GetMembers().OfType <IFieldSymbol>().Where(s => !s.HasAttribute(nonSerializedAttribute) && !s.IsStatic); foreach (var fieldPoint in fieldPoints) { var fieldTypePoint = fieldPoint.Type; AddLineToBothGraphs(point, fieldPoint); AddLineToBothGraphs(fieldPoint, fieldTypePoint); DrawGraph(fieldTypePoint); } } } static HashSet <ITypeSymbol> GetAssociatedTypes(ITypeSymbol type) { var result = new HashSet <ITypeSymbol>(); if (type is INamedTypeSymbol namedTypeSymbol) { // 1. Type arguments of generic type. if (namedTypeSymbol.IsGenericType) { foreach (var arg in namedTypeSymbol.TypeArguments) { result.Add(arg); } } // 2. The type it constructed from. var constructedFrom = namedTypeSymbol.ConstructedFrom; result.Add(constructedFrom); } else if (type is IArrayTypeSymbol arrayTypeSymbol) { // 3. Element type of the array. result.Add(arrayTypeSymbol.ElementType); } // 4. Base type. result.Add(type.BaseType); return(result); } // Add a line to the graph. // // from: The start point of the line // to: The end point of the line // degree: The out degree of all vertices in the graph // graph: The graph void AddLine(ISymbol from, ISymbol to, ConcurrentDictionary <ISymbol, int> degree, ConcurrentDictionary <ISymbol, ConcurrentDictionary <ISymbol, bool> > graph) { graph.AddOrUpdate(from, new ConcurrentDictionary <ISymbol, bool> { [to] = true }, (k, v) => { v[to] = true; return(v); }); degree.AddOrUpdate(from, 1, (k, v) => v + 1); }
private static async Task <Document> AddSerializableAttribute(Document document, SyntaxNode node, CancellationToken cancellationToken) { DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); SyntaxNode attr = editor.Generator.Attribute(editor.Generator.TypeExpression(WellKnownTypes.SerializableAttribute(editor.SemanticModel.Compilation))); editor.AddAttribute(node, attr); return(editor.GetChangedDocument()); }
public override void Initialize(AnalysisContext analysisContext) { // TODO: Make analyzer thread safe //analysisContext.EnableConcurrentExecution(); // We need to analyze generated code, but don't intend to report diagnostics for generated code fields. analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze); analysisContext.RegisterCompilationStartAction( (compilationContext) => { HashSet <IFieldSymbol> unreferencedPrivateFields = new HashSet <IFieldSymbol>(); HashSet <IFieldSymbol> referencedPrivateFields = new HashSet <IFieldSymbol>(); ImmutableHashSet <INamedTypeSymbol> specialAttributes = GetSpecialAttributes(compilationContext.Compilation); var structLayoutAttribute = WellKnownTypes.StructLayoutAttribute(compilationContext.Compilation); compilationContext.RegisterSymbolAction( (symbolContext) => { IFieldSymbol field = (IFieldSymbol)symbolContext.Symbol; // Fields of types marked with StructLayoutAttribute with LayoutKind.Sequential should never be flagged as unused as their removal can change the runtime behavior. if (structLayoutAttribute != null && field.ContainingType != null) { foreach (var attribute in field.ContainingType.GetAttributes()) { if (structLayoutAttribute.Equals(attribute.AttributeClass.OriginalDefinition) && attribute.ConstructorArguments.Length == 1) { var argument = attribute.ConstructorArguments[0]; if (argument.Type != null) { SpecialType specialType = argument.Type.TypeKind == TypeKind.Enum ? ((INamedTypeSymbol)argument.Type).EnumUnderlyingType.SpecialType : argument.Type.SpecialType; if (DiagnosticHelpers.TryConvertToUInt64(argument.Value, specialType, out ulong convertedLayoutKindValue) && convertedLayoutKindValue == (ulong)System.Runtime.InteropServices.LayoutKind.Sequential) { return; } } } } } if (field.DeclaredAccessibility == Accessibility.Private && !referencedPrivateFields.Contains(field)) { // Fields with certain special attributes should never be considered unused. if (!specialAttributes.IsEmpty) { foreach (var attribute in field.GetAttributes()) { if (specialAttributes.Contains(attribute.AttributeClass.OriginalDefinition)) { return; } } } unreferencedPrivateFields.Add(field); } }, SymbolKind.Field); compilationContext.RegisterOperationAction( (operationContext) => { IFieldSymbol field = ((IFieldReferenceOperation)operationContext.Operation).Field; if (field.DeclaredAccessibility == Accessibility.Private) { referencedPrivateFields.Add(field); unreferencedPrivateFields.Remove(field); } }, OperationKind.FieldReference); compilationContext.RegisterCompilationEndAction( (compilationEndContext) => { foreach (IFieldSymbol unreferencedPrivateField in unreferencedPrivateFields) { compilationEndContext.ReportDiagnostic(Diagnostic.Create(Rule, unreferencedPrivateField.Locations[0], unreferencedPrivateField.Name)); } }); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol localizableStateAttributeSymbol = WellKnownTypes.LocalizableAttribute(compilationContext.Compilation); INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation); INamedTypeSymbol systemConsoleSymbol = WellKnownTypes.Console(compilationContext.Compilation); ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation); compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod)) { return; } var lazyValueContentResult = new Lazy <DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> >( valueFactory: ComputeValueContentAnalysisResult, isThreadSafe: false); operationBlockStartContext.RegisterOperationAction(operationContext => { var argument = (IArgumentOperation)operationContext.Operation; switch (argument.Parent?.Kind) { case OperationKind.Invocation: case OperationKind.ObjectCreation: AnalyzeArgument(argument.Parameter, containingPropertySymbolOpt: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic); return; } }, OperationKind.Argument); operationBlockStartContext.RegisterOperationAction(operationContext => { var propertyReference = (IPropertyReferenceOperation)operationContext.Operation; if (propertyReference.Parent is IAssignmentOperation assignment && assignment.Target == propertyReference && !propertyReference.Property.IsIndexer && propertyReference.Property.SetMethod?.Parameters.Length == 1) { IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0]; AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic); } }, OperationKind.PropertyReference); void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol containingPropertySymbolOpt, IOperation operation, Action <Diagnostic> reportDiagnostic) { if (ShouldBeLocalized(parameter, containingPropertySymbolOpt, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore)) { ValueContentAbstractValue stringContentValue = lazyValueContentResult.Value[operation.Kind, operation.Syntax]; if (stringContentValue.IsLiteralState) { Debug.Assert(stringContentValue.LiteralValues.Count > 0); if (stringContentValue.LiteralValues.Any(l => !(l is string))) { return; } var stringLiteralValues = stringContentValue.LiteralValues.Select(l => (string)l); // FxCop compat: Do not fire if the literal value came from a default parameter value if (stringContentValue.LiteralValues.Count == 1 && parameter.IsOptional && parameter.ExplicitDefaultValue is string defaultValue && defaultValue == stringLiteralValues.Single()) { return; } // FxCop compat: Do not fire if none of the string literals have any non-control character. if (!LiteralValuesHaveNonControlCharacters(stringLiteralValues)) { return; } // FxCop compat: Filter out xml string literals. var filteredStrings = stringLiteralValues.Where(literal => !LooksLikeXmlTag(literal)); if (filteredStrings.Any()) { // Method '{0}' passes a literal string as parameter '{1}' of a call to '{2}'. Retrieve the following string(s) from a resource table instead: "{3}". var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = parameter.Name; var arg3 = parameter.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg4 = FormatLiteralValues(filteredStrings); var diagnostic = operation.CreateDiagnostic(Rule, arg1, arg2, arg3, arg4); reportDiagnostic(diagnostic); } } } } DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> ComputeValueContentAnalysisResult() { foreach (var operationRoot in operationBlockStartContext.OperationBlocks) { IBlockOperation topmostBlock = operationRoot.GetTopmostParentBlock(); if (topmostBlock != null) { var cfg = topmostBlock.GetEnclosingControlFlowGraph(); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation); return(ValueContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, operationBlockStartContext.Options, Rule, operationBlockStartContext.CancellationToken)); } } return(null); } }); }); }
internal NamedTypeSymbol GetCallSiteDelegateType( TypeSymbol loweredReceiver, RefKind receiverRefKind, ImmutableArray <TypeSymbol> loweredArguments, ImmutableArray <RefKind> refKinds, TypeSymbol loweredRight, TypeSymbol resultType) { Debug.Assert(refKinds.IsDefaultOrEmpty || refKinds.Length == loweredArguments.Length); var callSiteType = this.CallSite; if (callSiteType.IsErrorType()) { return(null); } var delegateSignature = MakeCallSiteDelegateSignature(callSiteType, loweredReceiver, loweredArguments, loweredRight, resultType); bool returnsVoid = resultType.SpecialType == SpecialType.System_Void; bool hasByRefs = receiverRefKind != RefKind.None || !refKinds.IsDefaultOrEmpty; if (!hasByRefs) { var wkDelegateType = returnsVoid ? WellKnownTypes.GetWellKnownActionDelegate(invokeArgumentCount: delegateSignature.Length) : WellKnownTypes.GetWellKnownFunctionDelegate(invokeArgumentCount: delegateSignature.Length - 1); if (wkDelegateType != WellKnownType.Unknown) { var delegateType = _compilation.GetWellKnownType(wkDelegateType); if (delegateType != null && !delegateType.IsErrorType()) { return(delegateType.Construct(delegateSignature)); } } } BitVector byRefs; if (hasByRefs) { byRefs = BitVector.Create(1 + (loweredReceiver != null ? 1 : 0) + loweredArguments.Length + (loweredRight != null ? 1 : 0)); int j = 1; if (loweredReceiver != null) { byRefs[j++] = receiverRefKind != RefKind.None; } if (!refKinds.IsDefault) { for (int i = 0; i < refKinds.Length; i++, j++) { if (refKinds[i] != RefKind.None) { byRefs[j] = true; } } } } else { byRefs = default(BitVector); } int parameterCount = delegateSignature.Length - (returnsVoid ? 0 : 1); return(_compilation.AnonymousTypeManager.SynthesizeDelegate(parameterCount, byRefs, returnsVoid).Construct(delegateSignature)); }
/// <summary> /// Returns syntax for the deserializer method. /// </summary> private static MemberDeclarationSyntax GenerateDeserializerMethod(WellKnownTypes wellKnownTypes, INamedTypeSymbol type, List <FieldInfoMember> fields, SemanticModel model) { var contextParameter = IdentifierName("context"); var resultDeclaration = LocalDeclarationStatement( VariableDeclaration(type.ToTypeSyntax()) .AddVariables( VariableDeclarator("result") .WithInitializer(EqualsValueClause(GetObjectCreationExpressionSyntax(wellKnownTypes, type, model))))); var resultVariable = IdentifierName("result"); var body = new List <StatementSyntax> { resultDeclaration }; // Value types cannot be referenced, only copied, so there is no need to box & record instances of value types. if (!type.IsValueType) { // Record the result for cyclic deserialization. var currentSerializationContext = contextParameter; body.Add( ExpressionStatement( InvocationExpression(currentSerializationContext.Member("RecordObject")) .AddArgumentListArguments(Argument(resultVariable)))); } // Deserialize all fields. foreach (var field in fields) { var deserialized = InvocationExpression(contextParameter.Member("DeserializeInner")) .AddArgumentListArguments( Argument(TypeOfExpression(field.Type))); body.Add( ExpressionStatement( field.GetSetter( resultVariable, CastExpression(field.Type, deserialized)))); } // If the type implements the internal IOnDeserialized lifecycle method, invoke it's method now. if (type.HasInterface(wellKnownTypes.IOnDeserialized)) { // C#: ((IOnDeserialized)result).OnDeserialized(context); var typedResult = ParenthesizedExpression(CastExpression(wellKnownTypes.IOnDeserialized.ToTypeSyntax(), resultVariable)); var invokeOnDeserialized = InvocationExpression(typedResult.Member("OnDeserialized")) .AddArgumentListArguments(Argument(contextParameter)); body.Add(ExpressionStatement(invokeOnDeserialized)); } body.Add(ReturnStatement(CastExpression(type.ToTypeSyntax(), resultVariable))); return (MethodDeclaration(wellKnownTypes.Object.ToTypeSyntax(), "Deserializer") .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( Parameter(Identifier("expected")).WithType(wellKnownTypes.Type.ToTypeSyntax()), Parameter(Identifier("context")).WithType(wellKnownTypes.IDeserializationContext.ToTypeSyntax())) .AddBodyStatements(body.ToArray()) .AddAttributeLists( AttributeList() .AddAttributes(Attribute(wellKnownTypes.DeserializerMethodAttribute.ToNameSyntax())))); }
public CoreTypes(PhpCompilation compilation) { Contract.ThrowIfNull(compilation); _compilation = compilation; _table = new Dictionary <string, CoreType>(); Void = Create(SpecialType.System_Void); Object = Create(SpecialType.System_Object); Int32 = Create(SpecialType.System_Int32); Long = Create(SpecialType.System_Int64); Double = Create(SpecialType.System_Double); Boolean = Create(SpecialType.System_Boolean); String = Create(SpecialType.System_String); Exception = CreateFromFullName(WellKnownTypes.GetMetadataName(WellKnownType.System_Exception)); RuntimeTypeHandle = Create(SpecialType.System_RuntimeTypeHandle); RuntimeMethodHandle = Create(SpecialType.System_RuntimeMethodHandle); PhpNumber = Create("PhpNumber"); PhpAlias = Create("PhpAlias"); PhpValue = Create("PhpValue"); PhpString = Create("PhpString"); PhpArray = Create("PhpArray"); PhpResource = Create("PhpResource"); IPhpArray = Create("IPhpArray"); IPhpEnumerable = Create("IPhpEnumerable"); IPhpCallable = Create("IPhpCallable"); IPhpConvertible = Create("IPhpConvertible"); PhpString_Blob = Create("PhpString+Blob"); IntStringKey = Create("IntStringKey"); PhpHashtable = Create("PhpHashtable"); ScriptDiedException = Create("ScriptDiedException"); Context = Create("Context"); Operators = Create("Operators"); Comparison = Create("Comparison"); StrictComparison = Create("StrictComparison"); Convert = Create("Convert"); PhpException = Create("PhpException"); ScriptAttribute = Create("ScriptAttribute"); PhpTraitAttribute = Create(PhpTraitAttributeName); PhpTypeAttribute = Create("PhpTypeAttribute"); PhpHiddenAttribute = Create("PhpHiddenAttribute"); PhpFieldsOnlyCtorAttribute = Create(PhpFieldsOnlyCtorAttributeName); NotNullAttribute = Create("NotNullAttribute"); PhpMemberVisibilityAttribute = Create(PhpMemberVisibilityAttributeName); IStaticInit = Create("IStaticInit"); RoutineInfo = Create("Reflection.RoutineInfo"); stdClass = CreateFromFullName("stdClass"); ArrayAccess = CreateFromFullName("ArrayAccess"); Closure = CreateFromFullName("Closure"); BinderFactory = Create("Dynamic.BinderFactory"); GetClassConstBinder = Create("Dynamic.GetClassConstBinder"); GetFieldBinder = Create("Dynamic.GetFieldBinder"); SetFieldBinder = Create("Dynamic.SetFieldBinder"); AccessMask = CreateFromFullName("Pchp.CodeAnalysis.Semantics.AccessMask"); Dynamic_NameParam_T = Create("Dynamic.NameParam`1"); Dynamic_TargetTypeParam = Create("Dynamic.TargetTypeParam"); Dynamic_CallerTypeParam = Create("Dynamic.CallerTypeParam"); Dynamic_UnpackingParam_T = Create("Dynamic.UnpackingParam`1"); PhpTypeInfoExtension = Create("Reflection.PhpTypeInfoExtension"); PhpTypeInfo = Create("Reflection.PhpTypeInfo"); CommonPhpArrayKeys = Create("CommonPhpArrayKeys"); Iterator = CreateFromFullName("Iterator"); Generator = CreateFromFullName("Generator"); GeneratorStateMachineDelegate = CreateFromFullName("GeneratorStateMachineDelegate"); IntPtr = CreateFromFullName("System.IntPtr"); }
/// <summary> /// Returns a sorted list of the fields of the provided type. /// </summary> private static List <FieldInfoMember> GetFields(WellKnownTypes wellKnownTypes, SemanticModel model, INamedTypeSymbol type, ILogger logger) { var result = new List <FieldInfoMember>(); foreach (var field in type.GetDeclaredMembers <IFieldSymbol>()) { if (ShouldSerializeField(wellKnownTypes, field)) { result.Add(new FieldInfoMember(wellKnownTypes, model, type, field, result.Count)); } } if (type.TypeKind == TypeKind.Class) { // Some reference assemblies are compiled without private fields. // Warn the user if they are inheriting from a type in one of these assemblies using a heuristic: // If the type inherits from a type in a reference assembly and there are no fields declared on those // base types, emit a warning. var hasUnsupportedRefAsmBase = false; var referenceAssemblyHasFields = false; var baseType = type.BaseType; while (baseType != null && !baseType.Equals(wellKnownTypes.Object) && !baseType.Equals(wellKnownTypes.Attribute)) { if (!hasUnsupportedRefAsmBase && baseType.ContainingAssembly.HasAttribute("ReferenceAssemblyAttribute") && !IsSupportedRefAsmType(baseType)) { hasUnsupportedRefAsmBase = true; } foreach (var field in baseType.GetDeclaredMembers <IFieldSymbol>()) { if (hasUnsupportedRefAsmBase) { referenceAssemblyHasFields = true; } if (ShouldSerializeField(wellKnownTypes, field)) { result.Add(new FieldInfoMember(wellKnownTypes, model, type, field, result.Count)); } } baseType = baseType.BaseType; } if (hasUnsupportedRefAsmBase && !referenceAssemblyHasFields) { var fileLocation = string.Empty; var declaration = type.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() as ClassDeclarationSyntax; if (declaration != null) { var location = declaration.Identifier.GetLocation(); if (location.IsInSource) { var pos = location.GetLineSpan(); fileLocation = string.Format( "{0}({1},{2},{3},{4}): ", pos.Path, pos.StartLinePosition.Line + 1, pos.StartLinePosition.Character + 1, pos.EndLinePosition.Line + 1, pos.EndLinePosition.Character + 1); } } logger.LogWarning( $"{fileLocation}warning ORL1001: Type {type} has a base type which belongs to a reference assembly." + " Serializer generation for this type may not include important base type fields."); } bool IsSupportedRefAsmType(INamedTypeSymbol t) { INamedTypeSymbol baseDefinition; if (t.IsGenericType && !t.IsUnboundGenericType) { baseDefinition = t.ConstructUnboundGenericType().OriginalDefinition; } else { baseDefinition = t.OriginalDefinition; } foreach (var refAsmType in wellKnownTypes.SupportedRefAsmBaseTypes) { if (baseDefinition.Equals(refAsmType)) { return(true); } } return(false); } } result.Sort(FieldInfoMember.Comparer.Instance); return(result); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction( compilationStartAnalysisContext => { Compilation compilation = compilationStartAnalysisContext.Compilation; ImmutableHashSet <INamedTypeSymbol> nativeResourceTypes = ImmutableHashSet.Create( WellKnownTypes.IntPtr(compilation), WellKnownTypes.UIntPtr(compilation), WellKnownTypes.HandleRef(compilation) ); var disposableType = WellKnownTypes.IDisposable(compilation); compilationStartAnalysisContext.RegisterOperationAction( operationAnalysisContext => { var assignment = (IAssignmentOperation)operationAnalysisContext.Operation; IOperation target = assignment.Target; if (target == null) { // This can happen if the left-hand side is an undefined symbol. return; } if (target.Kind != OperationKind.FieldReference) { return; } var fieldReference = (IFieldReferenceOperation)target; var field = fieldReference.Member as IFieldSymbol; if (field == null || field.Kind != SymbolKind.Field || field.IsStatic) { return; } if (!nativeResourceTypes.Contains(field.Type)) { return; } INamedTypeSymbol containingType = field.ContainingType; if (containingType == null || containingType.IsValueType) { return; } if (!containingType.AllInterfaces.Contains(disposableType)) { return; } if (containingType.HasFinalizer()) { return; } if (assignment.Value == null || assignment.Value.Kind != OperationKind.Invocation) { return; } var invocation = (IInvocationOperation)assignment.Value; if (invocation == null) { return; } IMethodSymbol method = invocation.TargetMethod; // TODO: What about COM? if (method.GetDllImportData() == null) { return; } operationAnalysisContext.ReportDiagnostic(containingType.CreateDiagnostic(Rule)); }, OperationKind.SimpleAssignment); }); }
internal static bool IsOrleansShallowCopyable(WellKnownTypes wellKnownTypes, ITypeSymbol type, HashSet <ITypeSymbol> examining) { switch (type.SpecialType) { case SpecialType.System_Boolean: case SpecialType.System_Char: case SpecialType.System_SByte: case SpecialType.System_Byte: case SpecialType.System_Int16: case SpecialType.System_UInt16: case SpecialType.System_Int32: case SpecialType.System_UInt32: case SpecialType.System_Int64: case SpecialType.System_UInt64: case SpecialType.System_Decimal: case SpecialType.System_Single: case SpecialType.System_Double: case SpecialType.System_String: case SpecialType.System_DateTime: return(true); } if (wellKnownTypes.TimeSpan.Equals(type) || wellKnownTypes.IPAddress.Equals(type) || wellKnownTypes.IPEndPoint.Equals(type) || wellKnownTypes.SiloAddress.Equals(type) || wellKnownTypes.GrainId.Equals(type) || wellKnownTypes.ActivationId.Equals(type) || wellKnownTypes.ActivationAddress.Equals(type) || wellKnownTypes.CorrelationId is WellKnownTypes.Some correlationIdType && correlationIdType.Value.Equals(type) || wellKnownTypes.CancellationToken.Equals(type)) { return(true); } if (ShallowCopyableTypes.TryGetValue(type, out var result)) { return(result); } if (type.HasAttribute(wellKnownTypes.ImmutableAttribute)) { return(ShallowCopyableTypes[type] = true); } if (type.HasBaseType(wellKnownTypes.Exception)) { return(ShallowCopyableTypes[type] = true); } if (!(type is INamedTypeSymbol namedType)) { return(ShallowCopyableTypes[type] = false); } if (namedType.IsGenericType && wellKnownTypes.Immutable_1.Equals(namedType.ConstructedFrom)) { return(ShallowCopyableTypes[type] = true); } if (type.TypeKind == TypeKind.Struct && !namedType.IsGenericType && !namedType.IsUnboundGenericType) { return(ShallowCopyableTypes[type] = IsValueTypeFieldsShallowCopyable(wellKnownTypes, type, examining)); } return(ShallowCopyableTypes[type] = false); }
/// <summary> /// Check whether given symbol is from mscorlib /// </summary> public static bool IsFromMscorlib(this ISymbol symbol, Compilation compilation) { var @object = WellKnownTypes.Object(compilation); return(symbol.ContainingAssembly?.Equals(@object.ContainingAssembly) == true); }
private static List <MethodCategory> GetMethodCategories(Compilation compilation) { var methodCategories = new List <MethodCategory> { new MethodCategory(IsPropertyGetter, true, PropertyGetterRule, WellKnownTypes.InvalidOperationException(compilation), WellKnownTypes.NotSupportedException(compilation)), new MethodCategory(IsIndexerGetter, true, PropertyGetterRule, WellKnownTypes.InvalidOperationException(compilation), WellKnownTypes.NotSupportedException(compilation), WellKnownTypes.ArgumentException(compilation), WellKnownTypes.KeyNotFoundException(compilation)), new MethodCategory(IsEventAccessor, true, HasAllowedExceptionsRule, WellKnownTypes.InvalidOperationException(compilation), WellKnownTypes.NotSupportedException(compilation), WellKnownTypes.ArgumentException(compilation)), new MethodCategory(IsGetHashCodeInterfaceImplementation, true, HasAllowedExceptionsRule, WellKnownTypes.ArgumentException(compilation)), new MethodCategory(IsEqualsOverrideOrInterfaceImplementation, true, NoAllowedExceptionsRule), new MethodCategory(IsEqualityOperator, true, NoAllowedExceptionsRule), new MethodCategory(IsGetHashCodeOverride, true, NoAllowedExceptionsRule), new MethodCategory(IsToString, true, NoAllowedExceptionsRule), new MethodCategory(IsImplicitCastOperator, true, NoAllowedExceptionsRule), new MethodCategory(IsStaticConstructor, false, NoAllowedExceptionsRule), new MethodCategory(IsFinalizer, false, NoAllowedExceptionsRule), new MethodCategory(IMethodSymbolExtensions.IsDisposeImplementation, true, NoAllowedExceptionsRule), }; return(methodCategories); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol iDbCommandType = WellKnownTypes.IDbCommand(compilationContext.Compilation); INamedTypeSymbol iDataAdapterType = WellKnownTypes.IDataAdapter(compilationContext.Compilation); IPropertySymbol commandTextProperty = iDbCommandType?.GetMembers("CommandText").OfType <IPropertySymbol>().FirstOrDefault(); if (iDbCommandType == null || iDataAdapterType == null || commandTextProperty == null) { return; } compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { ISymbol symbol = operationBlockStartContext.OwningSymbol; if (symbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, Rule, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken)) { return; } var isInDbCommandConstructor = false; var isInDataAdapterConstructor = false; if (symbol.Kind != SymbolKind.Method) { return; } var methodSymbol = (IMethodSymbol)symbol; if (methodSymbol.MethodKind == MethodKind.Constructor) { CheckForDbCommandAndDataAdapterImplementation(symbol.ContainingType, iDbCommandType, iDataAdapterType, out isInDbCommandConstructor, out isInDataAdapterConstructor); } operationBlockStartContext.RegisterOperationAction(operationContext => { var creation = (IObjectCreationOperation)operationContext.Operation; AnalyzeMethodCall(operationContext, creation.Constructor, symbol, creation.Arguments, creation.Syntax, isInDbCommandConstructor, isInDataAdapterConstructor, iDbCommandType, iDataAdapterType); }, OperationKind.ObjectCreation); // If an object calls a constructor in a base class or the same class, this will get called. operationBlockStartContext.RegisterOperationAction(operationContext => { var invocation = (IInvocationOperation)operationContext.Operation; // We only analyze constructor invocations if (invocation.TargetMethod.MethodKind != MethodKind.Constructor) { return; } // If we're calling another constructor in the same class from this constructor, assume that all parameters are safe and skip analysis. Parameter usage // will be analyzed there if (Equals(invocation.TargetMethod.ContainingType, symbol.ContainingType)) { return; } AnalyzeMethodCall(operationContext, invocation.TargetMethod, symbol, invocation.Arguments, invocation.Syntax, isInDbCommandConstructor, isInDataAdapterConstructor, iDbCommandType, iDataAdapterType); }, OperationKind.Invocation); operationBlockStartContext.RegisterOperationAction(operationContext => { var propertyReference = (IPropertyReferenceOperation)operationContext.Operation; // We're only interested in implementations of IDbCommand.CommandText if (!propertyReference.Property.IsOverrideOrImplementationOfInterfaceMember(commandTextProperty)) { return; } // Make sure we're in assignment statement if (!(propertyReference.Parent is IAssignmentOperation assignment)) { return; } // Only if the property reference is actually the target of the assignment if (assignment.Target != propertyReference) { return; } ReportDiagnosticIfNecessary(operationContext, assignment.Value, assignment.Syntax, propertyReference.Property, symbol); }, OperationKind.PropertyReference); }); }); }
private static void AssertNoIsByRefLikeAttributeExists(AssemblySymbol assembly) { var isByRefLikeAttributeTypeName = WellKnownTypes.GetMetadataName(WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute); Assert.Null(assembly.GetTypeByMetadataName(isByRefLikeAttributeTypeName)); }
private async Task <Document> GenerateConstructor(Document document, SyntaxNode node, ISymbol symbol, INamedTypeSymbol notImplementedExceptionType, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); var typeSymbol = symbol as INamedTypeSymbol; await editor.EditOneDeclarationAsync(typeSymbol, node.GetLocation(), (docEditor, declaration) => { SyntaxGenerator generator = docEditor.Generator; SyntaxNode throwStatement = generator.ThrowStatement(generator.ObjectCreationExpression(generator.TypeExpression(notImplementedExceptionType))); SyntaxNode ctorDecl = generator.ConstructorDeclaration( typeSymbol.Name, new[] { generator.ParameterDeclaration("serializationInfo", generator.TypeExpression(WellKnownTypes.SerializationInfo(docEditor.SemanticModel.Compilation))), generator.ParameterDeclaration("streamingContext", generator.TypeExpression(WellKnownTypes.StreamingContext(docEditor.SemanticModel.Compilation))) }, typeSymbol.IsSealed ? Accessibility.Private : Accessibility.Protected, statements: new[] { throwStatement }); docEditor.AddMember(declaration, ctorDecl); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
internal NamedTypeSymbol GetDelegateType( BoundExpression loweredReceiver, RefKind receiverRefKind, ImmutableArray <BoundExpression> loweredArguments, ImmutableArray <RefKind> refKinds, BoundExpression loweredRight, TypeSymbol resultType) { Debug.Assert(refKinds.IsDefaultOrEmpty || refKinds.Length == loweredArguments.Length); var callSiteType = _factory.WellKnownType(WellKnownType.System_Runtime_CompilerServices_CallSite); if (callSiteType.IsErrorType()) { return(null); } var delegateSignature = MakeCallSiteDelegateSignature(callSiteType, loweredReceiver, loweredArguments, loweredRight, resultType); bool returnsVoid = resultType.SpecialType == SpecialType.System_Void; bool hasByRefs = receiverRefKind != RefKind.None || !refKinds.IsDefaultOrEmpty; if (!hasByRefs) { var wkDelegateType = returnsVoid ? WellKnownTypes.GetWellKnownActionDelegate(invokeArgumentCount: delegateSignature.Length) : WellKnownTypes.GetWellKnownFunctionDelegate(invokeArgumentCount: delegateSignature.Length - 1); if (wkDelegateType != WellKnownType.Unknown) { var delegateType = _factory.Compilation.GetWellKnownType(wkDelegateType); if (!delegateType.HasUseSiteError) { return(delegateType.Construct(delegateSignature)); } } } BitVector byRefs; if (hasByRefs) { byRefs = BitVector.Create(1 + (loweredReceiver != null ? 1 : 0) + loweredArguments.Length + (loweredRight != null ? 1 : 0)); int j = 1; if (loweredReceiver != null) { byRefs[j++] = receiverRefKind != RefKind.None; } if (!refKinds.IsDefault) { for (int i = 0; i < refKinds.Length; i++, j++) { if (refKinds[i] != RefKind.None) { byRefs[j] = true; } } } } else { byRefs = default(BitVector); } int parameterCount = delegateSignature.Length - (returnsVoid ? 0 : 1); int generation = _factory.CompilationState.ModuleBuilderOpt.CurrentGenerationOrdinal; var synthesizedType = _factory.Compilation.AnonymousTypeManager.SynthesizeDelegate(parameterCount, byRefs, returnsVoid, generation); return(synthesizedType.Construct(delegateSignature)); }
/// <summary> /// Checks if the given method implements IDisposable.Dispose() /// </summary> public static bool IsDisposeImplementation(this IMethodSymbol method, Compilation compilation) { INamedTypeSymbol iDisposable = WellKnownTypes.IDisposable(compilation); return(method.IsDisposeImplementation(iDisposable)); }
private static async Task <Document> AddConstructorsAsync(Document document, IEnumerable <Diagnostic> diagnostics, SyntaxNode root, CancellationToken cancellationToken) { DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); SyntaxGenerator generator = editor.Generator; SemanticModel model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostics.First().Location.SourceSpan; // All the diagnostics are reported at the same location -- the name of the declared class -- so it doesn't matter which one we pick SyntaxNode node = root.FindNode(diagnosticSpan); SyntaxNode targetNode = editor.Generator.GetDeclaration(node, DeclarationKind.Class); var typeSymbol = model.GetDeclaredSymbol(targetNode) as INamedTypeSymbol; foreach (Diagnostic diagnostic in diagnostics) { var missingCtorSignature = (ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature)Enum.Parse(typeof(ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature), diagnostic.Properties["Signature"]); switch (missingCtorSignature) { case ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature.CtorWithNoParameter: // Add missing CtorWithNoParameter SyntaxNode newConstructorNode1 = generator.ConstructorDeclaration(typeSymbol.Name, accessibility: Accessibility.Public); editor.AddMember(targetNode, newConstructorNode1); break; case ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature.CtorWithStringParameter: // Add missing CtorWithStringParameter SyntaxNode newConstructorNode2 = generator.ConstructorDeclaration( containingTypeName: typeSymbol.Name, parameters: new[] { generator.ParameterDeclaration("message", generator.TypeExpression(WellKnownTypes.String(editor.SemanticModel.Compilation))) }, accessibility: Accessibility.Public, baseConstructorArguments: new[] { generator.Argument(generator.IdentifierName("message")) }); editor.AddMember(targetNode, newConstructorNode2); break; case ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature.CtorWithStringAndExceptionParameters: // Add missing CtorWithStringAndExceptionParameters SyntaxNode newConstructorNode3 = generator.ConstructorDeclaration( containingTypeName: typeSymbol.Name, parameters: new[] { generator.ParameterDeclaration("message", generator.TypeExpression(WellKnownTypes.String(editor.SemanticModel.Compilation))), generator.ParameterDeclaration("innerException", generator.TypeExpression(WellKnownTypes.Exception(editor.SemanticModel.Compilation))) }, accessibility: Accessibility.Public, baseConstructorArguments: new[] { generator.Argument(generator.IdentifierName("message")), generator.Argument(generator.IdentifierName("innerException")) }); editor.AddMember(targetNode, newConstructorNode3); break; } } return(editor.GetChangedDocument()); }
private static MemberDeclarationSyntax GenerateConstructor(WellKnownTypes wellKnownTypes, string className, List <FieldInfoMember> fields) { var body = new List <StatementSyntax>(); // Expressions for specifying binding flags. var bindingFlags = SymbolSyntaxExtensions.GetBindingFlagsParenthesizedExpressionSyntax( SyntaxKind.BitwiseOrExpression, BindingFlags.Instance, BindingFlags.NonPublic, BindingFlags.Public); var fieldUtils = IdentifierName("fieldUtils"); foreach (var field in fields) { // Get the field var fieldInfoField = IdentifierName(field.InfoFieldName); var fieldInfo = InvocationExpression(TypeOfExpression(field.Field.ContainingType.ToTypeSyntax()).Member("GetField")) .AddArgumentListArguments( Argument(field.Field.Name.ToLiteralExpression()), Argument(bindingFlags)); var fieldInfoVariable = VariableDeclarator(field.InfoFieldName).WithInitializer(EqualsValueClause(fieldInfo)); if (!field.IsGettableProperty || !field.IsSettableProperty) { body.Add(LocalDeclarationStatement( VariableDeclaration(wellKnownTypes.FieldInfo.ToTypeSyntax()).AddVariables(fieldInfoVariable))); } // Set the getter/setter of the field if (!field.IsGettableProperty) { var getterType = wellKnownTypes.Func_2.Construct(field.Field.ContainingType, field.SafeType).ToTypeSyntax(); var getterInvoke = CastExpression( getterType, InvocationExpression(fieldUtils.Member("GetGetter")).AddArgumentListArguments(Argument(fieldInfoField))); body.Add(ExpressionStatement( AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(field.GetterFieldName), getterInvoke))); } if (!field.IsSettableProperty) { if (field.Field.ContainingType != null && field.Field.ContainingType.IsValueType) { var setterType = wellKnownTypes.ValueTypeSetter_2.Construct(field.Field.ContainingType, field.SafeType).ToTypeSyntax(); var getValueSetterInvoke = CastExpression( setterType, InvocationExpression(fieldUtils.Member("GetValueSetter")) .AddArgumentListArguments(Argument(fieldInfoField))); body.Add(ExpressionStatement( AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(field.SetterFieldName), getValueSetterInvoke))); } else { var setterType = wellKnownTypes.Action_2.Construct(field.Field.ContainingType, field.SafeType).ToTypeSyntax(); var getReferenceSetterInvoke = CastExpression( setterType, InvocationExpression(fieldUtils.Member("GetReferenceSetter")) .AddArgumentListArguments(Argument(fieldInfoField))); body.Add(ExpressionStatement( AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(field.SetterFieldName), getReferenceSetterInvoke))); } } } return (ConstructorDeclaration(className) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( Parameter(fieldUtils.Identifier).WithType(wellKnownTypes.IFieldUtils.ToTypeSyntax())) .AddBodyStatements(body.ToArray())); }
#pragma warning disable RS1026 // Enable concurrent execution public override void Initialize(AnalysisContext context) #pragma warning restore RS1026 // Enable concurrent execution { // TODO: Consider making this analyzer thread-safe. //context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationStartContext => { INamedTypeSymbol eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') INamedTypeSymbol onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol obsoleteAttribute = WellKnownTypes.ObsoleteAttribute(compilationStartContext.Compilation); ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore = ImmutableHashSet.Create( conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute, obsoleteAttribute); UnusedParameterDictionary unusedMethodParameters = new ConcurrentDictionary <IMethodSymbol, ISet <IParameterSymbol> >(); ISet <IMethodSymbol> methodsUsedAsDelegates = new HashSet <IMethodSymbol>(); // Create a list of functions to exclude from analysis. We assume that any function that is used in an IMethodBindingExpression // cannot have its signature changed, and add it to the list of methods to be excluded from analysis. compilationStartContext.RegisterOperationAction(operationContext => { var methodBinding = (IMethodReferenceOperation)operationContext.Operation; methodsUsedAsDelegates.Add(methodBinding.Method.OriginalDefinition); }, OperationKind.MethodReference); compilationStartContext.RegisterOperationBlockStartAction(startOperationBlockContext => { // We only care about methods. if (!(startOperationBlockContext.OwningSymbol is IMethodSymbol method)) { return; } AnalyzeMethod(method, startOperationBlockContext, unusedMethodParameters, eventsArgSymbol, methodsUsedAsDelegates, attributeSetForMethodsToIgnore); foreach (var localFunctionOperation in startOperationBlockContext.OperationBlocks.SelectMany(o => o.Descendants()).OfType <ILocalFunctionOperation>()) { AnalyzeMethod(localFunctionOperation.Symbol, startOperationBlockContext, unusedMethodParameters, eventsArgSymbol, methodsUsedAsDelegates, attributeSetForMethodsToIgnore); } }); // Register a compilation end action to filter all methods used as delegates and report any diagnostics compilationStartContext.RegisterCompilationEndAction(compilationAnalysisContext => { // Report diagnostics for unused parameters. var unusedParameters = unusedMethodParameters.Where(kvp => !methodsUsedAsDelegates.Contains(kvp.Key)).SelectMany(kvp => kvp.Value); foreach (var parameter in unusedParameters) { var diagnostic = Diagnostic.Create(Rule, parameter.Locations[0], parameter.Name, parameter.ContainingSymbol.Name); compilationAnalysisContext.ReportDiagnostic(diagnostic); } }); }); }
private static async Task <Document> AddSerializableAttributeToType(Document document, ITypeSymbol type, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); await editor.EditOneDeclarationAsync(type, (docEditor, declaration) => { SyntaxNode serializableAttr = docEditor.Generator.Attribute(docEditor.Generator.TypeExpression(WellKnownTypes.SerializableAttribute(docEditor.SemanticModel.Compilation))); docEditor.AddAttribute(declaration, serializableAttr); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }