Browse Source

TypeSystemConvertVisitor: implemented ConvertInterfaceImplementation for methods and properties.

Implemented 'goto case' support in control flow analysis.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
0b263b0b74
  1. 44
      ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
  2. 4
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
  3. 16
      ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
  4. 68
      ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs
  5. 10
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  6. 13
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  7. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs

44
ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs

@ -21,9 +21,9 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Analysis namespace ICSharpCode.NRefactory.CSharp.Analysis
@ -429,7 +429,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
foreach (CaseLabel label in section.CaseLabels) { foreach (CaseLabel label in section.CaseLabels) {
if (label.Expression.IsNull) { if (label.Expression.IsNull) {
defaultSection = section; defaultSection = section;
} else if (constant != null) { } else if (constant != null && constant.IsCompileTimeConstant) {
ResolveResult labelConstant = builder.EvaluateConstant(label.Expression); ResolveResult labelConstant = builder.EvaluateConstant(label.Expression);
if (builder.AreEqualConstants(constant, labelConstant)) if (builder.AreEqualConstants(constant, labelConstant))
sectionMatchedByConstant = section; sectionMatchedByConstant = section;
@ -440,17 +440,22 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
sectionMatchedByConstant = defaultSection; sectionMatchedByConstant = defaultSection;
int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count; int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count;
List<ControlFlowNode> sectionStartNodes = new List<ControlFlowNode>();
ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false); ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false);
breakTargets.Push(end); breakTargets.Push(end);
foreach (SwitchSection section in switchStatement.SwitchSections) { foreach (SwitchSection section in switchStatement.SwitchSections) {
if (constant == null || section == sectionMatchedByConstant) { int sectionStartNodeID = builder.nodes.Count;
if (constant == null || !constant.IsCompileTimeConstant || section == sectionMatchedByConstant) {
HandleStatementList(section.Statements, data); HandleStatementList(section.Statements, data);
} else { } else {
// This section is unreachable: pass null to HandleStatementList. // This section is unreachable: pass null to HandleStatementList.
HandleStatementList(section.Statements, null); HandleStatementList(section.Statements, null);
} }
// Don't bother connecting the ends of the sections: the 'break' statement takes care of that. // Don't bother connecting the ends of the sections: the 'break' statement takes care of that.
// Store the section start node for 'goto case' statements.
sectionStartNodes.Add(sectionStartNodeID < builder.nodes.Count ? builder.nodes[sectionStartNodeID] : null);
} }
breakTargets.Pop(); breakTargets.Pop();
if (defaultSection == null && sectionMatchedByConstant == null) { if (defaultSection == null && sectionMatchedByConstant == null) {
@ -459,7 +464,38 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) { if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) {
// Resolve 'goto case' statements: // Resolve 'goto case' statements:
throw new NotImplementedException(); for (int i = gotoCaseOrDefaultInOuterScope; i < gotoCaseOrDefault.Count; i++) {
ControlFlowNode gotoCaseNode = gotoCaseOrDefault[i];
GotoCaseStatement gotoCaseStatement = gotoCaseNode.NextStatement as GotoCaseStatement;
ResolveResult gotoCaseConstant = null;
if (gotoCaseStatement != null) {
gotoCaseConstant = builder.EvaluateConstant(gotoCaseStatement.LabelExpression);
}
int targetSectionIndex = -1;
int currentSectionIndex = 0;
foreach (SwitchSection section in switchStatement.SwitchSections) {
foreach (CaseLabel label in section.CaseLabels) {
if (gotoCaseStatement != null) {
// goto case
if (!label.Expression.IsNull) {
ResolveResult labelConstant = builder.EvaluateConstant(label.Expression);
if (builder.AreEqualConstants(gotoCaseConstant, labelConstant))
targetSectionIndex = currentSectionIndex;
}
} else {
// goto default
if (label.Expression.IsNull)
targetSectionIndex = currentSectionIndex;
}
}
currentSectionIndex++;
}
if (targetSectionIndex >= 0 && sectionStartNodes[targetSectionIndex] != null)
Connect(gotoCaseNode, sectionStartNodes[targetSectionIndex], ControlFlowEdgeType.Jump);
else
Connect(gotoCaseNode, end, ControlFlowEdgeType.Jump);
}
gotoCaseOrDefault.RemoveRange(gotoCaseOrDefaultInOuterScope, gotoCaseOrDefault.Count - gotoCaseOrDefaultInOuterScope);
} }
builder.nodes.Add(end); builder.nodes.Add(end);

4
ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs

@ -89,6 +89,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public void ApplyNavigator(IResolveVisitorNavigator navigator, CancellationToken cancellationToken = default(CancellationToken)) public void ApplyNavigator(IResolveVisitorNavigator navigator, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (navigator == null)
throw new ArgumentNullException("navigator");
if (resolveVisitor != null) if (resolveVisitor != null)
throw new InvalidOperationException("Applying a navigator is only valid as the first operation on the CSharpAstResolver."); throw new InvalidOperationException("Applying a navigator is only valid as the first operation on the CSharpAstResolver.");
resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile, navigator); resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile, navigator);
@ -101,6 +103,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public ResolveResult Resolve(AstNode node, CancellationToken cancellationToken = default(CancellationToken)) public ResolveResult Resolve(AstNode node, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (node == null || node.IsNull)
return ErrorResolveResult.UnknownError;
if (resolveVisitor == null) { if (resolveVisitor == null) {
resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile); resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile);
resolveVisitor.Scan(rootNode); resolveVisitor.Scan(rootNode);

16
ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs

@ -494,11 +494,19 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
IMemberReference ConvertInterfaceImplementation(AstType interfaceType, AbstractUnresolvedMember unresolvedMember) IMemberReference ConvertInterfaceImplementation(AstType interfaceType, AbstractUnresolvedMember unresolvedMember)
{ {
ITypeReference interfaceTypeReference = ConvertType(interfaceType); ITypeReference interfaceTypeReference = ConvertType(interfaceType);
if (unresolvedMember.EntityType == EntityType.Method || unresolvedMember.EntityType == EntityType.Indexer) { int typeParameterCount = 0;
throw new NotImplementedException(); IList<ITypeReference> parameterTypes = null;
} else { if (unresolvedMember.EntityType == EntityType.Method) {
return new DefaultMemberReference(unresolvedMember.EntityType, ConvertType(interfaceType), unresolvedMember.Name); typeParameterCount = ((IUnresolvedMethod)unresolvedMember).TypeParameters.Count;
}
IUnresolvedParameterizedMember parameterizedMember = unresolvedMember as IUnresolvedParameterizedMember;
if (parameterizedMember != null) {
parameterTypes = new ITypeReference[parameterizedMember.Parameters.Count];
for (int i = 0; i < parameterTypes.Count; i++) {
parameterTypes[i] = parameterizedMember.Parameters[i].Type;
}
} }
return new DefaultMemberReference(unresolvedMember.EntityType, ConvertType(interfaceType), unresolvedMember.Name, typeParameterCount, parameterTypes);
} }
#endregion #endregion

68
ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -221,5 +222,72 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop.Iterators.Single())); Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop.Iterators.Single()));
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(loop)); Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(loop));
} }
[Test]
public void SwitchWithGotoDefault()
{
SwitchStatement @switch = new SwitchStatement {
SwitchSections = {
new SwitchSection { // case 0:
CaseLabels = { new CaseLabel(new PrimitiveExpression(0)) },
Statements = { new GotoDefaultStatement() }
},
new SwitchSection { // default:
CaseLabels = { new CaseLabel() },
Statements = {
new ExpressionStatement(new AssignmentExpression(new IdentifierExpression("a"), new PrimitiveExpression(1))),
new BreakStatement()
}
}
}};
SwitchSection case0 = @switch.SwitchSections.ElementAt(0);
SwitchSection defaultSection = @switch.SwitchSections.ElementAt(1);
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(@switch);
da.Analyze("a");
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(@switch));
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(case0.Statements.First()));
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(defaultSection.Statements.First()));
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(defaultSection.Statements.Last()));
Assert.AreEqual(DefiniteAssignmentStatus.CodeUnreachable, da.GetStatusAfter(defaultSection.Statements.Last()));
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(@switch));
}
[Test]
public void SwitchWithGotoCase()
{
SwitchStatement @switch = new SwitchStatement {
Expression = new PrimitiveExpression(1),
SwitchSections = {
new SwitchSection { // case 0:
CaseLabels = { new CaseLabel(new PrimitiveExpression(0)) },
Statements = { new BreakStatement() }
},
new SwitchSection { // case 1:
CaseLabels = { new CaseLabel(new PrimitiveExpression(1)) },
Statements = {
new ExpressionStatement(new AssignmentExpression(new IdentifierExpression("a"), new PrimitiveExpression(0))),
new GotoCaseStatement { LabelExpression = new PrimitiveExpression(2) }
}
},
new SwitchSection { // case 2:
CaseLabels = { new CaseLabel(new PrimitiveExpression(2)) },
Statements = { new BreakStatement() }
}
}};
SwitchSection case0 = @switch.SwitchSections.ElementAt(0);
SwitchSection case1 = @switch.SwitchSections.ElementAt(1);
SwitchSection case2 = @switch.SwitchSections.ElementAt(2);
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(@switch);
da.Analyze("a");
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(@switch));
Assert.AreEqual(DefiniteAssignmentStatus.CodeUnreachable, da.GetStatusBefore(case0.Statements.First()));
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(case1.Statements.First()));
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(case2.Statements.First()));
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(@switch));
}
} }
} }

