Browse Source

Add C# resolve visitor.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
a7e253e3ea
  1. 68
      ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs
  2. 17
      ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs
  3. 2
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  4. 4
      ICSharpCode.NRefactory/CSharp/Dom/AbstractDomVisitor.cs
  5. 10
      ICSharpCode.NRefactory/CSharp/Dom/DomLocation.cs
  6. 12
      ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs
  7. 85
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  8. 272
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
  9. 3
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

68
ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope
{
[TestFixture, Ignore]
public class AttributeSectionTests
{
[Test, Ignore]
public void GlobalAttributeCSharp()
{
string program = @"[global::Microsoft.VisualBasic.CompilerServices.DesignerGenerated()]
[someprefix::DesignerGenerated()]
public class Form1 {
}";
// TODO This test checks that [global] attributes are incorrectly applies to the following type???
//TypeDeclaration decl = ParseUtilCSharp.ParseGlobal<TypeDeclaration>(program);
//Assert.AreEqual("Microsoft.VisualBasic.CompilerServices.DesignerGenerated", decl.Attributes.First().Attributes.Single().Name);
//Assert.AreEqual("someprefix.DesignerGenerated", decl.Attributes.Last().Attributes.Single().Name);
}
[Test]
public void AssemblyAttributeCSharp()
{
string program = @"[assembly: System.Attribute()]";
AttributeSection decl = ParseUtilCSharp.ParseGlobal<AttributeSection>(program);
Assert.AreEqual(new DomLocation(1, 1), decl.StartLocation);
Assert.AreEqual("assembly", decl.AttributeTarget);
}
[Test]
public void AssemblyAttributeCSharpWithNamedArguments()
{
string program = @"[assembly: Foo(1, namedArg: 2, prop = 3)]";
AttributeSection decl = ParseUtilCSharp.ParseGlobal<AttributeSection>(program);
Assert.AreEqual("assembly", decl.AttributeTarget);
var a = decl.Attributes.Single();
Assert.AreEqual("Foo", a.Name);
Assert.AreEqual(3, a.Arguments.Count());
// TODO: check arguments
}
[Test]
public void ModuleAttributeCSharp()
{
string program = @"[module: System.Attribute()]";
AttributeSection decl = ParseUtilCSharp.ParseGlobal<AttributeSection>(program);
Assert.AreEqual(new DomLocation(1, 1), decl.StartLocation);
Assert.AreEqual("module", decl.AttributeTarget);
}
[Test]
public void TypeAttributeCSharp()
{
string program = @"[type: System.Attribute()] class Test {}";
TypeDeclaration type = ParseUtilCSharp.ParseGlobal<TypeDeclaration>(program);
AttributeSection decl = type.Attributes.Single();
Assert.AreEqual(new DomLocation(1, 1), decl.StartLocation);
Assert.AreEqual("type", decl.AttributeTarget);
}
}
}

17
ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs

