示例#1
0
 private void CheckDeclared(LocalSymbol local)
 {
     if (!DeclaredLocals.Contains(local))
     {
         Debug.Assert(false, "undeclared local " + local.GetDebuggerDisplay());
     }
 }
        public override void VisitIdentifierName(IdentifierNameSyntax node)
        {
            if (_ignoredSpans?.HasIntervalThatOverlapsWith(node.FullSpan.Start, node.FullSpan.Length) ?? false)
            {
                return;
            }

            // Always try to simplify identifiers with an 'Attribute' suffix.
            //
            // In other cases, don't bother looking at the right side of A.B or A::B. We will process those in
            // one of our other top level Visit methods (like VisitQualifiedName).
            var canTrySimplify = node.Identifier.ValueText.EndsWith("Attribute", StringComparison.Ordinal);

            if (!canTrySimplify && !node.IsRightSideOfDotOrArrowOrColonColon())
            {
                // The only possible simplifications to an unqualified identifier are replacement with an alias or
                // replacement with a predefined type.
                canTrySimplify = CanReplaceIdentifierWithAlias(node.Identifier.ValueText) ||
                                 CanReplaceIdentifierWithPredefinedType(node.Identifier.ValueText);
            }

            if (canTrySimplify && TrySimplify(node))
            {
                // found a match. report it and stop processing.
                return;
            }

            // descend further.
            DefaultVisit(node);
            return;

            // Local functions
            bool CanReplaceIdentifierWithAlias(string identifier)
            => _aliasedNames.Contains(identifier);
        private static TypeSymbol GetNextDeclaredBase(NamedTypeSymbol type, ConsList <Symbol> basesBeingResolved, CSharpCompilation compilation, ref PooledHashSet <NamedTypeSymbol> visited)
        {
            // We shouldn't have visited this type earlier.
            Debug.Assert(visited == null || !visited.Contains(type.OriginalDefinition));

            if (basesBeingResolved != null && basesBeingResolved.ContainsReference(type.OriginalDefinition))
            {
                return(null);
            }

            if (type.SpecialType == SpecialType.System_Object)
            {
                type.SetKnownToHaveNoDeclaredBaseCycles();
                return(null);
            }

            var nextType = type.GetDeclaredBaseType(basesBeingResolved);

            // types with no declared bases inherit object's members
            if ((object)nextType == null)
            {
                SetKnownToHaveNoDeclaredBaseCycles(ref visited);
                return(GetDefaultBaseOrNull(type, compilation));
            }

            var origType = type.OriginalDefinition;

            if (nextType.KnownToHaveNoDeclaredBaseCycles)
            {
                origType.SetKnownToHaveNoDeclaredBaseCycles();
                SetKnownToHaveNoDeclaredBaseCycles(ref visited);
            }
            else
            {
                // start cycle tracking
                visited = visited ?? PooledHashSet <NamedTypeSymbol> .GetInstance();

                visited.Add(origType);
                if (visited.Contains(nextType.OriginalDefinition))
                {
                    return(GetDefaultBaseOrNull(type, compilation));
                }
            }

            return(nextType);
        }
示例#4
0
 internal static void AddNs(UsingDirectiveSyntax usingDirective, NamespaceOrTypeSymbol ns, ArrayBuilder <NamespaceOrTypeAndUsingDirective> usings, PooledHashSet <NamespaceOrTypeSymbol> uniqueUsings)
 {
     if (!uniqueUsings.Contains(ns))
     {
         uniqueUsings.Add(ns);
         usings.Add(new NamespaceOrTypeAndUsingDirective(ns, usingDirective));
     }
 }
示例#5
0
        protected override ImmutableArray <PendingBranch> Scan(ref bool badRegion)
        {
            this.Diagnostics.Clear();  // clear reported diagnostics
            var result = base.Scan(ref badRegion);

            foreach (var label in _labelsDefined.Keys)
            {
                if (!_labelsUsed.Contains(label))
                {
                    Diagnostics.Add(ErrorCode.WRN_UnreferencedLabel, label.Locations[0]);
                }
            }

            return(result);
        }
示例#6
0
        private void StopTrackingDataForEntity(AnalysisEntity analysisEntity, TAnalysisData analysisData, PooledHashSet <AnalysisEntity> allEntities)
        {
            if (!allEntities.Contains(analysisEntity))
            {
                return;
            }

            // Stop tracking entity that is now out of scope.
            StopTrackingEntity(analysisEntity, analysisData);

            // Additionally, stop tracking all the child entities if the entity type has value copy semantics.
            if (analysisEntity.Type.HasValueCopySemantics())
            {
                foreach (var childEntity in GetChildAnalysisEntities(analysisEntity, allEntities))
                {
                    StopTrackingEntity(childEntity, analysisData);
                }
            }
        }
示例#7
0
 /// <summary>
 /// True if the method signature can be rewritten to contain ref/out parameters.
 /// </summary>
 public bool CanTakeRefParameters(MethodSymbol closure) => !(closure.IsAsync ||
                                                             closure.IsIterator
                                                             // We can't rewrite delegate signatures
                                                             || MethodsConvertedToDelegates.Contains(closure));
示例#8
0
        internal void ValidateParameterNameConflicts(
            ImmutableArray <TypeParameterSymbol> typeParameters,
            ImmutableArray <ParameterSymbol> parameters,
            bool allowShadowingNames,
            DiagnosticBag diagnostics)
        {
            PooledHashSet <string>?tpNames = null;

            if (!typeParameters.IsDefaultOrEmpty)
            {
                tpNames = PooledHashSet <string> .GetInstance();

                foreach (var tp in typeParameters)
                {
                    var name = tp.Name;
                    if (string.IsNullOrEmpty(name))
                    {
                        continue;
                    }

                    if (!tpNames.Add(name))
                    {
                        // Type parameter declaration name conflicts are detected elsewhere
                    }
                    else if (!allowShadowingNames)
                    {
                        ValidateDeclarationNameConflictsInScope(tp, diagnostics);
                    }
                }
            }

            PooledHashSet <string>?pNames = null;

            if (!parameters.IsDefaultOrEmpty)
            {
                pNames = PooledHashSet <string> .GetInstance();

                foreach (var p in parameters)
                {
                    var name = p.Name;
                    if (string.IsNullOrEmpty(name))
                    {
                        continue;
                    }

                    if (tpNames != null && tpNames.Contains(name))
                    {
                        // CS0412: 'X': a parameter or local variable cannot have the same name as a method type parameter
                        diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, GetLocation(p), name);
                    }

                    if (!pNames.Add(name))
                    {
                        // The parameter name '{0}' is a duplicate
                        diagnostics.Add(ErrorCode.ERR_DuplicateParamName, GetLocation(p), name);
                    }
                    else if (!allowShadowingNames)
                    {
                        ValidateDeclarationNameConflictsInScope(p, diagnostics);
                    }
                }
            }

            tpNames?.Free();
            pNames?.Free();
        }
