Browse Source

CSharpAstResolver: don't return the same ResolveResult for two different nodes.

(make clones when using caches)
Closes icsharpcode/NRefactory#46.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
585ae50c2f
  1. 20
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  2. 19
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  3. 4
      ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
  4. 6
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/LinqTests.cs
  5. 10
      ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs
  6. 5
      ICSharpCode.NRefactory/Semantics/ResolveResult.cs
  7. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultMemberReference.cs

20
ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -41,8 +41,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -41,8 +41,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public class CSharpResolver
{
static readonly ResolveResult ErrorResult = ErrorResolveResult.UnknownError;
static readonly ResolveResult DynamicResult = new ResolveResult(SpecialType.Dynamic);
static readonly ResolveResult NullResult = new ResolveResult(SpecialType.NullType);
readonly ICompilation compilation;
internal readonly CSharpConversions conversions;
@ -1381,7 +1379,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1381,7 +1379,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
foundInCache = cache.TryGetValue(identifier, out r);
}
}
if (!foundInCache) {
if (foundInCache) {
r = (r != null ? r.ShallowClone() : null);
} else {
r = LookInCurrentType(identifier, typeArguments, lookupMode, parameterizeResultType);
if (cache != null) {
// also cache missing members (r==null)
@ -1398,9 +1398,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1398,9 +1398,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
r = LookInUsingScopeNamespace(null, compilation.RootNamespace, identifier, typeArguments, parameterizeResultType);
} else {
if (k == 0 && lookupMode != NameLookupMode.TypeInUsingDeclaration) {
if (!context.CurrentUsingScope.ResolveCache.TryGetValue(identifier, out r)) {
if (context.CurrentUsingScope.ResolveCache.TryGetValue(identifier, out r)) {
r = (r != null ? r.ShallowClone() : null);
} else {
r = LookInCurrentUsingScope(identifier, typeArguments, false, false);
r = context.CurrentUsingScope.ResolveCache.GetOrAdd(identifier, r);
context.CurrentUsingScope.ResolveCache.TryAdd(identifier, r);
}
} else {
r = LookInCurrentUsingScope(identifier, typeArguments, lookupMode == NameLookupMode.TypeInUsingDeclaration, parameterizeResultType);
@ -1477,7 +1479,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1477,7 +1479,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!(isInUsingDeclaration && u == currentUsingScope)) {
foreach (var pair in u.UsingAliases) {
if (pair.Key == identifier) {
return pair.Value;
return pair.Value.ShallowClone();
}
}
}
@ -1589,7 +1591,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1589,7 +1591,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
if (target.Type.Kind == TypeKind.Dynamic)
return DynamicResult;
return new ResolveResult(SpecialType.Dynamic);
MemberLookup lookup = CreateMemberLookup(lookupMode);
ResolveResult result;
@ -1887,7 +1889,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1887,7 +1889,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §7.6.5
if (target.Type.Kind == TypeKind.Dynamic)
return DynamicResult;
return new ResolveResult(SpecialType.Dynamic);
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) {
@ -2297,7 +2299,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2297,7 +2299,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public ResolveResult ResolvePrimitive(object value)
{
if (value == null) {
return NullResult;
return new ResolveResult(SpecialType.NullType);
} else {
TypeCode typeCode = Type.GetTypeCode(value.GetType());
IType type = compilation.FindType(typeCode);

19
ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -59,7 +59,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -59,7 +59,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// The ResolveVisitor is also responsible for handling lambda expressions.
static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError;
readonly ResolveResult voidResult;
CSharpResolver resolver;
/// <summary>Resolve result of the current LINQ query.</summary>
@ -112,13 +111,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -112,13 +111,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.resolver = resolver;
this.parsedFile = parsedFile;
this.navigator = skipAllNavigator;
this.voidResult = new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void));
}
internal void SetNavigator(IResolveVisitorNavigator navigator)
{
this.navigator = navigator ?? skipAllNavigator;
}
ResolveResult voidResult {
get {
return new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void));
}
}
#endregion
#region ResetContext
@ -1594,7 +1598,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1594,7 +1598,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<ResolveResult>.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression)
{
if (resolverEnabled) {
return Resolve(typeReferenceExpression.Type);
return Resolve(typeReferenceExpression.Type).ShallowClone();
} else {
Scan(typeReferenceExpression.Type);
return null;
@ -2420,6 +2424,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2420,6 +2424,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal abstract AstNode BodyExpression { get; }
internal abstract void EnforceMerge(ResolveVisitor parentVisitor);
public override ResolveResult ShallowClone()
{
if (IsUndecided)
throw new NotSupportedException();
return base.ShallowClone();
}
}
void MergeUndecidedLambdas()
@ -3261,7 +3272,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3261,7 +3272,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
foreach (var clause in queryExpression.Clauses) {
currentQueryResult = Resolve(clause);
}
return currentQueryResult;
return WrapResult(currentQueryResult);
} finally {
currentQueryResult = oldQueryResult;
cancellationToken = oldCancellationToken;

4
ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -55,6 +55,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
}
Dictionary<AstNode, ResolveResult> resolvedNodes = new Dictionary<AstNode, ResolveResult>();
HashSet<ResolveResult> resolveResults = new HashSet<ResolveResult>();
HashSet<AstNode> nodesWithConversions = new HashSet<AstNode>();
public ResolveVisitorNavigationMode Scan(AstNode node)
@ -69,6 +70,9 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -69,6 +70,9 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
resolvedNodes.Add(node, result);
if (CSharpAstResolver.IsUnresolvableNode(node))
throw new InvalidOperationException("Resolved unresolvable node");
if (!ParenthesizedExpression.ActsAsParenthesizedExpression(node))
if (!resolveResults.Add(result))
throw new InvalidOperationException("Duplicate resolve result");
if (result.IsError && !allowErrors) {
Console.WriteLine("Compiler error at " + fileName + ":" + node.StartLocation + ": " + result);

6
ICSharpCode.NRefactory.Tests/CSharp/Resolver/LinqTests.cs

@ -103,8 +103,8 @@ class TestClass { @@ -103,8 +103,8 @@ class TestClass {
}
}
";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.AreEqual("System.Linq.Enumerable.Select", rr.Member.FullName);
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsIdentityConversion);
Assert.AreEqual("System.Collections.Generic.IEnumerable", rr.Type.FullName);
Assert.AreEqual("System.Int32", ((ParameterizedType)rr.Type).TypeArguments[0].FullName);
}
@ -114,7 +114,7 @@ class TestClass { @@ -114,7 +114,7 @@ class TestClass {
{
string program = @"using System;
class TestClass { static void M() {
$(from a in new XYZ() select a.ToUpper())$.ToString();
(from a in new XYZ() $select a.ToUpper()$).ToString();
}}
class XYZ {
public int Select<U>(Func<string, U> f) { return 42; }

10
ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

@ -75,6 +75,16 @@ namespace ICSharpCode.NRefactory.Semantics @@ -75,6 +75,16 @@ namespace ICSharpCode.NRefactory.Semantics
this.constantValue = constantValue;
}
public MemberResolveResult(ResolveResult targetResult, IMember member, IType returnType, bool isConstant, object constantValue, bool isVirtualCall)
: base(returnType)
{
this.targetResult = targetResult;
this.member = member;
this.isConstant = isConstant;
this.constantValue = constantValue;
this.isVirtualCall = isVirtualCall;
}
public ResolveResult TargetResult {
get { return targetResult; }
}

5
ICSharpCode.NRefactory/Semantics/ResolveResult.cs

@ -70,5 +70,10 @@ namespace ICSharpCode.NRefactory.Semantics @@ -70,5 +70,10 @@ namespace ICSharpCode.NRefactory.Semantics
{
return DomRegion.Empty;
}
public virtual ResolveResult ShallowClone()
{
return (ResolveResult)MemberwiseClone();
}
}
}

4
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultMemberReference.cs

@ -63,7 +63,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -63,7 +63,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
IType type = typeReference.Resolve(context);
IEnumerable<IMember> members;
if (entityType == EntityType.Accessor) {
members = type.GetAccessors(m => m.Name == name && !m.IsExplicitInterfaceImplementation);
members = type.GetAccessors(
m => m.Name == name && !m.IsExplicitInterfaceImplementation,
GetMemberOptions.IgnoreInheritedMembers);
} else if (entityType == EntityType.Method) {
members = type.GetMethods(
m => m.Name == name && m.EntityType == EntityType.Method

Loading…
Cancel
Save