# HG changeset patch # User Alexander Simon # Date 1409566294 -14400 # Mon Sep 01 14:11:34 2014 +0400 # Node ID 8ecc0ecd74df643fa66da769a8a31b09f37625dd # Parent 6f74f50530c907f133a329b0b715bb8bee198cbd fixing Bug 246800 - C/C++ Go To Symbol provider does not support "pending" result. diff --git a/cnd.gotodeclaration/src/org/netbeans/modules/cnd/gotodeclaration/symbol/CppSymbolProvider.java b/cnd.gotodeclaration/src/org/netbeans/modules/cnd/gotodeclaration/symbol/CppSymbolProvider.java --- a/cnd.gotodeclaration/src/org/netbeans/modules/cnd/gotodeclaration/symbol/CppSymbolProvider.java +++ b/cnd.gotodeclaration/src/org/netbeans/modules/cnd/gotodeclaration/symbol/CppSymbolProvider.java @@ -44,16 +44,18 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; -import org.netbeans.api.project.Project; import org.netbeans.modules.cnd.api.model.CsmClass; import org.netbeans.modules.cnd.api.model.CsmDeclaration; import org.netbeans.modules.cnd.api.model.CsmDeclaration.Kind; @@ -80,7 +82,9 @@ import org.netbeans.spi.jumpto.support.NameMatcherFactory; import org.netbeans.spi.jumpto.symbol.SymbolProvider; import org.netbeans.spi.jumpto.type.SearchType; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; /** * SymbolProvider for C/C++ implementation @@ -89,50 +93,36 @@ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.jumpto.symbol.SymbolProvider.class) public class CppSymbolProvider implements SymbolProvider { - private static class Cache { - public final String text; - public final SearchType searchType; - private final Map> data; - public Cache(SearchType searchType, String text) { - this.text = text; - this.searchType = searchType; - this.data = new HashMap>(); + private static final boolean TRACE = true;//Boolean.getBoolean("cnd.gotosymbol.trace"); + private static final Logger LOG = TRACE ? Logger.getLogger("cnd.symbol.provider.trace") : null; // NOI18N + private static final RequestProcessor RP = new RequestProcessor(CppSymbolProvider.class.getName(), 1); + private static final Object resultLock = new Object(); + private final Object activeTaskLock = new Object(); + private WorkerTask activeTask; + + + public CppSymbolProvider() { + if (TRACE) { + LOG.info("CppSymbolProvider created"); // NOI18N } } - private volatile Cache cache; - private final AtomicBoolean cancelled = new AtomicBoolean(false); - private static final boolean TRACE = Boolean.getBoolean("cnd.gotosymbol.trace"); - private static final boolean USE_CACHE = CndUtils.getBoolean("cnd.gotosymbol.cache", true); - - public CppSymbolProvider() { - if (TRACE) { trace("ctor"); } // NOI18N + @Override + public String name() { + return "C/C++"; //NOI18N } @Override - public void cancel() { - if (TRACE) { trace("cancel"); } // NOI18N - cancelled.set(true); - cache = null; - } - - @Override - public void cleanup() { - if (TRACE) { trace("cleanup"); } // NOI18N - cancelled.set(false); - cache = null; - } - - public static CsmSelect.NameAcceptor createNameAcceptor(final String text, final SearchType searchType) { - final NameMatcher nameMatcher = NameMatcherFactory.createNameMatcher(text, searchType); - return new NameAcceptorImpl(nameMatcher); + public String getDisplayName() { + return NbBundle.getMessage(getClass(), "CPP_Provider_Display_Name"); } // synchronized is just in case here - it shouldn't be called async @Override - public synchronized void computeSymbolNames(Context context, Result result) { - if (TRACE) { trace("computeSymbolNames %s", toString(context)); } // NOI18N - cancelled.set(false); + public synchronized void computeSymbolNames(Context context, Result res) { + if (TRACE) { + LOG.log(Level.INFO, "computeSymbolNames {0}", toString(context)); // NOI18N + } CsmSelect.NameAcceptor nameAcceptor = createNameAcceptor(context.getText(), context.getSearchType()); if (nameAcceptor == null) { if (CndUtils.isDebugMode()) { @@ -141,280 +131,110 @@ } return; } + + WorkerTask task; + synchronized (activeTaskLock) { + task = activeTask; + if (task != null && !sameContext(task.context, context)) { + task.cancel(); + task = null; + activeTask = null; + } - List symbols = new ArrayList(); - - boolean filled = false; - Cache aCache = cache; - if (aCache != null && context.getSearchType() == aCache.searchType && context.getText().startsWith(aCache.text)) { - List cached = aCache.data.get(context.getProject()); - if (cached != null) { - filled = true; - long time = System.currentTimeMillis(); - for (CppSymbolDescriptor desc : cached) { - if (nameAcceptor.accept(desc.getRawName())) { - symbols.add(desc); - } - } - if (TRACE) { trace("Narrowing %d symbols took %d ms", symbols.size(), System.currentTimeMillis() - time); } //NOI18N + if (task == null) { + task = new WorkerTask(context, nameAcceptor); + activeTask = task; + RP.submit(task); } } - if (!filled) { - long time = System.currentTimeMillis(); - CsmCacheManager.enter(); + + while (!task.isDone()) { try { - collect(context, nameAcceptor, symbols); - } finally { - CsmCacheManager.leave(); - } - if (TRACE) { trace("Collecting %d symbols took %d ms", symbols.size(), System.currentTimeMillis() - time); } //NOI18N - } - - if (cancelled.get()) { - cache = null; - } else { - if (USE_CACHE) { - aCache = new Cache(context.getSearchType(), context.getText()); - aCache.data.put(context.getProject(), symbols); - cache = aCache; - } - result.addResult(symbols); - } - cancelled.set(false); - } - - private void collect(Context context, NameAcceptor nameAcceptor, List symbols) { - if (context.getProject() == null) { - Set libs = new HashSet(); - for (CsmProject csmProject : CsmModelAccessor.getModel().projects()) { - if (cancelled.get()) { - break; + task.get(200, TimeUnit.MILLISECONDS); + } catch (TimeoutException ex) { + // See Bug 246793 - Go To Symbol ignore "pending" result + continue; + //if (task.hasResult()) { + // break; + //} + } catch (InterruptedException ex) { + task.cancel(); + // clean flag + Thread.interrupted(); + if (TRACE) { + LOG.log(Level.INFO, "InterruptedException"); // NOI18N + } + break; + } catch (CancellationException ex) { + if (TRACE) { + LOG.log(Level.INFO, "CancellationException"); // NOI18N + } + break; + } catch (ExecutionException ex) { + if (!(ex.getCause() instanceof CancellationException)) { + Exceptions.printStackTrace(ex); } - collectSymbols(csmProject, nameAcceptor, symbols); - collectLibs(csmProject, libs); - } - for (CsmProject csmProject : libs) { - if (cancelled.get()) { - break; - } - collectSymbols(csmProject, nameAcceptor, symbols); - } - } else { - NativeProject nativeProject = context.getProject().getLookup().lookup(NativeProject.class); - if (nativeProject != null) { - CsmProject csmProject = CsmModelAccessor.getModel().getProject(nativeProject); - if (csmProject != null) { - collectSymbols(csmProject, nameAcceptor, symbols); - } - } - } - } - - private void collectLibs(CsmProject project, Collection libs) { - for( CsmProject lib : project.getLibraries()) { - if (! libs.contains(lib)) { - libs.add(lib); - collectLibs(lib, libs); - } - } - } - - private void collectSymbols(CsmProject csmProject, CsmSelect.NameAcceptor nameAcceptor, List symbols) { - - // process project namespaces - collectSymbols(csmProject.getGlobalNamespace(), nameAcceptor, symbols); - - CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); - - // process project files - for(CsmFile csmFile : csmProject.getAllFiles()) { - // macros - Iterator macros = CsmSelect.getMacros(csmFile, nameFilter); - while (macros.hasNext() && !cancelled.get()) { - CsmMacro macro = macros.next(); - if (nameAcceptor.accept(macro.getName())) { - if(CsmVisibilityQuery.isVisible(macro)) { - symbols.add(new CppSymbolDescriptor(macro)); - } - } - } - if (cancelled.get()) { - break; - } - // static functions - Iterator funcs = CsmSelect.getStaticFunctions(csmFile, nameFilter); - while (funcs.hasNext() && !cancelled.get()) { - CsmFunction func = funcs.next(); - if (nameAcceptor.accept(func.getName())) { - if (CsmKindUtilities.isFunctionDefinition(func)) { // which is unlikely, but just in case - if(CsmVisibilityQuery.isVisible(func)) { - symbols.add(new CppSymbolDescriptor(func)); - } - } else { - // static functions definitions are not returned by Select; - // neither do they reside in namespace - CsmFunctionDefinition definition = func.getDefinition(); - if (definition != null ) { - if(CsmVisibilityQuery.isVisible(definition)) { - symbols.add(new CppSymbolDescriptor(definition)); - } - } - } - } - } - if (cancelled.get()) { - break; - } - CsmSelect.CsmFilter definitions = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, CsmSelect.getFilterBuilder().createKindFilter(Kind.FUNCTION_DEFINITION)); - Iterator declarations = CsmSelect.getDeclarations(csmFile, definitions); - while (declarations.hasNext() && !cancelled.get()) { - CsmOffsetableDeclaration decl = declarations.next(); - if (nameAcceptor.accept(decl.getName())) { - if (CsmKindUtilities.isFunctionDefinition(decl) && ((CsmFunction)decl).isStatic()) { - CsmFunction func = (CsmFunction) decl; - if (func.equals(func.getDeclaration()) && CsmKindUtilities.isFile(func.getScope())) { - if(CsmVisibilityQuery.isVisible(func)) { - symbols.add(new CppSymbolDescriptor(func)); - } - } - } - } - } - if (cancelled.get()) { - break; - } - // static variables - Iterator vars = CsmSelect.getStaticVariables(csmFile, nameFilter); - while (vars.hasNext() && !cancelled.get()) { - CsmVariable var = vars.next(); - if (nameAcceptor.accept(var.getName())) { - if(CsmVisibilityQuery.isVisible(var)) { - symbols.add(new CppSymbolDescriptor(var)); - } - } - } - if (cancelled.get()) { break; } } - } - - private void collectSymbols(CsmNamespace namespace, CsmSelect.NameAcceptor nameAcceptor, List symbols) { - - // we can filter out "simple" (non-class) namespace elements via CsmSelect; - // later we have to instantiate classes and enums to check their *members* as well - - CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); - - CsmSelect.CsmFilter simpleKindFilter = CsmSelect.getFilterBuilder().createKindFilter( - CsmDeclaration.Kind.FUNCTION, CsmDeclaration.Kind.FUNCTION_DEFINITION, - CsmDeclaration.Kind.FUNCTION_FRIEND, CsmDeclaration.Kind.FUNCTION_FRIEND_DEFINITION, - CsmDeclaration.Kind.VARIABLE, CsmDeclaration.Kind.TYPEDEF); - - CsmSelect.CsmFilter simpleNameAndKindFilter = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, simpleKindFilter); - - Iterator declarations = CsmSelect.getDeclarations(namespace, simpleNameAndKindFilter); - while (declarations.hasNext()) { - if (cancelled.get()) { - break; - } - CsmOffsetableDeclaration decl = declarations.next(); - if (nameAcceptor.accept(decl.getName())) { - if (CsmKindUtilities.isFunction(decl)) { - // do not add declarations if their definitions exist - if (CsmKindUtilities.isFunctionDefinition(decl)) { - if(CsmVisibilityQuery.isVisible(decl)) { - symbols.add(new CppSymbolDescriptor(decl)); - } - } else { - CsmFunctionDefinition definition = ((CsmFunction) decl).getDefinition(); - if (definition == null || definition == decl) { - if(CsmVisibilityQuery.isVisible(decl)) { - symbols.add(new CppSymbolDescriptor(decl)); - } - } - } - } else { - if(CsmVisibilityQuery.isVisible(decl)) { - symbols.add(new CppSymbolDescriptor(decl)); - } - } + if (!task.isDone()) { + res.pendingResult(); + if (TRACE) { + LOG.log(Level.INFO, "Results are not fully available yet at {0} ms.", System.currentTimeMillis()); // NOI18N } } - // instantiate classes and enums to check them and their members as well - CsmSelect.CsmFilter kindFilter = CsmSelect.getFilterBuilder().createKindFilter( - CsmDeclaration.Kind.CLASS, CsmDeclaration.Kind.ENUM, CsmDeclaration.Kind.STRUCT); - CsmSelect.CsmFilter classesOrMembers = CsmSelect.getFilterBuilder().createOrFilter(kindFilter, nameFilter); - declarations = CsmSelect.getDeclarations(namespace, kindFilter); - while (declarations.hasNext()) { - if (cancelled.get()) { - break; - } - addDeclarationIfNeed(declarations.next(), nameAcceptor, symbols, classesOrMembers, nameFilter); - } - - // process nested namespaces - for (CsmNamespace child : namespace.getNestedNamespaces()) { - if (cancelled.get()) { - break; - } - collectSymbols(child, nameAcceptor, symbols); - } + res.addResult(task.getResult()); } - /** - * Is called for classes, enums and their members. - * Checks name, if it suites, adds result to symbols collection. - * Does the same recursively (with members/enumerators) - */ - private void addDeclarationIfNeed(CsmOffsetableDeclaration decl, CsmSelect.NameAcceptor nameAcceptor, List symbols, - CsmSelect.CsmFilter classesOrMembers, CsmSelect.CsmFilter nameFilter) { - if (nameAcceptor.accept(decl.getName())) { - if(CsmVisibilityQuery.isVisible(decl)) { - symbols.add(new CppSymbolDescriptor(decl)); - } + @Override + public void cancel() { + if (TRACE) { + LOG.info("cancel request"); // NOI18N } - if (CsmKindUtilities.isClass(decl)) { - CsmClass cls = (CsmClass) decl; - final Iterator classMembers = CsmSelect.getClassMembers(cls, classesOrMembers); - while(classMembers.hasNext()) { - addDeclarationIfNeed(classMembers.next(), nameAcceptor, symbols, classesOrMembers, nameFilter); - } - } else if (CsmKindUtilities.isEnum(decl)) { - CsmEnum en = (CsmEnum) decl; - Iterator enumerators = CsmSelect.getEnumerators(en, nameFilter); - while(enumerators.hasNext()) { - CsmEnumerator enumerator = enumerators.next(); - if (nameAcceptor.accept(enumerator.getName())) { - if(CsmVisibilityQuery.isVisible(enumerator)) { - symbols.add(new CppSymbolDescriptor(enumerator)); - } - } - } + WorkerTask task; + synchronized (activeTaskLock) { + task = activeTask; + activeTask = null; + } + if (task != null) { + task.cancel(); } } @Override - public String getDisplayName() { - return NbBundle.getMessage(getClass(), "CPP_Provider_Display_Name"); - } - - @Override - public String name() { - return "C/C++"; //NOI18N + public void cleanup() { + // GoToTypeAction-RP + if (TRACE) { + LOG.info("cleanup request"); // NOI18N + } + cancel(); } private String toString(Context context) { return String.format("Context: prj=%s type=%s text=%s", context.getProject(), context.getSearchType(), context.getText()); //NOI18N } + + public static CsmSelect.NameAcceptor createNameAcceptor(final String text, final SearchType searchType) { + final NameMatcher nameMatcher = NameMatcherFactory.createNameMatcher(text, searchType); + return new NameAcceptorImpl(nameMatcher); + } - private void trace(String format, Object... args) { - if (TRACE) { - format = String.format("%s @%x %s\n", getClass().getSimpleName(), hashCode(), format); //NOI18N - System.err.printf(format, args); + private static boolean sameContext(Context context1, Context context2) { + if (context1 == null) { + return context2 == null; } + if (context2 == null) { + return false; + } + if (!context1.getSearchType().equals(context2.getSearchType())) { + return false; + } + if (!context1.getText().equals(context2.getText())) { + return false; + } + return true; } private static final class NameAcceptorImpl implements NameAcceptor { @@ -450,4 +270,295 @@ } } + private static class WorkerTask extends FutureTask { + + private final Set result; + private final Context context; + private final AtomicBoolean cancelled; + + public WorkerTask(Context context, CsmSelect.NameAcceptor nameAcceptor) { + this(context, nameAcceptor, new HashSet(), new AtomicBoolean(false)); + } + + private WorkerTask(Context context, CsmSelect.NameAcceptor nameAcceptor, Set result, AtomicBoolean cancelled) { + super(new Worker(context, nameAcceptor, result, cancelled), null); + this.context = context; + this.result = result; + this.cancelled = cancelled; + } + + private List getResult() { + synchronized (resultLock) { + return new ArrayList(result); + } + } + + private boolean hasResult() { + synchronized (resultLock) { + return !result.isEmpty(); + } + } + + public void cancel() { + cancelled.set(true); + } + } + + private static class Worker implements Runnable { + + private final Context context; + private final Set result; + private long startTime; + private final AtomicBoolean cancelled; + private final CsmSelect.NameAcceptor nameAcceptor; + + private Worker(Context context, CsmSelect.NameAcceptor nameAcceptor, Set result, AtomicBoolean cancelled) { + if (TRACE) { + LOG.log(Level.INFO, "New Worker for searching \"{0}\", {1} in {2} created.", // NOI18N + new Object[]{context.getText(), context.getSearchType().name(), context.getProject()}); + } + this.context = context; + this.result = result; + this.cancelled = cancelled; + this.nameAcceptor = nameAcceptor; + } + + @Override + public void run() { + if (TRACE) { + startTime = System.currentTimeMillis(); + } + try { + CsmCacheManager.enter(); + try { + collect(context); + } finally { + CsmCacheManager.leave(); + } + if (TRACE) { + LOG.log(Level.INFO, "Worker for searching \"{0}\", {1} in {2} cancelled [after {3} ms.].", // NOI18N + new Object[]{context.getText(), context.getSearchType().name(), context.getProject(), (System.currentTimeMillis() - startTime)}); + } + } catch (CancellationException ex) { + if (TRACE) { + LOG.log(Level.INFO, "Worker for searching \"{0}\", {1} in {2} cancelled [after {3} ms.].", // NOI18N + new Object[]{context.getText(), context.getSearchType().name(), context.getProject(), (System.currentTimeMillis() - startTime)}); + } + } finally { + if (TRACE) { + LOG.log(Level.INFO, "Worker for searching \"{0}\", {1} in {2} done [in {3} ms.].", // NOI18N + new Object[]{context.getText(), context.getSearchType().name(), context.getProject(), (System.currentTimeMillis() - startTime)}); + } + } + } + + private void collect(Context context) { + if (context.getProject() == null) { + Set libs = new HashSet(); + for (CsmProject csmProject : CsmModelAccessor.getModel().projects()) { + checkCancelled(); + collectSymbols(csmProject); + collectLibs(csmProject, libs); + } + for (CsmProject csmProject : libs) { + checkCancelled(); + collectSymbols(csmProject); + } + } else { + NativeProject nativeProject = context.getProject().getLookup().lookup(NativeProject.class); + if (nativeProject != null) { + CsmProject csmProject = CsmModelAccessor.getModel().getProject(nativeProject); + if (csmProject != null) { + collectSymbols(csmProject); + } + } + } + } + + private void collectLibs(CsmProject project, Collection libs) { + for( CsmProject lib : project.getLibraries()) { + if (! libs.contains(lib)) { + libs.add(lib); + collectLibs(lib, libs); + } + } + } + + private void collectSymbols(CsmProject csmProject) { + + // process project namespaces + collectSymbols(csmProject.getGlobalNamespace()); + + CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); + + // process project files + for(CsmFile csmFile : csmProject.getAllFiles()) { + checkCancelled(); + // macros + Iterator macros = CsmSelect.getMacros(csmFile, nameFilter); + while (macros.hasNext()) { + checkCancelled(); + CsmMacro macro = macros.next(); + if (nameAcceptor.accept(macro.getName())) { + if(CsmVisibilityQuery.isVisible(macro)) { + addResult(new CppSymbolDescriptor(macro)); + } + } + } + checkCancelled(); + // static functions + Iterator funcs = CsmSelect.getStaticFunctions(csmFile, nameFilter); + while (funcs.hasNext()) { + checkCancelled(); + CsmFunction func = funcs.next(); + if (nameAcceptor.accept(func.getName())) { + if (CsmKindUtilities.isFunctionDefinition(func)) { // which is unlikely, but just in case + if(CsmVisibilityQuery.isVisible(func)) { + addResult(new CppSymbolDescriptor(func)); + } + } else { + // static functions definitions are not returned by Select; + // neither do they reside in namespace + CsmFunctionDefinition definition = func.getDefinition(); + if (definition != null ) { + if(CsmVisibilityQuery.isVisible(definition)) { + addResult(new CppSymbolDescriptor(definition)); + } + } + } + } + } + checkCancelled(); + CsmSelect.CsmFilter definitions = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, CsmSelect.getFilterBuilder().createKindFilter(Kind.FUNCTION_DEFINITION)); + Iterator declarations = CsmSelect.getDeclarations(csmFile, definitions); + while (declarations.hasNext()) { + checkCancelled(); + CsmOffsetableDeclaration decl = declarations.next(); + if (nameAcceptor.accept(decl.getName())) { + if (CsmKindUtilities.isFunctionDefinition(decl) && ((CsmFunction)decl).isStatic()) { + CsmFunction func = (CsmFunction) decl; + if (func.equals(func.getDeclaration()) && CsmKindUtilities.isFile(func.getScope())) { + if(CsmVisibilityQuery.isVisible(func)) { + addResult(new CppSymbolDescriptor(func)); + } + } + } + } + } + checkCancelled(); + // static variables + Iterator vars = CsmSelect.getStaticVariables(csmFile, nameFilter); + while (vars.hasNext()) { + checkCancelled(); + CsmVariable var = vars.next(); + if (nameAcceptor.accept(var.getName())) { + if(CsmVisibilityQuery.isVisible(var)) { + addResult(new CppSymbolDescriptor(var)); + } + } + } + } + } + + private void collectSymbols(CsmNamespace namespace) { + + // we can filter out "simple" (non-class) namespace elements via CsmSelect; + // later we have to instantiate classes and enums to check their *members* as well + + CsmSelect.CsmFilter nameFilter = CsmSelect.getFilterBuilder().createNameFilter(nameAcceptor); + + CsmSelect.CsmFilter simpleKindFilter = CsmSelect.getFilterBuilder().createKindFilter( + CsmDeclaration.Kind.FUNCTION, CsmDeclaration.Kind.FUNCTION_DEFINITION, + CsmDeclaration.Kind.FUNCTION_FRIEND, CsmDeclaration.Kind.FUNCTION_FRIEND_DEFINITION, + CsmDeclaration.Kind.VARIABLE, CsmDeclaration.Kind.TYPEDEF); + + CsmSelect.CsmFilter simpleNameAndKindFilter = CsmSelect.getFilterBuilder().createCompoundFilter(nameFilter, simpleKindFilter); + + Iterator declarations = CsmSelect.getDeclarations(namespace, simpleNameAndKindFilter); + while (declarations.hasNext()) { + checkCancelled(); + CsmOffsetableDeclaration decl = declarations.next(); + if (nameAcceptor.accept(decl.getName())) { + if (CsmKindUtilities.isFunction(decl)) { + // do not add declarations if their definitions exist + if (CsmKindUtilities.isFunctionDefinition(decl)) { + if(CsmVisibilityQuery.isVisible(decl)) { + addResult(new CppSymbolDescriptor(decl)); + } + } else { + CsmFunctionDefinition definition = ((CsmFunction) decl).getDefinition(); + if (definition == null || definition == decl) { + if(CsmVisibilityQuery.isVisible(decl)) { + addResult(new CppSymbolDescriptor(decl)); + } + } + } + } else { + if(CsmVisibilityQuery.isVisible(decl)) { + addResult(new CppSymbolDescriptor(decl)); + } + } + } + } + + // instantiate classes and enums to check them and their members as well + CsmSelect.CsmFilter kindFilter = CsmSelect.getFilterBuilder().createKindFilter( + CsmDeclaration.Kind.CLASS, CsmDeclaration.Kind.ENUM, CsmDeclaration.Kind.STRUCT); + CsmSelect.CsmFilter classesOrMembers = CsmSelect.getFilterBuilder().createOrFilter(kindFilter, nameFilter); + declarations = CsmSelect.getDeclarations(namespace, kindFilter); + while (declarations.hasNext()) { + checkCancelled(); + addDeclarationIfNeed(declarations.next(), classesOrMembers, nameFilter); + } + + // process nested namespaces + for (CsmNamespace child : namespace.getNestedNamespaces()) { + checkCancelled(); + collectSymbols(child); + } + } + + /** + * Is called for classes, enums and their members. + * Checks name, if it suites, adds result to symbols collection. + * Does the same recursively (with members/enumerators) + */ + private void addDeclarationIfNeed(CsmOffsetableDeclaration decl, CsmSelect.CsmFilter classesOrMembers, CsmSelect.CsmFilter nameFilter) { + if (nameAcceptor.accept(decl.getName())) { + if(CsmVisibilityQuery.isVisible(decl)) { + addResult(new CppSymbolDescriptor(decl)); + } + } + if (CsmKindUtilities.isClass(decl)) { + CsmClass cls = (CsmClass) decl; + final Iterator classMembers = CsmSelect.getClassMembers(cls, classesOrMembers); + while(classMembers.hasNext()) { + addDeclarationIfNeed(classMembers.next(), classesOrMembers, nameFilter); + } + } else if (CsmKindUtilities.isEnum(decl)) { + CsmEnum en = (CsmEnum) decl; + Iterator enumerators = CsmSelect.getEnumerators(en, nameFilter); + while(enumerators.hasNext()) { + CsmEnumerator enumerator = enumerators.next(); + if (nameAcceptor.accept(enumerator.getName())) { + if(CsmVisibilityQuery.isVisible(enumerator)) { + addResult(new CppSymbolDescriptor(enumerator)); + } + } + } + } + } + + private void checkCancelled() throws CancellationException { + if (cancelled.get()) { + throw new CancellationException(); + } + } + + private void addResult(CppSymbolDescriptor symbolDescriptor) { + synchronized (resultLock) { + result.add(symbolDescriptor); + } + } + } }