public override void Analyze(SymbolAnalysisContext context, List<IncludeAttributeData> includeTags, List<ProtobufAttributeData> memberTags, List<ContractAttributeData> contractAttributes) { foreach (var tag in memberTags.Where(a => a.Tag >= 19000 && a.Tag <= 19999)) { context.ReportDiagnostic(Diagnostic.Create(GetDescriptor(), tag.GetLocation(), tag.Tag, tag.Symbol.Name)); } }
private void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol flagsAttribute) { var symbol = (INamedTypeSymbol)context.Symbol; if (symbol.TypeKind != TypeKind.Enum) { return; } SpecialType underlyingType = symbol.EnumUnderlyingType.SpecialType; if (underlyingType == SpecialType.System_Int32) { return; } // If accessibility of enum is not public exit if (symbol.GetResultantVisibility() != SymbolVisibility.Public) { return; } // If enum is Int64 and has Flags attributes then exit bool hasFlagsAttribute = symbol.GetAttributes().Any(a => a.AttributeClass.Equals(flagsAttribute)); if (underlyingType == SpecialType.System_Int64 && hasFlagsAttribute) { return; } context.ReportDiagnostic(symbol.CreateDiagnostic(Rule, symbol.Name, symbol.EnumUnderlyingType)); }
private void AnalyzeSymbol(SymbolAnalysisContext context) { var symbol = (IMethodSymbol)context.Symbol; if (CommonFunctions.SkipSymbolAnalysisIgnoringAttributes(symbol, _settingsHandler)) return; var ignoredVariables = CommonFunctions.ItemsToIgnoreFromAttributes(symbol, SuppressionAttributes).ToList(); var syntax = symbol.DeclaringSyntaxReferences[0].GetSyntaxAsync().Result; var identifiers = syntax.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.VariableDeclarator)) .Cast<VariableDeclaratorSyntax>() .Select(variable => variable.Identifier.Value.ToString()).ToList(); foreach (var reassignment in GetAllNonIgnoredMutations(syntax, ignoredVariables, identifiers)) { context.ReportDiagnostic(Diagnostic.Create(AnalyzerRule, reassignment.Location, reassignment.Name)); } foreach (var ignoredSyntaxInfo in NonExistantIgnoredVariables(ignoredVariables, identifiers)) { context.ReportDiagnostic(Diagnostic.Create(SuppressionMisuseRule, ignoredSyntaxInfo.Location, ignoredSyntaxInfo.Name)); } }
private static void AnalyzeField(SymbolAnalysisContext symbolAnalysisContext) { var fieldDeclarationSyntax = (IFieldSymbol)symbolAnalysisContext.Symbol; if (!IsFieldPrivate(fieldDeclarationSyntax) && !IsStaticReadonly(fieldDeclarationSyntax) && IsParentAClass(fieldDeclarationSyntax) && !fieldDeclarationSyntax.IsConst) { foreach (var location in symbolAnalysisContext.Symbol.Locations) { if (!location.IsInSource) { // assume symbols not defined in a source document are "out of reach" return; } if (location.SourceTree.IsGeneratedDocument(symbolAnalysisContext.Compilation, symbolAnalysisContext.CancellationToken)) { return; } } symbolAnalysisContext.ReportDiagnostic(Diagnostic.Create(Descriptor, fieldDeclarationSyntax.Locations[0])); } }
private static void AnalyzeSymbol(SymbolAnalysisContext context) { var namedSymbol = context.Symbol as INamedTypeSymbol; var iMvxViewType = context.Compilation.GetTypeByMetadataName(typeof(IMvxView).FullName); if (namedSymbol != null && namedSymbol.ImplementsSymbol(iMvxViewType) && namedSymbol.GetMembers(ViewModelPropertyName).Any()) { var viewModelProperty = namedSymbol.GetMembers(ViewModelPropertyName).FirstOrDefault() as IPropertySymbol; var viewModelReturnType = viewModelProperty?.Type; if (!IsViewModelType(context, viewModelReturnType)) return; var syntax = namedSymbol.DeclaringSyntaxReferences.First().GetSyntax() as ClassDeclarationSyntax; var baseType = syntax?.BaseList.Types.First(); if (baseType?.Type is GenericNameSyntax) return; context.ReportDiagnostic( Diagnostic.Create( Rule , baseType?.GetLocation() , baseType?.ToString()) ); } }
/// <summary> /// Détermine si l'ordre d'assignations des champs est correct (en tête, par ordre alphabétique). /// </summary> /// <param name="context">Le contexte du symbole.</param> /// <returns>Oui ou non.</returns> private static async Task<bool> OrdreAssignationEstFaux(SymbolAnalysisContext context) { // On vérifie que la méthode est bien un constructeur. if ((context.Symbol as IMethodSymbol)?.MethodKind != MethodKind.Constructor) return false; // On récupère les informations nécessaires du contexte du symbole. var location = context.Symbol.Locations.First(); var racine = await location.SourceTree.GetRootAsync(); var modèleSémantique = context.Compilation.GetSemanticModel(location.SourceTree); var méthode = racine.FindNode(location.SourceSpan) as ConstructorDeclarationSyntax; // On récupère le corps du constructeur. var corps = méthode?.ChildNodes().FirstOrDefault(nœud => nœud as BlockSyntax != null) as BlockSyntax; if (corps == null) return false; // On récupère toutes les conditions sur les paramètres. var conditions = Partagé.TrouveConditionsParametres(corps.Statements, méthode.ParameterList, modèleSémantique); // On récupère toutes les assignations de champs par des paramètres. var assignations = Partagé.TrouverAssignations(corps.Statements, modèleSémantique); // On vérifie que toutes les conditions puis toutes les assignations sont au début. if (!conditions.Concat(assignations).SequenceEqual(corps.Statements.Take(conditions.Count() + assignations.Count()))) return true; // Et on vérifie l'ordre. return !assignations.SequenceEqual(assignations.OrderBy(x => x.ToString())); }
public static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol iCollectionType, INamedTypeSymbol arrayType, INamedTypeSymbol dataMemberAttribute) { var property = (IPropertySymbol)context.Symbol; // check whether it has a public setter IMethodSymbol setter = property.SetMethod; if (setter == null || setter.DeclaredAccessibility != Accessibility.Public) { return; } // make sure this property is NOT indexer, return type is NOT array but implement ICollection if (property.IsIndexer || Inherits(property.Type, arrayType) || !Inherits(property.Type, iCollectionType)) { return; } if (dataMemberAttribute != null) { // Special case: the DataContractSerializer requires that a public setter exists. bool hasDataMemberAttribute = property.GetAttributes().Any(a => a.AttributeClass.Equals(dataMemberAttribute)); if (hasDataMemberAttribute) { return; } } context.ReportDiagnostic(property.CreateDiagnostic(Rule)); }
/// <summary> /// Vérifie si un champ en lecture seule à bien été initialisé. /// </summary> /// <param name="context">Le contexte du symbole.</param> /// <returns>Oui ou non.</returns> private static async Task<bool> EstChampInitialisé(SymbolAnalysisContext context) { // On récupère les informations nécessaires du contexte du symbole. var location = context.Symbol.Locations.First(); var racine = await location.SourceTree.GetRootAsync(); var modèleSémantique = context.Compilation.GetSemanticModel(location.SourceTree); var déclarationChamp = racine.FindNode(location.SourceSpan) as VariableDeclaratorSyntax; // On vérifie que le champ est bien en lecture seule et n'est pas initialisé à la déclaration. if (déclarationChamp == null || (context.Symbol as IFieldSymbol)?.IsReadOnly == false || déclarationChamp.Initializer != null) return false; // On parcourt tous les constructeurs de la classe et récupère les assignations du champ dans chacun. var usages = racine.FindNode(déclarationChamp.Ancestors().OfType<ClassDeclarationSyntax>().First().Span) .ChildNodes().OfType<ConstructorDeclarationSyntax>() .SelectMany(constructeur => constructeur.DescendantNodes() .Where(x => { var assignation = x as AssignmentExpressionSyntax; return assignation?.Left != null && modèleSémantique.GetSymbolInfo(assignation.Left).Symbol == context.Symbol; }).Concat( constructeur.DescendantNodes() .Where(x => { var argument = x as ArgumentSyntax; return argument?.RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword && modèleSémantique.GetSymbolInfo(argument.Expression).Symbol == context.Symbol; }))); // Si le champ n'est jamais initialisé, on lève l'erreur. return usages.Count() == 0; }
private void CheckOperators(SymbolAnalysisContext analysisContext, INamedTypeSymbol namedType, ImmutableArray<ISymbol> operators1, ImmutableArray<ISymbol> operators2, string opName1, string opName2) { foreach (var operator1 in operators1) { if (!operator1.IsUserDefinedOperator()) { continue; } if (operator1.GetParameters().Length != 2) { continue; } if (HasSymmetricOperator(operator1, operators2)) { continue; } // Operator was missing match. // Since_0_redefines_operator_1_it_should_also_redefine_operator_2 analysisContext.ReportDiagnostic(operator1.CreateDiagnostic( Rule, namedType.Name, opName1, opName2)); } }
private static bool ContainingTypeImplementsIDisposableAndCallsItOnTheField(SymbolAnalysisContext context, IFieldSymbol fieldSymbol) { var containingType = fieldSymbol.ContainingType; if (containingType == null) return false; var iDisposableInterface = containingType.AllInterfaces.FirstOrDefault(i => i.ToString() == "System.IDisposable"); if (iDisposableInterface == null) return false; var disposableMethod = iDisposableInterface.GetMembers("Dispose").OfType<IMethodSymbol>().First(d => d.Arity == 0); var disposeMethodSymbol = containingType.FindImplementationForInterfaceMember(disposableMethod) as IMethodSymbol; if (disposeMethodSymbol == null) return false; if (disposeMethodSymbol.IsAbstract) return true; foreach (MethodDeclarationSyntax disposeMethod in disposeMethodSymbol.DeclaringSyntaxReferences.Select(sr => sr.GetSyntax())) { if (disposeMethod == null) return false; var semanticModel = context.Compilation.GetSemanticModel(disposeMethod.SyntaxTree); if (CallsDisposeOnField(fieldSymbol, disposeMethod, semanticModel)) return true; var invocations = disposeMethod.DescendantNodes().OfKind<InvocationExpressionSyntax>(SyntaxKind.InvocationExpression); foreach (var invocation in invocations) { var invocationExpressionSymbol = semanticModel.GetSymbolInfo(invocation.Expression).Symbol; if (invocationExpressionSymbol == null || invocationExpressionSymbol.Kind != SymbolKind.Method || invocationExpressionSymbol.Locations.Any(l => l.Kind != LocationKind.SourceFile) || !invocationExpressionSymbol.ContainingType.Equals(containingType)) continue; foreach (MethodDeclarationSyntax method in invocationExpressionSymbol.DeclaringSyntaxReferences.Select(sr => sr.GetSyntax())) if (CallsDisposeOnField(fieldSymbol, method, semanticModel)) return true; } } return false; }
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol equatableType) { var namedType = context.Symbol as INamedTypeSymbol; if (namedType == null || !(namedType.TypeKind == TypeKind.Struct || namedType.TypeKind == TypeKind.Class)) { return; } bool overridesObjectEquals = namedType.OverridesEquals(); INamedTypeSymbol constructedEquatable = equatableType.Construct(namedType); INamedTypeSymbol implementation = namedType .Interfaces .Where(x => x.Equals(constructedEquatable)) .FirstOrDefault(); bool implementsEquatable = implementation != null; if (overridesObjectEquals && !implementsEquatable && namedType.TypeKind == TypeKind.Struct) { context.ReportDiagnostic(namedType.CreateDiagnostic(s_implementIEquatableDescriptor, namedType)); } if (!overridesObjectEquals && implementsEquatable) { context.ReportDiagnostic(namedType.CreateDiagnostic(s_overridesObjectEqualsDescriptor, namedType)); } }
private void HandleMethodDeclaration(SymbolAnalysisContext context) { IMethodSymbol symbol = (IMethodSymbol)context.Symbol; if (symbol.Name.EndsWith("Async", StringComparison.Ordinal)) return; if (symbol.Locations.IsDefaultOrEmpty) return; Location location = symbol.Locations[0]; if (!location.IsInSource || location.SourceTree.IsGeneratedDocument(context.CancellationToken)) return; // void-returning methods are not asynchronous according to their signature, even if they use `async` if (symbol.ReturnsVoid) return; if (!string.Equals(nameof(Task), symbol.ReturnType?.Name, StringComparison.Ordinal)) return; if (!string.Equals(typeof(Task).Namespace, symbol.ReturnType?.ContainingNamespace?.ToString(), StringComparison.Ordinal)) return; if (symbol.MethodKind == MethodKind.PropertyGet || symbol.MethodKind == MethodKind.PropertySet) return; context.ReportDiagnostic(Diagnostic.Create(Descriptor, symbol.Locations[0], symbol.Name)); }
public override void Analyze(SymbolAnalysisContext context, List<IncludeAttributeData> includeTags, List<ProtobufAttributeData> memberTags, List<ContractAttributeData> contractAttributes) { if (!includeTags.Any()) { return; } var allTags = includeTags.Concat(memberTags); // Group it by tag var groupedByTag = allTags .GroupBy(m => m.Tag) .ToList(); // Any group with more than one element is suspicious foreach (var group in groupedByTag.Where(g => g.Count() > 1)) { // Any group with an include means an error if (group.Any(a => a is ProtoIncludeAttributeData)) { var symbolList = string.Join(", ", group.Select(g => g.GetRelevantSymbolName())); foreach (var a in group) { var diagnostic = Diagnostic.Create(GetDescriptor(), a.GetLocation(), a.Tag, context.Symbol.Name, symbolList); context.ReportDiagnostic(diagnostic); } } } }
private static void Analyze(SymbolAnalysisContext context) { if (context.IsGenerated()) return; var symbol = (INamedTypeSymbol)context.Symbol; if (symbol.TypeKind != TypeKind.Class) return; if (!symbol.Interfaces.Any(i => i.SpecialType == SpecialType.System_IDisposable)) return; if (symbol.IsSealed && !ContainsUserDefinedFinalizer(symbol)) return; if (!ContainsNonPrivateConstructors(symbol)) return; var disposeMethod = FindDisposeMethod(symbol); if (disposeMethod == null) return; var syntaxTree = disposeMethod.DeclaringSyntaxReferences[0]?.GetSyntax(); var statements = ((MethodDeclarationSyntax)syntaxTree)?.Body?.Statements.OfType<ExpressionStatementSyntax>(); if (statements != null) { foreach (var statement in statements) { var invocation = statement.Expression as InvocationExpressionSyntax; var method = invocation?.Expression as MemberAccessExpressionSyntax; var identifierSyntax = method?.Expression as IdentifierNameSyntax; if (identifierSyntax != null && identifierSyntax.Identifier.ToString() == "GC" && method.Name.ToString() == "SuppressFinalize") return; } } context.ReportDiagnostic(Diagnostic.Create(Rule, disposeMethod.Locations[0], symbol.Name)); }
/// <summary> /// Implementation for CA1044: Properties should not be write only /// </summary> private static void AnalyzeSymbol(SymbolAnalysisContext context) { var property = context.Symbol as IPropertySymbol; if (property == null) { return; } // not raising a violation for when: // property is overridden because the issue can only be fixed in the base type // property is the implementaton of any interface member if (property.IsOverride || property.IsImplementationOfAnyInterfaceMember()) { return; } // If property is not visible outside the assembly if (property.GetResultantVisibility() != SymbolVisibility.Public) { return; } // We handled the non-CA1044 cases earlier. Now, we handle CA1044 cases // If there is no getter then it is not accessible if (property.IsWriteOnly) { context.ReportDiagnostic(property.CreateDiagnostic(AddGetterRule, property.Name)); } // Otherwise if there is a setter, check for its relative accessibility else if (!(property.IsReadOnly) && (property.GetMethod.DeclaredAccessibility < property.SetMethod.DeclaredAccessibility)) { context.ReportDiagnostic(property.CreateDiagnostic(MakeMoreAccessibleRule, property.Name)); } }
private void CheckForDecreasedVisibility(SymbolAnalysisContext context) { ISymbol symbol = context.Symbol; // Only look for methods hiding others (not overriding). Overriding with a different visibility is already a compiler error if (symbol.IsOverride) { return; } // Bail out if the member is publicly accessible, or sealed, or on a sealed type if (IsVisibleOutsideAssembly(symbol) || symbol.IsSealed || (symbol.ContainingType?.IsSealed ?? true)) { return; } // Event accessors cannot have visibility modifiers, so don't analyze them if ((symbol as IMethodSymbol)?.AssociatedSymbol as IEventSymbol != null) { return; } // Find members on base types that share the member's name System.Collections.Generic.IEnumerable<INamedTypeSymbol> ancestorTypes = symbol?.ContainingType?.GetBaseTypes() ?? Enumerable.Empty<INamedTypeSymbol>(); System.Collections.Generic.IEnumerable<ISymbol> hiddenOrOverriddenMembers = ancestorTypes.SelectMany(t => t.GetMembers(symbol.Name)); if (hiddenOrOverriddenMembers.Any(IsVisibleOutsideAssembly)) { context.ReportDiagnostic(symbol.CreateDiagnostic(Rule)); } }
private void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol objectType, INamedTypeSymbol equatableType) { var namedType = context.Symbol as INamedTypeSymbol; if (namedType == null || !(namedType.TypeKind == TypeKind.Struct || namedType.TypeKind == TypeKind.Class)) { return; } var methodSymbol = namedType .GetMembers("Equals") .OfType<IMethodSymbol>() .Where(m => IsObjectEqualsOverride(m, objectType)) .FirstOrDefault(); var overridesObjectEquals = methodSymbol != null; var constructedEquatable = equatableType.Construct(namedType); var implementation = namedType .Interfaces .Where(x => x.Equals(constructedEquatable)) .FirstOrDefault(); var implementsEquatable = implementation != null; if (overridesObjectEquals && !implementsEquatable && namedType.TypeKind == TypeKind.Struct) { context.ReportDiagnostic(Diagnostic.Create(s_implementIEquatableDescriptor, methodSymbol.Locations[0], namedType)); } if (!overridesObjectEquals && implementsEquatable) { context.ReportDiagnostic(Diagnostic.Create(s_overridesObjectEqualsDescriptor, namedType.Locations[0], namedType)); } }
private static void CheckClassWithOnlyUnusedPrivateConstructors(SymbolAnalysisContext context) { var namedType = context.Symbol as INamedTypeSymbol; if (!namedType.IsClass() || namedType.IsStatic) { return; } var members = namedType.GetMembers(); var constructors = GetConstructors(members).ToList(); if (!constructors.Any() || HasNonPrivateConstructor(constructors) || HasOnlyStaticMembers(members.Except(constructors).ToList())) { return; } var classDeclarations = new RemovableDeclarationCollector(namedType, context.Compilation).ClassDeclarations; if (!IsAnyConstructorCalled(namedType, classDeclarations)) { var message = constructors.Count > 1 ? "at least one of its constructors" : "its constructor"; foreach (var classDeclaration in classDeclarations) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, classDeclaration.SyntaxNode.Identifier.GetLocation(), message)); } } }
private void AnalyzeSymbol(SymbolAnalysisContext context) { var symbol = (IPropertySymbol)context.Symbol; if (symbol.IsIndexer && !symbol.IsOverride) { if (symbol.GetParameters().Length == 1) { ITypeSymbol paramType = symbol.GetParameters()[0].Type; if (paramType.TypeKind == TypeKind.TypeParameter) { return; } if (paramType.TypeKind == TypeKind.Enum) { paramType = ((INamedTypeSymbol)paramType).EnumUnderlyingType; } if (!s_allowedTypes.Contains(paramType.SpecialType)) { context.ReportDiagnostic(symbol.CreateDiagnostic(Rule)); } } } }
private static void AnalyzeSymbol(SymbolAnalysisContext context) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; if (HasStackOnlyAttribute(namedTypeSymbol)) { if (namedTypeSymbol.IsValueType) { return; } else { // reference types should not have StackOnlyAttribute applied var diagnosticClass = Diagnostic.Create(RuleStackOnlyClass, namedTypeSymbol.Locations[0], namedTypeSymbol.Name); context.ReportDiagnostic(diagnosticClass); } } // This is not a stack-only type, so ... // check if any fields are of stack-only types foreach (var member in namedTypeSymbol.GetMembers()) { var field = member as IFieldSymbol; if (field == null) { continue; } var fieldType = field.Type; if(HasStackOnlyAttribute(fieldType)) { var diagnostic = Diagnostic.Create(RuleStackOnlyField, field.Locations[0], field.Type.Name); context.ReportDiagnostic(diagnostic); } } }
protected void AnalyzeType(SymbolAnalysisContext context) { var potentialController = (INamedTypeSymbol)context.Symbol; if (potentialController.AllInterfaces.Length == 0) return; var controllerTechnology = DetermineWebTechnology(potentialController.AllInterfaces); if (controllerTechnology == WebTechnology.None) return; var controllerAttributes = potentialController.GetAttributes(); foreach (var controllerAttribute in controllerAttributes) { var attributeTechnology = DetermineWebTechnology(controllerAttribute.AttributeClass.AllInterfaces); if (attributeTechnology != WebTechnology.None && attributeTechnology != controllerTechnology) context.ReportDiagnostic(Diagnostic.Create(webTechMixDiagnosticDescriptor, potentialController.Locations[0], controllerAttribute.AttributeClass.Name, attributeTechnology, potentialController.Name, controllerTechnology)); } foreach (var method in potentialController.GetMembers().Where(m => m.Kind == SymbolKind.Method)) { foreach (var methodAttribute in method.GetAttributes()) { var attributeTechnology = DetermineWebTechnology(methodAttribute.AttributeClass.AllInterfaces); if (attributeTechnology != WebTechnology.None && attributeTechnology != controllerTechnology) { context.ReportDiagnostic(Diagnostic.Create(webTechMixDiagnosticDescriptor, method.Locations[0], methodAttribute.AttributeClass.Name, attributeTechnology, potentialController.Name, controllerTechnology)); break; } } } }
/// <summary> /// Returns the first symbol matching the specified <paramref name="type"/>. /// </summary> /// <param name="type"> /// The <see cref="T:System.Type"/> for the symbol to match. /// </param> /// <param name="context"> /// The context to use to find the symbol. /// </param> /// <returns> /// The symbol if found; otherwise null. /// </returns> public static INamedTypeSymbol GetNamedSymbol(this Type type, SymbolAnalysisContext context) { foreach (var reference in context.Compilation.References) { if(reference == null) { continue; } var assembly = context.Compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol; if (assembly == null) { continue; } if (!assembly.Name.Equals(type.GetTypeInfo().Assembly.GetName().Name, StringComparison.CurrentCultureIgnoreCase)) { continue; } var namedTypeSymbol = assembly.GetTypeByMetadataName(type.FullName); if(namedTypeSymbol == null) { continue; } return namedTypeSymbol; } return null; }
private void AnalyzeSymbol(SymbolAnalysisContext context) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; var members = namedTypeSymbol.GetMembers().Where(x => !x.IsImplicitlyDeclared && x.CanBeReferencedByName).ToArray(); var orderedMembers = members.OrderBy(x => x.DeclaredAccessibility).ThenBy(x => x.Kind).ThenBy(x => x.Name).ToArray(); var alphabetized = true; for (var i = 0; i < members.Length; i++) { if(orderedMembers[i] != members[i]) { alphabetized = false; } } if (!alphabetized) { var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name); context.ReportDiagnostic(diagnostic); } }
public override void Analyze(SymbolAnalysisContext context, List<IncludeAttributeData> includeTags, List<ProtobufAttributeData> memberTags, List<ContractAttributeData> contractAttributes) { var grouped = memberTags.GroupBy(t => t.Symbol); foreach (var tagPerSymbol in grouped) { var list = tagPerSymbol.ToList(); var protoMemberAttributes = list.Where(a => a is ProtoMemberAttributeData).Cast<ProtoMemberAttributeData>().ToList(); var dataMemberAttributes = list.Where(a => a is DataMemberAttributeData).Cast<DataMemberAttributeData>().ToList(); foreach (var protoMemberTag in protoMemberAttributes) { foreach (var mismatchedDataMember in dataMemberAttributes.Where(d => d.Tag != protoMemberTag.Tag)) { context.ReportDiagnostic(Diagnostic.Create( GetDescriptor(), protoMemberTag.GetLocation(), protoMemberTag.Symbol.Name, protoMemberTag.Tag, mismatchedDataMember.Tag)); context.ReportDiagnostic(Diagnostic.Create( GetDescriptor(), mismatchedDataMember.GetLocation(), mismatchedDataMember.Symbol.Name, protoMemberTag.Tag, mismatchedDataMember.Tag)); } } } }
private void HandleMethodDeclaration(SymbolAnalysisContext context) { IMethodSymbol symbol = (IMethodSymbol)context.Symbol; if (symbol.IsAsync) return; if (!symbol.Name.EndsWith("Async", StringComparison.Ordinal)) return; if (symbol.Locations.IsDefaultOrEmpty) return; Location location = symbol.Locations[0]; if (!location.IsInSource || location.SourceTree.IsGeneratedDocument(context.CancellationToken)) return; if (!symbol.ReturnsVoid) { if (string.Equals(nameof(Task), symbol.ReturnType?.Name, StringComparison.Ordinal) && string.Equals(typeof(Task).Namespace, symbol.ReturnType?.ContainingNamespace?.ToString(), StringComparison.Ordinal)) { return; } } if (symbol.IsOverride) return; context.ReportDiagnostic(Diagnostic.Create(Descriptor, symbol.Locations[0], symbol.Name)); }
private void AnalyzeSymbol(SymbolAnalysisContext context) { var namedTypeSymbol = context.Symbol as INamedTypeSymbol; //Check if type derives from Exception type if (namedTypeSymbol.BaseType == exceptionType) { //Get the list of constructors var constructors = namedTypeSymbol.Constructors; //Set flags for the 3 different constructos, that is being searched for var defaultConstructorFound = false; //flag for default constructor var secondConstructorFound = false; //flag for constructor with string type parameter var thirdConstructorFound = false; //flag for constructor with string and exception type parameter foreach (var ctor in constructors) { var parameters = ctor.GetParameters(); //case 1: Default constructor - no parameters if (parameters.Length == 0) { defaultConstructorFound = true; } //case 2: Constructor with string type parameter else if (parameters.Length == 1 && parameters[0].Type.SpecialType == SpecialType.System_String) { secondConstructorFound = true; } //case 3: Constructor with string type and exception type parameter else if (parameters.Length == 2 && parameters[0].Type.SpecialType == SpecialType.System_String && parameters[1].Type == exceptionType) { thirdConstructorFound = true; } if (defaultConstructorFound && secondConstructorFound && thirdConstructorFound) { //reaches here only when all 3 constructors are found - no diagnostic needed return; } } //end of for loop if (!defaultConstructorFound) //missing default constructor { BuildDiagnostic(context, namedTypeSymbol, MissingCtorSignature.CtorWithNoParameter, GetConstructorSignatureNoParameter(namedTypeSymbol)); } if (!secondConstructorFound) //missing constructor with string parameter { BuildDiagnostic(context, namedTypeSymbol, MissingCtorSignature.CtorWithStringParameter, GetConstructorSignatureStringTypeParameter(namedTypeSymbol)); } if (!thirdConstructorFound) //missing constructor with string and exception type parameter - report diagnostic { BuildDiagnostic(context, namedTypeSymbol, MissingCtorSignature.CtorWithStringAndExceptionParameters, GetConstructorSignatureStringAndExceptionTypeParameter(namedTypeSymbol)); } } }
private static bool IsViewModelType(SymbolAnalysisContext context, ITypeSymbol symbol) { var iMvxViewModelType = context.Compilation.GetTypeByMetadataName(typeof(IMvxViewModel).FullName); var iNotifyPropertyChangedType = context.Compilation.GetTypeByMetadataName(typeof(System.ComponentModel.INotifyPropertyChanged).FullName); return symbol.ImplementsSymbol(iMvxViewModelType) || symbol.ImplementsSymbol(iNotifyPropertyChangedType); }
internal void AnalyzeSymbol(SymbolAnalysisContext symbolContext) { var namedType = (INamedTypeSymbol)symbolContext.Symbol; if (namedType.GetBaseTypes().Any(IsDiagnosticAnalyzer)) { AnalyzeDiagnosticAnalyzer(symbolContext); } }
private void HandleMethodDeclaration(SymbolAnalysisContext context) { IMethodSymbol symbol = (IMethodSymbol)context.Symbol; if (!symbol.IsAsync || !symbol.ReturnsVoid) return; context.ReportDiagnostic(Diagnostic.Create(Descriptor, symbol.Locations[0], symbol.Name)); }
private void AnalyzeInterface(SymbolAnalysisContext context) { var symbol = (INamedTypeSymbol)context.Symbol; if (symbol.TypeKind == TypeKind.Interface && !symbol.GetMembers().Any() && !symbol.AllInterfaces.SelectMany(s => s.GetMembers()).Any()) { context.ReportDiagnostic(symbol.CreateDiagnostic(Rule)); } }
public static void AnalyzeNamedType(SymbolAnalysisContext context) { var symbol = (INamedTypeSymbol)context.Symbol; if (symbol.TypeKind != TypeKind.Class) { return; } if (symbol.IsStatic) { return; } if (symbol.IsAbstract) { return; } if (symbol.IsImplicitClass) { return; } if (symbol.IsImplicitlyDeclared) { return; } if (symbol.BaseType?.IsObject() != true) { return; } if (!symbol.Interfaces.IsDefaultOrEmpty) { return; } var syntaxReferences = default(ImmutableArray <SyntaxReference>); if (symbol.IsSealed) { syntaxReferences = symbol.DeclaringSyntaxReferences; if (syntaxReferences.Length != 1) { return; } } if (!AnalyzeMembers(symbol)) { return; } if (syntaxReferences.IsDefault) { syntaxReferences = symbol.DeclaringSyntaxReferences; } foreach (SyntaxReference syntaxReference in syntaxReferences) { var classDeclaration = (ClassDeclarationSyntax)syntaxReference.GetSyntax(context.CancellationToken); if (!classDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword)) { context.ReportDiagnostic(DiagnosticDescriptors.MakeClassStatic, classDeclaration.Identifier); break; } } }
private void AnalyzeProperty(ConcurrentBag <AnalysisResult> analysisResults, SymbolAnalysisContext symbolContext) { var property = (IPropertySymbol)symbolContext.Symbol; if (property.IsIndexer) { return; } // The property can't be virtual. We don't know if it is overridden somewhere. If it // is, then calls to it may not actually assign to the field. if (property.IsVirtual || property.IsOverride || property.IsSealed) { return; } if (property.IsWithEvents) { return; } if (property.Parameters.Length > 0) { return; } // Need at least a getter. if (property.GetMethod == null) { return; } var containingType = property.ContainingType; if (containingType == null) { return; } var declarations = property.DeclaringSyntaxReferences; if (declarations.Length != 1) { return; } var cancellationToken = symbolContext.CancellationToken; var propertyDeclaration = property.DeclaringSyntaxReferences[0].GetSyntax(cancellationToken).FirstAncestorOrSelf <TPropertyDeclaration>(); if (propertyDeclaration == null) { return; } var semanticModel = symbolContext.Compilation.GetSemanticModel(propertyDeclaration.SyntaxTree); var getterField = GetGetterField(semanticModel, property.GetMethod, cancellationToken); if (getterField == null) { return; } // If the user made the field readonly, we only want to convert it to a property if we // can keep it readonly. if (getterField.IsReadOnly && !SupportsReadOnlyProperties(symbolContext.Compilation)) { return; } if (!containingType.Equals(getterField.ContainingType)) { // Field and property have to be in the same type. return; } // Property and field have to agree on type. if (!property.Type.Equals(getterField.Type)) { return; } // Don't want to remove constants. if (getterField.IsConst) { return; } if (getterField.DeclaringSyntaxReferences.Length != 1) { return; } // Field and property should match in static-ness if (getterField.IsStatic != property.IsStatic) { return; } // A setter is optional though. var setMethod = property.SetMethod; if (setMethod != null) { var setterField = GetSetterField(semanticModel, containingType, setMethod, cancellationToken); if (setterField != getterField) { // If there is a getter and a setter, they both need to agree on which field they are // writing to. return; } } var fieldReference = getterField.DeclaringSyntaxReferences[0]; var variableDeclarator = fieldReference.GetSyntax(symbolContext.CancellationToken) as TVariableDeclarator; if (variableDeclarator == null) { return; } var initializer = GetFieldInitializer(variableDeclarator, cancellationToken); if (initializer != null && !SupportsPropertyInitializer(symbolContext.Compilation)) { return; } var fieldDeclaration = variableDeclarator?.Parent?.Parent as TFieldDeclaration; if (fieldDeclaration == null) { return; } // Can't remove the field if it has attributes on it. if (getterField.GetAttributes().Length > 0) { return; } // Looks like a viable property/field to convert into an auto property. analysisResults.Add(new AnalysisResult(property, getterField, propertyDeclaration, fieldDeclaration, variableDeclarator, property.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))); }
public static void AnalyzeNamedType(SymbolAnalysisContext context) { var namedType = (INamedTypeSymbol)context.Symbol; if (namedType.IsTypeKind(TypeKind.Class, TypeKind.Struct) && namedType.Arity > 0 && !namedType.IsStatic && !namedType.IsImplicitClass && !namedType.IsImplicitlyDeclared) { foreach (ISymbol member in namedType.GetMembers()) { if (!member.IsImplicitlyDeclared && member.IsStatic && member.IsDeclaredAccessibility(Accessibility.Public, Accessibility.Internal, Accessibility.ProtectedOrInternal)) { switch (member.Kind) { case SymbolKind.Event: { var eventSymbol = (IEventSymbol)member; if (!ContainsAnyTypeParameter(namedType.TypeParameters, eventSymbol.Type)) { ReportDiagnostic(context, eventSymbol); } break; } case SymbolKind.Field: { var fieldSymbol = (IFieldSymbol)member; if (!ContainsAnyTypeParameter(namedType.TypeParameters, fieldSymbol.Type)) { ReportDiagnostic(context, fieldSymbol); } break; } case SymbolKind.Method: { var methodsymbol = (IMethodSymbol)member; if (methodsymbol.MethodKind == MethodKind.Ordinary) { ImmutableArray <ITypeParameterSymbol> typeParameters = namedType.TypeParameters; if (!ContainsAnyTypeParameter(typeParameters, methodsymbol.ReturnType) && !methodsymbol.Parameters.Any(parameter => ContainsAnyTypeParameter(typeParameters, parameter.Type))) { ReportDiagnostic(context, methodsymbol); } } break; } case SymbolKind.Property: { var propertySymbol = (IPropertySymbol)member; if (!propertySymbol.IsIndexer && !ContainsAnyTypeParameter(namedType.TypeParameters, propertySymbol.Type)) { ReportDiagnostic(context, propertySymbol); } break; } } } } } }
private static void AnalyzeSymbolForAttribute(ref SymbolAnalysisContext context, INamedTypeSymbol exportAttributeOpt, INamedTypeSymbol importingConstructorAttribute, INamedTypeSymbol namedType, IEnumerable <AttributeData> namedTypeAttributes) { if (exportAttributeOpt is null) { return; } var exportAttributeApplication = namedTypeAttributes.FirstOrDefault(ad => ad.AttributeClass.DerivesFrom(exportAttributeOpt)); if (exportAttributeApplication is null) { return; } IMethodSymbol importingConstructor = null; ImmutableArray <IMethodSymbol> nonImportingConstructors = ImmutableArray <IMethodSymbol> .Empty; foreach (var constructor in namedType.Constructors) { if (constructor.IsStatic) { // Ignore static constructors continue; } if (constructor.IsImplicitlyDeclared) { if (exportAttributeApplication.ApplicationSyntaxReference is object) { // '{0}' is MEF-exported and should have a single importing constructor of the correct form context.ReportDiagnostic(Diagnostic.Create(Rule, exportAttributeApplication.ApplicationSyntaxReference.GetSyntax().GetLocation(), ScenarioProperties.ImplicitConstructor, namedType.Name)); } continue; } var constructorAttributes = constructor.GetAttributes(); var appliedImportingConstructorAttribute = constructorAttributes.FirstOrDefault(ad => ad.AttributeClass.DerivesFrom(importingConstructorAttribute)); if (appliedImportingConstructorAttribute is null) { nonImportingConstructors = nonImportingConstructors.Add(constructor); continue; } importingConstructor = constructor; if (constructor.DeclaredAccessibility != Accessibility.Public) { // '{0}' is MEF-exported and should have a single importing constructor of the correct form context.ReportDiagnostic(Diagnostic.Create(Rule, appliedImportingConstructorAttribute.ApplicationSyntaxReference.GetSyntax().GetLocation(), ScenarioProperties.NonPublicConstructor, namedType.Name)); continue; } } IMethodSymbol missingImportingConstructor = null; if (importingConstructor is null) { missingImportingConstructor = nonImportingConstructors.FirstOrDefault(constructor => constructor.DeclaredAccessibility == Accessibility.Public) ?? nonImportingConstructors.FirstOrDefault(); } foreach (var constructor in nonImportingConstructors) { var properties = Equals(constructor, missingImportingConstructor) ? ScenarioProperties.MissingAttribute : ScenarioProperties.MultipleConstructors; // '{0}' is MEF-exported and should have a single importing constructor of the correct form context.ReportDiagnostic(Diagnostic.Create(Rule, constructor.DeclaringSyntaxReferences.First().GetSyntax().GetLocation(), properties, namedType.Name)); continue; } }
public static void AnalyzeNamedType(SymbolAnalysisContext context) { var typeSymbol = (INamedTypeSymbol)context.Symbol; if (typeSymbol.IsImplicitlyDeclared) { return; } if (typeSymbol.TypeKind != TypeKind.Enum) { return; } bool isFlags = typeSymbol.HasAttribute(MetadataNames.System_FlagsAttribute); ImmutableArray <ISymbol> members = default; if (isFlags && !context.IsAnalyzerSuppressed(DiagnosticDescriptors.DeclareEnumMemberWithZeroValue)) { members = typeSymbol.GetMembers(); if (!ContainsFieldWithZeroValue(members)) { var enumDeclaration = (EnumDeclarationSyntax)typeSymbol.GetSyntax(context.CancellationToken); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.DeclareEnumMemberWithZeroValue, enumDeclaration.Identifier); } } EnumSymbolInfo enumInfo = default; if (isFlags && !context.IsAnalyzerSuppressed(DiagnosticDescriptors.CompositeEnumValueContainsUndefinedFlag)) { enumInfo = EnumSymbolInfo.Create(typeSymbol); ImmutableArray <EnumFieldSymbolInfo> fields = enumInfo.Fields; for (int i = 0; i < fields.Length; i++) { if (fields[i].HasValue && fields[i].HasCompositeValue()) { foreach (ulong value in (fields[i].DecomposeValue())) { if (!enumInfo.Contains(value)) { ReportUndefinedFlag(context, fields[i].Symbol, value.ToString()); } } } } } if (isFlags && !context.IsAnalyzerSuppressed(DiagnosticDescriptors.DeclareEnumValueAsCombinationOfNames)) { if (members.IsDefault) { members = typeSymbol.GetMembers(); } foreach (ISymbol member in members) { if (!(member is IFieldSymbol fieldSymbol)) { continue; } if (!fieldSymbol.HasConstantValue) { return; } EnumFieldSymbolInfo fieldInfo = EnumFieldSymbolInfo.Create(fieldSymbol); if (!fieldInfo.HasCompositeValue()) { continue; } var declaration = (EnumMemberDeclarationSyntax)fieldInfo.Symbol.GetSyntax(context.CancellationToken); ExpressionSyntax expression = declaration.EqualsValue?.Value; if (expression != null && (expression.IsKind(SyntaxKind.NumericLiteralExpression) || expression .DescendantNodes() .Any(f => f.IsKind(SyntaxKind.NumericLiteralExpression)))) { if (enumInfo.IsDefault) { enumInfo = EnumSymbolInfo.Create(typeSymbol); if (enumInfo.Fields.Any(f => !f.HasValue)) { return; } } List <EnumFieldSymbolInfo> values = enumInfo.Decompose(fieldInfo); if (values?.Count > 1) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.DeclareEnumValueAsCombinationOfNames, expression); } } } } if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.DuplicateEnumValue)) { if (enumInfo.IsDefault) { enumInfo = EnumSymbolInfo.Create(typeSymbol); } ImmutableArray <EnumFieldSymbolInfo> fields = enumInfo.Fields; if (fields.Length > 1) { EnumFieldSymbolInfo symbolInfo1 = fields[0]; EnumFieldSymbolInfo symbolInfo2 = default; for (int i = 1; i < fields.Length; i++, symbolInfo1 = symbolInfo2) { symbolInfo2 = fields[i]; if (!symbolInfo1.HasValue || !symbolInfo2.HasValue || symbolInfo1.Value != symbolInfo2.Value) { continue; } var enumMember1 = (EnumMemberDeclarationSyntax)symbolInfo1.Symbol.GetSyntax(context.CancellationToken); if (enumMember1 == null) { continue; } var enumMember2 = (EnumMemberDeclarationSyntax)symbolInfo2.Symbol.GetSyntax(context.CancellationToken); if (enumMember2 == null) { continue; } ExpressionSyntax value1 = enumMember1.EqualsValue?.Value?.WalkDownParentheses(); ExpressionSyntax value2 = enumMember2.EqualsValue?.Value?.WalkDownParentheses(); if (value1 == null) { if (value2 != null) { ReportDuplicateValue(context, enumMember1); } } else if (value2 == null) { ReportDuplicateValue(context, enumMember2); } else { SyntaxKind kind1 = value1.Kind(); SyntaxKind kind2 = value2.Kind(); if (kind1 == SyntaxKind.NumericLiteralExpression) { if (kind2 == SyntaxKind.NumericLiteralExpression) { var enumDeclaration = (EnumDeclarationSyntax)enumMember1.Parent; SeparatedSyntaxList <EnumMemberDeclarationSyntax> enumMembers = enumDeclaration.Members; if (enumMembers.IndexOf(enumMember1) < enumMembers.IndexOf(enumMember2)) { ReportDuplicateValue(context, value2); } else { ReportDuplicateValue(context, value1); } } else if (!string.Equals((value2 as IdentifierNameSyntax)?.Identifier.ValueText, enumMember1.Identifier.ValueText, StringComparison.Ordinal)) { ReportDuplicateValue(context, value1); } } else if (kind2 == SyntaxKind.NumericLiteralExpression && !string.Equals((value1 as IdentifierNameSyntax)?.Identifier.ValueText, enumMember2.Identifier.ValueText, StringComparison.Ordinal)) { ReportDuplicateValue(context, value2); } } } } } }
private static void ReportDiagnostic(SymbolAnalysisContext context, [NotNull] ISymbol symbol, [NotNull] string name) { Diagnostic diagnostic = Diagnostic.Create(Rule, symbol.Locations[0], name); context.ReportDiagnostic(diagnostic); }
protected override void AnalyzeNode(SymbolAnalysisContext symbolContext, TInvocationExpressionSyntax invocation, SemanticModel semanticModel) { var symbol = semanticModel.GetSymbolInfo(invocation, symbolContext.CancellationToken).Symbol; if (symbol == null || symbol.Kind != SymbolKind.Method || !symbol.Name.StartsWith("Register")) { return; } var method = (IMethodSymbol)symbol; var isRegisterSymbolAction = IsRegisterAction(RegisterSymbolActionName, method, analysisContext, compilationStartAnalysisContext); var isRegisterSyntaxNodeAction = IsRegisterAction(RegisterSyntaxNodeActionName, method, analysisContext, compilationStartAnalysisContext, codeBlockStartAnalysisContext); var isRegisterCodeBlockStartAction = IsRegisterAction(RegisterCodeBlockStartActionName, method, analysisContext, compilationStartAnalysisContext); if (isRegisterSymbolAction || isRegisterSyntaxNodeAction) { if (method.Parameters.Length == 2 && method.Parameters[1].IsParams) { var arguments = GetArgumentExpressions(invocation); if (arguments != null) { var argumentCount = arguments.Count(); if (argumentCount >= 1) { var type = semanticModel.GetTypeInfo(arguments.First(), symbolContext.CancellationToken).ConvertedType; if (type == null || type.Name.Equals(nameof(Action))) { if (argumentCount == 1) { string arg1, arg2; if (isRegisterSymbolAction) { arg1 = nameof(SymbolKind); arg2 = "symbol"; } else { arg1 = "SyntaxKind"; arg2 = "syntax"; } var invocationExpression = GetInvocationExpression(invocation); var diagnostic = Diagnostic.Create(MissingKindArgumentRule, invocationExpression.GetLocation(), arg1, arg2); symbolContext.ReportDiagnostic(diagnostic); } else if (isRegisterSymbolAction) { foreach (var argument in arguments.Skip(1)) { symbol = semanticModel.GetSymbolInfo(argument, symbolContext.CancellationToken).Symbol; if (symbol != null && symbol.Kind == SymbolKind.Field && symbolKind.Equals(symbol.ContainingType) && !supportedSymbolKinds.Contains(symbol.Name)) { var diagnostic = Diagnostic.Create(UnsupportedSymbolKindArgumentRule, argument.GetLocation(), symbol.Name); symbolContext.ReportDiagnostic(diagnostic); } } } } } } } } if (isRegisterSyntaxNodeAction || isRegisterCodeBlockStartAction) { Debug.Assert(method.TypeParameters.Length > 0); ITypeSymbol typeArgument = null; if (method.TypeParameters.Length == 1) { if (method.TypeParameters[0].Name == TLanguageKindEnumName) { typeArgument = method.TypeArguments[0]; } } else { var typeParam = method.TypeParameters.SingleOrDefault(t => t.Name == TLanguageKindEnumName); if (typeParam != null) { var index = method.TypeParameters.IndexOf(typeParam); typeArgument = method.TypeArguments[index]; } } if (typeArgument != null && typeArgument.TypeKind != TypeKind.TypeParameter && typeArgument.TypeKind != TypeKind.Error && !IsSyntaxKind(typeArgument)) { var location = typeArgument.Locations[0]; if (!location.IsInSource) { var invocationExpression = GetInvocationExpression(invocation); location = invocationExpression.GetLocation(); } var diagnostic = Diagnostic.Create(InvalidSyntaxKindTypeArgumentRule, location, typeArgument.Name, TLanguageKindEnumName, method.Name); symbolContext.ReportDiagnostic(diagnostic); } } }
private static void AnalyzeEvent(SymbolAnalysisContext context) { var eventSymbol = (IEventSymbol)context.Symbol; if (eventSymbol.IsImplicitlyDeclared) { return; } if (eventSymbol.IsOverride) { return; } if (!eventSymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty) { return; } var namedType = eventSymbol.Type as INamedTypeSymbol; if (namedType?.Arity != 0) { return; } if (namedType.HasMetadataName(MetadataNames.System_EventHandler)) { return; } IMethodSymbol delegateInvokeMethod = namedType.DelegateInvokeMethod; if (delegateInvokeMethod == null) { return; } ImmutableArray <IParameterSymbol> parameters = delegateInvokeMethod.Parameters; if (parameters.Length != 2) { return; } if (!parameters[0].Type.IsObject()) { return; } if (eventSymbol.ImplementsInterfaceMember <IEventSymbol>(allInterfaces: true)) { return; } SyntaxNode node = eventSymbol.GetSyntax(context.CancellationToken); TypeSyntax type = GetTypeSyntax(node); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseGenericEventHandler, type); }
private static void ReportDiagnostic(ITypeSymbol type, TTypeSyntax typeSyntax, SymbolAnalysisContext context) { var diagnostic = Diagnostic.Create(DoNotStorePerCompilationDataOntoFieldsRule, typeSyntax.GetLocation(), type.ToDisplayString()); context.ReportDiagnostic(diagnostic); }
public void AnalyzeSymbol(SymbolAnalysisContext context) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; if (namedTypeSymbol.TypeKind is TypeKind.Delegate or TypeKind.Interface) { return; } var implementsISerializable = namedTypeSymbol.AllInterfaces.Contains(_iserializableTypeSymbol); var isSerializable = IsSerializable(namedTypeSymbol); // If the type is public and implements ISerializable if (namedTypeSymbol.DeclaredAccessibility == Accessibility.Public && implementsISerializable) { if (!isSerializable) { // CA2237 : Mark serializable types with the SerializableAttribute if (namedTypeSymbol.BaseType.SpecialType == SpecialType.System_Object || IsSerializable(namedTypeSymbol.BaseType)) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2237, namedTypeSymbol.Name)); } } else { // Look for a serialization constructor. // A serialization constructor takes two params of type SerializationInfo and StreamingContext. IMethodSymbol serializationCtor = namedTypeSymbol.Constructors .FirstOrDefault(c => c.IsSerializationConstructor(_serializationInfoTypeSymbol, _streamingContextTypeSymbol)); // There is no serialization ctor - issue a diagnostic. if (serializationCtor == null) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2229Default, namedTypeSymbol.Name)); } else { // Check the accessibility // The serialization ctor should be protected if the class is unsealed and private if the class is sealed. if (namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Private) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229Sealed, namedTypeSymbol.Name)); } if (!namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Protected) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229Unsealed, namedTypeSymbol.Name)); } } } } // If this is type is marked Serializable and doesn't implement ISerializable, check its fields' types as well if (isSerializable && !implementsISerializable) { foreach (ISymbol member in namedTypeSymbol.GetMembers()) { // Only process field members if (member is not IFieldSymbol field) { continue; } // Only process instance fields if (field.IsStatic) { continue; } // Only process non-serializable fields if (IsSerializable(field.Type)) { continue; } // We bail out from reporting CA2235 in netstandard assemblies for types in metadata // due to missing support: https://github.com/dotnet/roslyn-analyzers/issues/1775#issuecomment-519686818 if (_isNetStandardAssembly && field.Type.Locations.All(l => !l.IsInSource)) { continue; } // Check for [NonSerialized] if (field.GetAttributes().Any(x => x.AttributeClass.Equals(_nonSerializedAttributeTypeSymbol))) { continue; } // Handle compiler-generated fields (without source declaration) that have an associated symbol in code. // For example, auto-property backing fields. ISymbol targetSymbol = field.IsImplicitlyDeclared && field.AssociatedSymbol != null ? field.AssociatedSymbol : field; context.ReportDiagnostic( targetSymbol.CreateDiagnostic( RuleCA2235, targetSymbol.Name, namedTypeSymbol.Name, field.Type)); } } }
private void AnalyzeType(SymbolAnalysisContext context) { // Are there any problems with this symbol? If there is, I don't want to continue because the code // fix needs a good class declaration because I will build up the DebuggerDisplay parameter based // on the inheritance (IEnumerable only), properties, and fields. I don't want to create a string // with bad data. var diagnostics = context.Compilation.GetDeclarationDiagnostics(); if (diagnostics.Any()) { return; } INamedTypeSymbol namedSymbol = context.Symbol as INamedTypeSymbol; // Right now this analyzer only applies to classes. It could be applicable to structs, but if (namedSymbol.IsValueType) { return; } if (namedSymbol.DeclaredAccessibility != Accessibility.Public) { return; } // If there's no "state" (fields or properties) there's no sense to have a DebuggerDisplayAttribute. var propsOrFields = namedSymbol.GetMembers().Where(n => ((n.Kind == SymbolKind.Property) || (n.Kind == SymbolKind.Field))); if (!propsOrFields.Any()) { return; } // Make sure we look for the parameterless ToString that is on this type. IMethodSymbol method = namedSymbol.GetSpecificMethod("ToString", new Type[0]); if (method != null) { return; } // Grind through the attributes for DebuggerDisplay. var attributes = namedSymbol.GetAttributes(); for (Int32 i = 0; i < attributes.Length; i++) { String name = attributes[i].AttributeClass.Name; if (name.EndsWith("DebuggerDisplayAttribute")) { var args = attributes[i].ConstructorArguments; for (Int32 j = 0; j < args.Count(); j++) { String textValue = args[j].Value.ToString(); if (!(String.IsNullOrEmpty(textValue))) { return; } } } } var diagnostic = Diagnostic.Create(Rule, namedSymbol.Locations[0], namedSymbol.Name); context.ReportDiagnostic(diagnostic); }
private static void AnalyzeMethodSymbol(SymbolAnalysisContext analysisContext) { var methodSymbol = (IMethodSymbol)analysisContext.Symbol; if (!methodSymbol.IsExternallyVisible() || !(methodSymbol.CanBeReferencedByName || methodSymbol.IsImplementationOfAnyExplicitInterfaceMember()) || !methodSymbol.Locations.Any(x => x.IsInSource) || string.IsNullOrWhiteSpace(methodSymbol.Name)) { return; } if (!methodSymbol.IsOverride && !methodSymbol.IsImplementationOfAnyImplicitInterfaceMember()) { return; } ImmutableArray <IMethodSymbol> originalDefinitions = GetOriginalDefinitions(methodSymbol); if (originalDefinitions.Length == 0) { // We did not find any original definitions so we don't have to do anything. // This can happen when the method has an override modifier, // but does not have any valid method it is overriding. return; } IMethodSymbol bestMatch = null; int bestMatchScore = -1; foreach (var originalDefinition in originalDefinitions) { // always prefer the method override, if it is available // (the overridden method will always be the first item in the list.) if (originalDefinition.ContainingType.TypeKind != TypeKind.Interface) { bestMatch = originalDefinition; break; } int currentMatchScore = 0; for (int i = 0; i < methodSymbol.Parameters.Length; i++) { IParameterSymbol currentParameter = methodSymbol.Parameters[i]; IParameterSymbol originalParameter = originalDefinition.Parameters[i]; if (currentParameter.Name == originalParameter.Name) { currentMatchScore++; } } if (currentMatchScore > bestMatchScore) { bestMatch = originalDefinition; bestMatchScore = currentMatchScore; if (bestMatchScore == methodSymbol.Parameters.Length) { break; } } } for (int i = 0; i < methodSymbol.Parameters.Length; i++) { IParameterSymbol currentParameter = methodSymbol.Parameters[i]; IParameterSymbol bestMatchParameter = bestMatch.Parameters[i]; if (currentParameter.Name != bestMatchParameter.Name) { var properties = ImmutableDictionary <string, string> .Empty.SetItem(NewNamePropertyName, bestMatchParameter.Name); analysisContext.ReportDiagnostic(Diagnostic.Create(Rule, currentParameter.Locations.First(), properties, methodSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), currentParameter.Name, bestMatchParameter.Name, bestMatch.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat))); } } }
private static void ReportDuplicateValue(SymbolAnalysisContext context, SyntaxNode node) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.DuplicateEnumValue, node); }
private static void AnalyzeSymbol( SymbolAnalysisContext context, INamedTypeSymbol?iCollectionType, INamedTypeSymbol?gCollectionType, INamedTypeSymbol?iEnumerableType, INamedTypeSymbol?gEnumerableType, INamedTypeSymbol?iListType, INamedTypeSymbol?gListType) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; // FxCop compat: only fire on externally visible types by default. if (!namedTypeSymbol.MatchesConfiguredVisibility(context.Options, Rule, context.CancellationToken)) { return; } var allInterfacesStatus = default(CollectionsInterfaceStatus); foreach (var @interface in namedTypeSymbol.AllInterfaces) { var originalDefinition = @interface.OriginalDefinition; if (originalDefinition.Equals(iCollectionType)) { allInterfacesStatus.ICollectionPresent = true; } else if (originalDefinition.Equals(iEnumerableType)) { allInterfacesStatus.IEnumerablePresent = true; } else if (originalDefinition.Equals(iListType)) { allInterfacesStatus.IListPresent = true; } else if (originalDefinition.Equals(gCollectionType)) { allInterfacesStatus.GenericICollectionPresent = true; } else if (originalDefinition.Equals(gEnumerableType)) { allInterfacesStatus.GenericIEnumerablePresent = true; } else if (originalDefinition.Equals(gListType)) { allInterfacesStatus.GenericIListPresent = true; } } INamedTypeSymbol?missingInterface; INamedTypeSymbol?implementedInterface; if (allInterfacesStatus.GenericIListPresent) { // Implemented IList<T>, meaning has all 3 generic interfaces. Nothing can be wrong. return; } else if (allInterfacesStatus.IListPresent) { // Implemented IList but not IList<T>. missingInterface = gListType; implementedInterface = iListType; } else if (allInterfacesStatus.GenericICollectionPresent) { // Implemented ICollection<T>, and doesn't have an inherit of IList. Nothing can be wrong return; } else if (allInterfacesStatus.ICollectionPresent) { // Implemented ICollection but not ICollection<T> missingInterface = gCollectionType; implementedInterface = iCollectionType; } else if (allInterfacesStatus.GenericIEnumerablePresent) { // Implemented IEnumerable<T>, and doesn't have an inherit of ICollection. Nothing can be wrong return; } else if (allInterfacesStatus.IEnumerablePresent) { // Implemented IEnumerable, but not IEnumerable<T> missingInterface = gEnumerableType; implementedInterface = iEnumerableType; } else { // No collections implementation, nothing can be wrong. return; } RoslynDebug.Assert(missingInterface != null && implementedInterface != null); context.ReportDiagnostic(Diagnostic.Create(Rule, namedTypeSymbol.Locations.First(), namedTypeSymbol.Name, implementedInterface.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), missingInterface.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat))); }
private static async Task AnalyzeAttributesWithinUnBoundFieldAsync(IPropertySymbol property, ImmutableArray <AttributeData> attributes, PXContext pxContext, SymbolAnalysisContext symbolContext, AttributeInformation attributeInformation) { foreach (AttributeData attribute in attributes) { if (attributeInformation.IsAttributeDerivedFromClass(attribute.AttributeClass, pxContext.AttributeTypes.PXDefaultAttribute) && !attributeInformation.IsAttributeDerivedFromClass(attribute.AttributeClass, pxContext.AttributeTypes.PXUnboundDefaultAttribute)) { foreach (KeyValuePair <string, TypedConstant> argument in attribute.NamedArguments) { if (isAttributeContainsPersistingCheckNothing(argument)) { return; } } Location attributeLocation = await GetAttributeLocationAsync(attribute, symbolContext.CancellationToken); if (attributeLocation != null) { var diagnosticProperties = new Dictionary <string, string> { { DiagnosticProperty.IsBoundField, false.ToString() } }.ToImmutableDictionary(); symbolContext.ReportDiagnostic( Diagnostic.Create( Descriptors.PX1030_DefaultAttibuteToExisitingRecords, attributeLocation, diagnosticProperties)); } } } }
private static void AnalyzeField(SymbolAnalysisContext context, INamedTypeSymbol nonDefaultableAttribute, ConcurrentDictionary <ITypeSymbol, bool> knownNonDefaultableTypes) { AnalyzeField(context, (IFieldSymbol)context.Symbol, nonDefaultableAttribute, knownNonDefaultableTypes); }
public void AnalyzeSymbol(SymbolAnalysisContext context) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; if (namedTypeSymbol.TypeKind == TypeKind.Delegate || namedTypeSymbol.TypeKind == TypeKind.Interface) { return; } // If the type is public and implements ISerializable if (namedTypeSymbol.DeclaredAccessibility == Accessibility.Public && namedTypeSymbol.AllInterfaces.Contains(_iserializableTypeSymbol)) { if (!IsSerializable(namedTypeSymbol)) { // CA2237 : Mark serializable types with the SerializableAttribute if (namedTypeSymbol.BaseType.SpecialType == SpecialType.System_Object || IsSerializable(namedTypeSymbol.BaseType)) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2237, namedTypeSymbol.Name)); } } else { // Look for a serialization constructor. // A serialization constructor takes two params of type SerializationInfo and StreamingContext. IMethodSymbol serializationCtor = namedTypeSymbol.Constructors.Where(c => c.Parameters.Count() == 2 && c.Parameters[0].Type == _serializationInfoTypeSymbol && c.Parameters[1].Type == _streamingContextTypeSymbol) .SingleOrDefault(); // There is no serialization ctor - issue a diagnostic. if (serializationCtor == null) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2229, string.Format(MicrosoftNetFrameworkAnalyzersResources.ImplementSerializationConstructorsMessageCreateMagicConstructor, namedTypeSymbol.Name))); } else { // Check the accessibility // The serialization ctor should be protected if the class is unsealed and private if the class is sealed. if (namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Private) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229, string.Format( MicrosoftNetFrameworkAnalyzersResources.ImplementSerializationConstructorsMessageMakeSealedMagicConstructorPrivate, namedTypeSymbol.Name))); } if (!namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Protected) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229, string.Format( MicrosoftNetFrameworkAnalyzersResources.ImplementSerializationConstructorsMessageMakeUnsealedMagicConstructorFamily, namedTypeSymbol.Name))); } } } } // If this is type is marked Serializable check it's fields types' as well if (IsSerializable(namedTypeSymbol)) { System.Collections.Generic.IEnumerable <IFieldSymbol> nonSerializableFields = namedTypeSymbol.GetMembers().OfType <IFieldSymbol>().Where(m => !IsSerializable(m.Type)); foreach (IFieldSymbol field in nonSerializableFields) { // Check for [NonSerialized] if (field.GetAttributes().Any(x => x.AttributeClass.Equals(_nonSerializedAttributeTypeSymbol))) { continue; } if (field.IsImplicitlyDeclared && field.AssociatedSymbol != null) { context.ReportDiagnostic(field.AssociatedSymbol.CreateDiagnostic(RuleCA2235, field.AssociatedSymbol.Name, namedTypeSymbol.Name, field.Type)); } else { context.ReportDiagnostic(field.CreateDiagnostic(RuleCA2235, field.Name, namedTypeSymbol.Name, field.Type)); } } } }
private static Location GetAttributeLocation(ref SymbolAnalysisContext symbolAnalysisContext, AttributeData attribute) { var syntax = attribute.ApplicationSyntaxReference.GetSyntax(symbolAnalysisContext.CancellationToken); return(syntax?.GetLocation() ?? Location.None); }
private void RegisterDiagnosticForIdentifier(SyntaxToken identifier, PXContext pxContext, SymbolAnalysisContext context) { bool isDeletedDatabaseRecord = string.Equals(identifier.ValueText, DeletedDatabaseRecord, StringComparison.OrdinalIgnoreCase); DiagnosticDescriptor descriptorToShow = isDeletedDatabaseRecord && !pxContext.CodeAnalysisSettings.IsvSpecificAnalyzersEnabled ? Descriptors.PX1027_ForbiddenFieldsInDacDeclaration_NonISV : Descriptors.PX1027_ForbiddenFieldsInDacDeclaration; context.ReportDiagnosticWithSuppressionCheck( Diagnostic.Create(descriptorToShow, identifier.GetLocation(), identifier.ValueText), pxContext.CodeAnalysisSettings); }
/// <summary> /// Check namespace naming rules. /// </summary> /// <param name="context">Analysis context.</param> private static void AnalyzeNamespaceName(SymbolAnalysisContext context) { // Delegate. CheckName(context, NameNamespacesWithPascalCasing, IsPascalCase); }
/// <summary> /// Check property naming rules. /// </summary> /// <param name="context">Analysis context.</param> private static void AnalyzePropertyName(SymbolAnalysisContext context) { // Delegate. CheckName(context, NamePropertiesWithPascalCase, IsPascalCase); }
protected abstract void AnalyzeSymbol(SymbolAnalysisContext context, PXContext pxContext);
public static void ReportDiagnosticWhenActive(this SymbolAnalysisContext context, Diagnostic diagnostic) => ReportDiagnostic(new ReportingContext(context, diagnostic), SonarAnalysisContext.IsTestProjectNoCache(context.Compilation, context.Options));
protected abstract void AnalyzeDiagnosticAnalyzer(SymbolAnalysisContext symbolContext);
private static AttributeSyntax GetAttributeSyntax(SymbolAnalysisContext context, AttributeData attribute) => (AttributeSyntax)attribute.ApplicationSyntaxReference.GetSyntax(context.CancellationToken);
public static SyntaxTree GetFirstSyntaxTree(this SymbolAnalysisContext context) => context.Symbol.Locations.FirstOrDefault(l => l.SourceTree != null)?.SourceTree;
private void AnalyzeSymbol(SymbolAnalysisContext context) { OnAbstractMember("Symbol", symbol: context.Symbol); OnOptions(context.Options); }
private static void AnalyzeSymbol(SymbolAnalysisContext symbolContext) { var methodSymbol = (IMethodSymbol)symbolContext.Symbol; // FxCop compat: only analyze externally visible symbols. if (!methodSymbol.IsExternallyVisible()) { return; } if (methodSymbol.ContainingSymbol is ITypeSymbol typeSymbol && (methodSymbol.MethodKind == MethodKind.UserDefinedOperator || methodSymbol.MethodKind == MethodKind.Conversion)) { string operatorName = methodSymbol.Name; if (IsPropertyExpected(operatorName) && operatorName != OpFalseText) { // don't report a diagnostic on the `op_False` method because then the user would see two diagnostics for what is really one error // special-case looking for `IsTrue` instance property // named properties can't be overloaded so there will only ever be 0 or 1 IPropertySymbol property = typeSymbol.GetMembers(IsTrueText).OfType <IPropertySymbol>().SingleOrDefault(); if (property == null || property.Type.SpecialType != SpecialType.System_Boolean) { symbolContext.ReportDiagnostic(CreateDiagnostic(PropertyRule, GetSymbolLocation(methodSymbol), AddAlternateText, IsTrueText, operatorName)); } else if (!property.IsPublic()) { symbolContext.ReportDiagnostic(CreateDiagnostic(VisibilityRule, GetSymbolLocation(property), FixVisibilityText, IsTrueText, operatorName)); } } else { ExpectedAlternateMethodGroup expectedGroup = GetExpectedAlternateMethodGroup(operatorName, methodSymbol.ReturnType); if (expectedGroup == null) { // no alternate methods required return; } var matchedMethods = new List <IMethodSymbol>(); var unmatchedMethods = new HashSet <string>() { expectedGroup.AlternateMethod1 }; if (expectedGroup.AlternateMethod2 != null) { unmatchedMethods.Add(expectedGroup.AlternateMethod2); } foreach (IMethodSymbol candidateMethod in typeSymbol.GetMembers().OfType <IMethodSymbol>()) { if (candidateMethod.Name == expectedGroup.AlternateMethod1 || candidateMethod.Name == expectedGroup.AlternateMethod2) { // found an appropriately-named method matchedMethods.Add(candidateMethod); unmatchedMethods.Remove(candidateMethod.Name); } } // only one public method match is required if (matchedMethods.Any(m => m.IsPublic())) { // at least one public alternate method was found, do nothing } else { // either we found at least one method that should be public or we didn't find anything IMethodSymbol notPublicMethod = matchedMethods.FirstOrDefault(m => !m.IsPublic()); if (notPublicMethod != null) { // report error for improper visibility directly on the method itself symbolContext.ReportDiagnostic(CreateDiagnostic(VisibilityRule, GetSymbolLocation(notPublicMethod), FixVisibilityText, notPublicMethod.Name, operatorName)); } else { // report error for missing methods on the operator overload if (expectedGroup.AlternateMethod2 == null) { // only one alternate expected symbolContext.ReportDiagnostic(CreateDiagnostic(DefaultRule, GetSymbolLocation(methodSymbol), AddAlternateText, expectedGroup.AlternateMethod1, operatorName)); } else { // one of two alternates expected symbolContext.ReportDiagnostic(CreateDiagnostic(MultipleRule, GetSymbolLocation(methodSymbol), AddAlternateText, expectedGroup.AlternateMethod1, expectedGroup.AlternateMethod2, operatorName)); } } } } } }
/// <summary> /// Check rule: Remove IDisposable from the list of interfaces implemented by {0} as it is already implemented by base type {1}. /// </summary> private static void CheckIDisposableReimplementationRule(INamedTypeSymbol type, SymbolAnalysisContext context, bool implementsDisposableInBaseType) { if (implementsDisposableInBaseType) { context.ReportDiagnostic(type.CreateDiagnostic(IDisposableReimplementationRule, type.Name, type.BaseType.Name)); } }
private static void Collect( SymbolAnalysisContext context, ConcurrentDictionary <INamedTypeSymbol, bool> privateOrInternalBaseClasses, ConcurrentDictionary <INamedTypeSymbol, Location> privateOrInternalUnsealedClasses ) { var symbol = (INamedTypeSymbol)context.Symbol; if (!symbol.IsDefinition) { return; } // We can ignore types in other assemblies (forgetting about // InternalsVisibleTo because if we're seeing them here they must // be public so 1) not our deal 2) not subtypes of our internal // or private types. This isn't strictly necessary because of // the next check (ignore public types) but it is more explicit. if (symbol.ContainingAssembly != context.Compilation.Assembly) { return; } // We can't make calls about public unsealed types and a public // type can't have an internal or private base type so we can // safely ignore them. if (symbol.DeclaredAccessibility.HasFlag(Accessibility.Public)) { return; } if (symbol.BaseType != null) { privateOrInternalBaseClasses[symbol.BaseType] = true; } // From this point we are trying to determine if symbol represents // an internal or private unsealed type if (symbol.IsStatic) { return; } if (symbol.IsSealed) { return; } // An abstract class can't be sealed. If this analyzer would emit a // diagnostic then this class is probably dead-code. That's worth // complaining about but not in this analyzer. if (symbol.IsAbstract) { return; } // Not sure how this would happen... implicit types? if (symbol.DeclaringSyntaxReferences.Length == 0) { return; } var firstDecl = symbol .DeclaringSyntaxReferences .First() .GetSyntax(); if (firstDecl is ClassDeclarationSyntax) { // at this point we know its a class, its private or internal and its not sealed privateOrInternalUnsealedClasses[symbol] = (firstDecl as ClassDeclarationSyntax).Identifier.GetLocation(); } }