|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 using System; |
|
18 using System.Collections.Generic; |
|
19 using System.Text; |
|
20 using SymbianUtils.Strings; |
|
21 |
|
22 namespace SymbianUtils.XRef |
|
23 { |
|
24 public class XRefIdentiferExtractor |
|
25 { |
|
26 #region Constructors |
|
27 public XRefIdentiferExtractor( string aFunction ) |
|
28 { |
|
29 iIdentifiers = ExtractSearchableElements( aFunction ); |
|
30 } |
|
31 #endregion |
|
32 |
|
33 #region Properties |
|
34 public List<XRefIdentifer> Identifiers |
|
35 { |
|
36 get { return iIdentifiers; } |
|
37 } |
|
38 #endregion |
|
39 |
|
40 #region Internal methods |
|
41 private static bool ContainsParameters( string aText ) |
|
42 { |
|
43 // Search initiall for '(' - if that is found, then |
|
44 // we should also find a closing bracket. |
|
45 bool parameters = false; |
|
46 int openingBracketPos = aText.IndexOf( "(" ); |
|
47 // |
|
48 if ( openingBracketPos > 0 ) |
|
49 { |
|
50 // Should also be a closing bracket and it should |
|
51 // appear after the opening bracket |
|
52 int closingBracketPos = aText.LastIndexOf( ")" ); |
|
53 parameters = ( closingBracketPos > openingBracketPos ); |
|
54 } |
|
55 // |
|
56 return parameters; |
|
57 } |
|
58 |
|
59 private static string ExtractParameters( ref string aText ) |
|
60 { |
|
61 const string KOperatorChevronText = "operator <<"; |
|
62 |
|
63 // DoAppendFormatList<TDes16, (int)2>(T1&, const T3&, std::__va_list, T2*) |
|
64 // DoAppendFormatList<TDes16, (int)2>(T1&, TBuf<(int)256>, std::__va_list, T2*) |
|
65 // Method<TDes16>::Wibble( something ) |
|
66 // Method::Wibble( RPointerArray<HBufC> ) |
|
67 // RTest::operator ()(int, int, const unsigned short*) |
|
68 // TDesC16::Left(int) const |
|
69 // CObjectCon::AtL(int) const |
|
70 // User::Panic(const TDesC16&, int) |
|
71 // operator <<(RWriteStream&, const unsigned char&) |
|
72 |
|
73 // Handle special case of "operator <<" confusing matters |
|
74 string workingText = aText; |
|
75 int operatorOpeningChevronPos = aText.IndexOf( KOperatorChevronText ); |
|
76 if ( operatorOpeningChevronPos >= 0 ) |
|
77 { |
|
78 aText = aText.Substring( 0, operatorOpeningChevronPos + KOperatorChevronText.Length ); |
|
79 workingText = workingText.Substring( operatorOpeningChevronPos + KOperatorChevronText.Length ); |
|
80 } |
|
81 else |
|
82 { |
|
83 aText = string.Empty; |
|
84 } |
|
85 |
|
86 string ret = string.Empty; |
|
87 // |
|
88 int closingPos = 0; |
|
89 int openingPos = 0; |
|
90 int templatePos = 0; |
|
91 // |
|
92 while ( openingPos >= 0 ) |
|
93 { |
|
94 if ( templatePos >= 0 ) |
|
95 templatePos = workingText.IndexOf( "<", templatePos ); |
|
96 openingPos = workingText.IndexOf( "(", openingPos ); |
|
97 |
|
98 if ( templatePos >= 0 && templatePos < openingPos ) |
|
99 { |
|
100 // Template region appears before the next bracket. Skip |
|
101 // over all characters until we hit the end of the template |
|
102 // section |
|
103 int endingPos = templatePos; |
|
104 StringParsingUtils.SkipToEndOfSection( ref workingText, ref endingPos, '<', '>' ); |
|
105 |
|
106 if ( endingPos < 0 ) |
|
107 { |
|
108 // Matching closing brace was never found - dealing with operator << ? |
|
109 templatePos = -1; |
|
110 } |
|
111 else |
|
112 { |
|
113 // Something like DoAppendFormatList<TDes16, (int)2>(T1&, const T3&, std::__va_list, T2*) ??? |
|
114 templatePos = endingPos; |
|
115 openingPos = endingPos; |
|
116 } |
|
117 } |
|
118 else if ( openingPos >= 0 ) |
|
119 { |
|
120 // Skipped over any template nonsense. Work backward from the end |
|
121 // in order to locate start of parameters. |
|
122 closingPos = workingText.LastIndexOf( ')' ); |
|
123 openingPos = closingPos; |
|
124 StringParsingUtils.SkipToBeginningOfSection( ref workingText, ref openingPos, '(', ')' ); |
|
125 |
|
126 string parameters = workingText.Substring( openingPos + 1, ( closingPos - openingPos ) - 1 ).Trim(); |
|
127 ret = parameters; |
|
128 workingText = workingText.Substring( 0, openingPos + 1 ) + workingText.Substring( closingPos ); |
|
129 aText = aText + workingText; |
|
130 break; |
|
131 } |
|
132 } |
|
133 // |
|
134 return ret; |
|
135 } |
|
136 |
|
137 private static void SplitParameters( string aParams, ref List<string> aEntries ) |
|
138 { |
|
139 /* |
|
140 * TPtrC16::TPtrC16(const unsigned short*) |
|
141 * TPtrC16::TPtrC16(const TDesC16&) |
|
142 * UserHal::MemoryInfo(TDes8&) |
|
143 * RHandleBase::Close() |
|
144 * TBufCBase16::Copy(const TDesC16&, int) |
|
145 * CBufFlat::NewL(int) |
|
146 * TBufCBase16::TBufCBase16() |
|
147 * CServer2::RunL() |
|
148 * CServer2::StartL(const TDesC16&) |
|
149 * CServer2::DoCancel() |
|
150 * CServer2::RunError(int) |
|
151 * CServer2::DoConnect(const RMessage2&) |
|
152 * CServer2::CServer2__sub_object(int, CServer2::TServerType) |
|
153 */ |
|
154 string paramType; |
|
155 while ( aParams.Length > 0 ) |
|
156 { |
|
157 int commaPos = aParams.IndexOf( "," ); |
|
158 // |
|
159 paramType = aParams; |
|
160 if ( commaPos > 0 ) |
|
161 { |
|
162 paramType = aParams.Substring( 0, commaPos ).Trim(); |
|
163 if ( commaPos < aParams.Length ) |
|
164 aParams = aParams.Substring( commaPos + 1 ).Trim(); |
|
165 else |
|
166 aParams = string.Empty; |
|
167 } |
|
168 else |
|
169 { |
|
170 // Everything was consumed |
|
171 aParams = string.Empty; |
|
172 } |
|
173 |
|
174 // Add it |
|
175 aEntries.Add( paramType ); |
|
176 } |
|
177 } |
|
178 |
|
179 private static string[] IdentifyFurtherClassAndMethodInformation( string aEntry ) |
|
180 { |
|
181 string[] classAndMethodData = aEntry.Split( new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries ); |
|
182 return classAndMethodData; |
|
183 } |
|
184 |
|
185 private static List<XRefIdentifer> ExtractSearchableElements( string aFunction ) |
|
186 { |
|
187 List<string> workingData = new List<string>(); |
|
188 |
|
189 // See if this entry contains parameter data? |
|
190 if ( ContainsParameters( aFunction ) ) |
|
191 { |
|
192 // This call modifies aFunction so that the parameters are removed |
|
193 string parameters = ExtractParameters( ref aFunction ); |
|
194 |
|
195 // Now we get the individual parameter elements from the arguments |
|
196 SplitParameters( parameters, ref workingData ); |
|
197 } |
|
198 |
|
199 // Extract class & method names if present |
|
200 string[] classAndMethodData = aFunction.Split( new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries ); |
|
201 if ( classAndMethodData.Length > 0 ) |
|
202 { |
|
203 foreach ( string identifiedEntry in classAndMethodData ) |
|
204 { |
|
205 workingData.Add( identifiedEntry ); |
|
206 } |
|
207 } |
|
208 else |
|
209 { |
|
210 // Not a class & method - so just take the entire text as a |
|
211 // global function name |
|
212 workingData.Add( aFunction ); |
|
213 } |
|
214 |
|
215 // Recursively check for any more class types, e.g. in the following entry: |
|
216 // |
|
217 // CServer2::CServer2__sub_object(int, CServer2::TServerType) |
|
218 // |
|
219 // We also need to extract CServer2 and TServerType as individual elements |
|
220 for ( int i = workingData.Count - 1; i >= 0; i-- ) |
|
221 { |
|
222 string entry = workingData[ i ]; |
|
223 string[] furtherSplit = IdentifyFurtherClassAndMethodInformation( entry ); |
|
224 if ( furtherSplit != null && furtherSplit.Length > 1 ) |
|
225 { |
|
226 foreach ( string furtherEntry in furtherSplit ) |
|
227 { |
|
228 workingData.Add( furtherEntry ); |
|
229 } |
|
230 |
|
231 // Remove defunct entry |
|
232 workingData.RemoveAt( i ); |
|
233 } |
|
234 } |
|
235 |
|
236 // Clean up phase |
|
237 List<string> cleanedEntries = new List<string>(); |
|
238 foreach ( string identifiedEntry in workingData ) |
|
239 { |
|
240 string entry = identifiedEntry; |
|
241 |
|
242 // Now go through the identified entries and ensure they don't include |
|
243 // any pointer (*), reference (&) or bracketry. |
|
244 int pos = entry.IndexOfAny( new char[] { '*', '+', '&', '[', ']', '<', '>', '(', ')' } ); |
|
245 if ( pos >= 0 ) |
|
246 { |
|
247 entry = entry.Substring( 0, pos ); |
|
248 } |
|
249 |
|
250 // Strip any reserved keywords |
|
251 if ( entry.Length > 0 ) |
|
252 { |
|
253 entry = entry.Replace( "const", string.Empty ); |
|
254 entry = entry.Replace( "static", string.Empty ); |
|
255 entry = entry.Replace( "public", string.Empty ); |
|
256 entry = entry.Replace( "protected", string.Empty ); |
|
257 entry = entry.Replace( "private", string.Empty ); |
|
258 entry = entry.Replace( "__sub_object", string.Empty ); |
|
259 // |
|
260 if ( !cleanedEntries.Contains( entry ) ) |
|
261 { |
|
262 cleanedEntries.Add( entry.Trim() ); |
|
263 } |
|
264 } |
|
265 } |
|
266 |
|
267 // Convert to XRefIdentifiers |
|
268 List<XRefIdentifer> finalEntries = new List<XRefIdentifer>(); |
|
269 foreach ( string cleanedEntry in cleanedEntries ) |
|
270 { |
|
271 XRefIdentifer item = new XRefIdentifer( cleanedEntry ); |
|
272 finalEntries.Add( item ); |
|
273 } |
|
274 // |
|
275 return finalEntries; |
|
276 } |
|
277 #endregion |
|
278 |
|
279 #region Data members |
|
280 private readonly List<XRefIdentifer> iIdentifiers; |
|
281 #endregion |
|
282 } |
|
283 } |