示例#9
0
            private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasInvalidOrDynamicOperation)
            {
                // We bail out reporting diagnostics for named types if it contains following kind of operations:
                //  1. Invalid operations, i.e. erroneous code:
                //     We do so to ensure that we don't report false positives during editing scenarios in the IDE, where the user
                //     is still editing code and fixing unresolved references to symbols, such as overload resolution errors.
                //  2. Dynamic operations, where we do not know the exact member being referenced at compile time.
                if (hasInvalidOrDynamicOperation)
                {
                    return;
                }

                if (symbolEndContext.Symbol.GetAttributes().Any(a => a.AttributeClass == _structLayoutAttributeType))
                {
                    // Bail out for types with 'StructLayoutAttribute' as the ordering of the members is critical,
                    // and removal of unused members might break semantics.
                    return;
                }

                // Report diagnostics for unused candidate members.
                var first = true;
                PooledHashSet <ISymbol> symbolsReferencedInDocComments    = null;
                ArrayBuilder <string>   debuggerDisplayAttributeArguments = null;

                try
                {
                    var namedType = (INamedTypeSymbol)symbolEndContext.Symbol;
                    foreach (var member in namedType.GetMembers())
                    {
                        // Check if the underlying member is neither read nor a readable reference to the member is taken.
                        // If so, we flag the member as either unused (never written) or unread (written but not read).
                        if (TryRemove(member, out var valueUsageInfo) &&
                            !valueUsageInfo.IsReadFrom())
                        {
                            Debug.Assert(IsCandidateSymbol(member));
                            Debug.Assert(!member.IsImplicitlyDeclared);

                            if (first)
                            {
                                // Bail out if there are syntax errors in any of the declarations of the containing type.
                                // Note that we check this only for the first time that we report an unused or unread member for the containing type.
                                if (HasSyntaxErrors(namedType, symbolEndContext.CancellationToken))
                                {
                                    return;
                                }

                                // Compute the set of candidate symbols referenced in all the documentation comments within the named type declarations.
                                // This set is computed once and used for all the iterations of the loop.
                                symbolsReferencedInDocComments = GetCandidateSymbolsReferencedInDocComments(namedType, symbolEndContext.Compilation, symbolEndContext.CancellationToken);

                                // Compute the set of string arguments to DebuggerDisplay attributes applied to any symbol within the named type declaration.
                                // These strings may have an embedded reference to the symbol.
                                // This set is computed once and used for all the iterations of the loop.
                                debuggerDisplayAttributeArguments = GetDebuggerDisplayAttributeArguments(namedType);

                                first = false;
                            }

                            // Simple heuristic for members referenced in DebuggerDisplayAttribute's string argument:
                            // bail out if any of the DebuggerDisplay string arguments contains the member name.
                            // In future, we can consider improving this heuristic to parse the embedded expression
                            // and resolve symbol references.
                            if (debuggerDisplayAttributeArguments.Any(arg => arg.Contains(member.Name)))
                            {
                                continue;
                            }

                            // Report IDE0051 or IDE0052 based on whether the underlying member has any Write/WritableRef/NonReadWriteRef references or not.
                            var rule = !valueUsageInfo.IsWrittenTo() && !valueUsageInfo.IsNameOnly() && !symbolsReferencedInDocComments.Contains(member)
                                ? s_removeUnusedMembersRule
                                : s_removeUnreadMembersRule;

                            // Do not flag write-only properties that are not read.
                            // Write-only properties are assumed to have side effects
                            // visible through other means than a property getter.
                            if (rule == s_removeUnreadMembersRule &&
                                member is IPropertySymbol property &&
                                property.IsWriteOnly)
                            {
                                continue;
                            }

                            // Most of the members should have a single location, except for partial methods.
                            // We report the diagnostic on the first location of the member.
                            var diagnostic = DiagnosticHelper.CreateWithMessage(
                                rule,
                                member.Locations[0],
                                rule.GetEffectiveSeverity(symbolEndContext.Compilation.Options),
                                additionalLocations: null,
                                properties: null,
                                GetMessage(rule, member));
                            symbolEndContext.ReportDiagnostic(diagnostic);
                        }
                    }
                }
                finally
                {
                    symbolsReferencedInDocComments?.Free();
                    debuggerDisplayAttributeArguments?.Free();
                }

                return;
            }
