Skip to content

Commit ca317ad

Browse files
committed
Make printStmt in the grammar compatible with unqualified VB6 form print statements
This also includes an amendment to the resolver to deal with these statements.
1 parent a15e2b6 commit ca317ad

File tree

8 files changed

+83
-12
lines changed

8 files changed

+83
-12
lines changed

Rubberduck.Parsing/Binding/Bindings/ObjectPrintDefaultBinding.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@ namespace Rubberduck.Parsing.Binding
55
public sealed class ObjectPrintDefaultBinding : IExpressionBinding
66
{
77
private readonly ParserRuleContext _context;
8-
private readonly IExpressionBinding _memberAccessBinding;
8+
private readonly IExpressionBinding _printMethodBinding;
99
private readonly IExpressionBinding _outputListBinding;
1010

1111
public ObjectPrintDefaultBinding(
1212
ParserRuleContext context,
13-
IExpressionBinding memberAccessBinding,
13+
IExpressionBinding printMethodBinding,
1414
IExpressionBinding outputListBinding)
1515
{
1616
_context = context;
17-
_memberAccessBinding = memberAccessBinding;
17+
_printMethodBinding = printMethodBinding;
1818
_outputListBinding = outputListBinding;
1919
}
2020

2121
public IBoundExpression Resolve()
2222
{
23-
var memberAccessExpression = _memberAccessBinding.Resolve();
23+
var printMethodExpression = _printMethodBinding.Resolve();
2424
var outputListExpression = _outputListBinding.Resolve();
25-
return new ObjectPrintExpression(_context, memberAccessExpression, outputListExpression);
25+
return new ObjectPrintExpression(_context, printMethodExpression, outputListExpression);
2626
}
2727
}
2828
}

Rubberduck.Parsing/Binding/DefaultBindingContext.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public IExpressionBinding Visit(Declaration module, Declaration parent, IParseTr
7373
return Visit(module, parent, integerExpressionContext, withBlockVariable);
7474
case VBAParser.OutputListContext outputListContext:
7575
return Visit(module, parent, outputListContext, withBlockVariable);
76+
case VBAParser.PrintStmtContext printStmtContext:
77+
return Visit(module, parent, printStmtContext, withBlockVariable);
7678
default:
7779
throw new NotSupportedException($"Unexpected context type {expression.GetType()}");
7880
}
@@ -264,6 +266,25 @@ private IExpressionBinding Visit(Declaration module, Declaration parent, VBAPars
264266
return new ObjectPrintDefaultBinding(expression, memberAccessBinding, outputListBinding);
265267
}
266268

269+
private IExpressionBinding Visit(Declaration module, Declaration parent, VBAParser.PrintStmtContext expression, IBoundExpression withBlockVariable)
270+
{
271+
var printMethodContext = expression.printMethod();
272+
var simpleNameBinding = new SimpleNameDefaultBinding(
273+
_declarationFinder,
274+
Declaration.GetProjectParent(parent),
275+
module,
276+
parent,
277+
printMethodContext,
278+
printMethodContext.GetText(),
279+
StatementResolutionContext.Undefined);
280+
var outputListBinding = Visit(
281+
module,
282+
parent,
283+
expression.outputList(),
284+
withBlockVariable);
285+
return new ObjectPrintDefaultBinding(expression, simpleNameBinding, outputListBinding);
286+
}
287+
267288
private IExpressionBinding Visit(Declaration module, Declaration parent, VBAParser.IndexExprContext expression, IBoundExpression withBlockVariable)
268289
{
269290
var lExpression = expression.lExpression();

Rubberduck.Parsing/Binding/Expressions/ObjectPrintExpression.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ public sealed class ObjectPrintExpression : BoundExpression
66
{
77
public ObjectPrintExpression(
88
ParserRuleContext context,
9-
IBoundExpression memberAccessExpression,
9+
IBoundExpression printMethodExpression,
1010
IBoundExpression outputListBoundExpression)
1111
: base(null, ExpressionClassification.Subroutine, context)
1212
{
13-
MemberAccessExpressions = memberAccessExpression;
13+
PrintMethodExpressions = printMethodExpression;
1414
OutputListExpression = outputListBoundExpression;
1515
}
1616

17-
public IBoundExpression MemberAccessExpressions { get; }
17+
public IBoundExpression PrintMethodExpressions { get; }
1818
public IBoundExpression OutputListExpression { get; }
1919
}
2020
}

Rubberduck.Parsing/Grammar/VBAParser.g4

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,10 @@ lineWidth : expression;
257257

258258

