提交 932bb7a8 编写于 作者: B Brett V. Forsgren 提交者: GitHub

Merge pull request #21578 from dotnet/merges/master-to-features/ioperation-20170817-070013

Merge master to features/ioperation
......@@ -31,3 +31,7 @@ How did we miss it? What tests are we adding to guard against it in the future?
**How was the bug found?**
(E.g. customer reported it vs. ad hoc testing)
**Test documentation updated?**
If this is a new non-compiler feature or a significant improvement to an existing feature, update https://github.com/dotnet/roslyn/wiki/Manual-Testing once you know which release it is targeting.
......@@ -35,9 +35,9 @@
<MicrosoftDiagnosticsRuntimeVersion>0.8.31-beta</MicrosoftDiagnosticsRuntimeVersion>
<MicrosoftDiagnosticsTracingTraceEventVersion>1.0.35</MicrosoftDiagnosticsTracingTraceEventVersion>
<MicrosoftDiaSymReaderVersion>1.2.0-beta1-62008-01</MicrosoftDiaSymReaderVersion>
<MicrosoftDiaSymReaderConverterXmlVersion>1.1.0-beta1-62008-01</MicrosoftDiaSymReaderConverterXmlVersion>
<MicrosoftDiaSymReaderConverterXmlVersion>1.1.0-beta1-62016-01</MicrosoftDiaSymReaderConverterXmlVersion>
<MicrosoftDiaSymReaderNativeVersion>1.7.0-private-25604</MicrosoftDiaSymReaderNativeVersion>
<MicrosoftDiaSymReaderPortablePdbVersion>1.3.0-beta1-62008-01</MicrosoftDiaSymReaderPortablePdbVersion>
<MicrosoftDiaSymReaderPortablePdbVersion>1.4.0-beta1-62016-01</MicrosoftDiaSymReaderPortablePdbVersion>
<MicrosoftDotNetIBCMerge>4.7.2-alpha-00001</MicrosoftDotNetIBCMerge>
<MicrosoftDotNetVersionToolsVersion>1.0.27-prerelease-01811-02</MicrosoftDotNetVersionToolsVersion>
<MicrosoftIdentityModelClientsActiveDirectoryVersion>3.13.8</MicrosoftIdentityModelClientsActiveDirectoryVersion>
......
......@@ -660,7 +660,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
var diagnosticsThisMethod = DiagnosticBag.GetInstance();
var method = methodWithBody.Method;
var lambda = method as SynthesizedLambdaMethod;
var lambda = method as SynthesizedClosureMethod;
var variableSlotAllocatorOpt = ((object)lambda != null) ?
_moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(lambda, lambda.TopLevelMethod, diagnosticsThisMethod) :
_moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method, diagnosticsThisMethod);
......
......@@ -112,6 +112,11 @@ public sealed class Closure
/// </summary>
public readonly MethodSymbol OriginalMethodSymbol;
/// <summary>
/// Syntax for the block of the nested function.
/// </summary>
public readonly SyntaxReference BlockSyntax;
public readonly PooledHashSet<Symbol> CapturedVariables = PooledHashSet<Symbol>.GetInstance();
public readonly ArrayBuilder<ClosureEnvironment> CapturedEnvironments
......@@ -136,10 +141,13 @@ public bool CapturesThis
}
}
public Closure(MethodSymbol symbol)
public SynthesizedClosureMethod SynthesizedLoweredMethod;
public Closure(MethodSymbol symbol, SyntaxReference blockSyntax)
{
Debug.Assert(symbol != null);
OriginalMethodSymbol = symbol;
BlockSyntax = blockSyntax;
}
public void Free()
......@@ -154,9 +162,8 @@ public sealed class ClosureEnvironment
public readonly SetWithInsertionOrder<Symbol> CapturedVariables;
/// <summary>
/// Represents a <see cref="SynthesizedEnvironment"/> that had its environment
/// pointer (a local pointing to the environment) captured like a captured
/// variable. Assigned in
/// True if this environment captures a reference to a class environment
/// declared in a higher scope. Assigned by
/// <see cref="ComputeLambdaScopesAndFrameCaptures(ParameterSymbol)"/>
/// </summary>
public bool CapturesParent;
......@@ -435,7 +442,7 @@ private BoundNode VisitClosure(MethodSymbol closureSymbol, BoundBlock body)
// Closure is declared (lives) in the parent scope, but its
// variables are in a nested scope
var closure = new Closure(closureSymbol);
var closure = new Closure(closureSymbol, body.Syntax.GetReference());
_currentScope.Closures.Add(closure);
var oldClosure = _currentClosure;
......
// 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.PooledObjects;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed partial class LambdaRewriter : MethodToClassRewriter
{
/// <summary>
/// This pass is expected to run on partially lowered methods
/// previously containing one or more local functions. At this
/// point all local functions should have been rewritten into
/// proper closure classes and have frames and proxies generated
/// for them.
///
/// The only thing left is to visit all "references" to local functions
/// and rewrite them to be references to the rewritten form.
/// </summary>
private sealed class LocalFunctionReferenceRewriter : BoundTreeRewriterWithStackGuard
{
private readonly LambdaRewriter _lambdaRewriter;
public LocalFunctionReferenceRewriter(LambdaRewriter lambdaRewriter)
{
_lambdaRewriter = lambdaRewriter;
}
public override BoundNode Visit(BoundNode node)
{
var partiallyLowered = node as PartiallyLoweredLocalFunctionReference;
if (partiallyLowered != null)
{
var underlying = partiallyLowered.UnderlyingNode;
Debug.Assert(underlying.Kind == BoundKind.Call ||
underlying.Kind == BoundKind.DelegateCreationExpression ||
underlying.Kind == BoundKind.Conversion);
var oldProxies = _lambdaRewriter.proxies;
_lambdaRewriter.proxies = partiallyLowered.Proxies;
var result = base.Visit(underlying);
_lambdaRewriter.proxies = oldProxies;
return result;
}
return base.Visit(node);
}
public override BoundNode VisitCall(BoundCall node)
{
if (node.Method.MethodKind == MethodKind.LocalFunction)
{
BoundExpression receiver;
MethodSymbol method;
var arguments = node.Arguments;
_lambdaRewriter.RemapLocalFunction(
node.Syntax,
node.Method,
out receiver,
out method,
ref arguments);
node = node.Update(receiver, method, arguments);
}
return base.VisitCall(node);
}
public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationExpression node)
{
if (node.MethodOpt?.MethodKind == MethodKind.LocalFunction)
{
BoundExpression receiver;
MethodSymbol method;
var arguments = default(ImmutableArray<BoundExpression>);
_lambdaRewriter.RemapLocalFunction(
node.Syntax,
node.MethodOpt,
out receiver,
out method,
ref arguments);
return new BoundDelegateCreationExpression(
node.Syntax, receiver, method, isExtensionMethod: false, type: node.Type);
}
return base.VisitDelegateCreationExpression(node);
}
}
/// <summary>
/// Visit all references to local functions (calls, delegate
/// conversions, delegate creations) and rewrite them to point
/// to the rewritten local function method instead of the original.
/// </summary>
public BoundStatement RewriteLocalFunctionReferences(BoundStatement loweredBody)
{
var rewriter = new LocalFunctionReferenceRewriter(this);
Debug.Assert(_currentMethod == _topLevelMethod);
// Visit the body first since the state is already set
// for the top-level method
var newBody = (BoundStatement)rewriter.Visit(loweredBody);
// Visit all the rewritten methods as well
var synthesizedMethods = _synthesizedMethods;
if (synthesizedMethods != null)
{
var newMethods = ArrayBuilder<TypeCompilationState.MethodWithBody>.GetInstance(
synthesizedMethods.Count);
foreach (var oldMethod in synthesizedMethods)
{
var synthesizedLambda = oldMethod.Method as SynthesizedLambdaMethod;
if (synthesizedLambda == null)
{
// The only methods synthesized by the rewriter should
// be lowered closures and frame constructors
Debug.Assert(oldMethod.Method.MethodKind == MethodKind.Constructor ||
oldMethod.Method.MethodKind == MethodKind.StaticConstructor);
newMethods.Add(oldMethod);
continue;
}
_currentMethod = synthesizedLambda;
var closureKind = synthesizedLambda.ClosureKind;
if (closureKind == ClosureKind.Static || closureKind == ClosureKind.Singleton)
{
// no link from a static lambda to its container
_innermostFramePointer = _currentFrameThis = null;
}
else
{
_currentFrameThis = synthesizedLambda.ThisParameter;
_innermostFramePointer = null;
_framePointers.TryGetValue(synthesizedLambda.ContainingType, out _innermostFramePointer);
}
var containerAsFrame = synthesizedLambda.ContainingType as SynthesizedClosureEnvironment;
// Includes type parameters from the containing type iff
// the containing type is a frame. If it is a frame then
// the type parameters are captured, meaning that the
// type parameters should be included.
// If it is not a frame then the local function is being
// directly lowered into the method's containing type and
// the parameters should never be substituted.
_currentTypeParameters = containerAsFrame?.TypeParameters.Concat(synthesizedLambda.TypeParameters)
?? synthesizedLambda.TypeParameters;
_currentLambdaBodyTypeMap = synthesizedLambda.TypeMap;
var rewrittenBody = (BoundStatement)rewriter.Visit(oldMethod.Body);
var newMethod = new TypeCompilationState.MethodWithBody(
synthesizedLambda, rewrittenBody, oldMethod.ImportChainOpt);
newMethods.Add(newMethod);
}
_synthesizedMethods = newMethods;
synthesizedMethods.Free();
}
return newBody;
}
/// <summary>
/// Rewrites a reference to an unlowered local function to the newly
/// lowered local function.
/// </summary>
private void RemapLocalFunction(
SyntaxNode syntax,
MethodSymbol localFunc,
out BoundExpression receiver,
out MethodSymbol method,
ref ImmutableArray<BoundExpression> parameters)
{
Debug.Assert(localFunc.MethodKind == MethodKind.LocalFunction);
var mappedLocalFunction = _localFunctionMap[(LocalFunctionSymbol)localFunc.OriginalDefinition];
var loweredSymbol = mappedLocalFunction.Symbol;
// If the local function captured variables then they will be stored
// in frames and the frames need to be passed as extra parameters.
var frameCount = loweredSymbol.ExtraSynthesizedParameterCount;
if (frameCount != 0)
{
Debug.Assert(!parameters.IsDefault);
// Build a new list of parameters to pass to the local function
// call that includes any necessary capture frames
var parametersBuilder = ArrayBuilder<BoundExpression>.GetInstance();
parametersBuilder.AddRange(parameters);
var start = loweredSymbol.ParameterCount - frameCount;
for (int i = start; i < loweredSymbol.ParameterCount; i++)
{
// will always be a LambdaFrame, it's always a capture frame
var frameType = (NamedTypeSymbol)loweredSymbol.Parameters[i].Type.OriginalDefinition;
Debug.Assert(frameType is SynthesizedClosureEnvironment);
if (frameType.Arity > 0)
{
var typeParameters = ((SynthesizedClosureEnvironment)frameType).ConstructedFromTypeParameters;
Debug.Assert(typeParameters.Length == frameType.Arity);
var subst = this.TypeMap.SubstituteTypeParameters(typeParameters);
frameType = frameType.Construct(subst);
}
var frame = FrameOfType(syntax, frameType);
parametersBuilder.Add(frame);
}
parameters = parametersBuilder.ToImmutableAndFree();
}
method = loweredSymbol;
NamedTypeSymbol constructedFrame;
RemapLambdaOrLocalFunction(syntax,
localFunc,
SubstituteTypeArguments(localFunc.TypeArguments),
mappedLocalFunction.ClosureKind,
ref method,
out receiver,
out constructedFrame);
}
/// <summary>
/// Substitutes references from old type arguments to new type arguments
/// in the lowered methods.
/// </summary>
/// <example>
/// Consider the following method:
/// void M() {
/// void L&lt;T&gt;(T t) => Console.Write(t);
/// L("A");
/// }
///
/// In this example, L&lt;T&gt; is a local function that will be
/// lowered into its own method and the type parameter T will be
/// alpha renamed to something else (let's call it T'). In this case,
/// all references to the original type parameter T in L must be
/// rewritten to the renamed parameter, T'.
/// </example>
private ImmutableArray<TypeSymbol> SubstituteTypeArguments(ImmutableArray<TypeSymbol> typeArguments)
{
Debug.Assert(!typeArguments.IsDefault);
if (typeArguments.IsEmpty)
{
return typeArguments;
}
// We must perform this process repeatedly as local
// functions may nest inside one another and capture type
// parameters from the enclosing local functions. Each
// iteration of nesting will cause alpha-renaming of the captured
// parameters, meaning that we must replace until there are no
// more alpha-rename mappings.
//
// The method symbol references are different from all other
// substituted types in this context because the method symbol in
// local function references is not rewritten until all local
// functions have already been lowered. Everything else is rewritten
// by the visitors as the definition is lowered. This means that
// only one substition happens per lowering, but we need to do
// N substitutions all at once, where N is the number of lowerings.
var builder = ArrayBuilder<TypeSymbol>.GetInstance();
foreach (var typeArg in typeArguments)
{
TypeSymbol oldTypeArg;
TypeSymbol newTypeArg = typeArg;
do
{
oldTypeArg = newTypeArg;
newTypeArg = this.TypeMap.SubstituteType(typeArg).Type;
}
while (oldTypeArg != newTypeArg);
Debug.Assert((object)oldTypeArg == newTypeArg);
builder.Add(newTypeArg);
}
return builder.ToImmutableAndFree();
}
}
}
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Semantics;
namespace Microsoft.CodeAnalysis.CSharp
{
/// <summary>
/// This represents a partially lowered local function reference (e.g.,
/// a local function call or delegate conversion) with relevant proxies
/// attached. It will later be rewritten by the
/// <see cref="LambdaRewriter.LocalFunctionReferenceRewriter"/> into a
/// proper call.
/// </summary>
internal class PartiallyLoweredLocalFunctionReference : BoundExpression
{
private const BoundKind s_privateKind = (BoundKind)byte.MaxValue;
public BoundExpression UnderlyingNode { get; }
public Dictionary<Symbol, CapturedSymbolReplacement> Proxies { get; }
public PartiallyLoweredLocalFunctionReference(
BoundExpression underlying,
Dictionary<Symbol, CapturedSymbolReplacement> proxies)
: base(s_privateKind, underlying.Syntax, underlying.Type)
{
UnderlyingNode = underlying;
Proxies = proxies;
}
public override BoundNode Accept(BoundTreeVisitor visitor) =>
visitor.Visit(this);
}
}
......@@ -12,51 +12,62 @@ namespace Microsoft.CodeAnalysis.CSharp
/// <summary>
/// A method that results from the translation of a single lambda expression.
/// </summary>
internal sealed class SynthesizedLambdaMethod : SynthesizedMethodBaseSymbol, ISynthesizedMethodBodyImplementationSymbol
internal sealed class SynthesizedClosureMethod : SynthesizedMethodBaseSymbol, ISynthesizedMethodBodyImplementationSymbol
{
private readonly MethodSymbol _topLevelMethod;
private readonly ImmutableArray<NamedTypeSymbol> _structEnvironments;
internal SynthesizedLambdaMethod(
internal readonly DebugId LambdaId;
internal SynthesizedClosureMethod(
NamedTypeSymbol containingType,
ImmutableArray<SynthesizedClosureEnvironment> structEnvironments,
ClosureKind closureKind,
MethodSymbol topLevelMethod,
DebugId topLevelMethodId,
IBoundLambdaOrFunction lambdaNode,
MethodSymbol originalMethod,
SyntaxReference blockSyntax,
DebugId lambdaId)
: base(containingType,
lambdaNode.Symbol,
originalMethod,
null,
lambdaNode.Syntax.SyntaxTree.GetReference(lambdaNode.Body.Syntax),
lambdaNode.Syntax.GetLocation(),
lambdaNode is BoundLocalFunctionStatement ?
MakeName(topLevelMethod.Name, lambdaNode.Symbol.Name, topLevelMethodId, closureKind, lambdaId) :
MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId),
(closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal)
| (closureKind == ClosureKind.Static ? DeclarationModifiers.Static : 0)
| (lambdaNode.Symbol.IsAsync ? DeclarationModifiers.Async : 0))
blockSyntax,
originalMethod.DeclaringSyntaxReferences[0].GetLocation(),
originalMethod is LocalFunctionSymbol
? MakeName(topLevelMethod.Name, originalMethod.Name, topLevelMethodId, closureKind, lambdaId)
: MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId),
MakeDeclarationModifiers(closureKind, originalMethod))
{
_topLevelMethod = topLevelMethod;
ClosureKind = closureKind;
LambdaId = lambdaId;
TypeMap typeMap;
ImmutableArray<TypeParameterSymbol> typeParameters;
ImmutableArray<TypeParameterSymbol> constructedFromTypeParameters;
SynthesizedClosureEnvironment lambdaFrame;
lambdaFrame = this.ContainingType as SynthesizedClosureEnvironment;
var lambdaFrame = ContainingType as SynthesizedClosureEnvironment;
switch (closureKind)
{
case ClosureKind.Singleton: // all type parameters on method (except the top level method's)
case ClosureKind.General: // only lambda's type parameters on method (rest on class)
Debug.Assert(lambdaFrame != null);
typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, lambdaFrame.OriginalContainingMethodOpt);
typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(
originalMethod,
this,
out typeParameters,
out constructedFromTypeParameters,
lambdaFrame.OriginalContainingMethodOpt);
break;
case ClosureKind.ThisOnly: // all type parameters on method
case ClosureKind.Static:
Debug.Assert(lambdaFrame == null);
typeMap = TypeMap.Empty.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, null);
typeMap = TypeMap.Empty.WithConcatAlphaRename(
originalMethod,
this,
out typeParameters,
out constructedFromTypeParameters,
stopAt: null);
break;
default:
throw ExceptionUtilities.UnexpectedValue(closureKind);
......@@ -90,6 +101,23 @@ internal sealed class SynthesizedLambdaMethod : SynthesizedMethodBaseSymbol, ISy
AssignTypeMapAndTypeParameters(typeMap, typeParameters);
}
private static DeclarationModifiers MakeDeclarationModifiers(ClosureKind closureKind, MethodSymbol originalMethod)
{
var mods = closureKind == ClosureKind.ThisOnly ? DeclarationModifiers.Private : DeclarationModifiers.Internal;
if (closureKind == ClosureKind.Static)
{
mods |= DeclarationModifiers.Static;
}
if (originalMethod.IsAsync)
{
mods |= DeclarationModifiers.Async;
}
return mods;
}
private static string MakeName(string topLevelMethodName, string localFunctionName, DebugId topLevelMethodId, ClosureKind closureKind, DebugId lambdaId)
{
return GeneratedNames.MakeLocalFunctionName(
......
......@@ -4889,15 +4889,15 @@ .maxstack 3
IL_0018: ldc.i4.1
IL_0019: callvirt ""System.Func<int> System.Func<int, System.Func<int>>.Invoke(int)""
IL_001e: pop
IL_001f: ldsfld ""System.Func<int, System.Func<int>> Program.<>c.<>9__1_2""
IL_001f: ldsfld ""System.Func<int, System.Func<int>> Program.<>c.<>9__1_1""
IL_0024: dup
IL_0025: brtrue.s IL_003e
IL_0027: pop
IL_0028: ldsfld ""Program.<>c Program.<>c.<>9""
IL_002d: ldftn ""System.Func<int> Program.<>c.<Test>b__1_2(int)""
IL_002d: ldftn ""System.Func<int> Program.<>c.<Test>b__1_1(int)""
IL_0033: newobj ""System.Func<int, System.Func<int>>..ctor(object, System.IntPtr)""
IL_0038: dup
IL_0039: stsfld ""System.Func<int, System.Func<int>> Program.<>c.<>9__1_2""
IL_0039: stsfld ""System.Func<int, System.Func<int>> Program.<>c.<>9__1_1""
IL_003e: ldc.i4.1
IL_003f: callvirt ""System.Func<int> System.Func<int, System.Func<int>>.Invoke(int)""
IL_0044: pop
......@@ -4905,7 +4905,7 @@ .maxstack 3
}
");
verifier.VerifyIL("Program.<>c.<Test>b__1_2(int)",
verifier.VerifyIL("Program.<>c.<Test>b__1_1(int)",
@"
{
// Code size 44 (0x2c)
......@@ -4943,17 +4943,17 @@ .locals init (System.Func<int> V_0)
IL_0004: ldc.i4.s 123
IL_0006: call ""void System.Console.WriteLine(int)""
IL_000b: ldarg.0
IL_000c: ldfld ""System.Func<int> Program.<>c__DisplayClass1_0.<>9__1""
IL_000c: ldfld ""System.Func<int> Program.<>c__DisplayClass1_0.<>9__2""
IL_0011: dup
IL_0012: brtrue.s IL_002a
IL_0014: pop
IL_0015: ldarg.0
IL_0016: ldarg.0
IL_0017: ldftn ""int Program.<>c__DisplayClass1_0.<Test>b__1()""
IL_0017: ldftn ""int Program.<>c__DisplayClass1_0.<Test>b__2()""
IL_001d: newobj ""System.Func<int>..ctor(object, System.IntPtr)""
IL_0022: dup
IL_0023: stloc.0
IL_0024: stfld ""System.Func<int> Program.<>c__DisplayClass1_0.<>9__1""
IL_0024: stfld ""System.Func<int> Program.<>c__DisplayClass1_0.<>9__2""
IL_0029: ldloc.0
IL_002a: ret
IL_002b: ldnull
......
......@@ -274,23 +274,23 @@ .maxstack 2
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call ""void C.<M>g__L32_2(ref C.<>c__DisplayClass2_0)""
IL_0002: call ""void C.<M>g__L32_3(ref C.<>c__DisplayClass2_0)""
IL_0007: ret
}");
// Skip some... L5
verifier.VerifyIL("C.<M>g__L52_4(ref C.<>c__DisplayClass2_0, ref C.<>c__DisplayClass2_1)", @"
verifier.VerifyIL("C.<M>g__L52_5(ref C.<>c__DisplayClass2_0, ref C.<>c__DisplayClass2_1)", @"
{
// Code size 10 (0xa)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: call ""int C.<M>g__L62_5(ref C.<>c__DisplayClass2_0, ref C.<>c__DisplayClass2_1)""
IL_0003: call ""int C.<M>g__L62_6(ref C.<>c__DisplayClass2_0, ref C.<>c__DisplayClass2_1)""
IL_0008: pop
IL_0009: ret
}");
// L6
verifier.VerifyIL("C.<M>g__L62_5(ref C.<>c__DisplayClass2_0, ref C.<>c__DisplayClass2_1)", @"
verifier.VerifyIL("C.<M>g__L62_6(ref C.<>c__DisplayClass2_0, ref C.<>c__DisplayClass2_1)", @"
{
// Code size 25 (0x19)
.maxstack 4
......
......@@ -549,10 +549,10 @@ void F()
// no new synthesized members generated (with #1 in names):
diff1.VerifySynthesizedMembers(
"C: {<F>b__1_2, <F>b__1_4, <>c__DisplayClass1_0, <>c__DisplayClass1_1, <>c}",
"C.<>c: {<>9__1_0, <>9__1_1, <>9__1_6, <F>b__1_0, <F>b__1_1, <F>b__1_6}",
"C.<>c__DisplayClass1_0: {<>h__TransparentIdentifier0, <F>b__3}",
"C.<>c__DisplayClass1_1: {<>h__TransparentIdentifier0, <F>b__5}",
"C.<>c__DisplayClass1_1: {<>h__TransparentIdentifier0, <F>b__6}",
"C.<>c__DisplayClass1_0: {<>h__TransparentIdentifier0, <F>b__5}",
"C.<>c: {<>9__1_0, <>9__1_1, <>9__1_4, <F>b__1_0, <F>b__1_1, <F>b__1_4}",
"C: {<F>b__1_2, <F>b__1_3, <>c__DisplayClass1_0, <>c__DisplayClass1_1, <>c}",
"<>f__AnonymousType0<<a>j__TPar, <b>j__TPar>: {Equals, GetHashCode, ToString}");
var md1 = diff1.GetMetadata();
......@@ -632,10 +632,10 @@ void F()
// no new synthesized members generated (with #1 in names):
diff1.VerifySynthesizedMembers(
"C: {<F>b__1_0, <>c__DisplayClass1_0, <>c}",
"C.<>c: {<>9__1_2, <F>b__1_2}",
"C.<>c__DisplayClass1_0: {a, <F>b__1}",
"<>f__AnonymousType0<<a>j__TPar, <b>j__TPar>: {Equals, GetHashCode, ToString}");
"C.<>c: {<>9__1_1, <F>b__1_1}",
"<>f__AnonymousType0<<a>j__TPar, <b>j__TPar>: {Equals, GetHashCode, ToString}",
"C.<>c__DisplayClass1_0: {a, <F>b__2}",
"C: {<F>b__1_0, <>c__DisplayClass1_0, <>c}");
var md1 = diff1.GetMetadata();
var reader1 = md1.Reader;
......@@ -714,10 +714,10 @@ public void F()
// no new synthesized members generated (with #1 in names):
diff1.VerifySynthesizedMembers(
"C.<>c__DisplayClass1_2: {a, b, <F>b__5}",
"C.<>c__DisplayClass1_1: {b, <F>b__3}",
"C: {<F>b__1_0, <F>b__1_2, <F>b__1_4, <>c__DisplayClass1_0, <>c__DisplayClass1_1, <>c__DisplayClass1_2}",
"C.<>c__DisplayClass1_0: {a, <F>b__1}");
"C.<>c__DisplayClass1_1: {b, <F>b__4}",
"C.<>c__DisplayClass1_2: {a, b, <F>b__5}",
"C.<>c__DisplayClass1_0: {a, <F>b__3}",
"C: {<F>b__1_0, <F>b__1_1, <F>b__1_2, <>c__DisplayClass1_0, <>c__DisplayClass1_1, <>c__DisplayClass1_2}");
var md1 = diff1.GetMetadata();
var reader1 = md1.Reader;
......
......@@ -6599,5 +6599,35 @@ private static Symbol[] GetCrefOriginalDefinitions(SemanticModel model, IEnumera
{
return crefs.Select(syntax => model.GetSymbolInfo(syntax).Symbol).Select(symbol => (object)symbol == null ? null : (Symbol)symbol.OriginalDefinition).ToArray();
}
[Fact]
[WorkItem(410932, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=410932")]
public void LookupOnCrefTypeParameter()
{
var source = @"
class Test
{
T F<T>()
{
}
/// <summary>
/// <see cref=""F{U}()""/>
/// </summary>
void S()
{ }
}
";
var compilation = CreateCompilationWithMscorlibAndDocumentationComments(source);
var tree = compilation.SyntaxTrees[0];
var model = compilation.GetSemanticModel(tree);
var crefSyntax = (NameMemberCrefSyntax)GetCrefSyntaxes(compilation).Single();
var name = ((GenericNameSyntax)crefSyntax.Name).TypeArgumentList.Arguments.Single();
Assert.Equal("U", name.ToString());
var typeParameter = (TypeParameterSymbol)model.GetSymbolInfo(name).Symbol;
Assert.Empty(model.LookupSymbols(name.SpanStart, typeParameter, "GetAwaiter"));
}
}
}
......@@ -1995,6 +1995,10 @@ ExitForFor:
typeParameter As TypeParameterSymbol,
options As LookupOptions,
binder As Binder)
If typeParameter.TypeParameterKind = TypeParameterKind.Cref Then
Return
End If
AddLookupSymbolsInfoInTypeParameterNoExtensionMethods(nameSet, typeParameter, options, binder)
' Search for extension methods.
......
......@@ -12410,5 +12410,40 @@ DashDash
stringMapper:=Function(o) StringReplace(o, System.IO.Path.Combine(TestHelpers.AsXmlCommentText(path), "- - -.xml"), "**FILE**"), ensureEnglishUICulture:=True)
End Sub
<Fact>
<WorkItem(410932, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=410932")>
Public Sub LookupOnCrefTypeParameter()
Dim sources =
<compilation>
<file name="a.vb">
<![CDATA[
Public Class Test
Function F(Of T)() As T
End Function
''' <summary>
''' <see cref="F(Of U)()"/>
''' </summary>
Public Sub S()
End Sub
End Class
]]>
</file>
</compilation>
Dim compilation = CreateCompilationWithMscorlibAndVBRuntime(
sources,
options:=TestOptions.ReleaseDll)
Dim tree = compilation.SyntaxTrees(0)
Dim model = compilation.GetSemanticModel(tree)
Dim name = FindNodesOfTypeFromText(Of NameSyntax)(tree, "U").Single()
Dim typeParameter = DirectCast(model.GetSymbolInfo(name).Symbol, TypeParameterSymbol)
Assert.Empty(model.LookupSymbols(name.SpanStart, typeParameter, "GetAwaiter"))
End Sub
End Class
End Namespace
......@@ -2058,6 +2058,48 @@ class Program
await VerifyItemExistsAsync(markup, "CompareTo");
}
[WorkItem(21596, "https://github.com/dotnet/roslyn/issues/21596")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task AmbiguityBetweenExpressionAndLocalFunctionReturnType()
{
var markup = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
AwaitTest test = new AwaitTest();
test.Test1().Wait();
}
}
class AwaitTest
{
List<string> stringList = new List<string>();
public async Task<bool> Test1()
{
stringList.$$
await Test2();
return true;
}
public async Task<bool> Test2()
{
return true;
}
}";
await VerifyItemExistsAsync(markup, "Add");
}
[WorkItem(540750, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540750")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task CompletionAfterNewInScript()
......
......@@ -161,7 +161,7 @@ public void ErrorSpans_TopLevel()
}
";
TestSpans(source, kind => TopSyntaxComparer.HasLabel(kind, ignoreVariableDeclarations: false));
TestSpans(source, kind => TopSyntaxComparer.HasLabel(kind));
}
[Fact]
......@@ -227,7 +227,7 @@ void M()
public void ErrorSpansAllKinds()
{
TestErrorSpansAllKinds(StatementSyntaxComparer.IgnoreLabeledChild);
TestErrorSpansAllKinds(kind => TopSyntaxComparer.HasLabel(kind, ignoreVariableDeclarations: false));
TestErrorSpansAllKinds(kind => TopSyntaxComparer.HasLabel(kind));
}
[Fact]
......
......@@ -3210,6 +3210,28 @@ static void Main(string[] args)
edits.VerifyRudeDiagnostics();
}
[Fact]
public void MethodUpdate_LocalFunctionsParameterRefnessInBody()
{
var src1 = @"class C { public void M(int a) { void f(ref int b) => b = 1; } }";
var src2 = @"class C { public void M(int a) { void f(out int b) => b = 1; } } ";
var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [public void M(int a) { void f(ref int b) => b = 1; }]@10 -> [public void M(int a) { void f(out int b) => b = 1; }]@10");
}
[Fact]
public void MethodUpdate_LambdaParameterRefnessInBody()
{
var src1 = @"class C { public void M(int a) { f((ref int b) => b = 1); } }";
var src2 = @"class C { public void M(int a) { f((out int b) => b = 1); } } ";
var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [public void M(int a) { f((ref int b) => b = 1); }]@10 -> [public void M(int a) { f((out int b) => b = 1); }]@10");
}
#endregion
#region Operators
......
......@@ -4992,5 +4992,28 @@ static void Main(string[] args)
}",
MainDescription($"({FeaturesResources.local_variable}) ref int i"));
}
[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
[WorkItem(410932, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=410932")]
public async Task TestGenericMethodInDocComment()
{
await TestAsync(
@"
class Test
{
T F<T>()
{
F<T>();
}
/// <summary>
/// <see cref=""F$${T}()""/>
/// </summary>
void S()
{ }
}
",
MainDescription("T Test.F<T>()"));
}
}
}
......@@ -2089,5 +2089,25 @@ End Class
",
Documentation("String http://microsoft.com Nothing cat"))
End Function
<Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)>
<WorkItem(410932, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=410932")>
Public Async Function TestGenericMethodInDocComment() As Task
Await TestWithImportsAsync(<Text><![CDATA[
Public Class Test
Function F(Of T)() As T
F(Of T)()
End Function
''' <summary>
''' <see cref="F$$(Of T)()"/>
''' </summary>
Public Sub S()
End Sub
End Class
]]></Text>.NormalizedValue,
MainDescription("Function Test.F(Of T)() As T"))
End Function
End Class
End Namespace
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue
{
......@@ -60,7 +61,7 @@ private static bool HasChildren(SyntaxNode node)
{
// Leaves are labeled statements that don't have a labeled child.
// We also return true for non-labeled statements.
Label label = Classify(node.Kind(), out var isLeaf, ignoreVariableDeclarations: false);
Label label = Classify(node.Kind(), out var isLeaf);
// ignored should always be reported as leaves
Debug.Assert(label != Label.Ignored || isLeaf);
......@@ -160,7 +161,7 @@ private static int TiedToAncestor(Label label)
}
// internal for testing
internal static Label Classify(SyntaxKind kind, out bool isLeaf, bool ignoreVariableDeclarations)
internal static Label Classify(SyntaxKind kind, out bool isLeaf)
{
switch (kind)
{
......@@ -205,12 +206,12 @@ internal static Label Classify(SyntaxKind kind, out bool isLeaf, bool ignoreVari
return Label.FieldDeclaration;
case SyntaxKind.VariableDeclaration:
isLeaf = ignoreVariableDeclarations;
return ignoreVariableDeclarations ? Label.Ignored : Label.FieldVariableDeclaration;
isLeaf = false;
return Label.FieldVariableDeclaration;
case SyntaxKind.VariableDeclarator:
isLeaf = true;
return ignoreVariableDeclarations ? Label.Ignored : Label.FieldVariableDeclarator;
return Label.FieldVariableDeclarator;
case SyntaxKind.MethodDeclaration:
isLeaf = false;
......@@ -306,13 +307,13 @@ protected internal override int GetLabel(SyntaxNode node)
internal static Label GetLabel(SyntaxKind kind)
{
return Classify(kind, out var isLeaf, ignoreVariableDeclarations: false);
return Classify(kind, out var isLeaf);
}
// internal for testing
internal static bool HasLabel(SyntaxKind kind, bool ignoreVariableDeclarations)
internal static bool HasLabel(SyntaxKind kind)
{
return Classify(kind, out var isLeaf, ignoreVariableDeclarations) != Label.Ignored;
return Classify(kind, out var isLeaf) != Label.Ignored;
}
protected internal override int LabelCount
......@@ -346,13 +347,22 @@ public override bool ValuesEqual(SyntaxNode left, SyntaxNode right)
case SyntaxKind.RemoveAccessorDeclaration:
// When comparing method bodies we need to NOT ignore VariableDeclaration and VariableDeclarator children,
// but when comparing field definitions we should ignore VariableDeclarations children.
ignoreChildFunction = childKind => HasLabel(childKind, ignoreVariableDeclarations: true);
var leftBody = GetBody(left);
var rightBody = GetBody(right);
if (!SyntaxFactory.AreEquivalent(leftBody, rightBody, null))
{
return false;
}
ignoreChildFunction = childKind => childKind == SyntaxKind.Block || childKind == SyntaxKind.ArrowExpressionClause || HasLabel(childKind);
break;
default:
if (HasChildren(left))
{
ignoreChildFunction = childKind => HasLabel(childKind, ignoreVariableDeclarations: false);
ignoreChildFunction = childKind => HasLabel(childKind);
}
else
{
......@@ -365,6 +375,16 @@ public override bool ValuesEqual(SyntaxNode left, SyntaxNode right)
return SyntaxFactory.AreEquivalent(left, right, ignoreChildFunction);
}
private static SyntaxNode GetBody(SyntaxNode node)
{
switch (node)
{
case BaseMethodDeclarationSyntax baseMethodDeclarationSyntax: return baseMethodDeclarationSyntax.Body ?? (SyntaxNode)baseMethodDeclarationSyntax.ExpressionBody?.Expression;
case AccessorDeclarationSyntax accessorDeclarationSyntax: return accessorDeclarationSyntax.Body ?? (SyntaxNode)accessorDeclarationSyntax.ExpressionBody?.Expression;
default: throw ExceptionUtilities.UnexpectedValue(node);
}
}
protected override bool TryComputeWeightedDistance(SyntaxNode leftNode, SyntaxNode rightNode, out double distance)
{
SyntaxNodeOrToken? leftName = TryGetName(leftNode);
......
// 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.Linq;
using Microsoft.CodeAnalysis.CodeActions;
......@@ -19,7 +20,7 @@ internal class AddImportFixData
/// May be empty for fixes that don't need to add an import and only do something like
/// add a project/metadata reference.
/// </summary>
public ImmutableArray<TextChange> TextChanges { get; }
public IList<TextChange> TextChanges { get; }
/// <summary>
/// String to display in the lightbulb menu.
......@@ -29,7 +30,7 @@ internal class AddImportFixData
/// <summary>
/// Tags that control what glyph is displayed in the lightbulb menu.
/// </summary>
public ImmutableArray<string> Tags { get; private set; }
public IList<string> Tags { get; private set; }
/// <summary>
/// The priority this item should have in the lightbulb list.
......
......@@ -5,6 +5,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
{
......@@ -44,9 +45,9 @@ private abstract class AddImportCodeAction : CodeAction
FixData = fixData;
Title = fixData.Title;
Tags = fixData.Tags;
Tags = fixData.Tags.ToImmutableArrayOrEmpty();
Priority = fixData.Priority;
_textChanges = fixData.TextChanges;
_textChanges = fixData.TextChanges.ToImmutableArrayOrEmpty();
}
protected async Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToken)
......
......@@ -66,7 +66,8 @@ internal sealed partial class ServiceHubRemoteHostClient : RemoteHostClient
}
}
private static async Task RegisterWorkspaceHostAsync(Workspace workspace, RemoteHostClient client)
// internal for debugging purpose
internal static async Task RegisterWorkspaceHostAsync(Workspace workspace, RemoteHostClient client)
{
var vsWorkspace = workspace as VisualStudioWorkspaceImpl;
if (vsWorkspace == null)
......
......@@ -19,7 +19,12 @@ public async Task<RemoteHostClient> CreateAsync(Workspace workspace, Cancellatio
// this is the point where we can create different kind of remote host client in future (cloud or etc)
if (workspace.Options.GetOption(RemoteHostClientFactoryOptions.RemoteHost_InProc))
{
return await InProcRemoteHostClient.CreateAsync(workspace, runCacheCleanup: true, cancellationToken: cancellationToken).ConfigureAwait(false);
var client = await InProcRemoteHostClient.CreateAsync(workspace, runCacheCleanup: true, cancellationToken: cancellationToken).ConfigureAwait(false);
// register workspace host for in proc remote host client
await ServiceHubRemoteHostClient.RegisterWorkspaceHostAsync(workspace, client).ConfigureAwait(false);
return client;
}
return await ServiceHubRemoteHostClient.CreateAsync(workspace, cancellationToken).ConfigureAwait(false);
......
......@@ -296,13 +296,21 @@ private static ImmutableArray<ISymbol> GetSymbolsForNamespaceDeclarationNameCont
// int i = 5;
// i. // <-- here
// List<string> ml = new List<string>();
//
// The problem is that "i.List<string>" gets parsed as a type. In this case we need
// to try binding again as if "i" is an expression and not a type. In order to do
// that, we need to speculate as to what 'i' meant if it wasn't part of a local
// declaration's type.
//
// Another interesting case is something like:
//
// stringList.
// await Test2();
//
// Here "stringList.await" is thought of as the return type of a local function.
// The problem is that "i.List<string>" gets parsed as a type. In this case we need to
// try binding again as if "i" is an expression and not a type. In order to do that, we
// need to speculate as to what 'i' meant if it wasn't part of a local declaration's
// type.
if (name.IsFoundUnder<LocalDeclarationStatementSyntax>(d => d.Declaration.Type) ||
if (name.IsFoundUnder<LocalFunctionStatementSyntax>(d => d.ReturnType) ||
name.IsFoundUnder<LocalDeclarationStatementSyntax>(d => d.Declaration.Type) ||
name.IsFoundUnder<FieldDeclarationSyntax>(d => d.Declaration.Type))
{
var speculativeBinding = context.SemanticModel.GetSpeculativeSymbolInfo(
......
......@@ -24,7 +24,7 @@ internal enum OpenFlags
// SQLITE_OPEN_MASTER_JOURNAL = 0x00004000, /* VFS only */
// SQLITE_OPEN_NOMUTEX = 0x00008000, /* Ok for sqlite3_open_v2() */
// SQLITE_OPEN_FULLMUTEX = 0x00010000, /* Ok for sqlite3_open_v2() */
// SQLITE_OPEN_SHAREDCACHE = 0x00020000, /* Ok for sqlite3_open_v2() */
SQLITE_OPEN_SHAREDCACHE = 0x00020000, /* Ok for sqlite3_open_v2() */
// SQLITE_OPEN_PRIVATECACHE = 0x00040000, /* Ok for sqlite3_open_v2() */
// SQLITE_OPEN_WAL = 0x00080000, /* VFS only */
}
......
......@@ -51,7 +51,9 @@ public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector
{
faultInjector?.OnNewConnection();
var flags = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE;
// Enable shared cache so that multiple connections inside of same process share cache
// see https://sqlite.org/threadsafe.html for more detail
var flags = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_SHAREDCACHE;
var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null);
if (result != Result.OK)
......
......@@ -122,6 +122,7 @@ static SQLitePersistentStorage()
private readonly CancellationTokenSource _shutdownTokenSource = new CancellationTokenSource();
private readonly IDisposable _dbOwnershipLock;
private readonly IPersistentStorageFaultInjector _faultInjectorOpt;
// Accessors that allow us to retrieve/store data into specific DB tables. The
......@@ -146,10 +147,13 @@ static SQLitePersistentStorage()
string solutionFilePath,
string databaseFile,
Action<AbstractPersistentStorage> disposer,
IDisposable dbOwnershipLock,
IPersistentStorageFaultInjector faultInjectorOpt)
: base(optionService, workingFolderPath, solutionFilePath, databaseFile, disposer)
{
_dbOwnershipLock = dbOwnershipLock;
_faultInjectorOpt = faultInjectorOpt;
_solutionAccessor = new SolutionAccessor(this);
_projectAccessor = new ProjectAccessor(this);
_documentAccessor = new DocumentAccessor(this);
......@@ -187,6 +191,21 @@ private void ReleaseConnection(SqlConnection connection)
}
public override void Close()
{
// Flush all pending writes so that all data our features wanted written
// are definitely persisted to the DB.
try
{
CloseWorker();
}
finally
{
// let the lock go
_dbOwnershipLock.Dispose();
}
}
private void CloseWorker()
{
// Flush all pending writes so that all data our features wanted written
// are definitely persisted to the DB.
......
......@@ -4,6 +4,7 @@
using System.IO;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.SolutionSize;
using Microsoft.CodeAnalysis.Storage;
using Roslyn.Utilities;
......@@ -12,6 +13,7 @@ namespace Microsoft.CodeAnalysis.SQLite
{
internal partial class SQLitePersistentStorageService : AbstractPersistentStorageService
{
private const string LockFile = "db.lock";
private const string StorageExtension = "sqlite3";
private const string PersistentStorageFileName = "storage.ide";
......@@ -24,7 +26,7 @@ internal partial class SQLitePersistentStorageService : AbstractPersistentStorag
{
}
public SQLitePersistentStorageService(IOptionService optionService, IPersistentStorageFaultInjector faultInjector)
public SQLitePersistentStorageService(IOptionService optionService, IPersistentStorageFaultInjector faultInjector)
: base(optionService, testing: true)
{
_faultInjectorOpt = faultInjector;
......@@ -36,9 +38,47 @@ protected override string GetDatabaseFilePath(string workingFolderPath)
return Path.Combine(workingFolderPath, StorageExtension, PersistentStorageFileName);
}
protected override AbstractPersistentStorage OpenDatabase(Solution solution, string workingFolderPath, string databaseFilePath)
=> new SQLitePersistentStorage(
OptionService, workingFolderPath, solution.FilePath, databaseFilePath, this.Release, _faultInjectorOpt);
protected override bool TryOpenDatabase(
Solution solution, string workingFolderPath, string databaseFilePath, out AbstractPersistentStorage storage)
{
storage = null;
// try to get db ownership lock. if someone else already has the lock. it will throw
var dbOwnershipLock = TryGetDatabaseOwnership(databaseFilePath);
if (dbOwnershipLock == null)
{
return false;
}
storage = new SQLitePersistentStorage(
OptionService, workingFolderPath, solution.FilePath, databaseFilePath, this.Release, dbOwnershipLock, _faultInjectorOpt);
return true;
}
private static IDisposable TryGetDatabaseOwnership(string databaseFilePath)
{
return IOUtilities.PerformIO<IDisposable>(() =>
{
// make sure directory exist first.
EnsureDirectory(databaseFilePath);
return File.Open(
Path.Combine(Path.GetDirectoryName(databaseFilePath), LockFile),
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
});
}
private static void EnsureDirectory(string databaseFilePath)
{
var directory = Path.GetDirectoryName(databaseFilePath);
if (Directory.Exists(directory))
{
return;
}
Directory.CreateDirectory(directory);
}
protected override bool ShouldDeleteDatabase(Exception exception)
{
......
......@@ -54,7 +54,7 @@ protected AbstractPersistentStorageService(IOptionService optionService, bool te
}
protected abstract string GetDatabaseFilePath(string workingFolderPath);
protected abstract AbstractPersistentStorage OpenDatabase(Solution solution, string workingFolderPath, string databaseFilePath);
protected abstract bool TryOpenDatabase(Solution solution, string workingFolderPath, string databaseFilePath, out AbstractPersistentStorage storage);
protected abstract bool ShouldDeleteDatabase(Exception exception);
public IPersistentStorage GetStorage(Solution solution)
......@@ -235,7 +235,11 @@ private AbstractPersistentStorage TryCreatePersistentStorage(Solution solution,
var databaseFilePath = GetDatabaseFilePath(workingFolderPath);
try
{
database = OpenDatabase(solution, workingFolderPath, databaseFilePath);
if (!TryOpenDatabase(solution, workingFolderPath, databaseFilePath, out database))
{
return false;
}
database.Initialize(solution);
persistentStorage = database;
......
......@@ -44,7 +44,8 @@ public static void UpdateStorageLocation(SolutionId id, string storageLocation)
}
else
{
_idToStorageLocation[id] = storageLocation;
// Store the esent database in a different location for the out of proc server.
_idToStorageLocation[id] = Path.Combine(storageLocation, "Server");
}
}
}
......
// 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.Linq;
using Microsoft.CodeAnalysis.AddImport;
......@@ -165,7 +166,7 @@ protected override PackageWithTypeResult ReadValue(JsonReader reader, JsonSerial
var typeName = ReadProperty<string>(reader);
var version = ReadProperty<string>(reader);
var rank = (int)ReadProperty<long>(reader);
var containingNamespaceNames = ReadProperty<ImmutableArray<string>>(serializer, reader);
var containingNamespaceNames = ReadProperty<IList<string>>(serializer, reader);
Contract.ThrowIfFalse(reader.Read());
Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject);
......@@ -237,7 +238,7 @@ protected override ReferenceAssemblyWithTypeResult ReadValue(JsonReader reader,
var assemblyName = ReadProperty<string>(reader);
var typeName = ReadProperty<string>(reader);
var containingNamespaceNames = ReadProperty<ImmutableArray<string>>(serializer, reader);
var containingNamespaceNames = ReadProperty<IList<string>>(serializer, reader);
Contract.ThrowIfFalse(reader.Read());
Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject);
......@@ -298,9 +299,9 @@ protected override AddImportFixData ReadValue(JsonReader reader, JsonSerializer
Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject);
var kind = (AddImportFixKind)ReadProperty<long>(reader);
var textChanges = ReadProperty<ImmutableArray<TextChange>>(serializer, reader);
var textChanges = ReadProperty<IList<TextChange>>(serializer, reader).ToImmutableArrayOrEmpty();
var title = ReadProperty<string>(reader);
var tags = ReadProperty<ImmutableArray<string>>(serializer, reader);
var tags = ReadProperty<IList<string>>(serializer, reader).ToImmutableArrayOrEmpty();
var priority = (CodeActionPriority)ReadProperty<long>(reader);
var projectReferenceToAdd = ReadProperty<ProjectId>(serializer, reader);
......@@ -344,13 +345,13 @@ protected override void WriteValue(JsonWriter writer, AddImportFixData source, J
writer.WriteValue((int)source.Kind);
writer.WritePropertyName(nameof(AddImportFixData.TextChanges));
serializer.Serialize(writer, source.TextChanges);
serializer.Serialize(writer, source.TextChanges ?? SpecializedCollections.EmptyList<TextChange>());
writer.WritePropertyName(nameof(AddImportFixData.Title));
writer.WriteValue(source.Title);
writer.WritePropertyName(nameof(AddImportFixData.Tags));
serializer.Serialize(writer, source.Tags.NullToEmpty());
serializer.Serialize(writer, source.Tags ?? SpecializedCollections.EmptyList<string>());
writer.WritePropertyName(nameof(AddImportFixData.Priority));
writer.WriteValue((int)source.Priority);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册