| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
| <ImportGroup Label="Settings"> | ||
| <Import Project="..\..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Settings.targets" /> | ||
| <Import Project="..\..\..\..\..\build\VSL.Settings.Closed.targets" /> | ||
| </ImportGroup> | ||
| <PropertyGroup> | ||
| <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
| <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
| <ProjectGuid>{FD6BA96C-7905-4876-8BCC-E38E2CA64F31}</ProjectGuid> | ||
| <OutputType>Library</OutputType> | ||
| <RootNamespace>Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator</RootNamespace> | ||
| <AssemblyName>Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ExpressionCompiler</AssemblyName> | ||
| <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
| <SolutionDir Condition="'$(SolutionDir)' == '' OR '$(SolutionDir)' == '*Undefined*'">..\..\..\..\..\</SolutionDir> | ||
| <UseCommonOutputDirectory>True</UseCommonOutputDirectory> | ||
| <RestorePackages>true</RestorePackages> | ||
| <!-- Don't transitively copy output files, since everything builds to the same folder. --> | ||
| </PropertyGroup> | ||
| <ItemGroup Label="File References"> | ||
| <Reference Include="$(OutDir)Microsoft.VisualStudio.Debugger.Engine.dll" /> | ||
| <Reference Include="System.Reflection.Metadata, Version=1.0.18.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | ||
| <SpecificVersion>False</SpecificVersion> | ||
| <HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.1.0.18-beta\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath> | ||
| </Reference> | ||
| </ItemGroup> | ||
| <ItemGroup Label="Project References"> | ||
| <ProjectReference Include="..\..\..\Core\Source\Concord\Concord.csproj"> | ||
| <Project>{5002636a-fe8d-40bf-8818-ab513a2194fa}</Project> | ||
| <Name>Concord</Name> | ||
| <ReferenceOutputAssembly>false</ReferenceOutputAssembly> | ||
| </ProjectReference> | ||
| <ProjectReference Include="..\..\..\..\Compilers\Core\Desktop\CodeAnalysis.Desktop.csproj"> | ||
| <Project>{dfa21ca1-7f96-47ee-940c-069858e81727}</Project> | ||
| <Name>CodeAnalysis.Desktop</Name> | ||
| </ProjectReference> | ||
| <ProjectReference Include="..\..\..\..\Compilers\Core\Portable\CodeAnalysis.csproj"> | ||
| <Project>{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}</Project> | ||
| <Name>CodeAnalysis</Name> | ||
| </ProjectReference> | ||
| <ProjectReference Include="..\..\..\..\Compilers\CSharp\Portable\CSharpCodeAnalysis.csproj"> | ||
| <Project>{B501A547-C911-4A05-AC6E-274A50DFF30E}</Project> | ||
| <Name>CSharpCodeAnalysis</Name> | ||
| </ProjectReference> | ||
| <ProjectReference Include="..\..\..\Core\Source\ExpressionCompiler\ExpressionCompiler.csproj"> | ||
| <Project>{b8da3a90-a60c-42e3-9d8e-6c67b800c395}</Project> | ||
| <Name>ExpressionCompiler</Name> | ||
| </ProjectReference> | ||
| </ItemGroup> | ||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
| <DefineConstants>TRACE;DEBUG</DefineConstants> | ||
| </PropertyGroup> | ||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <Reference Include="System" /> | ||
| <Reference Include="System.Collections.Immutable, Version=1.1.33.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | ||
| <SpecificVersion>False</SpecificVersion> | ||
| <HintPath>..\..\..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> | ||
| </Reference> | ||
| <Reference Include="System.Core" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <Compile Include="Binders\EEMethodBinder.cs" /> | ||
| <Compile Include="Binders\WithTypeArgumentsBinder.cs" /> | ||
| <Compile Include="Binders\PlaceholderLocalBinder.cs" /> | ||
| <Compile Include="CompilationContext.cs" /> | ||
| <Compile Include="CompilationExtensions.cs" /> | ||
| <Compile Include="CSharpLanguageInstructionDecoder.cs" /> | ||
| <Compile Include="CSharpMetadataContext.cs" /> | ||
| <Compile Include="CSharpExpressionCompiler.cs" /> | ||
| <Compile Include="CSharpFrameDecoder.cs" /> | ||
| <Compile Include="CSharpInstructionDecoder.cs" /> | ||
| <Compile Include="EEAssemblyBuilder.cs" /> | ||
| <Compile Include="EETypeNameDecoder.cs" /> | ||
| <Compile Include="EvaluationContext.cs" /> | ||
| <Compile Include="InternalsVisibleTo.cs" /> | ||
| <Compile Include="Rewriters\CapturedVariableRewriter.cs" /> | ||
| <Compile Include="Rewriters\LocalDeclarationRewriter.cs" /> | ||
| <Compile Include="Rewriters\MayHaveSideEffectsVisitor.cs" /> | ||
| <Compile Include="Rewriters\PlaceholderLocalRewriter.cs" /> | ||
| <Compile Include="Symbols\DisplayClassInstance.cs" /> | ||
| <Compile Include="Symbols\DisplayClassVariable.cs" /> | ||
| <Compile Include="Symbols\EEDisplayClassFieldLocalSymbol.cs" /> | ||
| <Compile Include="Symbols\EELocalConstantSymbol.cs" /> | ||
| <Compile Include="Symbols\EELocalSymbol.cs" /> | ||
| <Compile Include="Symbols\EELocalSymbolBase.cs" /> | ||
| <Compile Include="Symbols\EEConstructorSymbol.cs" /> | ||
| <Compile Include="Symbols\EEMethodSymbol.cs" /> | ||
| <Compile Include="Symbols\EENamedTypeSymbol.cs" /> | ||
| <Compile Include="Symbols\EETypeParameterSymbol.cs" /> | ||
| <Compile Include="Symbols\ObjectAddressLocalSymbol.cs" /> | ||
| <Compile Include="Symbols\ObjectIdLocalSymbol.cs" /> | ||
| <Compile Include="Symbols\PlaceholderLocalSymbol.cs" /> | ||
| <Compile Include="Symbols\PlaceholderMethodSymbol.cs" /> | ||
| <Compile Include="Symbols\ExceptionLocalSymbol.cs" /> | ||
| <Compile Include="Symbols\ReturnValueLocalSymbol.cs" /> | ||
| <Compile Include="Symbols\SimpleTypeParameterSymbol.cs" /> | ||
| <Compile Include="Symbols\SynthesizedContextMethodSymbol.cs" /> | ||
| <Compile Include="SyntaxHelpers.cs" /> | ||
| <Compile Include="TypeParameterChecker.cs" /> | ||
| <VsdConfigXml Include="CSharpExpressionCompiler.vsdconfigxml" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <InternalsVisibleToTest Include="Roslyn.ExpressionEvaluator.CSharp.ExpressionCompiler.UnitTests" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <None Include="packages.config" /> | ||
| </ItemGroup> | ||
| <ImportGroup Label="Targets"> | ||
| <Import Project="..\..\..\..\Tools\Vsdconfig\Vsdconfig.targets" /> | ||
| <Import Project="..\..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" /> | ||
| <Import Project="..\..\..\..\..\build\VSL.Imports.Closed.targets" /> | ||
| <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> | ||
| </ImportGroup> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <!-- | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| --> | ||
| <Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008"> | ||
| <DefineGuid Name="CSharpExpressionCompilerId" Value="CFC88282-E29A-47A1-9FAD-E46391CBD26D"/> | ||
| <ManagedComponent | ||
| ComponentId="CSharpExpressionCompilerId" | ||
| ComponentLevel="9991500" | ||
| Synchronized="true" | ||
| AssemblyName="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ExpressionCompiler"> | ||
| <Class Name="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.CSharpExpressionCompiler"> | ||
| <Implements> | ||
| <InterfaceGroup Priority="Low"> | ||
| <NoFilter/> | ||
| <Interface Name="IDkmClrExpressionCompiler"/> | ||
| <Interface Name="IDkmClrExpressionCompilerCallback"/> | ||
| </InterfaceGroup> | ||
| <InterfaceGroup | ||
| CallOnlyWhenLoaded="true"> | ||
| <NoFilter/> | ||
| <Interface Name="IDkmModuleModifiedNotification"/> | ||
| </InterfaceGroup> | ||
| </Implements> | ||
| </Class> | ||
| <Class Name="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.CSharpFrameDecoder"> | ||
| <Implements> | ||
| <InterfaceGroup Priority="Low"> | ||
| <Filter> | ||
| <RuntimeId RequiredValue="DkmRuntimeId.Clr"/> | ||
| </Filter> | ||
| <Interface Name="IDkmLanguageFrameDecoder"/> | ||
| </InterfaceGroup> | ||
| </Implements> | ||
| </Class> | ||
| <Class Name="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.CSharpLanguageInstructionDecoder"> | ||
| <Implements> | ||
| <InterfaceGroup Priority="Low"> | ||
| <Filter> | ||
| <RuntimeId RequiredValue="DkmRuntimeId.Clr"/> | ||
| </Filter> | ||
| <Interface Name="IDkmLanguageInstructionDecoder"/> | ||
| </InterfaceGroup> | ||
| </Implements> | ||
| </Class> | ||
| </ManagedComponent> | ||
| </Configuration> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| [DkmReportNonFatalWatsonException(ExcludeExceptionType = typeof(NotImplementedException)), DkmContinueCorruptingException] | ||
| internal sealed class CSharpFrameDecoder : FrameDecoder | ||
| { | ||
| public CSharpFrameDecoder() | ||
| : base(CSharpInstructionDecoder.Instance) | ||
| { | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System.Text; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
| using Microsoft.VisualStudio.Debugger; | ||
| using Microsoft.VisualStudio.Debugger.Clr; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class CSharpInstructionDecoder : InstructionDecoder<PEMethodSymbol> | ||
| { | ||
| // This string was not localized in the old EE. We'll keep it that way | ||
| // so as not to break consumers who may have been parsing frame names... | ||
| private const string AnonymousMethodName = "AnonymousMethod"; | ||
|
|
||
| /// <summary> | ||
| /// Singleton instance of <see cref="CSharpInstructionDecoder"/> (created using default constructor). | ||
| /// </summary> | ||
| internal static readonly CSharpInstructionDecoder Instance = new CSharpInstructionDecoder(); | ||
|
|
||
| private CSharpInstructionDecoder() | ||
| { | ||
| } | ||
|
|
||
| private static readonly SymbolDisplayFormat s_propertyDisplayFormat = DisplayFormat. | ||
| AddMemberOptions(SymbolDisplayMemberOptions.IncludeParameters). | ||
| WithParameterOptions(SymbolDisplayParameterOptions.IncludeType); | ||
|
|
||
| internal override void AppendFullName(StringBuilder builder, PEMethodSymbol method) | ||
| { | ||
| var displayFormat = | ||
| ((method.MethodKind == MethodKind.PropertyGet) || (method.MethodKind == MethodKind.PropertySet)) ? | ||
| s_propertyDisplayFormat : | ||
| DisplayFormat; | ||
|
|
||
| var parts = method.ToDisplayParts(displayFormat); | ||
| var numParts = parts.Length; | ||
| for (int i = 0; i < numParts; i++) | ||
| { | ||
| var part = parts[i]; | ||
| var displayString = part.ToString(); | ||
|
|
||
| switch (part.Kind) | ||
| { | ||
| case SymbolDisplayPartKind.ClassName: | ||
| if (GeneratedNames.GetKind(displayString) != GeneratedNameKind.LambdaDisplayClass) | ||
| { | ||
| builder.Append(displayString); | ||
| } | ||
| else | ||
| { | ||
| // Drop any remaining display class name parts and the subsequent dot... | ||
| do | ||
| { | ||
| i++; | ||
| } | ||
| while ((i < numParts) && parts[i].Kind != SymbolDisplayPartKind.MethodName); | ||
| i--; | ||
| } | ||
| break; | ||
| case SymbolDisplayPartKind.MethodName: | ||
| GeneratedNameKind kind; | ||
| int openBracketOffset, closeBracketOffset; | ||
| if (GeneratedNames.TryParseGeneratedName(displayString, out kind, out openBracketOffset, out closeBracketOffset) && | ||
| (kind == GeneratedNameKind.LambdaMethod)) | ||
| { | ||
| builder.Append(displayString, openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1); // source method name | ||
| builder.Append('.'); | ||
| builder.Append(AnonymousMethodName); | ||
| // NOTE: The old implementation only appended the first ordinal number. Since this is not useful | ||
| // in uniquely identifying the lambda, we'll append the entire ordinal suffix (which may contain | ||
| // multiple numbers, as well as '-' or '_'). | ||
| builder.Append(displayString.Substring(closeBracketOffset + 2)); // ordinal suffix (e.g. "__1") | ||
| } | ||
| else | ||
| { | ||
| builder.Append(displayString); | ||
| } | ||
| break; | ||
| default: | ||
| builder.Append(displayString); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| internal override PEMethodSymbol GetMethod(DkmClrInstructionAddress instructionAddress) | ||
| { | ||
| var moduleInstance = instructionAddress.ModuleInstance; | ||
| var appDomain = moduleInstance.AppDomain; | ||
| var previous = appDomain.GetDataItem<CSharpMetadataContext>(); | ||
| var metadataBlocks = instructionAddress.Process.GetMetadataBlocks(appDomain); | ||
|
|
||
| CSharpCompilation compilation; | ||
| if (metadataBlocks.HaveNotChanged(previous)) | ||
| { | ||
| compilation = previous.Compilation; | ||
| } | ||
| else | ||
| { | ||
| var dataItem = new CSharpMetadataContext(metadataBlocks); | ||
| appDomain.SetDataItem(DkmDataCreationDisposition.CreateAlways, dataItem); | ||
| compilation = dataItem.Compilation; | ||
| } | ||
|
|
||
| return compilation.GetSourceMethod(moduleInstance.Mvid, instructionAddress.MethodId.Token); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| [DkmReportNonFatalWatsonException(ExcludeExceptionType = typeof(NotImplementedException)), DkmContinueCorruptingException] | ||
| internal sealed class CSharpLanguageInstructionDecoder : LanguageInstructionDecoder<PEMethodSymbol> | ||
| { | ||
| public CSharpLanguageInstructionDecoder() | ||
| : base(CSharpInstructionDecoder.Instance) | ||
| { | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // Copyright (c) Microsoft. 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 Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class CSharpMetadataContext : MetadataContext | ||
| { | ||
| internal readonly CSharpCompilation Compilation; | ||
| internal readonly EvaluationContext EvaluationContext; | ||
|
|
||
| internal CSharpMetadataContext(ImmutableArray<MetadataBlock> metadataBlocks) | ||
| : base(metadataBlocks) | ||
| { | ||
| this.Compilation = metadataBlocks.ToCompilation(); | ||
| } | ||
|
|
||
| internal CSharpMetadataContext(EvaluationContext evaluationContext) | ||
| : base(evaluationContext.MetadataBlocks) | ||
| { | ||
| this.Compilation = evaluationContext.Compilation; | ||
| this.EvaluationContext = evaluationContext; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Immutable; | ||
| using System.Reflection.Metadata; | ||
| using System.Reflection.Metadata.Ecma335; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal static class CompilationExtensions | ||
| { | ||
| private static PENamedTypeSymbol GetType(PEModuleSymbol module, TypeDefinitionHandle typeHandle) | ||
| { | ||
| var metadataDecoder = new MetadataDecoder(module); | ||
| return (PENamedTypeSymbol)metadataDecoder.GetTypeOfToken(typeHandle); | ||
| } | ||
|
|
||
| internal static PENamedTypeSymbol GetType(this CSharpCompilation compilation, Guid moduleVersionId, int typeToken, out MetadataDecoder metadataDecoder) | ||
| { | ||
| var module = compilation.GetModule(moduleVersionId); | ||
| var reader = module.Module.MetadataReader; | ||
| var typeHandle = (TypeDefinitionHandle)MetadataTokens.Handle(typeToken); | ||
| var type = GetType(module, typeHandle); | ||
| metadataDecoder = new MetadataDecoder(module, type); | ||
| return type; | ||
| } | ||
|
|
||
| internal static PEMethodSymbol GetSourceMethod(this CSharpCompilation compilation, Guid moduleVersionId, int methodToken) | ||
| { | ||
| var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); | ||
| var method = GetMethod(compilation, moduleVersionId, methodHandle); | ||
| var metadataDecoder = new MetadataDecoder((PEModuleSymbol)method.ContainingModule); | ||
| var containingType = method.ContainingType; | ||
| string sourceMethodName; | ||
| if (GeneratedNames.TryParseSourceMethodNameFromGeneratedName(containingType.Name, GeneratedNameKind.StateMachineType, out sourceMethodName)) | ||
| { | ||
| foreach (var member in containingType.ContainingType.GetMembers(sourceMethodName)) | ||
| { | ||
| var candidateMethod = member as PEMethodSymbol; | ||
| if (candidateMethod != null) | ||
| { | ||
| var module = metadataDecoder.Module; | ||
| methodHandle = candidateMethod.Handle; | ||
| string stateMachineTypeName; | ||
| if (module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, out stateMachineTypeName) || | ||
| module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, out stateMachineTypeName)) | ||
| { | ||
| if (metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType)) | ||
| { | ||
| return candidateMethod; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return method; | ||
| } | ||
|
|
||
| internal static PEMethodSymbol GetMethod(this CSharpCompilation compilation, Guid moduleVersionId, MethodDefinitionHandle methodHandle) | ||
| { | ||
| var module = compilation.GetModule(moduleVersionId); | ||
| var reader = module.Module.MetadataReader; | ||
| var typeHandle = reader.GetMethodDefinition(methodHandle).GetDeclaringType(); | ||
| var type = GetType(module, typeHandle); | ||
| var method = (PEMethodSymbol)new MetadataDecoder(module, type).GetMethodSymbolForMethodDefOrMemberRef(methodHandle, type); | ||
| return method; | ||
| } | ||
|
|
||
| internal static PEModuleSymbol GetModule(this CSharpCompilation compilation, Guid moduleVersionId) | ||
| { | ||
| foreach (var pair in compilation.GetBoundReferenceManager().GetReferencedAssemblies()) | ||
| { | ||
| var assembly = (AssemblySymbol)pair.Value; | ||
| foreach (var module in assembly.Modules) | ||
| { | ||
| var m = (PEModuleSymbol)module; | ||
| var id = m.Module.GetModuleVersionIdOrThrow(); | ||
| if (id == moduleVersionId) | ||
| { | ||
| return m; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| internal static CSharpCompilation ToCompilation(this ImmutableArray<MetadataBlock> metadataBlocks) | ||
| { | ||
| return CSharpCompilation.Create( | ||
| assemblyName: ExpressionCompilerUtilities.GenerateUniqueName(), | ||
| references: metadataBlocks.MakeAssemblyReferences(), | ||
| options: s_compilationOptions); | ||
| } | ||
|
|
||
| // XML file references, #r directives not supported: | ||
| private static readonly CSharpCompilationOptions s_compilationOptions = new CSharpCompilationOptions( | ||
| outputKind: OutputKind.DynamicallyLinkedLibrary, | ||
| allowUnsafe: true, | ||
| platform: Platform.AnyCpu, // Platform should match PEModule.Machine, in this case I386. | ||
| optimizationLevel: OptimizationLevel.Release, | ||
| assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default). | ||
| WithMetadataImportOptions(MetadataImportOptions.All); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.Cci; | ||
| using Microsoft.CodeAnalysis.CodeGen; | ||
| using Microsoft.CodeAnalysis.CSharp.Emit; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; | ||
| using Microsoft.CodeAnalysis.Emit; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
| using Roslyn.Utilities; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class EEAssemblyBuilder : PEAssemblyBuilderBase | ||
| { | ||
| private readonly ImmutableHashSet<MethodSymbol> _methods; | ||
|
|
||
| public EEAssemblyBuilder( | ||
| SourceAssemblySymbol sourceAssembly, | ||
| EmitOptions emitOptions, | ||
| ImmutableArray<MethodSymbol> methods, | ||
| ModulePropertiesForSerialization serializationProperties, | ||
| ImmutableArray<NamedTypeSymbol> additionalTypes, | ||
| CompilationTestData testData) : | ||
| base( | ||
| sourceAssembly, | ||
| emitOptions, | ||
| outputKind: OutputKind.DynamicallyLinkedLibrary, | ||
| serializationProperties: serializationProperties, | ||
| manifestResources: SpecializedCollections.EmptyEnumerable<ResourceDescription>(), | ||
| assemblySymbolMapper: null, | ||
| additionalTypes: additionalTypes) | ||
| { | ||
| _methods = ImmutableHashSet.CreateRange(methods); | ||
|
|
||
| if (testData != null) | ||
| { | ||
| this.SetMethodTestData(testData.Methods); | ||
| testData.Module = this; | ||
| } | ||
| } | ||
|
|
||
| protected override IModuleReference TranslateModule(ModuleSymbol symbol, DiagnosticBag diagnostics) | ||
| { | ||
| var moduleSymbol = symbol as PEModuleSymbol; | ||
| if ((object)moduleSymbol != null) | ||
| { | ||
| var module = moduleSymbol.Module; | ||
| // Expose the individual runtime Windows.*.winmd modules as assemblies. | ||
| // (The modules were wrapped in a placeholder Windows.winmd assembly | ||
| // in MetadataUtilities.MakeAssemblyReferences.) | ||
| if (MetadataUtilities.IsWindowsComponent(module.MetadataReader, module.Name) && | ||
| MetadataUtilities.IsWindowsAssemblyName(moduleSymbol.ContainingAssembly.Name)) | ||
| { | ||
| var identity = module.ReadAssemblyIdentityOrThrow(); | ||
| return new Microsoft.CodeAnalysis.ExpressionEvaluator.AssemblyReference(identity); | ||
| } | ||
| } | ||
| return base.TranslateModule(symbol, diagnostics); | ||
| } | ||
|
|
||
| public override int CurrentGenerationOrdinal => 0; | ||
|
|
||
| internal override VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol symbol) | ||
| { | ||
| var method = symbol as EEMethodSymbol; | ||
| if (((object)method != null) && _methods.Contains(method)) | ||
| { | ||
| var defs = GetLocalDefinitions(method.Locals); | ||
| return new SlotAllocator(defs); | ||
| } | ||
|
|
||
| Debug.Assert(!_methods.Contains(symbol)); | ||
| return null; | ||
| } | ||
|
|
||
| private static ImmutableArray<LocalDefinition> GetLocalDefinitions(ImmutableArray<LocalSymbol> locals) | ||
| { | ||
| var builder = ArrayBuilder<LocalDefinition>.GetInstance(); | ||
| foreach (var local in locals) | ||
| { | ||
| if (local.DeclarationKind == LocalDeclarationKind.Constant) | ||
| { | ||
| continue; | ||
| } | ||
| var def = ToLocalDefinition(local, builder.Count); | ||
| Debug.Assert(((EELocalSymbol)local).Ordinal == def.SlotIndex); | ||
| builder.Add(def); | ||
| } | ||
| return builder.ToImmutableAndFree(); | ||
| } | ||
|
|
||
| private static LocalDefinition ToLocalDefinition(LocalSymbol local, int index) | ||
| { | ||
| // See EvaluationContext.GetLocals. | ||
| TypeSymbol type; | ||
| LocalSlotConstraints constraints; | ||
| if (local.DeclarationKind == LocalDeclarationKind.FixedVariable) | ||
| { | ||
| type = ((PointerTypeSymbol)local.Type).PointedAtType; | ||
| constraints = LocalSlotConstraints.ByRef | LocalSlotConstraints.Pinned; | ||
| } | ||
| else | ||
| { | ||
| type = local.Type; | ||
| constraints = (local.IsPinned ? LocalSlotConstraints.Pinned : LocalSlotConstraints.None) | | ||
| ((local.RefKind == RefKind.None) ? LocalSlotConstraints.None : LocalSlotConstraints.ByRef); | ||
| } | ||
| return new LocalDefinition( | ||
| local, | ||
| local.Name, | ||
| (Cci.ITypeReference)type, | ||
| slot: index, | ||
| synthesizedKind: (SynthesizedLocalKind)local.SynthesizedKind, | ||
| id: LocalDebugId.None, | ||
| pdbAttributes: Cci.PdbWriter.DefaultLocalAttributesValue, | ||
| constraints: constraints, | ||
| isDynamic: false, | ||
| dynamicTransformFlags: ImmutableArray<TypedConstant>.Empty); | ||
| } | ||
|
|
||
| private sealed class SlotAllocator : VariableSlotAllocator | ||
| { | ||
| private readonly ImmutableArray<LocalDefinition> _locals; | ||
|
|
||
| internal SlotAllocator(ImmutableArray<LocalDefinition> locals) | ||
| { | ||
| _locals = locals; | ||
| } | ||
|
|
||
| public override void AddPreviousLocals(ArrayBuilder<Cci.ILocalDefinition> builder) | ||
| { | ||
| builder.AddRange(_locals); | ||
| } | ||
|
|
||
| public override LocalDefinition GetPreviousLocal( | ||
| Cci.ITypeReference type, | ||
| ILocalSymbolInternal symbol, | ||
| string nameOpt, | ||
| SynthesizedLocalKind synthesizedKind, | ||
| LocalDebugId id, | ||
| uint pdbAttributes, | ||
| LocalSlotConstraints constraints, | ||
| bool isDynamic, | ||
| ImmutableArray<TypedConstant> dynamicTransformFlags) | ||
| { | ||
| var local = symbol as EELocalSymbol; | ||
| if ((object)local == null) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| return _locals[local.Ordinal]; | ||
| } | ||
|
|
||
| public override string PreviousStateMachineTypeName | ||
| { | ||
| get { return null; } | ||
| } | ||
|
|
||
| public override bool TryGetPreviousHoistedLocalSlotIndex(SyntaxNode currentDeclarator, Cci.ITypeReference currentType, SynthesizedLocalKind synthesizedKind, LocalDebugId currentId, out int slotIndex) | ||
| { | ||
| slotIndex = -1; | ||
| return false; | ||
| } | ||
|
|
||
| public override int PreviousHoistedLocalSlotCount | ||
| { | ||
| get { return 0; } | ||
| } | ||
|
|
||
| public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, out int slotIndex) | ||
| { | ||
| slotIndex = -1; | ||
| return false; | ||
| } | ||
|
|
||
| public override bool TryGetPreviousClosure(SyntaxNode closureSyntax, out int closureOrdinal) | ||
| { | ||
| closureOrdinal = -1; | ||
| return false; | ||
| } | ||
|
|
||
| public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out int lambdaOrdinal) | ||
| { | ||
| lambdaOrdinal = -1; | ||
| return false; | ||
| } | ||
|
|
||
| public override int PreviousAwaiterSlotCount | ||
| { | ||
| get { return 0; } | ||
| } | ||
|
|
||
| public override MethodDebugId PreviousMethodId | ||
| { | ||
| get | ||
| { | ||
| return default(MethodDebugId); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| // Copyright (c) Microsoft. 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.CSharp.Symbols; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class EETypeNameDecoder : TypeNameDecoder<PEModuleSymbol, TypeSymbol> | ||
| { | ||
| private readonly CSharpCompilation _compilation; | ||
|
|
||
| internal EETypeNameDecoder(CSharpCompilation compilation, PEModuleSymbol moduleSymbol) : | ||
| base(SymbolFactory.Instance, moduleSymbol) | ||
| { | ||
| _compilation = compilation; | ||
| } | ||
|
|
||
| protected override int GetIndexOfReferencedAssembly(AssemblyIdentity identity) | ||
| { | ||
| var assemblies = this.GetAssemblies(); | ||
| // Find assembly matching identity. | ||
| int index = assemblies.IndexOf((assembly, id) => id.Equals(assembly.Identity), identity); | ||
| if (index >= 0) | ||
| { | ||
| return index; | ||
| } | ||
| if (identity.IsWindowsComponent()) | ||
| { | ||
| // Find placeholder Windows.winmd assembly (created | ||
| // in MetadataUtilities.MakeAssemblyReferences). | ||
| index = assemblies.IndexOf((assembly, unused) => assembly.Identity.IsWindowsRuntime(), (object)null); | ||
| if (index >= 0) | ||
| { | ||
| // Find module in Windows.winmd matching identity. | ||
| var modules = assemblies[index].Modules; | ||
| var moduleIndex = modules.IndexOf((m, id) => id.Equals(GetComponentAssemblyIdentity(m)), identity); | ||
| if (moduleIndex >= 0) | ||
| { | ||
| return index; | ||
| } | ||
| } | ||
| } | ||
| return -1; | ||
| } | ||
|
|
||
| protected override bool IsContainingAssembly(AssemblyIdentity identity) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| protected override TypeSymbol LookupNestedTypeDefSymbol(TypeSymbol container, ref MetadataTypeName emittedName) | ||
| { | ||
| return container.LookupMetadataType(ref emittedName); | ||
| } | ||
|
|
||
| protected override TypeSymbol LookupTopLevelTypeDefSymbol(int referencedAssemblyIndex, ref MetadataTypeName emittedName) | ||
| { | ||
| var assembly = this.GetAssemblies()[referencedAssemblyIndex]; | ||
| return assembly.LookupTopLevelMetadataType(ref emittedName, digThroughForwardedTypes: true); | ||
| } | ||
|
|
||
| protected override TypeSymbol LookupTopLevelTypeDefSymbol(ref MetadataTypeName emittedName, out bool isNoPiaLocalType) | ||
| { | ||
| return this.moduleSymbol.LookupTopLevelMetadataType(ref emittedName, out isNoPiaLocalType); | ||
| } | ||
|
|
||
| private ImmutableArray<AssemblySymbol> GetAssemblies() | ||
| { | ||
| return _compilation.Assembly.Modules.Single().GetReferencedAssemblySymbols(); | ||
| } | ||
|
|
||
| private static AssemblyIdentity GetComponentAssemblyIdentity(ModuleSymbol module) | ||
| { | ||
| return ((PEModuleSymbol)module).Module.ReadAssemblyIdentityOrThrow(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System.Runtime.CompilerServices; | ||
|
|
||
| [assembly: InternalsVisibleTo("Microsoft.VisualStudio.ProductionBreakpoints.CodeAnalysis, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Roslyn.Utilities; | ||
| using System.Collections.Generic; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
| using System.Linq; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class CapturedVariableRewriter : BoundTreeRewriter | ||
| { | ||
| internal static BoundNode Rewrite( | ||
| ParameterSymbol targetMethodThisParameter, | ||
| Conversions conversions, | ||
| ImmutableDictionary<string, DisplayClassVariable> displayClassVariables, | ||
| BoundNode node, | ||
| DiagnosticBag diagnostics) | ||
| { | ||
| var rewriter = new CapturedVariableRewriter(targetMethodThisParameter, conversions, displayClassVariables, diagnostics); | ||
| return rewriter.Visit(node); | ||
| } | ||
|
|
||
| private readonly ParameterSymbol _targetMethodThisParameter; | ||
| private readonly Conversions _conversions; | ||
| private readonly ImmutableDictionary<string, DisplayClassVariable> _displayClassVariables; | ||
| private readonly DiagnosticBag _diagnostics; | ||
|
|
||
| private CapturedVariableRewriter( | ||
| ParameterSymbol targetMethodThisParameter, | ||
| Conversions conversions, | ||
| ImmutableDictionary<string, DisplayClassVariable> displayClassVariables, | ||
| DiagnosticBag diagnostics) | ||
| { | ||
| _targetMethodThisParameter = targetMethodThisParameter; | ||
| _conversions = conversions; | ||
| _displayClassVariables = displayClassVariables; | ||
| _diagnostics = diagnostics; | ||
| } | ||
|
|
||
| public override BoundNode VisitBlock(BoundBlock node) | ||
| { | ||
| var rewrittenLocals = node.Locals.WhereAsArray(local => local.IsCompilerGenerated || local.Name == null || this.GetVariable(local.Name) == null); | ||
| var rewrittenStatements = VisitList(node.Statements); | ||
| return node.Update(rewrittenLocals, rewrittenStatements); | ||
| } | ||
|
|
||
| public override BoundNode VisitLocal(BoundLocal node) | ||
| { | ||
| var local = node.LocalSymbol; | ||
| if (!local.IsCompilerGenerated) | ||
| { | ||
| var variable = this.GetVariable(local.Name); | ||
| if (variable != null) | ||
| { | ||
| var result = variable.ToBoundExpression(node.Syntax); | ||
| Debug.Assert(node.Type == result.Type); | ||
| return result; | ||
| } | ||
| } | ||
| return node; | ||
| } | ||
|
|
||
| public override BoundNode VisitParameter(BoundParameter node) | ||
| { | ||
| return RewriteParameter(node.Syntax, node.ParameterSymbol, node); | ||
| } | ||
|
|
||
| public override BoundNode VisitMethodGroup(BoundMethodGroup node) | ||
| { | ||
| if ((node.Flags & BoundMethodGroupFlags.HasImplicitReceiver) == BoundMethodGroupFlags.HasImplicitReceiver && | ||
| (object)_targetMethodThisParameter == null) | ||
| { | ||
| // This can happen in static contexts. | ||
| // NOTE: LocalRewriter has already been run, so the receiver has already been replaced with an | ||
| // appropriate type expression, if this is a static context. | ||
| // NOTE: Don't go through VisitThisReference, because it'll produce a diagnostic. | ||
| return node.Update( | ||
| node.TypeArgumentsOpt, | ||
| node.Name, | ||
| node.Methods, | ||
| node.LookupSymbolOpt, | ||
| node.LookupError, | ||
| node.Flags, | ||
| receiverOpt: null, | ||
| resultKind: node.ResultKind); | ||
| } | ||
| else | ||
| { | ||
| return base.VisitMethodGroup(node); | ||
| } | ||
| } | ||
|
|
||
| public override BoundNode VisitThisReference(BoundThisReference node) | ||
| { | ||
| return RewriteParameter(node.Syntax, _targetMethodThisParameter, node); | ||
| } | ||
|
|
||
| public override BoundNode VisitBaseReference(BoundBaseReference node) | ||
| { | ||
| var syntax = node.Syntax; | ||
| var rewrittenParameter = RewriteParameter(syntax, _targetMethodThisParameter, node); | ||
|
|
||
| var baseType = node.Type; | ||
| HashSet<DiagnosticInfo> unusedUseSiteDiagnostics = null; | ||
| var conversion = _conversions.ClassifyImplicitConversionFromExpression(rewrittenParameter, baseType, ref unusedUseSiteDiagnostics); | ||
| Debug.Assert(unusedUseSiteDiagnostics == null || !conversion.IsValid || unusedUseSiteDiagnostics.All(d => d.Severity < DiagnosticSeverity.Error)); | ||
|
|
||
| // It would be nice if we could just call BoundConversion.Synthesized, but it doesn't seem worthwile to | ||
| // introduce a bunch of new overloads to accommodate isBaseConversion. | ||
| return new BoundConversion( | ||
| syntax, | ||
| rewrittenParameter, | ||
| conversion.Kind, | ||
| conversion.ResultKind, | ||
| isBaseConversion: true, | ||
| symbolOpt: conversion.Method, | ||
| @checked: false, | ||
| explicitCastInCode: false, | ||
| isExtensionMethod: conversion.IsExtensionMethod, | ||
| isArrayIndex: conversion.IsArrayIndex, | ||
| constantValueOpt: null, | ||
| type: baseType, | ||
| hasErrors: !conversion.IsValid) | ||
| { WasCompilerGenerated = true }; | ||
| } | ||
|
|
||
| private BoundExpression RewriteParameter(CSharpSyntaxNode syntax, ParameterSymbol symbol, BoundExpression node) | ||
| { | ||
| // This can happen in error scenarios (e.g. user binds "this" in a lambda in a static method). | ||
| if ((object)symbol == null) | ||
| { | ||
| ReportMissingThis(node.Kind, syntax); | ||
| return node; | ||
| } | ||
|
|
||
| var variable = this.GetVariable(symbol.Name); | ||
| if (variable == null) | ||
| { | ||
| var typeNameKind = GeneratedNames.GetKind(symbol.Type.Name); | ||
| if (typeNameKind != GeneratedNameKind.None) | ||
| { | ||
| // The state machine case is for async lambdas. The state machine | ||
| // will have a hoisted "this" field if it needs to access the | ||
| // containing display class, but the display class may not have a | ||
| // "this" field. | ||
| Debug.Assert(typeNameKind == GeneratedNameKind.LambdaDisplayClass || | ||
| typeNameKind == GeneratedNameKind.StateMachineType); | ||
| ReportMissingThis(node.Kind, syntax); | ||
| return node; | ||
| } | ||
|
|
||
| return (node as BoundParameter) ?? new BoundParameter(syntax, symbol); | ||
| } | ||
|
|
||
| var result = variable.ToBoundExpression(syntax); | ||
| Debug.Assert(node.Kind == BoundKind.BaseReference | ||
| ? result.Type.BaseType.Equals(node.Type, ignoreDynamic: true) | ||
| : result.Type.Equals(node.Type, ignoreDynamic: true)); | ||
| return result; | ||
| } | ||
|
|
||
| private void ReportMissingThis(BoundKind boundKind, CSharpSyntaxNode syntax) | ||
| { | ||
| Debug.Assert(boundKind == BoundKind.ThisReference || boundKind == BoundKind.BaseReference); | ||
| var errorCode = boundKind == BoundKind.BaseReference | ||
| ? ErrorCode.ERR_BaseInBadContext | ||
| : ErrorCode.ERR_ThisInBadContext; | ||
| _diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(errorCode), syntax.Location)); | ||
| } | ||
|
|
||
| private DisplayClassVariable GetVariable(string name) | ||
| { | ||
| DisplayClassVariable variable; | ||
| _displayClassVariables.TryGetValue(name, out variable); | ||
| return variable; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
| using System.Collections.Generic; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class LocalDeclarationRewriter | ||
| { | ||
| internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals, BoundNode node) | ||
| { | ||
| var builder = ArrayBuilder<BoundStatement>.GetInstance(); | ||
| bool hasChanged; | ||
|
|
||
| // Rewrite top-level declarations only. | ||
| switch (node.Kind) | ||
| { | ||
| case BoundKind.LocalDeclaration: | ||
| RewriteLocalDeclaration(compilation, container, declaredLocals, builder, (BoundLocalDeclaration)node); | ||
| hasChanged = true; | ||
| break; | ||
| case BoundKind.MultipleLocalDeclarations: | ||
| foreach (var declaration in ((BoundMultipleLocalDeclarations)node).LocalDeclarations) | ||
| { | ||
| RewriteLocalDeclaration(compilation, container, declaredLocals, builder, declaration); | ||
| } | ||
| hasChanged = true; | ||
| break; | ||
| default: | ||
| hasChanged = false; | ||
| break; | ||
| } | ||
|
|
||
| if (hasChanged) | ||
| { | ||
| node = new BoundBlock(node.Syntax, ImmutableArray<LocalSymbol>.Empty, builder.ToImmutable()) { WasCompilerGenerated = true }; | ||
| } | ||
|
|
||
| builder.Free(); | ||
| return node; | ||
| } | ||
|
|
||
| private static void RewriteLocalDeclaration( | ||
| CSharpCompilation compilation, | ||
| EENamedTypeSymbol container, | ||
| HashSet<LocalSymbol> declaredLocals, | ||
| ArrayBuilder<BoundStatement> statements, | ||
| BoundLocalDeclaration node) | ||
| { | ||
| Debug.Assert(node.ArgumentsOpt.IsDefault); | ||
|
|
||
| var local = node.LocalSymbol; | ||
| var syntax = node.Syntax; | ||
|
|
||
| declaredLocals.Add(local); | ||
|
|
||
| var voidType = compilation.GetSpecialType(SpecialType.System_Void); | ||
| var objectType = compilation.GetSpecialType(SpecialType.System_Object); | ||
| var typeType = compilation.GetWellKnownType(WellKnownType.System_Type); | ||
| var stringType = compilation.GetSpecialType(SpecialType.System_String); | ||
|
|
||
| // <>CreateVariable(Type type, string name) | ||
| var method = container.GetOrAddSynthesizedMethod( | ||
| ExpressionCompilerConstants.CreateVariableMethodName, | ||
| (c, n, s) => new PlaceholderMethodSymbol( | ||
| c, | ||
| s, | ||
| n, | ||
| voidType, | ||
| m => ImmutableArray.Create<ParameterSymbol>( | ||
| new SynthesizedParameterSymbol(m, typeType, ordinal: 0, refKind: RefKind.None), | ||
| new SynthesizedParameterSymbol(m, stringType, ordinal: 1, refKind: RefKind.None)))); | ||
| var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType); | ||
| var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType); | ||
| var call = BoundCall.Synthesized( | ||
| syntax, | ||
| receiverOpt: null, | ||
| method: method, | ||
| arguments: ImmutableArray.Create<BoundExpression>(type, name)); | ||
| statements.Add(new BoundExpressionStatement(syntax, call)); | ||
|
|
||
| var initializer = node.InitializerOpt; | ||
| if (initializer != null) | ||
| { | ||
| // Generate assignment to local. The assignment will | ||
| // be rewritten in PlaceholderLocalRewriter. | ||
| var assignment = new BoundAssignmentOperator( | ||
| syntax, | ||
| new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type), | ||
| initializer, | ||
| RefKind.None, | ||
| local.Type); | ||
| statements.Add(new BoundExpressionStatement(syntax, assignment)); | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class MayHaveSideEffectsVisitor : BoundTreeWalker | ||
| { | ||
| private bool _mayHaveSideEffects; | ||
|
|
||
| internal static bool MayHaveSideEffects(BoundNode node) | ||
| { | ||
| var visitor = new MayHaveSideEffectsVisitor(); | ||
| visitor.Visit(node); | ||
| return visitor._mayHaveSideEffects; | ||
| } | ||
|
|
||
| public override BoundNode Visit(BoundNode node) | ||
| { | ||
| if (_mayHaveSideEffects) | ||
| { | ||
| return null; | ||
| } | ||
| return base.Visit(node); | ||
| } | ||
|
|
||
| public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) | ||
| { | ||
| return this.SetMayHaveSideEffects(); | ||
| } | ||
|
|
||
| // Calls are treated as having side effects, but properties and | ||
| // indexers are not. (Since this visitor is run on the bound tree | ||
| // before lowering, properties are not represented as calls.) | ||
| public override BoundNode VisitCall(BoundCall node) | ||
| { | ||
| return this.SetMayHaveSideEffects(); | ||
| } | ||
|
|
||
| public override BoundNode VisitDynamicInvocation(BoundDynamicInvocation node) | ||
| { | ||
| return this.SetMayHaveSideEffects(); | ||
| } | ||
|
|
||
| public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) | ||
| { | ||
| return this.SetMayHaveSideEffects(); | ||
| } | ||
|
|
||
| public override BoundNode VisitEventAssignmentOperator(BoundEventAssignmentOperator node) | ||
| { | ||
| return this.SetMayHaveSideEffects(); | ||
| } | ||
|
|
||
| public override BoundNode VisitIncrementOperator(BoundIncrementOperator node) | ||
| { | ||
| return this.SetMayHaveSideEffects(); | ||
| } | ||
|
|
||
| public override BoundNode VisitObjectInitializerExpression(BoundObjectInitializerExpression node) | ||
| { | ||
| foreach (var initializer in node.Initializers) | ||
| { | ||
| // Do not treat initializer assignment as a side effect since it is | ||
| // part of an object creation. In short, visit the RHS only. | ||
| var expr = (initializer.Kind == BoundKind.AssignmentOperator) ? | ||
| ((BoundAssignmentOperator)initializer).Right : | ||
| initializer; | ||
| this.Visit(expr); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| private BoundNode SetMayHaveSideEffects() | ||
| { | ||
| _mayHaveSideEffects = true; | ||
| return null; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class PlaceholderLocalRewriter : BoundTreeRewriter | ||
| { | ||
| internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals, BoundNode node) | ||
| { | ||
| var rewriter = new PlaceholderLocalRewriter(compilation, container, declaredLocals); | ||
| return rewriter.Visit(node); | ||
| } | ||
|
|
||
| private readonly CSharpCompilation _compilation; | ||
| private readonly EENamedTypeSymbol _container; | ||
| private readonly HashSet<LocalSymbol> _declaredLocals; | ||
|
|
||
| private PlaceholderLocalRewriter(CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals) | ||
| { | ||
| _compilation = compilation; | ||
| _container = container; | ||
| _declaredLocals = declaredLocals; | ||
| } | ||
|
|
||
| public override BoundNode VisitLocal(BoundLocal node) | ||
| { | ||
| var result = RewriteLocal(node); | ||
| Debug.Assert(result.Type == node.Type); | ||
| return result; | ||
| } | ||
|
|
||
| private BoundExpression RewriteLocal(BoundLocal node) | ||
| { | ||
| var local = node.LocalSymbol; | ||
| var placeholder = local as PlaceholderLocalSymbol; | ||
| if ((object)placeholder != null) | ||
| { | ||
| return placeholder.RewriteLocal(_compilation, _container, node.Syntax); | ||
| } | ||
| if (_declaredLocals.Contains(local)) | ||
| { | ||
| return ObjectIdLocalSymbol.RewriteLocal(_compilation, _container, node.Syntax, local); | ||
| } | ||
| return node; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using System.Diagnostics; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal abstract class DisplayClassInstance | ||
| { | ||
| internal abstract Symbol ContainingSymbol { get; } | ||
|
|
||
| internal abstract NamedTypeSymbol Type { get; } | ||
|
|
||
| internal abstract DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap); | ||
|
|
||
| internal abstract BoundExpression ToBoundExpression(CSharpSyntaxNode syntax); | ||
| } | ||
|
|
||
| internal sealed class DisplayClassInstanceFromLocal : DisplayClassInstance | ||
| { | ||
| internal readonly EELocalSymbol Local; | ||
|
|
||
| internal DisplayClassInstanceFromLocal(EELocalSymbol local) | ||
| { | ||
| Debug.Assert(!local.IsPinned); | ||
| Debug.Assert(local.RefKind == RefKind.None); | ||
| Debug.Assert(local.DeclarationKind == LocalDeclarationKind.RegularVariable); | ||
|
|
||
| this.Local = local; | ||
| } | ||
|
|
||
| internal override Symbol ContainingSymbol | ||
| { | ||
| get { return this.Local.ContainingSymbol; } | ||
| } | ||
|
|
||
| internal override NamedTypeSymbol Type | ||
| { | ||
| get { return (NamedTypeSymbol)this.Local.Type; } | ||
| } | ||
|
|
||
| internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap) | ||
| { | ||
| var otherInstance = (EELocalSymbol)this.Local.ToOtherMethod(method, typeMap); | ||
| return new DisplayClassInstanceFromLocal(otherInstance); | ||
| } | ||
|
|
||
| internal override BoundExpression ToBoundExpression(CSharpSyntaxNode syntax) | ||
| { | ||
| return new BoundLocal(syntax, this.Local, constantValueOpt: null, type: this.Local.Type) { WasCompilerGenerated = true }; | ||
| } | ||
| } | ||
|
|
||
| internal sealed class DisplayClassInstanceFromThis : DisplayClassInstance | ||
| { | ||
| internal readonly ParameterSymbol ThisParameter; | ||
|
|
||
| internal DisplayClassInstanceFromThis(ParameterSymbol thisParameter) | ||
| { | ||
| Debug.Assert(thisParameter != null); | ||
| this.ThisParameter = thisParameter; | ||
| } | ||
|
|
||
| internal override Symbol ContainingSymbol | ||
| { | ||
| get { return this.ThisParameter.ContainingSymbol; } | ||
| } | ||
|
|
||
| internal override NamedTypeSymbol Type | ||
| { | ||
| get { return (NamedTypeSymbol)this.ThisParameter.Type; } | ||
| } | ||
|
|
||
| internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap) | ||
| { | ||
| Debug.Assert(method.IsStatic); | ||
| var otherParameter = method.Parameters[0]; | ||
| return new DisplayClassInstanceFromThis(otherParameter); | ||
| } | ||
|
|
||
| internal override BoundExpression ToBoundExpression(CSharpSyntaxNode syntax) | ||
| { | ||
| return new BoundParameter(syntax, this.ThisParameter) { WasCompilerGenerated = true }; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,208 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Roslyn.Utilities; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal enum DisplayClassVariableKind | ||
| { | ||
| Local, | ||
| Parameter, | ||
| This, | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// A field in a display class that represents a captured | ||
| /// variable: either a local, a parameter, or "this". | ||
| /// </summary> | ||
| internal sealed class DisplayClassVariable | ||
| { | ||
| internal readonly string Name; | ||
| internal readonly DisplayClassVariableKind Kind; | ||
| internal readonly DisplayClassInstance DisplayClassInstance; | ||
| internal readonly ConsList<FieldSymbol> DisplayClassFields; | ||
|
|
||
| internal DisplayClassVariable(string name, DisplayClassVariableKind kind, DisplayClassInstance displayClassInstance, ConsList<FieldSymbol> displayClassFields) | ||
| { | ||
| Debug.Assert(displayClassFields.Any()); | ||
|
|
||
| this.Name = name; | ||
| this.Kind = kind; | ||
| this.DisplayClassInstance = displayClassInstance; | ||
| this.DisplayClassFields = displayClassFields; | ||
|
|
||
| // Verify all type parameters are substituted. | ||
| Debug.Assert(this.ContainingSymbol.IsContainingSymbolOfAllTypeParameters(this.Type)); | ||
| } | ||
|
|
||
| internal TypeSymbol Type | ||
| { | ||
| get { return this.DisplayClassFields.Head.Type; } | ||
| } | ||
|
|
||
| internal Symbol ContainingSymbol | ||
| { | ||
| get { return this.DisplayClassInstance.ContainingSymbol; } | ||
| } | ||
|
|
||
| internal DisplayClassVariable ToOtherMethod(MethodSymbol method, TypeMap typeMap) | ||
| { | ||
| var otherInstance = this.DisplayClassInstance.ToOtherMethod(method, typeMap); | ||
| return SubstituteFields(otherInstance, typeMap); | ||
| } | ||
|
|
||
| internal BoundExpression ToBoundExpression(CSharpSyntaxNode syntax) | ||
| { | ||
| var expr = this.DisplayClassInstance.ToBoundExpression(syntax); | ||
| var fields = ArrayBuilder<FieldSymbol>.GetInstance(); | ||
| fields.AddRange(this.DisplayClassFields); | ||
| fields.ReverseContents(); | ||
| foreach (var field in fields) | ||
| { | ||
| expr = new BoundFieldAccess(syntax, expr, field, constantValueOpt: null) { WasCompilerGenerated = true }; | ||
| } | ||
| fields.Free(); | ||
| return expr; | ||
| } | ||
|
|
||
| internal DisplayClassVariable SubstituteFields(DisplayClassInstance otherInstance, TypeMap typeMap) | ||
| { | ||
| var otherFields = SubstituteFields(this.DisplayClassFields, typeMap); | ||
| return new DisplayClassVariable(this.Name, this.Kind, otherInstance, otherFields); | ||
| } | ||
|
|
||
| private static ConsList<FieldSymbol> SubstituteFields(ConsList<FieldSymbol> fields, TypeMap typeMap) | ||
| { | ||
| if (!fields.Any()) | ||
| { | ||
| return ConsList<FieldSymbol>.Empty; | ||
| } | ||
|
|
||
| var head = SubstituteField(fields.Head, typeMap); | ||
| var tail = SubstituteFields(fields.Tail, typeMap); | ||
| return tail.Prepend(head); | ||
| } | ||
|
|
||
| private static FieldSymbol SubstituteField(FieldSymbol field, TypeMap typeMap) | ||
| { | ||
| Debug.Assert(!field.IsStatic); | ||
| Debug.Assert(!field.IsReadOnly); | ||
| Debug.Assert(field.CustomModifiers.Length == 0); | ||
| // CONSIDER: Instead of digging fields out of the unsubstituted type and then performing substitution | ||
| // on each one individually, we could dig fields out of the substituted type. | ||
| return new EEDisplayClassFieldSymbol(typeMap.SubstituteNamedType(field.ContainingType), field.Name, typeMap.SubstituteType(field.Type)); | ||
| } | ||
|
|
||
| private sealed class EEDisplayClassFieldSymbol : FieldSymbol | ||
| { | ||
| private readonly NamedTypeSymbol _container; | ||
| private readonly string _name; | ||
| private readonly TypeSymbol _type; | ||
|
|
||
| internal EEDisplayClassFieldSymbol(NamedTypeSymbol container, string name, TypeSymbol type) | ||
| { | ||
| _container = container; | ||
| _name = name; | ||
| _type = type; | ||
| } | ||
|
|
||
| public override Symbol AssociatedSymbol | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override Symbol ContainingSymbol | ||
| { | ||
| get { return _container; } | ||
| } | ||
|
|
||
| public override ImmutableArray<CustomModifier> CustomModifiers | ||
| { | ||
| get { return ImmutableArray<CustomModifier>.Empty; } | ||
| } | ||
|
|
||
| public override Accessibility DeclaredAccessibility | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override bool IsConst | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override bool IsReadOnly | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override bool IsStatic | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override bool IsVolatile | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override ImmutableArray<Location> Locations | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override string Name | ||
| { | ||
| get { return _name; } | ||
| } | ||
|
|
||
| internal override bool HasRuntimeSpecialName | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| internal override bool HasSpecialName | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| internal override bool IsNotSerialized | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| internal override MarshalPseudoCustomAttributeData MarshallingInformation | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| internal override ObsoleteAttributeData ObsoleteAttributeData | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| internal override int? TypeLayoutOffset | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| internal override ConstantValue GetConstantValue(ConstantFieldsInProgress inProgress, bool earlyDecodingWellKnownAttributes) | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| internal override TypeSymbol GetFieldType(ConsList<FieldSymbol> fieldsBeingBound) | ||
| { | ||
| return _type; | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // Copyright (c) Microsoft. 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 Microsoft.CodeAnalysis.CSharp.Symbols; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| /// <summary> | ||
| /// Synthesized expression evaluation method. | ||
| /// </summary> | ||
| internal sealed class EEConstructorSymbol : SynthesizedInstanceConstructor | ||
| { | ||
| internal EEConstructorSymbol(NamedTypeSymbol containingType) | ||
| : base(containingType) | ||
| { | ||
| } | ||
|
|
||
| internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) | ||
| { | ||
| var noLocals = ImmutableArray<LocalSymbol>.Empty; | ||
| var initializerInvocation = MethodCompiler.BindConstructorInitializer(this, diagnostics, compilationState.Compilation); | ||
| var syntax = initializerInvocation.Syntax; | ||
|
|
||
| compilationState.AddSynthesizedMethod(this, | ||
| new BoundBlock( | ||
| syntax, | ||
| noLocals, | ||
| ImmutableArray.Create<BoundStatement>( | ||
| new BoundExpressionStatement(syntax, initializerInvocation), | ||
| new BoundReturnStatement(syntax, null)))); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
| using Roslyn.Utilities; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| /// <summary> | ||
| /// A display class field representing a local, exposed | ||
| /// as a local on the original method. | ||
| /// </summary> | ||
| internal sealed class EEDisplayClassFieldLocalSymbol : EELocalSymbolBase | ||
| { | ||
| private readonly DisplayClassVariable _variable; | ||
|
|
||
| public EEDisplayClassFieldLocalSymbol(DisplayClassVariable variable) | ||
| { | ||
| _variable = variable; | ||
|
|
||
| // Verify all type parameters are substituted. | ||
| Debug.Assert(this.ContainingSymbol.IsContainingSymbolOfAllTypeParameters(this.Type)); | ||
| } | ||
|
|
||
| internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap) | ||
| { | ||
| return new EEDisplayClassFieldLocalSymbol(_variable.ToOtherMethod(method, typeMap)); | ||
| } | ||
|
|
||
| public override string Name | ||
| { | ||
| get { return _variable.Name; } | ||
| } | ||
|
|
||
| internal override LocalDeclarationKind DeclarationKind | ||
| { | ||
| get { return LocalDeclarationKind.RegularVariable; } | ||
| } | ||
|
|
||
| internal override SyntaxToken IdentifierToken | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override Symbol ContainingSymbol | ||
| { | ||
| get { return _variable.ContainingSymbol; } | ||
| } | ||
|
|
||
| public override TypeSymbol Type | ||
| { | ||
| get { return _variable.Type; } | ||
| } | ||
|
|
||
| internal override bool IsPinned | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override bool IsCompilerGenerated | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override RefKind RefKind | ||
| { | ||
| get { return RefKind.None; } | ||
| } | ||
|
|
||
| public override ImmutableArray<Location> Locations | ||
| { | ||
| get { return NoLocations; } | ||
| } | ||
|
|
||
| public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences | ||
| { | ||
| get { return ImmutableArray<SyntaxReference>.Empty; } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // Copyright (c) Microsoft. 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 Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Roslyn.Utilities; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class EELocalConstantSymbol : EELocalSymbolBase | ||
| { | ||
| private readonly MethodSymbol _method; | ||
| private readonly string _name; | ||
| private readonly TypeSymbol _type; | ||
| private readonly ConstantValue _value; | ||
|
|
||
| public EELocalConstantSymbol( | ||
| MethodSymbol method, | ||
| string name, | ||
| TypeSymbol type, | ||
| ConstantValue value) | ||
| { | ||
| _method = method; | ||
| _name = name; | ||
| _type = type; | ||
| _value = value; | ||
| } | ||
|
|
||
| internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap) | ||
| { | ||
| var type = typeMap.SubstituteType(_type); | ||
| return new EELocalConstantSymbol(method, _name, type, _value); | ||
| } | ||
|
|
||
| public override string Name | ||
| { | ||
| get { return _name; } | ||
| } | ||
|
|
||
| internal override LocalDeclarationKind DeclarationKind | ||
| { | ||
| get { return LocalDeclarationKind.Constant; } | ||
| } | ||
|
|
||
| internal override SyntaxToken IdentifierToken | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override Symbol ContainingSymbol | ||
| { | ||
| get { return _method; } | ||
| } | ||
|
|
||
| public override TypeSymbol Type | ||
| { | ||
| get { return _type; } | ||
| } | ||
|
|
||
| internal override bool IsPinned | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override bool IsCompilerGenerated | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics) | ||
| { | ||
| return _value; | ||
| } | ||
|
|
||
| internal override RefKind RefKind | ||
| { | ||
| get { return RefKind.None; } | ||
| } | ||
|
|
||
| public override ImmutableArray<Location> Locations | ||
| { | ||
| get { return NoLocations; } | ||
| } | ||
|
|
||
| public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences | ||
| { | ||
| get { return ImmutableArray<SyntaxReference>.Empty; } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Roslyn.Utilities; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class EELocalSymbol : EELocalSymbolBase | ||
| { | ||
| private readonly MethodSymbol _method; | ||
| private readonly TypeSymbol _type; | ||
|
|
||
| private readonly LocalDeclarationKind _declarationKind; | ||
| private readonly bool _isCompilerGenerated; | ||
| private readonly ImmutableArray<Location> _locations; | ||
| private readonly string _nameOpt; | ||
| private readonly int _ordinal; // index in locals of containing block | ||
| private readonly bool _isPinned; | ||
| private readonly RefKind _refKind; | ||
| private readonly bool _canScheduleToStack; | ||
|
|
||
| public EELocalSymbol( | ||
| MethodSymbol method, | ||
| ImmutableArray<Location> locations, | ||
| string nameOpt, | ||
| int ordinal, | ||
| LocalDeclarationKind declarationKind, | ||
| TypeSymbol type, | ||
| RefKind refKind, | ||
| bool isPinned, | ||
| bool isCompilerGenerated, | ||
| bool canScheduleToStack) | ||
| { | ||
| Debug.Assert(method != null); | ||
| Debug.Assert(ordinal >= -1); | ||
| Debug.Assert(!locations.IsDefault); | ||
| Debug.Assert(type != null); | ||
|
|
||
| _method = method; | ||
| _locations = locations; | ||
| _nameOpt = nameOpt; | ||
| _ordinal = ordinal; | ||
| _declarationKind = declarationKind; | ||
| _type = type; | ||
| _refKind = refKind; | ||
| _isPinned = isPinned; | ||
| _isCompilerGenerated = isCompilerGenerated; | ||
| _canScheduleToStack = canScheduleToStack; | ||
| } | ||
|
|
||
| internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap) | ||
| { | ||
| var type = typeMap.SubstituteType(_type); | ||
| return new EELocalSymbol(method, _locations, _nameOpt, _ordinal, _declarationKind, type, _refKind, _isPinned, _isCompilerGenerated, _canScheduleToStack); | ||
| } | ||
|
|
||
| internal override LocalDeclarationKind DeclarationKind | ||
| { | ||
| get { return _declarationKind; } | ||
| } | ||
|
|
||
| internal override bool CanScheduleToStack | ||
| { | ||
| get { return _canScheduleToStack; } | ||
| } | ||
|
|
||
| internal int Ordinal | ||
| { | ||
| get { return _ordinal; } | ||
| } | ||
|
|
||
| public override string Name | ||
| { | ||
| get { return _nameOpt; } | ||
| } | ||
|
|
||
| internal override SyntaxToken IdentifierToken | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences | ||
| { | ||
| get { return ImmutableArray<SyntaxReference>.Empty; } | ||
| } | ||
|
|
||
| public override ImmutableArray<Location> Locations | ||
| { | ||
| get { return _locations; } | ||
| } | ||
|
|
||
| public override Symbol ContainingSymbol | ||
| { | ||
| get { return _method; } | ||
| } | ||
|
|
||
| public override TypeSymbol Type | ||
| { | ||
| get { return _type; } | ||
| } | ||
|
|
||
| internal override bool IsPinned | ||
| { | ||
| get { return _isPinned; } | ||
| } | ||
|
|
||
| internal override bool IsCompilerGenerated | ||
| { | ||
| get { return _isCompilerGenerated; } | ||
| } | ||
|
|
||
| internal override RefKind RefKind | ||
| { | ||
| get { return _refKind; } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Collections.Immutable; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Roslyn.Utilities; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal static class LocalSymbolExtensions | ||
| { | ||
| internal static LocalSymbol ToOtherMethod(this LocalSymbol local, MethodSymbol method, TypeMap typeMap) | ||
| { | ||
| var l = local as EELocalSymbolBase; | ||
| if ((object)l != null) | ||
| { | ||
| return l.ToOtherMethod(method, typeMap); | ||
| } | ||
| var type = typeMap.SubstituteType(local.Type); | ||
| return new EELocalSymbol(method, local.Locations, local.Name, -1, local.DeclarationKind, type, local.RefKind, local.IsPinned, local.IsCompilerGenerated, local.CanScheduleToStack); | ||
| } | ||
| } | ||
|
|
||
| internal abstract class EELocalSymbolBase : LocalSymbol | ||
| { | ||
| internal static readonly ImmutableArray<Location> NoLocations = ImmutableArray.Create(NoLocation.Singleton); | ||
|
|
||
| internal abstract EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap); | ||
|
|
||
| internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| internal override ImmutableArray<Diagnostic> GetConstantValueDiagnostics(BoundExpression boundInitValue) | ||
| { | ||
| return ImmutableArray<Diagnostic>.Empty; | ||
| } | ||
|
|
||
| internal sealed override SynthesizedLocalKind SynthesizedKind | ||
| { | ||
| get { return SynthesizedLocalKind.UserDefined; } | ||
| } | ||
|
|
||
| internal sealed override bool IsImportedFromMetadata | ||
| { | ||
| get { return true; } | ||
| } | ||
|
|
||
| internal override SyntaxNode GetDeclaratorSyntax() | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| internal sealed override DiagnosticInfo GetUseSiteDiagnostic() | ||
| { | ||
| var type = this.Type; | ||
| DiagnosticInfo result = null; | ||
| if (!DeriveUseSiteDiagnosticFromType(ref result, type) && this.ContainingModule.HasUnifiedReferences) | ||
| { | ||
| // If the member is in an assembly with unified references, | ||
| // we check if its definition depends on a type from a unified reference. | ||
| HashSet<TypeSymbol> unificationCheckedTypes = null; | ||
| type.GetUnificationUseSiteDiagnosticRecursive(ref result, this, ref unificationCheckedTypes); | ||
| } | ||
| return result; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,380 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Roslyn.Utilities; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class EENamedTypeSymbol : NamedTypeSymbol | ||
| { | ||
| internal readonly NamedTypeSymbol SubstitutedSourceType; | ||
| internal readonly ImmutableArray<TypeParameterSymbol> SourceTypeParameters; | ||
|
|
||
| private readonly NamespaceSymbol _container; | ||
| private readonly NamedTypeSymbol _baseType; | ||
| private readonly string _name; | ||
| private readonly CSharpSyntaxNode _syntax; | ||
| private readonly ImmutableArray<TypeParameterSymbol> _typeParameters; | ||
| private readonly ImmutableArray<MethodSymbol> _methods; | ||
|
|
||
| private Dictionary<string, PlaceholderMethodSymbol> _lazySynthesizedMethods; | ||
| #if DEBUG | ||
| private bool _sealed; | ||
| #endif | ||
|
|
||
| internal EENamedTypeSymbol( | ||
| NamespaceSymbol container, | ||
| NamedTypeSymbol baseType, | ||
| CSharpSyntaxNode syntax, | ||
| MethodSymbol currentFrame, | ||
| string typeName, | ||
| string methodName, | ||
| CompilationContext context, | ||
| GenerateMethodBody generateMethodBody) : | ||
| this(container, baseType, syntax, currentFrame, typeName, (m, t) => ImmutableArray.Create<MethodSymbol>(context.CreateMethod(t, methodName, syntax, generateMethodBody))) | ||
| { | ||
| } | ||
|
|
||
| internal EENamedTypeSymbol( | ||
| NamespaceSymbol container, | ||
| NamedTypeSymbol baseType, | ||
| CSharpSyntaxNode syntax, | ||
| MethodSymbol currentFrame, | ||
| string typeName, | ||
| Func<MethodSymbol, EENamedTypeSymbol, ImmutableArray<MethodSymbol>> getMethods, | ||
| ImmutableArray<TypeParameterSymbol> sourceTypeParameters, | ||
| Func<NamedTypeSymbol, EENamedTypeSymbol, ImmutableArray<TypeParameterSymbol>> getTypeParameters) | ||
| { | ||
| _container = container; | ||
| _baseType = baseType; | ||
| _syntax = syntax; | ||
| _name = typeName; | ||
| this.SourceTypeParameters = sourceTypeParameters; | ||
| _typeParameters = getTypeParameters(currentFrame.ContainingType, this); | ||
| VerifyTypeParameters(this, _typeParameters); | ||
| _methods = getMethods(currentFrame, this); | ||
| } | ||
|
|
||
| internal EENamedTypeSymbol( | ||
| NamespaceSymbol container, | ||
| NamedTypeSymbol baseType, | ||
| CSharpSyntaxNode syntax, | ||
| MethodSymbol currentFrame, | ||
| string typeName, | ||
| Func<MethodSymbol, EENamedTypeSymbol, ImmutableArray<MethodSymbol>> getMethods) | ||
| { | ||
| _container = container; | ||
| _baseType = baseType; | ||
| _syntax = syntax; | ||
| _name = typeName; | ||
|
|
||
| // What we want is to map all original type parameters to the corresponding new type parameters | ||
| // (since the old ones have the wrong owners). Unfortunately, we have a circular dependency: | ||
| // 1) Each new type parameter requires the entire map in order to be able to construct its constraint list. | ||
| // 2) The map cannot be constructed until all new type parameters exist. | ||
| // Our solution is to pass each new type parameter a lazy reference to the type map. We then | ||
| // initialize the map as soon as the new type parameters are available - and before they are | ||
| // handed out - so that there is never a period where they can require the type map and find | ||
| // it uninitialized. | ||
|
|
||
| var sourceType = currentFrame.ContainingType; | ||
| this.SourceTypeParameters = sourceType.GetAllTypeParameters(); | ||
|
|
||
| TypeMap typeMap = null; | ||
| var getTypeMap = new Func<TypeMap>(() => typeMap); | ||
| _typeParameters = this.SourceTypeParameters.SelectAsArray( | ||
| (tp, i, arg) => (TypeParameterSymbol)new EETypeParameterSymbol(this, tp, i, getTypeMap), | ||
| (object)null); | ||
|
|
||
| typeMap = new TypeMap(this.SourceTypeParameters, _typeParameters); | ||
|
|
||
| VerifyTypeParameters(this, _typeParameters); | ||
|
|
||
| this.SubstitutedSourceType = typeMap.SubstituteNamedType(sourceType); | ||
| TypeParameterChecker.Check(this.SubstitutedSourceType, _typeParameters); | ||
|
|
||
| _methods = getMethods(currentFrame, this); | ||
| } | ||
|
|
||
| internal ImmutableArray<MethodSymbol> Methods | ||
| { | ||
| get { return _methods; } | ||
| } | ||
|
|
||
| internal override IEnumerable<FieldSymbol> GetFieldsToEmit() | ||
| { | ||
| return SpecializedCollections.EmptyEnumerable<FieldSymbol>(); | ||
| } | ||
|
|
||
| internal override IEnumerable<MethodSymbol> GetMethodsToEmit() | ||
| { | ||
| foreach (var method in _methods) | ||
| { | ||
| yield return method; | ||
| } | ||
| #if DEBUG | ||
| _sealed = true; | ||
| #endif | ||
| if (_lazySynthesizedMethods != null) | ||
| { | ||
| foreach (var method in _lazySynthesizedMethods.Values) | ||
| { | ||
| yield return method; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| internal override ImmutableArray<NamedTypeSymbol> GetInterfacesToEmit() | ||
| { | ||
| return ImmutableArray<NamedTypeSymbol>.Empty; | ||
| } | ||
|
|
||
| public override int Arity | ||
| { | ||
| get { return _typeParameters.Length; } | ||
| } | ||
|
|
||
| public override ImmutableArray<TypeParameterSymbol> TypeParameters | ||
| { | ||
| get { return _typeParameters; } | ||
| } | ||
|
|
||
| internal override ImmutableArray<TypeSymbol> TypeArgumentsNoUseSiteDiagnostics | ||
| { | ||
| get { return _typeParameters.Cast<TypeParameterSymbol, TypeSymbol>(); } | ||
| } | ||
|
|
||
| public override NamedTypeSymbol ConstructedFrom | ||
| { | ||
| get { return this; } | ||
| } | ||
|
|
||
| public override bool MightContainExtensionMethods | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override AttributeUsageInfo GetAttributeUsageInfo() | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| public override string Name | ||
| { | ||
| get { return _name; } | ||
| } | ||
|
|
||
| // No additional name mangling since CompileExpression | ||
| // is providing an explicit type name. | ||
| internal override bool MangleName | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override IEnumerable<string> MemberNames | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override ImmutableArray<Symbol> GetMembers() | ||
| { | ||
| return _methods.Cast<MethodSymbol, Symbol>(); | ||
| } | ||
|
|
||
| public override ImmutableArray<Symbol> GetMembers(string name) | ||
| { | ||
| // Should not be requesting generated members | ||
| // by name other than constructors. | ||
| Debug.Assert((name == WellKnownMemberNames.InstanceConstructorName) || (name == WellKnownMemberNames.StaticConstructorName)); | ||
| return this.GetMembers().WhereAsArray(m => m.Name == name); | ||
| } | ||
|
|
||
| public override ImmutableArray<NamedTypeSymbol> GetTypeMembers() | ||
| { | ||
| return ImmutableArray<NamedTypeSymbol>.Empty; | ||
| } | ||
|
|
||
| public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(string name) | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(string name, int arity) | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| public override Accessibility DeclaredAccessibility | ||
| { | ||
| get { return Accessibility.Internal; } | ||
| } | ||
|
|
||
| internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers() | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers(string name) | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| internal override NamedTypeSymbol GetDeclaredBaseType(ConsList<Symbol> basesBeingResolved) | ||
| { | ||
| return _baseType; | ||
| } | ||
|
|
||
| internal override ImmutableArray<NamedTypeSymbol> GetDeclaredInterfaces(ConsList<Symbol> basesBeingResolved) | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| internal override bool HasSpecialName | ||
| { | ||
| get { return true; } | ||
| } | ||
|
|
||
| internal override bool IsComImport | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override bool IsWindowsRuntimeImport | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override bool ShouldAddWinRTMembers | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override bool IsSerializable | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override TypeLayout Layout | ||
| { | ||
| get { return default(TypeLayout); } | ||
| } | ||
|
|
||
| internal override System.Runtime.InteropServices.CharSet MarshallingCharSet | ||
| { | ||
| get { return System.Runtime.InteropServices.CharSet.Ansi; } | ||
| } | ||
|
|
||
| internal override bool HasDeclarativeSecurity | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override IEnumerable<Cci.SecurityAttribute> GetSecurityInformation() | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| internal override ImmutableArray<string> GetAppliedConditionalSymbols() | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics | ||
| { | ||
| get { return _baseType; } | ||
| } | ||
|
|
||
| internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList<Symbol> basesBeingResolved) | ||
| { | ||
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| public override TypeKind TypeKind | ||
| { | ||
| get { return TypeKind.Class; } | ||
| } | ||
|
|
||
| public override NamedTypeSymbol ContainingType | ||
| { | ||
| get { return null; } | ||
| } | ||
|
|
||
| public override Symbol ContainingSymbol | ||
| { | ||
| get { return _container; } | ||
| } | ||
|
|
||
| public override ImmutableArray<Location> Locations | ||
| { | ||
| get { return ImmutableArray<Location>.Empty; } | ||
| } | ||
|
|
||
| public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences | ||
| { | ||
| get { return ImmutableArray<SyntaxReference>.Empty; } | ||
| } | ||
|
|
||
| public override bool IsStatic | ||
| { | ||
| get { return true; } | ||
| } | ||
|
|
||
| public override bool IsAbstract | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override bool IsSealed | ||
| { | ||
| get { return true; } | ||
| } | ||
|
|
||
| internal override ObsoleteAttributeData ObsoleteAttributeData | ||
| { | ||
| get { return null; } | ||
| } | ||
|
|
||
| internal override bool IsInterface | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal delegate PlaceholderMethodSymbol CreateSynthesizedMethod(EENamedTypeSymbol container, string methodName, CSharpSyntaxNode syntax); | ||
|
|
||
| // Not thread-safe. | ||
| internal PlaceholderMethodSymbol GetOrAddSynthesizedMethod(string methodName, CreateSynthesizedMethod factory) | ||
| { | ||
| #if DEBUG | ||
| Debug.Assert(!_sealed); | ||
| #endif | ||
| if (_lazySynthesizedMethods == null) | ||
| { | ||
| _lazySynthesizedMethods = new Dictionary<string, PlaceholderMethodSymbol>(); | ||
| } | ||
| PlaceholderMethodSymbol method; | ||
| if (!_lazySynthesizedMethods.TryGetValue(methodName, out method)) | ||
| { | ||
| method = factory(this, methodName, _syntax); | ||
| Debug.Assert((object)method != null); | ||
| Debug.Assert(method.Name == methodName); | ||
| _lazySynthesizedMethods.Add(methodName, method); | ||
| } | ||
| return method; | ||
| } | ||
|
|
||
| [Conditional("DEBUG")] | ||
| internal static void VerifyTypeParameters(Symbol container, ImmutableArray<TypeParameterSymbol> typeParameters) | ||
| { | ||
| for (int i = 0; i < typeParameters.Length; i++) | ||
| { | ||
| var typeParameter = typeParameters[i]; | ||
| Debug.Assert((object)typeParameter.ContainingSymbol == (object)container); | ||
| Debug.Assert(typeParameter.Ordinal == i); | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Immutable; | ||
| using System.Diagnostics; | ||
| using System.Threading; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Roslyn.Utilities; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class EETypeParameterSymbol : TypeParameterSymbol | ||
| { | ||
| private readonly Symbol _container; | ||
| private readonly TypeParameterSymbol _sourceTypeParameter; | ||
| private readonly int _ordinal; | ||
| private readonly Func<TypeMap> _getTypeMap; | ||
| private TypeMap _lazyTypeMap; | ||
|
|
||
| public EETypeParameterSymbol( | ||
| Symbol container, | ||
| TypeParameterSymbol sourceTypeParameter, | ||
| int ordinal, | ||
| Func<TypeMap> getTypeMap) | ||
| { | ||
| Debug.Assert((container.Kind == SymbolKind.NamedType) || (container.Kind == SymbolKind.Method)); | ||
| _container = container; | ||
| _sourceTypeParameter = sourceTypeParameter; | ||
| _ordinal = ordinal; | ||
| _getTypeMap = getTypeMap; | ||
| } | ||
|
|
||
| public override Symbol ContainingSymbol | ||
| { | ||
| get { return _container; } | ||
| } | ||
|
|
||
| public override string Name | ||
| { | ||
| get { return _sourceTypeParameter.Name; } | ||
| } | ||
|
|
||
| public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override bool HasConstructorConstraint | ||
| { | ||
| get { return _sourceTypeParameter.HasConstructorConstraint; } | ||
| } | ||
|
|
||
| public override bool HasReferenceTypeConstraint | ||
| { | ||
| get { return _sourceTypeParameter.HasReferenceTypeConstraint; } | ||
| } | ||
|
|
||
| public override bool HasValueTypeConstraint | ||
| { | ||
| get { return _sourceTypeParameter.HasValueTypeConstraint; } | ||
| } | ||
|
|
||
| public override ImmutableArray<Location> Locations | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override int Ordinal | ||
| { | ||
| get { return _ordinal; } | ||
| } | ||
|
|
||
| public override TypeParameterKind TypeParameterKind | ||
| { | ||
| get { throw ExceptionUtilities.Unreachable; } | ||
| } | ||
|
|
||
| public override VarianceKind Variance | ||
| { | ||
| get { return _sourceTypeParameter.Variance; } | ||
| } | ||
|
|
||
| public override bool IsImplicitlyDeclared | ||
| { | ||
| get { return true; } | ||
| } | ||
|
|
||
| internal override void EnsureAllConstraintsAreResolved() | ||
| { | ||
| _sourceTypeParameter.EnsureAllConstraintsAreResolved(); | ||
| } | ||
|
|
||
| internal override ImmutableArray<TypeSymbol> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress) | ||
| { | ||
| var constraintTypes = _sourceTypeParameter.GetConstraintTypes(inProgress); | ||
|
|
||
| if (constraintTypes.IsEmpty) | ||
| { | ||
| return constraintTypes; | ||
| } | ||
|
|
||
| // Remap constraints from sourceTypeParameter since constraints | ||
| // may be defined in terms of other type parameters. | ||
| return this.TypeMap.SubstituteTypes(constraintTypes); | ||
| } | ||
|
|
||
| internal override TypeSymbol GetDeducedBaseType(ConsList<TypeParameterSymbol> inProgress) | ||
| { | ||
| var type = _sourceTypeParameter.GetDeducedBaseType(inProgress); | ||
| return this.TypeMap.SubstituteType(type); | ||
| } | ||
|
|
||
| internal override NamedTypeSymbol GetEffectiveBaseClass(ConsList<TypeParameterSymbol> inProgress) | ||
| { | ||
| var type = _sourceTypeParameter.GetEffectiveBaseClass(inProgress); | ||
| return this.TypeMap.SubstituteNamedType(type); | ||
| } | ||
|
|
||
| internal override ImmutableArray<NamedTypeSymbol> GetInterfaces(ConsList<TypeParameterSymbol> inProgress) | ||
| { | ||
| var interfaces = _sourceTypeParameter.GetInterfaces(inProgress); | ||
| return this.TypeMap.SubstituteNamedTypes(Interfaces); | ||
| } | ||
|
|
||
| private TypeMap TypeMap | ||
| { | ||
| get | ||
| { | ||
| if (_lazyTypeMap == null) | ||
| { | ||
| Interlocked.CompareExchange(ref _lazyTypeMap, _getTypeMap(), null); | ||
| } | ||
| return _lazyTypeMap; | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| // Copyright (c) Microsoft. 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.Diagnostics; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class ExceptionLocalSymbol : PlaceholderLocalSymbol | ||
| { | ||
| internal ExceptionLocalSymbol(MethodSymbol method, string name, TypeSymbol type) : | ||
| base(method, name, type) | ||
| { | ||
| } | ||
|
|
||
| internal override bool IsWritable | ||
| { | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax) | ||
| { | ||
| Debug.Assert(this.Name == this.Name.ToLowerInvariant()); | ||
| var method = container.GetOrAddSynthesizedMethod( | ||
| this.Name, | ||
| (c, n, s) => | ||
| { | ||
| var returnType = compilation.GetWellKnownType(WellKnownType.System_Exception); | ||
| return new PlaceholderMethodSymbol( | ||
| c, | ||
| s, | ||
| n, | ||
| returnType, | ||
| m => ImmutableArray<ParameterSymbol>.Empty); | ||
| }); | ||
| var call = BoundCall.Synthesized(syntax, receiverOpt: null, method: method); | ||
| return ConvertToLocalType(compilation, call, this.Type); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| // Copyright (c) Microsoft. 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.Diagnostics; | ||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class ObjectAddressLocalSymbol : PlaceholderLocalSymbol | ||
| { | ||
| private readonly ulong _address; | ||
|
|
||
| internal ObjectAddressLocalSymbol(MethodSymbol method, string name, TypeSymbol type, ulong address) : | ||
| base(method, name, type) | ||
| { | ||
| Debug.Assert(type.SpecialType == SpecialType.System_Object); | ||
| _address = address; | ||
| } | ||
|
|
||
| internal override bool IsWritable | ||
| { | ||
| // Return true? | ||
| get { return false; } | ||
| } | ||
|
|
||
| internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax) | ||
| { | ||
| var method = container.GetOrAddSynthesizedMethod( | ||
| ExpressionCompilerConstants.GetObjectAtAddressMethodName, | ||
| (c, n, s) => | ||
| { | ||
| var parameterType = compilation.GetSpecialType(SpecialType.System_UInt64); | ||
| return new PlaceholderMethodSymbol( | ||
| c, | ||
| s, | ||
| n, | ||
| this.Type, | ||
| m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None))); | ||
| }); | ||
| var argument = new BoundLiteral( | ||
| syntax, | ||
| Microsoft.CodeAnalysis.ConstantValue.Create(_address), | ||
| method.Parameters[0].Type); | ||
| var call = BoundCall.Synthesized( | ||
| syntax, | ||
| receiverOpt: null, | ||
| method: method, | ||
| arguments: ImmutableArray.Create<BoundExpression>(argument)); | ||
| Debug.Assert(call.Type == this.Type); | ||
| return call; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
| using Microsoft.CodeAnalysis.ExpressionEvaluator; | ||
| using System.Collections.Immutable; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator | ||
| { | ||
| internal sealed class ObjectIdLocalSymbol : PlaceholderLocalSymbol | ||
| { | ||
| private readonly string _id; | ||
| private readonly bool _isWritable; | ||
|
|
||
| internal ObjectIdLocalSymbol(MethodSymbol method, TypeSymbol type, string id, bool isWritable) : | ||
| base(method, id, type) | ||
| { | ||
| _id = id; | ||
| _isWritable = isWritable; | ||
| } | ||
|
|
||
| internal override bool IsWritable | ||
| { | ||
| get { return _isWritable; } | ||
| } | ||
|
|
||
| internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax) | ||
| { | ||
| return RewriteLocalInternal(compilation, container, syntax, this); | ||
| } | ||
|
|
||
| internal static BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, LocalSymbol local) | ||
| { | ||
| return RewriteLocalInternal(compilation, container, syntax, local); | ||
| } | ||
|
|
||
| private static BoundExpression RewriteLocalInternal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, LocalSymbol local) | ||
| { | ||
| var parameterType = compilation.GetSpecialType(SpecialType.System_String); | ||
| var getValueMethod = container.GetOrAddSynthesizedMethod( | ||
| ExpressionCompilerConstants.GetVariableValueMethodName, | ||
| (c, n, s) => | ||
| { | ||
| var returnType = compilation.GetSpecialType(SpecialType.System_Object); | ||
| return new PlaceholderMethodSymbol( | ||
| c, | ||
| s, | ||
| n, | ||
| returnType, | ||
| m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None))); | ||
| }); | ||
| var getAddressMethod = container.GetOrAddSynthesizedMethod( | ||
| ExpressionCompilerConstants.GetVariableAddressMethodName, | ||
| (c, n, s) => | ||
| { | ||
| return new PlaceholderMethodSymbol( | ||
| c, | ||
| s, | ||
| n, | ||
| m => ImmutableArray.Create<TypeParameterSymbol>(new SimpleTypeParameterSymbol(m, 0, "<>T")), | ||
| m => m.TypeParameters[0], // return type is <>T& | ||
| m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None)), | ||
| returnValueIsByRef: true); | ||
| }); | ||
| return new BoundPseudoVariable( | ||
| syntax, | ||
| local, | ||
| new ObjectIdExpressions(compilation, getValueMethod, getAddressMethod), | ||
| local.Type); | ||
| } | ||
|
|
||
| private sealed class ObjectIdExpressions : PseudoVariableExpressions | ||
| { | ||
| private readonly CSharpCompilation _compilation; | ||
| private readonly MethodSymbol _getValueMethod; | ||
| private readonly MethodSymbol _getAddressMethod; | ||
|
|
||
| internal ObjectIdExpressions(CSharpCompilation compilation, MethodSymbol getValueMethod, MethodSymbol getAddressMethod) | ||
| { | ||
| _compilation = compilation; | ||
| _getValueMethod = getValueMethod; | ||
| _getAddressMethod = getAddressMethod; | ||
| } | ||
|
|
||
| internal override BoundExpression GetValue(BoundPseudoVariable variable) | ||
| { | ||
| var local = variable.LocalSymbol; | ||
| var expr = InvokeGetMethod(_getValueMethod, variable.Syntax, local.Name); | ||
| return ConvertToLocalType(_compilation, expr, local.Type); | ||
| } | ||
|
|
||
| internal override BoundExpression GetAddress(BoundPseudoVariable variable) | ||
| { | ||
| var local = variable.LocalSymbol; | ||
| return InvokeGetMethod(_getAddressMethod.Construct(local.Type), variable.Syntax, local.Name); | ||
| } | ||
|
|
||
| private static BoundExpression InvokeGetMethod(MethodSymbol method, CSharpSyntaxNode syntax, string name) | ||
| { | ||
| var argument = new BoundLiteral( | ||
| syntax, | ||
| Microsoft.CodeAnalysis.ConstantValue.Create(name), | ||
| method.Parameters[0].Type); | ||
| return BoundCall.Synthesized( | ||
| syntax, | ||
| receiverOpt: null, | ||
| method: method, | ||
| arguments: ImmutableArray.Create<BoundExpression>(argument)); | ||
| } | ||
| } | ||
| } | ||
| } |