259259
// 5.4.5.8 Print Statement
260+
//We make the part regarding the file handle optional to support VB6's print statement in forms.
261+
//It is an invocation of the Print member of the enclosing form, which also takes an output list as argument.
260262
printMethod : PRINT;
261-
printStmt : PRINT whiteSpace markedFileNumber whiteSpace? COMMA (whiteSpace? outputList)?;
263+
printStmt : printMethod (whiteSpace markedFileNumber whiteSpace? COMMA)? (whiteSpace? outputList)?;
262264

263265
// 5.4.5.8.1 Output Lists
264266
outputList : outputItem (whiteSpace? outputItem)*;

Rubberduck.Parsing/VBA/ReferenceManagement/BoundExpressionVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ private void Visit(
186186
Declaration parent)
187187
{
188188
Visit(expression.OutputListExpression, module, scope, parent);
189-
Visit(expression.MemberAccessExpressions, module, scope, parent);
189+
Visit(expression.PrintMethodExpressions, module, scope, parent);
190190
}
191191

192192
private void Visit(

Rubberduck.Parsing/VBA/ReferenceManagement/FailedResolutionVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ private void Visit(MemberAccessExpression expression, Declaration parent, IBound
116116
private void Visit(ObjectPrintExpression expression, Declaration parent, IBoundExpression withExpression)
117117
{
118118
Visit(expression.OutputListExpression, parent, withExpression);
119-
Visit(expression.MemberAccessExpressions, parent, withExpression);
119+
Visit(expression.PrintMethodExpressions, parent, withExpression);
120120
}
121121

122122
private void Visit(OutputListExpression expression, Declaration parent, IBoundExpression withExpression)

Rubberduck.Parsing/VBA/ReferenceManagement/IdentifierReferenceResolver.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,19 @@ public void Resolve(VBAParser.WidthStmtContext context)
500500
}
501501

502502
public void Resolve(VBAParser.PrintStmtContext context)
503+
{
504+
if (context.markedFileNumber() != null)
505+
{
506+
ResolvePrintStatement(context);
507+
}
508+
else
509+
{
510+
//Since there is no file handle, this must be an unqualified print member call in a VB6 form.
511+
ResolveDefault(context);
512+
}
513+
}
514+
515+
public void ResolvePrintStatement(VBAParser.PrintStmtContext context)
503516
{
504517
ResolveDefault(context.markedFileNumber().expression(), true);
505518
ResolveOutputList(context.outputList());

RubberduckTests/Grammar/ResolverTests.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2244,14 +2244,49 @@ Dim referenced As String
22442244
End Sub";
22452245
using (var state = Resolve(code))
22462246
{
2247-
22482247
var declaration = state.AllUserDeclarations.Single(item =>
22492248
item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "referenced");
22502249

22512250
Assert.AreEqual(7, declaration.References.Count());
22522251
}
22532252
}
22542253

2254+
[Category("Grammar")]
2255+
[Category("Resolver")]
2256+
[Test]
2257+
//This form is legal inside VB6 forms and other classes implementing the IVBPrint COM interface.
2258+
//To simplify the test we use a dummy Sub in the class instead, which cannot be defined in regular VBA.
2259+
public void UnqualifiedObjectPrintExpr_IsReferencePrintOnContainingModule()
2260+
{
2261+
var code = @"
2262+
Sub Test()
2263+
Dim obj As Object
2264+
Dim referenced As String
2265+
Print referenced;referenced, referenced , referenced ;
2266+
End Sub
2267+
2268+
Public Sub Print()
2269+
End Sub
2270+
";
2271+
using (var state = Resolve(code, false, ComponentType.ClassModule))
2272+
{
2273+
var referencedDeclaration = state.DeclarationFinder
2274+
.UserDeclarations(DeclarationType.Variable)
2275+
.Single(item => item.IdentifierName == "referenced");
2276+
var printDeclaration = state.DeclarationFinder
2277+
.UserDeclarations(DeclarationType.Procedure)
2278+
.Single(item => item.IdentifierName == "Print");
2279+
var printReference = printDeclaration.References.Single();
2280+
2281+
var module = state.DeclarationFinder.AllModules.Single(qmn => qmn.ComponentType == ComponentType.ClassModule);
2282+
var expectedPrintSelection = new QualifiedSelection(module, new Selection(5, 5,5, 10));
2283+
var actualPrintSelection = new QualifiedSelection(printReference.QualifiedModuleName, printReference.Selection);
2284+
2285+
Assert.AreEqual(4, referencedDeclaration.References.Count());
2286+
Assert.AreEqual(expectedPrintSelection, actualPrintSelection);
2287+
}
2288+
}
2289+
22552290
[Category("Grammar")]
22562291
[Category("Resolver")]
22572292
[Test]

0 commit comments

Comments
 (0)