protected override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { if ((options & (LookupOptions.NamespaceAliasesOnly | LookupOptions.MustBeInvocableIfMember)) != 0) { return; } Debug.Assert(result.IsClear); var count = parameterMap.GetCountForKey(name); if (count == 1) { ParameterSymbol p; parameterMap.TryGetSingleValue(name, out p); result.MergeEqual(originalBinder.CheckViability(p, arity, options, null, diagnose, ref useSiteDiagnostics)); } else if (count > 1) { var parameters = parameterMap[name]; foreach (var sym in parameters) { result.MergeEqual(originalBinder.CheckViability(sym, arity, options, null, diagnose, ref useSiteDiagnostics)); } } }
public BoundMethodGroup( CSharpSyntaxNode syntax, ImmutableArray<TypeSymbol> typeArgumentsOpt, BoundExpression receiverOpt, string name, ImmutableArray<MethodSymbol> methods, LookupResult lookupResult, BoundMethodGroupFlags flags, bool hasErrors = false) : this(syntax, typeArgumentsOpt, name, methods, lookupResult.SingleSymbolOrDefault, lookupResult.Error, flags, receiverOpt, lookupResult.Kind, hasErrors) { }
internal override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(result.IsClear); if ((options & LookupOptions.NamespaceAliasesOnly) != 0) { return; } foreach (var parameterSymbol in parameterMap[name]) { result.MergeEqual(originalBinder.CheckViability(parameterSymbol, arity, options, null, diagnose, ref useSiteDiagnostics)); } }
protected override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { if ((options & (LookupOptions.NamespaceAliasesOnly | LookupOptions.MustBeInvocableIfMember)) != 0) { return; } Debug.Assert(result.IsClear); foreach (ParameterSymbol parameter in parameters) { if (parameter.Name == name) { result.MergeEqual(originalBinder.CheckViability(parameter, arity, options, null, diagnose, ref useSiteDiagnostics)); } } }
internal override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { var hostObjectType = GetHostObjectType(); if (hostObjectType.Kind == SymbolKind.ErrorType) { // The name '{0}' does not exist in the current context (are you missing a reference to assembly '{1}'?) result.SetFrom(new CSDiagnosticInfo( ErrorCode.ERR_NameNotInContextPossibleMissingReference, new object[] { name, ((MissingMetadataTypeSymbol)hostObjectType).ContainingAssembly.Identity }, ImmutableArray<Symbol>.Empty, ImmutableArray<Location>.Empty )); } else { LookupMembersInternal(result, hostObjectType, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteDiagnostics); } }
internal override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { if (!ShouldLookInUsings(options)) { return; } LookupResult tmp = LookupResult.GetInstance(); // usings: Imports.Empty.LookupSymbolInUsings(ConsolidatedUsings, originalBinder, tmp, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics); // if we found a viable result in imported namespaces, use it instead of unviable symbols found in source: if (tmp.IsMultiViable) { result.MergeEqual(tmp); } tmp.Free(); }
/// <summary> /// Report appropriate diagnostics when lookup of a pattern member (i.e. GetEnumerator, Current, or MoveNext) fails. /// </summary> /// <param name="lookupResult">Failed lookup result.</param> /// <param name="patternType">Type in which member was looked up.</param> /// <param name="memberName">Name of looked up member.</param> /// <param name="warningsOnly">True if failures should result in warnings; false if they should result in errors.</param> /// <param name="diagnostics">Populated appropriately.</param> private void ReportPatternMemberLookupDiagnostics(LookupResult lookupResult, TypeSymbol patternType, string memberName, bool warningsOnly, DiagnosticBag diagnostics) { if (lookupResult.Symbols.Any()) { if (warningsOnly) { ReportEnumerableWarning(diagnostics, patternType, lookupResult.Symbols.First()); } else { lookupResult.Clear(); HashSet<DiagnosticInfo> useSiteDiagnostics = null; this.LookupMembersInType( lookupResult, patternType, memberName, arity: 0, basesBeingResolved: null, options: LookupOptions.Default, originalBinder: this, diagnose: true, useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(_syntax.Expression, useSiteDiagnostics); if (lookupResult.Error != null) { diagnostics.Add(lookupResult.Error, _syntax.Expression.Location); } } } else if (!warningsOnly) { diagnostics.Add(ErrorCode.ERR_NoSuchMember, _syntax.Expression.Location, patternType, memberName); } }
/// <summary> /// Perform a lookup for the specified method on the specified type. Perform overload resolution /// on the lookup results. /// </summary> /// <param name="patternType">Type to search.</param> /// <param name="methodName">Method to search for.</param> /// <param name="lookupResult">Passed in for reusability.</param> /// <param name="warningsOnly">True if failures should result in warnings; false if they should result in errors.</param> /// <param name="diagnostics">Populated with binding diagnostics.</param> /// <returns>The desired method or null.</returns> private MethodSymbol FindForEachPatternMethod(TypeSymbol patternType, string methodName, LookupResult lookupResult, bool warningsOnly, DiagnosticBag diagnostics) { Debug.Assert(lookupResult.IsClear); // Not using LookupOptions.MustBeInvocableMember because we don't want the corresponding lookup error. // We filter out non-methods below. HashSet<DiagnosticInfo> useSiteDiagnostics = null; this.LookupMembersInType( lookupResult, patternType, methodName, arity: 0, basesBeingResolved: null, options: LookupOptions.Default, originalBinder: this, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(_syntax.Expression, useSiteDiagnostics); if (!lookupResult.IsMultiViable) { ReportPatternMemberLookupDiagnostics(lookupResult, patternType, methodName, warningsOnly, diagnostics); return null; } ArrayBuilder<MethodSymbol> candidateMethods = ArrayBuilder<MethodSymbol>.GetInstance(); foreach (Symbol member in lookupResult.Symbols) { if (member.Kind != SymbolKind.Method) { candidateMethods.Free(); if (warningsOnly) { ReportEnumerableWarning(diagnostics, patternType, member); } return null; } MethodSymbol method = (MethodSymbol)member; // SPEC VIOLATION: The spec says we should apply overload resolution, but Dev10 uses // some custom logic in ExpressionBinder.BindGrpToParams. The biggest difference // we've found (so far) is that it only considers methods with zero parameters // (i.e. doesn't work with "params" or optional parameters). if (!method.Parameters.Any()) { candidateMethods.Add((MethodSymbol)member); } } MethodSymbol patternMethod = PerformForEachPatternOverloadResolution(patternType, candidateMethods, warningsOnly, diagnostics); candidateMethods.Free(); return patternMethod; }
/// <summary> /// Merge another result with this one, with the symbols combined if both /// this and other are viable. Otherwise the highest priority result wins (this if equal /// priority and non-viable.) /// </summary> internal void MergeEqual(LookupResult other) { if (Kind > other.Kind) { return; } else if (other.Kind > Kind) { this.SetFrom(other); } else if (Kind != LookupResultKind.Viable) { // this makes the operator not symmetrical, but so far we do not care. // it is really a matter of which error gets reported. return; } else { // Merging two viable results together. We will always end up with at least two symbols. _symbolList.AddRange(other._symbolList); } }
// Merge another result with this one, with the current result being prioritized // over the other if they are of equal "goodness". Mutates the current result. internal void MergePrioritized(LookupResult other) { if (other.Kind > Kind) { SetFrom(other); } }
/// <summary> /// Set current result according to another. /// </summary> internal void SetFrom(LookupResult other) { _kind = other._kind; _symbolList.Clear(); _symbolList.AddRange(other._symbolList); _error = other._error; }
internal void LookupSymbolInUsings( ImmutableArray<NamespaceOrTypeAndUsingDirective> usings, Binder originalBinder, LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { bool callerIsSemanticModel = originalBinder.IsSemanticModelBinder; foreach (var typeOrNamespace in usings) { ImmutableArray<Symbol> candidates = Binder.GetCandidateMembers(typeOrNamespace.NamespaceOrType, name, options, originalBinder: originalBinder); foreach (Symbol symbol in candidates) { switch (symbol.Kind) { // lookup via "using namespace" ignores namespaces inside case SymbolKind.Namespace: continue; // lookup via "using static" ignores extension methods and non-static methods case SymbolKind.Method: if (!symbol.IsStatic || ((MethodSymbol)symbol).IsExtensionMethod) { continue; } break; // types are considered static members for purposes of "using static" feature // regardless of whether they are declared with "static" modifier or not case SymbolKind.NamedType: break; // lookup via "using static" ignores non-static members default: if (!symbol.IsStatic) { continue; } break; } // Found a match in our list of normal using directives. Mark the directive // as being seen so that it won't be reported to the user as something that // can be removed. var res = originalBinder.CheckViability(symbol, arity, options, null, diagnose, ref useSiteDiagnostics, basesBeingResolved); if (res.Kind == LookupResultKind.Viable) { MarkImportDirective(typeOrNamespace.UsingDirective, callerIsSemanticModel); } result.MergeEqual(res); } } }
private Binder XSLookupSymbolsInternal( LookupResult result, string name, int arity, ConsList <Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(result.IsClear); Debug.Assert(options.AreValid()); // X# looks for functions first //if (Compilation.Options.HasRuntime) { // check for function calls method calls outside the current class bool check = (options.HasFlag(LookupOptions.MustNotBeInstance) && !options.HasFlag(LookupOptions.MustNotBeMethod)); if (check) { var funcOptions = options; funcOptions |= LookupOptions.MustBeInvocableIfMember; Binder scope = this; while (scope != null) { if (scope is InContainerBinder && scope.ContainingType == null) // at the namespace level, so outside of all types { scope.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, funcOptions, this, diagnose, ref useSiteDiagnostics); FilterResults(result, options); if (!result.IsClear) { break; } } scope = scope.Next; } } } LookupResult functionResults = LookupResult.GetInstance(); if (!result.IsClear) { foreach (var symbol in result.Symbols) { if (symbol is MethodSymbol) { var ms = symbol as MethodSymbol; if (ms.IsStatic && ms.ContainingType.Name.EndsWith("Functions", XSharpString.Comparison)) { SingleLookupResult single = new SingleLookupResult(LookupResultKind.Viable, ms, null); functionResults.MergeEqual(single); } } } result.Clear(); } Binder binder = null; for (var scope = this; scope != null && !result.IsMultiViable; scope = scope.Next) { if (binder != null) { var tmp = LookupResult.GetInstance(); scope.LookupSymbolsInSingleBinder(tmp, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics); FilterResults(tmp, options); result.MergeEqual(tmp); tmp.Free(); } else { scope.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics); FilterResults(result, options); if (!result.IsClear) { binder = scope; } } } if (!functionResults.IsClear) { // compare the function results with the overall results found // create a list of functions and methods // function first and then the methods LookupResult mergedResults = LookupResult.GetInstance(); mergedResults.MergeEqual(functionResults); // now add the symbols from result that do not exist for (int j = 0; j < result.Symbols.Count; j++) { var sym = result.Symbols[j]; var found = false; for (int i = 0; i < mergedResults.Symbols.Count; i++) { if (sym == mergedResults.Symbols[i]) { found = true; break; } } if (!found) { SingleLookupResult single = new SingleLookupResult(LookupResultKind.Viable, sym, null); mergedResults.MergeEqual(single); } } result.Clear(); result.MergeEqual(mergedResults); } // C563 Make sure the error is generated for Inaccessible types. if (!result.IsClear && result.Kind == LookupResultKind.Inaccessible && result.Error != null) { // we only want to add this for internal fields (globals) if (result.Symbols[0].Kind == SymbolKind.Field) { if (useSiteDiagnostics == null) { useSiteDiagnostics = new HashSet <DiagnosticInfo>(); } useSiteDiagnostics.Add(result.Error); } } return(binder); }
/// <summary> /// Called after it is determined that the expression being enumerated is of a type that /// has a GetEnumerator method. Checks to see if the return type of the GetEnumerator /// method is suitable (i.e. has Current and MoveNext). /// </summary> /// <param name="builder">Must be non-null and contain a non-null GetEnumeratorMethod.</param> /// <param name="diagnostics">Will be populated with pattern diagnostics.</param> /// <returns>True if the return type has suitable members.</returns> /// <remarks> /// It seems that every failure path reports the same diagnostics, so that is left to the caller. /// </remarks> private bool SatisfiesForEachPattern(ref ForEachEnumeratorInfo.Builder builder, DiagnosticBag diagnostics) { Debug.Assert((object)builder.GetEnumeratorMethod != null); MethodSymbol getEnumeratorMethod = builder.GetEnumeratorMethod; TypeSymbol enumeratorType = getEnumeratorMethod.ReturnType; switch (enumeratorType.TypeKind) { case TypeKind.Class: case TypeKind.Struct: case TypeKind.Interface: case TypeKind.TypeParameter: // Not specifically mentioned in the spec, but consistent with Dev10. case TypeKind.Dynamic: // Not specifically mentioned in the spec, but consistent with Dev10. break; case TypeKind.Submission: // submission class is synthesized and should never appear in a foreach: throw ExceptionUtilities.UnexpectedValue(enumeratorType.TypeKind); default: return(false); } // Use a try-finally since there are many return points LookupResult lookupResult = LookupResult.GetInstance(); try { // If we searched for the accessor directly, we could reuse FindForEachPatternMethod and we // wouldn't have to mangle CurrentPropertyName. However, Dev10 searches for the property and // then extracts the accessor, so we should do the same (in case of accessors with non-standard // names). HashSet <DiagnosticInfo> useSiteDiagnostics = null; this.LookupMembersInType( lookupResult, enumeratorType, CurrentPropertyName, arity: 0, basesBeingResolved: null, options: LookupOptions.Default, // properties are not invocable - their accessors are originalBinder: this, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(_syntax.Expression, useSiteDiagnostics); useSiteDiagnostics = null; if (!lookupResult.IsSingleViable) { ReportPatternMemberLookupDiagnostics(lookupResult, enumeratorType, CurrentPropertyName, warningsOnly: false, diagnostics: diagnostics); return(false); } // lookupResult.IsSingleViable above guaranteed there is exactly one symbol. Symbol lookupSymbol = lookupResult.SingleSymbolOrDefault; Debug.Assert((object)lookupSymbol != null); if (lookupSymbol.IsStatic || lookupSymbol.DeclaredAccessibility != Accessibility.Public || lookupSymbol.Kind != SymbolKind.Property) { return(false); } // NOTE: accessor can be inherited from overridden property MethodSymbol currentPropertyGetterCandidate = ((PropertySymbol)lookupSymbol).GetOwnOrInheritedGetMethod(); if ((object)currentPropertyGetterCandidate == null) { return(false); } else { bool isAccessible = this.IsAccessible(currentPropertyGetterCandidate, ref useSiteDiagnostics); diagnostics.Add(_syntax.Expression, useSiteDiagnostics); if (!isAccessible) { // NOTE: per Dev10 and the spec, the property has to be public, but the accessor just has to be accessible return(false); } } builder.CurrentPropertyGetter = currentPropertyGetterCandidate; lookupResult.Clear(); // Reuse the same LookupResult MethodSymbol moveNextMethodCandidate = FindForEachPatternMethod(enumeratorType, MoveNextMethodName, lookupResult, warningsOnly: false, diagnostics: diagnostics); // SPEC VIOLATION: Dev10 checks the return type of the original definition, rather than the return type of the actual method. if ((object)moveNextMethodCandidate == null || moveNextMethodCandidate.IsStatic || moveNextMethodCandidate.DeclaredAccessibility != Accessibility.Public || ((MethodSymbol)moveNextMethodCandidate.OriginalDefinition).ReturnType.SpecialType != SpecialType.System_Boolean) { return(false); } builder.MoveNextMethod = moveNextMethodCandidate; return(true); } finally { lookupResult.Free(); } }
private BoundExpression BindWithExpression( WithExpressionSyntax syntax, BindingDiagnosticBag diagnostics ) { var receiver = BindRValueWithoutTargetType(syntax.Expression, diagnostics); var receiverType = receiver.Type; var lookupResult = LookupResult.GetInstance(); bool hasErrors = false; if (receiverType is null || receiverType.IsVoidType()) { diagnostics.Add(ErrorCode.ERR_InvalidWithReceiverType, syntax.Expression.Location); receiverType = CreateErrorType(); } MethodSymbol?cloneMethod = null; if (!receiverType.IsErrorType()) { CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo( diagnostics ); cloneMethod = SynthesizedRecordClone.FindValidCloneMethod( receiverType is TypeParameterSymbol typeParameter ? typeParameter.EffectiveBaseClass(ref useSiteInfo) : receiverType, ref useSiteInfo ); if (cloneMethod is null) { hasErrors = true; diagnostics.Add( ErrorCode.ERR_NoSingleCloneMethod, syntax.Expression.Location, receiverType ); } else { cloneMethod.AddUseSiteInfo(ref useSiteInfo); } diagnostics.Add(syntax.Expression, useSiteInfo); } var initializer = BindInitializerExpression( syntax.Initializer, receiverType, syntax.Expression, isForNewInstance: true, diagnostics ); // N.B. Since we only don't parse nested initializers in syntax there should be no extra // errors we need to check for here. return(new BoundWithExpression( syntax, receiver, cloneMethod, initializer, receiverType, hasErrors: hasErrors )); }
internal static bool HandleXSharpImport(UsingDirectiveSyntax usingDirective, Binder usingsBinder, ArrayBuilder <NamespaceOrTypeAndUsingDirective> usings, PooledHashSet <NamespaceOrTypeSymbol> uniqueUsings, ConsList <Symbol> basesBeingResolved, CSharpCompilation compilation) { // The usingDirective name contains spaces when it is nested and the GlobalClassName not , so we must eliminate them here // nvk: usingDirective.Name.ToString() ONLY has spaces if it is nested. This is not supposed to be nested, as it is "Functions" even for the non-core dialects !!! if (usingDirective.Name.ToString().EndsWith(XSharpSpecialNames.FunctionsClass)) { var result = LookupResult.GetInstance(); LookupOptions options = LookupOptions.AllNamedTypesOnArityZero; HashSet <DiagnosticInfo> useSiteDiagnostics = null; usingsBinder.LookupSymbolsSimpleName(result, null, XSharpSpecialNames.FunctionsClass, 0, basesBeingResolved, options, false, useSiteDiagnostics: ref useSiteDiagnostics); foreach (var sym in result.Symbols) { if (sym.Kind == SymbolKind.NamedType) { var ts = (NamedTypeSymbol)sym; AddNs(usingDirective, ts, usings, uniqueUsings); } } var opts = ((CSharpSyntaxTree)usingDirective.SyntaxTree).Options; if (opts.CommandLineArguments != null) { string functionsClass = null; if (compilation.Options.HasRuntime) { functionsClass = Syntax.InternalSyntax.XSharpTreeTransformationRT.VOGlobalClassName(opts); } else { functionsClass = Syntax.InternalSyntax.XSharpTreeTransformationCore.GlobalFunctionClassName(opts.TargetDLL); } if (!string.IsNullOrEmpty(functionsClass)) { var declbinder = usingsBinder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); var diagnostics = DiagnosticBag.GetInstance(); var name = Syntax.InternalSyntax.XSharpTreeTransformationCore.ExtGenerateQualifiedName(functionsClass); var imported = declbinder.BindNamespaceOrTypeSymbol(name, diagnostics, basesBeingResolved); if (imported.Kind == SymbolKind.NamedType) { var importedType = (NamedTypeSymbol)imported; AddNs(usingDirective, importedType, usings, uniqueUsings); } } } if (!compilation.ClassLibraryType().IsErrorType() && !compilation.ImplicitNamespaceType().IsErrorType()) { var declbinder = usingsBinder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); var diagnostics = DiagnosticBag.GetInstance(); string[] defNs; if (compilation.Options.XSharpRuntime) { defNs = new string[] { OurNameSpaces.XSharp } } ; else { defNs = new string[] { OurNameSpaces.Vulcan } }; foreach (var n in defNs) { var name = Syntax.InternalSyntax.XSharpTreeTransformationCore.ExtGenerateQualifiedName(n); var imported = declbinder.BindNamespaceOrTypeSymbol(name, diagnostics, basesBeingResolved); if (imported.Kind == SymbolKind.Namespace) { AddNs(usingDirective, imported, usings, uniqueUsings); } else if (imported.Kind == SymbolKind.NamedType) { var importedType = (NamedTypeSymbol)imported; AddNs(usingDirective, importedType, usings, uniqueUsings); } } var vcla = compilation.ClassLibraryType(); var vins = compilation.ImplicitNamespaceType(); var refMan = compilation.GetBoundReferenceManager(); foreach (var r in refMan.ReferencedAssemblies) { foreach (var attr in r.GetAttributes()) { // Check for VulcanImplicitNameSpace attribute if (attr.AttributeClass.ConstructedFrom == vins && compilation.Options.ImplicitNameSpace) { var args = attr.CommonConstructorArguments; if (args != null && args.Length == 1) { // only one argument, must be default namespace var defaultNamespace = args[0].Value.ToString(); if (!string.IsNullOrEmpty(defaultNamespace)) { var name = Syntax.InternalSyntax.XSharpTreeTransformationCore.ExtGenerateQualifiedName(defaultNamespace); var imported = declbinder.BindNamespaceOrTypeSymbol(name, diagnostics, basesBeingResolved); if (imported.Kind == SymbolKind.Namespace) { AddNs(usingDirective, imported, usings, uniqueUsings); } } } } // Check for VulcanClasslibrary attribute else if (attr.AttributeClass.ConstructedFrom == vcla) { var args = attr.CommonConstructorArguments; if (args != null && args.Length == 2) { // first element is the Functions class var globalClassName = args[0].Value.ToString(); if (!string.IsNullOrEmpty(globalClassName)) { var name = Syntax.InternalSyntax.XSharpTreeTransformationCore.ExtGenerateQualifiedName(globalClassName); var imported = declbinder.BindNamespaceOrTypeSymbol(name, diagnostics, basesBeingResolved); if (imported.Kind == SymbolKind.NamedType) { var importedType = (NamedTypeSymbol)imported; AddNs(usingDirective, importedType, usings, uniqueUsings); } } // second element is the default namespace var defaultNamespace = args[1].Value.ToString(); if (!string.IsNullOrEmpty(defaultNamespace) && compilation.Options.ImplicitNameSpace) { var name = Syntax.InternalSyntax.XSharpTreeTransformationCore.ExtGenerateQualifiedName(defaultNamespace); var imported = declbinder.BindNamespaceOrTypeSymbol(name, diagnostics, basesBeingResolved); if (imported.Kind == SymbolKind.Namespace) { AddNs(usingDirective, imported, usings, uniqueUsings); } } } } } } } return(true); } return(false); } }
private ImmutableArray <Symbol> ComputeSortedCrefMembers(NamespaceOrTypeSymbol containerOpt, string memberName, int arity, bool hasParameterList, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { // Since we may find symbols without going through the lookup API, // expose the symbols via an ArrayBuilder. ArrayBuilder <Symbol> builder; { LookupResult result = LookupResult.GetInstance(); this.LookupSymbolsOrMembersInternal( result, containerOpt, name: memberName, arity: arity, basesBeingResolved: null, options: LookupOptions.AllMethodsOnArityZero, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics); // CONSIDER: Dev11 also checks for a constructor in the event of an ambiguous result. if (result.IsMultiViable) { // Dev11 doesn't consider members from System.Object when the container is an interface. // Lookup should already have dropped such members. builder = ArrayBuilder <Symbol> .GetInstance(); builder.AddRange(result.Symbols); result.Free(); } else { result.Free(); // Won't be using this. // Dev11 has a complicated two-stage process for determining when a cref is really referring to a constructor. // Under two sets of conditions, XmlDocCommentBinder::bindXMLReferenceName will decide that a name refers // to a constructor and under one set of conditions, the calling method, XmlDocCommentBinder::bindXMLReference, // will roll back that decision and return null. // In XmlDocCommentBinder::bindXMLReferenceName: // 1) If an unqualified, non-generic name didn't bind to anything and the name matches the name of the type // to which the doc comment is applied, then bind to a constructor. // 2) If a qualified, non-generic name didn't bind to anything and the LHS of the qualified name is a type // with the same name, then bind to a constructor. // Quoted from XmlDocCommentBinder::bindXMLReference: // Filtering out the case where specifying the name of a generic type without specifying // any arity returns a constructor. This case shouldn't return anything. Note that // returning the constructors was a fix for the wonky constructor behavior, but in order // to not introduce a regression and breaking change we return NULL in this case. // e.g. // // /// <see cref="Foo"/> // class Foo<T> { } // // This cref used not to bind to anything, because before it was looking for a type and // since there was no arity, it didn't find Foo<T>. Now however, it finds Foo<T>.ctor, // which is arguably correct, but would be a breaking change (albeit with minimal impact) // so we catch this case and chuck out the symbol found. // In Roslyn, we're doing everything in one pass, rather than guessing and rolling back. // As in the native compiler, we treat this as a fallback case - something that actually has the // specified name is preferred. NamedTypeSymbol constructorType = null; if (arity == 0) // Member arity { NamedTypeSymbol containerType = containerOpt as NamedTypeSymbol; if ((object)containerType != null) { // Case 1: If the name is qualified by a type with the same name, then we want a // constructor (unless the type is generic, the cref is on/in the type (but not // on/in a nested type), and there were no parens after the member name). if (containerType.Name == memberName && (hasParameterList || containerType.Arity == 0 || this.ContainingType != containerType.OriginalDefinition)) { constructorType = containerType; } } else if ((object)containerOpt == null && hasParameterList) { // Case 2: If the name is not qualified by anything, but we're in the scope // of a type with the same name (regardless of arity), then we want a constructor, // as long as there were parens after the member name. NamedTypeSymbol binderContainingType = this.ContainingType; if ((object)binderContainingType != null && memberName == binderContainingType.Name) { constructorType = binderContainingType; } } } if ((object)constructorType != null) { ImmutableArray <MethodSymbol> instanceConstructors = constructorType.InstanceConstructors; int numInstanceConstructors = instanceConstructors.Length; if (numInstanceConstructors == 0) { return(ImmutableArray <Symbol> .Empty); } builder = ArrayBuilder <Symbol> .GetInstance(numInstanceConstructors); builder.AddRange(instanceConstructors); } else { return(ImmutableArray <Symbol> .Empty); } } } Debug.Assert(builder != null); // Since we resolve ambiguities by just picking the first symbol we encounter, // the order of the symbols matters for repeatability. if (builder.Count > 1) { builder.Sort(ConsistentSymbolOrder.Instance); } return(builder.ToImmutableAndFree()); }
internal void LookupSymbolInAliases( Binder originalBinder, LookupResult result, string name, int arity, ConsList <TypeSymbol> basesBeingResolved, LookupOptions options, bool diagnose, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo ) { bool callerIsSemanticModel = originalBinder.IsSemanticModelBinder; AliasAndUsingDirective alias; if (this.UsingAliases.TryGetValue(name, out alias)) { // Found a match in our list of normal aliases. Mark the alias as being seen so that // it won't be reported to the user as something that can be removed. var res = originalBinder.CheckViability( alias.Alias, arity, options, null, diagnose, ref useSiteInfo, basesBeingResolved ); if (res.Kind == LookupResultKind.Viable) { MarkImportDirective(alias.UsingDirective, callerIsSemanticModel); } result.MergeEqual(res); } foreach (var a in this.ExternAliases) { if (a.Alias.Name == name) { // Found a match in our list of extern aliases. Mark the extern alias as being // seen so that it won't be reported to the user as something that can be // removed. var res = originalBinder.CheckViability( a.Alias, arity, options, null, diagnose, ref useSiteInfo, basesBeingResolved ); if (res.Kind == LookupResultKind.Viable) { MarkImportDirective(a.ExternAliasDirective, callerIsSemanticModel); } result.MergeEqual(res); } } }
internal override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList <TypeSymbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo ) { Debug.Assert(result.IsClear); if (IsSubmissionClass) { this.LookupMembersInternal( result, _container, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteInfo ); return; } var imports = GetImports(basesBeingResolved); // first lookup members of the namespace if ((options & LookupOptions.NamespaceAliasesOnly) == 0 && _container != null) { this.LookupMembersInternal( result, _container, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteInfo ); if (result.IsMultiViable) { // symbols cannot conflict with using alias names if ( arity == 0 && imports.IsUsingAlias(name, originalBinder.IsSemanticModelBinder) ) { CSDiagnosticInfo diagInfo = new CSDiagnosticInfo( ErrorCode.ERR_ConflictAliasAndMember, name, _container ); var error = new ExtendedErrorTypeSymbol( (NamespaceOrTypeSymbol)null, name, arity, diagInfo, unreported: true ); result.SetFrom(LookupResult.Good(error)); // force lookup to be done w/ error symbol as result } return; } } // next try using aliases or symbols in imported namespaces imports.LookupSymbol( originalBinder, result, name, arity, basesBeingResolved, options, diagnose, ref useSiteInfo ); }
private void BindPCallAndDelegate(InvocationExpressionSyntax node, ArrayBuilder <BoundExpression> args, DiagnosticBag diagnostics, TypeSyntax type) { var XNode = node.XNode as XP.MethodCallContext; string method = XNode?.Expr.GetText(); if (string.IsNullOrEmpty(method)) { method = "PCALL"; } if (!ValidatePCallArguments(node, args, diagnostics, method)) { return; } var kind = args[0].Kind; if (kind != BoundKind.Local && kind != BoundKind.FieldAccess) { Error(diagnostics, ErrorCode.ERR_PCallFirstArgument, node, method, "typed function pointer"); return; } string methodName = null; // Note that this does not get the syntax of the argument itself // but the syntax of the place where the symbol (Global, Field or Local) that the argument points to was defined SyntaxReference syntaxref = null; if (kind == BoundKind.FieldAccess) { var bfa = args[0] as BoundFieldAccess; // Global or Field if (bfa != null && bfa.ExpressionSymbol.DeclaringSyntaxReferences.Length > 0) { syntaxref = bfa.ExpressionSymbol.DeclaringSyntaxReferences[0] as SyntaxReference; } } else if (kind == BoundKind.Local) { var bl = args[0] as BoundLocal; // Local if (bl != null && bl.LocalSymbol?.DeclaringSyntaxReferences.Length > 0) { syntaxref = bl.LocalSymbol.DeclaringSyntaxReferences[0] as SyntaxReference; } } if (syntaxref != null) { CSharpSyntaxNode syntaxnode = syntaxref.GetSyntax() as CSharpSyntaxNode; var xNode = syntaxnode?.XNode; methodName = GetTypedPtrName(xNode); } if (methodName == null) { // first argument for pcall must be typed ptr Error(diagnostics, ErrorCode.ERR_PCallFirstArgument, node, method, "typed function pointer"); return; } var lookupResult = LookupResult.GetInstance(); HashSet <DiagnosticInfo> useSiteDiagnostics = null; LookupOptions options = LookupOptions.AllMethodsOnArityZero; options |= LookupOptions.MustNotBeInstance; this.LookupSymbolsWithFallback(lookupResult, methodName, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: options); SourceMethodSymbol methodSym = null; if (lookupResult.IsClear) { // Cannot locate types pointer for pcall Error(diagnostics, ErrorCode.ERR_PCallTypedPointerName, node, method, methodName); methodSym = null; } else if (lookupResult.IsMultiViable) { foreach (var symbol in lookupResult.Symbols) { if (symbol.DeclaringCompilation == this.Compilation && symbol is SourceMethodSymbol) { methodSym = (SourceMethodSymbol)symbol; break; } } } else { methodSym = (SourceMethodSymbol)lookupResult.Symbols[0]; } if (methodSym != null) { lookupResult.Clear(); var ts = FindPCallDelegateType(type as IdentifierNameSyntax); if (ts != null && ts.IsDelegateType()) { SourceDelegateMethodSymbol delmeth = ts.DelegateInvokeMethod() as SourceDelegateMethodSymbol; // clone the parameters from the methodSym var builder = ArrayBuilder <ParameterSymbol> .GetInstance(); foreach (var par in methodSym.Parameters) { var parameter = new SourceSimpleParameterSymbol( delmeth, par.Type, par.Ordinal, par.RefKind, par.Name, par.Locations); builder.Add(parameter); } delmeth.InitializeParameters(builder.ToImmutableAndFree()); delmeth.SetReturnType(methodSym.ReturnType); } else { Error(diagnostics, ErrorCode.ERR_PCallResolveGeneratedDelegate, node, method, type.ToString()); } } return; }
internal void LookupSymbolInAliases( Binder originalBinder, LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { bool callerIsSemanticModel = originalBinder.IsSemanticModelBinder; AliasAndUsingDirective alias; if (this.UsingAliases != null && this.UsingAliases.TryGetValue(name, out alias)) { // Found a match in our list of normal aliases. Mark the alias as being seen so that // it won't be reported to the user as something that can be removed. var res = originalBinder.CheckViability(alias.Alias, arity, options, null, diagnose, ref useSiteDiagnostics, basesBeingResolved); if (res.Kind == LookupResultKind.Viable) { MarkImportDirective(alias.UsingDirective, callerIsSemanticModel); } result.MergeEqual(res); } foreach (var a in this.ExternAliases) { if (a.Alias.Name == name) { // Found a match in our list of extern aliases. Mark the extern alias as being // seen so that it won't be reported to the user as something that can be // removed. var res = originalBinder.CheckViability(a.Alias, arity, options, null, diagnose, ref useSiteDiagnostics, basesBeingResolved); if (res.Kind == LookupResultKind.Viable) { MarkImportDirective(a.ExternAliasDirective, callerIsSemanticModel); } result.MergeEqual(res); } } }
internal void LookupSymbolInUsings( ImmutableArray<NamespaceOrTypeAndUsingDirective> usings, Binder originalBinder, LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { bool callerIsSemanticModel = originalBinder.IsSemanticModelBinder; foreach (var typeOrNamespace in usings) { ImmutableArray<Symbol> candidates = Binder.GetCandidateMembers(typeOrNamespace.NamespaceOrType, name, options, originalBinder: originalBinder); foreach (Symbol symbol in candidates) { // lookup via "using namespace" ignores namespaces inside if (symbol.Kind != SymbolKind.Namespace) { // Found a match in our list of normal using directives. Mark the directive // as being seen so that it won't be reported to the user as something that // can be removed. var res = originalBinder.CheckViability(symbol, arity, options, null, diagnose, ref useSiteDiagnostics, basesBeingResolved); if (res.Kind == LookupResultKind.Viable) { MarkImportDirective(typeOrNamespace.UsingDirective, callerIsSemanticModel); } result.MergeEqual(res); } } } }
internal static void LookupSymbolInUsings( ImmutableArray <NamespaceOrTypeAndUsingDirective> usings, Binder originalBinder, LookupResult result, string name, int arity, ConsList <Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { if (originalBinder.Flags.Includes(BinderFlags.InScriptUsing)) { return; } bool callerIsSemanticModel = originalBinder.IsSemanticModelBinder; foreach (var typeOrNamespace in usings) { ImmutableArray <Symbol> candidates = Binder.GetCandidateMembers(typeOrNamespace.NamespaceOrType, name, options, originalBinder: originalBinder); foreach (Symbol symbol in candidates) { switch (symbol.Kind) { // lookup via "using namespace" ignores namespaces inside case SymbolKind.Namespace: continue; // lookup via "using static" ignores extension methods and non-static methods case SymbolKind.Method: if (!symbol.IsStatic || ((MethodSymbol)symbol).IsExtensionMethod) { continue; } break; // types are considered static members for purposes of "using static" feature // regardless of whether they are declared with "static" modifier or not case SymbolKind.NamedType: break; // lookup via "using static" ignores non-static members default: if (!symbol.IsStatic) { continue; } break; } // Found a match in our list of normal using directives. Mark the directive // as being seen so that it won't be reported to the user as something that // can be removed. var res = originalBinder.CheckViability(symbol, arity, options, null, diagnose, ref useSiteDiagnostics, basesBeingResolved); if (res.Kind == LookupResultKind.Viable) { MarkImportDirective(originalBinder.Compilation, typeOrNamespace.UsingDirective, callerIsSemanticModel); } result.MergeEqual(res); } } }
/// <summary> /// Set current result according to another. /// </summary> internal void SetFrom(LookupResult other) { this.kind = other.kind; this.symbolList.Clear(); this.symbolList.AddRange(other.symbolList); this.error = other.error; }
internal void LookupSymbol( Binder originalBinder, LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { LookupSymbolInAliases(originalBinder, result, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics); if (!result.IsMultiViable && (options & LookupOptions.NamespaceAliasesOnly) == 0) { LookupSymbolInUsings(this.Usings, originalBinder, result, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics); } }
internal override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(result.IsClear); if (_container.IsSubmissionClass) { this.LookupMembersInternal(result, _container, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteDiagnostics); return; } var imports = GetImports(basesBeingResolved); // first lookup members of the namespace if ((options & LookupOptions.NamespaceAliasesOnly) == 0) { this.LookupMembersInternal(result, _container, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteDiagnostics); if (result.IsMultiViable) { // symbols cannot conflict with using alias names if (arity == 0 && imports.IsUsingAlias(name, originalBinder.IsSemanticModelBinder)) { CSDiagnosticInfo diagInfo = new CSDiagnosticInfo(ErrorCode.ERR_ConflictAliasAndMember, name, _container); var error = new ExtendedErrorTypeSymbol((NamespaceOrTypeSymbol)null, name, arity, diagInfo, unreported: true); result.SetFrom(LookupResult.Good(error)); // force lookup to be done w/ error symbol as result } return; } } // next try using aliases or symbols in imported namespaces imports.LookupSymbol(originalBinder, result, name, arity, basesBeingResolved, options, diagnose, ref useSiteDiagnostics); }
/// <summary> /// Perform a lookup for the specified method on the specified type. Perform overload resolution /// on the lookup results. /// </summary> /// <param name="patternType">Type to search.</param> /// <param name="methodName">Method to search for.</param> /// <param name="lookupResult">Passed in for reusability.</param> /// <param name="warningsOnly">True if failures should result in warnings; false if they should result in errors.</param> /// <param name="diagnostics">Populated with binding diagnostics.</param> /// <returns>The desired method or null.</returns> private MethodSymbol FindForEachPatternMethod(TypeSymbol patternType, string methodName, LookupResult lookupResult, bool warningsOnly, DiagnosticBag diagnostics) { Debug.Assert(lookupResult.IsClear); // Not using LookupOptions.MustBeInvocableMember because we don't want the corresponding lookup error. // We filter out non-methods below. HashSet <DiagnosticInfo> useSiteDiagnostics = null; this.LookupMembersInType( lookupResult, patternType, methodName, arity: 0, basesBeingResolved: null, options: LookupOptions.Default, originalBinder: this, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(_syntax.Expression, useSiteDiagnostics); if (!lookupResult.IsMultiViable) { ReportPatternMemberLookupDiagnostics(lookupResult, patternType, methodName, warningsOnly, diagnostics); return(null); } ArrayBuilder <MethodSymbol> candidateMethods = ArrayBuilder <MethodSymbol> .GetInstance(); foreach (Symbol member in lookupResult.Symbols) { if (member.Kind != SymbolKind.Method) { candidateMethods.Free(); if (warningsOnly) { ReportEnumerableWarning(diagnostics, patternType, member); } return(null); } MethodSymbol method = (MethodSymbol)member; // SPEC VIOLATION: The spec says we should apply overload resolution, but Dev10 uses // some custom logic in ExpressionBinder.BindGrpToParams. The biggest difference // we've found (so far) is that it only considers methods with zero parameters // (i.e. doesn't work with "params" or optional parameters). if (!method.Parameters.Any()) { candidateMethods.Add((MethodSymbol)member); } } MethodSymbol patternMethod = PerformForEachPatternOverloadResolution(patternType, candidateMethods, warningsOnly, diagnostics); candidateMethods.Free(); return(patternMethod); }