Exemple #1
0
        private TaintedDataConfig(Compilation compilation)
        {
            this.WellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);
            this.SourceSymbolMap       = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > >();
            this.SanitizerSymbolMap    = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > >();
            this.SinkSymbolMap         = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > >();

            // For tainted data rules with the same set of sources, we'll reuse the same TaintedDataSymbolMap<SourceInfo> instance.
            // Same for sanitizers.
            PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourcesToSymbolMap =
                PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance();

            PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizersToSymbolMap =
                PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance();

            // Build a mapping of (sourceSet, sanitizerSet) -> (sinkKinds, sinkSet), so we'll reuse the same TaintedDataSymbolMap<SinkInfo> instance.
            PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> sourceSanitizersToSinks =
                PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> .GetInstance();

            try
            {
                // Using LazyThreadSafetyMode.ExecutionAndPublication to avoid instantiating multiple times.
                foreach (SinkKind sinkKind in Enum.GetValues(typeof(SinkKind)))
                {
                    ImmutableHashSet <SourceInfo> sources = GetSourceInfos(sinkKind);
                    if (!sourcesToSymbolMap.TryGetValue(sources, out Lazy <TaintedDataSymbolMap <SourceInfo> > lazySourceSymbolMap))
                    {
                        lazySourceSymbolMap = new Lazy <TaintedDataSymbolMap <SourceInfo> >(
                            () => { return(new TaintedDataSymbolMap <SourceInfo>(this.WellKnownTypeProvider, sources)); },
                            LazyThreadSafetyMode.ExecutionAndPublication);
                        sourcesToSymbolMap.Add(sources, lazySourceSymbolMap);
                    }

                    this.SourceSymbolMap.Add(sinkKind, lazySourceSymbolMap);

                    ImmutableHashSet <SanitizerInfo> sanitizers = GetSanitizerInfos(sinkKind);
                    if (!sanitizersToSymbolMap.TryGetValue(sanitizers, out Lazy <TaintedDataSymbolMap <SanitizerInfo> > lazySanitizerSymbolMap))
                    {
                        lazySanitizerSymbolMap = new Lazy <TaintedDataSymbolMap <SanitizerInfo> >(
                            () => { return(new TaintedDataSymbolMap <SanitizerInfo>(this.WellKnownTypeProvider, sanitizers)); },
                            LazyThreadSafetyMode.ExecutionAndPublication);
                        sanitizersToSymbolMap.Add(sanitizers, lazySanitizerSymbolMap);
                    }

                    this.SanitizerSymbolMap.Add(sinkKind, lazySanitizerSymbolMap);

                    ImmutableHashSet <SinkInfo> sinks = GetSinkInfos(sinkKind);
                    if (!sourceSanitizersToSinks.TryGetValue((sources, sanitizers), out (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)sinksPair))
                    {
                        sinksPair = (ImmutableHashSet.CreateBuilder <SinkKind>(), ImmutableHashSet.CreateBuilder <SinkInfo>());
                        sourceSanitizersToSinks.Add((sources, sanitizers), sinksPair);
                    }

                    sinksPair.SinkKinds.Add(sinkKind);
                    sinksPair.SinkInfos.UnionWith(sinks);
                }

                foreach (KeyValuePair <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> kvp in sourceSanitizersToSinks)
                {
                    ImmutableHashSet <SinkInfo>             sinks             = kvp.Value.SinkInfos.ToImmutable();
                    Lazy <TaintedDataSymbolMap <SinkInfo> > lazySinkSymbolMap = new Lazy <TaintedDataSymbolMap <SinkInfo> >(
                        () => { return(new TaintedDataSymbolMap <SinkInfo>(this.WellKnownTypeProvider, sinks)); },
                        LazyThreadSafetyMode.ExecutionAndPublication);
                    foreach (SinkKind sinkKind in kvp.Value.SinkKinds)
                    {
                        this.SinkSymbolMap.Add(sinkKind, lazySinkSymbolMap);
                    }
                }
            }
            finally
            {
                sourcesToSymbolMap.Free();
                sanitizersToSymbolMap.Free();
                sourceSanitizersToSinks.Free();
            }
        }
Exemple #2
0
        private static TaintedDataAnalysisResult?TryGetOrComputeResult(
            ControlFlowGraph cfg,
            Compilation compilation,
            ISymbol containingMethod,
            AnalyzerOptions analyzerOptions,
            TaintedDataSymbolMap <SourceInfo> taintedSourceInfos,
            TaintedDataSymbolMap <SanitizerInfo> taintedSanitizerInfos,
            TaintedDataSymbolMap <SinkInfo> taintedSinkInfos,
            InterproceduralAnalysisConfiguration interproceduralAnalysisConfig)
        {
            if (cfg == null)
            {
                Debug.Fail("Expected non-null CFG");
                return(null);
            }

            WellKnownTypeProvider      wellKnownTypeProvider      = WellKnownTypeProvider.GetOrCreate(compilation);
            ValueContentAnalysisResult?valueContentAnalysisResult = null;
            CopyAnalysisResult?        copyAnalysisResult         = null;
            PointsToAnalysisResult?    pointsToAnalysisResult     = null;

            if (taintedSourceInfos.RequiresValueContentAnalysis || taintedSanitizerInfos.RequiresValueContentAnalysis || taintedSinkInfos.RequiresValueContentAnalysis)
            {
                valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                    cfg,
                    containingMethod,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    PointsToAnalysisKind.Complete,
                    interproceduralAnalysisConfig,
                    out copyAnalysisResult,
                    out pointsToAnalysisResult,
                    pessimisticAnalysis: true,
                    performCopyAnalysis: false);
                if (valueContentAnalysisResult == null)
                {
                    return(null);
                }
            }
            else
            {
                pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult(
                    cfg,
                    containingMethod,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    PointsToAnalysisKind.Complete,
                    interproceduralAnalysisConfig,
                    interproceduralAnalysisPredicateOpt: null,
                    pessimisticAnalysis: true,
                    performCopyAnalysis: false);
                if (pointsToAnalysisResult == null)
                {
                    return(null);
                }
            }

            TaintedDataAnalysisContext analysisContext = TaintedDataAnalysisContext.Create(
                TaintedDataAbstractValueDomain.Default,
                wellKnownTypeProvider,
                cfg,
                containingMethod,
                analyzerOptions,
                interproceduralAnalysisConfig,
                pessimisticAnalysis: false,
                copyAnalysisResultOpt: copyAnalysisResult,
                pointsToAnalysisResult: pointsToAnalysisResult,
                valueContentAnalysisResult: valueContentAnalysisResult,
                tryGetOrComputeAnalysisResult: TryGetOrComputeResultForAnalysisContext,
                taintedSourceInfos: taintedSourceInfos,
                taintedSanitizerInfos: taintedSanitizerInfos,
                taintedSinkInfos: taintedSinkInfos);

            return(TryGetOrComputeResultForAnalysisContext(analysisContext));
        }
Exemple #3
0
        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 =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                wellKnownTypeProvider.TryGetTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyRSA,
                    out var rsaTypeSymbol);
                wellKnownTypeProvider.TryGetTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyAsymmetricAlgorithm,
                    out var asymmetricAlgorithmTypeSymbol);
                wellKnownTypeProvider.TryGetTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyCryptoConfig,
                    out var cryptoConfigTypeSymbol);

                if (rsaTypeSymbol == null &&
                    asymmetricAlgorithmTypeSymbol == null &&
                    cryptoConfigTypeSymbol == null)
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var objectCreationOperation = (IObjectCreationOperation)operationAnalysisContext.Operation;
                    var typeSymbol = objectCreationOperation.Constructor.ContainingType;

                    if (typeSymbol == null)
                    {
                        return;
                    }

                    var baseTypesAndThis = typeSymbol.GetBaseTypesAndThis();

                    if (rsaTypeSymbol != null && baseTypesAndThis.Contains(rsaTypeSymbol))
                    {
                        var arguments = objectCreationOperation.Arguments;

                        if (arguments.Length == 1 &&
                            arguments[0].Parameter.Type.SpecialType == SpecialType.System_Int32 &&
                            arguments[0].Value.ConstantValue.HasValue &&
                            Convert.ToInt32(arguments[0].Value.ConstantValue.Value) < 2048)
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                objectCreationOperation.CreateDiagnostic(
                                    Rule,
                                    typeSymbol.Name));
                        }
                    }
                }, OperationKind.ObjectCreation);

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                    var methodSymbol        = invocationOperation.TargetMethod;
                    var typeSymbol          = methodSymbol.ContainingType;

                    if (typeSymbol == null)
                    {
                        return;
                    }

                    var methodName = methodSymbol.Name;
                    var arguments  = invocationOperation.Arguments;

                    if (methodName == "Create" &&
                        typeSymbol.Equals(asymmetricAlgorithmTypeSymbol) &&
                        arguments.Length == 0)
                    {
                        // Use AsymmetricAlgorithm.Create() to create RSA and the default key size is 1024.
                        operationAnalysisContext.ReportDiagnostic(
                            invocationOperation.CreateDiagnostic(
                                Rule,
                                "RSA"));
                    }
                    else if (methodName == "Create" &&
                             typeSymbol.Equals(asymmetricAlgorithmTypeSymbol) &&
                             arguments.Length > 0 &&
                             arguments[0].Parameter.Type.SpecialType == SpecialType.System_String &&
                             arguments[0].Value.ConstantValue.HasValue)
                    {
                        var argValue = arguments[0].Value.ConstantValue.Value;

                        if (s_RSAAlgorithmNames.Contains(argValue.ToString()))
                        {
                            // Use AsymmetricAlgorithm.Create(string) to create RSA and the default key size is 1024.
                            operationAnalysisContext.ReportDiagnostic(
                                invocationOperation.CreateDiagnostic(
                                    Rule,
                                    argValue));
                        }
                    }
                    else if (methodName == "CreateFromName" &&
                             typeSymbol.Equals(cryptoConfigTypeSymbol) &&
                             arguments.Length > 0 &&
                             arguments[0].Parameter.Type.SpecialType == SpecialType.System_String &&
                             arguments[0].Value.ConstantValue.HasValue)
                    {
                        // Use CryptoConfig.CreateFromName(string, ...).
                        var argValue = arguments[0].Value.ConstantValue.Value;

                        if (s_RSAAlgorithmNames.Contains(argValue.ToString()))
                        {
                            // Create RSA.
                            if (arguments.Length == 1 /* The default key size is 1024 */ ||
                                arguments[1].Value is IArrayCreationOperation arrayCreationOperation /* Use CryptoConfig.CreateFromName(string, object[]) to create RSA */ &&
                                arrayCreationOperation.DimensionSizes[0].ConstantValue.Value.Equals(1) &&
                                arrayCreationOperation.Initializer.ElementValues.Any(
                                    s => s is IConversionOperation conversionOperation &&
                                    conversionOperation.Operand.ConstantValue.HasValue &&
                                    Convert.ToInt32(conversionOperation.Operand.ConstantValue.Value) < 2048) /* Specify the key size is smaller than 2048 explicitly */)
                            {
                                operationAnalysisContext.ReportDiagnostic(
                                    invocationOperation.CreateDiagnostic(
                                        Rule,
                                        argValue));
                            }
                        }
                    }
                }, OperationKind.Invocation);
            });
        }