示例#10
0
        private static TypeSymbol GetNextDeclaredBase(NamedTypeSymbol type, ConsList<Symbol> basesBeingResolved, CSharpCompilation compilation, ref PooledHashSet<NamedTypeSymbol> visited)
        {
            // We shouldn't have visited this type earlier.
            Debug.Assert(visited == null || !visited.Contains(type.OriginalDefinition));

            if (basesBeingResolved != null && basesBeingResolved.ContainsReference(type.OriginalDefinition))
            {
                return null;
            }

            if (type.SpecialType == SpecialType.System_Object)
            {
                type.SetKnownToHaveNoDeclaredBaseCycles();
                return null;
            }

            var nextType = type.GetDeclaredBaseType(basesBeingResolved);

            // types with no declared bases inherit object's members
            if ((object)nextType == null)
            {
                SetKnownToHaveNoDeclaredBaseCycles(ref visited);
                return GetDefaultBaseOrNull(type, compilation);
            }

            var origType = type.OriginalDefinition;
            if (nextType.KnownToHaveNoDeclaredBaseCycles)
            {
                origType.SetKnownToHaveNoDeclaredBaseCycles();
                SetKnownToHaveNoDeclaredBaseCycles(ref visited);
            }
            else
            {
                // start cycle tracking
                visited = visited ?? PooledHashSet<NamedTypeSymbol>.GetInstance();
                visited.Add(origType);
                if (visited.Contains(nextType.OriginalDefinition))
                {
                    return GetDefaultBaseOrNull(type, compilation);
                }
            }

            return nextType;
        }
