public void TestBinaryOperatorTypeConversions(string opText, string leftText, string rightText, string expectedResult) { var left = ExpressionTestUtility.GetValue(leftText); var right = ExpressionTestUtility.GetValue(rightText); var source = $"{left} {opText} {right}"; var syntaxTree = SyntaxFactory.ParseExpression(source); var syntaxTreeSource = syntaxTree.Root.ToString(); if (syntaxTreeSource != source) Assert.Fail($"Source should have been {syntaxTreeSource} but is {source}"); var expression = (BinaryExpressionSyntax)syntaxTree.Root; var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var leftType = ExpressionTestUtility.GetExpressionTypeString(semanticModel.GetExpressionType(expression.Left)); if (leftText != leftType) Assert.Fail($"Left should be of type '{leftText}' but has type '{leftType}'"); var rightType = ExpressionTestUtility.GetExpressionTypeString(semanticModel.GetExpressionType(expression.Right)); if (rightText != rightType) Assert.Fail($"Right should be of type '{rightText}' but has type '{rightType}'"); var diagnostic = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).SingleOrDefault(); var expressionType = semanticModel.GetExpressionType(expression); var result = diagnostic == null ? ExpressionTestUtility.GetExpressionTypeString(expressionType) : ExpressionTestUtility.GetErrorString(diagnostic.DiagnosticId); Assert.AreEqual(expectedResult, result, $"Expression {source} should have evaluated to '{expectedResult}' but was '{result}'"); }
public void AllowsMissingFunctionImplementationIfUnused() { var code = @"void foo();"; var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code)); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var diagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToImmutableArray(); Assert.That(diagnostics, Is.Empty); }
public void AllowsFunctionOverloads() { var code = @" void foo(int x) {} void foo() {}"; var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code)); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var diagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToImmutableArray(); Assert.That(diagnostics, Is.Empty); }
public void DetectsRedefinitionAsFunction() { var code = @" struct foo {}; void foo();"; var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code)); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var diagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToImmutableArray(); Assert.That(diagnostics, Has.Length.EqualTo(1)); Assert.That(diagnostics[0].DiagnosticId, Is.EqualTo(DiagnosticId.SymbolRedefined)); }
public void DetectsUndeclaredVariable() { var code = @" void main() { int foo = a; }"; var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code)); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var diagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToImmutableArray(); Assert.That(diagnostics, Has.Length.EqualTo(1)); Assert.That(diagnostics[0].DiagnosticId, Is.EqualTo(DiagnosticId.UndeclaredVariable)); }
public void TestFunctionOverloadResolution2Args(string type1, string type2, string expectedMatchTypes) { var code = $@" int foo(int x, float y) {{ return 1; }} int foo(float x, float y) {{ return 2; }} int foo(double x, float y) {{ return 3; }} int foo(float x, int y) {{ return 4; }} int foo(float x, double y) {{ return 5; }} int foo(double x, int y) {{ return 6; }} int foo(int2 x, float y) {{ return 7; }} int foo(float2 x, float y) {{ return 8; }} int foo(double2 x, float y) {{ return 9; }} int foo(float3x3 x, float y) {{ return 10; }} void main() {{ foo({ExpressionTestUtility.GetValue(type1)}, {ExpressionTestUtility.GetValue(type2)}); }}"; var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code)); var syntaxTreeSource = syntaxTree.Root.ToFullString(); Assert.AreEqual(code, syntaxTreeSource, $"Source should have been {code} but is {syntaxTreeSource}."); var expression = (FunctionInvocationExpressionSyntax)syntaxTree.Root.ChildNodes .OfType <FunctionDefinitionSyntax>() .Where(x => x.Name.GetName() == "main") .Select(x => ((ExpressionStatementSyntax)x.Body.Statements[0]).Expression) .First(); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var combinedDiagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToList(); foreach (var d in combinedDiagnostics) { Debug.WriteLine(d); } var invokedFunctionSymbol = (FunctionSymbol)semanticModel.GetSymbol(expression); var diagnostic = combinedDiagnostics.SingleOrDefault(x => x.Severity == Diagnostics.DiagnosticSeverity.Error); var result = diagnostic == null ? $"{SymbolMarkup.ForSymbol(invokedFunctionSymbol.Parameters[0].ValueType)}, {SymbolMarkup.ForSymbol(invokedFunctionSymbol.Parameters[1].ValueType)}" : ExpressionTestUtility.GetErrorString(diagnostic.DiagnosticId); Assert.AreEqual(expectedMatchTypes, result, $"Expression should have matched the function overload '{expectedMatchTypes}' but it actually matched '{result}'."); }
public void SemanticModelForStructAndFunction() { var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(@" struct MyStruct { float a; int b; }; void MyFunc() { MyStruct s; s.a = 1.0; }")); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var structDefinition = (TypeDeclarationStatementSyntax)syntaxTree.Root.ChildNodes[0]; var functionDefinition = (FunctionDefinitionSyntax)syntaxTree.Root.ChildNodes[1]; var variableDeclaration = (VariableDeclarationStatementSyntax)functionDefinition.Body.Statements[0]; var assignmentStatement = (ExpressionStatementSyntax)functionDefinition.Body.Statements[1]; var structSymbol = semanticModel.GetDeclaredSymbol((StructTypeSyntax)structDefinition.Type); Assert.That(structSymbol, Is.Not.Null); Assert.That(structSymbol.Name, Is.EqualTo("MyStruct")); Assert.That(structSymbol.Members, Has.Length.EqualTo(2)); var functionSymbol = semanticModel.GetDeclaredSymbol(functionDefinition); Assert.That(functionSymbol, Is.Not.Null); Assert.That(functionSymbol.Name, Is.EqualTo("MyFunc")); Assert.That(functionSymbol.ReturnType, Is.EqualTo(IntrinsicTypes.Void)); var variableSymbol = semanticModel.GetDeclaredSymbol(variableDeclaration.Declaration.Variables[0]); Assert.That(variableSymbol, Is.Not.Null); Assert.That(variableSymbol.Name, Is.EqualTo("s")); Assert.That(variableSymbol.ValueType, Is.Not.Null); Assert.That(variableSymbol.ValueType, Is.EqualTo(structSymbol)); var assignmentExpressionType = semanticModel.GetExpressionType(assignmentStatement.Expression); Assert.That(assignmentExpressionType, Is.Not.Null); Assert.That(assignmentExpressionType, Is.EqualTo(IntrinsicTypes.Float)); }
public void DetectsMissingFunctionImplementation() { var code = @" void foo(); void main() { foo(); }"; var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code)); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var diagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToImmutableArray(); Assert.That(diagnostics, Has.Length.EqualTo(1)); Assert.That(diagnostics[0].DiagnosticId, Is.EqualTo(DiagnosticId.FunctionMissingImplementation)); }
public void CanGetSemanticModel(string testFile) { var sourceCode = File.ReadAllText(testFile); // Build syntax tree. var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(sourceCode), fileSystem: new TestFileSystem(testFile)); ShaderTestUtility.CheckForParseErrors(syntaxTree); // Get semantic model. var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); Assert.That(semanticModel, Is.Not.Null); foreach (var diagnostic in semanticModel.GetDiagnostics()) Debug.WriteLine(diagnostic); Assert.That(semanticModel.GetDiagnostics().Count(x => x.Severity == DiagnosticSeverity.Error), Is.EqualTo(0)); }
public void TestFunctionOverloadResolution1Arg(string type, string expectedMatchType) { var code = $@" struct MyStruct {{}}; int foo(int x) {{ return 1; }} int foo(float x) {{ return 2; }} int foo(double x) {{ return 3; }} int foo(int2 x) {{ return 4; }} int foo(float2 x) {{ return 5; }} int foo(double2 x) {{ return 6; }} int foo(float3x3 x) {{ return 7; }} void main() {{ foo(({type}) 0); }}"; var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code)); var syntaxTreeSource = syntaxTree.Root.ToFullString(); Assert.AreEqual(code, syntaxTreeSource, $"Source should have been {code} but is {syntaxTreeSource}."); var expression = (FunctionInvocationExpressionSyntax) syntaxTree.Root.ChildNodes .OfType<FunctionDefinitionSyntax>() .Where(x => x.Name.GetName() == "main") .Select(x => ((ExpressionStatementSyntax) x.Body.Statements[0]).Expression) .First(); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var combinedDiagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToList(); foreach (var d in combinedDiagnostics) Debug.WriteLine(d); var invokedFunctionSymbol = (FunctionSymbol) semanticModel.GetSymbol(expression); var diagnostic = combinedDiagnostics.SingleOrDefault(x => x.Severity == Diagnostics.DiagnosticSeverity.Error); var result = diagnostic == null ? ExpressionTestUtility.GetExpressionTypeString(invokedFunctionSymbol.Parameters[0].ValueType) : ExpressionTestUtility.GetErrorString(diagnostic.DiagnosticId); Assert.AreEqual(expectedMatchType, result, $"Expression should have matched the function overload '{expectedMatchType}' but it actually matched '{result}'."); }
public void SemanticModelForStructAndFunction() { var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(@" struct MyStruct { float a; int b; }; void MyFunc() { MyStruct s; s.a = 1.0; }")); var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var structDefinition = (TypeDeclarationStatementSyntax) syntaxTree.Root.ChildNodes[0]; var functionDefinition = (FunctionDefinitionSyntax) syntaxTree.Root.ChildNodes[1]; var variableDeclaration = (VariableDeclarationStatementSyntax) functionDefinition.Body.Statements[0]; var assignmentStatement = (ExpressionStatementSyntax) functionDefinition.Body.Statements[1]; var structSymbol = semanticModel.GetDeclaredSymbol((StructTypeSyntax) structDefinition.Type); Assert.That(structSymbol, Is.Not.Null); Assert.That(structSymbol.Name, Is.EqualTo("MyStruct")); Assert.That(structSymbol.Members, Has.Length.EqualTo(2)); var functionSymbol = semanticModel.GetDeclaredSymbol(functionDefinition); Assert.That(functionSymbol, Is.Not.Null); Assert.That(functionSymbol.Name, Is.EqualTo("MyFunc")); Assert.That(functionSymbol.ReturnType, Is.EqualTo(IntrinsicTypes.Void)); var variableSymbol = semanticModel.GetDeclaredSymbol(variableDeclaration.Declaration.Variables[0]); Assert.That(variableSymbol, Is.Not.Null); Assert.That(variableSymbol.Name, Is.EqualTo("s")); Assert.That(variableSymbol.ValueType, Is.Not.Null); Assert.That(variableSymbol.ValueType, Is.EqualTo(structSymbol)); var assignmentExpressionType = semanticModel.GetExpressionType(assignmentStatement.Expression); Assert.That(assignmentExpressionType, Is.Not.Null); Assert.That(assignmentExpressionType, Is.EqualTo(IntrinsicTypes.Float)); }
public void CanGetSemanticModel(string testFile) { var sourceCode = File.ReadAllText(testFile); // Build syntax tree. var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(sourceCode), fileSystem: new TestFileSystem(testFile)); ShaderTestUtility.CheckForParseErrors(syntaxTree); // Get semantic model. var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); Assert.That(semanticModel, Is.Not.Null); foreach (var diagnostic in semanticModel.GetDiagnostics()) { Debug.WriteLine(diagnostic); } Assert.That(semanticModel.GetDiagnostics().Count(x => x.Severity == DiagnosticSeverity.Error), Is.EqualTo(0)); }
public void TestBinaryOperatorTypeConversions(string opText, string leftText, string rightText, string expectedResult) { var left = ExpressionTestUtility.GetValue(leftText); var right = ExpressionTestUtility.GetValue(rightText); var source = $"{left} {opText} {right}"; var syntaxTree = SyntaxFactory.ParseExpression(source); var syntaxTreeSource = syntaxTree.Root.ToString(); if (syntaxTreeSource != source) { Assert.Fail($"Source should have been {syntaxTreeSource} but is {source}"); } var expression = (BinaryExpressionSyntax)syntaxTree.Root; var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var leftType = ExpressionTestUtility.GetExpressionTypeString(semanticModel.GetExpressionType(expression.Left)); if (leftText != leftType) { Assert.Fail($"Left should be of type '{leftText}' but has type '{leftType}'"); } var rightType = ExpressionTestUtility.GetExpressionTypeString(semanticModel.GetExpressionType(expression.Right)); if (rightText != rightType) { Assert.Fail($"Right should be of type '{rightText}' but has type '{rightType}'"); } var diagnostic = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).SingleOrDefault(); var expressionType = semanticModel.GetExpressionType(expression); var result = diagnostic == null ? ExpressionTestUtility.GetExpressionTypeString(expressionType) : ExpressionTestUtility.GetErrorString(diagnostic.DiagnosticId); Assert.AreEqual(expectedResult, result, $"Expression {source} should have evaluated to '{expectedResult}' but was '{result}'"); }
public void TestIntrinsicFunctionOverloading(string function, string type1, string type2, string expectedMatchTypes) { var expressionCode = $"{function}(({type1}) 0, ({type2}) 0)"; var syntaxTree = SyntaxFactory.ParseExpression(expressionCode); var syntaxTreeSource = syntaxTree.Root.ToFullString(); Assert.AreEqual(expressionCode, syntaxTreeSource, $"Source should have been {expressionCode} but is {syntaxTreeSource}."); var expression = (ExpressionSyntax) syntaxTree.Root; var compilation = new HlslTools.Compilation.Compilation(syntaxTree); var semanticModel = compilation.GetSemanticModel(); var combinedDiagnostics = syntaxTree.GetDiagnostics().Concat(semanticModel.GetDiagnostics()).ToList(); foreach (var d in combinedDiagnostics) Debug.WriteLine(d); var invokedFunctionSymbol = (FunctionSymbol) semanticModel.GetSymbol(expression); var diagnostic = combinedDiagnostics.SingleOrDefault(x => x.Severity == Diagnostics.DiagnosticSeverity.Error); var result = diagnostic == null ? $"{SymbolMarkup.ForSymbol(invokedFunctionSymbol.Parameters[0].ValueType)}, {SymbolMarkup.ForSymbol(invokedFunctionSymbol.Parameters[1].ValueType)}" : ExpressionTestUtility.GetErrorString(diagnostic.DiagnosticId); Assert.AreEqual(expectedMatchTypes, result, $"Expression should have matched the function overload '{expectedMatchTypes}' but it actually matched '{result}'."); }