Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: CallerArgumentExpressionAttribute #51952

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
15ea810
Initial work for caller argument expression
Youssef1313 Mar 18, 2021
b480dd5
Add resources for caller argument expression diagnostics
Youssef1313 Mar 18, 2021
3ea7b29
Account for swapped named arguments
Youssef1313 Mar 18, 2021
28f460a
Add few tests
Youssef1313 Mar 18, 2021
8085998
Complete implementation in PEParameterSymbol
Youssef1313 Mar 18, 2021
c1669d0
Update tests
Youssef1313 Mar 18, 2021
ac953bc
Produce warning for invalid parameter name
Youssef1313 Mar 18, 2021
cab0727
Run generate-compiler-code.cmd
Youssef1313 Mar 18, 2021
a2b2607
Fix out of range exception and add more tests
Youssef1313 Mar 19, 2021
1c49908
Extract DecodeCallerArgumentExpressionAttribute extension
Youssef1313 Mar 19, 2021
380edbc
Fix freeing twice
Youssef1313 Mar 19, 2021
6adaa54
Fix comments
Youssef1313 Mar 19, 2021
c119c1b
Simplify PEParameterSymbol
Youssef1313 Mar 19, 2021
174d1ca
Fix NullableWarnings test
Youssef1313 Mar 19, 2021
75bcaa3
Add test for two parameters referring to each other
Youssef1313 Mar 20, 2021
0e658e0
Use warning level 1
Youssef1313 Mar 20, 2021
54afaec
Add test for extension methods and remove addressed comments
Youssef1313 Mar 20, 2021
4e34954
Add title resources for new warnings
Youssef1313 Mar 20, 2021
a8c9851
Use static lambda
Youssef1313 Mar 20, 2021
564993d
Add PROTOTYPE comment
Youssef1313 Mar 20, 2021
79cae72
Add trivia test and skip PEVerification
Youssef1313 Mar 20, 2021
b8ec8b3
Address feedback
Youssef1313 Mar 24, 2021
31c72d9
Fix resources
Youssef1313 Mar 24, 2021
0fe2481
Simplify based on @AlekseyTs feedback
Youssef1313 Mar 24, 2021
4d0fe25
Pass array builder instead of creating a temporary immutable array
Youssef1313 Mar 24, 2021
6f55195
Check feature availability on language version
Youssef1313 Mar 24, 2021
9c8d283
Add "semantic check" comment
Youssef1313 Mar 24, 2021
1326603
Add missing IDS_Feature resource
Youssef1313 Mar 25, 2021
a2055ec
Don't check feature availability on attribute application
Youssef1313 Mar 25, 2021
670d405
Remove helper that's used only once
Youssef1313 Mar 25, 2021
765c6e3
Cleanup
Youssef1313 Mar 25, 2021
4358fbb
Don't check generatedDiagnostics
Youssef1313 Mar 25, 2021
8b5480a
Use LanguageVersion.Preview in tests
Youssef1313 Mar 25, 2021
416d995
Cleanup resx
Youssef1313 Mar 26, 2021
9b1dd49
Use TestOptions.RegularPreview
Youssef1313 Mar 26, 2021
dba8bae
ConditionalFact[typeof(CoreClrOnly)]
Youssef1313 Mar 26, 2021
628dadb
Add assertion
Youssef1313 Mar 26, 2021
c299f7c
Update tests
Youssef1313 Mar 27, 2021
e3b0894
Update test
Youssef1313 Mar 27, 2021
418ec88
Adjust NullableWarnings test
Youssef1313 Apr 6, 2021
b99bb7a
Address feedback
Youssef1313 Apr 6, 2021
e8023b1
Simplify
Youssef1313 Apr 6, 2021
3da9a8a
Fix formatting
Youssef1313 Apr 6, 2021
3e68c55
Address feedback
Youssef1313 Apr 7, 2021
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
19 changes: 17 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,7 @@ internal void BindDefaultArguments(
// Params array is filled in the local rewriter
var lastIndex = expanded ? ^1 : ^0;

var argumentsCount = argumentsBuilder.Count;
// Go over missing parameters, inserting default values for optional parameters
foreach (var parameter in parameters.AsSpan()[..lastIndex])
{
Expand All @@ -1316,7 +1317,7 @@ internal void BindDefaultArguments(
Debug.Assert(parameter.IsOptional || !assertMissingParametersAreOptional);

defaultArguments[argumentsBuilder.Count] = true;
argumentsBuilder.Add(bindDefaultArgument(node, parameter, containingMember, enableCallerInfo, diagnostics));
argumentsBuilder.Add(bindDefaultArgument(node, parameter, containingMember, enableCallerInfo, diagnostics, argumentsBuilder, argumentsCount, argsToParamsOpt));

if (argumentRefKindsBuilder is { Count: > 0 })
{
Expand All @@ -1335,7 +1336,7 @@ internal void BindDefaultArguments(
argsToParamsBuilder.Free();
}

BoundExpression bindDefaultArgument(SyntaxNode syntax, ParameterSymbol parameter, Symbol containingMember, bool enableCallerInfo, BindingDiagnosticBag diagnostics)
BoundExpression bindDefaultArgument(SyntaxNode syntax, ParameterSymbol parameter, Symbol containingMember, bool enableCallerInfo, BindingDiagnosticBag diagnostics, ArrayBuilder<BoundExpression> argumentsBuilder, int argumentsCount, ImmutableArray<int> argsToParamsOpt)
{
TypeSymbol parameterType = parameter.Type;
if (Flags.Includes(BinderFlags.ParameterDefaultValue))
Expand Down Expand Up @@ -1370,6 +1371,15 @@ BoundExpression bindDefaultArgument(SyntaxNode syntax, ParameterSymbol parameter
var memberName = containingMember.GetMemberCallerName();
defaultValue = new BoundLiteral(syntax, ConstantValue.Create(memberName), Compilation.GetSpecialType(SpecialType.System_String)) { WasCompilerGenerated = true };
}
else if (callerSourceLocation is object && getArgumentIndex(parameter.CallerArgumentExpressionParameterIndex, argsToParamsOpt) is int argumentIndex &&
argumentIndex > -1 && argumentIndex < argumentsCount)
{
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureCallerArgumentExpression, diagnostics);
// PROTOTYPE(caller-expr): Do we need to support VB?

var argument = argumentsBuilder[argumentIndex];
defaultValue = new BoundLiteral(syntax, ConstantValue.Create(argument.Syntax.ToString()), Compilation.GetSpecialType(SpecialType.System_String)) { WasCompilerGenerated = true };
}
else if (defaultConstantValue == ConstantValue.NotAvailable)
{
// There is no constant value given for the parameter in source/metadata.
Expand Down Expand Up @@ -1423,6 +1433,11 @@ BoundExpression bindDefaultArgument(SyntaxNode syntax, ParameterSymbol parameter
}

return defaultValue;

static int getArgumentIndex(int parameterIndex, ImmutableArray<int> argsToParamsOpt)
=> argsToParamsOpt.IsDefault
Copy link
Contributor

@AlekseyTs AlekseyTs Mar 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

argsToParamsOpt.IsDefault [](start = 23, length = 25)

Is this condition ever true? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlekseyTs Yes. When the arguments order matches the parameters order. I don't know the reason, only figured that by testing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this condition ever true?

Yes. When the arguments order matches the parameters order. I don't know the reason, only figured that by testing.

Just to confirm. We have omitted arguments and argsToParamsOpt.IsDefault can still be true?


In reply to: 600234291 [](ancestors = 600234291)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have omitted arguments and argsToParamsOpt.IsDefault can still be true?

Not sure what you mean by "We have omitted arguments". But yes I confirmed it can be true.

For example, for the following test:

            string source = @"
using System;
using System.Runtime.CompilerServices;

class Program
{
    public static void Main()
    {
        Log(123);
    }
    const string p = nameof(p);
    static void Log(int p, [CallerArgumentExpression(p)] string arg = null)
    {
        Console.WriteLine(arg);
    }
}
";

image

? parameterIndex
: argsToParamsOpt.IndexOf(parameterIndex);
}

}
Expand Down
41 changes: 40 additions & 1 deletion src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -6600,4 +6600,43 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_FunctionPointerTypesInAttributeNotSupported" xml:space="preserve">
<value>Using a function pointer type in a 'typeof' in an attribute is not supported.</value>
</data>
</root>
<data name="ERR_BadCallerArgumentExpressionParamWithoutDefaultValue" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute may only be applied to parameters with default values</value>
</data>
<data name="ERR_NoConversionForCallerArgumentExpressionParam" xml:space="preserve">
<value>CallerArgumentExpressionAttribute cannot be applied because there are no standard conversions from type '{0}' to type '{1}'</value>
Copy link
Contributor

@AlekseyTs AlekseyTs Mar 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

standard [](start = 84, length = 8)

Should conversio be also implicit? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the exact same text from existing diagnostics. I'm not entirely sure about the correct terminology. Will need to go through the Standard conversions in spec.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlekseyTs The following code compiles (standard explicit conversion from object to string - based on my understanding from spec):

using System.Runtime.CompilerServices;

public class C
{
    public void M([CallerMemberName] object name = null)
    {
    }
}

So it seems standard conversion is correct

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following code compiles (standard explicit conversion from object to string - based on my understanding from spec):

Doesn't conversion in this scenario go from string to object instead?


In reply to: 600250422 [](ancestors = 600250422)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlekseyTs Consider the following code:

using System.Runtime.CompilerServices;

public class C
{
    public static void M([CallerMemberName] C name = null)
    {
    }
}

The error message is:

error CS4019: CallerMemberNameAttribute cannot be applied because there are no standard conversions from type 'string' to type 'C'

Changing C to object compiles fine. So it looks like these kind of attribute requires a standard conversion from string to whatever the declared type is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing C to object compiles fine. So it looks like these kind of attribute requires a standard conversion from string to whatever the declared type is.

The question is whether the standard conversion should also be implicit.


In reply to: 600628537 [](ancestors = 600628537)

Copy link
Member Author

@Youssef1313 Youssef1313 Mar 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlekseyTs, Well, looking at the spec of CallerMemberName:

The System.Runtime.CompilerServices.CallerMemberNameAttribute is allowed on optional parameters when there is a standard implicit conversion (Standard implicit conversions) from string to the parameter's type.

However, the compiler allows the parameter of a CallerMemberName to be object. I don't think the conversion from string to object. So it seems like the current implementation violates the spec. (unless there is something I'm not understanding). (This was a stupid comment 😄 )

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ops I was swapping the source and destination for conversion in mind 😄
Yes it should be standard implicit conversion.

</data>
<data name="WRN_CallerArgumentExpressionParamForUnconsumedLocation" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments</value>
</data>
<data name="WRN_CallerArgumentExpressionParamForUnconsumedLocation_Title" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute will have no effect because it applies to a member that is used in contexts that do not allow optional arguments</value>
</data>
<data name="WRN_CallerFilePathPreferredOverCallerArgumentExpression" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect. It is overridden by the CallerFilePathAttribute.</value>
</data>
<data name="WRN_CallerFilePathPreferredOverCallerArgumentExpression_Title" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerFilePathAttribute</value>
</data>
<data name="WRN_CallerLineNumberPreferredOverCallerArgumentExpression" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect. It is overridden by the CallerLineNumberAttribute.</value>
</data>
<data name="WRN_CallerLineNumberPreferredOverCallerArgumentExpression_Title" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerLineNumberAttribute</value>
</data>
<data name="WRN_CallerMemberNamePreferredOverCallerArgumentExpression" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect. It is overriden by the CallerMemberNameAttribute.</value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the [](start = 116, length = 3)

English nit: remove the

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for the other preferred warnings above.


In reply to: 602453392 [](ancestors = 602453392)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I do the same with existing warnings for consistency? e.g:

<value>The CallerMemberNameAttribute applied to parameter '{0}' will have no effect. It is overridden by the CallerFilePathAttribute.</value>

or only remove "The" from the new warnings?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course it is... I guess just leave it as is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we should do, though, is add a remarks section to indicate that CallerArgumentExpressionAttribute and CallerMemberNameAttribute should not be localized.

Copy link
Contributor

@AlekseyTs AlekseyTs Mar 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we should do, though, is add a remarks section to indicate that CallerArgumentExpressionAttribute and CallerMemberNameAttribute should not be localized.

The localization team has asked us for these types notes before. I always support making sure we don't get future bugs on things that were translated and shouldn't have been.

FWIW, I am not aware of a requirement to add comments like that. Obviously, a developer can add remarks if he or she would like to do so. In this particular case, however, I believe that the suggested remark would state the obvious - type names are not translated and I personally wouldn't add it. It is quite obvious that "CallerArgumentExpressionAttribute" is not a word.


In reply to: 605055933 [](ancestors = 605055933)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there was some issues with translation for things that looks "trivial" that shouldn't be translated.

See also #48364

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also an example where "unmanaged" keyword was incorrectly translated, despite it's surrounded with single quotes which is a high indication it shouldn't be localized.

<trans-unit id="ERR_CannotSpecifyManagedWithUnmanagedSpecifiers">
<source>'managed' calling convention cannot be combined with unmanaged calling convention specifiers.</source>
<target state="translated">'マネージド' 呼び出し規則をアンマネージド呼び出し規則指定子と組み合わせることはできません。</target>
<note />
</trans-unit>

Copy link
Contributor

@AlekseyTs AlekseyTs Apr 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there was some issues with translation for things that looks "trivial" that shouldn't be translated.

This is your PR, feel free to add remarks that you feel appropriate.


In reply to: 605664888 [](ancestors = 605664888)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, let's check with the loc team.

@cristianosuzuki77 Is a "Locked" comment required for CallerMemberNameAttribute in a message like the following?

  <trans-unit id="WRN_CallerMemberNamePreferredOverCallerArgumentExpression">
    <source>The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect. It is overriden by the CallerMemberNameAttribute.</source>
    <note />
  </trans-unit>

</data>
<data name="WRN_CallerMemberNamePreferredOverCallerArgumentExpression_Title" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute</value>
</data>
<data name="WRN_CallerArgumentExpressionAttributeHasInvalidParameterName" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect. It is applied with an invalid parameter name.</value>
</data>
<data name="WRN_CallerArgumentExpressionAttributeHasInvalidParameterName_Title" xml:space="preserve">
<value>The CallerArgumentExpressionAttribute is applied with an invalid parameter name.</value>
</data>
<data name="IDS_FeatureCallerArgumentExpression" xml:space="preserve">
<value>caller argument expression</value>
</data>
</root>
11 changes: 11 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1932,6 +1932,17 @@ internal enum ErrorCode

#endregion diagnostics introduced for C# 9.0

#region diagnostics introduced in C# 10.0
WRN_CallerArgumentExpressionParamForUnconsumedLocation = 8912,
ERR_NoConversionForCallerArgumentExpressionParam = 8913,
ERR_BadCallerArgumentExpressionParamWithoutDefaultValue = 8914,
WRN_CallerLineNumberPreferredOverCallerArgumentExpression = 8915,
WRN_CallerFilePathPreferredOverCallerArgumentExpression = 8916,
WRN_CallerMemberNamePreferredOverCallerArgumentExpression = 8917,
WRN_CallerArgumentExpressionAttributeHasInvalidParameterName = 8918,

#endregion

// Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd)
}
}
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_AnalyzerReferencesFramework:
case ErrorCode.WRN_UnreadRecordParameter:
case ErrorCode.WRN_DoNotCompareFunctionPointers:
case ErrorCode.WRN_CallerArgumentExpressionParamForUnconsumedLocation:
case ErrorCode.WRN_CallerLineNumberPreferredOverCallerArgumentExpression:
case ErrorCode.WRN_CallerFilePathPreferredOverCallerArgumentExpression:
case ErrorCode.WRN_CallerMemberNamePreferredOverCallerArgumentExpression:
case ErrorCode.WRN_CallerArgumentExpressionAttributeHasInvalidParameterName:
return 1;
default:
return 0;
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/MessageID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ internal enum MessageID
IDS_FeatureVarianceSafetyForStaticInterfaceMembers = MessageBase + 12791,
IDS_FeatureConstantInterpolatedStrings = MessageBase + 12792,
IDS_FeatureMixedDeclarationsAndExpressionsInDeconstruction = MessageBase + 12793,
IDS_FeatureCallerArgumentExpression = MessageBase + 12794,
Copy link
Contributor

