Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
eb4fdf1
Initial implementation of IAttributeOperation
Youssef1313 May 22, 2021
218fbbf
Update IOperationTests_IAttributeOperation.cs
Youssef1313 Feb 8, 2022
52e8782
Fix implementation
Youssef1313 Feb 9, 2022
1611fca
Fix freeing
Youssef1313 Feb 9, 2022
c074598
Add caller info test
Youssef1313 Feb 9, 2022
75bcbda
Produce InvalidOperation for null attribute constructor
Youssef1313 Feb 9, 2022
c184951
Fix crash
Youssef1313 Feb 9, 2022
395f0cd
Apply suggestions from code review
Youssef1313 Feb 9, 2022
878080b
Fix implementation
Youssef1313 Feb 10, 2022
3af6851
Add assertion back
Youssef1313 Feb 10, 2022
aeebffd
null suppressions
Youssef1313 Feb 10, 2022
28aa869
Match existing hasErrors logic
Youssef1313 Feb 10, 2022
a7834df
Fix failures
Youssef1313 Feb 10, 2022
443b239
Fix test
Youssef1313 Feb 10, 2022
dfdf708
Attempt to fix failing test
Youssef1313 Feb 10, 2022
322d436
Null suppressions
Youssef1313 Feb 10, 2022
548a136
Create ContextualAttributeBinder for attributes
Youssef1313 Feb 11, 2022
3624368
Fix attributed member
Youssef1313 Feb 11, 2022
11f579f
Special case local function - feels bad?
Youssef1313 Feb 11, 2022
dad1e82
Fix implementation
Youssef1313 Feb 11, 2022
5b486b3
Revert
Youssef1313 Feb 11, 2022
842ff18
Null suppression
Youssef1313 Feb 11, 2022
3af9698
Loosen invalid operation
Youssef1313 Feb 11, 2022
01c964b
More fixes
Youssef1313 Feb 11, 2022
91364c8
Fix tests
Youssef1313 Feb 11, 2022
7221124
Update TestOperationVisitor.cs
Youssef1313 Feb 11, 2022
4f1a9e8
Fix IDE failing tests
Youssef1313 Feb 12, 2022
03cf01b
Fix more tests
Youssef1313 Feb 12, 2022
7147e17
Small fix, add more tests
Youssef1313 Feb 12, 2022
d4526f1
Merge branch 'main' of https://GitHub.com/dotnet/roslyn into iattribu…
Youssef1313 Mar 4, 2022
a767e98
Rely on recent BoundAttribute updates for IAttributeOperation
Youssef1313 Mar 4, 2022
702bc40
Fix CallerMemberName for IOperation
Youssef1313 Mar 4, 2022
bb93029
Apply suggestions from code review
Youssef1313 Mar 4, 2022
67315c8
Address feedback
Youssef1313 Mar 4, 2022
72962a8
Fix speculative model
Youssef1313 Mar 5, 2022
ea43f08
Fix naming
Youssef1313 Mar 5, 2022
3e5640c
IAttributeOperation for VB
Youssef1313 Mar 5, 2022
25049f9
Update VB test
Youssef1313 Mar 5, 2022
e42a20e
Merge remote-tracking branch 'upstream/main' into iattribute-operation
Youssef1313 Apr 6, 2022
59aed03
More little progress
Youssef1313 Apr 6, 2022
9b03d73
Attempt to fix
Youssef1313 Apr 9, 2022
2117d3a
Add more tests
Youssef1313 Apr 10, 2022
9502a6e
Add assert and remove invalid comment
Youssef1313 Apr 19, 2022
3fdbd8e
Merge branch 'main' into iattribute-operation
Youssef1313 Apr 19, 2022
5f76ef6
Add test
Youssef1313 Apr 23, 2022
29c9f92
Merge remote-tracking branch 'upstream/main' into iattribute-operation
Youssef1313 May 24, 2022
7799e55
A little more progress
Youssef1313 May 24, 2022
be1fa46
Merge branch 'main' of https://GitHub.com/dotnet/roslyn into iattribu…
Youssef1313 May 26, 2022
92ca441
Merge branch 'main' into iattribute-operation
Youssef1313 Jun 18, 2022
cfc0925
more tests
Youssef1313 Jun 18, 2022
e98a831
Temporary assert
Youssef1313 Jun 18, 2022
49ba5b5
Update assert
Youssef1313 Jun 18, 2022
6ad85a3
Fix error
Youssef1313 Jun 18, 2022
310a77d
More work
Youssef1313 Jun 19, 2022
73ed2b4
Rename
Youssef1313 Jun 19, 2022
32ebc64
Refactor
Youssef1313 Jun 19, 2022
d848fd3
Small fix
Youssef1313 Jun 19, 2022
7dfc2cb
More refactoring
Youssef1313 Jun 19, 2022
3db4b70
Fix VB bug
Youssef1313 Jun 19, 2022
0659d25
More tests
Youssef1313 Jun 19, 2022
e7a6644
Update test
Youssef1313 Jun 19, 2022
8b3365c
Address part of feedback
Youssef1313 Jun 29, 2022
4440e09
Merge remote-tracking branch 'upstream/main' into iattribute-operation
Youssef1313 Jun 29, 2022
2148d52
CFG
Youssef1313 Jun 29, 2022
5d6c23a
Public API
Youssef1313 Jun 29, 2022
495d3b4
Suppress
Youssef1313 Jun 29, 2022
ba9be5a
Update PublicAPI.Unshipped.txt
Youssef1313 Jun 29, 2022
31b77a9
Merge branch 'main' into iattribute-operation
Youssef1313 Jul 20, 2022
60ac6c4
Fix bad merge conflict resolution
Youssef1313 Jul 20, 2022
6d33516
Address feedback
Youssef1313 Jul 20, 2022
5a406a0
Merge branch 'main' into iattribute-operation
Youssef1313 Jul 21, 2022
76fb6f9
Add more tests
Youssef1313 Jul 21, 2022
dd72277
Update src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTest…
Youssef1313 Jul 22, 2022
d87efc2
Merge branch 'main' into iattribute-operation
Youssef1313 Aug 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ internal static void GetAttributes(
beforeAttributePartBound?.Invoke(node);
var boundAttribute = new ExecutableCodeBinder(node, this.ContainingMemberOrLambda, this).BindAttribute(node, boundAttributeType, diagnostics);
afterAttributePartBound?.Invoke(node);
return (GetAttribute(boundAttribute, diagnostics), boundAttribute);
Debug.Assert(!boundAttribute.HasAnyErrors || boundAttribute.AttributeData.HasErrors);
return (boundAttribute.AttributeData, boundAttribute);
}

