Skip to content

Commit 8a8fe88

Browse files
committed
Merge branch 'next' of git://github.com/rubberduck-vba/Rubberduck into redim
2 parents a27adc3 + 0e28e45 commit 8a8fe88

File tree

16 files changed

+414
-78
lines changed

16 files changed

+414
-78
lines changed

Rubberduck.CodeAnalysis/Inspections/Concrete/VariableRequiresSetAssignmentEvaluator.cs

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Rubberduck.Parsing.VBA;
55
using System.Diagnostics;
66
using System.Linq;
7+
using Rubberduck.VBEditor;
78

89
namespace Rubberduck.Inspections
910
{
@@ -52,13 +53,7 @@ public static bool RequiresSetAssignment(IdentifierReference reference, IDeclara
5253
{
5354
// get the members of the returning type, a default member could make us lie otherwise
5455
var classModule = declaration.AsTypeDeclaration as ClassModuleDeclaration;
55-
if (classModule?.DefaultMember == null)
56-
{
57-
return true;
58-
}
59-
var parameters = (classModule.DefaultMember as IParameterizedDeclaration)?.Parameters;
60-
// assign declaration is an object without a default parameterless (or with all parameters optional) member - LHS needs a 'Set' keyword.
61-
return parameters != null && parameters.All(p => p.IsOptional);
56+
return !HasPotentiallyNonObjectParameterlessDefaultMember(classModule);
6257
}
6358

6459
// assigned declaration is a variant. we need to know about the RHS of the assignment.
@@ -75,9 +70,30 @@ public static bool RequiresSetAssignment(IdentifierReference reference, IDeclara
7570
return false;
7671
}
7772

78-
if (expression is VBAParser.NewExprContext)
73+
74+
var module = Declaration.GetModuleParent(reference.ParentScoping);
75+
76+
if (expression is VBAParser.NewExprContext newExpr)
7977
{
80-
// RHS expression is newing up an object reference - LHS needs a 'Set' keyword:
78+
var newTypeExpression = newExpr.expression();
79+
80+
// todo resolve expression type
81+
82+
//Covers the case of a single type on the RHS of the assignment.
83+
var simpleTypeName = newTypeExpression.GetDescendent<VBAParser.SimpleNameExprContext>();
84+
if (simpleTypeName != null && simpleTypeName.GetText() == newTypeExpression.GetText())
85+
{
86+
var qualifiedIdentifierSelection = new QualifiedSelection(module.QualifiedModuleName,
87+
simpleTypeName.identifier().GetSelection());
88+
var identifierText = simpleTypeName.identifier().GetText();
89+
return declarationFinderProvider.DeclarationFinder.IdentifierReferences(qualifiedIdentifierSelection)
90+
.Select(identifierReference => identifierReference.Declaration)
91+
.Where(decl => identifierText == decl.IdentifierName)
92+
.OfType<ClassModuleDeclaration>()
93+
.Any(typeDecl => !HasPotentiallyNonObjectParameterlessDefaultMember(typeDecl));
94+
}
95+
//Here, we err on the side of false-positives, but that seems more appropriate than not to treat qualified type expressions incorrectly.
96+
//Whether there is a legitimate use here for default members is questionable anyway.
8197
return true;
8298
}
8399

@@ -93,20 +109,48 @@ public static bool RequiresSetAssignment(IdentifierReference reference, IDeclara
93109
}
94110

95111
// todo resolve expression return type
96-
var project = Declaration.GetProjectParent(reference.ParentScoping);
97-
var module = Declaration.GetModuleParent(reference.ParentScoping);
98112

113+
//Covers the case of a single variable on the RHS of the assignment.
99114
var simpleName = expression.GetDescendent<VBAParser.SimpleNameExprContext>();
100-
if (simpleName != null)
115+
if (simpleName != null && simpleName.GetText() == expression.GetText())
101116
{
102-
return declarationFinderProvider.DeclarationFinder.MatchName(simpleName.identifier().GetText())
103-
.Any(d => AccessibilityCheck.IsAccessible(project, module, reference.ParentScoping, d) && d.IsObject);
117+
var qualifiedIdentifierSelection = new QualifiedSelection(module.QualifiedModuleName,
118+
simpleName.identifier().GetSelection());
119+
return declarationFinderProvider.DeclarationFinder.IdentifierReferences(qualifiedIdentifierSelection)
120+
.Select(identifierReference => identifierReference.Declaration)
121+
.Where(decl => decl.IsObject
122+
&& simpleName.identifier().GetText() == decl.IdentifierName)
123+
.Select(typeDeclaration => typeDeclaration.AsTypeDeclaration as ClassModuleDeclaration)
124+
.Any(typeDecl => !HasPotentiallyNonObjectParameterlessDefaultMember(typeDecl));
104125
}
105126

127+
var project = Declaration.GetProjectParent(reference.ParentScoping);
128+
129+
//todo: Use code path analysis to ensure that we are really picking up the last assignment to the RHS.
106130
// is the reference referring to something else in scope that's a object?
107131
return declarationFinderProvider.DeclarationFinder.MatchName(expression.GetText())
108132
.Any(decl => (decl.DeclarationType.HasFlag(DeclarationType.ClassModule) || Tokens.Object.Equals(decl.AsTypeName))
109133
&& AccessibilityCheck.IsAccessible(project, module, reference.ParentScoping, decl));
110134
}
135+
136+
private static bool HasPotentiallyNonObjectParameterlessDefaultMember(ClassModuleDeclaration classModule)
137+
{
138+
var defaultMember = classModule?.DefaultMember;
139+
140+
if (defaultMember == null)
141+
{
142+
return false;
143+
}
144+
145+
var parameters = (defaultMember as IParameterizedDeclaration)?.Parameters;
146+
// assign declaration is an object without a default parameterless (or with all parameters optional) member - LHS needs a 'Set' keyword.
147+
if (parameters != null && parameters.Any(p => !p.IsOptional))
148+
{
149+
return false;
150+
}
151+
152+
var defaultMemberType = defaultMember.AsTypeDeclaration as ClassModuleDeclaration;
153+
return defaultMemberType == null || HasPotentiallyNonObjectParameterlessDefaultMember(defaultMemberType);
154+
}
111155
}
112156
}