@AlekseyTs AlekseyTs Mar 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IDS_FeatureCallerArgumentExpression [](start = 8, length = 35)

It looks like we are missing the corresponding string in resourses #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

// Message IDs may refer to strings that need to be localized.
Expand Down Expand Up @@ -324,6 +325,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
{
// C# preview features.
case MessageID.IDS_FeatureMixedDeclarationsAndExpressionsInDeconstruction:
case MessageID.IDS_FeatureCallerArgumentExpression: // semantic check
return LanguageVersion.Preview;
// C# 9.0 features.
case MessageID.IDS_FeatureLambdaDiscardParameters: // semantic check
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 @@ -76,6 +76,7 @@ internal int MethodHashCode()
internal override bool IsCallerFilePath => false;
internal override bool IsCallerLineNumber => false;
internal override bool IsCallerMemberName => false;
internal override int CallerArgumentExpressionParameterIndex => -1;
internal override FlowAnalysisAnnotations FlowAnalysisAnnotations => FlowAnalysisAnnotations.None;
internal override ImmutableHashSet<string> NotNullIfParameterNotNull => ImmutableHashSet<string>.Empty;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ private struct PackedFlags
// r = RefKind. 2 bits.
// n = hasNameInMetadata. 1 bit.
// f = FlowAnalysisAnnotations. 9 bits (8 value bits + 1 completion bit).
// Current total = 28 bits.

private const int WellKnownAttributeDataOffset = 0;
private const int WellKnownAttributeCompletionFlagOffset = 8;
Expand Down Expand Up @@ -141,6 +142,12 @@ public bool TryGetFlowAnalysisAnnotations(out FlowAnalysisAnnotations value)
private ConstantValue _lazyDefaultValue = ConstantValue.Unset;
private ThreeState _lazyIsParams;

/// <summary>
/// The index of a CallerArgumentExpression. The value -2 means uninitialized, -1 means
/// not found. Otherwise, the index of the CallerArgumentExpression.
/// </summary>
private int _lazyCallerArgumentExpressionParameterIndex = -2;

/// <summary>
/// Attributes filtered out from m_lazyCustomAttributes, ParamArray, etc.
/// </summary>
Expand Down Expand Up @@ -656,6 +663,42 @@ internal override bool IsCallerMemberName
}
}