Exemple #4
0
        /// <summary>
        /// Analyzers should use BatchGetOrComputeHazardousUsages instead. Gets hazardous usages of an object based on a set of its properties.
        /// </summary>
        /// <param name="cfg">Control flow graph of the code.</param>
        /// <param name="compilation">Compilation containing the code.</param>
        /// <param name="owningSymbol">Symbol of the code to examine.</param>
        /// <param name="typeToTrackMetadataNames">Names of the types to track.</param>
        /// <param name="constructorMapper">How constructor invocations map to <see cref="PropertySetAbstractValueKind"/>s.</param>
        /// <param name="propertyMappers">How property assignments map to <see cref="PropertySetAbstractValueKind"/>.</param>
        /// <param name="hazardousUsageEvaluators">When and how to evaluate <see cref="PropertySetAbstractValueKind"/>s to for hazardous usages.</param>
        /// <param name="interproceduralAnalysisConfig">Interprocedural dataflow analysis configuration.</param>
        /// <param name="pessimisticAnalysis">Whether to be pessimistic.</param>
        /// <returns>Property set analysis result.</returns>
        internal static PropertySetAnalysisResult GetOrComputeResult(
            ControlFlowGraph cfg,
            Compilation compilation,
            ISymbol owningSymbol,
            AnalyzerOptions analyzerOptions,
            ImmutableHashSet <string> typeToTrackMetadataNames,
            ConstructorMapper constructorMapper,
            PropertyMapperCollection propertyMappers,
            HazardousUsageEvaluatorCollection hazardousUsageEvaluators,
            InterproceduralAnalysisConfiguration interproceduralAnalysisConfig,
            bool pessimisticAnalysis = false)
        {
            if (constructorMapper == null)
            {
                throw new ArgumentNullException(nameof(constructorMapper));
            }

            if (propertyMappers == null)
            {
                throw new ArgumentNullException(nameof(propertyMappers));
            }

            if (hazardousUsageEvaluators == null)
            {
                throw new ArgumentNullException(nameof(hazardousUsageEvaluators));
            }

            constructorMapper.Validate(propertyMappers.PropertyValuesCount);

            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

            PointsToAnalysisResult     pointsToAnalysisResult;
            ValueContentAnalysisResult valueContentAnalysisResultOpt;

            if (!constructorMapper.RequiresValueContentAnalysis && !propertyMappers.RequiresValueContentAnalysis)
            {
                pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult(
                    cfg,
                    owningSymbol,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    interproceduralAnalysisConfig,
                    interproceduralAnalysisPredicateOpt: null,
                    pessimisticAnalysis,
                    performCopyAnalysis: false);
                if (pointsToAnalysisResult == null)
                {
                    return(null);
                }

                valueContentAnalysisResultOpt = null;
            }
            else
            {
                valueContentAnalysisResultOpt = ValueContentAnalysis.TryGetOrComputeResult(
                    cfg,
                    owningSymbol,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    interproceduralAnalysisConfig,
                    out var copyAnalysisResult,
                    out pointsToAnalysisResult,
                    pessimisticAnalysis,
                    performCopyAnalysis: false);
                if (valueContentAnalysisResultOpt == null)
                {
                    return(null);
                }
            }

            var analysisContext = PropertySetAnalysisContext.Create(
                PropertySetAbstractValueDomain.Default,
                wellKnownTypeProvider,
                cfg,
                owningSymbol,
                analyzerOptions,
                interproceduralAnalysisConfig,
                pessimisticAnalysis,
                pointsToAnalysisResult,
                valueContentAnalysisResultOpt,
                TryGetOrComputeResultForAnalysisContext,
                typeToTrackMetadataNames,
                constructorMapper,
                propertyMappers,
                hazardousUsageEvaluators);
            var result = TryGetOrComputeResultForAnalysisContext(analysisContext);

            return(result);
        }
Exemple #5
0
        public sealed override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            context.RegisterCompilationStartAction(compilationContext =>
            {
                var typeProvider = WellKnownTypeProvider.GetOrCreate(compilationContext.Compilation);

                // Get the String and StringBuilder types.
                if (!typeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemTextStringBuilder, out var stringBuilderType))
                {
                    return;
                }

                // Get all of the one-arg StringBuilder.Append methods and two-arg Insert methods.  We skip over the object-based
                // overloads, as there's little benefit to removing such ToString calls.  And we skip over arrays, to avoid
                // differences of behavior between Append(char[]) and Append(char[].ToString()).
                var appendMethods = stringBuilderType
                                    .GetMembers("Append")
                                    .OfType <IMethodSymbol>()
                                    .WhereAsArray(s =>
                                                  s.Parameters.Length == 1 &&
                                                  s.Parameters[0].Type.SpecialType != SpecialType.System_Object &&
                                                  s.Parameters[0].Type.TypeKind != TypeKind.Array);
                var insertMethods = stringBuilderType
                                    .GetMembers("Insert")
                                    .OfType <IMethodSymbol>()
                                    .WhereAsArray(s =>
                                                  s.Parameters.Length == 2 &&
                                                  s.Parameters[0].Type.SpecialType == SpecialType.System_Int32 &&
                                                  s.Parameters[1].Type.SpecialType != SpecialType.System_Object &&
                                                  s.Parameters[1].Type.TypeKind != TypeKind.Array);

                // Get the StringBuilder.Append(string)/Insert(int, string) method, for comparison purposes.
                var appendStringMethod = appendMethods.FirstOrDefault(s =>
                                                                      s.Parameters[0].Type.SpecialType == SpecialType.System_String);
                var insertStringMethod = insertMethods.FirstOrDefault(s =>
                                                                      s.Parameters[0].Type.SpecialType == SpecialType.System_Int32 &&
                                                                      s.Parameters[1].Type.SpecialType == SpecialType.System_String);
                if (appendStringMethod is null || insertStringMethod is null)
                {
                    return;
                }

                // Check every invocation to see if it's StringBuilder.Append(string)/Insert(int, string).
                compilationContext.RegisterOperationAction(operationContext =>
                {
                    var invocation = (IInvocationOperation)operationContext.Operation;

                    // We're interested in the string argument to Append(string) and Insert(int, string).
                    // Get the argument position, or bail if this isn't either method.
                    int stringParamIndex;
                    if (appendStringMethod.Equals(invocation.TargetMethod))
                    {
                        stringParamIndex = 0;
                    }
                    else if (insertStringMethod.Equals(invocation.TargetMethod))
                    {
                        stringParamIndex = 1;
                    }
                    else
                    {
                        return;
                    }

                    // We're only interested if the string argument is a "string ToString()" call.
                    if (invocation.Arguments.Length != stringParamIndex + 1 ||
                        invocation.Arguments[stringParamIndex] is not IArgumentOperation argument ||
                        argument.Value is not IInvocationOperation toStringInvoke ||
                        toStringInvoke.TargetMethod.Name != "ToString" ||
                        toStringInvoke.Type.SpecialType != SpecialType.System_String ||
                        !toStringInvoke.TargetMethod.Parameters.IsEmpty)
                    {
                        return;
                    }

                    // We're only interested if the receiver type of that ToString call has a corresponding strongly-typed overload.
                    IMethodSymbol?stronglyTypedAppend =
                        (stringParamIndex == 0 ? appendMethods : insertMethods)
                        .FirstOrDefault(s => s.Parameters[stringParamIndex].Type.Equals(toStringInvoke.TargetMethod.ReceiverType));
                    if (stronglyTypedAppend is null)
                    {
                        return;
                    }

                    // Warn.
                    operationContext.ReportDiagnostic(toStringInvoke.CreateDiagnostic(Rule));
                }, OperationKind.Invocation);
            });
        }
Exemple #6
0
        public sealed override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);

            analysisContext.RegisterCompilationStartAction(startContext =>
            {
                ConcurrentDictionary <INamedTypeSymbol, object?> instantiatedTypes = new ConcurrentDictionary <INamedTypeSymbol, object?>();
                var internalTypes = new ConcurrentDictionary <INamedTypeSymbol, object?>();

                var compilation           = startContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                // If the assembly being built by this compilation exposes its internals to
                // any other assembly, don't report any "uninstantiated internal class" errors.
                // If we were to report an error for an internal type that is not instantiated
                // by this assembly, and then it turned out that the friend assembly did
                // instantiate the type, that would be a false positive. We've decided it's
                // better to have false negatives (which would happen if the type were *not*
                // instantiated by any friend assembly, but we didn't report the issue) than
                // to have false positives.
                var internalsVisibleToAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeCompilerServicesInternalsVisibleToAttribute);
                if (compilation.Assembly.HasAttribute(internalsVisibleToAttributeSymbol))
                {
                    return;
                }

                var systemAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemAttribute);
                var iConfigurationSectionHandlerSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemConfigurationIConfigurationSectionHandler);
                var configurationSectionSymbol         = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemConfigurationConfigurationSection);
                var safeHandleSymbol          = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesSafeHandle);
                var traceListenerSymbol       = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsTraceListener);
                var mef1ExportAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemComponentModelCompositionExportAttribute);
                var mef2ExportAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCompositionExportAttribute);
                var coClassAttributeSymbol    = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesCoClassAttribute);
                var designerAttributeSymbol   = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemComponentModelDesignerAttribute);

                RegisterLanguageSpecificChecks(startContext, instantiatedTypes);

                startContext.RegisterOperationAction(context =>
                {
                    var expr = (IObjectCreationOperation)context.Operation;
                    if (expr.Type is INamedTypeSymbol namedType)
                    {
                        instantiatedTypes.TryAdd(namedType, null);
                    }
                }, OperationKind.ObjectCreation);

                startContext.RegisterSymbolAction(context =>
                {
                    var type = (INamedTypeSymbol)context.Symbol;
                    if (!type.IsExternallyVisible() &&
                        !IsOkToBeUnused(type, compilation,
                                        systemAttributeSymbol,
                                        iConfigurationSectionHandlerSymbol,
                                        configurationSectionSymbol,
                                        safeHandleSymbol,
                                        traceListenerSymbol,
                                        mef1ExportAttributeSymbol,
                                        mef2ExportAttributeSymbol))
                    {
                        internalTypes.TryAdd(type, null);
                    }

                    // Instantiation from the subtype constructor initializer.
                    if (type.BaseType != null)
                    {
                        instantiatedTypes.TryAdd(type.BaseType, null);
                    }

                    // Consider class types declared in the CoClassAttribute or DesignerAttribute as instantiated
                    if ((coClassAttributeSymbol != null || designerAttributeSymbol != null) &&
                        (type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Interface))
                    {
                        bool isCoClassHandled = false;
                        foreach (var attribute in type.GetAttributes())
                        {
                            if (coClassAttributeSymbol != null &&
                                !isCoClassHandled &&
                                attribute.AttributeClass.Equals(coClassAttributeSymbol))
                            {
                                isCoClassHandled = true;
                                if (attribute.ConstructorArguments.Length == 1 &&
                                    attribute.ConstructorArguments[0].Kind == TypedConstantKind.Type &&
                                    attribute.ConstructorArguments[0].Value is INamedTypeSymbol typeSymbol &&
                                    typeSymbol.TypeKind == TypeKind.Class)
                                {
                                    instantiatedTypes.TryAdd(typeSymbol, null);
                                }
                            }

                            if (designerAttributeSymbol != null &&
                                (attribute.ConstructorArguments.Length == 1 || attribute.ConstructorArguments.Length == 2) &&
                                attribute.AttributeClass.Equals(designerAttributeSymbol))
                            {
                                switch (attribute.ConstructorArguments[0].Value)
                                {
                                case string designerTypeName when designerTypeName != null:
                                    {
                                        var nameParts = designerTypeName.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                        if (nameParts.Length >= 2 &&
                                            nameParts[1].Trim().Equals(context.Compilation.AssemblyName, StringComparison.Ordinal) &&
                                            wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(nameParts[0].Trim(), out var namedType) &&
                                            namedType.ContainingAssembly.Equals(compilation.Assembly))
                                        {
                                            instantiatedTypes.TryAdd(namedType, null);
                                        }
                                        break;
                                    }

                                case INamedTypeSymbol namedType when namedType != null:
                                    instantiatedTypes.TryAdd(namedType, null);
                                    break;
                                }
                            }
                        }
                    }
                }, SymbolKind.NamedType);

                startContext.RegisterOperationAction(context =>
                {
                    var expr             = (IObjectCreationOperation)context.Operation;
                    var constructedClass = (INamedTypeSymbol)expr.Type;

                    if (!constructedClass.IsGenericType || constructedClass.IsUnboundGenericType)
                    {
                        return;
                    }

                    var generics = constructedClass.TypeParameters.Zip(constructedClass.TypeArguments, (parameter, argument) => (parameter, argument));
                    ProcessGenericTypes(generics, instantiatedTypes);
                }, OperationKind.ObjectCreation);

                startContext.RegisterOperationAction(context =>
                {
                    var expr       = (IInvocationOperation)context.Operation;
                    var methodType = expr.TargetMethod;

                    if (!methodType.IsGenericMethod)
                    {
                        return;
                    }

                    var generics = methodType.TypeParameters.Zip(methodType.TypeArguments, (parameter, argument) => (parameter, argument));
                    ProcessGenericTypes(generics, instantiatedTypes);
                }, OperationKind.Invocation);

                startContext.RegisterCompilationEndAction(context =>
                {
                    var uninstantiatedInternalTypes = internalTypes
                                                      .Select(it => it.Key.OriginalDefinition)
                                                      .Except(instantiatedTypes.Select(it => it.Key.OriginalDefinition))
                                                      .Where(type => !HasInstantiatedNestedType(type, instantiatedTypes.Keys));

                    foreach (var type in uninstantiatedInternalTypes)
                    {
                        context.ReportDiagnostic(type.CreateDiagnostic(Rule, type.FormatMemberName()));
                    }
                });
            });
        }
