Skip to content

Commit 760ec98

Browse files
cominternretailcoder
authored andcommitted
Fix ByRef, ParamArray, and array parameter declarations. (#1692)
* Fix ByRef and array determinations, added ParamArray support. * Forgot to remove some comments from test.
1 parent 71a9ab5 commit 760ec98

File tree

5 files changed

+64
-82
lines changed

5 files changed

+64
-82
lines changed

Rubberduck.Parsing/Rubberduck.Parsing.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
<Compile Include="Preprocessing\VBAConditionalCompilationParserListener.cs" />
129129
<Compile Include="Preprocessing\VBAConditionalCompilationParserVisitor.cs" />
130130
<Compile Include="Symbols\ComInformation.cs" />
131+
<Compile Include="Symbols\ComParameter.cs" />
131132
<Compile Include="Symbols\Identifier.cs" />
132133
<Compile Include="Binding\IBindingContext.cs" />
133134
<Compile Include="Binding\IBoundExpression.cs" />
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Rubberduck.Parsing.Symbols
8+
{
9+
public class ComParameter
10+
{
11+
public bool IsArray { get; set; }
12+
public bool IsByRef { get; set;}
13+
public string Name { get; set;}
14+
15+
public ComParameter(string name, bool byRef)
16+
{
17+
Name = name;
18+
IsByRef = byRef;
19+
}
20+
}
21+
}

Rubberduck.Parsing/Symbols/ParameterDeclaration.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ public class ParameterDeclaration : Declaration
88
{
99
private readonly bool _isOptional;
1010
private readonly bool _isByRef;
11-
private readonly bool _isParamArray;
1211

1312
/// <summary>
1413
/// Creates a new built-in parameter declaration.
@@ -39,7 +38,7 @@ public ParameterDeclaration(QualifiedMemberName qualifiedName,
3938
{
4039
_isOptional = isOptional;
4140
_isByRef = isByRef;
42-
_isParamArray = isParamArray;
41+
IsParamArray = isParamArray;
4342
}
4443

4544
/// <summary>
@@ -74,11 +73,11 @@ public ParameterDeclaration(QualifiedMemberName qualifiedName,
7473
{
7574
_isOptional = isOptional;
7675
_isByRef = isByRef;
77-
_isParamArray = isParamArray;
76+
IsParamArray = isParamArray;
7877
}
7978

8079
public bool IsOptional { get { return _isOptional; } }
8180
public bool IsByRef { get { return _isByRef; } }
82-
public bool IsParamArray { get { return _isParamArray; } }
81+
public bool IsParamArray { get; set; }
8382
}
8483
}

Rubberduck.Parsing/Symbols/ReferencedDeclarationsCollector.cs

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ public ReferencedDeclarationsCollector(RubberduckParserState state)
5555
_state = state;
5656
}
5757

58+
private static readonly HashSet<string> IgnoredInterfaceMembers = new HashSet<string> { "QueryInterface", "AddRef", "Release", "GetTypeInfoCount", "GetTypeInfo", "GetIDsOfNames", "Invoke" };
59+
5860
private static readonly IDictionary<VarEnum, string> TypeNames = new Dictionary<VarEnum, string>
5961
{
6062
{VarEnum.VT_DISPATCH, "DISPATCH"},
@@ -87,7 +89,7 @@ public ReferencedDeclarationsCollector(RubberduckParserState state)
8789

8890
private readonly Dictionary<Guid, ComInformation> _comInformation = new Dictionary<Guid, ComInformation>();
8991

90-
private string GetTypeName(TYPEDESC desc, ITypeInfo info)
92+
private ComParameter GetParameterInfo(TYPEDESC desc, ITypeInfo info)
9193
{
9294
var vt = (VarEnum)desc.vt;
9395
TYPEDESC tdesc;
@@ -96,7 +98,9 @@ private string GetTypeName(TYPEDESC desc, ITypeInfo info)
9698
{
9799
case VarEnum.VT_PTR:
98100
tdesc = (TYPEDESC)Marshal.PtrToStructure(desc.lpValue, typeof(TYPEDESC));
99-
return GetTypeName(tdesc, info);
101+
var pointer = GetParameterInfo(tdesc, info);
102+
pointer.IsByRef = true;
103+
return pointer;
100104
case VarEnum.VT_USERDEFINED:
101105
int href;
102106
unchecked
@@ -107,24 +111,29 @@ private string GetTypeName(TYPEDESC desc, ITypeInfo info)
107111
{
108112
ITypeInfo refTypeInfo;
109113
info.GetRefTypeInfo(href, out refTypeInfo);
110-
return GetTypeName(refTypeInfo);
114+
return new ComParameter(GetTypeName(refTypeInfo), false);
111115
}
112116
catch (Exception)
113117
{
114-
return "Object";
118+
return new ComParameter("Object", false);
115119
}
120+
case VarEnum.VT_SAFEARRAY:
116121
case VarEnum.VT_CARRAY:
122+
case VarEnum.VT_ARRAY:
117123
tdesc = (TYPEDESC)Marshal.PtrToStructure(desc.lpValue, typeof(TYPEDESC));
118-
return GetTypeName(tdesc, info) + "()";
124+
var array = GetParameterInfo(tdesc, info);
125+
array.IsArray = true;
126+
array.Name += "()";
127+
return array;
119128
default:
120129
string result;
121130
if (TypeNames.TryGetValue(vt, out result))
122131
{
123-
return result;
132+
return new ComParameter(result, false);
124133
}
125134
break;
126135
}
127-
return "Object";
136+
return new ComParameter("Object", false);
128137
}
129138

130139
private string GetTypeName(ITypeInfo info)
@@ -191,10 +200,9 @@ public List<Declaration> GetDeclarationsForReference(Reference reference)
191200

192201
IntPtr typeAttributesPointer;
193202
info.GetTypeAttr(out typeAttributesPointer);
194-
195203
var typeAttributes = (TYPEATTR)Marshal.PtrToStructure(typeAttributesPointer, typeof(TYPEATTR));
196-
197204
var attributes = new Attributes();
205+
198206
if (typeAttributes.wTypeFlags.HasFlag(TYPEFLAGS.TYPEFLAG_FPREDECLID))
199207
{
200208
attributes.AddPredeclaredIdTypeAttribute();
@@ -294,20 +302,25 @@ memberDeclaration is ICanBeDefaultMember &&
294302
}
295303
output.Add(memberDeclaration);
296304

297-
var parameterCount = memberDescriptor.cParams -
298-
(memberDescriptor.invkind.HasFlag(INVOKEKIND.INVOKE_PROPERTYGET) ? 0 : 1);
305+
var parameterCount = memberDescriptor.cParams - (memberDescriptor.invkind.HasFlag(INVOKEKIND.INVOKE_PROPERTYGET) ? 0 : 1);
306+
var parameters = new List<ParameterDeclaration>();
299307
for (var paramIndex = 0; paramIndex < parameterCount; paramIndex++)
300308
{
301309
var parameter = CreateParameterDeclaration(memberNames, paramIndex, memberDescriptor,
302310
member.TypeQualifiedModuleName, memberDeclaration, member.TypeInfo);
303311
var declaration = memberDeclaration as IDeclarationWithParameter;
304312
if (declaration != null)
305313
{
314+
parameters.Add(parameter);
306315
declaration.AddParameter(parameter);
307316
}
308317
output.Add(parameter);
309318
}
310319
member.TypeInfo.ReleaseFuncDesc(memberDescriptorPointer);
320+
if (parameters.Any() && memberDescriptor.cParamsOpt == -1)
321+
{
322+
parameters.Last().IsParamArray = true;
323+
}
311324
}
312325

313326
for (var fieldIndex = 0; fieldIndex < member.TypeAttributes.cVars; fieldIndex++)
@@ -337,10 +350,10 @@ private Declaration CreateMemberDeclaration(FUNCDESC memberDescriptor, TYPEKIND
337350
var funcValueType = (VarEnum)memberDescriptor.elemdescFunc.tdesc.vt;
338351
var memberDeclarationType = GetDeclarationType(memberName, memberDescriptor, funcValueType, typeKind, parentImplFlags);
339352

340-
var asTypeName = string.Empty;
353+
var asTypeName = new ComParameter(string.Empty, false);
341354
if (memberDeclarationType != DeclarationType.Procedure)
342355
{
343-
asTypeName = GetTypeName(memberDescriptor.elemdescFunc.tdesc, info);
356+
asTypeName = GetParameterInfo(memberDescriptor.elemdescFunc.tdesc, info);
344357
}
345358
var attributes = new Attributes();
346359
if (memberName == "_NewEnum" && ((FUNCFLAGS)memberDescriptor.wFuncFlags).HasFlag(FUNCFLAGS.FUNCFLAG_FNONBROWSABLE))
@@ -363,7 +376,7 @@ private Declaration CreateMemberDeclaration(FUNCDESC memberDescriptor, TYPEKIND
363376
new QualifiedMemberName(typeQualifiedModuleName, memberName),
364377
moduleDeclaration,
365378
moduleDeclaration,
366-
asTypeName,
379+
asTypeName.Name,
367380
Accessibility.Global,
368381
null,
369382
Selection.Home,
@@ -375,14 +388,13 @@ private Declaration CreateMemberDeclaration(FUNCDESC memberDescriptor, TYPEKIND
375388
new QualifiedMemberName(typeQualifiedModuleName, memberName),
376389
moduleDeclaration,
377390
moduleDeclaration,
378-
asTypeName,
391+
asTypeName.Name,
379392
null,
380393
null,
381394
Accessibility.Global,
382395
null,
383396
Selection.Home,
384-
// TODO: how to find out if it's an array?
385-
false,
397+
asTypeName.IsArray,
386398
true,
387399
null,
388400
attributes);
@@ -391,14 +403,13 @@ private Declaration CreateMemberDeclaration(FUNCDESC memberDescriptor, TYPEKIND
391403
new QualifiedMemberName(typeQualifiedModuleName, memberName),
392404
moduleDeclaration,
393405
moduleDeclaration,
394-
asTypeName,
406+
asTypeName.Name,
395407
null,
396408
null,
397409
Accessibility.Global,
398410
null,
399411
Selection.Home,
400-
// TODO: how to find out if it's an array?
401-
false,
412+
asTypeName.IsArray,
402413
true,
403414
null,
404415
attributes);
@@ -407,7 +418,7 @@ private Declaration CreateMemberDeclaration(FUNCDESC memberDescriptor, TYPEKIND
407418
new QualifiedMemberName(typeQualifiedModuleName, memberName),
408419
moduleDeclaration,
409420
moduleDeclaration,
410-
asTypeName,
421+
asTypeName.Name,
411422
Accessibility.Global,
412423
null,
413424
Selection.Home,
@@ -419,7 +430,7 @@ private Declaration CreateMemberDeclaration(FUNCDESC memberDescriptor, TYPEKIND
419430
new QualifiedMemberName(typeQualifiedModuleName, memberName),
420431
moduleDeclaration,
421432
moduleDeclaration,
422-
asTypeName,
433+
asTypeName.Name,
423434
Accessibility.Global,
424435
null,
425436
Selection.Home,
@@ -431,7 +442,7 @@ private Declaration CreateMemberDeclaration(FUNCDESC memberDescriptor, TYPEKIND
431442
new QualifiedMemberName(typeQualifiedModuleName, memberName),
432443
moduleDeclaration,
433444
moduleDeclaration,
434-
asTypeName,
445+
asTypeName.Name,
435446
null,
436447
false,
437448
false,
@@ -462,11 +473,11 @@ private Declaration CreateFieldDeclaration(ITypeInfo info, int fieldIndex, Decla
462473
var fieldName = names[0];
463474
var memberType = GetDeclarationType(varDesc, typeDeclarationType);
464475

465-
var asTypeName = GetTypeName(varDesc.elemdescVar.tdesc, info);
476+
var asTypeName = GetParameterInfo(varDesc.elemdescVar.tdesc, info);
466477
info.ReleaseVarDesc(ppVarDesc);
467478

468479
return new Declaration(new QualifiedMemberName(typeQualifiedModuleName, fieldName),
469-
moduleDeclaration, moduleDeclaration, asTypeName, null, false, false, Accessibility.Global, memberType, null,
480+
moduleDeclaration, moduleDeclaration, asTypeName.Name, null, false, false, Accessibility.Global, memberType, null,
470481
Selection.Home, false, null);
471482
}
472483

@@ -478,20 +489,10 @@ private ParameterDeclaration CreateParameterDeclaration(IReadOnlyList<string> me
478489
var paramPointer = new IntPtr(memberDescriptor.lprgelemdescParam.ToInt64() + Marshal.SizeOf(typeof(ELEMDESC)) * paramIndex);
479490
var elementDesc = (ELEMDESC)Marshal.PtrToStructure(paramPointer, typeof(ELEMDESC));
480491
var isOptional = elementDesc.desc.paramdesc.wParamFlags.HasFlag(PARAMFLAG.PARAMFLAG_FOPT);
481-
482-
var isByRef = elementDesc.desc.paramdesc.wParamFlags.HasFlag(PARAMFLAG.PARAMFLAG_FOUT);
483-
var isArray = false;
484492
var paramDesc = elementDesc.tdesc;
485-
var valueType = (VarEnum)paramDesc.vt;
486-
if (valueType == VarEnum.VT_CARRAY || valueType == VarEnum.VT_ARRAY || valueType == VarEnum.VT_SAFEARRAY)
487-
{
488-
// todo: tell ParamArray arrays from normal arrays
489-
isArray = true;
490-
}
491-
492-
var asParamTypeName = GetTypeName(paramDesc, info);
493+
var paramInfo = GetParameterInfo(paramDesc, info);
493494

494-
return new ParameterDeclaration(new QualifiedMemberName(typeQualifiedModuleName, paramName), memberDeclaration, asParamTypeName, null, null, isOptional, isByRef, isArray);
495+
return new ParameterDeclaration(new QualifiedMemberName(typeQualifiedModuleName, paramName), memberDeclaration, paramInfo.Name, null, null, isOptional, paramInfo.IsByRef, paramInfo.IsArray);
495496
}
496497

497498
private IEnumerable<string> GetImplementedInterfaceNames(TYPEATTR typeAttr, ITypeInfo info)
@@ -587,7 +588,7 @@ private DeclarationType GetDeclarationType(string memberName, FUNCDESC funcDesc,
587588
}
588589
else if ((parentImplTypeFlags.HasFlag(IMPLTYPEFLAGS.IMPLTYPEFLAG_FSOURCE) ||
589590
((FUNCFLAGS)funcDesc.wFuncFlags).HasFlag(FUNCFLAGS.FUNCFLAG_FSOURCE)) &&
590-
!new[] {"QueryInterface", "AddRef", "Release", "GetTypeInfoCount", "GetTypeInfo", "GetIDsOfNames", "Invoke"}.Contains(memberName)) // quick-and-dirty for beta
591+
!IgnoredInterfaceMembers.Contains(memberName)) // quick-and-dirty for beta
591592
{
592593
memberType = DeclarationType.Event;
593594
}

RubberduckTests/Settings/IndenterSettingsTests.cs

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -91,52 +91,12 @@ public static Rubberduck.SmartIndenter.IndenterSettings GetMockIndenterSettings(
9191

9292
private Configuration GetDefaultConfig()
9393
{
94-
//var indenterSettings = GetTestIndenterSettings();
95-
//{
96-
// indenterSettings.IndentEntireProcedureBody = true,
97-
// indenterSettings.IndentFirstCommentBlock = true,
98-
// indenterSettings.IndentFirstDeclarationBlock = true,
99-
// indenterSettings.AlignCommentsWithCode = true,
100-
// indenterSettings.AlignContinuations = true,
101-
// IgnoreOperatorsInContinuations = true,
102-
// IndentCase = false,
103-
// ForceDebugStatementsInColumn1 = false,
104-
// ForceCompilerDirectivesInColumn1 = false,
105-
// IndentCompilerDirectives = true,
106-
// AlignDims = false,
107-
// AlignDimColumn = 15,
108-
// EnableUndo = true,
109-
// EndOfLineCommentStyle = EndOfLineCommentStyle.AlignInColumn,
110-
// EndOfLineCommentColumnSpaceAlignment = 50,
111-
// IndentSpaces = 4
112-
//};
113-
11494
var userSettings = new UserSettings(null, null, null, null, null, GetMockIndenterSettings());
11595
return new Configuration(userSettings);
11696
}
11797

11898
private Configuration GetNondefaultConfig()
11999
{
120-
//var indenterSettings = new Rubberduck.SmartIndenter.IndenterSettings
121-
//{
122-
// IndentEntireProcedureBody = false,
123-
// IndentFirstCommentBlock = false,
124-
// IndentFirstDeclarationBlock = false,
125-
// AlignCommentsWithCode = false,
126-
// AlignContinuations = false,
127-
// IgnoreOperatorsInContinuations = false,
128-
// IndentCase = true,
129-
// ForceDebugStatementsInColumn1 = true,
130-
// ForceCompilerDirectivesInColumn1 = true,
131-
// IndentCompilerDirectives = false,
132-
// AlignDims = true,
133-
// AlignDimColumn = 16,
134-
// EnableUndo = false,
135-
// EndOfLineCommentStyle = EndOfLineCommentStyle.Absolute,
136-
// EndOfLineCommentColumnSpaceAlignment = 60,
137-
// IndentSpaces = 2
138-
//};
139-
140100
var userSettings = new UserSettings(null, null, null, null, null, GetMockIndenterSettings(true));
141101
return new Configuration(userSettings);
142102
}

0 commit comments

Comments
 (0)