10
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -1236,7 +1236,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }
throw new NotImplementedException();
} }
IType ReadType() IType ReadType()
@ -1246,8 +1245,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
IType typeInCurrentAssembly = typeReference.Resolve(new SimpleTypeResolveContext(currentResolvedAssembly)); IType typeInCurrentAssembly = typeReference.Resolve(new SimpleTypeResolveContext(currentResolvedAssembly));
if (typeInCurrentAssembly.Kind != TypeKind.Unknown) if (typeInCurrentAssembly.Kind != TypeKind.Unknown)
return typeInCurrentAssembly; return typeInCurrentAssembly;
// look for the type in mscorlib // look for the type in mscorlib
throw new NotImplementedException(); ITypeDefinition systemObject = currentResolvedAssembly.Compilation.FindType(KnownTypeCode.Object).GetDefinition();
if (systemObject != null) {
return typeReference.Resolve(new SimpleTypeResolveContext(systemObject.ParentAssembly));
} else {
// couldn't find corlib - return the unknown IType for the current assembly
return typeInCurrentAssembly;
}
} }
} }
#endregion #endregion

13
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -435,7 +435,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public ITypeReference ToTypeReference() public ITypeReference ToTypeReference()
{ {
throw new NotImplementedException(); ITypeDefinition declTypeDef = this.DeclaringTypeDefinition;
if (declTypeDef != null) {
return new NestedTypeReference(declTypeDef.ToTypeReference(), this.Name, this.TypeParameterCount - declTypeDef.TypeParameterCount);
} else {
IAssembly asm = this.ParentAssembly;
IAssemblyReference asmRef;
if (asm != null)
asmRef = new DefaultAssemblyReference(asm.AssemblyName);
else
asmRef = DefaultAssemblyReference.CurrentAssembly;
return new GetClassTypeReference(asmRef, this.Namespace, this.Name, this.TypeParameterCount);
}
} }
public IEnumerable<IType> GetNestedTypes(Predicate<ITypeDefinition> filter = null, GetMemberOptions options = GetMemberOptions.None) public IEnumerable<IType> GetNestedTypes(Predicate<ITypeDefinition> filter = null, GetMemberOptions options = GetMemberOptions.None)

2
ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs

@ -84,7 +84,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public override ITypeReference ToTypeReference() public override ITypeReference ToTypeReference()
{ {
throw new NotSupportedException(); return new TypeParameterReference(ownerType, index);
} }
public int Index { public int Index {

Loading…
Cancel
Save