10
10
using SourceBrowser . Generator . Extensions ;
11
11
using SourceBrowser . Generator . Model ;
12
12
using SourceBrowser . Generator . Model . VisualBasic ;
13
+ using Microsoft . CodeAnalysis . Shared . Extensions ;
14
+ using Microsoft . CodeAnalysis . FindSymbols ;
13
15
14
16
namespace SourceBrowser . Generator . DocumentWalkers
15
17
{
@@ -23,7 +25,9 @@ public class VBWalker : VisualBasicSyntaxWalker, IWalker
23
25
public DocumentModel DocumentModel { get ; private set ; }
24
26
public string FilePath { get ; set ; }
25
27
26
- public VBWalker ( IProjectItem parent , Document document , ReferencesourceLinkProvider refSourceLinkProvider ) : base ( SyntaxWalkerDepth . Trivia )
28
+ private Document _document ;
29
+
30
+ public VBWalker ( IProjectItem parent , Document document , ReferencesourceLinkProvider refSourceLinkProvider ) : base ( SyntaxWalkerDepth . Trivia )
27
31
{
28
32
_model = document . GetSemanticModelAsync ( ) . Result ;
29
33
_refsourceLinkProvider = refSourceLinkProvider ;
@@ -33,12 +37,13 @@ public VBWalker(IProjectItem parent, Document document, ReferencesourceLinkProvi
33
37
DocumentModel = new DocumentModel ( parent , document . Name , numberOfLines ) ;
34
38
FilePath = document . GetRelativeFilePath ( ) ;
35
39
_refsourceLinkProvider = refSourceLinkProvider ;
40
+ _document = document ;
36
41
}
37
42
38
43
public override void VisitToken ( SyntaxToken token )
39
44
{
40
45
Token tokenModel = null ;
41
-
46
+
42
47
if ( token . IsKeyword ( ) )
43
48
{
44
49
tokenModel = ProcessKeyword ( token ) ;
@@ -47,7 +52,7 @@ public override void VisitToken(SyntaxToken token)
47
52
{
48
53
tokenModel = ProcessIdentifier ( token ) ;
49
54
}
50
- else if ( token . VisualBasicKind ( ) == SyntaxKind . StringLiteralToken )
55
+ else if ( token . VisualBasicKind ( ) == SyntaxKind . StringLiteralToken )
51
56
{
52
57
tokenModel = ProcessStringLiteral ( token ) ;
53
58
}
@@ -92,7 +97,6 @@ private Token ProcessOtherToken(SyntaxToken token)
92
97
int lineNumber = token . GetLocation ( ) . GetLineSpan ( ) . StartLinePosition . Line + 1 ;
93
98
94
99
var tokenModel = new Token ( this . DocumentModel , fullName , value , type , lineNumber ) ;
95
-
96
100
return tokenModel ;
97
101
}
98
102
@@ -105,7 +109,6 @@ public Token ProcessKeyword(SyntaxToken token)
105
109
string value = token . ToString ( ) ;
106
110
string type = VisualBasicTokenTypes . KEYWORD ;
107
111
int lineNumber = token . GetLocation ( ) . GetLineSpan ( ) . StartLinePosition . Line + 1 ;
108
-
109
112
var tokenModel = new Token ( this . DocumentModel , fullName , value , type , lineNumber ) ;
110
113
return tokenModel ;
111
114
}
@@ -116,24 +119,19 @@ private Token ProcessStringLiteral(SyntaxToken token)
116
119
string value = token . ToString ( ) ;
117
120
string type = VisualBasicTokenTypes . STRING ;
118
121
int lineNumber = token . GetLocation ( ) . GetLineSpan ( ) . StartLinePosition . Line + 1 ;
119
-
120
122
var tokenModel = new Token ( this . DocumentModel , fullName , value , type , lineNumber ) ;
121
123
return tokenModel ;
122
124
}
123
125
124
- /// <summary>
125
- /// Given a syntax token identifier that represents a declaration,
126
- /// generate and return the proper HTML for this symbol.
127
- /// </summary>
128
- public Token ProcessDeclarationToken ( SyntaxToken token , ISymbol parentSymbol )
126
+ public Token ProcessSymbolUsage ( SyntaxToken token , ISymbol symbol , bool isDeclaration )
129
127
{
130
- string fullName = parentSymbol . ToString ( ) ;
128
+ string fullName = GetSymbolName ( symbol ) ;
131
129
string value = token . ToString ( ) ;
132
- string type = string . Empty ;
130
+ string type = String . Empty ;
133
131
int lineNumber = token . GetLocation ( ) . GetLineSpan ( ) . StartLinePosition . Line + 1 ;
134
- bool isDeclaration = true ;
132
+ bool isSearchable = isDeclaration ;
135
133
136
- if ( parentSymbol is INamedTypeSymbol )
134
+ if ( symbol is INamedTypeSymbol )
137
135
{
138
136
type = VisualBasicTokenTypes . TYPE ;
139
137
}
@@ -142,36 +140,19 @@ public Token ProcessDeclarationToken(SyntaxToken token, ISymbol parentSymbol)
142
140
type = VisualBasicTokenTypes . IDENTIFIER ;
143
141
}
144
142
145
- var tokenModel = new Token ( this . DocumentModel , fullName , value , type , lineNumber , isDeclaration ) ;
146
- return tokenModel ;
147
- }
148
-
149
- /// <summary>
150
- /// Given a syntax token identifier that represents a symbol's usage
151
- /// generate and return the proper HTML for this symbol
152
- /// </summary>
153
- public Token ProcessSymbolUsage ( SyntaxToken token , ISymbol symbol )
154
- {
155
- string fullName = symbol . ToString ( ) ;
156
- string value = token . ToString ( ) ;
157
- string type = string . Empty ;
158
- int lineNumber = token . GetLocation ( ) . GetLineSpan ( ) . StartLinePosition . Line + 1 ;
159
- if ( symbol is INamedTypeSymbol )
143
+ //Do not allow us to search locals
144
+ if ( symbol . Kind == SymbolKind . Local || symbol . Kind == SymbolKind . Parameter )
160
145
{
161
- type = VisualBasicTokenTypes . TYPE ;
146
+ isSearchable = false ;
162
147
}
163
- else
164
- {
165
- type = VisualBasicTokenTypes . IDENTIFIER ;
166
- }
167
-
148
+
168
149
var tokenModel = new Token ( this . DocumentModel , fullName , value , type , lineNumber ) ;
169
150
170
151
//If we can find the declaration, we'll link it ourselves
171
152
if ( symbol . DeclaringSyntaxReferences . Any ( )
172
153
&& ! ( symbol is INamespaceSymbol ) )
173
154
{
174
- var link = new SymbolLink ( referencedSymbolName : symbol . ToString ( ) ) ;
155
+ var link = new SymbolLink ( referencedSymbolName : fullName ) ;
175
156
tokenModel = tokenModel . WithLink ( link ) ;
176
157
}
177
158
//Otherwise, we try to link to the .Net Reference source
@@ -185,28 +166,41 @@ public Token ProcessSymbolUsage(SyntaxToken token, ISymbol symbol)
185
166
return tokenModel ;
186
167
}
187
168
169
+ private string GetSymbolName ( ISymbol symbol )
170
+ {
171
+ string fullyQualifiedName ;
172
+ if ( symbol . Kind == SymbolKind . Parameter )
173
+ {
174
+ var containingName = symbol . ContainingSymbol . ToString ( ) ;
175
+ fullyQualifiedName = containingName + VBDelimiters . PARAMETER + symbol . Name ;
176
+ }
177
+ else if ( symbol . Kind == SymbolKind . Local )
178
+ {
179
+ var containingName = symbol . ContainingSymbol . ToString ( ) ;
180
+ fullyQualifiedName = containingName + VBDelimiters . LOCAL_VARIABLE + symbol . Name ;
181
+ }
182
+ else
183
+ {
184
+ fullyQualifiedName = symbol . ToString ( ) ;
185
+ }
186
+
187
+ return fullyQualifiedName ;
188
+ }
189
+
188
190
public Token ProcessIdentifier ( SyntaxToken token )
189
191
{
190
192
//Check if this token is part of a declaration
191
- var parentSymbol = _model . GetDeclaredSymbol ( token . Parent ) ;
192
- if ( parentSymbol != null )
193
+ bool isDeclaration = false ;
194
+ if ( _model . GetDeclaredSymbol ( token . Parent ) != null )
193
195
{
194
- if ( parentSymbol . Kind == SymbolKind . Parameter )
195
- {
196
- parentSymbol = parentSymbol . ContainingSymbol ;
197
- }
198
- return ProcessDeclarationToken ( token , parentSymbol ) ;
196
+ isDeclaration = true ;
199
197
}
200
-
201
- //Find the symbol this token references
202
- var symbol = _model . GetSymbolInfo ( token . Parent ) . Symbol ;
198
+ var startPosition = token . GetLocation ( ) . SourceSpan . Start ;
199
+ //Note: We're using the SymbolFinder as it correctly resolves
200
+ var symbol = SymbolFinder . FindSymbolAtPosition ( _model , startPosition , _document . Project . Solution . Workspace ) ;
203
201
if ( symbol != null )
204
202
{
205
- if ( symbol . Kind == SymbolKind . Parameter )
206
- {
207
- symbol = symbol . ContainingSymbol ;
208
- }
209
- return ProcessSymbolUsage ( token , symbol ) ;
203
+ return ProcessSymbolUsage ( token , symbol , isDeclaration ) ;
210
204
}
211
205
212
206
//Otherwise it references something we don't
0 commit comments