Skip to content

Commit 496dcf9

Browse files
authored
Merge pull request #4401 from MDoerner/MakeModuleAnnotationRecognitionIndependentOfTheVBE
Fix module annotation recognition
2 parents ac318dd + e75127a commit 496dcf9

File tree

5 files changed

+323
-34
lines changed

5 files changed

+323
-34
lines changed

Rubberduck.CodeAnalysis/QuickFixes/RemoveDuplicatedAnnotationQuickFix.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public override void Fix(IInspectionResult result)
4040
var annotationList = (VBAParser.AnnotationListContext)annotation.Context.Parent;
4141

4242
RemoveAnnotationMarker(annotationList, annotation, rewriter);
43-
RemoveWhiteSpaceAfterAnnotation(annotationList, annotation, rewriter);
4443

4544
rewriter.Remove(annotation.Context);
4645

@@ -71,18 +70,6 @@ private static void RemoveAnnotationMarker(VBAParser.AnnotationListContext annot
7170
rewriter.Remove(annotationList.AT(index));
7271
}
7372

74-
private static void RemoveWhiteSpaceAfterAnnotation(VBAParser.AnnotationListContext annotationList,
75-
IAnnotation annotation, IModuleRewriter rewriter)
76-
{
77-
var whitespace = annotationList.whiteSpace().FirstOrDefault(ws =>
78-
ws.Start.StartIndex == annotation.Context.Stop.StopIndex + 1);
79-
80-
if (whitespace != null)
81-
{
82-
rewriter.Remove(whitespace);
83-
}
84-
}
85-
8673
private static bool OnlyQuoteRemainedFromAnnotationList(KeyValuePair<VBAParser.AnnotationListContext, int> pair)
8774
{
8875
return pair.Key.annotation().Length == pair.Value && pair.Key.commentBody() == null;

Rubberduck.Parsing/Grammar/VBAParser.g4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -926,8 +926,8 @@ commentOrAnnotation :
926926
remComment : REM whiteSpace? commentBody;
927927
comment : SINGLEQUOTE commentBody;
928928
commentBody : (~NEWLINE)*;
929-
annotationList : SINGLEQUOTE (AT annotation whiteSpace?)+ (COLON commentBody)?;
930-
annotation : annotationName annotationArgList?;
929+
annotationList : SINGLEQUOTE (AT annotation)+ (COLON commentBody)?;
930+
annotation : annotationName annotationArgList? whiteSpace?;
931931
annotationName : unrestrictedIdentifier;
932932
annotationArgList :
933933
whiteSpace annotationArg

Rubberduck.Parsing/Symbols/DeclarationSymbolsListener.cs

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class DeclarationSymbolsListener : VBAParserBaseListener
2121
private Declaration _currentScopeDeclaration;
2222
private Declaration _parentDeclaration;
2323

24-
private readonly IEnumerable<IAnnotation> _annotations;
24+
private readonly ICollection<IAnnotation> _annotations;
2525
private readonly IDictionary<(string scopeIdentifier, DeclarationType scopeType), Attributes> _attributes;
2626
private readonly IDictionary<(string scopeIdentifier, DeclarationType scopeType), ParserRuleContext> _membersAllowingAttributes;
2727

@@ -40,7 +40,7 @@ public DeclarationSymbolsListener(
4040
{
4141
_state = state;
4242
_qualifiedModuleName = qualifiedModuleName;
43-
_annotations = annotations;
43+
_annotations = annotations.ToList();
4444
_attributes = attributes;
4545
_membersAllowingAttributes = membersAllowingAttributes;
4646

@@ -61,7 +61,7 @@ public DeclarationSymbolsListener(
6161
projectDeclaration,
6262
_qualifiedModuleName.ComponentName,
6363
true,
64-
FindAnnotations(),
64+
FindModuleAnnotations(),
6565
moduleAttributes);
6666
}
6767
else
@@ -73,7 +73,7 @@ public DeclarationSymbolsListener(
7373
projectDeclaration,
7474
_qualifiedModuleName.ComponentName,
7575
true,
76-
FindAnnotations(),
76+
FindModuleAnnotations(),
7777
moduleAttributes,
7878
hasDefaultInstanceVariable: hasDefaultInstanceVariable);
7979
}
@@ -88,26 +88,73 @@ public DeclarationSymbolsListener(
8888
}
8989
}
9090