Exemple #7
0
 /// <summary>
 /// Gets a type by its full type name and cache it at the compilation level.
 /// </summary>
 /// <param name="compilation">The compilation.</param>
 /// <param name="fullTypeName">Namespace + type name, e.g. "System.Exception".</param>
 /// <returns>The <see cref="INamedTypeSymbol"/> if found, null otherwise.</returns>
 internal static INamedTypeSymbol GetOrCreateTypeByMetadataName(this Compilation compilation, string fullTypeName) =>
 WellKnownTypeProvider.GetOrCreate(compilation).GetOrCreateTypeByMetadataName(fullTypeName);
        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.OriginalDefinition, containingPropertySymbolOpt?.OriginalDefinition, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore) &&
                            lazyValueContentResult.Value != null)
                        {
                            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()
                    {
                        var cfg = operationBlockStartContext.OperationBlocks.GetControlFlowGraph();
                        if (cfg != null)
                        {
                            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation);
                            return(ValueContentAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider,
                                                                              operationBlockStartContext.Options, Rule, operationBlockStartContext.CancellationToken));
                        }

                        return(null);
                    }
                });
            });
        }
Exemple #9
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            // If there are more classes implement IResponseCookies, add them here later.
            HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection(
                new HazardousUsageEvaluator(
                    WellKnownTypeNames.MicrosoftAspNetCoreHttpInternalResponseCookies,
                    "Append",
                    "options",
                    HazardousUsageCallback));

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(
                        WellKnownTypeNames.MicrosoftAspNetCoreHttpIResponseCookies,
                        out var iResponseCookiesTypeSymbol))
                {
                    return;
                }

                wellKnownTypeProvider.TryGetTypeByMetadataName(
                    WellKnownTypeNames.MicrosoftAspNetCoreHttpCookieOptions,
                    out var cookieOptionsTypeSymbol);
                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    // TODO: Handle case when exactly one of the below rules is configured to skip analysis.
                    if (operationBlockStartAnalysisContext.OwningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options,
                                                                                                   DefinitelyUseSecureCookiesASPNetCoreRule, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken) &&
                        operationBlockStartAnalysisContext.OwningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options,
                                                                                                   MaybeUseSecureCookiesASPNetCoreRule, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken))
                    {
                        return;
                    }

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        var methodSymbol        = invocationOperation.TargetMethod;

                        if (methodSymbol.ContainingType is INamedTypeSymbol namedTypeSymbol &&
                            namedTypeSymbol.Interfaces.Contains(iResponseCookiesTypeSymbol) &&
                            invocationOperation.TargetMethod.Name == "Append")
                        {
                            if (methodSymbol.Parameters.Length < 3)
                            {
                                operationAnalysisContext.ReportDiagnostic(
                                    invocationOperation.CreateDiagnostic(
                                        DefinitelyUseSecureCookiesASPNetCoreRule));
                            }
                            else
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                                }
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (argumentOperation.Parameter.Type.Equals(cookieOptionsTypeSymbol))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                compilationAnalysisContext.Options,
                                WellKnownTypeNames.MicrosoftAspNetCoreHttpCookieOptions,
                                constructorMapper,
                                PropertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyUseSecureCookiesASPNetCoreRule;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeUseSecureCookiesASPNetCoreRule;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
Exemple #10
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationStartContext =>
            {
                var objectType = compilationStartContext.Compilation.GetSpecialType(SpecialType.System_Object);

                if (objectType == null)
                {
                    return;
                }

                var objectObjectParameters = new[]
                {
                    ParameterInfo.GetParameterInfo(objectType),
                    ParameterInfo.GetParameterInfo(objectType)
                };

                var referenceEqualsMethodGroup = objectType.GetMembers("ReferenceEquals").OfType <IMethodSymbol>();
                var referenceEqualsMethod      = referenceEqualsMethodGroup.GetFirstOrDefaultMemberWithParameterInfos(
                    objectObjectParameters);

                if (referenceEqualsMethod == null)
                {
                    return;
                }

                var typeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartContext.Compilation);
                var referenceEqualityComparer =
                    typeProvider.GetOrCreateTypeByMetadataName("System.Collections.Generic.ReferenceEqualityComparer");

                IMethodSymbol?comparerEqualsMethod = null;

                if (referenceEqualityComparer != null)
                {
                    var equalsMethodGroup = referenceEqualityComparer.GetMembers("Equals").OfType <IMethodSymbol>();
                    comparerEqualsMethod  = equalsMethodGroup.GetFirstOrDefaultMemberWithParameterInfos(
                        objectObjectParameters);
                }

                compilationStartContext.RegisterOperationAction(operationContext =>
                {
                    var invocationExpression = (IInvocationOperation)operationContext.Operation;
                    var targetMethod         = invocationExpression.TargetMethod;
                    DiagnosticDescriptor rule;

                    if (targetMethod == null)
                    {
                        return;
                    }

                    if (referenceEqualsMethod.Equals(targetMethod))
                    {
                        rule = MethodRule;
                    }
                    else if (comparerEqualsMethod != null && comparerEqualsMethod.Equals(targetMethod))
                    {
                        rule = ComparerRule;
                    }
                    else
                    {
                        return;
                    }

                    foreach (var argument in invocationExpression.Arguments)
                    {
                        var val = argument.Value;

                        // Only check through one level of conversion,
                        // which will be either the boxing conversion to object,
                        // or a reference type implicit conversion to object.
                        if (val is IConversionOperation conversion)
                        {
                            val = conversion.Operand;
                        }

                        if (val.Type?.IsValueType == true)
                        {
                            operationContext.ReportDiagnostic(
                                val.CreateDiagnostic(
                                    rule,
                                    val.Type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)));
                        }
                    }
                },
                                                                OperationKind.Invocation);
            });
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationStartContext =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartContext.Compilation);

                INamedTypeSymbol?eventsArgSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemEventArgs);

                // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter)
                INamedTypeSymbol?conditionalAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsConditionalAttribute);

                // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext')
                INamedTypeSymbol?onDeserializingAttribute = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationOnDeserializingAttribute);
                INamedTypeSymbol?onDeserializedAttribute  = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationOnDeserializedAttribute);
                INamedTypeSymbol?onSerializingAttribute   = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationOnSerializingAttribute);
                INamedTypeSymbol?onSerializedAttribute    = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationOnSerializedAttribute);
                INamedTypeSymbol?obsoleteAttribute        = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemObsoleteAttribute);

                INamedTypeSymbol?serializationInfoType = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationSerializationInfo);
                INamedTypeSymbol?streamingContextType  = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationStreamingContext);

                ImmutableHashSet <INamedTypeSymbol?> attributeSetForMethodsToIgnore = ImmutableHashSet.Create(
                    conditionalAttributeSymbol,
                    onDeserializedAttribute,
                    onDeserializingAttribute,
                    onSerializedAttribute,
                    onSerializingAttribute,
                    obsoleteAttribute);

                compilationStartContext.RegisterSymbolStartAction(symbolStartContext =>
                {
                    // Map from parameter to a bool indicating if the parameter is used or not.
                    var parameterUsageMap = new ConcurrentDictionary <IParameterSymbol, bool>();

                    // Set of methods which are used as delegates.
                    var methodsUsedAsDelegates = new ConcurrentDictionary <IMethodSymbol, bool>();

                    // Add candidate parameters for methods.
                    symbolStartContext.RegisterOperationBlockStartAction(startOperationBlockContext =>
                    {
                        if (startOperationBlockContext.OwningSymbol is IMethodSymbol method &&
                            ShouldAnalyzeMethod(method, startOperationBlockContext, eventsArgSymbol, attributeSetForMethodsToIgnore, serializationInfoType, streamingContextType))
                        {
                            AddParameters(method, parameterUsageMap);
                        }
                    });

                    // Add candidate parameters for local functions.
                    symbolStartContext.RegisterOperationAction(
                        context => AddParameters(((ILocalFunctionOperation)context.Operation).Symbol, parameterUsageMap),
                        OperationKind.LocalFunction);

                    // Add methods used as delegates.
                    symbolStartContext.RegisterOperationAction(
                        context => methodsUsedAsDelegates.TryAdd(((IMethodReferenceOperation)context.Operation).Method.OriginalDefinition, true),
                        OperationKind.MethodReference);

                    // Mark parameters with a parameter reference as used.
                    symbolStartContext.RegisterOperationAction(
                        context => parameterUsageMap.AddOrUpdate(
                            ((IParameterReferenceOperation)context.Operation).Parameter,
                            addValue: true,
                            updateValueFactory: ReturnTrue),
                        OperationKind.ParameterReference);

                    // Report unused parameters in SymbolEnd action.
                    symbolStartContext.RegisterSymbolEndAction(
                        context => ReportUnusedParameters(context, parameterUsageMap, methodsUsedAsDelegates));
                }, SymbolKind.NamedType);
            });
        }