示例#11
0
            private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasInvalidOperation)
            {
                // We bail out reporting diagnostics for named types which have any invalid operations, i.e. erroneous code.
                // We do so to ensure that we don't report false positives during editing scenarios in the IDE, where the user
                // is still editing code and fixing unresolved references to symbols, such as overload resolution errors.
                if (hasInvalidOperation)
                {
                    return;
                }

                // Report diagnostics for unused candidate members.
                var first = true;
                PooledHashSet <ISymbol> symbolsReferencedInDocComments = null;

                try
                {
                    var namedType = (INamedTypeSymbol)symbolEndContext.Symbol;
                    foreach (var member in namedType.GetMembers())
                    {
                        // Check if the underlying member is neither read nor a readable reference to the member is taken.
                        // If so, we flag the member as either unused (never written) or unread (written but not read).
                        if (TryRemove(member, out var valueUsageInfo) &&
                            !valueUsageInfo.ContainsReadOrReadableRef())
                        {
                            Debug.Assert(IsCandidateSymbol(member));
                            Debug.Assert(!member.IsImplicitlyDeclared);

                            if (first)
                            {
                                // Bail out if there are syntax errors in any of the declarations of the containing type.
                                // Note that we check this only for the first time that we report an unused or unread member for the containing type.
                                if (HasSyntaxErrors(namedType, symbolEndContext.CancellationToken))
                                {
                                    return;
                                }

                                // Compute the set of candidate symbols referenced in all the documentation comments within the named type declarations.
                                // This set is computed once and used for all the iterations of the loop.
                                symbolsReferencedInDocComments = GetCandidateSymbolsReferencedInDocComments(namedType, symbolEndContext.Compilation, symbolEndContext.CancellationToken);
                                first = false;
                            }

                            // Report IDE0051 or IDE0052 based on whether the underlying member has any Write/WritableRef/NonReadWriteRef references or not.
                            var rule = !valueUsageInfo.ContainsWriteOrWritableRef() && !valueUsageInfo.ContainsNonReadWriteRef() && !symbolsReferencedInDocComments.Contains(member)
                                ? s_removeUnusedMembersWithFadingRule
                                : s_removeUnreadMembersWithFadingRule;
                            var effectiveSeverity = rule.GetEffectiveSeverity(symbolEndContext.Compilation.Options);

                            // Most of the members should have a single location, except for partial methods.
                            // We report the diagnostic on the first location of the member.
                            var diagnostic = DiagnosticHelper.Create(
                                rule,
                                member.Locations[0],
                                effectiveSeverity,
                                additionalLocations: null,
                                properties: null,
                                member.ContainingType.Name,
                                member.Name);
                            symbolEndContext.ReportDiagnostic(diagnostic);
                        }
                    }
                }
                finally
                {
                    symbolsReferencedInDocComments?.Free();
                }

                return;
            }
 public bool CanTakeRefParameters(MethodSymbol function)
 => !function.IsAsync && !function.IsIterator
 // We can't rewrite delegate signatures
 && !MethodsConvertedToDelegates.Contains(function);