1+ using System . Collections . Generic ;
2+ using System . Linq ;
3+ using Antlr4 . Runtime ;
4+ using Rubberduck . Inspections . Abstract ;
5+ using Rubberduck . Inspections . Results ;
6+ using Rubberduck . Parsing ;
7+ using Rubberduck . Parsing . Annotations ;
8+ using Rubberduck . Parsing . Grammar ;
9+ using Rubberduck . Parsing . Inspections ;
10+ using Rubberduck . Parsing . Inspections . Abstract ;
11+ using Rubberduck . Parsing . Symbols ;
12+ using Rubberduck . Parsing . VBA ;
13+ using Rubberduck . Parsing . VBA . Parsing ;
14+ using Rubberduck . Resources . Inspections ;
15+
16+ namespace Rubberduck . Inspections . Concrete
17+ {
18+ [ CannotAnnotate ]
19+ public sealed class MissingAttributeInspection : ParseTreeInspectionBase
20+ {
21+ public MissingAttributeInspection ( RubberduckParserState state )
22+ : base ( state )
23+ {
24+ Listener = new MissingMemberAttributeListener ( state ) ;
25+ }
26+
27+ public override CodeKind TargetKindOfCode => CodeKind . AttributesCode ;
28+
29+ public override IInspectionListener Listener { get ; }
30+
31+ protected override IEnumerable < IInspectionResult > DoGetInspectionResults ( )
32+ {
33+ return Listener . Contexts . Select ( context =>
34+ {
35+ var name = string . Format ( InspectionResults . MissingAttributeInspection , context . MemberName . MemberName ,
36+ ( ( VBAParser . AnnotationContext ) context . Context ) . annotationName ( ) . GetText ( ) ) ;
37+ return new QualifiedContextInspectionResult ( this , name , context ) ;
38+ } ) ;
39+ }
40+
41+ public class MissingMemberAttributeListener : ParseTreeListeners . AttributeAnnotationListener
42+ {
43+ public MissingMemberAttributeListener ( RubberduckParserState state ) : base ( state ) { }
44+
45+ public override void ExitAnnotation ( VBAParser . AnnotationContext context )
46+ {
47+ var annotationType = context . AnnotationType ;
48+
49+ if ( ! annotationType . HasFlag ( AnnotationType . Attribute ) )
50+ {
51+ return ;
52+ }
53+
54+ var isMemberAnnotation = annotationType . HasFlag ( AnnotationType . MemberAnnotation ) ;
55+ var isModuleScope = CurrentScopeDeclaration . DeclarationType . HasFlag ( DeclarationType . Module ) ;
56+
57+ if ( isModuleScope && ! isMemberAnnotation )
58+ {
59+ // module-level annotation
60+ var module = State . DeclarationFinder . UserDeclarations ( DeclarationType . Module ) . Single ( m => m . QualifiedName . QualifiedModuleName . Equals ( CurrentModuleName ) ) ;
61+ if ( ! module . Attributes . HasAttributeFor ( context . AnnotationType ) )
62+ {
63+ AddContext ( new QualifiedContext < ParserRuleContext > ( CurrentModuleName , context ) ) ;
64+ }
65+ }
66+ else if ( isMemberAnnotation )
67+ {
68+ // member-level annotation is above the context for the first member in the module..
69+ if ( isModuleScope )
70+ {
71+ CurrentScopeDeclaration = FirstMember ;
72+ }
73+
74+ var member = Members . Value . Single ( m => m . Key . Equals ( CurrentScopeDeclaration . QualifiedName . MemberName ) ) ;
75+ if ( ! member . Value . Attributes . HasAttributeFor ( context . AnnotationType , member . Key ) )
76+ {
77+ AddContext ( new QualifiedContext < ParserRuleContext > ( CurrentModuleName , context ) ) ;
78+ }
79+ }
80+ else
81+ {
82+ // annotation is illegal. ignore.
83+ }
84+ }
85+ }
86+ }
87+ }
0 commit comments