Skip to content

Commit db8dbb1

Browse files
committed
Merge remote-tracking branch 'upstream/next' into Issue2964_TestExplorerDisableTestViaContextMenu
2 parents 0eb1070 + 66e505a commit db8dbb1

30 files changed

+1437
-528
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Rubberduck.Inspections.Abstract;
2+
using Rubberduck.Inspections.Results;
3+
using Rubberduck.Parsing.Inspections.Abstract;
4+
using Rubberduck.Resources.Inspections;
5+
using Rubberduck.Parsing.VBA;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using Rubberduck.Parsing.Symbols;
9+
using Rubberduck.Inspections.Inspections.Extensions;
10+
using Rubberduck.Common;
11+
12+
namespace Rubberduck.Inspections.Concrete
13+
{
14+
/// <summary>
15+
/// Identifies empty module member blocks.
16+
/// </summary>
17+
/// <why>
18+
/// Methods containing no executable statements are misleading as they appear to be doing something which they actually don't.
19+
/// This might be the result of delaying the actual implementation for a later stage of development, and then forgetting all about that.
20+
/// </why>
21+
/// <example hasResults="true">
22+
/// <![CDATA[
23+
/// Sub Foo()
24+
/// ' ...
25+
/// End Sub
26+
/// ]]>
27+
/// </example>
28+
/// <example hasResults="false">
29+
/// <![CDATA[
30+
/// Sub Foo()
31+
/// MsgBox "?"
32+
/// End Sub
33+
/// ]]>
34+
/// </example>
35+
internal class EmptyMethodInspection : InspectionBase
36+
{
37+
public EmptyMethodInspection(RubberduckParserState state)
38+
: base(state) { }
39+
40+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
41+
{
42+
var allInterfaces = new HashSet<ClassModuleDeclaration>(State.DeclarationFinder.FindAllUserInterfaces());
43+
44+
return State.DeclarationFinder.UserDeclarations(DeclarationType.Member)
45+
.Where(member => !allInterfaces.Any(userInterface => userInterface.QualifiedModuleName == member.QualifiedModuleName)
46+
&& !member.IsIgnoringInspectionResultFor(AnnotationName)
47+
&& !((ModuleBodyElementDeclaration)member).Block.ContainsExecutableStatements())
48+
49+
.Select(result => new DeclarationInspectionResult(this,
50+
string.Format(InspectionResults.EmptyMethodInspection,
51+
Resources.RubberduckUI.ResourceManager
52+
.GetString("DeclarationType_" + result.DeclarationType)
53+
.Capitalize(),
54+
result.IdentifierName),
55+
result));
56+
}
57+
}
58+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Rubberduck.Inspections.Abstract;
2+
using Rubberduck.Inspections.Results;
3+
using Rubberduck.Parsing.Inspections.Abstract;
4+
using Rubberduck.Resources.Inspections;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using Rubberduck.Parsing.Symbols;
8+
using Rubberduck.Inspections.Inspections.Extensions;
9+
using Rubberduck.Common;
10+
11+
namespace Rubberduck.Inspections.Concrete
12+
{
13+
/// <summary>
14+
/// Identifies implemented members of class modules that are used as interfaces.
15+
/// </summary>
16+
/// <why>
17+
/// Interfaces provide a unified programmatic access to different objects, and therefore are rarely instantiated as concrete objects.
18+
/// </why>
19+
/// <example hasResults="false">
20+
/// <![CDATA[
21+
/// Sub Foo()
22+
/// ' ...
23+
/// End Sub
24+
/// ]]>
25+
/// </example>
26+
/// <example hasResults="true">
27+
/// <![CDATA[
28+
/// Sub Foo()
29+
/// MsgBox "?"
30+
/// End Sub
31+
/// ]]>
32+
/// </example>
33+
internal class ImplementedInterfaceMemberInspection : InspectionBase
34+
{
35+
public ImplementedInterfaceMemberInspection(Parsing.VBA.RubberduckParserState state)
36+
: base(state) { }
37+
38+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
39+
{
40+
return State.DeclarationFinder.FindAllUserInterfaces()
41+
.SelectMany(interfaceModule => interfaceModule.Members
42+
.Where(member => ((ModuleBodyElementDeclaration)member).Block.ContainsExecutableStatements(true)
43+
&& !member.IsIgnoringInspectionResultFor(AnnotationName)))
44+
.Select(result => new DeclarationInspectionResult(this,
45+
string.Format(InspectionResults.ImplementedInterfaceMemberInspection,
46+
Resources.RubberduckUI.ResourceManager
47+
.GetString("DeclarationType_" + result.DeclarationType)
48+
.Capitalize(),
49+
result.IdentifierName),
50+
result));
51+
}
52+
}
53+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using Antlr4.Runtime.Tree;
2+
using static Rubberduck.Parsing.Grammar.VBAParser;
3+
4+
namespace Rubberduck.Inspections.Inspections.Extensions
5+
{
6+
public static class ExecutableBlocksExtensions
7+
{
8+
/// <summary>
9+
/// Checks a block of code for executable statments and returns true if are present.
10+
/// </summary>
11+
/// <param name="block">The block to inspect</param>
12+
/// <param name="considerAllocations">Determines wheather Dim or Const statements should be considered executables</param>
13+
/// <returns></returns>
14+
public static bool ContainsExecutableStatements(this BlockContext block, bool considerAllocations = false)
15+
{
16+
return block?.children != null && ContainsExecutableStatements(block.children, considerAllocations);
17+
}
18+
19+
private static bool ContainsExecutableStatements(System.Collections.Generic.IList<IParseTree> blockChildren,
20+
bool considerAllocations = false)
21+
{
22+
foreach (var child in blockChildren)
23+
{
24+
if (child is BlockStmtContext blockStmt)
25+
{
26+
var mainBlockStmt = blockStmt.mainBlockStmt();
27+
28+
if (mainBlockStmt == null)
29+
{
30+
continue; //We have a lone line label, which is not executable.
31+
}
32+
33+
// if inspection does not consider allocations as executables,
34+
// exclude variables and consts because they are not executable statements
35+
if (!considerAllocations && IsConstOrVariable(mainBlockStmt.GetChild(0)))
36+
{
37+
continue;
38+
}
39+
40+
return true;
41+
}
42+
43+
if (child is RemCommentContext ||
44+
child is CommentContext ||
45+
child is CommentOrAnnotationContext ||
46+
child is EndOfStatementContext)
47+
{
48+
continue;
49+
}
50+
51+
return true;
52+
}
53+
54+
return false;
55+
}
56+
57+
private static bool IsConstOrVariable(IParseTree block)
58+
{
59+
return block is VariableStmtContext || block is ConstStmtContext;
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)