Skip to content

Commit 143541a

Browse files
committed
Merge remote-tracking branch 'upstream/next' into next
2 parents 21cb970 + e5d31d8 commit 143541a

33 files changed

+2380
-187
lines changed

Rubberduck.CodeAnalysis/Inspections/Concrete/NonReturningFunctionInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
5151
private bool IsAssignedByRefArgument(Declaration enclosingProcedure, IdentifierReference reference)
5252
{
5353
var argExpression = reference.Context.GetAncestor<VBAParser.ArgumentExpressionContext>();
54-
var parameter = State.DeclarationFinder.FindParameterFromArgument(argExpression, enclosingProcedure);
54+
var parameter = State.DeclarationFinder.FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly(argExpression, enclosingProcedure);
5555

5656
// note: not recursive, by design.
5757
return parameter != null

Rubberduck.CodeAnalysis/Inspections/Concrete/ParameterCanBeByValInspection.cs

Lines changed: 167 additions & 91 deletions
Large diffs are not rendered by default.

Rubberduck.CodeAnalysis/Inspections/Concrete/UnassignedVariableUsageInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
5454
private bool IsAssignedByRefArgument(Declaration enclosingProcedure, IdentifierReference reference)
5555
{
5656
var argExpression = reference.Context.GetAncestor<VBAParser.ArgumentExpressionContext>();
57-
var parameter = State.DeclarationFinder.FindParameterFromArgument(argExpression, enclosingProcedure);
57+
var parameter = State.DeclarationFinder.FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly(argExpression, enclosingProcedure);
5858

5959
// note: not recursive, by design.
6060
return parameter != null

Rubberduck.CodeAnalysis/Inspections/Concrete/VariableNotAssignedInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
3737
private bool IsAssignedByRefArgument(Declaration enclosingProcedure, IdentifierReference reference)
3838
{
3939
var argExpression = reference.Context.GetAncestor<VBAParser.ArgumentExpressionContext>();
40-
var parameter = State.DeclarationFinder.FindParameterFromArgument(argExpression, enclosingProcedure);
40+
var parameter = State.DeclarationFinder.FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly(argExpression, enclosingProcedure);
4141

4242
// note: not recursive, by design.
4343
return parameter != null

Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs

Lines changed: 150 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Diagnostics;
55
using System.Linq;
6+
using System.Runtime.InteropServices.WindowsRuntime;
67
using Antlr4.Runtime;
78
using NLog;
89
using Rubberduck.Parsing.Annotations;
@@ -475,16 +476,16 @@ public IEnumerable<ModuleBodyElementDeclaration> FindInterfaceImplementationMemb
475476
: Enumerable.Empty<ModuleBodyElementDeclaration>();
476477
}
477478

478-
public ParameterDeclaration FindParameter(Declaration procedure, string parameterName)
479+
public ParameterDeclaration FindParameter(Declaration parameterizedMember, string parameterName)
479480
{
480-
return _parametersByParent.TryGetValue(procedure, out List<ParameterDeclaration> parameters)
481+
return _parametersByParent.TryGetValue(parameterizedMember, out List<ParameterDeclaration> parameters)
481482
? parameters.SingleOrDefault(parameter => parameter.IdentifierName == parameterName)
482483
: null;
483484
}
484485

485-
public IEnumerable<ParameterDeclaration> Parameters(Declaration procedure)
486+
public IEnumerable<ParameterDeclaration> Parameters(Declaration parameterizedMember)
486487
{
487-
return _parametersByParent.TryGetValue(procedure, out List<ParameterDeclaration> result)
488+
return _parametersByParent.TryGetValue(parameterizedMember, out List<ParameterDeclaration> result)
488489
? result
489490
: Enumerable.Empty<ParameterDeclaration>();
490491
}
@@ -542,46 +543,34 @@ public IEnumerable<Declaration> MatchName(string name)
542543
: Enumerable.Empty<Declaration>();
543544
}
544545

545-
public ParameterDeclaration FindParameterFromArgument(VBAParser.ArgumentExpressionContext argExpression, Declaration enclosingProcedure)
546+
public ParameterDeclaration FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly(VBAParser.ArgumentExpressionContext argumentExpression, Declaration enclosingProcedure)
546547
{
547-
if (argExpression == null ||
548-
argExpression.GetDescendent<VBAParser.ParenthesizedExprContext>() != null ||
549-
argExpression.BYVAL() != null)
550-
{
551-
// not an argument, or argument is parenthesized and thus passed ByVal
552-
return null;
553-
}
554-
555-
var callStmt = argExpression.GetAncestor<VBAParser.CallStmtContext>();
556-
557-
var identifier = callStmt?
558-
.GetDescendent<VBAParser.LExpressionContext>()
559-
.GetDescendents<VBAParser.IdentifierContext>()
560-
.LastOrDefault();
548+
return FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly(argumentExpression, enclosingProcedure.QualifiedModuleName);
549+
}
561550

562-
if (identifier == null)
563-
{
564-
// if we don't know what we're calling, we can't dig any further
565-
return null;
566-
}
551+
public ParameterDeclaration FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly(VBAParser.ArgumentExpressionContext argumentExpression, QualifiedModuleName module)
552+
{
553+
//todo: Rename after making it work for more general cases.
567554

568-
var selection = new QualifiedSelection(enclosingProcedure.QualifiedModuleName, identifier.GetSelection());
569-
if (!_referencesBySelection.TryGetValue(selection, out var matches))
555+
if (argumentExpression == null
556+
|| argumentExpression.GetDescendent<VBAParser.ParenthesizedExprContext>() != null
557+
|| argumentExpression.BYVAL() != null)
570558
{
559+
// not a simple argument, or argument is parenthesized and thus passed ByVal
571560
return null;
572561
}
573562

574-
var procedure = matches.SingleOrDefault()?.Declaration;
575-
if (procedure?.ParentScopeDeclaration is ClassModuleDeclaration)
563+
var callingNonDefaultMember = CallingNonDefaultMember(argumentExpression, module);
564+
if (callingNonDefaultMember == null)
576565
{
577-
// we can't know that the member is on the class' default interface
566+
// Either we could not resolve the call or there is a default member call involved.
578567
return null;
579568
}
580569

581-
var parameters = Parameters(procedure);
570+
var parameters = Parameters(callingNonDefaultMember);
582571

583572
ParameterDeclaration parameter;
584-
var namedArg = argExpression.GetAncestor<VBAParser.NamedArgumentContext>();
573+
var namedArg = argumentExpression.GetAncestor<VBAParser.NamedArgumentContext>();
585574
if (namedArg != null)
586575
{
587576
// argument is named: we're lucky
@@ -591,12 +580,12 @@ public ParameterDeclaration FindParameterFromArgument(VBAParser.ArgumentExpressi
591580
else
592581
{
593582
// argument is positional: work out its index
594-
var argList = callStmt.GetDescendent<VBAParser.ArgumentListContext>();
595-
var args = argList.GetDescendents<VBAParser.PositionalArgumentContext>().ToArray();
583+
var argumentList = argumentExpression.GetAncestor<VBAParser.ArgumentListContext>();
584+
var arguments = argumentList.GetDescendents<VBAParser.PositionalArgumentContext>().ToArray();
596585

597-
var parameterIndex = args
598-
.Select((param, index) => param.GetDescendent<VBAParser.ArgumentExpressionContext>() == argExpression ? (param, index) : (null, -1))
599-
.SingleOrDefault(item => item.param != null).index;
586+
var parameterIndex = arguments
587+
.Select((arg, index) => arg.GetDescendent<VBAParser.ArgumentExpressionContext>() == argumentExpression ? (arg, index) : (null, -1))
588+
.SingleOrDefault(item => item.arg != null).index;
600589

601590
parameter = parameters
602591
.OrderBy(p => p.Selection)
@@ -607,6 +596,121 @@ public ParameterDeclaration FindParameterFromArgument(VBAParser.ArgumentExpressi
607596
return parameter;
608597
}
609598

599+
private ModuleBodyElementDeclaration CallingNonDefaultMember(VBAParser.ArgumentExpressionContext argumentExpression, QualifiedModuleName module)
600+
{
601+
//todo: Make this work for default member calls.
602+
603+
var argumentList = argumentExpression.GetAncestor<VBAParser.ArgumentListContext>();
604+
var cannotHaveDefaultMemberCall = false;
605+
606+
ParserRuleContext callingExpression;
607+
switch (argumentList.Parent)
608+
{
609+
case VBAParser.CallStmtContext callStmt:
610+
cannotHaveDefaultMemberCall = true;
611+
callingExpression = callStmt.lExpression();
612+
break;
613+
case VBAParser.IndexExprContext indexExpr:
614+
callingExpression = indexExpr.lExpression();
615+
break;
616+
case VBAParser.WhitespaceIndexExprContext indexExpr:
617+
callingExpression = indexExpr.lExpression();
618+
break;
619+
default:
620+
//This should never happen.
621+
return null;
622+
}
623+
624+
VBAParser.IdentifierContext callingIdentifier;
625+
if (cannotHaveDefaultMemberCall)
626+
{
627+
callingIdentifier = callingExpression
628+
.GetDescendents<VBAParser.IdentifierContext>()
629+
.LastOrDefault();
630+
}
631+
else
632+
{
633+
switch (callingExpression)
634+
{
635+
case VBAParser.SimpleNameExprContext simpleName:
636+
callingIdentifier = simpleName.identifier();
637+
break;
638+
case VBAParser.MemberAccessExprContext memberAccess:
639+
callingIdentifier = memberAccess
640+
.GetDescendents<VBAParser.IdentifierContext>()
641+
.LastOrDefault();
642+
break;
643+
case VBAParser.WithMemberAccessExprContext memberAccess:
644+
callingIdentifier = memberAccess
645+
.GetDescendents<VBAParser.IdentifierContext>()
646+
.LastOrDefault();
647+
break;
648+
default:
649+
//This is only possible in case of a default member access.
650+
return null;
651+
}
652+
}
653+
654+
if (callingIdentifier == null)
655+
{
656+
return null;
657+
}
658+
659+
var referencedMember = IdentifierReferences(callingIdentifier, module)
660+
.Select(reference => reference.Declaration)
661+
.OfType<ModuleBodyElementDeclaration>()
662+
.FirstOrDefault();
663+
664+
return referencedMember;
665+
}
666+
667+
public ParameterDeclaration FindParameterFromSimpleEventArgumentNotPassedByValExplicitly(VBAParser.EventArgumentContext eventArgument, QualifiedModuleName module)
668+
{
669+
if (eventArgument == null
670+
|| eventArgument.GetDescendent<VBAParser.ParenthesizedExprContext>() != null
671+
|| eventArgument.BYVAL() != null)
672+
{
673+
// not a simple argument, or argument is parenthesized and thus passed ByVal
674+
return null;
675+
}
676+
677+
var raisedEvent = RaisedEvent(eventArgument, module);
678+
if (raisedEvent == null)
679+
{
680+
return null;
681+
}
682+
683+
var parameters = Parameters(raisedEvent);
684+
685+
// event arguments are always positional: work out the index
686+
var argumentList = eventArgument.GetAncestor<VBAParser.EventArgumentListContext>();
687+
var arguments = argumentList.eventArgument();
688+
689+
var parameterIndex = arguments
690+
.Select((arg, index) => arg == eventArgument ? (arg, index) : (null, -1))
691+
.SingleOrDefault(tpl => tpl.arg != null).index;
692+
693+
var parameter = parameters
694+
.OrderBy(p => p.Selection)
695+
.Select((param, index) => (param, index))
696+
.SingleOrDefault(tpl => tpl.index == parameterIndex).param;
697+
698+
return parameter;
699+
}
700+
701+
private EventDeclaration RaisedEvent(VBAParser.EventArgumentContext argument, QualifiedModuleName module)
702+
{
703+
var raiseEventContext = argument.GetAncestor<VBAParser.RaiseEventStmtContext>();
704+
var eventIdentifier = raiseEventContext.identifier();
705+
706+
var referencedMember = IdentifierReferences(eventIdentifier, module)
707+
.Select(reference => reference.Declaration)
708+
.OfType<EventDeclaration>()
709+
.FirstOrDefault();
710+
711+
return referencedMember;
712+
}
713+
610714
private string ToNormalizedName(string name)
611715
{
612716
var lower = name.ToLowerInvariant();
@@ -1253,6 +1357,16 @@ public IEnumerable<IdentifierReference> IdentifierReferences(QualifiedModuleName
12531357
: Enumerable.Empty<IdentifierReference>();
12541358
}
12551359

1360+
/// <summary>
1361+
/// Gets all identifier references for an IdentifierContext.
1362+
/// </summary>
1363+
public IEnumerable<IdentifierReference> IdentifierReferences(VBAParser.IdentifierContext identifierContext, QualifiedModuleName module)
1364+
{
1365+
var qualifiedSelection = new QualifiedSelection(module, identifierContext.GetSelection());
1366+
return IdentifierReferences(qualifiedSelection)
1367+
.Where(identifierReference => identifierReference.IdentifierName.Equals(identifierContext.GetText()));
1368+
}
1369+
12561370
/// <summary>
12571371
/// Gets all identifier references with the specified selection.
12581372
/// </summary>

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.cs.resx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,28 @@
243243
<data name="CodeExplorer_AddFormText" xml:space="preserve">
244244
<value>UserForm (.frm)</value>
245245
</data>
246+
<data name="CodeExplorer_AddMDIFormText" xml:space="preserve">
247+
<value>MDI form (.frm)</value>
248+
</data>
249+
<data name="CodeExplorer_AddPropertyPageText" xml:space="preserve">
250+
<value>Property stránka (.pag)</value>
251+
</data>
252+
<data name="CodeExplorer_AddUserControlText" xml:space="preserve">
253+
<value>UserControl (.ctl)</value>
254+
</data>
255+
<data name="CodeExplorer_AddUserDocumentText" xml:space="preserve">
256+
<value>Uživatelský dokument (.dob)</value>
257+
</data>
258+
<data name="CodeExplorer_AddVBFormText" xml:space="preserve">
259+
<value>Form (.frm)</value>
260+
</data>
261+
<data name="CodeExplorer_Rename" xml:space="preserve">
262+
<value>Přejmenovat</value>
263+
</data>
264+
<data name="CodeExplorer_SetAsStartupProject" xml:space="preserve">
265+
<value>Startovací projekt</value>
266+
</data>
267+
<data name="CodeExplorer_AddTemplatesSubMenu" xml:space="preserve">
268+
<value>Šablony</value>
269+
</data>
246270
</root>

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.fr.resx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,28 @@
261261
<data name="CodeExplorer_SetAsStartupProject" xml:space="preserve">
262262
<value>Lancer au démarrage</value>
263263
</data>
264+
<data name="CodeExplorer_AddTemplatesSubMenu" xml:space="preserve">
265+
<value>Modèles</value>
266+
</data>
267+
<data name="CodeExplorer_FontSizeToolTip" xml:space="preserve">
268+
<value>Taille du texte</value>
269+
</data>
270+
<data name="CodeExplorer_LibraryReferences" xml:space="preserve">
271+
<value>Bibliothèques</value>
272+
</data>
273+
<data name="CodeExplorer_ProjectReferences" xml:space="preserve">
274+
<value>Projets</value>
275+
</data>
276+
<data name="CodeExplorer_SearchPlaceholder" xml:space="preserve">
277+
<value>Rechercher...</value>
278+
</data>
279+
<data name="CodeExplorer_SyncCodePaneToolTip" xml:space="preserve">
280+
<value>Synchroniser la sélection courante</value>
281+
</data>
282+
<data name="ExportError_Caption" xml:space="preserve">
283+
<value>Erreur lors de l'exportation de '{0}'</value>
284+
</data>
285+
<data name="RemoveError_Caption" xml:space="preserve">
286+
<value>Erreur lors de la suppression de '{0}'</value>
287+
</data>
264288
</root>

0 commit comments

Comments
 (0)