Rubberduck.Core/Common/IOperatingSystem.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
public interface IOperatingSystem
44
{
55
void ShowFolder(string folderPath);
6+
WindowsVersion? GetOSVersion();
67
}
78
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System.Runtime.InteropServices;
2+
3+
namespace Rubberduck.Common.WinAPI
4+
{
5+
/// <summary>
6+
/// Native functions from SHCore.dll
7+
/// </summary>
8+
public static class SHCore
9+
{
10+
/// <summary>
11+
/// Sets the DPI awareness level of the current process.
12+
/// </summary>
13+
/// <param name="awareness">DPI awareness level.</param>
14+
/// <returns>HRESULT of S_OK, E_INVALIDARG or E_ACCESSDENIED.</returns>
15+
/// <remarks>
16+
/// Only the first DPI awareness call made by a process will have effect, subsequent calls are disregarded.
17+
/// Thus, calling this method before WPF loads will override the default WPF DPI awareness behavior.
18+
/// </remarks>
19+
[DllImport("SHCore.dll", SetLastError = true)]
20+
public static extern bool SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness);
21+
}
22+
23+
/// <summary>
24+
/// Describes DPI awareness of a process.
25+
/// </summary>
26+
public enum PROCESS_DPI_AWARENESS
27+
{
28+
/// <summary>
29+
/// Process is not DPI aware.
30+
/// </summary>
31+
Process_DPI_Unaware = 0,
32+
33+
/// <summary>
34+
/// Process is aware of the System DPI (monitor 1).
35+
/// </summary>
36+
Process_System_DPI_Aware = 1,
37+
38+
/// <summary>
39+
/// Process is aware of the DPI of individual monitors.
40+
/// </summary>
41+
Process_Per_Monitor_DPI_Aware = 2
42+
}
43+
44+
}
Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,56 @@
1-
using System.Diagnostics;
1+
using System;
2+
using System.Diagnostics;
23
using System.IO;
4+
using System.Management;
5+
using System.Runtime.CompilerServices;
6+
using NLog;
37