Exemple #12
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationContext) =>
            {
                Compilation compilation             = compilationContext.Compilation;
                TaintedDataConfig taintedDataConfig = TaintedDataConfig.GetOrCreate(compilation);
                TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = taintedDataConfig.GetSourceSymbolMap(this.SinkKind);
                if (sourceInfoSymbolMap.IsEmpty)
                {
                    return;
                }

                TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = taintedDataConfig.GetSinkSymbolMap(this.SinkKind);
                if (sinkInfoSymbolMap.IsEmpty)
                {
                    return;
                }

                compilationContext.RegisterOperationBlockStartAction(
                    operationBlockStartContext =>
                {
                    ISymbol owningSymbol                = operationBlockStartContext.OwningSymbol;
                    AnalyzerOptions options             = operationBlockStartContext.Options;
                    CancellationToken cancellationToken = operationBlockStartContext.CancellationToken;
                    if (owningSymbol.IsConfiguredToSkipAnalysis(options, TaintedDataEnteringSinkDescriptor, compilation, cancellationToken))
                    {
                        return;
                    }

                    WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);
                    InterproceduralAnalysisConfiguration interproceduralAnalysisConfiguration = InterproceduralAnalysisConfiguration.Create(
                        options,
                        SupportedDiagnostics,
                        owningSymbol,
                        operationBlockStartContext.Compilation,
                        defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                        cancellationToken: cancellationToken);
                    Lazy <ControlFlowGraph?> controlFlowGraphFactory = new Lazy <ControlFlowGraph?>(
                        () => operationBlockStartContext.OperationBlocks.GetControlFlowGraph());
                    Lazy <PointsToAnalysisResult?> pointsToFactory = new Lazy <PointsToAnalysisResult?>(
                        () =>
                    {
                        if (controlFlowGraphFactory.Value == null)
                        {
                            return(null);
                        }

                        return(PointsToAnalysis.TryGetOrComputeResult(
                                   controlFlowGraphFactory.Value,
                                   owningSymbol,
                                   options,
                                   wellKnownTypeProvider,
                                   PointsToAnalysisKind.Complete,
                                   interproceduralAnalysisConfiguration,
                                   interproceduralAnalysisPredicateOpt: null));
                    });
                    Lazy <(PointsToAnalysisResult?, ValueContentAnalysisResult?)> valueContentFactory = new Lazy <(PointsToAnalysisResult?, ValueContentAnalysisResult?)>(
                        () =>
                    {
                        if (controlFlowGraphFactory.Value == null)
                        {
                            return(null, null);
                        }

                        ValueContentAnalysisResult?valuecontentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                            controlFlowGraphFactory.Value,
                            owningSymbol,
                            options,
                            wellKnownTypeProvider,
                            PointsToAnalysisKind.Complete,
                            interproceduralAnalysisConfiguration,
                            out _,
                            out PointsToAnalysisResult? p);

                        return(p, valuecontentAnalysisResult);
                    });

                    PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance();

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation;
                        if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(propertyReferenceOperation.GetRoot());
                            }
                        }
                    },
                        OperationKind.PropertyReference);

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        if (sourceInfoSymbolMap.IsSourceMethod(
                                invocationOperation.TargetMethod,
                                invocationOperation.Arguments,
                                pointsToFactory,
                                valueContentFactory,
                                out _))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(invocationOperation.GetRoot());
                            }
                        }
                    },
                        OperationKind.Invocation);

                    if (TaintedDataConfig.HasTaintArraySource(SinkKind))
                    {
                        operationBlockStartContext.RegisterOperationAction(
                            operationAnalysisContext =>
                        {
                            IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation;
                            if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol &&
                                sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol))
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot());
                                }
                            }
                        },
                            OperationKind.ArrayInitializer);
                    }

                    operationBlockStartContext.RegisterOperationBlockEndAction(
                        operationBlockAnalysisContext =>
                    {
                        try
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                if (!rootOperationsNeedingAnalysis.Any())
                                {
                                    return;
                                }

                                if (controlFlowGraphFactory.Value == null)
                                {
                                    return;
                                }

                                foreach (IOperation rootOperation in rootOperationsNeedingAnalysis)
                                {
                                    TaintedDataAnalysisResult?taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult(
                                        controlFlowGraphFactory.Value,
                                        operationBlockAnalysisContext.Compilation,
                                        operationBlockAnalysisContext.OwningSymbol,
                                        operationBlockAnalysisContext.Options,
                                        TaintedDataEnteringSinkDescriptor,
                                        sourceInfoSymbolMap,
                                        taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind),
                                        sinkInfoSymbolMap,
                                        operationBlockAnalysisContext.CancellationToken);
                                    if (taintedDataAnalysisResult == null)
                                    {
                                        return;
                                    }

                                    foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks)
                                    {
                                        if (!sourceSink.SinkKinds.Contains(this.SinkKind))
                                        {
                                            continue;
                                        }

                                        foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins)
                                        {
                                            // Something like:
                                            // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'.
                                            Diagnostic diagnostic = Diagnostic.Create(
                                                this.TaintedDataEnteringSinkDescriptor,
                                                sourceSink.Sink.Location,
                                                additionalLocations: new Location[] { sourceOrigin.Location },
                                                messageArgs: new object[] {
                                                sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
                                            });
                                            operationBlockAnalysisContext.ReportDiagnostic(diagnostic);
                                        }
                                    }
                                }
                            }
                        }
                        finally
                        {
                            rootOperationsNeedingAnalysis.Free();
                        }
                    });
                });
            });
        }
        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) =>
            {
                Compilation?compilation = compilationStartAnalysisContext.Compilation;
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataSet,
                        out INamedTypeSymbol? dataSetTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataTable,
                        out INamedTypeSymbol? dataTableTypeSymbol))
                {
                    return;
                }

                INamedTypeSymbol?serializableAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSerializableAttribute);

                INamedTypeSymbol?generatedCodeAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemCodeDomCompilerGeneratedCodeAttribute);

                // For completeness, could also consider CollectionDataContractAttribute
                INamedTypeSymbol?dataContractAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationDataContractAttribute);
                INamedTypeSymbol?dataMemberAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationDataMemberAttribute);
                INamedTypeSymbol?ignoreDataMemberTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationIgnoreDataMemberAttribute);
                INamedTypeSymbol?knownTypeAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationKnownTypeAttribute);

                XmlSerializationAttributeTypes xmlSerializationAttributeTypes = new XmlSerializationAttributeTypes(
                    wellKnownTypeProvider);
                if (serializableAttributeTypeSymbol == null &&
                    (dataContractAttributeTypeSymbol == null || dataMemberAttributeTypeSymbol == null) &&
                    ignoreDataMemberTypeSymbol == null &&
                    knownTypeAttributeTypeSymbol == null &&
                    !xmlSerializationAttributeTypes.Any)
                {
                    return;
                }

                INamedTypeSymbol?designerCategoryAttributeTypeSymbol =
                    wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemComponentModelDesignerCategoryAttribute);
                INamedTypeSymbol?typedTableBaseTypeSymbol =
                    wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataTypedTableBase1);

                InsecureDeserializationTypeDecider decider = InsecureDeserializationTypeDecider.GetOrCreate(compilation);

                ConcurrentDictionary <INamedTypeSymbol, bool> visitedTypes =
                    new ConcurrentDictionary <INamedTypeSymbol, bool>();

                compilationStartAnalysisContext.RegisterSymbolAction(
                    (SymbolAnalysisContext symbolAnalysisContext) =>
                {
                    INamedTypeSymbol namedTypeSymbol = (INamedTypeSymbol)symbolAnalysisContext.Symbol;
                    bool hasSerializableAttribute    = namedTypeSymbol.HasAttribute(serializableAttributeTypeSymbol);

                    bool hasDataContractAttribute        = namedTypeSymbol.HasAttribute(dataContractAttributeTypeSymbol);
                    bool hasKnownTypeAttribute           = namedTypeSymbol.HasAttribute(knownTypeAttributeTypeSymbol);
                    bool hasAnyIgnoreDataMemberAttribute =
                        namedTypeSymbol.GetMembers().Any(m => m.HasAttribute(ignoreDataMemberTypeSymbol));
                    bool hasAnyXmlSerializationAttributes =
                        xmlSerializationAttributeTypes.HasAnyAttribute(namedTypeSymbol) ||
                        namedTypeSymbol.GetMembers().Any(m => xmlSerializationAttributeTypes.HasAnyAttribute(m));
                    if (!hasSerializableAttribute &&
                        !hasDataContractAttribute &&
                        !hasKnownTypeAttribute &&
                        !hasAnyIgnoreDataMemberAttribute &&
                        !hasAnyXmlSerializationAttributes)
                    {
                        // Don't have any attributes suggesting this class is serialized.
                        return;
                    }

                    bool isProbablyAutogeneratedForGuiApp =
                        namedTypeSymbol.HasAttribute(designerCategoryAttributeTypeSymbol) ||
                        (namedTypeSymbol.BaseType != null &&
                         namedTypeSymbol.BaseType.IsGenericType &&
                         namedTypeSymbol.BaseType.ConstructedFrom.Equals(typedTableBaseTypeSymbol));

                    ObjectGraphOptions options = new ObjectGraphOptions(
                        recurse: false,
                        binarySerialization: hasSerializableAttribute,
                        dataContractSerialization:
                        hasDataContractAttribute ||
                        hasAnyIgnoreDataMemberAttribute ||
                        hasKnownTypeAttribute,
                        xmlSerialization: hasAnyXmlSerializationAttributes);

                    if (decider.IsObjectGraphInsecure(
                            namedTypeSymbol,
                            options,
                            out ImmutableArray <InsecureObjectGraphResult> results))
                    {
                        DiagnosticDescriptor diagnosticToReport;
                        if (hasSerializableAttribute)
                        {
                            diagnosticToReport =
                                isProbablyAutogeneratedForGuiApp
                                            ? RceAutogeneratedSerializableContainsDangerousType
                                            : RceSerializableContainsDangerousType;
                        }
                        else
                        {
                            diagnosticToReport = SerializableContainsDangerousType;
                        }

                        foreach (InsecureObjectGraphResult result in results)
                        {
                            symbolAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    diagnosticToReport,
                                    result.GetLocation(),
                                    result.InsecureType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                    result.GetDisplayString(typedConstant => ToString(typedConstant))));
                        }
                    }
                },
                    SymbolKind.NamedType);
            });
        }
