Exemple #1
0
        // Take a warning and return the final deposition of the given warning,
        // based on both command line options and pragmas.
        public static ReportDiagnostic GetDiagnosticReport(
            DiagnosticSeverity severity,
            bool isEnabledByDefault,
            string id,
            int diagnosticWarningLevel,
            Location location,
            string category,
            int warningLevelOption,
            NullableContextOptions nullableOption,
            ReportDiagnostic generalDiagnosticOption,
            IDictionary <string, ReportDiagnostic> specificDiagnosticOptions,
            out bool hasPragmaSuppression)
        {
            hasPragmaSuppression = false;

            // Read options (e.g., /nowarn or /warnaserror)
            ReportDiagnostic report = ReportDiagnostic.Default;
            var isSpecified         = specificDiagnosticOptions.TryGetValue(id, out report);

            if (!isSpecified)
            {
                report = isEnabledByDefault ? ReportDiagnostic.Default : ReportDiagnostic.Suppress;
            }

            // Compute if the reporting should be suppressed.
            if (diagnosticWarningLevel > warningLevelOption)              // honor the warning level
            {
                return(ReportDiagnostic.Suppress);
            }

            bool isNullableFlowAnalysisSafetyWarning    = ErrorFacts.NullableFlowAnalysisSafetyWarnings.Contains(id);
            bool isNullableFlowAnalysisNonSafetyWarning = ErrorFacts.NullableFlowAnalysisNonSafetyWarnings.Contains(id);

            Debug.Assert(!isNullableFlowAnalysisSafetyWarning || !isNullableFlowAnalysisNonSafetyWarning);

            if (report == ReportDiagnostic.Suppress &&             // check options (/nowarn)
                !isNullableFlowAnalysisSafetyWarning && !isNullableFlowAnalysisNonSafetyWarning)
            {
                return(ReportDiagnostic.Suppress);
            }

            var pragmaWarningState = PragmaWarningState.Default;

            // If location is available, check out pragmas
            //if (location != null &&
            //	location.SourceTree != null &&
            //	(pragmaWarningState = location.SourceTree.GetPragmaDirectiveWarningState(id, location.SourceSpan.Start)) == PragmaWarningState.Disabled)
            //{
            //	hasPragmaSuppression = true;
            //}

            if (pragmaWarningState == PragmaWarningState.Enabled)
            {
                switch (report)
                {
                case ReportDiagnostic.Error:
                case ReportDiagnostic.Hidden:
                case ReportDiagnostic.Info:
                case ReportDiagnostic.Warn:
                    // No need to adjust the current report state, it already means "enabled"
                    return(report);

                case ReportDiagnostic.Suppress:
                    // Enable the warning
                    return(ReportDiagnostic.Default);

                case ReportDiagnostic.Default:
                    if (generalDiagnosticOption == ReportDiagnostic.Error && promoteToAnError())
                    {
                        return(ReportDiagnostic.Error);
                    }

                    return(ReportDiagnostic.Default);

                default:
                    throw ExceptionUtilities.UnexpectedValue(report);
                }
            }
            else if (report == ReportDiagnostic.Suppress)             // check options (/nowarn)
            {
                return(ReportDiagnostic.Suppress);
            }

            // Nullable flow analysis warnings cannot be turned on by specific diagnostic options.
            // They can be turned on by nullable options and specific diagnostic options
            // can either turn them off, or adjust the way they are reported.
            switch (nullableOption)
            {
            case NullableContextOptions.Disable:
                if (isNullableFlowAnalysisSafetyWarning || isNullableFlowAnalysisNonSafetyWarning)
                {
                    return(ReportDiagnostic.Suppress);
                }
                break;

            case NullableContextOptions.SafeOnly:
            case NullableContextOptions.SafeOnlyWarnings:
                if (isNullableFlowAnalysisNonSafetyWarning)
                {
                    return(ReportDiagnostic.Suppress);
                }
                break;

            case NullableContextOptions.Enable:
            case NullableContextOptions.Warnings:
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(nullableOption);
            }

            // Unless specific warning options are defined (/warnaserror[+|-]:<n> or /nowarn:<n>,
            // follow the global option (/warnaserror[+|-] or /nowarn).
            if (report == ReportDiagnostic.Default)
            {
                switch (generalDiagnosticOption)
                {
                case ReportDiagnostic.Error:
                    if (promoteToAnError())
                    {
                        return(ReportDiagnostic.Error);
                    }
                    break;

                case ReportDiagnostic.Suppress:
                    // When doing suppress-all-warnings, don't lower severity for anything other than warning and info.
                    // We shouldn't suppress hidden diagnostics here because then features that use hidden diagnostics to
                    // display a lightbulb would stop working if someone has suppress-all-warnings (/nowarn) specified in their project.
                    if (severity == DiagnosticSeverity.Warning || severity == DiagnosticSeverity.Info)
                    {
                        return(ReportDiagnostic.Suppress);
                    }
                    break;

                default:
                    break;
                }
            }

            return(report);

            bool promoteToAnError()
            {
                Debug.Assert(report == ReportDiagnostic.Default);
                Debug.Assert(generalDiagnosticOption == ReportDiagnostic.Error);

                // If we've been asked to do warn-as-error then don't raise severity for anything below warning (info or hidden).
                return(severity == DiagnosticSeverity.Warning &&
                       // In the case where /warnaserror+ is followed by /warnaserror-:<n> on the command line,
                       // do not promote the warning specified in <n> to an error.
                       !isSpecified);
            }
        }
