internal static Type Lookup(ITypeName typeName, TypeResolutionState typeResolutionState) { Type result; s_cache.TryGetValue(Tuple.Create(typeName, typeResolutionState), out result); return(result); }
private TypeResolutionState(TypeResolutionState other, HashSet <string> typesDefined) { this.namespaces = other.namespaces; this.assemblies = other.assemblies; _typesDefined = typesDefined; this.genericArgumentCount = other.genericArgumentCount; this.attribute = other.attribute; }
internal TypeResolutionState(TypeResolutionState other, int genericArgumentCount, bool attribute) { this.namespaces = other.namespaces; this.assemblies = other.assemblies; _typesDefined = other._typesDefined; this.genericArgumentCount = genericArgumentCount; this.attribute = attribute; }
private bool VisitTypeName(TypeName typeName, int genericArgumentCount, bool isAttribute) { var classDefn = _symbolTable.LookupType(typeName); if (classDefn != null && classDefn.IsAmbiguous()) { _parser.ReportError(typeName.Extent, nameof(ParserStrings.AmbiguousTypeReference), ParserStrings.AmbiguousTypeReference, typeName.Name, GetModuleQualifiedName(classDefn.ExternalNamespaces[0], typeName.Name), GetModuleQualifiedName(classDefn.ExternalNamespaces[1], typeName.Name)); } else if (classDefn != null && genericArgumentCount == 0) { typeName.SetTypeDefinition(classDefn.Type); } else { Exception e; TypeResolutionState trs = genericArgumentCount > 0 || isAttribute ? new TypeResolutionState(_typeResolutionState, genericArgumentCount, isAttribute) : _typeResolutionState; var type = TypeResolver.ResolveTypeNameWithContext(typeName, out e, null, trs); if (type == null) { if (_symbolTable.GetCurrentTypeDefinitionAst() != null) { // [ordered] is an attribute, but it's looks like a type constraint. if (!typeName.FullName.Equals(LanguagePrimitives.OrderedAttribute, StringComparison.OrdinalIgnoreCase)) { string errorId; string errorMsg; if (isAttribute) { errorId = nameof(ParserStrings.CustomAttributeTypeNotFound); errorMsg = ParserStrings.CustomAttributeTypeNotFound; } else { errorId = nameof(ParserStrings.TypeNotFound); errorMsg = ParserStrings.TypeNotFound; } _parser.ReportError(typeName.Extent, errorId, errorMsg, typeName.Name); } } } else { ((ISupportsTypeCaching)typeName).CachedType = type; return(true); } } return(false); }
private SymbolResolver(Parser parser, TypeResolutionState typeResolutionState) { _symbolTable = new SymbolTable(parser); _parser = parser; _typeResolutionState = typeResolutionState; _symbolResolvePostActionVisitor = new SymbolResolvePostActionVisitor { _symbolResolver = this }; }
/// <summary> /// A helper method to call ResolveTypeNameWorker in steps. /// </summary> private static Type CallResolveTypeNameWorkerHelper(TypeName typeName, ExecutionContext context, IEnumerable <Assembly> assemblies, bool isAssembliesExplicitlyPassedIn, TypeResolutionState typeResolutionState, out Exception exception) { if (t_searchedAssemblies == null) { t_searchedAssemblies = new HashSet <Assembly>(); } else { // Clear the set before starting a full search to make sure we have a clean start. t_searchedAssemblies.Clear(); } try { exception = null; var currentScope = context != null ? context.EngineSessionState.CurrentScope : null; Type result = ResolveTypeNameWorker(typeName, currentScope, typeResolutionState.assemblies, t_searchedAssemblies, typeResolutionState, /*onlySearchInGivenAssemblies*/ false, /* reportAmbiguousException */ true, out exception); if (exception == null && result == null) { if (context != null && !isAssembliesExplicitlyPassedIn) { // If the assemblies to search from is not specified by the caller of 'ResolveTypeNameWithContext', // then we search our assembly cache first, so as to give preference to resolving the type against // assemblies explicitly loaded by powershell, for example, via importing module/snapin. result = ResolveTypeNameWorker(typeName, currentScope, context.AssemblyCache.Values, t_searchedAssemblies, typeResolutionState, /*onlySearchInGivenAssemblies*/ true, /* reportAmbiguousException */ false, out exception); } if (result == null) { // Search from the assembly list passed in. result = ResolveTypeNameWorker(typeName, currentScope, assemblies, t_searchedAssemblies, typeResolutionState, /*onlySearchInGivenAssemblies*/ true, /* reportAmbiguousException */ false, out exception); } } return(result); } finally { // Clear the set after a full search, so dynamic assemblies can get reclaimed as needed. t_searchedAssemblies.Clear(); } }
private static Type ResolveTypeNameWorker(TypeName typeName, SessionStateScope currentScope, IEnumerable <Assembly> loadedAssemblies, HashSet <Assembly> searchedAssemblies, TypeResolutionState typeResolutionState, bool onlySearchInGivenAssemblies, bool reportAmbiguousException, out Exception exception) { Type result; exception = null; if (!onlySearchInGivenAssemblies) { while (currentScope != null) { result = currentScope.LookupType(typeName.Name); if (result != null) { return(result); } currentScope = currentScope.Parent; } if (TypeAccelerators.builtinTypeAccelerators.TryGetValue(typeName.Name, out result)) { return(result); } } result = LookForTypeInAssemblies(typeName, loadedAssemblies, searchedAssemblies, typeResolutionState, reportAmbiguousException, out exception); if (exception != null) { // skip the rest of lookups, if exception reported. return(result); } if (!onlySearchInGivenAssemblies && result == null) { lock (TypeAccelerators.userTypeAccelerators) { TypeAccelerators.userTypeAccelerators.TryGetValue(typeName.Name, out result); } } return(result); }
internal static void ResolveSymbols(Parser parser, ScriptBlockAst scriptBlockAst) { Diagnostics.Assert(scriptBlockAst.Parent == null, "Can only resolve starting from the root"); var usingState = scriptBlockAst.UsingStatements.Count > 0 ? new TypeResolutionState(TypeOps.GetNamespacesForTypeResolutionState(scriptBlockAst.UsingStatements), TypeResolutionState.emptyAssemblies) : TypeResolutionState.GetDefaultUsingState(null); var resolver = new SymbolResolver(parser, usingState); resolver._symbolTable.EnterScope(scriptBlockAst, ScopeType.ScriptBlock); scriptBlockAst.Visit(resolver); resolver._symbolTable.LeaveScope(); Diagnostics.Assert(resolver._symbolTable._scopes.Count == 0, "Somebody missed removing a scope"); }
internal static void Add(ITypeName typeName, TypeResolutionState typeResolutionState, Type type) { s_cache.GetOrAdd(Tuple.Create(typeName, typeResolutionState), type); }
private static Type LookForTypeInAssemblies(TypeName typeName, IEnumerable <Assembly> assemblies, HashSet <Assembly> searchedAssemblies, TypeResolutionState typeResolutionState, bool reportAmbiguousException, out Exception exception) { exception = null; string alternateNameToFind = typeResolutionState.GetAlternateTypeName(typeName.Name); Type foundType = null; Type foundType2 = null; foreach (Assembly assembly in assemblies) { // Skip the assemblies that we already searched and found no matching type. if (searchedAssemblies.Contains(assembly)) { continue; } try { Type targetType = LookForTypeInSingleAssembly(assembly, typeName.Name); if (targetType == null && alternateNameToFind != null) { targetType = LookForTypeInSingleAssembly(assembly, alternateNameToFind); } if (targetType != null) { if (!reportAmbiguousException) { // accelerator for the common case, when we are not interested in ambiguity exception. return(targetType); } // .NET has forward notation for types, when they declared in one assembly and implemented in another one. // We want to support both scenarios: // 1) When we pass assembly with declared forwarded type (CoreCLR) // 2) When we pass assembly with declared forwarded type and assembly with implemented forwarded type (FullCLR) // In the case (2) we should not report duplicate, hence this check if (foundType != targetType) { if (foundType != null) { foundType2 = targetType; break; } else { foundType = targetType; } } } else { // We didn't find a match from the current assembly, so update the searchedAssemblies set. searchedAssemblies.Add(assembly); } } catch (Exception) // Assembly.GetType might throw unadvertised exceptions { } } if (foundType2 != null) { exception = new AmbiguousTypeException(typeName, new string[] { foundType.AssemblyQualifiedName, foundType2.AssemblyQualifiedName }); return(null); } return(foundType); }
internal static Type ResolveTypeNameWithContext(TypeName typeName, out Exception exception, Assembly[] assemblies, TypeResolutionState typeResolutionState) { ExecutionContext context = null; exception = null; if (typeResolutionState == null) { // Usings from script scope (and if no script scope, fall back to default 'using namespace system') context = LocalPipeline.GetExecutionContextFromTLS(); typeResolutionState = TypeResolutionState.GetDefaultUsingState(context); } // We can do the cache lookup only if we don't define type in the current scope (cache would be invalid in this case). var result = typeResolutionState.ContainsTypeDefined(typeName.Name) ? null : TypeCache.Lookup(typeName, typeResolutionState); if (result != null) { return(result); } if (typeName.AssemblyName != null) { result = ResolveAssemblyQualifiedTypeName(typeName, out exception); TypeCache.Add(typeName, typeResolutionState, result); return(result); } // Simple typename (no generics, no arrays, no assembly name) // We use the following search order, using the specified name (assumed to be fully namespace qualified): // // * Search scope table (includes 'using type x = ...' aliases) // * Built in type accelerators (implicit 'using type x = ...' aliases that are effectively in global scope // * typeResolutionState.assemblies, which contains: // - Assemblies with PS types, added by 'using module' // - Assemblies added by 'using assembly'. // For this case, we REPORT ambiguity, since user explicitly specifies the set of assemblies. // * All other loaded assemblies (excluding dynamic assemblies created for PS defined types). // IGNORE ambiguity. It mimics PS v4. There are two reasons: // 1) If we report ambiguity, we need to fix our caching logic accordingly. // Consider this code // Add-Type 'public class Q {}' # ok // Add-Type 'public class Q { }' # get error about the same name // [Q] # we would get error about ambiguous type, because we added assembly with duplicated type // # before we can report TYPE_ALREADY_EXISTS error. // // Add-Type 'public class Q2 {}' # ok // [Q2] # caching Q2 type // Add-Type 'public class Q2 { }' # get error about the same name // [Q2] # we don't get an error about ambiguous type, because it's cached already // 2) NuGet (VS Package Management console) uses MEF extensibility model. // Different assemblies includes same interface (i.e. NuGet.VisualStudio.IVsPackageInstallerServices), // where they include only methods that they are interested in the interface declaration (result interfaces are different!). // Then, at runtime VS provides an instance. Everything work as far as instance has compatible API. // So [NuGet.VisualStudio.IVsPackageInstallerServices] can be resolved to several different assemblies and it's ok. // * User defined type accelerators (rare - interface was never public) // // If nothing is found, we search again, this time applying any 'using namespace ...' declarations including the implicit 'using namespace System'. // We must search all using aliases and REPORT an error if there is an ambiguity. // If this is TypeDefinition we should not cache anything in TypeCache. if (typeName._typeDefinitionAst != null) { return(typeName._typeDefinitionAst.Type); } if (context == null) { context = LocalPipeline.GetExecutionContextFromTLS(); } // Use the explicitly passed-in assembly list when it's specified by the caller. // Otherwise, retrieve all currently loaded assemblies. var assemList = assemblies ?? ClrFacade.GetAssemblies(typeResolutionState, typeName); var isAssembliesExplicitlyPassedIn = assemblies != null; result = CallResolveTypeNameWorkerHelper(typeName, context, assemList, isAssembliesExplicitlyPassedIn, typeResolutionState, out exception); if (result != null) { TypeCache.Add(typeName, typeResolutionState, result); return(result); } if (exception == null) { foreach (var ns in typeResolutionState.namespaces) { var newTypeNameToSearch = ns + "." + typeName.Name; newTypeNameToSearch = typeResolutionState.GetAlternateTypeName(newTypeNameToSearch) ?? newTypeNameToSearch; var newTypeName = new TypeName(typeName.Extent, newTypeNameToSearch); #if CORECLR if (!isAssembliesExplicitlyPassedIn) { // We called 'ClrFacade.GetAssemblies' to get assemblies. That means the assemblies to search from // are not pre-defined, and thus we have to refetch assembly again based on the new type name. assemList = ClrFacade.GetAssemblies(typeResolutionState, newTypeName); } #endif var newResult = CallResolveTypeNameWorkerHelper(newTypeName, context, assemList, isAssembliesExplicitlyPassedIn, typeResolutionState, out exception); if (exception != null) { break; } if (newResult != null) { if (result == null) { result = newResult; } else { exception = new AmbiguousTypeException(typeName, new string[] { result.FullName, newResult.FullName }); result = null; break; } } } } if (exception != null) { // AmbiguousTypeException is for internal representation only. var ambiguousException = exception as AmbiguousTypeException; if (ambiguousException != null) { exception = new PSInvalidCastException("AmbiguousTypeReference", exception, ParserStrings.AmbiguousTypeReference, ambiguousException.TypeName.Name, ambiguousException.Candidates[0], ambiguousException.Candidates[1]); } } if (result != null) { TypeCache.Add(typeName, typeResolutionState, result); } return(result); }
private static Type LookForTypeInAssemblies(TypeName typeName, IEnumerable <Assembly> assemblies, TypeResolutionState typeResolutionState, bool reportAmbiguousException, out Exception exception) { exception = null; string alternateNameToFind = typeResolutionState.GetAlternateTypeName(typeName.Name); Type foundType = null; Type foundType2 = null; foreach (Assembly assembly in assemblies) { try { Type targetType = LookForTypeInSingleAssembly(assembly, typeName.Name);; if (targetType == null && alternateNameToFind != null) { targetType = LookForTypeInSingleAssembly(assembly, alternateNameToFind); } if (targetType != null) { if (!reportAmbiguousException) { // accelerator for the common case, when we are not interested in ambiguity exception. return(targetType); } // .NET has forward notation for types, when they declared in one assembly and implemented in another one. // We want to support both scenarios: // 1) When we pass assembly with declared forwarded type (CoreCLR) // 2) When we pass assembly with declared forwarded type and assembly with implemented forwarded type (FullCLR) // In the case (2) we should not report duplicate, hence this check if (foundType != targetType) { if (foundType != null) { foundType2 = targetType; break; } else { foundType = targetType; } } } } catch (Exception e) // Assembly.GetType might throw unadvertised exceptions { CommandProcessorBase.CheckForSevereException(e); } } if (foundType2 != null) { exception = new AmbiguousTypeException(typeName, new String[] { foundType.AssemblyQualifiedName, foundType2.AssemblyQualifiedName }); return(null); } return(foundType); }