Exemple #14
0
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);

            analysisContext.RegisterCompilationStartAction(startContext =>
            {
                ConcurrentDictionary <INamedTypeSymbol, object?> instantiatedTypes = new ConcurrentDictionary <INamedTypeSymbol, object?>();
                var internalTypes = new ConcurrentDictionary <INamedTypeSymbol, object?>();

                var compilation           = startContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                // If the assembly being built by this compilation exposes its internals to
                // any other assembly, don't report any "uninstantiated internal class" errors.
                // If we were to report an error for an internal type that is not instantiated
                // by this assembly, and then it turned out that the friend assembly did
                // instantiate the type, that would be a false positive. We've decided it's
                // better to have false negatives (which would happen if the type were *not*
                // instantiated by any friend assembly, but we didn't report the issue) than
                // to have false positives.
                var internalsVisibleToAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeCompilerServicesInternalsVisibleToAttribute);
                if (compilation.Assembly.HasAttribute(internalsVisibleToAttributeSymbol))
                {
                    return;
                }

                var systemAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemAttribute);
                var iConfigurationSectionHandlerSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemConfigurationIConfigurationSectionHandler);
                var configurationSectionSymbol         = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemConfigurationConfigurationSection);
                var safeHandleSymbol          = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesSafeHandle);
                var traceListenerSymbol       = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsTraceListener);
                var mef1ExportAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemComponentModelCompositionExportAttribute);
                var mef2ExportAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCompositionExportAttribute);
                var coClassAttributeSymbol    = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesCoClassAttribute);
                var designerAttributeSymbol   = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemComponentModelDesignerAttribute);

                startContext.RegisterOperationAction(context =>
                {
                    var expr = (IObjectCreationOperation)context.Operation;
                    if (expr.Type is INamedTypeSymbol namedType)
                    {
                        instantiatedTypes.TryAdd(namedType, null);
                    }
                }, OperationKind.ObjectCreation);

                startContext.RegisterSymbolAction(context =>
                {
                    var type = (INamedTypeSymbol)context.Symbol;
                    if (!type.IsExternallyVisible() &&
                        !IsOkToBeUnused(type, compilation,
                                        systemAttributeSymbol,
                                        iConfigurationSectionHandlerSymbol,
                                        configurationSectionSymbol,
                                        safeHandleSymbol,
                                        traceListenerSymbol,
                                        mef1ExportAttributeSymbol,
                                        mef2ExportAttributeSymbol))
                    {
                        internalTypes.TryAdd(type, null);
                    }

                    // Instantiation from the subtype constructor initializer.
                    if (type.BaseType != null)
                    {
                        instantiatedTypes.TryAdd(type.BaseType, null);
                    }

                    // Consider class types declared in the CoClassAttribute or DesignerAttribute as instantiated
                    if ((coClassAttributeSymbol != null || designerAttributeSymbol != null) &&
                        (type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Interface))
                    {
                        bool isCoClassHandled = false;
                        foreach (var attribute in type.GetAttributes())
                        {
                            if (coClassAttributeSymbol != null &&
                                !isCoClassHandled &&
                                attribute.AttributeClass.Equals(coClassAttributeSymbol))
                            {
                                isCoClassHandled = true;
                                if (attribute.ConstructorArguments.Length == 1 &&
                                    attribute.ConstructorArguments[0].Kind == TypedConstantKind.Type &&
                                    attribute.ConstructorArguments[0].Value is INamedTypeSymbol typeSymbol &&
                                    typeSymbol.TypeKind == TypeKind.Class)
                                {
                                    instantiatedTypes.TryAdd(typeSymbol, null);
                                }
                            }

                            if (designerAttributeSymbol != null &&
                                (attribute.ConstructorArguments.Length == 1 || attribute.ConstructorArguments.Length == 2) &&
                                attribute.AttributeClass.Equals(designerAttributeSymbol))
                            {
                                switch (attribute.ConstructorArguments[0].Value)
                                {
                                case string designerTypeName when designerTypeName != null:
                                    {
                                        var nameParts = designerTypeName.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                        if (nameParts.Length >= 2 &&
                                            nameParts[1].Trim().Equals(context.Compilation.AssemblyName, StringComparison.Ordinal) &&
                                            wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(nameParts[0].Trim(), out var namedType) &&
                                            namedType.ContainingAssembly.Equals(compilation.Assembly))
                                        {
                                            instantiatedTypes.TryAdd(namedType, null);
                                        }
                                        break;
                                    }

                                case INamedTypeSymbol namedType when namedType != null:
                                    instantiatedTypes.TryAdd(namedType, null);
                                    break;
                                }
                            }
                        }
                    }
                }, SymbolKind.NamedType);

                // If a type is passed a generic argument to another type or a method that specifies that the type must have a constructor,
                // we presume that the method will be constructing the type, and add it to the list of instantiated types.

                void ProcessGenericTypes(IEnumerable <(ITypeParameterSymbol param, ITypeSymbol arg)> generics)
                {
                    foreach (var(typeParam, typeArg) in generics)
                    {
                        if (typeParam.HasConstructorConstraint)
                        {
                            void ProcessNamedTypeParamConstraint(INamedTypeSymbol namedTypeArg)
                            {
                                if (!instantiatedTypes.TryAdd(namedTypeArg, null))
                                {
                                    // Already processed.
                                    return;
                                }

                                // We need to handle if this type param also has type params that have a generic constraint. Take the following example:
                                // new Factory1<Factory2<InstantiatedType>>();
                                // In this example, Factory1 and Factory2 have type params with constructor constraints. Therefore, we need to add all 3
                                // types to the list of types that have actually been instantiated. However, in the following example:
                                // new List<Factory<InstantiatedType>>();
                                // List does not have a constructor constraint, so we can't reasonably infer anything about its type parameters.
                                if (namedTypeArg.IsGenericType)
                                {
                                    var newGenerics = namedTypeArg.TypeParameters.Zip(namedTypeArg.TypeArguments, (parameter, argument) => (parameter, argument));
                                    ProcessGenericTypes(newGenerics);
                                }
                            };

                            if (typeArg is INamedTypeSymbol namedType)
                            {
                                ProcessNamedTypeParamConstraint(namedType);
                            }
                            else if (typeArg is ITypeParameterSymbol typeParameterArg && !typeParameterArg.ConstraintTypes.IsEmpty)
                            {
Exemple #15
0
 /// <summary>
 /// Gets a type by its full type name and cache it at the compilation level.
 /// </summary>
 /// <param name="compilation">The compilation.</param>
 /// <param name="fullTypeName">Namespace + type name, e.g. "System.Exception".</param>
 /// <returns>The <see cref="INamedTypeSymbol"/> if found, null otherwise.</returns>
 internal static bool TryGetOrCreateTypeByMetadataName(this Compilation compilation, string fullTypeName, out INamedTypeSymbol namedTypeSymbol) =>
 WellKnownTypeProvider.GetOrCreate(compilation).TryGetOrCreateTypeByMetadataName(fullTypeName, out namedTypeSymbol);
        internal static async Task <(int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics)> ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(
            ImmutableArray <SyntaxReference> declarations,
            ISymbol symbol,
            ImmutableHashSet <INamedTypeSymbol> .Builder builder,
            CodeMetricsAnalysisContext context)
        {
            int cyclomaticComplexity = 0;
            ComputationalComplexityMetrics computationalComplexityMetrics = ComputationalComplexityMetrics.Default;

            var nodesToProcess = new Queue <SyntaxNode>();

            using var applicableAttributeNodes = PooledHashSet <SyntaxNode> .GetInstance();

            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(context.Compilation);

            foreach (var declaration in declarations)
            {
                SyntaxNode syntax = await GetTopmostSyntaxNodeForDeclarationAsync(declaration, symbol, context).ConfigureAwait(false);

                nodesToProcess.Enqueue(syntax);

                // Ensure we process parameter initializers and attributes.
                var parameters = GetParameters(symbol);
                foreach (var parameter in parameters)
                {
                    var parameterSyntaxRef = parameter.DeclaringSyntaxReferences.FirstOrDefault();
                    if (parameterSyntaxRef != null)
                    {
                        var parameterSyntax = await parameterSyntaxRef.GetSyntaxAsync(context.CancellationToken).ConfigureAwait(false);

                        nodesToProcess.Enqueue(parameterSyntax);
                    }
                }

                var attributes = symbol.GetAttributes();
                if (symbol is IMethodSymbol methodSymbol)
                {
                    attributes = attributes.AddRange(methodSymbol.GetReturnTypeAttributes());
                }

                foreach (var attribute in attributes)
                {
                    if (attribute.ApplicationSyntaxReference != null &&
                        attribute.ApplicationSyntaxReference.SyntaxTree == declaration.SyntaxTree)
                    {
                        var attributeSyntax = await attribute.ApplicationSyntaxReference.GetSyntaxAsync(context.CancellationToken).ConfigureAwait(false);

                        if (applicableAttributeNodes.Add(attributeSyntax))
                        {
                            nodesToProcess.Enqueue(attributeSyntax);
                        }
                    }
                }

                do
                {
                    var node  = nodesToProcess.Dequeue();
                    var model = context.GetSemanticModel(node);

                    if (!ReferenceEquals(node, syntax))
                    {
                        var declaredSymbol = model.GetDeclaredSymbol(node, context.CancellationToken);
                        if (declaredSymbol != null && !Equals(symbol, declaredSymbol) && declaredSymbol.Kind != SymbolKind.Parameter)
                        {
                            // Skip member declarations.
                            continue;
                        }
                    }

                    var typeInfo = model.GetTypeInfo(node, context.CancellationToken);
                    AddCoupledNamedTypesCore(builder, typeInfo.Type, wellKnownTypeProvider);

                    var operationBlock = model.GetOperation(node, context.CancellationToken);
                    if (operationBlock != null && operationBlock.Parent == null)
                    {
                        switch (operationBlock.Kind)
                        {
                        case OperationKind.Block:
                        case OperationKind.MethodBodyOperation:
                        case OperationKind.ConstructorBodyOperation:
                            cyclomaticComplexity += 1;
                            break;

                        case OperationKind.None:
                            // Skip non-applicable attributes.
                            if (!applicableAttributeNodes.Contains(node))
                            {
                                continue;
                            }

                            break;
                        }

                        computationalComplexityMetrics = computationalComplexityMetrics.Union(ComputationalComplexityMetrics.Compute(operationBlock));

                        // Add used types within executable code in the operation tree.
                        foreach (var operation in operationBlock.DescendantsAndSelf())
                        {
#if LEGACY_CODE_METRICS_MODE
                            // Legacy mode does not account for code within lambdas/local functions for code metrics.
                            if (operation.IsWithinLambdaOrLocalFunction())
                            {
                                continue;
                            }
#endif

                            if (!operation.IsImplicit && hasConditionalLogic(operation))
                            {
                                cyclomaticComplexity += 1;
                            }

                            AddCoupledNamedTypesCore(builder, operation.Type, wellKnownTypeProvider);

                            // Handle static member accesses specially as there is no operation for static type off which the member is accessed.
                            if (operation is IMemberReferenceOperation memberReference &&
                                memberReference.Member.IsStatic)
                            {
                                AddCoupledNamedTypesCore(builder, memberReference.Member.ContainingType, wellKnownTypeProvider);
                            }
                            else if (operation is IInvocationOperation invocation &&
                                     (invocation.TargetMethod.IsStatic || invocation.TargetMethod.IsExtensionMethod))
                            {
                                AddCoupledNamedTypesCore(builder, invocation.TargetMethod.ContainingType, wellKnownTypeProvider);
                            }
                        }
                    }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartContext) =>
            {
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartContext.Compilation);
                INamedTypeSymbol?mvcControllerSymbol        = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcController);
                INamedTypeSymbol?mvcControllerBaseSymbol    = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcControllerBase);
                INamedTypeSymbol?actionResultSymbol         = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcActionResult);

                if ((mvcControllerSymbol == null && mvcControllerBaseSymbol == null) || actionResultSymbol == null)
                {
                    // No MVC controllers that return an ActionResult here.
                    return;
                }

                MvcAttributeSymbols mvcAttributeSymbols = new MvcAttributeSymbols(compilationStartContext.Compilation);

                compilationStartContext.RegisterSymbolAction(
                    (SymbolAnalysisContext symbolContext) =>
                {
                    // TODO enhancements: Consider looking at IAsyncResult-based action methods.
                    if (symbolContext.Symbol is not IMethodSymbol methodSymbol ||
                        methodSymbol.MethodKind != MethodKind.Ordinary ||
                        methodSymbol.IsStatic ||
                        !methodSymbol.IsPublic() ||
                        !(methodSymbol.ReturnType.Inherits(actionResultSymbol) ||          // FxCop implementation only looked at ActionResult-derived return types.
                          wellKnownTypeProvider.IsTaskOfType(
                              methodSymbol.ReturnType,
                              (ITypeSymbol typeArgument) => typeArgument.Inherits(actionResultSymbol))) ||
                        (!methodSymbol.ContainingType.Inherits(mvcControllerSymbol) &&
                         !methodSymbol.ContainingType.Inherits(mvcControllerBaseSymbol)))
                    {
                        return;
                    }

                    ImmutableArray <AttributeData> methodAttributes = methodSymbol.GetAttributes();
                    mvcAttributeSymbols.ComputeAttributeInfo(methodAttributes, out var verbs, out var isAntiforgeryTokenDefined, out var isAction);

                    if (!isAction)
                    {
                        return;
                    }

                    if (verbs == MvcHttpVerbs.None)
                    {
                        // no verbs specified
                        if (isAntiforgeryTokenDefined)
                        {
                            // antiforgery token attribute is set, but verbs are not specified
                            symbolContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(NoVerbsRule, methodSymbol.MetadataName));
                        }
                        else
                        {
                            // no verbs, no antiforgery token attribute
                            symbolContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(NoVerbsNoTokenRule, methodSymbol.MetadataName));
                        }
                    }
                    else
                    {
                        // verbs are defined
                        if (isAntiforgeryTokenDefined)
                        {
                            if (verbs.HasFlag(MvcHttpVerbs.Get))
                            {
                                symbolContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(GetAndTokenRule, methodSymbol.MetadataName));

                                if ((verbs & (MvcHttpVerbs.Post | MvcHttpVerbs.Put | MvcHttpVerbs.Delete | MvcHttpVerbs.Patch)) != MvcHttpVerbs.None)
                                {
                                    // both verbs, antiforgery token attribute
                                    symbolContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(GetAndOtherAndTokenRule, methodSymbol.MetadataName));
                                }
                            }
                        }
                        else
                        {
                            if ((verbs & (MvcHttpVerbs.Post | MvcHttpVerbs.Put | MvcHttpVerbs.Delete | MvcHttpVerbs.Patch)) != MvcHttpVerbs.None)
                            {
                                // HttpPost, no antiforgery token attribute
                                symbolContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(VerbsAndNoTokenRule, methodSymbol.MetadataName));
                            }
                        }
                    }
                },
                    SymbolKind.Method);
            }
                );
        }
        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 =>
            {
                var compilation           = compilationStartAnalysisContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesDllImportAttribute, out INamedTypeSymbol? dllImportAttributeTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesDefaultDllImportSearchPathsAttribute, out INamedTypeSymbol? defaultDllImportSearchPathsAttributeTypeSymbol) ||
                    compilationStartAnalysisContext.Compilation.SyntaxTrees.FirstOrDefault() is not SyntaxTree tree)
                {
                    return;
                }

                var cancellationToken             = compilationStartAnalysisContext.CancellationToken;
                var unsafeDllImportSearchPathBits = compilationStartAnalysisContext.Options.GetUnsignedIntegralOptionValue(
                    optionName: EditorConfigOptionNames.UnsafeDllImportSearchPathBits,
                    rule: DoNotUseUnsafeDllImportSearchPathRule,
                    tree,
                    compilationStartAnalysisContext.Compilation,
                    defaultValue: UnsafeBits,
                    cancellationToken: cancellationToken);
                var defaultDllImportSearchPathsAttributeOnAssembly = compilation.Assembly.GetAttributes().FirstOrDefault(o => o.AttributeClass.Equals(defaultDllImportSearchPathsAttributeTypeSymbol));

                compilationStartAnalysisContext.RegisterSymbolAction(symbolAnalysisContext =>
                {
                    var symbol = symbolAnalysisContext.Symbol;

                    if (!symbol.IsExtern || !symbol.IsStatic)
                    {
                        return;
                    }

                    var dllImportAttribute = symbol.GetAttributes().FirstOrDefault(s => s.AttributeClass.Equals(dllImportAttributeTypeSymbol));
                    var defaultDllImportSearchPathsAttribute = symbol.GetAttributes().FirstOrDefault(s => s.AttributeClass.Equals(defaultDllImportSearchPathsAttributeTypeSymbol));

                    if (dllImportAttribute != null)
                    {
                        var constructorArguments = dllImportAttribute.ConstructorArguments;

                        if (constructorArguments.IsEmpty)
                        {
                            return;
                        }

                        if (Path.IsPathRooted(constructorArguments[0].Value.ToString()))
                        {
                            return;
                        }

                        var rule         = UseDefaultDllImportSearchPathsAttributeRule;
                        var ruleArgument = symbol.Name;
                        var validatedDefaultDllImportSearchPathsAttribute = defaultDllImportSearchPathsAttribute ?? defaultDllImportSearchPathsAttributeOnAssembly;

                        if (validatedDefaultDllImportSearchPathsAttribute != null)
                        {
                            var dllImportSearchPath = (int)validatedDefaultDllImportSearchPathsAttribute.ConstructorArguments.FirstOrDefault().Value;
                            var validBits           = dllImportSearchPath & unsafeDllImportSearchPathBits;

                            if (dllImportSearchPath != LegacyBehavior &&
                                validBits == 0)
                            {
                                return;
                            }

                            rule         = DoNotUseUnsafeDllImportSearchPathRule;
                            ruleArgument = ((DllImportSearchPath)validBits).ToString();
                        }

                        symbolAnalysisContext.ReportDiagnostic(
                            symbol.CreateDiagnostic(
                                rule,
                                ruleArgument));
                    }
                }, SymbolKind.Method);
            });
        }