Exemple #2
0
        public static string ToDisplayString(this AttributeLocation locations)
        {
            StringBuilder result = new StringBuilder();

            for (int i = 1; i < (int)AttributeLocation.Unknown; i <<= 1)
            {
                if ((locations & (AttributeLocation)i) != 0)
                {
                    if (result.Length > 0)
                    {
                        result.Append(", ");
                    }

                    switch ((AttributeLocation)i)
                    {
                    case AttributeLocation.Assembly:
                        result.Append("assembly");
                        break;

                    case AttributeLocation.Module:
                        result.Append("module");
                        break;

                    case AttributeLocation.Type:
                        result.Append("type");
                        break;

                    case AttributeLocation.Method:
                        result.Append("method");
                        break;

                    case AttributeLocation.Field:
                        result.Append("field");
                        break;

                    case AttributeLocation.Property:
                        result.Append("property");
                        break;

                    case AttributeLocation.Event:
                        result.Append("event");
                        break;

                    case AttributeLocation.Return:
                        result.Append("return");
                        break;

                    case AttributeLocation.Parameter:
                        result.Append("param");
                        break;

                    case AttributeLocation.TypeParameter:
                        result.Append("typevar");
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(i);
                    }
                }
            }

            return(result.ToString());
        }
Exemple #3
0
            /// <summary>
            /// Decodes a type name.  A type name is a string which is terminated by the end of the string or one of the
            /// delimiters '+', ',', '[', ']'. '+' separates nested classes. '[' and ']'
            /// enclosed generic type arguments.  ',' separates types.
            /// </summary>
            public AssemblyQualifiedTypeName DecodeTypeName(bool isTypeArgument = false, bool isTypeArgumentWithAssemblyName = false)
            {
                Debug.Assert(!isTypeArgumentWithAssemblyName || isTypeArgument);

                string        topLevelType       = null;
                List <string> nestedTypesBuilder = null;

                AssemblyQualifiedTypeName[] typeArguments = null;
                int        pointerCount         = 0;
                List <int> arrayRanksBuilder    = null;
                string     assemblyName         = null;
                bool       decodingTopLevelType = true;
                bool       isGenericTypeName    = false;

                var           pooledStrBuilder = PooledStringBuilder.GetInstance();
                StringBuilder typeNameBuilder  = pooledStrBuilder.Builder;

                while (!EndOfInput)
                {
                    int i = _input.IndexOfAny(s_typeNameDelimiters, _offset);
                    if (i >= 0)
                    {
                        char c = _input[i];

                        // Found name, which could be a generic name with arity.
                        // Generic type parameter count, if any, are handled in DecodeGenericName.
                        string decodedString = DecodeGenericName(i);
                        Debug.Assert(decodedString != null);

                        // Type name is generic if the decoded name of the top level type OR any of the outer types of a nested type had the '`' character.
                        isGenericTypeName = isGenericTypeName || decodedString.IndexOf(GenericTypeNameManglingChar) >= 0;
                        typeNameBuilder.Append(decodedString);

                        switch (c)
                        {
                        case '*':
                            if (arrayRanksBuilder != null)
                            {
                                // Error case, array shape must be specified at the end of the type name.
                                // Process as a regular character and continue.
                                typeNameBuilder.Append(c);
                            }
                            else
                            {
                                pointerCount++;
                            }

                            Advance();
                            break;

                        case '+':
                            if (arrayRanksBuilder != null || pointerCount > 0)
                            {
                                // Error case, array shape must be specified at the end of the type name.
                                // Process as a regular character and continue.
                                typeNameBuilder.Append(c);
                            }
                            else
                            {
                                // Type followed by nested type. Handle nested class separator and collect the nested types.
                                HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder);
                                typeNameBuilder.Clear();
                                decodingTopLevelType = false;
                            }

                            Advance();
                            break;

                        case '[':
                            // Is type followed by generic type arguments?
                            if (isGenericTypeName && typeArguments == null)
                            {
                                Advance();
                                if (arrayRanksBuilder != null || pointerCount > 0)
                                {
                                    // Error case, array shape must be specified at the end of the type name.
                                    // Process as a regular character and continue.
                                    typeNameBuilder.Append(c);
                                }
                                else
                                {
                                    // Decode type arguments.
                                    typeArguments = DecodeTypeArguments();
                                }
                            }
                            else
                            {
                                // Decode array shape.
                                DecodeArrayShape(typeNameBuilder, ref arrayRanksBuilder);
                            }

                            break;

                        case ']':
                            if (isTypeArgument)
                            {
                                // End of type arguments.  This occurs when the last type argument is a type in the
                                // current assembly.
                                goto ExitDecodeTypeName;
                            }
                            else
                            {
                                // Error case, process as a regular character and continue.
                                typeNameBuilder.Append(c);
                                Advance();
                                break;
                            }

                        case ',':
                            // A comma may separate a type name from its assembly name or a type argument from
                            // another type argument.
                            // If processing non-type argument or a type argument with assembly name,
                            // process the characters after the comma as an assembly name.
                            if (!isTypeArgument || isTypeArgumentWithAssemblyName)
                            {
                                Advance();
                                if (!EndOfInput && Char.IsWhiteSpace(Current))
                                {
                                    Advance();
                                }

                                assemblyName = DecodeAssemblyName(isTypeArgumentWithAssemblyName);
                            }
                            goto ExitDecodeTypeName;

                        default:
                            throw ExceptionUtilities.UnexpectedValue(c);
                        }
                    }
                    else
                    {
                        typeNameBuilder.Append(DecodeGenericName(_input.Length));
                        goto ExitDecodeTypeName;
                    }
                }