internal BoundAttribute BindAttribute(AttributeSyntax node, NamedTypeSymbol attributeType, BindingDiagnosticBag diagnostics)
Expand Down Expand Up @@ -209,43 +210,53 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a
{
Error(diagnostics, ErrorCode.ERR_AttributeCtorInParameter, node, attributeConstructor.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
}

//BindDefaultArguments(node, attributeConstructor.Parameters, analyzedArguments.ConstructorArguments.Arguments, analyzedArguments.ConstructorArguments.RefKinds, ref argsToParamsOpt, out defaultArguments, expanded, enableCallerInfo: true, diagnostics);
}

ImmutableArray<string?> boundConstructorArgumentNamesOpt = analyzedArguments.ConstructorArguments.GetNames();
ImmutableArray<BoundAssignmentOperator> boundNamedArguments = analyzedArguments.NamedArguments?.ToImmutableAndFree() ?? ImmutableArray<BoundAssignmentOperator>.Empty;
Debug.Assert(boundNamedArguments.All(arg => !arg.Right.NeedsToBeConverted()));

// var boundAttribute = new BoundAttribute(node, attributeConstructor, analyzedArguments.ConstructorArguments.Arguments.ToImmutableArray(), boundConstructorArgumentNamesOpt, argsToParamsOpt, expanded,
// boundNamedArguments, resultKind, defaultArguments, attributeType, hasErrors: resultKind != LookupResultKind.Viable);
analyzedArguments.ConstructorArguments.Free();

//return boundAttribute;
var attributeData = GetAttribute(attributeType, attributeConstructor, boundConstructorArguments, boundNamedArguments, boundConstructorArgumentNamesOpt, argsToParamsOpt, node, hasErrors: resultKind != LookupResultKind.Viable, diagnostics);
return new BoundAttribute(node, attributeConstructor, boundConstructorArguments, boundConstructorArgumentNamesOpt, argsToParamsOpt, expanded,
boundNamedArguments, resultKind, attributeType, hasErrors: resultKind != LookupResultKind.Viable);
boundNamedArguments, resultKind, attributeData, attributeType, hasErrors: resultKind != LookupResultKind.Viable);
}

