-
Notifications
You must be signed in to change notification settings - Fork 10k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add analyzer to warn for invalid Component parameter usage.
- The newly added analyzer warns users if they try to assign another components parameter.It does sanity checks to ensure that 1. The property reference is indeed a component parameter 2. The property reference is from a component 3. The assignment is outside of the parameters type hierarchy. Aka, we don't warn users for setting a components parameter if it's in the same class. - Updated existing `ComponentsFacts` to add additional utility methods to properly interact with components. - Added tests to ensure we're analyzing all the goods properly. #8825
- Loading branch information
1 parent
4f638f8
commit d053be3
Showing
9 changed files
with
496 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
src/Components/Analyzers/src/ComponentParameterUsageAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Microsoft.CodeAnalysis.Operations; | ||
|
||
namespace Microsoft.AspNetCore.Components.Analyzers | ||
{ | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public class ComponentParameterUsageAnalyzer : DiagnosticAnalyzer | ||
{ | ||
public ComponentParameterUsageAnalyzer() | ||
{ | ||
SupportedDiagnostics = ImmutableArray.Create(new[] | ||
{ | ||
DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent, | ||
}); | ||
} | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); | ||
context.RegisterCompilationStartAction(context => | ||
{ | ||
if (!ComponentSymbols.TryCreate(context.Compilation, out var symbols)) | ||
{ | ||
// Types we need are not defined. | ||
return; | ||
} | ||
context.RegisterOperationBlockStartAction(startBlockContext => | ||
{ | ||
startBlockContext.RegisterOperationAction(context => | ||
{ | ||
var assignmentOperation = (IAssignmentOperation)context.Operation; | ||
var leftHandSide = assignmentOperation.Target; | ||
if (leftHandSide == null) | ||
{ | ||
// Malformed assignment, no left hand side. | ||
return; | ||
} | ||
if (leftHandSide.Kind != OperationKind.PropertyReference) | ||
{ | ||
// We don't want to capture situations where a user does | ||
// MyOtherProperty = aComponent.SomeParameter | ||
return; | ||
} | ||
var propertyReference = (IPropertyReferenceOperation)leftHandSide; | ||
var componentProperty = (IPropertySymbol)propertyReference.Member; | ||
if (!ComponentFacts.IsParameter(symbols, componentProperty)) | ||
{ | ||
// This is not a property reference that we care about, it is not decorated with [Parameter]. | ||
return; | ||
} | ||
var propertyContainingType = componentProperty.ContainingType; | ||
if (!ComponentFacts.IsComponent(symbols, context.Compilation, propertyContainingType)) | ||
{ | ||
// Someone referenced a property as [Parameter] inside something that is not a component. | ||
return; | ||
} | ||
var assignmentContainingType = startBlockContext.OwningSymbol?.ContainingType; | ||
if (assignmentContainingType == null) | ||
{ | ||
// Assignment location has no containing type. Most likely we're operating on malformed code, don't try and validate. | ||
return; | ||
} | ||
var conversion = context.Compilation.ClassifyConversion(propertyContainingType, assignmentContainingType); | ||
if (conversion.Exists && conversion.IsIdentity) | ||
{ | ||
// The assignment is taking place inside of the declaring component. | ||
return; | ||
} | ||
if (conversion.Exists && conversion.IsExplicit) | ||
{ | ||
// The assignment is taking place within the components type hierarchy. This means the user is setting this in a supported | ||
// scenario. | ||
return; | ||
} | ||
// At this point the user is referencing a component parameter outside of its declaring class. | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
DiagnosticDescriptors.ComponentParametersShouldNotBeSetOutsideOfTheirDeclaredComponent, | ||
propertyReference.Syntax.GetLocation(), | ||
propertyReference.Member.Name)); | ||
}, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment, OperationKind.CoalesceAssignment); | ||
}); | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.