You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
16 KiB
329 lines
16 KiB
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this |
|
// software and associated documentation files (the "Software"), to deal in the Software |
|
// without restriction, including without limitation the rights to use, copy, modify, merge, |
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
|
// to whom the Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in all copies or |
|
// substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
// DEALINGS IN THE SOFTWARE. |
|
|
|
using System; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Threading; |
|
using ICSharpCode.NRefactory.CSharp.Resolver; |
|
using ICSharpCode.NRefactory.TypeSystem; |
|
using ICSharpCode.NRefactory.TypeSystem.Implementation; |
|
using NUnit.Framework; |
|
|
|
namespace ICSharpCode.NRefactory.CSharp.Analysis |
|
{ |
|
[TestFixture] |
|
public class DefiniteAssignmentTests |
|
{ |
|
DefiniteAssignmentAnalysis CreateDefiniteAssignmentAnalysis(Statement rootStatement) |
|
{ |
|
var resolver = new CSharpAstResolver(new CSharpResolver(new SimpleCompilation(CecilLoaderTests.Mscorlib)), rootStatement); |
|
return new DefiniteAssignmentAnalysis(rootStatement, resolver, CancellationToken.None); |
|
} |
|
|
|
[Test] |
|
public void TryFinally() |
|
{ |
|
BlockStatement block = new BlockStatement { |
|
new TryCatchStatement { |
|
TryBlock = new BlockStatement { |
|
new GotoStatement("LABEL"), |
|
new AssignmentExpression(new IdentifierExpression("i"), new PrimitiveExpression(1)) |
|
}, |
|
CatchClauses = { |
|
new CatchClause { |
|
Body = new BlockStatement { |
|
new AssignmentExpression(new IdentifierExpression("i"), new PrimitiveExpression(3)) |
|
} |
|
} |
|
}, |
|
FinallyBlock = new BlockStatement { |
|
new AssignmentExpression(new IdentifierExpression("j"), new PrimitiveExpression(5)) |
|
} |
|
}, |
|
new LabelStatement { Label = "LABEL" }, |
|
new EmptyStatement() |
|
}; |
|
TryCatchStatement tryCatchStatement = (TryCatchStatement)block.Statements.First(); |
|
Statement stmt1 = tryCatchStatement.TryBlock.Statements.ElementAt(1); |
|
Statement stmt3 = tryCatchStatement.CatchClauses.Single().Body.Statements.Single(); |
|
Statement stmt5 = tryCatchStatement.FinallyBlock.Statements.Single(); |
|
LabelStatement label = (LabelStatement)block.Statements.ElementAt(1); |
|
|
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block); |
|
da.Analyze("i"); |
|
Assert.AreEqual(0, da.UnassignedVariableUses.Count); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(tryCatchStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.CodeUnreachable, da.GetStatusBefore(stmt1)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.CodeUnreachable, da.GetStatusAfter(stmt1)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(stmt3)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(stmt3)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(stmt5)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(stmt5)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(tryCatchStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(label)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(label)); |
|
|
|
da.Analyze("j"); |
|
Assert.AreEqual(0, da.UnassignedVariableUses.Count); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(tryCatchStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.CodeUnreachable, da.GetStatusBefore(stmt1)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.CodeUnreachable, da.GetStatusAfter(stmt1)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(stmt3)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(stmt3)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(stmt5)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(stmt5)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(tryCatchStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(label)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(label)); |
|
} |
|
|
|
[Test] |
|
public void ConditionalAnd() |
|
{ |
|
IfElseStatement ifStmt = new IfElseStatement { |
|
Condition = new BinaryOperatorExpression { |
|
Left = new BinaryOperatorExpression(new IdentifierExpression("x"), BinaryOperatorType.GreaterThan, new PrimitiveExpression(0)), |
|
Operator = BinaryOperatorType.ConditionalAnd, |
|
Right = new BinaryOperatorExpression { |
|
Left = new ParenthesizedExpression { |
|
Expression = new AssignmentExpression { |
|
Left = new IdentifierExpression("i"), |
|
Operator = AssignmentOperatorType.Assign, |
|
Right = new IdentifierExpression("y") |
|
} |
|
}, |
|
Operator = BinaryOperatorType.GreaterThanOrEqual, |
|
Right = new PrimitiveExpression(0) |
|
} |
|
}, |
|
TrueStatement = new BlockStatement(), |
|
FalseStatement = new BlockStatement() |
|
}; |
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(ifStmt); |
|
da.Analyze("i"); |
|
Assert.AreEqual(0, da.UnassignedVariableUses.Count); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(ifStmt)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(ifStmt.TrueStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(ifStmt.FalseStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(ifStmt)); |
|
} |
|
|
|
[Test] |
|
public void ConditionalOr() |
|
{ |
|
IfElseStatement ifStmt = new IfElseStatement { |
|
Condition = new BinaryOperatorExpression { |
|
Left = new BinaryOperatorExpression(new IdentifierExpression("x"), BinaryOperatorType.GreaterThan, new PrimitiveExpression(0)), |
|
Operator = BinaryOperatorType.ConditionalOr, |
|
Right = new BinaryOperatorExpression { |
|
Left = new ParenthesizedExpression { |
|
Expression = new AssignmentExpression { |
|
Left = new IdentifierExpression("i"), |
|
Operator = AssignmentOperatorType.Assign, |
|
Right = new IdentifierExpression("y") |
|
} |
|
}, |
|
Operator = BinaryOperatorType.GreaterThanOrEqual, |
|
Right = new PrimitiveExpression(0) |
|
} |
|
}, |
|
TrueStatement = new BlockStatement(), |
|
FalseStatement = new BlockStatement() |
|
}; |
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(ifStmt); |
|
da.Analyze("i"); |
|
Assert.AreEqual(0, da.UnassignedVariableUses.Count); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(ifStmt)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(ifStmt.TrueStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(ifStmt.FalseStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(ifStmt)); |
|
} |
|
|
|
[Test] |
|
public void WhileTrue() |
|
{ |
|
WhileStatement loop = new WhileStatement { |
|
Condition = new PrimitiveExpression(true), |
|
EmbeddedStatement = new BlockStatement { |
|
new AssignmentExpression(new IdentifierExpression("i"), new PrimitiveExpression(0)), |
|
new BreakStatement() |
|
} |
|
}; |
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(loop); |
|
da.Analyze("i"); |
|
Assert.AreEqual(0, da.UnassignedVariableUses.Count); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(loop)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(loop.EmbeddedStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.CodeUnreachable, da.GetStatusAfter(loop.EmbeddedStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop)); |
|
} |
|
|
|
[Test] |
|
public void ForLoop() |
|
{ |
|
ForStatement loop = new ForStatement { |
|
Initializers = { |
|
new ExpressionStatement( |
|
new AssignmentExpression(new IdentifierExpression("i"), new PrimitiveExpression(0)) |
|
) |
|
}, |
|
Condition = new BinaryOperatorExpression(new IdentifierExpression("i"), BinaryOperatorType.LessThan, new PrimitiveExpression(1000)), |
|
Iterators = { |
|
new ExpressionStatement( |
|
new AssignmentExpression { |
|
Left = new IdentifierExpression("i"), |
|
Operator = AssignmentOperatorType.Add, |
|
Right = new IdentifierExpression("j") |
|
} |
|
) |
|
}, |
|
EmbeddedStatement = new ExpressionStatement( |
|
new AssignmentExpression(new IdentifierExpression("j"), new IdentifierExpression("i")) |
|
)}; |
|
|
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(loop); |
|
da.Analyze("i"); |
|
Assert.AreEqual(0, da.UnassignedVariableUses.Count); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(loop)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(loop.Initializers.Single())); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop.Initializers.Single())); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBeforeLoopCondition(loop)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(loop.EmbeddedStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop.EmbeddedStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(loop.Iterators.Single())); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop.Iterators.Single())); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop)); |
|
|
|
da.Analyze("j"); |
|
Assert.AreEqual(0, da.UnassignedVariableUses.Count); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(loop)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(loop.Initializers.Single())); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(loop.Initializers.Single())); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBeforeLoopCondition(loop)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusBefore(loop.EmbeddedStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop.EmbeddedStatement)); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(loop.Iterators.Single())); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(loop.Iterators.Single())); |
|
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)); |
|
} |
|
|
|
[Test] |
|
public void ConditionalExpression1() |
|
{ |
|
string code = "int a; int b = X ? (a = 1) : 0;"; |
|
var block = new BlockStatement(); |
|
block.Statements.AddRange(new CSharpParser().ParseStatements(code)); |
|
|
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block); |
|
da.Analyze("a"); |
|
Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(block)); |
|
} |
|
|
|
[Test] |
|
public void ConditionalExpression2() |
|
{ |
|
string code = "int a; int b = X ? (a = 1) : (a = 2);"; |
|
var block = new BlockStatement(); |
|
block.Statements.AddRange(new CSharpParser().ParseStatements(code)); |
|
|
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block); |
|
da.Analyze("a"); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(block)); |
|
} |
|
|
|
[Test] |
|
public void ConditionalExpression3() |
|
{ |
|
string code = "int a; int b = true ? (a = 1) : 0;"; |
|
var block = new BlockStatement(); |
|
block.Statements.AddRange(new CSharpParser().ParseStatements(code)); |
|
|
|
DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block); |
|
da.Analyze("a"); |
|
Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(block)); |
|
} |
|
} |
|
}
|
|
|