private CSharpAttributeData GetAttribute(BoundAttribute boundAttribute, BindingDiagnosticBag diagnostics)
private CSharpAttributeData GetAttribute(
NamedTypeSymbol attributeType,
MethodSymbol? attributeConstructor,
ImmutableArray<BoundExpression> boundConstructorArguments,
ImmutableArray<BoundAssignmentOperator> boundNamedArguments,
ImmutableArray<string?> constructorArgumentNamesOpt,
ImmutableArray<int> constructorArgumentsToParamsOpt,
SyntaxNode node,
bool hasErrors,
BindingDiagnosticBag diagnostics)
{
var attributeType = (NamedTypeSymbol)boundAttribute.Type;
var attributeConstructor = boundAttribute.Constructor;

RoslynDebug.Assert((object)attributeType != null);
Debug.Assert(boundAttribute.Syntax.Kind() == SyntaxKind.Attribute);
Debug.Assert(node.Kind() == SyntaxKind.Attribute);

bool hasErrors = boundAttribute.HasAnyErrors;
hasErrors = hasErrors || node.HasErrors || attributeType.IsErrorType() || boundConstructorArguments.HasErrors() || boundNamedArguments.HasErrors();

if (attributeType.IsErrorType() || attributeType.IsAbstract || attributeConstructor is null)
{
// prevent cascading diagnostics
Debug.Assert(hasErrors);
return new SourceAttributeData(boundAttribute.Syntax.GetReference(), attributeType, attributeConstructor, hasErrors);
return new SourceAttributeData(node.GetReference(), attributeType, attributeConstructor, hasErrors);
}

// Validate attribute constructor parameters have valid attribute parameter type
ValidateTypeForAttributeParameters(attributeConstructor.Parameters, ((AttributeSyntax)boundAttribute.Syntax).Name, diagnostics, ref hasErrors);
ValidateTypeForAttributeParameters(attributeConstructor.Parameters, ((AttributeSyntax)node).Name, diagnostics, ref hasErrors);

// Validate the attribute arguments and generate TypedConstant for argument's BoundExpression.
var visitor = new AttributeExpressionVisitor(this);
var arguments = boundAttribute.ConstructorArguments;
var constructorArgsArray = visitor.VisitArguments(arguments, diagnostics, ref hasErrors);
var namedArguments = visitor.VisitNamedArguments(boundAttribute.NamedArguments, diagnostics, ref hasErrors);
var constructorArgsArray = visitor.VisitArguments(boundConstructorArguments, diagnostics, ref hasErrors);
var namedArguments = visitor.VisitNamedArguments(boundNamedArguments, diagnostics, ref hasErrors);

Debug.Assert(!constructorArgsArray.IsDefault, "Property of VisitArguments");

Expand All @@ -259,14 +270,14 @@ private CSharpAttributeData GetAttribute(BoundAttribute boundAttribute, BindingD
else
{
constructorArguments = GetRewrittenAttributeConstructorArguments(out constructorArgumentsSourceIndices, attributeConstructor,
constructorArgsArray, boundAttribute.ConstructorArgumentNamesOpt, (AttributeSyntax)boundAttribute.Syntax, boundAttribute.ConstructorArgumentsToParamsOpt, diagnostics, ref hasErrors);
constructorArgsArray, constructorArgumentNamesOpt, (AttributeSyntax)node, constructorArgumentsToParamsOpt, diagnostics, ref hasErrors);
}

CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
bool isConditionallyOmitted = IsAttributeConditionallyOmitted(attributeType, boundAttribute.SyntaxTree, ref useSiteInfo);
diagnostics.Add(boundAttribute.Syntax, useSiteInfo);
bool isConditionallyOmitted = IsAttributeConditionallyOmitted(attributeType, node.SyntaxTree, ref useSiteInfo);
diagnostics.Add(node, useSiteInfo);

return new SourceAttributeData(boundAttribute.Syntax.GetReference(), attributeType, attributeConstructor, constructorArguments, constructorArgumentsSourceIndices, namedArguments, hasErrors, isConditionallyOmitted);
return new SourceAttributeData(node.GetReference(), attributeType, attributeConstructor, constructorArguments, constructorArgumentsSourceIndices, namedArguments, hasErrors, isConditionallyOmitted);
}

