1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
- using Antlr4 . Runtime ;
5
4
using Antlr4 . Runtime . Misc ;
6
5
using Antlr4 . Runtime . Tree ;
7
6
using Rubberduck . Inspections . Abstract ;
7
+ using Rubberduck . Parsing . Annotations ;
8
8
using Rubberduck . Parsing . Grammar ;
9
9
using Rubberduck . Parsing . Inspections ;
10
10
using Rubberduck . Parsing . Inspections . Abstract ;
@@ -31,97 +31,109 @@ public IgnoreOnceQuickFix(RubberduckParserState state, IEnumerable<IInspection>
31
31
32
32
public override void Fix ( IInspectionResult result , IRewriteSession rewriteSession )
33
33
{
34
- var annotationText = result . Target ? . DeclarationType . HasFlag ( DeclarationType . Module ) == true
35
- ? $ "'@IgnoreModule { result . Inspection . AnnotationName } "
36
- : $ "'@Ignore { result . Inspection . AnnotationName } ";
37
-
38
- int annotationLine ;
39
- //TODO: Make this use the parse tree instead of the code module.
40
- var component = _state . ProjectsProvider . Component ( result . QualifiedSelection . QualifiedName ) ;
41
- using ( var codeModule = component . CodeModule )
34
+ if ( result . Target ? . DeclarationType . HasFlag ( DeclarationType . Module ) == true )
42
35
{
43
- annotationLine = result . QualifiedSelection . Selection . StartLine ;
44
- while ( annotationLine != 1 && codeModule . GetLines ( annotationLine - 1 , 1 ) . EndsWith ( " _" ) )
45
- {
46
- annotationLine -- ;
47
- }
36
+ FixModule ( result , rewriteSession ) ;
48
37
}
38
+ else
39
+ {
40
+ FixNonModule ( result , rewriteSession ) ;
41
+ }
42
+ }
43
+
44
+ private void FixNonModule ( IInspectionResult result , IRewriteSession rewriteSession )
45
+ {
46
+ int insertionIndex ;
47
+ string insertText ;
48
+ var annotationText = $ "'@Ignore { result . Inspection . AnnotationName } ";
49
49
50
50
var module = result . QualifiedSelection . QualifiedName ;
51
51
var parseTree = _state . GetParseTree ( module , CodeKind . CodePaneCode ) ;
52
-
53
- var listener = new CommentOrAnnotationListener ( ) ;
54
- ParseTreeWalker . Default . Walk ( listener , parseTree ) ;
55
- var commentContext = listener . Contexts . LastOrDefault ( i => i . Stop . TokenIndex <= result . Context . Start . TokenIndex ) ;
56
- var commented = commentContext ? . Stop . Line + 1 == annotationLine ;
52
+ var eolListener = new EndOfLineListener ( ) ;
53
+ ParseTreeWalker . Default . Walk ( eolListener , parseTree ) ;
54
+ var previousEol = eolListener . Contexts
55
+ . OrderBy ( eol => eol . Start . TokenIndex )
56
+ . LastOrDefault ( eol => eol . Start . Line < result . QualifiedSelection . Selection . StartLine ) ;
57
57
58
58
var rewriter = rewriteSession . CheckOutModuleRewriter ( module ) ;
59
59
60
- if ( commented )
60
+ if ( previousEol == null )
61
61
{
62
- var annotation = commentContext . annotationList ( ) ? . annotation ( 0 ) ;
63
- if ( annotation != null && annotation . GetText ( ) . StartsWith ( "Ignore" ) )
64
- {
65
- rewriter . InsertAfter ( annotation . annotationName ( ) . Stop . TokenIndex , $ " { result . Inspection . AnnotationName } ,") ;
66
- }
67
- else
68
- {
69
- var indent = new string ( Enumerable . Repeat ( ' ' , commentContext . Start . Column ) . ToArray ( ) ) ;
70
- rewriter . InsertAfter ( commentContext . Stop . TokenIndex , $ "{ indent } { annotationText } { Environment . NewLine } ") ;
71
- }
62
+ // The context to get annotated is on the first line; we need to insert before token index 0.
63
+ insertionIndex = 0 ;
64
+ insertText = annotationText + Environment . NewLine ;
65
+ rewriter . InsertBefore ( insertionIndex , insertText ) ;
66
+ return ;
72
67
}
73
- else
68
+
69
+ var commentContext = previousEol . commentOrAnnotation ( ) ;
70
+ if ( commentContext == null )
74
71
{
75
- int insertIndex ;
76
-
77
- // this value is used when the annotation should be on line 1--we need to insert before token index 0
78
- if ( annotationLine == 1 )
79
- {
80
- insertIndex = 0 ;
81
- annotationText += Environment . NewLine ;
82
- }
83
- else
84
- {
85
- var eol = new EndOfLineListener ( ) ;
86
- ParseTreeWalker . Default . Walk ( eol , parseTree ) ;
87
-
88
- // we subtract 2 here to get the insertion index to A) account for VBE's one-based indexing
89
- // and B) to get the newline token that introduces that line
90
- var eolContext = eol . Contexts . OrderBy ( o => o . Start . TokenIndex ) . ElementAt ( annotationLine - 2 ) ;
91
- insertIndex = eolContext . Start . TokenIndex ;
92
-
93
- annotationText = Environment . NewLine + annotationText ;
94
- }
95
-
96
- rewriter . InsertBefore ( insertIndex , annotationText ) ;
72
+ insertionIndex = previousEol . Start . TokenIndex ;
73
+ var indent = WhitespaceAfter ( previousEol ) ;
74
+ insertText = $ "{ Environment . NewLine } { indent } { annotationText } ";
75
+ rewriter . InsertBefore ( insertionIndex , insertText ) ;
76
+ return ;
97
77
}
78
+
79
+ var ignoreAnnotation = commentContext . annotationList ( ) ? . annotation ( )
80
+ . FirstOrDefault ( annotationContext => annotationContext . annotationName ( ) . GetText ( ) == AnnotationType . Ignore . ToString ( ) ) ;
81
+ if ( ignoreAnnotation == null )
82
+ {
83
+ insertionIndex = commentContext . Stop . TokenIndex ;
84
+ var indent = WhitespaceAfter ( previousEol ) ;
85
+ insertText = $ "{ indent } { annotationText } { Environment . NewLine } ";
86
+ rewriter . InsertAfter ( insertionIndex , insertText ) ;
87
+ return ;
88
+ }
89
+
90
+ insertionIndex = ignoreAnnotation . annotationName ( ) . Stop . TokenIndex ;
91
+ insertText = $ " { result . Inspection . AnnotationName } ,";
92
+ rewriter . InsertAfter ( insertionIndex , insertText ) ;
98
93
}
99
94
100
- public override string Description ( IInspectionResult result ) => Resources . Inspections . QuickFixes . IgnoreOnce ;
95
+ private string WhitespaceAfter ( VBAParser . EndOfLineContext endOfLine )
96
+ {
97
+ var individualEndOfStatement = ( VBAParser . IndividualNonEOFEndOfStatementContext ) endOfLine . Parent ;
98
+ var whiteSpaceOnNextLine = individualEndOfStatement . whiteSpace ( 0 ) ;
99
+ return whiteSpaceOnNextLine != null
100
+ ? whiteSpaceOnNextLine . GetText ( )
101
+ : string . Empty ;
102
+ }
101
103
102
- private class CommentOrAnnotationListener : VBAParserBaseListener
104
+ private void FixModule ( IInspectionResult result , IRewriteSession rewriteSession )
103
105
{
104
- private readonly IList < VBAParser . CommentOrAnnotationContext > _contexts = new List < VBAParser . CommentOrAnnotationContext > ( ) ;
105
- public IEnumerable < VBAParser . CommentOrAnnotationContext > Contexts => _contexts ;
106
+ var module = result . QualifiedSelection . QualifiedName ;
107
+ var moduleAnnotations = _state . GetModuleAnnotations ( module ) ;
108
+ var firstIgnoreModuleAnnotation = moduleAnnotations
109
+ . Where ( annotation => annotation . AnnotationType == AnnotationType . IgnoreModule )
110
+ . OrderBy ( annotation => annotation . Context . Start . TokenIndex )
111
+ . FirstOrDefault ( ) ;
106
112
107
- public override void ExitCommentOrAnnotation ( [ NotNull ] VBAParser . CommentOrAnnotationContext context )
113
+ var rewriter = rewriteSession . CheckOutModuleRewriter ( module ) ;
114
+
115
+ int insertionIndex ;
116
+ string insertText ;
117
+
118
+ if ( firstIgnoreModuleAnnotation == null )
108
119
{
109
- _contexts . Add ( context ) ;
120
+ insertionIndex = 0 ;
121
+ insertText = $ "'@IgnoreModule { result . Inspection . AnnotationName } { Environment . NewLine } ";
122
+ rewriter . InsertBefore ( insertionIndex , insertText ) ;
123
+ return ;
110
124
}
125
+
126
+ insertionIndex = firstIgnoreModuleAnnotation . Context . annotationName ( ) . Stop . TokenIndex ;
127
+ insertText = $ " { result . Inspection . AnnotationName } ,";
128
+ rewriter . InsertAfter ( insertionIndex , insertText ) ;
111
129
}
112
130
131
+ public override string Description ( IInspectionResult result ) => Resources . Inspections . QuickFixes . IgnoreOnce ;
132
+
113
133
private class EndOfLineListener : VBAParserBaseListener
114
134
{
115
- private readonly IList < ParserRuleContext > _contexts = new List < ParserRuleContext > ( ) ;
116
- public IEnumerable < ParserRuleContext > Contexts => _contexts ;
117
-
118
- public override void ExitWhiteSpace ( [ NotNull ] VBAParser . WhiteSpaceContext context )
119
- {
120
- if ( context . GetText ( ) . Contains ( Environment . NewLine ) )
121
- {
122
- _contexts . Add ( context ) ;
123
- }
124
- }
135
+ private readonly IList < VBAParser . EndOfLineContext > _contexts = new List < VBAParser . EndOfLineContext > ( ) ;
136
+ public IEnumerable < VBAParser . EndOfLineContext > Contexts => _contexts ;
125
137
126
138
public override void ExitEndOfLine ( [ NotNull ] VBAParser . EndOfLineContext context )
127
139
{
0 commit comments