Lines 44-59
Link Here
|
44 |
|
44 |
|
45 |
import java.util.ArrayList; |
45 |
import java.util.ArrayList; |
46 |
import java.util.Collection; |
46 |
import java.util.Collection; |
47 |
import java.util.HashMap; |
|
|
48 |
import java.util.HashSet; |
47 |
import java.util.HashSet; |
49 |
import java.util.Iterator; |
48 |
import java.util.Iterator; |
50 |
import java.util.List; |
49 |
import java.util.List; |
51 |
import java.util.Map; |
|
|
52 |
import java.util.Set; |
50 |
import java.util.Set; |
|
|
51 |
import java.util.concurrent.CancellationException; |
52 |
import java.util.concurrent.ExecutionException; |
53 |
import java.util.concurrent.FutureTask; |
54 |
import java.util.concurrent.TimeUnit; |
55 |
import java.util.concurrent.TimeoutException; |
53 |
import java.util.concurrent.atomic.AtomicBoolean; |
56 |
import java.util.concurrent.atomic.AtomicBoolean; |
54 |
import java.util.logging.Level; |
57 |
import java.util.logging.Level; |
55 |
import java.util.logging.Logger; |
58 |
import java.util.logging.Logger; |
56 |
import org.netbeans.api.project.Project; |
|
|
57 |
import org.netbeans.modules.cnd.api.model.CsmClass; |
59 |
import org.netbeans.modules.cnd.api.model.CsmClass; |
58 |
import org.netbeans.modules.cnd.api.model.CsmDeclaration; |
60 |
import org.netbeans.modules.cnd.api.model.CsmDeclaration; |
59 |
import org.netbeans.modules.cnd.api.model.CsmDeclaration.Kind; |
61 |
import org.netbeans.modules.cnd.api.model.CsmDeclaration.Kind; |
Lines 80-86
Link Here
|
80 |
import org.netbeans.spi.jumpto.support.NameMatcherFactory; |
82 |
import org.netbeans.spi.jumpto.support.NameMatcherFactory; |
81 |
import org.netbeans.spi.jumpto.symbol.SymbolProvider; |
83 |
import org.netbeans.spi.jumpto.symbol.SymbolProvider; |
82 |
import org.netbeans.spi.jumpto.type.SearchType; |
84 |
import org.netbeans.spi.jumpto.type.SearchType; |
|
|
85 |
import org.openide.util.Exceptions; |
83 |
import org.openide.util.NbBundle; |
86 |
import org.openide.util.NbBundle; |
|
|
87 |
import org.openide.util.RequestProcessor; |
84 |
|
88 |
|
85 |
/** |
89 |
/** |
86 |
* SymbolProvider for C/C++ implementation |
90 |
* SymbolProvider for C/C++ implementation |
Lines 89-138
Link Here
|
89 |
@org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.jumpto.symbol.SymbolProvider.class) |
93 |
@org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.jumpto.symbol.SymbolProvider.class) |
90 |
public class CppSymbolProvider implements SymbolProvider { |
94 |
public class CppSymbolProvider implements SymbolProvider { |
91 |
|
95 |
|
92 |
private static class Cache { |
96 |
private static final boolean TRACE = true;//Boolean.getBoolean("cnd.gotosymbol.trace"); |
93 |
public final String text; |
97 |
private static final Logger LOG = TRACE ? Logger.getLogger("cnd.symbol.provider.trace") : null; // NOI18N |
94 |
public final SearchType searchType; |
98 |
private static final RequestProcessor RP = new RequestProcessor(CppSymbolProvider.class.getName(), 1); |
95 |
private final Map<Project, List<CppSymbolDescriptor>> data; |
99 |
private static final Object resultLock = new Object(); |
96 |
public Cache(SearchType searchType, String text) { |
100 |
private final Object activeTaskLock = new Object(); |
97 |
this.text = text; |
101 |
private WorkerTask activeTask; |
98 |
this.searchType = searchType; |
102 |
|
99 |
this.data = new HashMap<Project, List<CppSymbolDescriptor>>(); |
103 |
|
|
|
104 |
public CppSymbolProvider() { |
105 |
if (TRACE) { |
106 |
LOG.info("CppSymbolProvider created"); // NOI18N |
100 |
} |
107 |
} |
101 |
} |
108 |
} |
102 |
|
109 |
|
103 |
private volatile Cache cache; |
110 |
@Override |
104 |
private final AtomicBoolean cancelled = new AtomicBoolean(false); |
111 |
public String name() { |
105 |
private static final boolean TRACE = Boolean.getBoolean("cnd.gotosymbol.trace"); |
112 |
return "C/C++"; //NOI18N |
106 |
private static final boolean USE_CACHE = CndUtils.getBoolean("cnd.gotosymbol.cache", true); |
|
|
107 |
|
108 |
public CppSymbolProvider() { |
109 |
if (TRACE) { trace("ctor"); } // NOI18N |
110 |
} |
113 |
} |
111 |
|
114 |
|
112 |
@Override |
115 |
@Override |
113 |
public void cancel() { |
116 |
public String getDisplayName() { |
114 |
if (TRACE) { trace("cancel"); } // NOI18N |
117 |
return NbBundle.getMessage(getClass(), "CPP_Provider_Display_Name"); |
115 |
cancelled.set(true); |
|
|
116 |
cache = null; |
117 |
} |
118 |
|
119 |
@Override |
120 |
public void cleanup() { |
121 |
if (TRACE) { trace("cleanup"); } // NOI18N |
122 |
cancelled.set(false); |
123 |
cache = null; |
124 |
} |
125 |
|
126 |
public static CsmSelect.NameAcceptor createNameAcceptor(final String text, final SearchType searchType) { |
127 |
final NameMatcher nameMatcher = NameMatcherFactory.createNameMatcher(text, searchType); |
128 |
return new NameAcceptorImpl(nameMatcher); |
129 |
} |
118 |
} |
130 |
|
119 |
|
131 |
// synchronized is just in case here - it shouldn't be called async |
120 |
// synchronized is just in case here - it shouldn't be called async |
132 |
@Override |
121 |
@Override |
133 |
public synchronized void computeSymbolNames(Context context, Result result) { |
122 |
public synchronized void computeSymbolNames(Context context, Result res) { |
134 |
if (TRACE) { trace("computeSymbolNames %s", toString(context)); } // NOI18N |
123 |
if (TRACE) { |
135 |
cancelled.set(false); |
124 |
LOG.log(Level.INFO, "computeSymbolNames {0}", toString(context)); // NOI18N |
|
|
125 |
} |
136 |
CsmSelect.NameAcceptor nameAcceptor = createNameAcceptor(context.getText(), context.getSearchType()); |
126 |
CsmSelect.NameAcceptor nameAcceptor = createNameAcceptor(context.getText(), context.getSearchType()); |
137 |
if (nameAcceptor == null) { |
127 |
if (nameAcceptor == null) { |
138 |
if (CndUtils.isDebugMode()) { |
128 |
if (CndUtils.isDebugMode()) { |
Lines 141-420
Link Here
|
141 |
} |
131 |
} |
142 |
return; |
132 |
return; |
143 |
} |
133 |
} |
|
|
134 |
|
135 |
WorkerTask task; |
136 |
synchronized (activeTaskLock) { |
137 |
task = activeTask; |
138 |
if (task != null && !sameContext(task.context, context)) { |
139 |
task.cancel(); |
140 |
task = null; |
141 |
activeTask = null; |
142 |
} |
144 |
|
143 |
|
145 |
List<CppSymbolDescriptor> symbols = new ArrayList<CppSymbolDescriptor>(); |
144 |
if (task == null) { |
146 |
|
145 |
task = new WorkerTask(context, nameAcceptor); |
147 |
boolean filled = false; |
146 |
activeTask = task; |
148 |
Cache aCache = cache; |
147 |
RP.submit(task); |
149 |
if (aCache != null && context.getSearchType() == aCache.searchType && context.getText().startsWith(aCache.text)) { |
|
|
150 |
List<CppSymbolDescriptor> cached = aCache.data.get(context.getProject()); |
151 |
if (cached != null) { |
152 |
filled = true; |
153 |
long time = System.currentTimeMillis(); |
154 |
for (CppSymbolDescriptor desc : cached) { |
155 |
if (nameAcceptor.accept(desc.getRawName())) { |
156 |
symbols.add(desc); |
157 |
} |
158 |
} |
159 |
if (TRACE) { trace("Narrowing %d symbols took %d ms", symbols.size(), System.currentTimeMillis() - time); } //NOI18N |
160 |
} |
148 |
} |
161 |
} |
149 |
} |
162 |
if (!filled) { |
150 |
|
163 |
long time = System.currentTimeMillis(); |
151 |
while (!task.isDone()) { |
164 |
CsmCacheManager.enter(); |
|
|
165 |
try { |
152 |
try { |
166 |
collect(context, nameAcceptor, symbols); |
153 |
task.get(200, TimeUnit.MILLISECONDS); |
167 |
} finally { |
154 |
} catch (TimeoutException ex) { |
168 |
CsmCacheManager.leave(); |
155 |
// See Bug 246793 - Go To Symbol ignore "pending" result |
169 |
} |
156 |
continue; |
170 |
if (TRACE) { trace("Collecting %d symbols took %d ms", symbols.size(), System.currentTimeMillis() - time); } //NOI18N |
157 |
//if (task.hasResult()) { |
171 |
} |
158 |
// break; |
172 |
|
159 |
//} |
173 |
if (cancelled.get()) { |
160 |
} catch (InterruptedException ex) { |
174 |
cache = null; |
161 |
task.cancel(); |
175 |
} else { |
162 |
// clean flag |
176 |
if (USE_CACHE) { |
163 |
Thread.interrupted(); |
177 |
aCache = new Cache(context.getSearchType(), context.getText()); |
164 |
if (TRACE) { |
178 |
aCache.data.put(context.getProject(), symbols); |
165 |
LOG.log(Level.INFO, "InterruptedException"); // NOI18N |
179 |
cache = aCache; |
166 |
} |
180 |
} |
167 |
break; |
181 |
result.addResult(symbols); |
168 |
} catch (CancellationException ex) { |
182 |
} |
169 |
if (TRACE) { |
183 |
cancelled.set(false); |
170 |
LOG.log(Level.INFO, "CancellationException"); // NOI18N |
184 |
} |
171 |
} |
185 |
|
172 |
break; |
186 |
private void collect(Context context, NameAcceptor nameAcceptor, List<CppSymbolDescriptor> symbols) { |
173 |
} catch (ExecutionException ex) { |
187 |
if (context.getProject() == null) { |
174 |
if (!(ex.getCause() instanceof CancellationException)) { |
188 |
Set<CsmProject> libs = new HashSet<CsmProject>(); |
175 |
Exceptions.printStackTrace(ex); |
189 |
for (CsmProject csmProject : CsmModelAccessor.getModel().projects()) { |
|
|
190 |
if (cancelled.get()) { |
191 |
break; |
192 |
} |
176 |
} |
193 |
collectSymbols(csmProject, nameAcceptor, symbols); |
|
|
194 |
collectLibs(csmProject, libs); |
195 |
} |
196 |
for (CsmProject csmProject : libs) { |
197 |
if (cancelled.get()) { |
198 |
break; |
199 |
} |
200 |
collectSymbols(csmProject, nameAcceptor, symbols); |
201 |
} |
202 |
} else { |
203 |
NativeProject nativeProject = context.getProject().getLookup().lookup(NativeProject.class); |
204 |
if (nativeProject != null) { |
205 |
CsmProject csmProject = CsmModelAccessor.getModel().getProject(nativeProject); |
206 |
if (csmProject != null) { |
207 |
collectSymbols(csmProject, nameAcceptor, symbols); |
208 |
} |
209 |
} |
210 |
} |
211 |
} |
212 |
|
213 |
private void collectLibs(CsmProject project, Collection<CsmProject> libs) { |
214 |
for( CsmProject lib : project.getLibraries()) { |
215 |
if (! libs.contains(lib)) { |
216 |
libs.add(lib); |
217 |
collectLibs(lib, libs); |
218 |
} |
219 |
} |
220 |
} |
221 |
|
222 |
private void collectSymbols(CsmProject csmProject, CsmSelect.NameAcceptor nameAcceptor, List<CppSymbolDescriptor> symbols) { |
223 |
|
224 |
// process project namespaces |
225 |
collectSymbols(csmProject.getGlobalNamespace(), nameAcceptor, symbols); |
226 |
|
227 |
CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); |
228 |
|
229 |
// process project files |
230 |
for(CsmFile csmFile : csmProject.getAllFiles()) { |
231 |
// macros |
232 |
Iterator<CsmMacro> macros = CsmSelect.getMacros(csmFile, nameFilter); |
233 |
while (macros.hasNext() && !cancelled.get()) { |
234 |
CsmMacro macro = macros.next(); |
235 |
if (nameAcceptor.accept(macro.getName())) { |
236 |
if(CsmVisibilityQuery.isVisible(macro)) { |
237 |
symbols.add(new CppSymbolDescriptor(macro)); |
238 |
} |
239 |
} |
240 |
} |
241 |
if (cancelled.get()) { |
242 |
break; |
243 |
} |
244 |
// static functions |
245 |
Iterator<CsmFunction> funcs = CsmSelect.getStaticFunctions(csmFile, nameFilter); |
246 |
while (funcs.hasNext() && !cancelled.get()) { |
247 |
CsmFunction func = funcs.next(); |
248 |
if (nameAcceptor.accept(func.getName())) { |
249 |
if (CsmKindUtilities.isFunctionDefinition(func)) { // which is unlikely, but just in case |
250 |
if(CsmVisibilityQuery.isVisible(func)) { |
251 |
symbols.add(new CppSymbolDescriptor(func)); |
252 |
} |
253 |
} else { |
254 |
// static functions definitions are not returned by Select; |
255 |
// neither do they reside in namespace |
256 |
CsmFunctionDefinition definition = func.getDefinition(); |
257 |
if (definition != null ) { |
258 |
if(CsmVisibilityQuery.isVisible(definition)) { |
259 |
symbols.add(new CppSymbolDescriptor(definition)); |
260 |
} |
261 |
} |
262 |
} |
263 |
} |
264 |
} |
265 |
if (cancelled.get()) { |
266 |
break; |
267 |
} |
268 |
CsmSelect.CsmFilter definitions = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, CsmSelect.getFilterBuilder().createKindFilter(Kind.FUNCTION_DEFINITION)); |
269 |
Iterator<CsmOffsetableDeclaration> declarations = CsmSelect.getDeclarations(csmFile, definitions); |
270 |
while (declarations.hasNext() && !cancelled.get()) { |
271 |
CsmOffsetableDeclaration decl = declarations.next(); |
272 |
if (nameAcceptor.accept(decl.getName())) { |
273 |
if (CsmKindUtilities.isFunctionDefinition(decl) && ((CsmFunction)decl).isStatic()) { |
274 |
CsmFunction func = (CsmFunction) decl; |
275 |
if (func.equals(func.getDeclaration()) && CsmKindUtilities.isFile(func.getScope())) { |
276 |
if(CsmVisibilityQuery.isVisible(func)) { |
277 |
symbols.add(new CppSymbolDescriptor(func)); |
278 |
} |
279 |
} |
280 |
} |
281 |
} |
282 |
} |
283 |
if (cancelled.get()) { |
284 |
break; |
285 |
} |
286 |
// static variables |
287 |
Iterator<CsmVariable> vars = CsmSelect.getStaticVariables(csmFile, nameFilter); |
288 |
while (vars.hasNext() && !cancelled.get()) { |
289 |
CsmVariable var = vars.next(); |
290 |
if (nameAcceptor.accept(var.getName())) { |
291 |
if(CsmVisibilityQuery.isVisible(var)) { |
292 |
symbols.add(new CppSymbolDescriptor(var)); |
293 |
} |
294 |
} |
295 |
} |
296 |
if (cancelled.get()) { |
297 |
break; |
177 |
break; |
298 |
} |
178 |
} |
299 |
} |
179 |
} |
300 |
|
180 |
|
301 |
} |
181 |
if (!task.isDone()) { |
302 |
|
182 |
res.pendingResult(); |
303 |
private void collectSymbols(CsmNamespace namespace, CsmSelect.NameAcceptor nameAcceptor, List<CppSymbolDescriptor> symbols) { |
183 |
if (TRACE) { |
304 |
|
184 |
LOG.log(Level.INFO, "Results are not fully available yet at {0} ms.", System.currentTimeMillis()); // NOI18N |
305 |
// we can filter out "simple" (non-class) namespace elements via CsmSelect; |
|
|
306 |
// later we have to instantiate classes and enums to check their *members* as well |
307 |
|
308 |
CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); |
309 |
|
310 |
CsmSelect.CsmFilter simpleKindFilter = CsmSelect.getFilterBuilder().createKindFilter( |
311 |
CsmDeclaration.Kind.FUNCTION, CsmDeclaration.Kind.FUNCTION_DEFINITION, |
312 |
CsmDeclaration.Kind.FUNCTION_FRIEND, CsmDeclaration.Kind.FUNCTION_FRIEND_DEFINITION, |
313 |
CsmDeclaration.Kind.VARIABLE, CsmDeclaration.Kind.TYPEDEF); |
314 |
|
315 |
CsmSelect.CsmFilter simpleNameAndKindFilter = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, simpleKindFilter); |
316 |
|
317 |
Iterator<? extends CsmOffsetableDeclaration> declarations = CsmSelect.getDeclarations(namespace, simpleNameAndKindFilter); |
318 |
while (declarations.hasNext()) { |
319 |
if (cancelled.get()) { |
320 |
break; |
321 |
} |
322 |
CsmOffsetableDeclaration decl = declarations.next(); |
323 |
if (nameAcceptor.accept(decl.getName())) { |
324 |
if (CsmKindUtilities.isFunction(decl)) { |
325 |
// do not add declarations if their definitions exist |
326 |
if (CsmKindUtilities.isFunctionDefinition(decl)) { |
327 |
if(CsmVisibilityQuery.isVisible(decl)) { |
328 |
symbols.add(new CppSymbolDescriptor(decl)); |
329 |
} |
330 |
} else { |
331 |
CsmFunctionDefinition definition = ((CsmFunction) decl).getDefinition(); |
332 |
if (definition == null || definition == decl) { |
333 |
if(CsmVisibilityQuery.isVisible(decl)) { |
334 |
symbols.add(new CppSymbolDescriptor(decl)); |
335 |
} |
336 |
} |
337 |
} |
338 |
} else { |
339 |
if(CsmVisibilityQuery.isVisible(decl)) { |
340 |
symbols.add(new CppSymbolDescriptor(decl)); |
341 |
} |
342 |
} |
343 |
} |
185 |
} |
344 |
} |
186 |
} |
345 |
|
187 |
|
346 |
// instantiate classes and enums to check them and their members as well |
188 |
res.addResult(task.getResult()); |
347 |
CsmSelect.CsmFilter kindFilter = CsmSelect.getFilterBuilder().createKindFilter( |
|
|
348 |
CsmDeclaration.Kind.CLASS, CsmDeclaration.Kind.ENUM, CsmDeclaration.Kind.STRUCT); |
349 |
CsmSelect.CsmFilter classesOrMembers = CsmSelect.getFilterBuilder().createOrFilter(kindFilter, nameFilter); |
350 |
declarations = CsmSelect.getDeclarations(namespace, kindFilter); |
351 |
while (declarations.hasNext()) { |
352 |
if (cancelled.get()) { |
353 |
break; |
354 |
} |
355 |
addDeclarationIfNeed(declarations.next(), nameAcceptor, symbols, classesOrMembers, nameFilter); |
356 |
} |
357 |
|
358 |
// process nested namespaces |
359 |
for (CsmNamespace child : namespace.getNestedNamespaces()) { |
360 |
if (cancelled.get()) { |
361 |
break; |
362 |
} |
363 |
collectSymbols(child, nameAcceptor, symbols); |
364 |
} |
365 |
} |
189 |
} |
366 |
|
190 |
|
367 |
/** |
191 |
@Override |
368 |
* Is called for classes, enums and their members. |
192 |
public void cancel() { |
369 |
* Checks name, if it suites, adds result to symbols collection. |
193 |
if (TRACE) { |
370 |
* Does the same recursively (with members/enumerators) |
194 |
LOG.info("cancel request"); // NOI18N |
371 |
*/ |
|
|
372 |
private void addDeclarationIfNeed(CsmOffsetableDeclaration decl, CsmSelect.NameAcceptor nameAcceptor, List<CppSymbolDescriptor> symbols, |
373 |
CsmSelect.CsmFilter classesOrMembers, CsmSelect.CsmFilter nameFilter) { |
374 |
if (nameAcceptor.accept(decl.getName())) { |
375 |
if(CsmVisibilityQuery.isVisible(decl)) { |
376 |
symbols.add(new CppSymbolDescriptor(decl)); |
377 |
} |
378 |
} |
195 |
} |
379 |
if (CsmKindUtilities.isClass(decl)) { |
196 |
WorkerTask task; |
380 |
CsmClass cls = (CsmClass) decl; |
197 |
synchronized (activeTaskLock) { |
381 |
final Iterator<CsmMember> classMembers = CsmSelect.getClassMembers(cls, classesOrMembers); |
198 |
task = activeTask; |
382 |
while(classMembers.hasNext()) { |
199 |
activeTask = null; |
383 |
addDeclarationIfNeed(classMembers.next(), nameAcceptor, symbols, classesOrMembers, nameFilter); |
200 |
} |
384 |
} |
201 |
if (task != null) { |
385 |
} else if (CsmKindUtilities.isEnum(decl)) { |
202 |
task.cancel(); |
386 |
CsmEnum en = (CsmEnum) decl; |
|
|
387 |
Iterator<CsmEnumerator> enumerators = CsmSelect.getEnumerators(en, nameFilter); |
388 |
while(enumerators.hasNext()) { |
389 |
CsmEnumerator enumerator = enumerators.next(); |
390 |
if (nameAcceptor.accept(enumerator.getName())) { |
391 |
if(CsmVisibilityQuery.isVisible(enumerator)) { |
392 |
symbols.add(new CppSymbolDescriptor(enumerator)); |
393 |
} |
394 |
} |
395 |
} |
396 |
} |
203 |
} |
397 |
} |
204 |
} |
398 |
|
205 |
|
399 |
@Override |
206 |
@Override |
400 |
public String getDisplayName() { |
207 |
public void cleanup() { |
401 |
return NbBundle.getMessage(getClass(), "CPP_Provider_Display_Name"); |
208 |
// GoToTypeAction-RP |
402 |
} |
209 |
if (TRACE) { |
403 |
|
210 |
LOG.info("cleanup request"); // NOI18N |
404 |
@Override |
211 |
} |
405 |
public String name() { |
212 |
cancel(); |
406 |
return "C/C++"; //NOI18N |
|
|
407 |
} |
213 |
} |
408 |
|
214 |
|
409 |
private String toString(Context context) { |
215 |
private String toString(Context context) { |
410 |
return String.format("Context: prj=%s type=%s text=%s", context.getProject(), context.getSearchType(), context.getText()); //NOI18N |
216 |
return String.format("Context: prj=%s type=%s text=%s", context.getProject(), context.getSearchType(), context.getText()); //NOI18N |
411 |
} |
217 |
} |
|
|
218 |
|
219 |
public static CsmSelect.NameAcceptor createNameAcceptor(final String text, final SearchType searchType) { |
220 |
final NameMatcher nameMatcher = NameMatcherFactory.createNameMatcher(text, searchType); |
221 |
return new NameAcceptorImpl(nameMatcher); |
222 |
} |
412 |
|
223 |
|
413 |
private void trace(String format, Object... args) { |
224 |
private static boolean sameContext(Context context1, Context context2) { |
414 |
if (TRACE) { |
225 |
if (context1 == null) { |
415 |
format = String.format("%s @%x %s\n", getClass().getSimpleName(), hashCode(), format); //NOI18N |
226 |
return context2 == null; |
416 |
System.err.printf(format, args); |
|
|
417 |
} |
227 |
} |
|
|
228 |
if (context2 == null) { |
229 |
return false; |
230 |
} |
231 |
if (!context1.getSearchType().equals(context2.getSearchType())) { |
232 |
return false; |
233 |
} |
234 |
if (!context1.getText().equals(context2.getText())) { |
235 |
return false; |
236 |
} |
237 |
return true; |
418 |
} |
238 |
} |
419 |
|
239 |
|
420 |
private static final class NameAcceptorImpl implements NameAcceptor { |
240 |
private static final class NameAcceptorImpl implements NameAcceptor { |
Lines 450-453
Link Here
|
450 |
} |
270 |
} |
451 |
} |
271 |
} |
452 |
|
272 |
|
|
|
273 |
private static class WorkerTask extends FutureTask<Void> { |
274 |
|
275 |
private final Set<CppSymbolDescriptor> result; |
276 |
private final Context context; |
277 |
private final AtomicBoolean cancelled; |
278 |
|
279 |
public WorkerTask(Context context, CsmSelect.NameAcceptor nameAcceptor) { |
280 |
this(context, nameAcceptor, new HashSet<CppSymbolDescriptor>(), new AtomicBoolean(false)); |
281 |
} |
282 |
|
283 |
private WorkerTask(Context context, CsmSelect.NameAcceptor nameAcceptor, Set<CppSymbolDescriptor> result, AtomicBoolean cancelled) { |
284 |
super(new Worker(context, nameAcceptor, result, cancelled), null); |
285 |
this.context = context; |
286 |
this.result = result; |
287 |
this.cancelled = cancelled; |
288 |
} |
289 |
|
290 |
private List<CppSymbolDescriptor> getResult() { |
291 |
synchronized (resultLock) { |
292 |
return new ArrayList<CppSymbolDescriptor>(result); |
293 |
} |
294 |
} |
295 |
|
296 |
private boolean hasResult() { |
297 |
synchronized (resultLock) { |
298 |
return !result.isEmpty(); |
299 |
} |
300 |
} |
301 |
|
302 |
public void cancel() { |
303 |
cancelled.set(true); |
304 |
} |
305 |
} |
306 |
|
307 |
private static class Worker implements Runnable { |
308 |
|
309 |
private final Context context; |
310 |
private final Set<CppSymbolDescriptor> result; |
311 |
private long startTime; |
312 |
private final AtomicBoolean cancelled; |
313 |
private final CsmSelect.NameAcceptor nameAcceptor; |
314 |
|
315 |
private Worker(Context context, CsmSelect.NameAcceptor nameAcceptor, Set<CppSymbolDescriptor> result, AtomicBoolean cancelled) { |
316 |
if (TRACE) { |
317 |
LOG.log(Level.INFO, "New Worker for searching \"{0}\", {1} in {2} created.", // NOI18N |
318 |
new Object[]{context.getText(), context.getSearchType().name(), context.getProject()}); |
319 |
} |
320 |
this.context = context; |
321 |
this.result = result; |
322 |
this.cancelled = cancelled; |
323 |
this.nameAcceptor = nameAcceptor; |
324 |
} |
325 |
|
326 |
@Override |
327 |
public void run() { |
328 |
if (TRACE) { |
329 |
startTime = System.currentTimeMillis(); |
330 |
} |
331 |
try { |
332 |
CsmCacheManager.enter(); |
333 |
try { |
334 |
collect(context); |
335 |
} finally { |
336 |
CsmCacheManager.leave(); |
337 |
} |
338 |
if (TRACE) { |
339 |
LOG.log(Level.INFO, "Worker for searching \"{0}\", {1} in {2} cancelled [after {3} ms.].", // NOI18N |
340 |
new Object[]{context.getText(), context.getSearchType().name(), context.getProject(), (System.currentTimeMillis() - startTime)}); |
341 |
} |
342 |
} catch (CancellationException ex) { |
343 |
if (TRACE) { |
344 |
LOG.log(Level.INFO, "Worker for searching \"{0}\", {1} in {2} cancelled [after {3} ms.].", // NOI18N |
345 |
new Object[]{context.getText(), context.getSearchType().name(), context.getProject(), (System.currentTimeMillis() - startTime)}); |
346 |
} |
347 |
} finally { |
348 |
if (TRACE) { |
349 |
LOG.log(Level.INFO, "Worker for searching \"{0}\", {1} in {2} done [in {3} ms.].", // NOI18N |
350 |
new Object[]{context.getText(), context.getSearchType().name(), context.getProject(), (System.currentTimeMillis() - startTime)}); |
351 |
} |
352 |
} |
353 |
} |
354 |
|
355 |
private void collect(Context context) { |
356 |
if (context.getProject() == null) { |
357 |
Set<CsmProject> libs = new HashSet<CsmProject>(); |
358 |
for (CsmProject csmProject : CsmModelAccessor.getModel().projects()) { |
359 |
checkCancelled(); |
360 |
collectSymbols(csmProject); |
361 |
collectLibs(csmProject, libs); |
362 |
} |
363 |
for (CsmProject csmProject : libs) { |
364 |
checkCancelled(); |
365 |
collectSymbols(csmProject); |
366 |
} |
367 |
} else { |
368 |
NativeProject nativeProject = context.getProject().getLookup().lookup(NativeProject.class); |
369 |
if (nativeProject != null) { |
370 |
CsmProject csmProject = CsmModelAccessor.getModel().getProject(nativeProject); |
371 |
if (csmProject != null) { |
372 |
collectSymbols(csmProject); |
373 |
} |
374 |
} |
375 |
} |
376 |
} |
377 |
|
378 |
private void collectLibs(CsmProject project, Collection<CsmProject> libs) { |
379 |
for( CsmProject lib : project.getLibraries()) { |
380 |
if (! libs.contains(lib)) { |
381 |
libs.add(lib); |
382 |
collectLibs(lib, libs); |
383 |
} |
384 |
} |
385 |
} |
386 |
|
387 |
private void collectSymbols(CsmProject csmProject) { |
388 |
|
389 |
// process project namespaces |
390 |
collectSymbols(csmProject.getGlobalNamespace()); |
391 |
|
392 |
CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); |
393 |
|
394 |
// process project files |
395 |
for(CsmFile csmFile : csmProject.getAllFiles()) { |
396 |
checkCancelled(); |
397 |
// macros |
398 |
Iterator<CsmMacro> macros = CsmSelect.getMacros(csmFile, nameFilter); |
399 |
while (macros.hasNext()) { |
400 |
checkCancelled(); |
401 |
CsmMacro macro = macros.next(); |
402 |
if (nameAcceptor.accept(macro.getName())) { |
403 |
if(CsmVisibilityQuery.isVisible(macro)) { |
404 |
addResult(new CppSymbolDescriptor(macro)); |
405 |
} |
406 |
} |
407 |
} |
408 |
checkCancelled(); |
409 |
// static functions |
410 |
Iterator<CsmFunction> funcs = CsmSelect.getStaticFunctions(csmFile, nameFilter); |
411 |
while (funcs.hasNext()) { |
412 |
checkCancelled(); |
413 |
CsmFunction func = funcs.next(); |
414 |
if (nameAcceptor.accept(func.getName())) { |
415 |
if (CsmKindUtilities.isFunctionDefinition(func)) { // which is unlikely, but just in case |
416 |
if(CsmVisibilityQuery.isVisible(func)) { |
417 |
addResult(new CppSymbolDescriptor(func)); |
418 |
} |
419 |
} else { |
420 |
// static functions definitions are not returned by Select; |
421 |
// neither do they reside in namespace |
422 |
CsmFunctionDefinition definition = func.getDefinition(); |
423 |
if (definition != null ) { |
424 |
if(CsmVisibilityQuery.isVisible(definition)) { |
425 |
addResult(new CppSymbolDescriptor(definition)); |
426 |
} |
427 |
} |
428 |
} |
429 |
} |
430 |
} |
431 |
checkCancelled(); |
432 |
CsmSelect.CsmFilter definitions = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, CsmSelect.getFilterBuilder().createKindFilter(Kind.FUNCTION_DEFINITION)); |
433 |
Iterator<CsmOffsetableDeclaration> declarations = CsmSelect.getDeclarations(csmFile, definitions); |
434 |
while (declarations.hasNext()) { |
435 |
checkCancelled(); |
436 |
CsmOffsetableDeclaration decl = declarations.next(); |
437 |
if (nameAcceptor.accept(decl.getName())) { |
438 |
if (CsmKindUtilities.isFunctionDefinition(decl) && ((CsmFunction)decl).isStatic()) { |
439 |
CsmFunction func = (CsmFunction) decl; |
440 |
if (func.equals(func.getDeclaration()) && CsmKindUtilities.isFile(func.getScope())) { |
441 |
if(CsmVisibilityQuery.isVisible(func)) { |
442 |
addResult(new CppSymbolDescriptor(func)); |
443 |
} |
444 |
} |
445 |
} |
446 |
} |
447 |
} |
448 |
checkCancelled(); |
449 |
// static variables |
450 |
Iterator<CsmVariable> vars = CsmSelect.getStaticVariables(csmFile, nameFilter); |
451 |
while (vars.hasNext()) { |
452 |
checkCancelled(); |
453 |
CsmVariable var = vars.next(); |
454 |
if (nameAcceptor.accept(var.getName())) { |
455 |
if(CsmVisibilityQuery.isVisible(var)) { |
456 |
addResult(new CppSymbolDescriptor(var)); |
457 |
} |
458 |
} |
459 |
} |
460 |
} |
461 |
} |
462 |
|
463 |
private void collectSymbols(CsmNamespace namespace) { |
464 |
|
465 |
// we can filter out "simple" (non-class) namespace elements via CsmSelect; |
466 |
// later we have to instantiate classes and enums to check their *members* as well |
467 |
|
468 |
CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); |
469 |
|
470 |
CsmSelect.CsmFilter simpleKindFilter = CsmSelect.getFilterBuilder().createKindFilter( |
471 |
CsmDeclaration.Kind.FUNCTION, CsmDeclaration.Kind.FUNCTION_DEFINITION, |
472 |
CsmDeclaration.Kind.FUNCTION_FRIEND, CsmDeclaration.Kind.FUNCTION_FRIEND_DEFINITION, |
473 |
CsmDeclaration.Kind.VARIABLE, CsmDeclaration.Kind.TYPEDEF); |
474 |
|
475 |
CsmSelect.CsmFilter simpleNameAndKindFilter = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, simpleKindFilter); |
476 |
|
477 |
Iterator<? extends CsmOffsetableDeclaration> declarations = CsmSelect.getDeclarations(namespace, simpleNameAndKindFilter); |
478 |
while (declarations.hasNext()) { |
479 |
checkCancelled(); |
480 |
CsmOffsetableDeclaration decl = declarations.next(); |
481 |
if (nameAcceptor.accept(decl.getName())) { |
482 |
if (CsmKindUtilities.isFunction(decl)) { |
483 |
// do not add declarations if their definitions exist |
484 |
if (CsmKindUtilities.isFunctionDefinition(decl)) { |
485 |
if(CsmVisibilityQuery.isVisible(decl)) { |
486 |
addResult(new CppSymbolDescriptor(decl)); |
487 |
} |
488 |
} else { |
489 |
CsmFunctionDefinition definition = ((CsmFunction) decl).getDefinition(); |
490 |
if (definition == null || definition == decl) { |
491 |
if(CsmVisibilityQuery.isVisible(decl)) { |
492 |
addResult(new CppSymbolDescriptor(decl)); |
493 |
} |
494 |
} |
495 |
} |
496 |
} else { |
497 |
if(CsmVisibilityQuery.isVisible(decl)) { |
498 |
addResult(new CppSymbolDescriptor(decl)); |
499 |
} |
500 |
} |
501 |
} |
502 |
} |
503 |
|
504 |
// instantiate classes and enums to check them and their members as well |
505 |
CsmSelect.CsmFilter kindFilter = CsmSelect.getFilterBuilder().createKindFilter( |
506 |
CsmDeclaration.Kind.CLASS, CsmDeclaration.Kind.ENUM, CsmDeclaration.Kind.STRUCT); |
507 |
CsmSelect.CsmFilter classesOrMembers = CsmSelect.getFilterBuilder().createOrFilter(kindFilter, nameFilter); |
508 |
declarations = CsmSelect.getDeclarations(namespace, kindFilter); |
509 |
while (declarations.hasNext()) { |
510 |
checkCancelled(); |
511 |
addDeclarationIfNeed(declarations.next(), classesOrMembers, nameFilter); |
512 |
} |
513 |
|
514 |
// process nested namespaces |
515 |
for (CsmNamespace child : namespace.getNestedNamespaces()) { |
516 |
checkCancelled(); |
517 |
collectSymbols(child); |
518 |
} |
519 |
} |
520 |
|
521 |
/** |
522 |
* Is called for classes, enums and their members. |
523 |
* Checks name, if it suites, adds result to symbols collection. |
524 |
* Does the same recursively (with members/enumerators) |
525 |
*/ |
526 |
private void addDeclarationIfNeed(CsmOffsetableDeclaration decl, CsmSelect.CsmFilter classesOrMembers, CsmSelect.CsmFilter nameFilter) { |
527 |
if (nameAcceptor.accept(decl.getName())) { |
528 |
if(CsmVisibilityQuery.isVisible(decl)) { |
529 |
addResult(new CppSymbolDescriptor(decl)); |
530 |
} |
531 |
} |
532 |
if (CsmKindUtilities.isClass(decl)) { |
533 |
CsmClass cls = (CsmClass) decl; |
534 |
final Iterator<CsmMember> classMembers = CsmSelect.getClassMembers(cls, classesOrMembers); |
535 |
while(classMembers.hasNext()) { |
536 |
addDeclarationIfNeed(classMembers.next(), classesOrMembers, nameFilter); |
537 |
} |
538 |
} else if (CsmKindUtilities.isEnum(decl)) { |
539 |
CsmEnum en = (CsmEnum) decl; |
540 |
Iterator<CsmEnumerator> enumerators = CsmSelect.getEnumerators(en, nameFilter); |
541 |
while(enumerators.hasNext()) { |
542 |
CsmEnumerator enumerator = enumerators.next(); |
543 |
if (nameAcceptor.accept(enumerator.getName())) { |
544 |
if(CsmVisibilityQuery.isVisible(enumerator)) { |
545 |
addResult(new CppSymbolDescriptor(enumerator)); |
546 |
} |
547 |
} |
548 |
} |
549 |
} |
550 |
} |
551 |
|
552 |
private void checkCancelled() throws CancellationException { |
553 |
if (cancelled.get()) { |
554 |
throw new CancellationException(); |
555 |
} |
556 |
} |
557 |
|
558 |
private void addResult(CppSymbolDescriptor symbolDescriptor) { |
559 |
synchronized (resultLock) { |
560 |
result.add(symbolDescriptor); |
561 |
} |
562 |
} |
563 |
} |
453 |
} |
564 |
} |