91-
private IEnumerable<IAnnotation> FindAnnotations()
91+
private IEnumerable<IAnnotation> FindModuleAnnotations()
9292
{
9393
if (_annotations == null)
9494
{
9595
return null;
9696
}
9797

98-
int lastDeclarationsSectionLine;
99-
var component = _state.ProjectsProvider.Component(_qualifiedModuleName);
100-
using (var codeModule = component.CodeModule)
98+
var lastDeclarationsSectionLine = LastDeclarationsSectionLine();
99+
100+
//There is no module body.
101+
if (lastDeclarationsSectionLine == null)
101102
{
102-
lastDeclarationsSectionLine = codeModule.CountOfDeclarationLines;
103+
return _annotations;
103104
}
104105

105-
var annotations = _annotations.Where(annotation => annotation.QualifiedSelection.QualifiedName.Equals(_qualifiedModuleName)
106-
&& annotation.QualifiedSelection.Selection.EndLine <= lastDeclarationsSectionLine);
106+
var lastPossibleModuleAnnotationLine = lastDeclarationsSectionLine.Value;
107+
var annotations = _annotations.Where(annotation => annotation.QualifiedSelection.Selection.EndLine <= lastPossibleModuleAnnotationLine);
107108
return annotations.ToList();
108109
}
109110

110-
private IEnumerable<IAnnotation> FindAnnotations(int line)
111+
private int? LastDeclarationsSectionLine()
112+
{
113+
var firstModuleBodyElementLine = FirstModuleBodyElementLine();
114+
115+
if (firstModuleBodyElementLine == null)
116+
{
117+
return null;
118+
}
119+
120+
//The VBE uses 1-based lines.
121+
for (var currentLine = firstModuleBodyElementLine.Value - 1; currentLine >= 1; currentLine--)
122+
{
123+
if (_annotations.Any(annotation => annotation.QualifiedSelection.Selection.StartLine <= currentLine
124+
&& annotation.QualifiedSelection.Selection.EndLine >=
125+
currentLine))
126+
{
127+
continue;
128+
}
129+
130+
return currentLine;
131+
}
132+
133+
//There is no declaration section.
134+
return 0;
135+
}
136+
137+
private int? FirstModuleBodyElementLine()
138+
{
139+
var moduleTrees = _state.ParseTrees.Where(kvp => kvp.Key.Equals(_qualifiedModuleName)).ToList();
140+
if (!moduleTrees.Any())
141+
{
142+
return null;
143+
}
144+
145+
var startContext = (ParserRuleContext) moduleTrees.First().Value;
146+
var moduleBody = startContext.GetDescendent<VBAParser.ModuleBodyContext>();
147+
148+
var moduleBodyElements = moduleBody.moduleBodyElement();
149+
if (!moduleBodyElements.Any())
150+
{
151+
return null;
152+
}
153+
154+
return moduleBodyElements.Select(context => context.start.Line).Min();
155+
}
156+
157+
private IEnumerable<IAnnotation> FindMemberAnnotations(int firstMemberLine)
111158
{
112159
if (_annotations == null)
113160
{
@@ -117,16 +164,17 @@ private IEnumerable<IAnnotation> FindAnnotations(int line)
117164
var annotations = new List<IAnnotation>();
118165

119166
// VBE 1-based indexing
120-
for (var i = line - 1; i >= 1; i--)
167+
for (var currentLine = firstMemberLine - 1; currentLine >= 1; currentLine--)
121168
{
122-
var lineAnnotations = _annotations.Where(a => a.QualifiedSelection.Selection.StartLine == i);
123-
124-
if (!lineAnnotations.Any())
169+
if (!_annotations.Any(annotation => annotation.QualifiedSelection.Selection.StartLine <= currentLine
170+
&& annotation.QualifiedSelection.Selection.EndLine >= currentLine))
125171
{
126172
break;
127173
}
128174

129-
annotations.AddRange(lineAnnotations);
175+
var annotationsStartingOnCurrentLine = _annotations.Where(a => a.QualifiedSelection.Selection.StartLine == currentLine);
176+
177+
annotations.AddRange(annotationsStartingOnCurrentLine);
130178
}
131179

132180
return annotations;
@@ -225,7 +273,7 @@ private Declaration CreateDeclaration(
225273
_attributes.TryGetValue(key, out var attributes);
226274
_membersAllowingAttributes.TryGetValue(key, out var attributesPassContext);
227275

228-
var annotations = FindAnnotations(selection.StartLine);
276+
var annotations = FindMemberAnnotations(selection.StartLine);
229277
switch (declarationType)
230278
{
231279
case DeclarationType.Procedure:
@@ -821,7 +869,7 @@ public override void EnterConstSubStmt(VBAParser.ConstSubStmtContext context)
821869
asTypeName,
822870
asTypeClause,
823871
typeHint,
824-
FindAnnotations(constStmt.Start.Line),
872+
FindMemberAnnotations(constStmt.Start.Line),
825873
accessibility,
826874
DeclarationType.Constant,
827875
value,

0 commit comments

Comments
 (0)