private void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context, INamedTypeSymbol asyncPackageType, INamedTypeSymbol provideToolWindowAttributeType) { var declaration = (ClassDeclarationSyntax)context.Node; BaseTypeSyntax?baseType = declaration.BaseList?.Types.FirstOrDefault(); if (baseType == null) { return; } var baseTypeSymbol = context.SemanticModel.GetSymbolInfo(baseType.Type, context.CancellationToken).Symbol?.OriginalDefinition as ITypeSymbol; if (!Utils.IsEqualToOrDerivedFrom(baseTypeSymbol, asyncPackageType)) { return; } INamedTypeSymbol userClassSymbol = context.SemanticModel.GetDeclaredSymbol(declaration, context.CancellationToken); AttributeData? packageRegistrationInstance = userClassSymbol?.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, provideToolWindowAttributeType)); TypedConstant? firstParameter = packageRegistrationInstance?.ConstructorArguments.FirstOrDefault(); if (firstParameter.HasValue && firstParameter.Value.Kind == TypedConstantKind.Type && firstParameter.Value.Value is INamedTypeSymbol typeOfUserToolWindow) { // If the tool window has a constructor that takes a parameter, // then the tool window is probably created asynchronously, because you // cannot easily pass a parameter when creating a synchronous tool window. bool toolWindowHasCtorWithOneParameter = typeOfUserToolWindow.GetMembers(ConstructorInfo.ConstructorName).OfType <IMethodSymbol>().Any(c => c.Parameters.Length == 1); if (toolWindowHasCtorWithOneParameter) { return; } // If the `GetAsyncToolWindowFactory` method has been overridden, // then it's highly likely that the tool window will be created asynchronously. var packageSymbol = context.SemanticModel.GetDeclaredSymbol(declaration, context.CancellationToken)?.OriginalDefinition as ITypeSymbol; if (this.IsGetAsyncToolWindowFactoryOverridden(packageSymbol, asyncPackageType)) { return; } if (packageRegistrationInstance !.ApplicationSyntaxReference?.GetSyntax(context.CancellationToken) is AttributeSyntax attributeSyntax) { AttributeArgumentSyntax firstArgumentSyntax = attributeSyntax.ArgumentList.Arguments.First(); Location diagnosticLocation = firstArgumentSyntax.GetLocation(); if (firstArgumentSyntax.Expression is TypeOfExpressionSyntax typeOfArg) { diagnosticLocation = typeOfArg.Type.GetLocation(); } context.ReportDiagnostic(Diagnostic.Create(Descriptor, diagnosticLocation)); } } }
private void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context, INamedTypeSymbol asyncPackageType, INamedTypeSymbol provideToolWindowAttributeType) { var declaration = (ClassDeclarationSyntax)context.Node; BaseTypeSyntax?baseType = declaration.BaseList?.Types.FirstOrDefault(); if (baseType == null) { return; } var baseTypeSymbol = context.SemanticModel.GetSymbolInfo(baseType.Type, context.CancellationToken).Symbol?.OriginalDefinition as ITypeSymbol; if (!Utils.IsEqualToOrDerivedFrom(baseTypeSymbol, asyncPackageType)) { return; } INamedTypeSymbol userClassSymbol = context.SemanticModel.GetDeclaredSymbol(declaration, context.CancellationToken); AttributeData? packageRegistrationInstance = userClassSymbol?.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, provideToolWindowAttributeType)); TypedConstant? firstParameter = packageRegistrationInstance?.ConstructorArguments.FirstOrDefault(); if (firstParameter.HasValue && firstParameter.Value.Kind == TypedConstantKind.Type && firstParameter.Value.Value is INamedTypeSymbol typeOfUserToolWindow) { bool toolWindowHasCtorWithOneParameter = typeOfUserToolWindow.GetMembers(ConstructorInfo.ConstructorName).OfType <IMethodSymbol>().Any(c => c.Parameters.Length == 1); if (!toolWindowHasCtorWithOneParameter) { if (packageRegistrationInstance !.ApplicationSyntaxReference?.GetSyntax(context.CancellationToken) is AttributeSyntax attributeSyntax) { AttributeArgumentSyntax firstArgumentSyntax = attributeSyntax.ArgumentList.Arguments.First(); Location diagnosticLocation = firstArgumentSyntax.GetLocation(); if (firstArgumentSyntax.Expression is TypeOfExpressionSyntax typeOfArg) { diagnosticLocation = typeOfArg.Type.GetLocation(); } context.ReportDiagnostic(Diagnostic.Create(Descriptor, diagnosticLocation)); } } } }