Permalink
Browse files

Added ResolverTest to consistency check and fixed some crashing bugs …

…in the resolver.
  • Loading branch information...
1 parent 3e8eb1e commit f1a1ab32ad112a3d336628da992f3ca680ab6600 @dgrunwald dgrunwald committed Dec 9, 2011
@@ -289,6 +289,8 @@ public LambdaUnaryOperatorMethod(CSharpOperators operators, Func<T, T> func)
public override object Invoke(CSharpResolver resolver, object input)
{
+ if (input == null)
+ return null;
return func((T)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T)), input));
}
@@ -456,6 +458,8 @@ public LambdaBinaryOperatorMethod(CSharpOperators operators, Func<T1, T2, T1> ch
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
{
+ if (lhs == null || rhs == null)
+ return null;
Func<T1, T2, T1> func = resolver.CheckForOverflow ? checkedFunc : uncheckedFunc;
return func((T1)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T1)), lhs),
(T2)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T2)), rhs));
@@ -692,6 +696,10 @@ public EqualityOperatorMethod(CSharpOperators operators, TypeCode type, bool neg
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
{
+ if (lhs == null && rhs == null)
+ return !Negate; // ==: true; !=: false
+ if (lhs == null || rhs == null)
+ return Negate; // ==: false; !=: true
lhs = resolver.CSharpPrimitiveCast(Type, lhs);
rhs = resolver.CSharpPrimitiveCast(Type, rhs);
bool equal;
@@ -734,10 +742,6 @@ public LiftedEqualityOperatorMethod(CSharpOperators operators, EqualityOperatorM
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
{
- if (lhs == null && rhs == null)
- return !baseMethod.Negate; // ==: true; !=: false
- if (lhs == null || rhs == null)
- return baseMethod.Negate; // ==: false; !=: true
return baseMethod.Invoke(resolver, lhs, rhs);
}
@@ -809,6 +813,8 @@ public RelationalOperatorMethod(CSharpOperators operators, Func<T1, T2, bool> fu
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
{
+ if (lhs == null || rhs == null)
+ return null;
return func((T1)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T1)), lhs),
(T2)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T2)), rhs));
}
@@ -393,7 +393,7 @@ public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult ex
break;
case UnaryOperatorType.BitNot:
if (type.Kind == TypeKind.Enum) {
- if (expression.IsCompileTimeConstant && !isNullable) {
+ if (expression.IsCompileTimeConstant && !isNullable && expression.ConstantValue != null) {
// evaluate as (E)(~(U)x);
var U = compilation.FindType(expression.ConstantValue.GetType());
var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
@@ -1325,7 +1325,16 @@ public ResolveResult LookupSimpleNameOrTypeName(string identifier, IList<IType>
ResolveResult LookInCurrentType(string identifier, IList<IType> typeArguments, SimpleNameLookupMode lookupMode, bool parameterizeResultType)
{
int k = typeArguments.Count;
- MemberLookup lookup = CreateMemberLookup();
+ MemberLookup lookup;
+ if (lookupMode == SimpleNameLookupMode.BaseTypeReference && this.CurrentTypeDefinition != null) {
+ // When looking up a base type reference, treat us as being outside the current type definition
+ // for accessibility purposes.
+ // This avoids a stack overflow when referencing a protected class nested inside the base class
+ // of a parent class. (NameLookupTests.InnerClassInheritingFromProtectedBaseInnerClassShouldNotCauseStackOverflow)
+ lookup = new MemberLookup(this.CurrentTypeDefinition.DeclaringTypeDefinition, this.Compilation.MainAssembly, false);
+ } else {
+ lookup = CreateMemberLookup();
+ }
// look in current type definitions
for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) {
if (k == 0) {
@@ -1376,7 +1385,7 @@ ResolveResult LookInCurrentUsingScope(string identifier, IList<IType> typeArgume
ITypeDefinition def = n.GetTypeDefinition(identifier, k);
if (def != null) {
IType result = def;
- if (parameterizeResultType) {
+ if (parameterizeResultType && k > 0) {
result = new ParameterizedType(def, typeArguments);
}
if (u.HasAlias(identifier))
@@ -1521,9 +1530,10 @@ ResolveResult ResolveMemberAccessOnNamespace(NamespaceResolveResult nrr, string
/// </summary>
public MemberLookup CreateMemberLookup()
{
+ ITypeDefinition currentTypeDefinition = this.CurrentTypeDefinition;
bool isInEnumMemberInitializer = this.CurrentMember != null && this.CurrentMember.EntityType == EntityType.Field
- && this.CurrentTypeDefinition != null && this.CurrentTypeDefinition.Kind == TypeKind.Enum;
- return new MemberLookup(this.CurrentTypeDefinition, this.Compilation.MainAssembly, isInEnumMemberInitializer);
+ && currentTypeDefinition != null && currentTypeDefinition.Kind == TypeKind.Enum;
+ return new MemberLookup(currentTypeDefinition, this.Compilation.MainAssembly, isInEnumMemberInitializer);
}
#endregion
@@ -547,7 +547,7 @@ public override IUnresolvedEntity VisitConstructorDeclaration(ConstructorDeclara
} else {
ctor.BodyRegion = MakeRegion(constructorDeclaration.Body);
}
- ctor.ReturnType = currentTypeDefinition;
+ ctor.ReturnType = KnownTypeReference.Void;
ConvertAttributes(ctor.Attributes, constructorDeclaration.Attributes);
ConvertParameters(ctor.Parameters, constructorDeclaration.Parameters);
@@ -0,0 +1,3 @@
+
+bin/
+obj/
@@ -50,6 +50,7 @@
<Compile Include="CSharpProject.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ResolverTest.cs" />
<Compile Include="RoundtripTest.cs" />
<Compile Include="Solution.cs" />
</ItemGroup>
@@ -36,29 +36,36 @@ class Program
public const string TempPath = @"C:\temp";
+ static Solution solution;
+
public static void Main(string[] args)
{
- Solution sln;
using (new Timer("Loading solution... ")) {
- sln = new Solution(Path.GetFullPath("../../../NRefactory.sln"));
+ solution = new Solution(Path.GetFullPath("../../../NRefactory.sln"));
}
Console.WriteLine("Loaded {0} lines of code ({1:f1} MB) in {2} files in {3} projects.",
- sln.AllFiles.Sum(f => f.LinesOfCode),
- sln.AllFiles.Sum(f => f.Content.TextLength) / 1024.0 / 1024.0,
- sln.AllFiles.Count(),
- sln.Projects.Count);
+ solution.AllFiles.Sum(f => f.LinesOfCode),
+ solution.AllFiles.Sum(f => f.Content.TextLength) / 1024.0 / 1024.0,
+ solution.AllFiles.Count(),
+ solution.Projects.Count);
- using (new Timer("Roundtripping tests... ")) {
- foreach (var file in sln.AllFiles) {
- RoundtripTest.RunTest(file);
- }
- }
+ //RunTestOnAllFiles("Roundtripping test", RoundtripTest.RunTest);
+ RunTestOnAllFiles("Resolver test", ResolverTest.RunTest);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
+ static void RunTestOnAllFiles(string title, Action<CSharpFile> runTest)
+ {
+ using (new Timer(title + "... ")) {
+ foreach (var file in solution.AllFiles) {
+ runTest(file);
+ }
+ }
+ }
+
static ConcurrentDictionary<string, IUnresolvedAssembly> assemblyDict = new ConcurrentDictionary<string, IUnresolvedAssembly>(Platform.FileNameComparer);
public static IUnresolvedAssembly LoadAssembly(string assemblyFileName)
@@ -0,0 +1,83 @@
+/*
+ * Created by SharpDevelop.
+ * User: Daniel
+ * Date: 12/9/2011
+ * Time: 01:26
+ *
+ * To change this template use Tools | Options | Coding | Edit Standard Headers.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using ICSharpCode.NRefactory.CSharp;
+using ICSharpCode.NRefactory.CSharp.Resolver;
+using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
+
+namespace ICSharpCode.NRefactory.ConsistencyCheck
+{
+ /// <summary>
+ /// Description of ResolverTest.
+ /// </summary>
+ public class ResolverTest
+ {
+ public static void RunTest(CSharpFile file)
+ {
+ CSharpAstResolver resolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit, file.ParsedFile);
+ var navigator = new ValidatingResolveAllNavigator(file.FileName);
+ resolver.ApplyNavigator(navigator, CancellationToken.None);
+ navigator.Validate(file.CompilationUnit);
+ }
+
+ sealed class ValidatingResolveAllNavigator : IResolveVisitorNavigator
+ {
+ string fileName;
+
+ public ValidatingResolveAllNavigator(string fileName)
+ {
+ this.fileName = fileName;
+ }
+
+ HashSet<AstNode> resolvedNodes = new HashSet<AstNode>();
+ HashSet<AstNode> nodesWithConversions = new HashSet<AstNode>();
+
+ public ResolveVisitorNavigationMode Scan(AstNode node)
+ {
+ return ResolveVisitorNavigationMode.Resolve;
+ }
+
+ public void Resolved(AstNode node, ResolveResult result)
+ {
+ if (!resolvedNodes.Add(node))
+ throw new InvalidOperationException("Duplicate Resolved() call");
+ if (CSharpAstResolver.IsUnresolvableNode(node))
+ throw new InvalidOperationException("Resolved unresolvable node");
+
+ if (result.IsError) {
+ Console.WriteLine("Compiler error at " + fileName + ":" + node.StartLocation + ": " + result);
+ }
+ }
+
+ public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
+ {
+ if (!nodesWithConversions.Add(expression))
+ throw new InvalidOperationException("Duplicate ProcessConversion() call");
+ if (conversion == Conversion.None) {
+ Console.WriteLine("Compiler error at " + fileName + ":" + expression.StartLocation + ": Cannot convert from " + result + " to " + targetType);
+ }
+ }
+
+ public void Validate(CompilationUnit cu)
+ {
+ foreach (AstNode node in cu.DescendantsAndSelf.Except(resolvedNodes)) {
+ if (node.NodeType != NodeType.Token) {
+ if (!CSharpAstResolver.IsUnresolvableNode(node)) {
+ Console.WriteLine("Forgot to resolve " + node);
+ }
+ }
+ }
+ }
+ }
+ }
+}
@@ -25,6 +25,10 @@
namespace ICSharpCode.NRefactory.ConsistencyCheck
{
+ /// <summary>
+ /// Tests parser + output visitor by roundtripping code.
+ /// Everything but whitespace must be preserved.
+ /// </summary>
public class RoundtripTest
{
public static void RunTest(CSharpFile file)
@@ -901,6 +901,19 @@ public void InheritingInnerClassShouldNotCauseStackOverflow()
}
[Test]
+ public void InnerClassInheritingFromProtectedBaseInnerClassShouldNotCauseStackOverflow()
+ {
+ string program = @"class Base {
+ protected class NestedBase {}
+}
+class Derived : Base {
+ class NestedDerived : $NestedBase$ { }
+}";
+ var result = Resolve<TypeResolveResult>(program);
+ Assert.AreEqual("Base.NestedBase", result.Type.FullName);
+ }
+
+ [Test]
public void EnumMembersHaveUnderlyingTypeWithinInitializers_MemberFromSameEnum()
{
string program = @"enum E { A = 0, B = $A$ + 1 }";
@@ -314,6 +314,7 @@ public void DefaultConstructorAddedToStruct()
var ctors = compilation.FindType(typeof(MyStructWithCtor)).GetConstructors();
Assert.AreEqual(2, ctors.Count());
Assert.IsFalse(ctors.Any(c => c.IsStatic));
+ Assert.IsTrue(ctors.All(c => c.ReturnType.Kind == TypeKind.Void));
}
[Test]
@@ -1645,10 +1645,7 @@ public IUnresolvedMethod ReadMethod(MethodDefinition method, IUnresolvedTypeDefi
}
}
- if (method.IsConstructor)
- m.ReturnType = parentType;
- else
- m.ReturnType = ReadTypeReference(method.ReturnType, typeAttributes: method.MethodReturnType);
+ m.ReturnType = ReadTypeReference(method.ReturnType, typeAttributes: method.MethodReturnType);
if (HasAnyAttributes(method))
AddAttributes(method, m.Attributes, m.ReturnTypeAttributes);
@@ -232,14 +232,30 @@ IEnumerable<IType> IType.GetNestedTypes(IList<IType> typeArguments, Predicate<IT
return EmptyList<IType>.Instance;
}
+ static readonly IUnresolvedMethod dummyConstructor = CreateDummyConstructor();
+
+ static IUnresolvedMethod CreateDummyConstructor()
+ {
+ var m = new DefaultUnresolvedMethod {
+ EntityType = EntityType.Constructor,
+ Name = ".ctor",
+ Accessibility = Accessibility.Public,
+ IsSynthetic = true,
+ ReturnType = KnownTypeReference.Void
+ };
+ m.Freeze();
+ return m;
+ }
+
public IEnumerable<IMethod> GetConstructors(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) {
- throw new NotImplementedException();
- //DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter(constraints));
- //if (filter(m))
- // return new [] { m };
+ if (filter == null || filter(dummyConstructor)) {
+ var resolvedCtor = (IMethod)dummyConstructor.CreateResolved(compilation.TypeResolveContext);
+ IMethod m = new SpecializedMethod(this, resolvedCtor, EmptyList<IType>.Instance);
+ return new [] { m };
+ }
}
return EmptyList<IMethod>.Instance;
} else {
@@ -28,7 +28,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
[Serializable]
public abstract class AbstractUnresolvedMember : AbstractUnresolvedEntity, IUnresolvedMember
{
- ITypeReference returnType;
+ ITypeReference returnType = SpecialType.UnknownType;
IList<IMemberReference> interfaceImplementations;
public override void ApplyInterningProvider(IInterningProvider provider)
@@ -67,6 +67,8 @@ internal override AbstractUnresolvedEntity.RareFields WriteRareFields()
public ITypeReference ReturnType {
get { return returnType; }
set {
+ if (value == null)
+ throw new ArgumentNullException();
ThrowIfFrozen();
returnType = value;
}
Oops, something went wrong. Retry.

0 comments on commit f1a1ab3

Please sign in to comment.