Browse Source

Add unit tests for TypeSystemAstBuilder.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
e17ba7462a
  1. 7
      ICSharpCode.NRefactory.Demo/CSDemo.cs
  2. 4
      ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs
  3. 185
      ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs
  4. 7
      ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs
  5. 2
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  6. 11
      ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs
  7. 10
      ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs
  8. 78
      ICSharpCode.NRefactory/CSharp/Refactoring/TypeSystemAstBuilder.cs
  9. 3
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  10. 10
      ICSharpCode.NRefactory/TypeSystem/Implementation/SubstitutionTypeReference.cs

7
ICSharpCode.NRefactory.Demo/CSDemo.cs

@ -182,9 +182,8 @@ namespace ICSharpCode.NRefactory.Demo @@ -182,9 +182,8 @@ namespace ICSharpCode.NRefactory.Demo
void ResolveButtonClick(object sender, EventArgs e)
{
SimpleProjectContent project = new SimpleProjectContent();
TypeSystemConvertVisitor convertVisitor = new TypeSystemConvertVisitor(project, "dummy.cs");
compilationUnit.AcceptVisitor(convertVisitor, null);
project.UpdateProjectContent(null, convertVisitor.ParsedFile);
var parsedFile = new TypeSystemConvertVisitor(project, "dummy.cs").Convert(compilationUnit);
project.UpdateProjectContent(null, parsedFile);
List<ITypeResolveContext> projects = new List<ITypeResolveContext>();
projects.Add(project);
@ -197,7 +196,7 @@ namespace ICSharpCode.NRefactory.Demo @@ -197,7 +196,7 @@ namespace ICSharpCode.NRefactory.Demo
if (csharpTreeView.SelectedNode != null) {
navigator = new NodeListResolveVisitorNavigator(new[] { (AstNode)csharpTreeView.SelectedNode.Tag });
}
ResolveVisitor visitor = new ResolveVisitor(resolver, convertVisitor.ParsedFile, navigator);
ResolveVisitor visitor = new ResolveVisitor(resolver, parsedFile, navigator);
visitor.Scan(compilationUnit);
csharpTreeView.BeginUpdate();
ShowResolveResultsInTree(csharpTreeView.Nodes, visitor);

4
ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs

@ -27,9 +27,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser @@ -27,9 +27,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
}
testCasePC = new SimpleProjectContent();
TypeSystemConvertVisitor visitor = new TypeSystemConvertVisitor(testCasePC, fileName);
cu.AcceptVisitor(visitor, null);
ParsedFile parsedFile = visitor.ParsedFile;
ParsedFile parsedFile = new TypeSystemConvertVisitor(testCasePC, fileName).Convert(cu);
parsedFile.Freeze();
testCasePC.UpdateProjectContent(null, parsedFile);
}

185
ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs

