void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func<IType, IType> typePred = null, Predicate<IMember> memberPred = null, Action<ICompletionData, IType> callback = null)
        {
            var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);

            if (currentType != null) {
                for (var ct = ctx.CurrentTypeDefinition; ct != null; ct = ct.DeclaringTypeDefinition) {
                    foreach (var nestedType in ct.GetNestedTypes ()) {
                        if (!lookup.IsAccessible (nestedType.GetDefinition (), true))
                            continue;

                        if (typePred == null) {
                            wrapper.AddType(nestedType, false, IsAttributeContext(node));
                            continue;
                        }

                        var type = typePred(nestedType);
                        if (type != null) {
                            var a2 = wrapper.AddType(type, false, IsAttributeContext(node));
                            if (a2 != null && callback != null) {
                                callback(a2, type);
                            }
                        }
                        continue;
                    }
                }
                if (this.currentMember != null && !(node is AstType)) {
                    var def = ctx.CurrentTypeDefinition;
                    if (def == null && currentType != null)
                        def = Compilation.MainAssembly.GetTypeDefinition(currentType.FullTypeName);
                    if (def != null) {
                        bool isProtectedAllowed = true;

                        foreach (var member in def.GetMembers (m => currentMember.IsStatic ? m.IsStatic : true)) {
                            if (member is IMethod && ((IMethod)member).FullName == "System.Object.Finalize") {
                                continue;
                            }
                            if (member.EntityType == EntityType.Operator) {
                                continue;
                            }
                            if (member.IsExplicitInterfaceImplementation) {
                                continue;
                            }
                            if (!lookup.IsAccessible(member, isProtectedAllowed)) {
                                continue;
                            }
                            if (memberPred == null || memberPred(member)) {
                                wrapper.AddMember(member);
                            }
                        }
                        var declaring = def.DeclaringTypeDefinition;
                        while (declaring != null) {
                            foreach (var member in declaring.GetMembers (m => m.IsStatic)) {
                                if (memberPred == null || memberPred(member)) {
                                    wrapper.AddMember(member);
                                }
                            }
                            declaring = declaring.DeclaringTypeDefinition;
                        }
                    }
                }
                if (ctx.CurrentTypeDefinition != null) {
                    foreach (var p in ctx.CurrentTypeDefinition.TypeParameters) {
                        wrapper.AddTypeParameter(p);
                    }
                }
            }
            var scope = ctx.CurrentUsingScope;

            for (var n = scope; n != null; n = n.Parent) {
                foreach (var pair in n.UsingAliases) {
                    wrapper.AddAlias(pair.Key);
                }
                foreach (var alias in n.ExternAliases) {
                    wrapper.AddAlias(alias);
                }
                foreach (var u in n.Usings) {
                    foreach (var type in u.Types) {
                        if (!lookup.IsAccessible(type, false))
                            continue;

                        IType addType = typePred != null ? typePred(type) : type;
                        if (addType != null) {
                            var a = wrapper.AddType(addType, false, IsAttributeContext(node));
                            if (a != null && callback != null) {
                                callback(a, type);
                            }
                        }
                    }
                }

                foreach (var type in n.Namespace.Types) {
                    if (!lookup.IsAccessible(type, false))
                        continue;
                    IType addType = typePred != null ? typePred(type) : type;
                    if (addType != null) {
                        var a2 = wrapper.AddType(addType, false);
                        if (a2 != null && callback != null) {
                            callback(a2, type);
                        }
                    }
                }

                foreach (var curNs in n.Namespace.ChildNamespaces) {
                    wrapper.AddNamespace(lookup, curNs);
                }
            }
        }
		void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func<IType, IType> typePred = null, Predicate<IMember> memberPred = null, Action<ICompletionData, IType> callback = null, bool onlyAddConstructors = false)
		{
			var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);

			if (currentType != null) {
				for (var ct = ctx.CurrentTypeDefinition; ct != null; ct = ct.DeclaringTypeDefinition) {
					foreach (var nestedType in ct.GetNestedTypes ()) {
						if (!lookup.IsAccessible(nestedType.GetDefinition(), true))
							continue;
						if (onlyAddConstructors) {
							if (!nestedType.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
								continue;
						}

						if (typePred == null) {
							if (onlyAddConstructors)
								wrapper.AddConstructors(nestedType, false, IsAttributeContext(node));
							else
								wrapper.AddType(nestedType, false, IsAttributeContext(node));
							continue;
						}

						var type = typePred(nestedType);
						if (type != null) {
							var a2 = onlyAddConstructors ? wrapper.AddConstructors(type, false, IsAttributeContext(node)) : wrapper.AddType(type, false, IsAttributeContext(node));
							if (a2 != null && callback != null) {
								callback(a2, type);
							}
						}
						continue;
					}
				}

				if (this.currentMember != null && !(node is AstType)) {
					var def = ctx.CurrentTypeDefinition;
					if (def == null && currentType != null)
						def = Compilation.MainAssembly.GetTypeDefinition(currentType.FullTypeName);
					if (def != null) {
						bool isProtectedAllowed = true;

						foreach (var member in def.GetMembers (m => currentMember.IsStatic ? m.IsStatic : true)) {
							if (member is IMethod && ((IMethod)member).FullName == "System.Object.Finalize") {
								continue;
							}
							if (member.SymbolKind == SymbolKind.Operator) {
								continue;
							}
							if (member.IsExplicitInterfaceImplementation) {
								continue;
							}
							if (!lookup.IsAccessible(member, isProtectedAllowed)) {
								continue;
							}
							if (memberPred == null || memberPred(member)) {
								wrapper.AddMember(member);
							}
						}
						var declaring = def.DeclaringTypeDefinition;
						while (declaring != null) {
							foreach (var member in declaring.GetMembers (m => m.IsStatic)) {
								if (memberPred == null || memberPred(member)) {
									wrapper.AddMember(member);
								}
							}
							declaring = declaring.DeclaringTypeDefinition;
						}
					}
				}
				if (ctx.CurrentTypeDefinition != null) {
					foreach (var p in ctx.CurrentTypeDefinition.TypeParameters) {
						wrapper.AddTypeParameter(p);
					}
				}
			}
			var scope = ctx.CurrentUsingScope;

			for (var n = scope; n != null; n = n.Parent) {
				foreach (var pair in n.UsingAliases) {
					wrapper.AddAlias(pair.Key);
				}
				foreach (var alias in n.ExternAliases) {
					wrapper.AddAlias(alias);
				}
				foreach (var u in n.Usings) {
					foreach (var type in u.Types) {
						if (!lookup.IsAccessible(type, false))
							continue;

						IType addType = typePred != null ? typePred(type) : type;

						if (onlyAddConstructors && addType != null) {
							if (!addType.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
								continue;
						}

						if (addType != null) {
							var a = onlyAddConstructors ? wrapper.AddConstructors(addType, false, IsAttributeContext(node)) : wrapper.AddType(addType, false, IsAttributeContext(node));
							if (a != null && callback != null) {
								callback(a, type);
							}
						}
					}
				}

				foreach (var type in n.Namespace.Types) {
					if (!lookup.IsAccessible(type, false))
						continue;
					IType addType = typePred != null ? typePred(type) : type;

					if (onlyAddConstructors && addType != null) {
						if (!addType.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
							continue;
					}

					if (addType != null) {
						var a2 = onlyAddConstructors ? wrapper.AddConstructors(addType, false, IsAttributeContext(node)) : wrapper.AddType(addType, false);
						if (a2 != null && callback != null) {
							callback(a2, type);
						}
					}
				}
			}

			for (var n = scope; n != null; n = n.Parent) {
				foreach (var curNs in n.Namespace.ChildNamespaces) {
					wrapper.AddNamespace(lookup, curNs);
				}
			}

			if (node is AstType && node.Parent is Constraint && IncludeKeywordsInCompletionList) {
				wrapper.AddCustom("new()");
			}

			if (AutomaticallyAddImports) {
				state = GetState();
				ICompletionData[] importData;

				var namespaces = new List<INamespace>();
				for (var n = ctx.CurrentUsingScope; n != null; n = n.Parent) {
					namespaces.Add(n.Namespace);
					foreach (var u in n.Usings)
						namespaces.Add(u);
				}

				if (this.CompletionEngineCache != null && ListEquals(namespaces, CompletionEngineCache.namespaces)) {
					importData = CompletionEngineCache.importCompletion;
				} else {
					// flatten usings
					var importList = new List<ICompletionData>();
					var dict = new Dictionary<string, Dictionary<string, ICompletionData>>();
					foreach (var type in Compilation.GetAllTypeDefinitions ()) {
						if (!lookup.IsAccessible(type, false))
							continue;
						if (namespaces.Any(n => n.FullName == type.Namespace))
							continue;
						bool useFullName = false;
						foreach (var ns in namespaces) {
							if (ns.GetTypeDefinition(type.Name, type.TypeParameterCount) != null) {
								useFullName = true;
								break;
							}
						}

						if (onlyAddConstructors) {
							if (!type.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
								continue;
						}
						var data = factory.CreateImportCompletionData(type, useFullName, onlyAddConstructors);
						Dictionary<string, ICompletionData> createdDict;
						if (!dict.TryGetValue(type.Name, out createdDict)) {
							createdDict = new Dictionary<string, ICompletionData>();
							dict.Add(type.Name, createdDict);
						}
						ICompletionData oldData;
						if (!createdDict.TryGetValue(type.Namespace, out oldData)) {
							importList.Add(data);
							createdDict.Add(type.Namespace, data);
						} else {
							oldData.AddOverload(data); 
						}
					}

					importData = importList.ToArray();
					if (CompletionEngineCache != null) {
						CompletionEngineCache.namespaces = namespaces;
						CompletionEngineCache.importCompletion = importData;
					}
				}
				foreach (var data in importData) {
					wrapper.Result.Add(data);
				}


			}

		}
        void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func<IType, IType> typePred = null, Predicate<IMember> memberPred = null, Action<ICompletionData, IType> callback = null, bool onlyAddConstructors = false)
        {
            var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);

            if (currentType != null) {
                for (var ct = ctx.CurrentTypeDefinition; ct != null; ct = ct.DeclaringTypeDefinition) {
                    foreach (var nestedType in ct.GetNestedTypes ()) {
                        if (!lookup.IsAccessible (nestedType.GetDefinition (), true))
                            continue;
                        if (onlyAddConstructors) {
                            if (!nestedType.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
                                continue;
                        }

                        if (typePred == null) {
                            if (onlyAddConstructors)
                                wrapper.AddConstructors (nestedType, false, IsAttributeContext(node));
                            else
                                wrapper.AddType(nestedType, false, IsAttributeContext(node));
                            continue;
                        }

                        var type = typePred(nestedType);
                        if (type != null) {
                            var a2 = onlyAddConstructors ? wrapper.AddConstructors(type, false, IsAttributeContext(node)) : wrapper.AddType(type, false, IsAttributeContext(node));
                            if (a2 != null && callback != null) {
                                callback(a2, type);
                            }
                        }
                        continue;
                    }
                }

                if (this.currentMember != null && !(node is AstType)) {
                    var def = ctx.CurrentTypeDefinition;
                    if (def == null && currentType != null)
                        def = Compilation.MainAssembly.GetTypeDefinition(currentType.FullTypeName);
                    if (def != null) {
                        bool isProtectedAllowed = true;

                        foreach (var member in def.GetMembers (m => currentMember.IsStatic ? m.IsStatic : true)) {
                            if (member is IMethod && ((IMethod)member).FullName == "System.Object.Finalize") {
                                continue;
                            }
                            if (member.SymbolKind == SymbolKind.Operator) {
                                continue;
                            }
                            if (member.IsExplicitInterfaceImplementation) {
                                continue;
                            }
                            if (!lookup.IsAccessible(member, isProtectedAllowed)) {
                                continue;
                            }
                            if (memberPred == null || memberPred(member)) {
                                wrapper.AddMember(member);
                            }
                        }
                        var declaring = def.DeclaringTypeDefinition;
                        while (declaring != null) {
                            foreach (var member in declaring.GetMembers (m => m.IsStatic)) {
                                if (memberPred == null || memberPred(member)) {
                                    wrapper.AddMember(member);
                                }
                            }
                            declaring = declaring.DeclaringTypeDefinition;
                        }
                    }
                }
                if (ctx.CurrentTypeDefinition != null) {
                    foreach (var p in ctx.CurrentTypeDefinition.TypeParameters) {
                        wrapper.AddTypeParameter(p);
                    }
                }
            }
            var scope = ctx.CurrentUsingScope;

            for (var n = scope; n != null; n = n.Parent) {
                foreach (var pair in n.UsingAliases) {
                    wrapper.AddAlias(pair.Key);
                }
                foreach (var alias in n.ExternAliases) {
                    wrapper.AddAlias(alias);
                }
                foreach (var u in n.Usings) {
                    foreach (var type in u.Types) {
                        if (!lookup.IsAccessible(type, false))
                            continue;

                        IType addType = typePred != null ? typePred(type) : type;

                        if (onlyAddConstructors && addType != null) {
                            if (!addType.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
                                continue;
                        }

                        if (addType != null) {
                            var a = onlyAddConstructors ? wrapper.AddConstructors(addType, false, IsAttributeContext(node)) : wrapper.AddType(addType, false, IsAttributeContext(node));
                            if (a != null && callback != null) {
                                callback(a, type);
                            }
                        }
                    }
                }

                foreach (var type in n.Namespace.Types) {
                    if (!lookup.IsAccessible(type, false))
                        continue;
                    IType addType = typePred != null ? typePred(type) : type;

                    if (onlyAddConstructors && addType != null) {
                        if (!addType.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
                            continue;
                    }

                    if (addType != null) {
                        var a2 = onlyAddConstructors ? wrapper.AddConstructors(addType, false, IsAttributeContext(node)) : wrapper.AddType(addType, false);
                        if (a2 != null && callback != null) {
                            callback(a2, type);
                        }
                    }
                }

                foreach (var curNs in n.Namespace.ChildNamespaces) {
                    wrapper.AddNamespace(lookup, curNs);
                }
            }

            if (node is AstType && node.Parent is Constraint && IncludeKeywordsInCompletionList) {
                wrapper.AddCustom ("new()");
            }

            if (AutomaticallyAddImports) {
                state = GetState();
                foreach (var type in Compilation.GetAllTypeDefinitions ()) {
                    if (!lookup.IsAccessible (type, false))
                        continue;
                    var resolveResult = state.LookupSimpleNameOrTypeName(type.Name, type.TypeArguments, NameLookupMode.Expression);
                    if (resolveResult.Type.GetDefinition () == type)
                        continue;

                    if (onlyAddConstructors) {
                        if (!type.GetConstructors().Any(c => lookup.IsAccessible(c, true)))
                            continue;
                    }

                    wrapper.AddTypeImport(type, !resolveResult.IsError, onlyAddConstructors);
                }
            }
        }