Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add C# resolve visitor.

  • Loading branch information...
commit a7e253e3eab8b8759ddf6ec0c32386723a2787fc 1 parent 9b04350
Daniel Grunwald dgrunwald authored
68 ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs
View
@@ -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
View
@@ -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
View
@@ -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 @@
</ItemGroup>
<ItemGroup>
<Folder Include="CSharp\Parser\Expression" />
+ <Folder Include="CSharp\Parser\GeneralScope" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
4 ...rpCode.NRefactory/CSharp/Dom/AbtractDomVisitor.cs → ...pCode.NRefactory/CSharp/Dom/AbstractDomVisitor.cs
View
@@ -1,4 +1,4 @@
-//
+//
// IDomVisitor.cs
//
// Author:
@@ -28,7 +28,7 @@
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
View
@@ -1,4 +1,4 @@
-//
+//
// DomLocation.cs
//
// Author:
@@ -63,14 +63,16 @@ public DomLocation (int line, int column) : this ()
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 @@ public static DomLocation FromInvariantString (string invariantString)
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
View
@@ -2259,12 +2259,12 @@ public CompilationUnit Parse (TextReader reader)
{
// 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
View
@@ -19,6 +19,7 @@ public class CSharpResolver
{
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;
@@ -33,6 +34,13 @@ public CSharpResolver(ITypeResolveContext context)
#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>
public bool CheckForOverflow { get; set; }
@@ -1555,6 +1563,11 @@ public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arg
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 @@ public ResolveResult ResolveSizeOf(IType type)
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
View
@@ -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
View
@@ -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 @@
<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" />
Please sign in to comment.
Something went wrong with that request. Please try again.