internal override int CallerArgumentExpressionParameterIndex
{
get
{
if (_lazyCallerArgumentExpressionParameterIndex != -2)
{
return _lazyCallerArgumentExpressionParameterIndex;
}

var info = _moduleSymbol.Module.FindTargetAttribute(_handle, AttributeDescription.CallerArgumentExpressionAttribute);
var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
bool isCallerArgumentExpression = info.HasValue
&& !HasCallerLineNumberAttribute
&& !HasCallerFilePathAttribute
&& !HasCallerMemberNameAttribute
&& new TypeConversions(ContainingAssembly).HasCallerInfoStringConversion(this.Type, ref discardedUseSiteInfo);

if (isCallerArgumentExpression)
{
_moduleSymbol.Module.TryExtractStringValueFromAttribute(info.Handle, out var parameterName);
Copy link
Contributor

@AlekseyTs AlekseyTs Mar 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to move this logic into a helper method on PEModule so that it could be used by VB as well. #Closed

var parameters = ContainingSymbol.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].Name == parameterName)
{
_lazyCallerArgumentExpressionParameterIndex = i;
return i;
}
}
}

_lazyCallerArgumentExpressionParameterIndex = -1;
return -1;
}
}

internal override FlowAnalysisAnnotations FlowAnalysisAnnotations
{
get
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ internal sealed override ObsoleteAttributeData ObsoleteAttributeData

internal abstract bool IsCallerMemberName { get; }

internal abstract int CallerArgumentExpressionParameterIndex { get; }

internal abstract FlowAnalysisAnnotations FlowAnalysisAnnotations { get; }

internal abstract ImmutableHashSet<string> NotNullIfParameterNotNull { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public SignatureOnlyParameterSymbol(

internal override bool IsCallerMemberName { get { throw ExceptionUtilities.Unreachable; } }

internal override int CallerArgumentExpressionParameterIndex { get { throw ExceptionUtilities.Unreachable; } }

internal override FlowAnalysisAnnotations FlowAnalysisAnnotations { get { throw ExceptionUtilities.Unreachable; } }

internal override ImmutableHashSet<string> NotNullIfParameterNotNull { get { throw ExceptionUtilities.Unreachable; } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ internal override bool IsCallerMemberName
get { return _originalParam.IsCallerMemberName; }
}

internal override int CallerArgumentExpressionParameterIndex
{
get { return _originalParam.CallerArgumentExpressionParameterIndex; }
}

internal override FlowAnalysisAnnotations FlowAnalysisAnnotations
{
get { return FlowAnalysisAnnotations.None; }
Expand Down
Loading