48
namespace Rubberduck.Common
59
{
610
public sealed class WindowsOperatingSystem : IOperatingSystem
711
{
12+
public static readonly ILogger _Logger = LogManager.GetCurrentClassLogger();
13+
814
public void ShowFolder(string folderPath)
915
{
1016
if (!Directory.Exists(folderPath))
1117
{
1218
Directory.CreateDirectory(folderPath);
1319
}
1420

15-
using (Process.Start(folderPath)) { }
21+
using (Process.Start(folderPath))
22+
{
23+
}
24+
}
25+
26+
27+
public WindowsVersion? GetOSVersion()
28+
{
29+
try
30+
{
31+
var wmiEnum = new ManagementObjectSearcher("root\\CIMV2", "SELECT Version FROM Win32_OperatingSystem")
32+
.Get().GetEnumerator();
33+
wmiEnum.MoveNext();
34+
var versionString = wmiEnum.Current.Properties["Version"].Value as string;
35+
36+
var versionElements = versionString?.Split('.');
37+
38+
if (versionElements?.Length >= 3 &&
39+
int.TryParse(versionElements[0], out var major) &&
40+
int.TryParse(versionElements[1], out var minor) &&
41+
int.TryParse(versionElements[2], out var build))
42+
{
43+
return new WindowsVersion(major, minor, build);
44+
}
45+
}
46+
catch (Exception exception)
47+
{
48+
_Logger.Warn(exception, "Unable to determine OS Version");
49+
return null;
50+
}
51+
_Logger.Warn("Unable to determine OS Version");
52+
return null;
1653
}
1754
}
1855
}
56+
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System;
2+
3+
namespace Rubberduck.Common
4+
{
5+
public struct WindowsVersion : IComparable<WindowsVersion>, IEquatable<WindowsVersion>
6+
{
7+
public static readonly WindowsVersion Windows10 = new WindowsVersion(10, 0, 10240);
8+
public static readonly WindowsVersion Windows81 = new WindowsVersion(6, 3, 9200);
9+
public static readonly WindowsVersion Windows8 = new WindowsVersion(6, 2, 9200);
10+
public static readonly WindowsVersion Windows7_SP1 = new WindowsVersion(6, 1, 7601);
11+
public static readonly WindowsVersion WindowsVista_SP2 = new WindowsVersion(6, 0, 6002);
12+
13+
public WindowsVersion(int major, int minor, int build)
14+
{
15+
Major = major;
16+
Minor = minor;
17+
Build = build;
18+
}
19+
20+
public int Major { get; }
21+
public int Minor { get; }
22+
public int Build { get; }
23+
24+
25+
public int CompareTo(WindowsVersion other)
26+
{
27+
var majorComparison = Major.CompareTo(other.Major);
28+
if (majorComparison != 0)
29+
{
30+
return majorComparison;
31+
}
32+
33+
var minorComparison = Minor.CompareTo(other.Minor);
34+
35+
return minorComparison != 0
36+
? minorComparison
37+
: Build.CompareTo(other.Build);
38+
}
39+
40+
public bool Equals(WindowsVersion other)
41+
{
42+
return Major == other.Major && Minor == other.Minor && Build == other.Build;
43+
}
44+
45+
public override bool Equals(object other)
46+
{
47+
return other is WindowsVersion otherVersion && Equals(otherVersion);
48+
}
49+
50+
public override int GetHashCode()
51+
{
52+
unchecked
53+
{
54+
var hashCode = Major;
55+
hashCode = (hashCode * 397) ^ Minor;
56+
hashCode = (hashCode * 397) ^ Build;
57+
return hashCode;
58+
}
59+
}
60+
61+
public static bool operator ==(WindowsVersion os1, WindowsVersion os2)
62+
{
63+
return os1.CompareTo(os2) == 0;
64+
}
65+
66+
public static bool operator !=(WindowsVersion os1, WindowsVersion os2)
67+
{
68+
return os1.CompareTo(os2) != 0;
69+
}
70+
71+
public static bool operator <(WindowsVersion os1, WindowsVersion os2)
72+
{
73+
return os1.CompareTo(os2) < 0;
74+
}
75+
76+
public static bool operator >(WindowsVersion os1, WindowsVersion os2)
77+
{
78+
return os1.CompareTo(os2) > 0;
79+
}
80+
81+
public static bool operator <=(WindowsVersion os1, WindowsVersion os2)
82+
{
83+
return os1.CompareTo(os2) <= 0;
84+
}
85+
86+
public static bool operator >=(WindowsVersion os1, WindowsVersion os2)
87+
{
88+
return os1.CompareTo(os2) >= 0;
89+
}
90+
}
91+
}