@ -0,0 +1,185 @@ @@ -0,0 +1,185 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
[TestFixture]
public class TypeSystemAstBuilderTests
{
const string program = @"
using System;
using System.Collections.Generic;
class Base<T> {
public class Nested<X> { }
}
class Derived<T, S> : Base<S> { }
namespace NS {
using R = global::System.Reflection;
using L = List<char>;
class System { }
}
";
SimpleProjectContent pc;
ITypeResolveContext ctx;
ITypeDefinition baseClass, derivedClass, nestedClass, systemClass;
ParsedFile parsedFile;
[SetUp]
public void SetUp()
{
pc = new SimpleProjectContent();
var cu = new CSharpParser().Parse(new StringReader(program));
parsedFile = new TypeSystemConvertVisitor(pc, "program.cs").Convert(cu);
pc.UpdateProjectContent(null, parsedFile);
ctx = new CompositeTypeResolveContext(new[] { pc, CecilLoaderTests.Mscorlib });
baseClass = pc.GetTypeDefinition(string.Empty, "Base", 1, StringComparer.Ordinal);
nestedClass = baseClass.NestedTypes.Single();
derivedClass = pc.GetTypeDefinition(string.Empty, "Derived", 2, StringComparer.Ordinal);
systemClass = pc.GetTypeDefinition("NS", "System", 0, StringComparer.Ordinal);
}
TypeSystemAstBuilder CreateBuilder(ITypeDefinition currentTypeDef = null)
{
return new TypeSystemAstBuilder(
new CSharpResolver(ctx) {
UsingScope = currentTypeDef != null ? parsedFile.GetUsingScope(currentTypeDef.Region.Begin) : parsedFile.RootUsingScope,
CurrentTypeDefinition = currentTypeDef
});
}
string TypeToString(ITypeReference type, ITypeDefinition currentTypeDef = null)
{
var builder = CreateBuilder(currentTypeDef);
IType resolvedType = type.Resolve(ctx);
AstType node = builder.ConvertType(resolvedType);
return node.ToString();
}
[Test]
public void PrimitiveVoid()
{
Assert.AreEqual("void", TypeToString(KnownTypeReference.Void));
}
[Test]
public void PrimitiveInt()
{
Assert.AreEqual("int", TypeToString(KnownTypeReference.Int32));
}
[Test]
public void PrimitiveDecimal()
{
Assert.AreEqual("decimal", TypeToString(KnownTypeReference.Decimal));
}
[Test]
public void SystemType()
{
Assert.AreEqual("Type", TypeToString(KnownTypeReference.Type));
}
[Test]
public void ListOfNSSystem()
{
var type = new ParameterizedType(ctx.GetTypeDefinition(typeof(List<>)), new[] { systemClass });
Assert.AreEqual("List<NS.System>", TypeToString(type));
Assert.AreEqual("List<System>", TypeToString(type, systemClass));
}
[Test]
public void NonGenericIEnumerable()
{
Assert.AreEqual("System.Collections.IEnumerable", TypeToString(typeof(IEnumerable).ToTypeReference()));
}
[Test]
public void NonGenericIEnumerableWithSystemNamespaceCollision()
{
Assert.AreEqual("global::System.Collections.IEnumerable", TypeToString(typeof(IEnumerable).ToTypeReference(), systemClass));
}
[Test]
public void AliasedNamespace()
{
var type = typeof(System.Reflection.Assembly).ToTypeReference();
Assert.AreEqual("R.Assembly", TypeToString(type, systemClass));
}
[Test]
public void AliasedType()
{
var type = new ParameterizedTypeReference(ctx.GetTypeDefinition(typeof(List<>)), new[] { KnownTypeReference.Char });
Assert.AreEqual("List<char>", TypeToString(type));
Assert.AreEqual("L", TypeToString(type, systemClass));
}
[Test]
public void UnboundType()
{
Assert.AreEqual("Base<>", TypeToString(baseClass));
Assert.AreEqual("Base<>.Nested<>", TypeToString(nestedClass));
}
[Test]
public void NestedType()
{
var type = new ParameterizedTypeReference(nestedClass, new[] { KnownTypeReference.Char, KnownTypeReference.String });
Assert.AreEqual("Base<char>.Nested<string>", TypeToString(type));
Assert.AreEqual("Base<char>.Nested<string>", TypeToString(type, baseClass));
Assert.AreEqual("Base<char>.Nested<string>", TypeToString(type, nestedClass));
Assert.AreEqual("Base<char>.Nested<string>", TypeToString(type, derivedClass));
}
[Test]
public void NestedTypeInCurrentClass()
{
var type = new ParameterizedTypeReference(nestedClass, new[] { baseClass.TypeParameters[0], KnownTypeReference.String });
Assert.AreEqual("Nested<string>", TypeToString(type, baseClass));
Assert.AreEqual("Nested<string>", TypeToString(type, nestedClass));
}
[Test]
public void NestedTypeInDerivedClass()
{
var type1 = new ParameterizedTypeReference(nestedClass, new[] { derivedClass.TypeParameters[0], KnownTypeReference.String });
Assert.AreEqual("Base<T>.Nested<string>", TypeToString(type1, derivedClass));
var type2 = new ParameterizedTypeReference(nestedClass, new[] { derivedClass.TypeParameters[1], KnownTypeReference.String });
Assert.AreEqual("Nested<string>", TypeToString(type2, derivedClass));
}
[Test]
public void MultidimensionalArray()
{
Assert.AreEqual("byte[][,]", TypeToString(typeof(byte[][,]).ToTypeReference()));
}
[Test]
public void Pointer()
{
Assert.AreEqual("long*", TypeToString(typeof(long*).ToTypeReference()));
}
[Test]
public void NullableType()
{
Assert.AreEqual("ulong?", TypeToString(typeof(ulong?).ToTypeReference()));
}
}
}

7
ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs

@ -30,11 +30,10 @@ namespace ICSharpCode.NRefactory.Documentation @@ -30,11 +30,10 @@ namespace ICSharpCode.NRefactory.Documentation
void Init(string program)
{
pc = new IDStringTestProjectContent();
CSharpParser parser = new CSharpParser();
TypeSystemConvertVisitor cv = new TypeSystemConvertVisitor(pc, "program.cs");
parser.Parse(new StringReader(program)).AcceptVisitor(cv, null);
pc.UpdateProjectContent(null, cv.ParsedFile);
var cu = new CSharpParser().Parse(new StringReader(program));
var parsedFile = new TypeSystemConvertVisitor(pc, "program.cs").Convert(cu);
pc.UpdateProjectContent(null, parsedFile);
}
ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount = 0)