private void ValidateTypeForAttributeParameters(ImmutableArray<ParameterSymbol> parameters, CSharpSyntaxNode syntax, BindingDiagnosticBag diagnostics, ref bool hasErrors)
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,7 @@
<Field Name="ConstructorExpanded" Type="bool" />
<Field Name="NamedArguments" Type ="ImmutableArray&lt;BoundAssignmentOperator&gt;"/>
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
<Field Name="AttributeData" Type="CSharpAttributeData" />
</Node>

<!--
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,9 @@ public CSharpOperationFactory(SemanticModel semanticModel)
return CreateBoundInterpolatedStringArgumentPlaceholder((BoundInterpolatedStringArgumentPlaceholder)boundNode);
case BoundKind.InterpolatedStringHandlerPlaceholder:
return CreateBoundInterpolatedStringHandlerPlaceholder((BoundInterpolatedStringHandlerPlaceholder)boundNode);

case BoundKind.Attribute:
return CreateBoundAttributeOperation((BoundAttribute)boundNode);

case BoundKind.ArgList:
case BoundKind.ArgListOperator:
case BoundKind.ConvertedStackAllocExpression:
Expand Down Expand Up @@ -483,6 +484,53 @@ private IOperation CreateBoundUnconvertedAddressOfOperatorOperation(BoundUnconve
boundUnconvertedAddressOf.WasCompilerGenerated);
}

private IOperation CreateBoundAttributeOperation(BoundAttribute boundAttribute)
{
if (boundAttribute.Constructor is null)
{
return OperationFactory.CreateInvalidOperation(_semanticModel, boundAttribute.Syntax, ImmutableArray<IOperation>.Empty, isImplicit: false);
}

var attributeData = boundAttribute.AttributeData;

var builder = ImmutableArray.CreateBuilder<IArgumentOperation>(boundAttribute.Constructor.ParameterCount);
var seenParameters = ImmutableHashSet.CreateBuilder<ParameterSymbol>();

for (int i = 0; i < boundAttribute.ConstructorArguments.Length; i++)
{
int parameterIndex = boundAttribute.ConstructorArgumentsToParamsOpt.IsDefaultOrEmpty switch
{
true => i,
false => boundAttribute.ConstructorArgumentsToParamsOpt[i],
};

var parameter = boundAttribute.Constructor.Parameters[parameterIndex];
seenParameters.Add(parameter);
builder.Add(CreateArgumentOperation(ArgumentKind.Explicit, parameter.GetPublicSymbol(), boundAttribute.ConstructorArguments[i]));
}

foreach (var parameter in boundAttribute.Constructor.Parameters)
{
if (!seenParameters.Contains(parameter))
{
var typedConstant = attributeData.CommonConstructorArguments[parameter.Ordinal];
builder.Add(CreateArgumentOperation(ArgumentKind.DefaultValue, parameter.GetPublicSymbol(), new BoundLiteral(boundAttribute.Syntax, ConstantValue.Create(typedConstant.Value!, typedConstant.Type!.SpecialType), parameter.Type) { WasCompilerGenerated = true }));
}
}

// var arguments = DeriveArguments(
// methodOrIndexer: boundAttribute.Constructor,
// boundArguments: boundAttribute.ConstructorArguments,
// argumentsToParametersOpt: boundAttribute.ConstructorArgumentsToParamsOpt,
// defaultArguments: boundAttribute.DefaultArguments,
// boundAttribute.ConstructorExpanded,
// boundAttribute.Syntax);

var namedArguments = CreateFromArray<BoundAssignmentOperator, ISimpleAssignmentOperation>(boundAttribute.NamedArguments);

return new AttributeOperation(builder.ToImmutable(), namedArguments, _semanticModel, boundAttribute.Syntax, boundAttribute.GetPublicTypeSymbol(), boundAttribute.WasCompilerGenerated);
}

internal ImmutableArray<IOperation> CreateIgnoredDimensions(BoundNode declaration, SyntaxNode declarationSyntax)
{
switch (declaration.Kind)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal IArgumentOperation CreateArgumentOperation(ArgumentKind kind, IParamete
{
// put argument syntax to argument operation
IOperation value = Create(expression);
(SyntaxNode syntax, bool isImplicit) = expression.Syntax is { Parent: ArgumentSyntax parent } ? (parent, expression.WasCompilerGenerated) : (value.Syntax, true);
(SyntaxNode syntax, bool isImplicit) = expression.Syntax is { Parent: ArgumentSyntax or AttributeArgumentSyntax } ? (expression.Syntax.Parent, expression.WasCompilerGenerated) : (value.Syntax, true);
return new ArgumentOperation(
kind,
parameter,
Expand Down
Loading