@ -13,6 +13,23 @@ namespace ICSharpCode.NRefactory.CSharp.Parser @@ -13,6 +13,23 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
/// </summary>
public class ParseUtilCSharp
{
public static T ParseGlobal<T>(string code, bool expectErrors = false) where T : INode
{
CSharpParser parser = new CSharpParser();
CompilationUnit cu = parser.Parse(new StringReader(code));
// TODO check for parser errors
/*if (expectErrors)
Assert.IsTrue(parser.Errors.ErrorOutput.Length > 0, "There were errors expected, but parser finished without errors.");
else
Assert.AreEqual("", parser.Errors.ErrorOutput);*/
INode node = cu.Children.Single();
Type type = typeof(T);
Assert.IsTrue(type.IsAssignableFrom(node.GetType()), String.Format("Parsed node was {0} instead of {1} ({2})", node.GetType(), type, node));
return (T)node;
}
public static T ParseStatement<T>(string stmt, bool expectErrors = false) where T : INode
{
Assert.Ignore("ParseExpression not yet implemented");

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

@ -84,6 +84,7 @@ @@ -84,6 +84,7 @@
<Compile Include="CSharp\Parser\Expression\TypeOfExpressionTests.cs" />
<Compile Include="CSharp\Parser\Expression\TypeReferenceExpressionTests.cs" />
<Compile Include="CSharp\Parser\Expression\UnaryOperatorExpressionTests.cs" />
<Compile Include="CSharp\Parser\GeneralScope\AttributeSectionTests.cs" />
<Compile Include="CSharp\Parser\ParseUtil.cs" />
<Compile Include="CSharp\Resolver\BinaryOperatorTests.cs" />
<Compile Include="CSharp\Resolver\CastTests.cs" />
@ -117,6 +118,7 @@ @@ -117,6 +118,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="CSharp\Parser\Expression" />
<Folder Include="CSharp\Parser\GeneralScope" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

4
ICSharpCode.NRefactory/CSharp/Dom/AbtractDomVisitor.cs → ICSharpCode.NRefactory/CSharp/Dom/AbstractDomVisitor.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// IDomVisitor.cs
//
// Author:
@ -28,7 +28,7 @@ using System; @@ -28,7 +28,7 @@ using System;
namespace ICSharpCode.NRefactory.CSharp
{
public abstract class AbtractDomVisitor<T, S> : IDomVisitor<T, S>
public abstract class AbstractDomVisitor<T, S> : IDomVisitor<T, S>
{
protected S VisitChildren (INode node, T data)
{

10
ICSharpCode.NRefactory/CSharp/Dom/DomLocation.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// DomLocation.cs
//
// Author:
@ -63,14 +63,16 @@ namespace ICSharpCode.NRefactory.CSharp @@ -63,14 +63,16 @@ namespace ICSharpCode.NRefactory.CSharp
public override bool Equals (object other)
{
if (!(other is DomLocation))
if (!(other is DomLocation))
return false;
return (DomLocation)other == this;
}
public override int GetHashCode ()
{
return Line + Column * 5000;
unchecked {
return Line + Column * 5000;
}
}
public bool Equals (DomLocation other)
@ -97,7 +99,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -97,7 +99,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (invariantString.ToUpper () == "EMPTY")
return DomLocation.Empty;
string[] splits = invariantString.Split (',', '/');
if (splits.Length == 2)
if (splits.Length == 2)
return new DomLocation (Int32.Parse (splits[0]), Int32.Parse (splits[1]));
return DomLocation.Empty;
}

12
ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs

@ -2259,12 +2259,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -2259,12 +2259,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
// TODO: can we optimize this to avoid the text->stream->text roundtrip?
using (MemoryStream stream = new MemoryStream ()) {
using (StreamWriter w = new StreamWriter(stream, Encoding.UTF8)) {
char[] buffer = new char[2048];
int read;
while ((read = reader.ReadBlock(buffer, 0, buffer.Length)) > 0)
w.Write(buffer, 0, read);
}
StreamWriter w = new StreamWriter(stream, Encoding.UTF8);
char[] buffer = new char[2048];
int read;
while ((read = reader.ReadBlock(buffer, 0, buffer.Length)) > 0)
w.Write(buffer, 0, read);
w.Flush(); // we can't close the StreamWriter because that would also close the MemoryStream
stream.Position = 0;
return Parse(stream);
}

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

@ -19,6 +19,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -19,6 +19,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
static readonly ResolveResult ErrorResult = new ErrorResolveResult(SharedTypes.UnknownType);
static readonly ResolveResult DynamicResult = new ResolveResult(SharedTypes.Dynamic);
static readonly ResolveResult NullResult = new ResolveResult(SharedTypes.Null);
readonly ITypeResolveContext context;
@ -32,6 +33,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -32,6 +33,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region Properties
/// <summary>
/// Gets the type resolve context used by the resolver.
/// </summary>
public ITypeResolveContext Context {
get { return context; }
}
/// <summary>
/// Gets/Sets whether the current context is <c>checked</c>.
/// </summary>
@ -1555,6 +1563,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1555,6 +1563,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return ErrorResult;
}
public ResolveResult ResolveIndexer(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
{
throw new NotImplementedException();
}
static List<DefaultParameter> CreateParameters(ResolveResult[] arguments, string[] argumentNames)
{
List<DefaultParameter> list = new List<DefaultParameter>();
@ -1653,5 +1666,77 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1653,5 +1666,77 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return new ConstantResolveResult(int32, size);
}
#endregion
#region This/Base
/// <summary>
/// Resolves 'this'.
/// </summary>
public ResolveResult ResolveThisReference()
{
ITypeDefinition t = CurrentTypeDefinition;
if (t != null) {
return new ResolveResult(t);
}
return ErrorResult;
}
/// <summary>
/// Resolves 'base'.
/// </summary>
public ResolveResult ResolveBaseReference()
{
ITypeDefinition t = CurrentTypeDefinition;
if (t != null) {
foreach (IType baseType in t.GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && baseTypeDef.ClassType != ClassType.Interface) {
return new ResolveResult(baseType);
}
}
}
return ErrorResult;
}
#endregion
#region ResolveConditional
public ResolveResult ResolveConditional(ResolveResult trueExpression, ResolveResult falseExpression)
{
// C# 4.0 spec §7.14: Conditional operator
Conversions c = new Conversions(context);
bool isValid;
IType resultType;
if (HasType(trueExpression) && HasType(falseExpression)) {
bool t2f = c.ImplicitConversion(trueExpression.Type, falseExpression.Type);
bool f2t = c.ImplicitConversion(falseExpression.Type, trueExpression.Type);
resultType = (f2t && !t2f) ? falseExpression.Type : trueExpression.Type;
isValid = (t2f != f2t) || (t2f && f2t && c.IdentityConversion(trueExpression.Type, falseExpression.Type));
} else if (HasType(trueExpression)) {
resultType = trueExpression.Type;
isValid = c.ImplicitConversion(falseExpression, resultType);
} else if (HasType(falseExpression)) {
resultType = falseExpression.Type;
isValid = c.ImplicitConversion(trueExpression, resultType);
} else {
return ErrorResult;
}
return isValid ? new ResolveResult(resultType) : new ErrorResolveResult(resultType);
}
bool HasType(ResolveResult r)
{
return r.Type != SharedTypes.UnknownType && r.Type != SharedTypes.Null;
}
#endregion
public ResolveResult ResolvePrimitive(object value)
{
if (value == null) {
return NullResult;
} else {
TypeCode typeCode = Type.GetTypeCode(value.GetType());
IType type = typeCode.ToTypeReference().Resolve(context);
return new ConstantResolveResult(type, value);
}
}
}
}

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

@ -0,0 +1,272 @@ @@ -0,0 +1,272 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Traverses the DOM and resolves every expression.
/// </summary>
public class ResolveVisitor : AbstractDomVisitor<object, ResolveResult>
{
static readonly ResolveResult errorResult = new ErrorResolveResult(SharedTypes.UnknownType);
readonly CSharpResolver resolver;
readonly Dictionary<INode, ResolveResult> cache = new Dictionary<INode, ResolveResult>();
/// <summary>
/// Set this property to false to skip resolving all sub expressions.
/// </summary>
public bool FullyResolveSubExpressions { get; set; }
public ResolveVisitor(CSharpResolver resolver)
{
if (resolver == null)
throw new ArgumentNullException("resolver");
this.resolver = resolver;
this.FullyResolveSubExpressions = true;
}
public ResolveResult Resolve(INode node)
{
ResolveResult result;
if (!cache.TryGetValue(node, out result)) {
result = cache[node] = node.AcceptVisitor(this, null) ?? errorResult;
}
return result;
}
#region Checked / Unchecked
public override ResolveResult VisitCheckedExpression(CheckedExpression checkedExpression, object data)
{
bool oldCheckForOverflow = resolver.CheckForOverflow;
try {
resolver.CheckForOverflow = true;
return checkedExpression.Expression.AcceptVisitor(this, data);
} finally {
resolver.CheckForOverflow = oldCheckForOverflow;
}
}
public override ResolveResult VisitUncheckedExpression(UncheckedExpression uncheckedExpression, object data)
{
bool oldCheckForOverflow = resolver.CheckForOverflow;
try {
resolver.CheckForOverflow = false;
return uncheckedExpression.Expression.AcceptVisitor(this, data);
} finally {
resolver.CheckForOverflow = oldCheckForOverflow;
}
}
public override ResolveResult VisitCheckedStatement(CheckedStatement checkedStatement, object data)
{
bool oldCheckForOverflow = resolver.CheckForOverflow;
try {
resolver.CheckForOverflow = true;
return base.VisitCheckedStatement(checkedStatement, data);
} finally {
resolver.CheckForOverflow = oldCheckForOverflow;
}
}
public override ResolveResult VisitUncheckedStatement(UncheckedStatement uncheckedStatement, object data)
{
bool oldCheckForOverflow = resolver.CheckForOverflow;
try {
resolver.CheckForOverflow = true;
return base.VisitUncheckedStatement(uncheckedStatement, data);
} finally {
resolver.CheckForOverflow = oldCheckForOverflow;
}
}
#endregion
static bool IsTargetOfInvocation(INode node)
{
InvocationExpression ie = node.Parent as InvocationExpression;
return ie != null && ie.Target == node;
}
IType ResolveType(INode node)
{
return SharedTypes.UnknownType;
}
public override ResolveResult VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data)
{
throw new NotImplementedException();
}
public override ResolveResult VisitArgListExpression(ArgListExpression argListExpression, object data)
{
return new ResolveResult(resolver.Context.GetClass(typeof(RuntimeArgumentHandle)) ?? SharedTypes.UnknownType);
}
public override ResolveResult VisitArrayObjectCreateExpression(ArrayObjectCreateExpression arrayObjectCreateExpression, object data)
{
throw new NotImplementedException();
}
public override ResolveResult VisitAsExpression(AsExpression asExpression, object data)
{
if (FullyResolveSubExpressions)
Resolve(asExpression.Expression);
return new ResolveResult(ResolveType(asExpression.TypeReference));
}
public override ResolveResult VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
{
ResolveResult left = Resolve(assignmentExpression.Left);
if (FullyResolveSubExpressions) {
Resolve(assignmentExpression.Right);
}
return new ResolveResult(left.Type);
}
public override ResolveResult VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression, object data)
{
return resolver.ResolveBaseReference();
}
public override ResolveResult VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{
ResolveResult left = Resolve(binaryOperatorExpression.Left);
ResolveResult right = Resolve(binaryOperatorExpression.Right);
return resolver.ResolveBinaryOperator(binaryOperatorExpression.BinaryOperatorType, left, right);
}
public override ResolveResult VisitCastExpression(CastExpression castExpression, object data)
{
return resolver.ResolveCast(ResolveType(castExpression.CastTo), Resolve(castExpression.Expression));
}
public override ResolveResult VisitConditionalExpression(ConditionalExpression conditionalExpression, object data)
{
if (FullyResolveSubExpressions)
Resolve(conditionalExpression.Condition);
return resolver.ResolveConditional(Resolve(conditionalExpression.TrueExpression),
Resolve(conditionalExpression.FalseExpression));
}
public override ResolveResult VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data)
{
return new ConstantResolveResult(ResolveType(defaultValueExpression.TypeReference), null);
}
public override ResolveResult VisitDirectionExpression(DirectionExpression directionExpression, object data)
{
ResolveResult rr = Resolve(directionExpression.Expression);
return new ResolveResult(new ByReferenceType(rr.Type));
}
public override ResolveResult VisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
{
// TODO: type arguments?
return resolver.ResolveSimpleName(identifierExpression.Identifier.Name, null,
IsTargetOfInvocation(identifierExpression));
}
public override ResolveResult VisitIndexerExpression(IndexerExpression indexerExpression, object data)
{
ResolveResult target = Resolve(indexerExpression.Target);
// TODO: add support for named arguments
var argumentExpressions = indexerExpression.Arguments.ToList();
ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count];
for (int i = 0; i < arguments.Length; i++) {
arguments[i] = Resolve(argumentExpressions[i]);
}
return resolver.ResolveIndexer(target, arguments);
}
public override ResolveResult VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
ResolveResult target = Resolve(invocationExpression.Target);
// TODO: add support for named arguments
var argumentExpressions = invocationExpression.Arguments.ToList();
ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count];
for (int i = 0; i < arguments.Length; i++) {
arguments[i] = Resolve(argumentExpressions[i]);
}
return resolver.ResolveInvocation(target, arguments);
}
public override ResolveResult VisitIsExpression(IsExpression isExpression, object data)
{
if (FullyResolveSubExpressions)
ResolveType(isExpression.TypeReference);
return new ResolveResult(TypeCode.Boolean.ToTypeReference().Resolve(resolver.Context));
}
public override ResolveResult VisitLambdaExpression(LambdaExpression lambdaExpression, object data)
{
throw new NotImplementedException();
}
public override ResolveResult VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data)
{
throw new NotImplementedException();
}
public override ResolveResult VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression, object data)
{
return resolver.ResolvePrimitive(null);
}
public override ResolveResult VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
{
throw new NotImplementedException();
}
public override ResolveResult VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
{
return Resolve(parenthesizedExpression.Expression);
}
public override ResolveResult VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data)
{
throw new NotImplementedException();
}
public override ResolveResult VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data)
{
return resolver.ResolvePrimitive(primitiveExpression.Value);
}
public override ResolveResult VisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data)
{
return resolver.ResolveSizeOf(ResolveType(sizeOfExpression.Type));
}
public override ResolveResult VisitStackAllocExpression(StackAllocExpression stackAllocExpression, object data)
{
if (FullyResolveSubExpressions)
Resolve(stackAllocExpression.CountExpression);
return new ResolveResult(new PointerType(ResolveType(stackAllocExpression.Type)));
}
public override ResolveResult VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data)
{
return resolver.ResolveThisReference();
}
static readonly GetClassTypeReference systemType = new GetClassTypeReference("System.Type", 0);
public override ResolveResult VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data)
{
if (FullyResolveSubExpressions)
ResolveType(typeOfExpression.Type);
return new ResolveResult(systemType.Resolve(resolver.Context));
}
public override ResolveResult VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{
ResolveResult expr = Resolve(unaryOperatorExpression.Expression);
return resolver.ResolveUnaryOperator(unaryOperatorExpression.UnaryOperatorType, expr);
}
}
}

3
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -56,7 +56,7 @@ @@ -56,7 +56,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CSharp\Dom\AbstractNode.cs" />
<Compile Include="CSharp\Dom\AbtractDomVisitor.cs" />
<Compile Include="CSharp\Dom\AbstractDomVisitor.cs" />
<Compile Include="CSharp\Dom\CompilationUnit.cs" />
<Compile Include="CSharp\Dom\CSharpModifierToken.cs" />
<Compile Include="CSharp\Dom\CSharpTokenNode.cs" />
@ -167,6 +167,7 @@ @@ -167,6 +167,7 @@
<Compile Include="CSharp\Resolver\OverloadResolution.cs" />
<Compile Include="CSharp\Resolver\OverloadResolutionErrors.cs" />
<Compile Include="CSharp\Resolver\ResolveResult.cs" />
<Compile Include="CSharp\Resolver\ResolveVisitor.cs" />
<Compile Include="CSharp\Resolver\SimpleTypeOrNamespaceReference.cs" />
<Compile Include="CSharp\Resolver\TypeInference.cs" />
<Compile Include="CSharp\Resolver\TypeResolveResult.cs" />

Loading…
Cancel
Save