#pragma warning disable RS1026 // Enable concurrent execution
        public override void Initialize(AnalysisContext analysisContext)
#pragma warning restore RS1026 // Enable concurrent execution
        {
            // TODO: Consider making this analyzer thread-safe.
            //analysisContext.EnableConcurrentExecution();

            // Don't report in generated code since that's not actionable.
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            analysisContext.RegisterCompilationStartAction(compilationContext =>
            {
                // Since property/event accessors cannot be marked static themselves and the associated symbol (property/event)
                // has to be marked static, we want to report the diagnostic on the property/event.
                // So we make a note of the property/event symbols which have at least one accessor with no instance access.
                // At compilation end, we report candidate property/event symbols whose all accessors are candidates to be marked static.
                var propertyOrEventCandidates = new HashSet <ISymbol>();
                var accessorCandidates        = new HashSet <IMethodSymbol>();

                // For candidate methods that are not externally visible, we only report a diagnostic if they are actually invoked via a method call in the compilation.
                // This prevents us from incorrectly flagging methods that are only invoked via delegate invocations: https://github.com/dotnet/roslyn-analyzers/issues/1511
                // and also reduces noise by not flagging dead code.
                var internalCandidates     = new HashSet <IMethodSymbol>();
                var invokedInternalMethods = new HashSet <IMethodSymbol>();

                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationContext.Compilation);

                // Get the list of all method' attributes for which the rule shall not be triggered.
                ImmutableArray <INamedTypeSymbol> skippedAttributes = GetSkippedAttributes(wellKnownTypeProvider);

                compilationContext.RegisterOperationBlockStartAction(blockStartContext =>
                {
                    if (!(blockStartContext.OwningSymbol is IMethodSymbol methodSymbol))
                    {
                        return;
                    }

                    // Whatever the method is, we want to store the not externally visible method calls.
                    blockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var invocation = (IInvocationOperation)operationContext.Operation;
                        if (!invocation.TargetMethod.IsExternallyVisible())
                        {
                            invokedInternalMethods.Add(invocation.TargetMethod);
                        }
                    }, OperationKind.Invocation);

                    // Don't run any other check for this method if it isn't a valid analysis context
                    if (!ShouldAnalyze(methodSymbol, wellKnownTypeProvider, skippedAttributes))
                    {
                        return;
                    }

                    bool isInstanceReferenced = false;

                    blockStartContext.RegisterOperationAction(operationContext =>
                    {
                        if (((IInstanceReferenceOperation)operationContext.Operation).ReferenceKind == InstanceReferenceKind.ContainingTypeInstance)
                        {
                            isInstanceReferenced = true;
                        }
                    }, OperationKind.InstanceReference);

                    blockStartContext.RegisterOperationBlockEndAction(blockEndContext =>
                    {
                        // Methods referenced by other non static methods
                        // and methods containing only NotImplementedException should not considered for marking them as static
                        if (!isInstanceReferenced && !blockEndContext.IsMethodNotImplementedOrSupported())
                        {
                            if (methodSymbol.IsAccessorMethod())
                            {
                                accessorCandidates.Add(methodSymbol);
                                propertyOrEventCandidates.Add(methodSymbol.AssociatedSymbol);
                            }
                            else if (methodSymbol.IsExternallyVisible())
                            {
                                blockEndContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name));
                            }
                            else
                            {
                                internalCandidates.Add(methodSymbol);
                            }
                        }
                    });
                });

                compilationContext.RegisterCompilationEndAction(compilationEndContext =>
                {
                    foreach (var candidate in internalCandidates)
                    {
                        if (invokedInternalMethods.Contains(candidate))
                        {
                            compilationEndContext.ReportDiagnostic(candidate.CreateDiagnostic(Rule, candidate.Name));
                        }
                    }

                    foreach (var candidatePropertyOrEvent in propertyOrEventCandidates)
                    {
                        var allAccessorsAreCandidates = true;
                        foreach (var accessor in candidatePropertyOrEvent.GetAccessors())
                        {
                            if (!accessorCandidates.Contains(accessor))
                            {
                                allAccessorsAreCandidates = false;
                                break;
                            }
                        }

                        if (allAccessorsAreCandidates)
                        {
                            compilationEndContext.ReportDiagnostic(candidatePropertyOrEvent.CreateDiagnostic(Rule, candidatePropertyOrEvent.Name));
                        }
                    }
                });
            });
        }