ExitDecodeTypeName:
                HandleDecodedTypeName(typeNameBuilder.ToString(), decodingTopLevelType, ref topLevelType, ref nestedTypesBuilder);
                pooledStrBuilder.Free();

                return(new AssemblyQualifiedTypeName(
                           topLevelType,
                           nestedTypesBuilder?.ToArray(),
                           typeArguments,
                           pointerCount,
                           arrayRanksBuilder?.ToArray(),
                           assemblyName));
            }
Exemple #4
0
        // Given the ordered list of all pragma warning and nullable directives in the syntax tree, return a list of mapping entries,
        // containing the cumulative set of warnings that are disabled for that point in the source.
        // This mapping also contains a global warning option, accumulated of all #pragma up to the current line position.
        private static WarningStateMapEntry[] CreatePragmaWarningStateEntries(List <DirectiveTriviaSyntax> directiveList, bool isGeneratedCode)
        {
            var entries = new WarningStateMapEntry[directiveList.Count + 1];
            var index   = 0;

            // Captures the mapping of a warning number to the reporting option, accumulated of all #pragma up to the current directive.
            var accumulatedSpecificWarningState = new Dictionary <string, PragmaWarningState>();

            // Captures the general reporting option, accumulated of all #pragma up to the current directive.
            var accumulatedGeneralWarningState = PragmaWarningState.Default;

            // Generated files have a default nullable warning state that is "disabled".
            if (isGeneratedCode)
            {
                accumulatedNullableWarningState(SyntaxKind.DisableKeyword);
            }

            var current = new WarningStateMapEntry(0, PragmaWarningState.Default, accumulatedSpecificWarningState);

            entries[index] = current;

            while (index < directiveList.Count)
            {
                var currentDirective = directiveList[index];

                if (currentDirective.IsKind(SyntaxKind.PragmaWarningDirectiveTrivia))
                {
                    var currentPragmaDirective = (PragmaWarningDirectiveTriviaSyntax)currentDirective;

                    if (currentPragmaDirective.NullableKeyword.IsKind(SyntaxKind.NullableKeyword))
                    {
                        accumulatedNullableWarningState(currentPragmaDirective.DisableOrRestoreKeyword.Kind);
                    }
                    else
                    {
                        // Compute the directive state
                        PragmaWarningState directiveState;

                        switch (currentPragmaDirective.DisableOrRestoreKeyword.Kind)
                        {
                        case SyntaxKind.DisableKeyword:
                            directiveState = PragmaWarningState.Disabled;
                            break;

                        case SyntaxKind.RestoreKeyword:
                            directiveState = PragmaWarningState.Default;
                            break;

                        case SyntaxKind.EnableKeyword:
                            directiveState = PragmaWarningState.Enabled;
                            break;

                        case SyntaxKind.SafeOnlyKeyword:
                        default:
                            throw ExceptionUtilities.UnexpectedValue(currentPragmaDirective.DisableOrRestoreKeyword.Kind);
                        }

                        // Check if this directive applies for all (e.g., #pragma warning disable)
                        if (currentPragmaDirective.ErrorCodes.Count == 0)
                        {
                            // Update the warning state and reset the specific one
                            accumulatedGeneralWarningState  = directiveState;
                            accumulatedSpecificWarningState = new Dictionary <string, PragmaWarningState>();
                        }
                        else
                        {
                            // Compute warning numbers from the current directive's codes
                            for (int x = 0; x < currentPragmaDirective.ErrorCodes.Count; x++)
                            {
                                var currentErrorCode = currentPragmaDirective.ErrorCodes[x];
                                if (currentErrorCode.IsMissing || currentErrorCode.ContainsDiagnostics)
                                {
                                    continue;
                                }

                                var errorId = string.Empty;
                                if (currentErrorCode.Kind == SyntaxKind.NumericLiteralExpression)
                                {
                                    var token = ((LiteralExpressionSyntax)currentErrorCode).Token;
                                    errorId = MessageProvider.Instance.GetIdForErrorCode((int)token.Value);
                                }
                                else if (currentErrorCode.Kind == SyntaxKind.IdentifierName)
                                {
                                    errorId = ((IdentifierNameSyntax)currentErrorCode).Identifier.ValueText;
                                }

                                if (!string.IsNullOrWhiteSpace(errorId))
                                {
                                    // Update the state of this error code with the current directive state
                                    accumulatedSpecificWarningState[errorId] = directiveState;
                                }
                            }
                        }
                    }
                }
                else
                {
                    var currentNullableDirective = (NullableDirectiveTriviaSyntax)currentDirective;
                    accumulatedNullableWarningState(currentNullableDirective.SettingToken.Kind);
                }

                current = new WarningStateMapEntry(currentDirective.Location.SourceSpan.End, accumulatedGeneralWarningState, accumulatedSpecificWarningState);
                ++index;
                entries[index] = current;
            }

#if DEBUG
            // Make sure the entries array is correctly sorted.
            for (int i = 1; i < entries.Length - 1; ++i)
            {
                Debug.Assert(entries[i].CompareTo(entries[i + 1]) < 0);
            }
#endif

            return(entries);

            void accumulatedNullableWarningState(SyntaxKind nullableAction)
            {
                PragmaWarningState safetyState;
                PragmaWarningState nonSafetyState;

                switch (nullableAction)
                {
                case SyntaxKind.DisableKeyword:
                    safetyState    = PragmaWarningState.Disabled;
                    nonSafetyState = PragmaWarningState.Disabled;
                    break;

                case SyntaxKind.EnableKeyword:
                    safetyState    = PragmaWarningState.Enabled;
                    nonSafetyState = PragmaWarningState.Enabled;
                    break;

                case SyntaxKind.SafeOnlyKeyword:
                    safetyState    = PragmaWarningState.Enabled;
                    nonSafetyState = PragmaWarningState.Disabled;
                    break;

                case SyntaxKind.RestoreKeyword:
                    safetyState    = PragmaWarningState.Default;
                    nonSafetyState = PragmaWarningState.Default;
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(nullableAction);
                }

                var builder = new List <KeyValuePair <string, PragmaWarningState> >();

                // Update the state of the error codes with the current directive state
                addNewStates(safetyState, ErrorFacts.NullableFlowAnalysisSafetyWarnings);
                addNewStates(nonSafetyState, ErrorFacts.NullableFlowAnalysisNonSafetyWarnings);

                for (int i = 0; i < builder.Count; i++)
                {
                    accumulatedSpecificWarningState[builder[i].Key] = builder[i].Value;
                }

                void addNewStates(PragmaWarningState directiveState, HashSet <string> warnings)
                {
                    foreach (string id in warnings)
                    {
                        builder.Add(new KeyValuePair <string, PragmaWarningState>(id, directiveState));
                    }
                }
            }
        }