2
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -117,6 +117,7 @@ @@ -117,6 +117,7 @@
<Compile Include="CSharp\Parser\Expression\UnaryOperatorExpressionTests.cs" />
<Compile Include="CSharp\Parser\GeneralScope\AttributeSectionTests.cs" />
<Compile Include="CSharp\Parser\ParseUtil.cs" />
<Compile Include="CSharp\Refactoring\TypeSystemAstBuilderTests.cs" />
<Compile Include="CSharp\Resolver\ArrayCreationTests.cs" />
<Compile Include="CSharp\Resolver\AttributeTests.cs" />
<Compile Include="CSharp\Resolver\BinaryOperatorTests.cs" />
@ -165,6 +166,7 @@ @@ -165,6 +166,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="CSharp\" />
<Folder Include="CSharp\Refactoring" />
<Folder Include="CSharp\Parser\" />
<Folder Include="CSharp\Parser\" />
<Folder Include="CSharp\Parser\" />

11
ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs

@ -166,5 +166,16 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -166,5 +166,16 @@ namespace ICSharpCode.NRefactory.TypeSystem
typeof(IEnumerable<>), typeof(ICollection<>), typeof(IList<>)),
typeof(List<string>).ToTypeReference().Resolve(context).GetAllBaseTypeDefinitions(context).OrderBy(t => t.ReflectionName).ToArray());
}
[Test]
public void BaseTypeDefinitionsOfStringArray()
{
Assert.AreEqual(
GetTypes(typeof(Array), typeof(object),
typeof(ICloneable), typeof(IStructuralComparable), typeof(IStructuralEquatable),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IEnumerable<>), typeof(ICollection<>), typeof(IList<>)),
typeof(string[]).ToTypeReference().Resolve(context).GetAllBaseTypeDefinitions(context).OrderBy(t => t.ReflectionName).ToArray());
}
}
}

10
ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs

@ -54,6 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -54,6 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp
this.currentTypeDefinition = currentTypeDefinition;
}
public ParsedFile Convert(AstNode node)
{
node.AcceptVisitor(this, null);
return parsedFile;
}
public ParsedFile ParsedFile {
get { return parsedFile; }
}
@ -720,8 +726,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -720,8 +726,8 @@ namespace ICSharpCode.NRefactory.CSharp
typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, lookupMode));
}
if (typeArguments.Count == 0 && parentMethodDefinition != null) {
// SimpleTypeOrNamespaceReference doesn't support method type parameters,
// so we directly handle them here.
// SimpleTypeOrNamespaceReference doesn't have a 'current method' context
// so we have to handle method type parameters here.
foreach (ITypeParameter tp in parentMethodDefinition.TypeParameters) {
if (tp.Name == s.Identifier)
return tp;

78
ICSharpCode.NRefactory/CSharp/Refactoring/TypeSystemAstBuilder.cs

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -54,10 +54,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -54,10 +54,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
ITypeDefinition typeDef = type as ITypeDefinition;
if (typeDef != null) {
if (typeDef.TypeParameterCount > 0) {
// Create an unbound type
// Unbound type
IType[] typeArguments = new IType[typeDef.TypeParameterCount];
for (int i = 0; i < typeArguments.Length; i++) {
typeArguments[i] = SharedTypes.UnknownType;
typeArguments[i] = SharedTypes.UnboundTypeArgument;
}
return ConvertTypeDefinition(typeDef, typeArguments);
} else {
@ -103,14 +103,40 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -103,14 +103,40 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return new PrimitiveType("string");
}
// There is no type code for System.Void
if (typeDef != null && typeDef.Namespace == "System" && typeDef.Name == "Void" && typeDef.TypeParameterCount == 0)
if (typeDef.Kind == TypeKind.Void)
return new PrimitiveType("void");
if (resolver != null && TypeArgumentsTrivial(typeArguments, OuterTypeParameterCount(typeDef))) {
TypeResolveResult trr = resolver.ResolveSimpleName(typeDef.Name, typeArguments) as TypeResolveResult;
if (trr != null && !trr.IsError && trr.Type.GetDefinition() == typeDef) {
// The number of type parameters belonging to outer classes
int outerTypeParameterCount;
if (typeDef.DeclaringType != null)
outerTypeParameterCount = typeDef.DeclaringType.TypeParameterCount;
else
outerTypeParameterCount = 0;
if (resolver != null) {
// Look if there's an alias to the target type
for (UsingScope usingScope = resolver.UsingScope; usingScope != null; usingScope = usingScope.Parent) {
foreach (var pair in usingScope.UsingAliases) {
IType type = pair.Value.Resolve(resolver.Context);
if (TypeMatches(type, typeDef, typeArguments))
return new SimpleType(pair.Key);
}
}
IList<IType> localTypeArguments;
if (typeDef.TypeParameterCount > outerTypeParameterCount) {
localTypeArguments = new IType[typeDef.TypeParameterCount - outerTypeParameterCount];
for (int i = 0; i < localTypeArguments.Count; i++) {
localTypeArguments[i] = typeArguments[outerTypeParameterCount + i];
}
} else {
localTypeArguments = EmptyList<IType>.Instance;
}
TypeResolveResult trr = resolver.ResolveSimpleName(typeDef.Name, localTypeArguments) as TypeResolveResult;
if (trr != null && !trr.IsError && TypeMatches(trr.Type, typeDef, typeArguments)) {
// We can use the short type name
SimpleType shortResult = new SimpleType(typeDef.Name);
AddTypeArguments(shortResult, typeArguments, OuterTypeParameterCount(typeDef), typeDef.TypeParameterCount);
AddTypeArguments(shortResult, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
return shortResult;
}
}
@ -129,33 +155,31 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -129,33 +155,31 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
}
result.MemberName = typeDef.Name;
AddTypeArguments(result, typeArguments, OuterTypeParameterCount(typeDef), typeDef.TypeParameterCount);
AddTypeArguments(result, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
return result;
}
/// <summary>
/// Gets the number of type parameters belonging to outer classes.
/// </summary>
int OuterTypeParameterCount(ITypeDefinition typeDef)
{
if (typeDef.DeclaringType != null)
return typeDef.DeclaringType.TypeParameterCount;
else
return 0;
}
/// <summary>
/// Gets whether the first <paramref name="num"/> type arguments are trivial,
/// that is, they point to a type parameter with the same index.
/// Gets whether 'type' is the same as 'typeDef' parameterized with the given type arguments.
/// </summary>
bool TypeArgumentsTrivial(IList<IType> typeArguments, int num)
bool TypeMatches(IType type, ITypeDefinition typeDef, IList<IType> typeArguments)
{
for (int i = 0; i < num; i++) {
ITypeParameter tp = typeArguments[i] as ITypeParameter;
if (!(tp != null && tp.OwnerType == EntityType.TypeDefinition && tp.Index == i))
if (typeDef.TypeParameterCount == 0) {
return typeDef.Equals(type);
} else {
if (!typeDef.Equals(type.GetDefinition()))
return false;
ParameterizedType pt = type as ParameterizedType;
if (pt == null) {
return typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument);
}
var ta = pt.TypeArguments;
for (int i = 0; i < ta.Count; i++) {
if (!ta[i].Equals(typeArguments[i]))
return false;
}
return true;
}
return true;
}
/// <summary>

3
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -170,6 +170,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -170,6 +170,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Gets whether the type is an delegate type.
/// </summary>
/// <remarks>This method returns <c>false</c> for System.Delegate itself</remarks>
[Obsolete("Use type.Kind == TypeKind.Delegate instead")]
public static bool IsDelegate(this IType type)
{
if (type == null)
@ -196,7 +197,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -196,7 +197,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
SpecializedMethod m = new SpecializedMethod(method);
m.SetDeclaringType(pt);
var substitution = pt.GetSubstitution();
m.SubstituteTypes(t => new SubstitutionTypeReference(t, substitution));
m.SubstituteTypes(t => SubstitutionTypeReference.Create(t, substitution));
return m;
}
return method;

10
ICSharpCode.NRefactory/TypeSystem/Implementation/SubstitutionTypeReference.cs

@ -23,6 +23,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -23,6 +23,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.substitution = substitution;
}
public static ITypeReference Create(ITypeReference baseTypeReference, TypeVisitor substitution)
{
IType baseType = baseTypeReference as IType;
if (baseType != null && substitution != null) {
return baseType.AcceptVisitor(substitution);
} else {
return new SubstitutionTypeReference(baseTypeReference, substitution);
}
}
public IType Resolve(ITypeResolveContext context)
{
return baseTypeReference.Resolve(context).AcceptVisitor(substitution);

Loading…
Cancel
Save