Exemple #20
0
            internal static async Task <NamedTypeMetricData> ComputeAsync(INamedTypeSymbol namedType, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(semanticModelProvider.Compilation);

                var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>();
                ImmutableArray <SyntaxReference> declarations = namedType.DeclaringSyntaxReferences;

                (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) =
                    await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, namedType, coupledTypesBuilder, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                // Compat: Filter out nested types as they are children of most closest containing namespace.
                var members = namedType.GetMembers().Where(m => m.Kind != SymbolKind.NamedType);

#if LEGACY_CODE_METRICS_MODE
                // Legacy mode skips metrics for field/property/event symbols, and explicitly includes accessors as methods.
                members = members.Where(m => m.Kind != SymbolKind.Field && m.Kind != SymbolKind.Property && m.Kind != SymbolKind.Event);
#else
                // Filter out accessors as they are children of their associated symbols, for which we generate a separate node.
                members = members.Where(m => m.Kind != SymbolKind.Method || ((IMethodSymbol)m).AssociatedSymbol == null);
#endif

                ImmutableArray <CodeAnalysisMetricData> children = await ComputeAsync(members, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                // Heuristic to prevent simple fields (no initializer or simple initializer) from skewing the complexity.
                ImmutableHashSet <IFieldSymbol> filteredFieldsForComplexity = getFilteredFieldsForComplexity();

                int effectiveChildrenCountForComplexity      = 0;
                int singleEffectiveChildMaintainabilityIndex = -1;
                foreach (CodeAnalysisMetricData child in children)
                {
                    MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, wellKnownTypeProvider, child.CoupledNamedTypes);

                    if (child.Symbol.Kind != SymbolKind.Field ||
                        filteredFieldsForComplexity.Contains((IFieldSymbol)child.Symbol))
                    {
                        singleEffectiveChildMaintainabilityIndex = effectiveChildrenCountForComplexity == 0 && computationalComplexityMetrics.IsDefault ?
                                                                   child.MaintainabilityIndex :
                                                                   -1;
                        effectiveChildrenCountForComplexity++;
                        cyclomaticComplexity          += child.CyclomaticComplexity;
                        computationalComplexityMetrics = computationalComplexityMetrics.Union(child.ComputationalComplexityMetrics);
                    }
                }

                if (cyclomaticComplexity == 0 && !namedType.IsStatic)
                {
                    // Empty named type, account for implicit constructor.
                    cyclomaticComplexity = 1;
                }

                int  depthOfInheritance = CalculateDepthOfInheritance(namedType);
                long linesOfCode        = await MetricsHelper.GetLinesOfCodeAsync(declarations, namedType, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                int maintainabilityIndex = singleEffectiveChildMaintainabilityIndex != -1 ?
                                           singleEffectiveChildMaintainabilityIndex :
                                           CalculateMaintainabilityIndex(computationalComplexityMetrics, cyclomaticComplexity, effectiveChildrenCountForComplexity);
                MetricsHelper.RemoveContainingTypes(namedType, coupledTypesBuilder);

                return(new NamedTypeMetricData(namedType, maintainabilityIndex, computationalComplexityMetrics,
                                               coupledTypesBuilder.ToImmutable(), linesOfCode, cyclomaticComplexity, depthOfInheritance, children));

                ImmutableHashSet <IFieldSymbol> getFilteredFieldsForComplexity()
                {
                    ImmutableHashSet <IFieldSymbol> .Builder?builderOpt = null;
                    var orderedFieldDatas = children.Where(c => c.Symbol.Kind == SymbolKind.Field).OrderBy(c => c.MaintainabilityIndex);
                    var indexThreshold    = 99;

                    foreach (CodeAnalysisMetricData fieldData in orderedFieldDatas)
                    {
                        if (fieldData.MaintainabilityIndex > indexThreshold)
                        {
                            break;
                        }

                        builderOpt ??= ImmutableHashSet.CreateBuilder <IFieldSymbol>();
                        builderOpt.Add((IFieldSymbol)fieldData.Symbol);
                        indexThreshold -= 4;
                    }

                    return(builderOpt?.ToImmutable() ?? ImmutableHashSet <IFieldSymbol> .Empty);
                }
            }
        public sealed override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);

            context.RegisterCompilationStartAction(startContext =>
            {
                ConcurrentDictionary <INamedTypeSymbol, object?> instantiatedTypes = new ConcurrentDictionary <INamedTypeSymbol, object?>();
                var internalTypes = new ConcurrentDictionary <INamedTypeSymbol, object?>();

                var compilation           = startContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                // If the assembly being built by this compilation exposes its internals to
                // any other assembly, don't report any "uninstantiated internal class" errors.
                // If we were to report an error for an internal type that is not instantiated
                // by this assembly, and then it turned out that the friend assembly did
                // instantiate the type, that would be a false positive. We've decided it's
                // better to have false negatives (which would happen if the type were *not*
                // instantiated by any friend assembly, but we didn't report the issue) than
                // to have false positives.
                var internalsVisibleToAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeCompilerServicesInternalsVisibleToAttribute);
                if (compilation.Assembly.HasAttribute(internalsVisibleToAttributeSymbol))
                {
                    return;
                }

                var systemAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemAttribute);
                var iConfigurationSectionHandlerSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemConfigurationIConfigurationSectionHandler);
                var configurationSectionSymbol         = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemConfigurationConfigurationSection);
                var safeHandleSymbol          = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesSafeHandle);
                var traceListenerSymbol       = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsTraceListener);
                var mef1ExportAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemComponentModelCompositionExportAttribute);
                var mef2ExportAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCompositionExportAttribute);

                var coClassAttributeSymbol           = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesCoClassAttribute);
                var designerAttributeSymbol          = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemComponentModelDesignerAttribute);
                var debuggerTypeProxyAttributeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsDebuggerTypeProxyAttribute);

                var instantiatingAttributeChecker = new List <(Func <INamedTypeSymbol, bool> isAttributeTarget, Func <AttributeData, Compilation, INamedTypeSymbol?> findTypeOrDefault)>
                {
                    (type => CanBeCoClassAttributeContext(type), (attribute, _) => FindTypeIfCoClassAttribute(attribute)),
                    (type => CanBeDesignerAttributeContext(type), (attribute, compilation) => FindTypeIfDesignerAttribute(attribute, compilation)),
                    (type => CanBeDebuggerTypeProxyAttributeContext(type), (attribute, compilation) => FindTypeIfDebuggerTypeProxyAttribute(attribute, compilation)),
                };

                RegisterLanguageSpecificChecks(startContext, instantiatedTypes);

                startContext.RegisterOperationAction(context =>
                {
                    var expr = (IObjectCreationOperation)context.Operation;
                    if (expr.Type is INamedTypeSymbol namedType)
                    {
                        instantiatedTypes.TryAdd(namedType, null);
                    }
                }, OperationKind.ObjectCreation);

                startContext.RegisterSymbolAction(context =>
                {
                    var type = (INamedTypeSymbol)context.Symbol;
                    if (!type.IsExternallyVisible() &&
                        !IsOkToBeUninstantiated(type, compilation,
                                                systemAttributeSymbol,
                                                iConfigurationSectionHandlerSymbol,
                                                configurationSectionSymbol,
                                                safeHandleSymbol,
                                                traceListenerSymbol,
                                                mef1ExportAttributeSymbol,
                                                mef2ExportAttributeSymbol))
                    {
                        internalTypes.TryAdd(type, null);
                    }

                    // Instantiation from the subtype constructor initializer.
                    if (type.BaseType != null)
                    {
                        instantiatedTypes.TryAdd(type.BaseType, null);
                    }

                    // Some attributes are known to behave as type activator so we want to check them
                    var applicableAttributes = instantiatingAttributeChecker.Where(tuple => tuple.isAttributeTarget(type)).ToArray();
                    foreach (var attribute in type.GetAttributes())
                    {
                        foreach (var(_, findTypeOrDefault) in applicableAttributes)
                        {
                            if (findTypeOrDefault(attribute, context.Compilation) is INamedTypeSymbol namedType)
                            {
                                instantiatedTypes.TryAdd(namedType, null);
                                break;
                            }
                        }
                    }
                }, SymbolKind.NamedType);

                startContext.RegisterOperationAction(context =>
                {
                    var expr             = (IObjectCreationOperation)context.Operation;
                    var constructedClass = (INamedTypeSymbol)expr.Type;

                    if (!constructedClass.IsGenericType || constructedClass.IsUnboundGenericType)
                    {
                        return;
                    }

                    var generics = constructedClass.TypeParameters.Zip(constructedClass.TypeArguments, (parameter, argument) => (parameter, argument));
                    ProcessGenericTypes(generics, instantiatedTypes);
                }, OperationKind.ObjectCreation);

                startContext.RegisterOperationAction(context =>
                {
                    var expr       = (IInvocationOperation)context.Operation;
                    var methodType = expr.TargetMethod;

                    if (!methodType.IsGenericMethod)
                    {
                        return;
                    }

                    var generics = methodType.TypeParameters.Zip(methodType.TypeArguments, (parameter, argument) => (parameter, argument));
                    ProcessGenericTypes(generics, instantiatedTypes);
                }, OperationKind.Invocation);

                startContext.RegisterCompilationEndAction(context =>
                {
                    var uninstantiatedInternalTypes = internalTypes
                                                      .Select(it => it.Key.OriginalDefinition)
                                                      .Except(instantiatedTypes.Select(it => it.Key.OriginalDefinition))
                                                      .Where(type => !HasInstantiatedNestedType(type, instantiatedTypes.Keys));

                    foreach (var type in uninstantiatedInternalTypes)
                    {
                        context.ReportDiagnostic(type.CreateDiagnostic(Rule, type.FormatMemberName()));
                    }
                });

                return;

                // Local functions

                bool CanBeCoClassAttributeContext(INamedTypeSymbol type)
                => coClassAttributeSymbol != null && type.TypeKind == TypeKind.Interface;

                INamedTypeSymbol?FindTypeIfCoClassAttribute(AttributeData attribute)
                {
                    RoslynDebug.Assert(coClassAttributeSymbol != null);

                    if (attribute.AttributeClass.Equals(coClassAttributeSymbol) &&
                        attribute.ConstructorArguments.Length == 1 &&
                        attribute.ConstructorArguments[0].Kind == TypedConstantKind.Type &&
                        attribute.ConstructorArguments[0].Value is INamedTypeSymbol typeSymbol &&
                        typeSymbol.TypeKind == TypeKind.Class)
                    {
                        return(typeSymbol);
                    }

                    return(null);
                }

                bool CanBeDesignerAttributeContext(INamedTypeSymbol type)
                => designerAttributeSymbol != null && (type.TypeKind == TypeKind.Interface || type.TypeKind == TypeKind.Class);

                INamedTypeSymbol?FindTypeIfDesignerAttribute(AttributeData attribute, Compilation compilation)
                {
                    RoslynDebug.Assert(designerAttributeSymbol != null);

                    if (attribute.ConstructorArguments.Length is not(1 or 2) ||
                        !attribute.AttributeClass.Equals(designerAttributeSymbol))
                    {
                        return(null);
                    }

                    switch (attribute.ConstructorArguments[0].Value)
                    {
                    case string designerTypeName:
                        {
                            if (IsTypeInCurrentAssembly(designerTypeName, compilation, out var namedType))
                            {
                                return(namedType);
                            }
                            break;
                        }

                    case INamedTypeSymbol namedType:
                        return(namedType);
                    }

                    return(null);
                }

                bool CanBeDebuggerTypeProxyAttributeContext(INamedTypeSymbol type)
                => debuggerTypeProxyAttributeSymbol != null && (type.TypeKind == TypeKind.Struct || type.TypeKind == TypeKind.Class);

                INamedTypeSymbol?FindTypeIfDebuggerTypeProxyAttribute(AttributeData attribute, Compilation compilation)
                {
                    RoslynDebug.Assert(debuggerTypeProxyAttributeSymbol != null);

                    if (!attribute.AttributeClass.Equals(debuggerTypeProxyAttributeSymbol))
                    {
                        return(null);
                    }

                    switch (attribute.ConstructorArguments[0].Value)
                    {
                    case string typeName:
                        {
                            if (IsTypeInCurrentAssembly(typeName, compilation, out var namedType))
                            {
                                return(namedType);
                            }
                            break;
                        }

                    case INamedTypeSymbol namedType:
                        return(namedType);
                    }

                    return(null);
                }
            });
        }
        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 =>
            {
                var microsoftWindowsAzureStorageNamespaceSymbol = compilationStartAnalysisContext
                                                                  .Compilation
                                                                  .GlobalNamespace
                                                                  .GetMembers("Microsoft")
                                                                  .FirstOrDefault()
                                                                  ?.GetMembers("WindowsAzure")
                                                                  .OfType <INamespaceSymbol>()
                                                                  .FirstOrDefault()
                                                                  ?.GetMembers("Storage")
                                                                  .OfType <INamespaceSymbol>()
                                                                  .FirstOrDefault();

                if (microsoftWindowsAzureStorageNamespaceSymbol == null)
                {
                    return;
                }

                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.MicrosoftWindowsAzureStorageCloudStorageAccount,
                    out INamedTypeSymbol cloudStorageAccountTypeSymbol);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemNullable1, out INamedTypeSymbol nullableTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftWindowsAzureStorageSharedAccessProtocol, out INamedTypeSymbol sharedAccessProtocolTypeSymbol))
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(operationBlockStartContext =>
                {
                    var owningSymbol = operationBlockStartContext.OwningSymbol;
                    if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, Rule,
                                                                operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken))
                    {
                        return;
                    }

                    operationBlockStartContext.RegisterOperationAction(operationAnalysisContext =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        var methodSymbol        = invocationOperation.TargetMethod;

                        if (methodSymbol.Name != "GetSharedAccessSignature")
                        {
                            return;
                        }

                        var namespaceSymbol = methodSymbol.ContainingNamespace;

                        while (namespaceSymbol != null)
                        {
                            if (namespaceSymbol.Equals(microsoftWindowsAzureStorageNamespaceSymbol))
                            {
                                break;
                            }

                            namespaceSymbol = namespaceSymbol.ContainingNamespace;
                        }

                        if (namespaceSymbol == null)
                        {
                            return;
                        }

                        var typeSymbol = methodSymbol.ContainingType;

                        if (!typeSymbol.Equals(cloudStorageAccountTypeSymbol))
                        {
                            var protocolsArgumentOperation = invocationOperation.Arguments.FirstOrDefault(s => s.Parameter.Name == "protocols" &&
                                                                                                          s.Parameter.Type is INamedTypeSymbol namedTypeSymbol &&
                                                                                                          namedTypeSymbol.IsGenericType &&
                                                                                                          namedTypeSymbol.ConstructedFrom.Equals(nullableTypeSymbol) &&
                                                                                                          namedTypeSymbol.TypeArguments.Length == 1 &&
                                                                                                          namedTypeSymbol.TypeArguments.Contains(sharedAccessProtocolTypeSymbol));

                            if (protocolsArgumentOperation != null)
                            {
                                var cfg = invocationOperation.GetTopmostParentBlock()?.GetEnclosingControlFlowGraph();
                                if (cfg != null)
                                {
                                    var interproceduralAnalysisConfig = InterproceduralAnalysisConfiguration.Create(
                                        operationBlockStartContext.Options,
                                        SupportedDiagnostics,
                                        defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.None,
                                        cancellationToken: operationBlockStartContext.CancellationToken,
                                        defaultMaxInterproceduralMethodCallChain: 1);
                                    var valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                                        cfg,
                                        owningSymbol,
                                        operationAnalysisContext.Options,
                                        wellKnownTypeProvider,
                                        interproceduralAnalysisConfig,
                                        out var copyAnalysisResult,
                                        out var pointsToAnalysisResult);
                                    if (valueContentAnalysisResult == null)
                                    {
                                        return;
                                    }

                                    var protocolsArgument = valueContentAnalysisResult[protocolsArgumentOperation.Kind, protocolsArgumentOperation.Syntax];

                                    if (protocolsArgument.IsLiteralState &&
                                        !protocolsArgument.LiteralValues.Contains(SharedAccessProtocolHttpsOnly))
                                    {
                                        operationAnalysisContext.ReportDiagnostic(
                                            invocationOperation.CreateDiagnostic(
                                                Rule));
                                    }
                                }
                            }
                        }
                    }, OperationKind.Invocation);
                });
            });
        }