Rubberduck.Core/Rubberduck.Core.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<DisabledWarnings>$(DisabledWarnings);1591</DisabledWarnings>
1313
<ApplicationIcon>Ducky.ico</ApplicationIcon>
1414
<!-- Give a fixed version to not blow XAML generated code to smithereens -->
15-
<AssemblyVersion>2.3.0</AssemblyVersion>
15+
<AssemblyVersion>2.3.1</AssemblyVersion>
1616
</PropertyGroup>
1717
<Import Project="..\RubberduckBaseProject.csproj" />
1818
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugAccess|AnyCPU'">
@@ -29,6 +29,7 @@
2929
<Reference Include="PresentationCore" />
3030
<Reference Include="PresentationFramework" />
3131
<Reference Include="PresentationFramework.Aero" />
32+
<Reference Include="System.Management" />
3233
<Reference Include="System.Net.Http" />
3334
<Reference Include="System.Windows.Forms" />
3435
<Reference Include="System.Xaml" />
@@ -111,4 +112,4 @@
111112
</ItemGroup>
112113
<!-- END WINDOWS FORMS WORKAROUND SECTION -->
113114

114-
</Project>
115+
</Project>

Rubberduck.Core/Settings/GeneralSettings.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public interface IGeneralSettings
1818
int AutoSavePeriod { get; set; }
1919
bool UserEditedLogLevel { get; set; }
2020
int MinimumLogLevel { get; set; }
21+
bool SetDpiUnaware { get; set; }
2122
List<ExperimentalFeatures> EnableExperimentalFeatures { get; set; }
2223
}
2324

@@ -56,6 +57,8 @@ public int MinimumLogLevel
5657
}
5758
}
5859

60+
public bool SetDpiUnaware { get; set; }
61+
5962
public List<ExperimentalFeatures> EnableExperimentalFeatures { get; set; } = new List<ExperimentalFeatures>();
6063

6164
public GeneralSettings()
@@ -79,7 +82,8 @@ public bool Equals(GeneralSettings other)
7982
UserEditedLogLevel == other.UserEditedLogLevel &&
8083
MinimumLogLevel == other.MinimumLogLevel &&
8184
EnableExperimentalFeatures.All(a => other.EnableExperimentalFeatures.Contains(a)) &&
82-
EnableExperimentalFeatures.Count == other.EnableExperimentalFeatures.Count;
85+
EnableExperimentalFeatures.Count == other.EnableExperimentalFeatures.Count &&
86+
SetDpiUnaware == other.SetDpiUnaware;
8387
}
8488
}
8589
}

Rubberduck.Core/UI/Settings/GeneralSettings.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@
131131
IsChecked="{Binding CheckVersionAtStartup}" />
132132
<CheckBox Margin="5,0,0,5" Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GeneralSettings_CompileBeforeParse}"
133133
IsChecked="{Binding CompileBeforeParse}" />
134+
<CheckBox Margin="5,0,0,5" Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GeneralSettings_SetDpiUnaware}"
135+
IsEnabled="{Binding SetDpiUnawareEnabled}" IsChecked="{Binding SetDpiUnaware}" />
134136
<StackPanel Orientation="Horizontal"/>
135137

136138
<Label Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GeneralSettings_MinimumLogLevelLabel}" FontWeight="SemiBold" />

0 commit comments

Comments
 (0)