This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 246800
Collapse All | Expand All

(-)a/cnd.gotodeclaration/src/org/netbeans/modules/cnd/gotodeclaration/symbol/CppSymbolProvider.java (-285 / +396 lines)
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
}

Return to bug 246800