IEnumerable<CodeAction> GetActionsForType(RefactoringContext context, AstNode node) { var rr = context.Resolve(node) as UnknownIdentifierResolveResult; if (rr == null) return EmptyList<CodeAction>.Instance; string identifier = rr.Identifier; int tc = rr.TypeArgumentCount; string attributeIdentifier = null; if (node.Parent is Attribute) attributeIdentifier = identifier + "Attribute"; var lookup = new MemberLookup(null, context.Compilation.MainAssembly); List<CodeAction> actions = new List<CodeAction>(); foreach (var typeDefinition in context.Compilation.GetAllTypeDefinitions()) { if ((typeDefinition.Name == identifier || typeDefinition.Name == attributeIdentifier) && typeDefinition.TypeParameterCount == tc && lookup.IsAccessible(typeDefinition, false)) { if (typeDefinition.DeclaringTypeDefinition == null) { actions.Add(NewUsingAction(context, node, typeDefinition.Namespace)); } actions.Add(ReplaceWithFullTypeNameAction(context, node, typeDefinition)); } } return actions; }
bool IsAccessible(MemberLookup lookup, INamespace ns) { if (ns.Types.Any (t => lookup.IsAccessible (t, false))) return true; foreach (var child in ns.ChildNamespaces) if (IsAccessible (lookup, child)) return true; return false; }
public void AddNamespace (MemberLookup lookup, INamespace ns) { if (usedNamespaces.Contains (ns.Name)) return; if (!IsAccessible (lookup, ns)) { usedNamespaces.Add (ns.Name); return; } usedNamespaces.Add (ns.Name); result.Add (Factory.CreateNamespaceCompletionData (ns)); }
IEnumerable<ICompletionData> HandleObjectInitializer(SyntaxTree unit, AstNode n) { var p = n.Parent; while (p != null && !(p is ObjectCreateExpression)) { p = p.Parent; } var parent = n.Parent as ArrayInitializerExpression; if (parent == null) return null; if (parent.IsSingleElement) parent = (ArrayInitializerExpression)parent.Parent; if (p != null) { var contextList = new CompletionDataWrapper(this); var initializerResult = ResolveExpression(p); if (initializerResult != null && initializerResult.Item1.Type.Kind != TypeKind.Unknown) { // check 3 cases: // 1) New initalizer { xpr // 2) Object initializer { prop = val1, field = val2, xpr // 3) Array initializer { new Foo (), a, xpr // in case 1 all object/array initializer options should be given - in the others not. AstNode prev = null; if (parent.Elements.Count > 1) { prev = parent.Elements.First(); if (prev is ArrayInitializerExpression && ((ArrayInitializerExpression)prev).IsSingleElement) prev = ((ArrayInitializerExpression)prev).Elements.FirstOrDefault(); } if (prev != null && !(prev is NamedExpression)) { AddContextCompletion(contextList, GetState(), n); // case 3) return contextList.Result; } var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly); var initializerType = initializerResult.Item1.Type; bool isProtectedAllowed = ctx.CurrentTypeDefinition != null && initializerType.GetDefinition() != null ? ctx.CurrentTypeDefinition.IsDerivedFrom(initializerType.GetDefinition()) : false; foreach (var m in initializerType.GetMembers (m => m.EntityType == EntityType.Field)) { var f = m as IField; if (f != null && (f.IsReadOnly || f.IsConst)) continue; if (lookup.IsAccessible (m, isProtectedAllowed)) contextList.AddMember(m); } foreach (IProperty m in initializerType.GetMembers (m => m.EntityType == EntityType.Property)) { if (m.CanSet && lookup.IsAccessible (m.Setter, isProtectedAllowed)) contextList.AddMember(m); } if (prev != null && (prev is NamedExpression)) { // case 2) return contextList.Result; } // case 1) // check if the object is a list, if not only provide object initalizers var list = typeof(System.Collections.IList).ToTypeReference().Resolve(Compilation); if (initializerType.Kind != TypeKind.Array && list != null) { var def = initializerType.GetDefinition(); if (def != null && !def.IsDerivedFrom(list.GetDefinition())) return contextList.Result; } AddContextCompletion(contextList, GetState(), n); return contextList.Result; } } return null; }
IEnumerable<ICompletionData> CreateCompletionData(TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state, Func<IType, IType> typePred = null) { if (resolveResult == null /*|| resolveResult.IsError*/) { return null; } var lookup = new MemberLookup( ctx.CurrentTypeDefinition, Compilation.MainAssembly ); if (resolveResult is NamespaceResolveResult) { var nr = (NamespaceResolveResult)resolveResult; var namespaceContents = new CompletionDataWrapper(this); foreach (var cl in nr.Namespace.Types) { if (!lookup.IsAccessible(cl, false)) continue; IType addType = typePred != null ? typePred(cl) : cl; if (addType != null) namespaceContents.AddType(addType, false); } foreach (var ns in nr.Namespace.ChildNamespaces) { namespaceContents.AddNamespace(lookup, ns); } return namespaceContents.Result; } IType type = resolveResult.Type; if (type.Namespace == "System" && type.Name == "Void") return null; if (resolvedNode.Parent is PointerReferenceExpression && (type is PointerType)) { resolveResult = new OperatorResolveResult (((PointerType)type).ElementType, System.Linq.Expressions.ExpressionType.Extension, resolveResult); } //var typeDef = resolveResult.Type.GetDefinition(); var result = new CompletionDataWrapper(this); bool includeStaticMembers = false; if (resolveResult is LocalResolveResult) { if (resolvedNode is IdentifierExpression) { var mrr = (LocalResolveResult)resolveResult; includeStaticMembers = mrr.Variable.Name == mrr.Type.Name; } } if (resolveResult is TypeResolveResult && type.Kind == TypeKind.Enum) { foreach (var field in type.GetFields ()) { if (!lookup.IsAccessible(field, false)) continue; result.AddMember(field); } return result.Result; } bool isProtectedAllowed = resolveResult is ThisResolveResult ? true : lookup.IsProtectedAccessAllowed(type); bool skipNonStaticMembers = (resolveResult is TypeResolveResult); if (resolveResult is MemberResolveResult && resolvedNode is IdentifierExpression) { var mrr = (MemberResolveResult)resolveResult; includeStaticMembers = mrr.Member.Name == mrr.Type.Name; TypeResolveResult trr; if (state.IsVariableReferenceWithSameType( resolveResult, ((IdentifierExpression)resolvedNode).Identifier, out trr )) { if (currentMember != null && mrr.Member.IsStatic ^ currentMember.IsStatic) { skipNonStaticMembers = true; if (trr.Type.Kind == TypeKind.Enum) { foreach (var field in trr.Type.GetFields ()) { if (lookup.IsAccessible (field, false)) result.AddMember(field); } return result.Result; } } } // ADD Aliases var scope = ctx.CurrentUsingScope; for (var n = scope; n != null; n = n.Parent) { foreach (var pair in n.UsingAliases) { if (pair.Key == mrr.Member.Name) { foreach (var r in CreateCompletionData (location, pair.Value, resolvedNode, state)) { if (r is IEntityCompletionData && ((IEntityCompletionData)r).Entity is IMember) { result.AddMember((IMember)((IEntityCompletionData)r).Entity); } else { result.Add(r); } } } } } } if (resolveResult is TypeResolveResult && (resolvedNode is IdentifierExpression || resolvedNode is MemberReferenceExpression)) { includeStaticMembers = true; } // Console.WriteLine ("type:" + type +"/"+type.GetType ()); // Console.WriteLine ("current:" + ctx.CurrentTypeDefinition); // Console.WriteLine ("IS PROT ALLOWED:" + isProtectedAllowed + " static: "+ includeStaticMembers); // Console.WriteLine (resolveResult); // Console.WriteLine ("node:" + resolvedNode); // Console.WriteLine (currentMember != null ? currentMember.IsStatic : "currentMember == null"); if (resolvedNode.Annotation<ObjectCreateExpression>() == null) { //tags the created expression as part of an object create expression. /* var filteredList = new List<IMember>(); foreach (var member in type.GetMembers ()) { filteredList.Add(member); } foreach (var member in filteredList) { // Console.WriteLine ("add:" + member + "/" + member.IsStatic); result.AddMember(member); }*/ foreach (var member in lookup.GetAccessibleMembers (resolveResult)) { if (member.EntityType == EntityType.Indexer || member.EntityType == EntityType.Operator || member.EntityType == EntityType.Constructor || member.EntityType == EntityType.Destructor) { continue; } if (resolvedNode is BaseReferenceExpression && member.IsAbstract) { continue; } if (member is IType) { if (resolveResult is TypeResolveResult || includeStaticMembers) { if (!lookup.IsAccessible(member, isProtectedAllowed)) continue; result.AddType((IType)member, false); continue; } } bool memberIsStatic = member.IsStatic; if (!includeStaticMembers && memberIsStatic && !(resolveResult is TypeResolveResult)) { // Console.WriteLine ("skip static member: " + member.FullName); continue; } var field = member as IField; if (field != null) { memberIsStatic |= field.IsConst; } if (!memberIsStatic && skipNonStaticMembers) { continue; } if (member is IMethod && ((IMethod)member).FullName == "System.Object.Finalize") { continue; } if (member.EntityType == EntityType.Operator) { continue; } if (member is IMember) { result.AddMember ((IMember)member); } } } if (!(resolveResult is TypeResolveResult || includeStaticMembers)) { foreach (var meths in state.GetExtensionMethods (type)) { foreach (var m in meths) { if (!lookup.IsAccessible(m, isProtectedAllowed)) continue; result.AddMember(new ReducedExtensionMethod (m)); } } } // IEnumerable<object> objects = resolveResult.CreateResolveResult (dom, resolver != null ? resolver.CallingMember : null); // CompletionDataCollector col = new CompletionDataCollector (this, dom, result, Document.CompilationUnit, resolver != null ? resolver.CallingType : null, location); // col.HideExtensionParameter = !resolveResult.StaticResolve; // col.NamePrefix = expressionResult.Expression; // bool showOnlyTypes = expressionResult.Contexts.Any (ctx => ctx == ExpressionContext.InheritableType || ctx == ExpressionContext.Constraints); // if (objects != null) { // foreach (object obj in objects) { // if (expressionResult.ExpressionContext != null && expressionResult.ExpressionContext.FilterEntry (obj)) // continue; // if (expressionResult.ExpressionContext == ExpressionContext.NamespaceNameExcepted && !(obj is Namespace)) // continue; // if (showOnlyTypes && !(obj is IType)) // continue; // CompletionData data = col.Add (obj); // if (data != null && expressionResult.ExpressionContext == ExpressionContext.Attribute && data.CompletionText != null && data.CompletionText.EndsWith ("Attribute")) { // string newText = data.CompletionText.Substring (0, data.CompletionText.Length - "Attribute".Length); // data.SetText (newText); // } // } // } return result.Result; }
IEnumerable<ICompletionData> CreateTypeAndNamespaceCompletionData(TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state) { if (resolveResult == null || resolveResult.IsError) { return null; } var exprParent = resolvedNode.GetParent<Expression>(); var unit = exprParent != null ? exprParent.GetParent<SyntaxTree>() : null; var astResolver = unit != null ? CompletionContextProvider.GetResolver(state, unit) : null; IType hintType = exprParent != null && astResolver != null ? CreateFieldAction.GetValidTypes(astResolver, exprParent) .FirstOrDefault() : null; var result = new CompletionDataWrapper(this); var lookup = new MemberLookup( ctx.CurrentTypeDefinition, Compilation.MainAssembly ); if (resolveResult is NamespaceResolveResult) { var nr = (NamespaceResolveResult)resolveResult; if (!(resolvedNode.Parent is UsingDeclaration || resolvedNode.Parent != null && resolvedNode.Parent.Parent is UsingDeclaration)) { foreach (var cl in nr.Namespace.Types) { if (hintType != null && hintType.Kind != TypeKind.Array && cl.Kind == TypeKind.Interface) { continue; } if (!lookup.IsAccessible (cl, false)) continue; result.AddType(cl, false, IsAttributeContext(resolvedNode)); } } foreach (var ns in nr.Namespace.ChildNamespaces) { result.AddNamespace(lookup, ns); } } else if (resolveResult is TypeResolveResult) { var type = resolveResult.Type; foreach (var nested in type.GetNestedTypes ()) { if (hintType != null && hintType.Kind != TypeKind.Array && nested.Kind == TypeKind.Interface) { continue; } var def = nested.GetDefinition(); if (def != null && !lookup.IsAccessible (def, false)) continue; result.AddType(nested, false); } } return result.Result; }
IEnumerable<ICompletionData> CreateTypeCompletionData(IType hintType) { var wrapper = new CompletionDataWrapper(this); var state = GetState(); Func<IType, IType> pred = null; Action<ICompletionData, IType> typeCallback = null; var inferredTypesCategory = new Category("Inferred Types", null); var derivedTypesCategory = new Category("Derived Types", null); if (hintType != null) { if (hintType.Kind != TypeKind.Unknown) { var lookup = new MemberLookup( ctx.CurrentTypeDefinition, Compilation.MainAssembly ); typeCallback = (data, t) => { //check if type is in inheritance tree. if (hintType.GetDefinition() != null && t.GetDefinition() != null && t.GetDefinition().IsDerivedFrom(hintType.GetDefinition())) { data.CompletionCategory = derivedTypesCategory; } }; pred = t => { if (t.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array) { return null; } // check for valid constructors if (t.GetConstructors().Count() > 0) { bool isProtectedAllowed = currentType != null ? currentType.Resolve(ctx).GetDefinition().IsDerivedFrom(t.GetDefinition()) : false; if (!t.GetConstructors().Any(m => lookup.IsAccessible(m, isProtectedAllowed))) { return null; } } // check derived types var typeDef = t.GetDefinition(); var hintDef = hintType.GetDefinition(); if (typeDef != null && hintDef != null && typeDef.IsDerivedFrom(hintDef)) { var newType = wrapper.AddType(t, true); if (newType != null) { newType.CompletionCategory = inferredTypesCategory; } } // check type inference var typeInference = new TypeInference(Compilation); typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults; var inferedType = typeInference.FindTypeInBounds (new [] { t }, new [] { hintType }); if (inferedType != SpecialType.UnknownType) { var newType = wrapper.AddType(inferedType, true); if (newType != null) { newType.CompletionCategory = inferredTypesCategory; } return null; } return t; }; if (!(hintType.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array)) { var hint = wrapper.AddType(hintType, true); DefaultCompletionString = hint.DisplayText; if (hint != null) { hint.CompletionCategory = derivedTypesCategory; } } if (hintType is ParameterizedType && hintType.TypeParameterCount == 1 && hintType.FullName == "System.Collections.Generic.IEnumerable") { var arg = ((ParameterizedType)hintType).TypeArguments.FirstOrDefault(); if (arg.Kind != TypeKind.TypeParameter) { var array = new ArrayType (ctx.Compilation, arg, 1); wrapper.AddType(array, true); } } } else { var hint = wrapper.AddType(hintType, true); if (hint != null) { DefaultCompletionString = hint.DisplayText; hint.CompletionCategory = derivedTypesCategory; } } } AddTypesAndNamespaces(wrapper, state, null, pred, m => false, typeCallback); if (hintType == null || hintType == SpecialType.UnknownType) { AddKeywords(wrapper, primitiveTypesKeywords.Where(k => k != "void")); } CloseOnSquareBrackets = true; AutoCompleteEmptyMatch = true; AutoCompleteEmptyMatchOnCurlyBracket = false; return wrapper.Result; }
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); } } if (node is AstType && node.Parent is Constraint) { wrapper.AddCustom ("new()"); } }
/// <summary> /// Gets the types that needs to be imported via using or full type name. /// </summary> public IEnumerable<ICompletionData> GetImportCompletionData(int offset) { var generalLookup = new MemberLookup (null, Compilation.MainAssembly); SetOffset(offset); // flatten usings 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); } foreach (var type in Compilation.GetAllTypeDefinitions ()) { if (!generalLookup.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; } } yield return factory.CreateImportCompletionData (type, useFullName); } }
IEnumerable<CodeAction> GetActionsForExtensionMethodInvocation(RefactoringContext context, InvocationExpression invocation) { var rr = context.Resolve(invocation) as UnknownMethodResolveResult; if (rr == null) return EmptyList<CodeAction>.Instance; var lookup = new MemberLookup(null, context.Compilation.MainAssembly); HashSet<string> namespaces = new HashSet<string>(); List<CodeAction> result = new List<CodeAction>(); foreach (var typeDefinition in context.Compilation.GetAllTypeDefinitions()) { if (!(typeDefinition.HasExtensionMethods && lookup.IsAccessible(typeDefinition, false))) { continue; } foreach (var method in typeDefinition.Methods.Where(m => m.IsExtensionMethod && m.Name == rr.MemberName)) { IType[] inferredTypes; if (CSharpResolver.IsEligibleExtensionMethod(rr.TargetType, method, true, out inferredTypes)) { // avoid offering the same namespace twice if (namespaces.Add(typeDefinition.Namespace)) { result.Add(NewUsingAction(context, invocation, typeDefinition.Namespace)); } break; // continue with the next type } } } return result; }
IEnumerable<IProperty> GetAccessibleIndexers(IType type) { var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly); var properties = new List<IProperty>(); foreach (var property in type.GetProperties ()) { if (!property.IsIndexer) continue; if (!lookup.IsAccessible (property, true)) continue; if (property.IsShadowing) { for (int j = 0; j < properties.Count; j++) { if (ParameterListComparer.Instance.Equals(properties[j].Parameters, property.Parameters)) { properties.RemoveAt (j); j--; } } } properties.Add (property); } return properties; }
IEnumerable<IMethod> CollectMethods(AstNode resolvedNode, MethodGroupResolveResult resolveResult) { var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly); bool onlyStatic = false; if (resolvedNode is IdentifierExpression && currentMember != null && currentMember.IsStatic || resolveResult.TargetResult is TypeResolveResult) { onlyStatic = true; } var methods = new List<IMethod>(); foreach (var method in resolveResult.Methods) { if (method.IsConstructor) { continue; } if (!lookup.IsAccessible (method, true)) continue; if (onlyStatic && !method.IsStatic) { continue; } if (method.IsShadowing) { for (int j = 0; j < methods.Count; j++) { if (ParameterListComparer.Instance.Equals(methods[j].Parameters, method.Parameters)) { methods.RemoveAt (j); j--; } } } methods.Add (method); } foreach (var m in methods) { yield return m; } foreach (var extMethods in resolveResult.GetEligibleExtensionMethods (true)) { foreach (var method in extMethods) { if (methods.Contains (method)) continue; yield return new ReducedExtensionMethod (method); } } }