Exemple #23
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection(
                new HazardousUsageEvaluator("GetBytes", HazardousUsageCallback));

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes, out var rfc2898DeriveBytesTypeSymbol))
                {
                    return;
                }

                var cancellationToken        = compilationStartAnalysisContext.CancellationToken;
                var sufficientIterationCount = compilationStartAnalysisContext.Options.GetUnsignedIntegralOptionValue(
                    optionName: EditorConfigOptionNames.SufficientIterationCountForWeakKDFAlgorithm,
                    rule: DefinitelyUseWeakKDFInsufficientIterationCountRule,
                    defaultValue: 100000,
                    cancellationToken: cancellationToken);
                var constructorMapper = new ConstructorMapper(
                    (IMethodSymbol constructorMethod, IReadOnlyList <ValueContentAbstractValue> argumentValueContentAbstractValues,
                     IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) =>
                {
                    var kind = DefaultIterationCount >= sufficientIterationCount ? PropertySetAbstractValueKind.Unflagged : PropertySetAbstractValueKind.Flagged;

                    if (constructorMethod.Parameters.Length >= 3)
                    {
                        if (constructorMethod.Parameters[2].Name == "iterations" &&
                            constructorMethod.Parameters[2].Type.SpecialType == SpecialType.System_Int32)
                        {
                            kind = PropertySetCallbacks.EvaluateLiteralValues(argumentValueContentAbstractValues[2], o => Convert.ToInt32(o) < sufficientIterationCount);
                        }
                    }

                    return(PropertySetAbstractValue.GetInstance(kind));
                });
                var propertyMappers = new PropertyMapperCollection(
                    new PropertyMapper(
                        "IterationCount",
                        (ValueContentAbstractValue valueContentAbstractValue) =>
                {
                    return(PropertySetCallbacks.EvaluateLiteralValues(valueContentAbstractValue, o => Convert.ToInt32(o) < sufficientIterationCount));
                }));
                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;

                        if (rfc2898DeriveBytesTypeSymbol.Equals(invocationOperation.Instance?.Type) &&
                            invocationOperation.TargetMethod.Name == "GetBytes")
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (rfc2898DeriveBytesTypeSymbol.Equals(argumentOperation.Parameter.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes,
                                constructorMapper,
                                propertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: cancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyUseWeakKDFInsufficientIterationCountRule;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeUseWeakKDFInsufficientIterationCountRule;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    sufficientIterationCount));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
        public sealed override void Initialize(AnalysisContext context)
        {
            ImmutableHashSet <string> cachedDeserializationMethodNames = this.DeserializationMethodNames;

            Debug.Assert(!String.IsNullOrWhiteSpace(this.DeserializerTypeMetadataName));
            Debug.Assert(!String.IsNullOrWhiteSpace(this.SerializationBinderPropertyMetadataName));
            Debug.Assert(cachedDeserializationMethodNames != null);
            Debug.Assert(!cachedDeserializationMethodNames.IsEmpty);
            Debug.Assert(this.BinderDefinitelyNotSetDescriptor != null);
            Debug.Assert(this.BinderMaybeNotSetDescriptor != null);

            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            // For PropertySetAnalysis dataflow analysis.
            PropertyMapperCollection propertyMappers = new PropertyMapperCollection(
                new PropertyMapper(
                    this.SerializationBinderPropertyMetadataName,
                    (NullAbstractValue nullAbstractValue) =>
            {
                // A null SerializationBinder is what we want to flag as hazardous.
                switch (nullAbstractValue)
                {
                case NullAbstractValue.Null:
                    return(PropertySetAbstractValueKind.Flagged);

                case NullAbstractValue.NotNull:
                    return(PropertySetAbstractValueKind.Unflagged);

                default:
                    return(PropertySetAbstractValueKind.MaybeFlagged);
                }
            }));

            HazardousUsageEvaluatorCollection hazardousUsageEvaluators =
                new HazardousUsageEvaluatorCollection(
                    cachedDeserializationMethodNames.Select(
                        methodName => new HazardousUsageEvaluator(methodName, DoNotUseInsecureDeserializerWithoutBinderBase.HazardousIfNull)));

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                WellKnownTypeProvider wellKnownTypeProvider =
                    WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(
                        this.DeserializerTypeMetadataName,
                        out INamedTypeSymbol deserializerTypeSymbol))
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance();

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IInvocationOperation invocationOperation =
                            (IInvocationOperation)operationAnalysisContext.Operation;
                        if (invocationOperation.Instance?.Type == deserializerTypeSymbol &&
                            cachedDeserializationMethodNames.Contains(invocationOperation.TargetMethod.Name))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot());
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IMethodReferenceOperation methodReferenceOperation =
                            (IMethodReferenceOperation)operationAnalysisContext.Operation;
                        if (methodReferenceOperation.Instance?.Type == deserializerTypeSymbol &&
                            cachedDeserializationMethodNames.Contains(
                                methodReferenceOperation.Method.MetadataName))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot());
                            }
                        }
                    },
                        OperationKind.MethodReference);

                    operationBlockStartAnalysisContext.RegisterOperationBlockEndAction(
                        (OperationBlockAnalysisContext operationBlockAnalysisContext) =>
                    {
                        PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;
                        try
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                if (!rootOperationsNeedingAnalysis.Any())
                                {
                                    return;
                                }

                                // Only instantiated if there are any results to report.
                                List <ControlFlowGraph> cfgs = new List <ControlFlowGraph>();

                                var interproceduralAnalysisConfig = InterproceduralAnalysisConfiguration.Create(
                                    operationBlockAnalysisContext.Options, SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.None,
                                    cancellationToken: operationBlockAnalysisContext.CancellationToken,
                                    defaultMaxInterproceduralMethodCallChain: 1);             // By default, we only want to track method calls one level down.

                                foreach (IOperation rootOperation in rootOperationsNeedingAnalysis)
                                {
                                    ImmutableDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> dfaResult =
                                        PropertySetAnalysis.GetOrComputeHazardousUsages(
                                            rootOperation.GetEnclosingControlFlowGraph(),
                                            operationBlockAnalysisContext.Compilation,
                                            operationBlockAnalysisContext.OwningSymbol,
                                            this.DeserializerTypeMetadataName,
                                            DoNotUseInsecureDeserializerWithoutBinderBase.ConstructorMapper,
                                            propertyMappers,
                                            hazardousUsageEvaluators,
                                            interproceduralAnalysisConfig);
                                    if (dfaResult.IsEmpty)
                                    {
                                        continue;
                                    }

                                    if (allResults == null)
                                    {
                                        allResults = PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> .GetInstance();
                                    }

                                    foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                             in dfaResult)
                                    {
                                        allResults.Add(kvp.Key, kvp.Value);
                                    }
                                }
                            }

                            if (allResults == null)
                            {
                                return;
                            }

                            foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                     in allResults)
                            {
                                DiagnosticDescriptor descriptor;
                                switch (kvp.Value)
                                {
                                case HazardousUsageEvaluationResult.Flagged:
                                    descriptor = this.BinderDefinitelyNotSetDescriptor;
                                    break;

                                case HazardousUsageEvaluationResult.MaybeFlagged:
                                    descriptor = this.BinderMaybeNotSetDescriptor;
                                    break;

                                default:
                                    Debug.Fail($"Unhandled result value {kvp.Value}");
                                    continue;
                                }

                                operationBlockAnalysisContext.ReportDiagnostic(
                                    Diagnostic.Create(
                                        descriptor,
                                        kvp.Key.Location,
                                        kvp.Key.Method.ToDisplayString(
                                            SymbolDisplayFormat.MinimallyQualifiedFormat)));
                            }
                        }
                        finally
                        {
                            rootOperationsNeedingAnalysis.Free();
                            allResults?.Free();
                        }
                    });
                });
            });
        }
Exemple #25
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                INamedTypeSymbol?localizableStateAttributeSymbol  = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemComponentModelLocalizableAttribute);
                INamedTypeSymbol?conditionalAttributeSymbol       = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsConditionalAttribute);
                INamedTypeSymbol?systemConsoleSymbol              = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemConsole);
                ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation);

                compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext =>
                {
                    if (operationBlockStartContext.OwningSymbol is not IMethodSymbol containingMethod ||
                        containingMethod.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options,
                                                                    Rule, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken))
                    {
                        return;
                    }

                    Lazy <DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue>?> lazyValueContentResult = new Lazy <DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue>?>(
                        valueFactory: ComputeValueContentAnalysisResult, isThreadSafe: false);

                    operationBlockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var argument = (IArgumentOperation)operationContext.Operation;
                        IMethodSymbol?targetMethod = null;
                        switch (argument.Parent)
                        {
                        case IInvocationOperation invocation:
                            targetMethod = invocation.TargetMethod;
                            break;

                        case IObjectCreationOperation objectCreation:
                            targetMethod = objectCreation.Constructor;
                            break;
                        }

                        if (ShouldAnalyze(targetMethod))
                        {
                            AnalyzeArgument(argument.Parameter, containingPropertySymbol: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic, GetUseNamingHeuristicOption(operationContext));
                        }
                    }, 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 &&
                            ShouldAnalyze(propertyReference.Property))
                        {
                            IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0];
                            AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic, GetUseNamingHeuristicOption(operationContext));
                        }
                    }, OperationKind.PropertyReference);

                    return;

                    // Local functions
                    bool ShouldAnalyze(ISymbol? symbol)
                    => symbol != null && !symbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.OwningSymbol, operationBlockStartContext.Options, Rule, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken);

                    static bool GetUseNamingHeuristicOption(OperationAnalysisContext operationContext)
                    => operationContext.Options.GetBoolOptionValue(EditorConfigOptionNames.UseNamingHeuristic, Rule,
                                                                   operationContext.Operation.Syntax.SyntaxTree, operationContext.Compilation, defaultValue: false, operationContext.CancellationToken);

                    void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol? containingPropertySymbol, IOperation operation, Action <Diagnostic> reportDiagnostic, bool useNamingHeuristic)
                    {
                        if (ShouldBeLocalized(parameter.OriginalDefinition, containingPropertySymbol?.OriginalDefinition, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore, useNamingHeuristic) &&
                            lazyValueContentResult.Value != null)
                        {
                            ValueContentAbstractValue stringContentValue = lazyValueContentResult.Value[operation.Kind, operation.Syntax];
                            if (stringContentValue.IsLiteralState)
                            {
                                Debug.Assert(!stringContentValue.LiteralValues.IsEmpty);

                                if (stringContentValue.LiteralValues.Any(l => l is not string))
                                {
                                    return;
                                }

                                var stringLiteralValues = stringContentValue.LiteralValues.Cast <string?>();

                                // 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.
                                IEnumerable <string> filteredStrings = stringLiteralValues.Where(literal => literal != null && !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()
                    {
                        var cfg = operationBlockStartContext.OperationBlocks.GetControlFlowGraph();
                        if (cfg != null)
                        {
                            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation);
                            return(ValueContentAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider,
                                                                              operationBlockStartContext.Options, Rule, PointsToAnalysisKind.PartialWithoutTrackingFieldsAndProperties, operationBlockStartContext.CancellationToken));
                        }

                        return(null);
                    }
                });