Example #1
0
 internal static PEMethodSymbol GetSourceMethod(this CSharpCompilation compilation, Guid moduleVersionId, int methodToken)
 {
     var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken);
     var method = GetMethod(compilation, moduleVersionId, methodHandle);
     var metadataDecoder = new MetadataDecoder((PEModuleSymbol)method.ContainingModule);
     var containingType = method.ContainingType;
     string sourceMethodName;
     if (GeneratedNames.TryParseSourceMethodNameFromGeneratedName(containingType.Name, GeneratedNameKind.StateMachineType, out sourceMethodName))
     {
         foreach (var member in containingType.ContainingType.GetMembers(sourceMethodName))
         {
             var candidateMethod = member as PEMethodSymbol;
             if (candidateMethod != null)
             {
                 var module = metadataDecoder.Module;
                 methodHandle = candidateMethod.Handle;
                 string stateMachineTypeName;
                 if (module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, out stateMachineTypeName) ||
                     module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, out stateMachineTypeName))
                 {
                     if (metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType))
                     {
                         return candidateMethod;
                     }
                 }
             }
         }
     }
     return method;
 }
 internal static PENamedTypeSymbol GetType(this CSharpCompilation compilation, Guid moduleVersionId, int typeToken, out MetadataDecoder metadataDecoder)
 {
     var module = compilation.GetModule(moduleVersionId);
     var reader = module.Module.MetadataReader;
     var typeHandle = (TypeDefinitionHandle)MetadataTokens.Handle(typeToken);
     var type = GetType(module, typeHandle);
     metadataDecoder = new MetadataDecoder(module, type);
     return type;
 }
        private EvaluationContext(
            MethodContextReuseConstraints? methodContextReuseConstraints,
            CSharpCompilation compilation,
            MetadataDecoder metadataDecoder,
            MethodSymbol currentFrame,
            ImmutableArray<LocalSymbol> locals,
            InScopeHoistedLocals inScopeHoistedLocals,
            MethodDebugInfo methodDebugInfo)
        {
            Debug.Assert(inScopeHoistedLocals != null);

            this.MethodContextReuseConstraints = methodContextReuseConstraints;
            this.Compilation = compilation;
            _metadataDecoder = metadataDecoder;
            _currentFrame = currentFrame;
            _locals = locals;
            _inScopeHoistedLocals = inScopeHoistedLocals;
            _methodDebugInfo = methodDebugInfo;
        }
Example #4
0
        private EvaluationContext(
            ImmutableArray<MetadataBlock> metadataBlocks,
            MethodScope methodScope,
            CSharpCompilation compilation,
            MetadataDecoder metadataDecoder,
            MethodSymbol currentFrame,
            ImmutableArray<LocalSymbol> locals,
            ImmutableSortedSet<int> inScopeHoistedLocalIndices,
            ImmutableArray<ImmutableArray<string>> importStringGroups,
            ImmutableArray<string> externAliasStrings)
        {
            Debug.Assert(inScopeHoistedLocalIndices != null);
            Debug.Assert(importStringGroups.IsDefault == externAliasStrings.IsDefault);

            this.MetadataBlocks = metadataBlocks;
            this.MethodScope = methodScope;
            this.Compilation = compilation;
            _metadataDecoder = metadataDecoder;
            _currentFrame = currentFrame;
            _locals = locals;
            _inScopeHoistedLocalIndices = inScopeHoistedLocalIndices;
            _importStringGroups = importStringGroups;
            _externAliasStrings = externAliasStrings;
        }
        private static void GetConstants(
            ArrayBuilder<LocalSymbol> builder,
            MethodSymbol method,
            IEnumerable<ISymUnmanagedScope> scopes,
            MetadataDecoder metadataDecoder,
            ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap,
            SourceAssemblySymbol containingAssembly)
        {
            foreach (var scope in scopes)
            {
                foreach (var constant in scope.GetConstants())
                {
                    string name = constant.GetName();
                    object rawValue = constant.GetValue();
                    var signature = constant.GetSignature();

                    var info = metadataDecoder.GetLocalInfo(signature);
                    Debug.Assert(!info.IsByRef);
                    Debug.Assert(!info.IsPinned);
                    var type = info.Type;

                    var constantValue = PdbHelpers.GetConstantValue(type.EnumUnderlyingType(), rawValue);

                    ImmutableArray<bool> dynamicFlags;
                    if (dynamicLocalConstantMap != null && dynamicLocalConstantMap.TryGetValue(name, out dynamicFlags))
                    {
                        type = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(
                            type,
                            containingAssembly,
                            RefKind.None,
                            dynamicFlags);
                    }

                    builder.Add(new EELocalConstantSymbol(method, name, type, constantValue));
                }
            }
        }
        internal static EvaluationContext CreateMethodContext(
            CSharpCompilation compilation,
            object symReader,
            Guid moduleVersionId,
            int methodToken,
            int methodVersion,
            int ilOffset,
            int localSignatureToken)
        {
            Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition);

            var typedSymReader = (ISymUnmanagedReader)symReader;
            var allScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
            var containingScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
            typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes);
            var methodContextReuseConstraints = allScopes.GetReuseConstraints(moduleVersionId, methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive);
            allScopes.Free();

            var localNames = containingScopes.GetLocalNames();

            var inScopeHoistedLocals = InScopeHoistedLocals.Empty;
            var methodDebugInfo = default(MethodDebugInfo);

            if (typedSymReader != null)
            {
                try
                {
                    // TODO (https://github.com/dotnet/roslyn/issues/702): switch on the type of typedSymReader and call the appropriate helper.
                    methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion, localNames.FirstOrDefault());
                    var inScopeHoistedLocalIndices = methodDebugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref methodContextReuseConstraints);
                    inScopeHoistedLocals = new CSharpInScopeHoistedLocals(inScopeHoistedLocalIndices);
                }
                catch (InvalidOperationException)
                {
                    // bad CDI, ignore
                }
            }

            var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken);
            var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle);
            Debug.Assert((object)currentFrame != null);
            var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame);
            var localInfo = metadataDecoder.GetLocalInfo(localSignatureToken);
            var localBuilder = ArrayBuilder<LocalSymbol>.GetInstance();
            var sourceAssembly = compilation.SourceAssembly;
            GetLocals(localBuilder, currentFrame, localNames, localInfo, methodDebugInfo.DynamicLocalMap, sourceAssembly);
            GetConstants(localBuilder, currentFrame, containingScopes, metadataDecoder, methodDebugInfo.DynamicLocalConstantMap, sourceAssembly);
            containingScopes.Free();

            var locals = localBuilder.ToImmutableAndFree();

            return new EvaluationContext(
                methodContextReuseConstraints,
                compilation,
                metadataDecoder,
                currentFrame,
                locals,
                inScopeHoistedLocals,
                methodDebugInfo);
        }
Example #7
0
        private void CompileTimeAndRuntimeAssemblies(
            ImmutableArray<MetadataReference> compileReferences,
            ImmutableArray<MetadataReference> runtimeReferences,
            string storageAssemblyName)
        {
            var source =
@"class C
{
    static void M(LibraryA.A a, LibraryB.B b, Windows.Data.Text.TextSegment t, Windows.Storage.StorageFolder f)
    {
    }
}";
            var compilation0 = CreateCompilationWithMscorlib(source, compileReferences, TestOptions.DebugDll);
            WithRuntimeInstance(compilation0, runtimeReferences, runtime =>
            {
                var context = CreateMethodContext(runtime, "C.M");
                string error;
                var testData = new CompilationTestData();
                context.CompileExpression("(object)a ?? (object)b ?? (object)t ?? f", out error, testData);
                Assert.Null(error);
                testData.GetMethodData("<>x.<>m0").VerifyIL(
@"{
  // Code size       17 (0x11)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  dup
  IL_0002:  brtrue.s   IL_0010
  IL_0004:  pop
  IL_0005:  ldarg.1
  IL_0006:  dup
  IL_0007:  brtrue.s   IL_0010
  IL_0009:  pop
  IL_000a:  ldarg.2
  IL_000b:  dup
  IL_000c:  brtrue.s   IL_0010
  IL_000e:  pop
  IL_000f:  ldarg.3
  IL_0010:  ret
}");
                testData = new CompilationTestData();
                var result = context.CompileExpression("default(Windows.Storage.StorageFolder)", out error, testData);
                Assert.Null(error);
                var methodData = testData.GetMethodData("<>x.<>m0");
                methodData.VerifyIL(
@"{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldnull
  IL_0001:  ret
}");
                // Check return type is from runtime assembly.
                var assemblyReference = AssemblyMetadata.CreateFromImage(result.Assembly).GetReference();
                var compilation = CSharpCompilation.Create(
                    assemblyName: ExpressionCompilerUtilities.GenerateUniqueName(),
                    references: runtimeReferences.Concat(ImmutableArray.Create<MetadataReference>(assemblyReference)));
                var assembly = ImmutableArray.CreateRange(result.Assembly);
                using (var metadata = ModuleMetadata.CreateFromImage(ImmutableArray.CreateRange(assembly)))
                {
                    var reader = metadata.MetadataReader;
                    var typeDef = reader.GetTypeDef("<>x");
                    var methodHandle = reader.GetMethodDefHandle(typeDef, "<>m0");
                    var module = (PEModuleSymbol)compilation.GetMember("<>x").ContainingModule;
                    var metadataDecoder = new MetadataDecoder(module);
                    SignatureHeader signatureHeader;
                    BadImageFormatException metadataException;
                    var parameters = metadataDecoder.GetSignatureForMethod(methodHandle, out signatureHeader, out metadataException);
                    Assert.Equal(parameters.Length, 5);
                    var actualReturnType = parameters[0].Type;
                    Assert.Equal(actualReturnType.TypeKind, TypeKind.Class); // not error
                    var expectedReturnType = compilation.GetMember("Windows.Storage.StorageFolder");
                    Assert.Equal(expectedReturnType, actualReturnType);
                    Assert.Equal(storageAssemblyName, actualReturnType.ContainingAssembly.Name);
                }
            });
        }
Example #8
0
        private static void GetConstants(
            ArrayBuilder<LocalSymbol> builder,
            MethodSymbol method,
            ImmutableArray<NamedLocalConstant> constants,
            MetadataDecoder metadataDecoder,
            ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap,
            SourceAssemblySymbol containingAssembly)
        {
            foreach (var constant in constants)
            {
                var info = metadataDecoder.GetLocalInfo(constant.Signature);
                Debug.Assert(!info.IsByRef);
                Debug.Assert(!info.IsPinned);
                var type = info.Type;

                ImmutableArray<bool> dynamicFlags;
                if (dynamicLocalConstantMap.TryGetValue(constant.Name, out dynamicFlags))
                {
                    type = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(
                        type,
                        containingAssembly,
                        RefKind.None,
                        dynamicFlags);
                }

                var constantValue = ReinterpretConstantValue(constant.Value, type.SpecialType);
                builder.Add(new EELocalConstantSymbol(method, constant.Name, type, constantValue));
            }
        }
Example #9
0
        /// <summary>
        /// Create a context for evaluating expressions within a method scope.
        /// </summary>
        /// <param name="previous">Previous context, if any, for possible re-use.</param>
        /// <param name="metadataBlocks">Module metadata</param>
        /// <param name="symReader"><see cref="ISymUnmanagedReader"/> for PDB associated with <paramref name="moduleVersionId"/></param>
        /// <param name="moduleVersionId">Module containing method</param>
        /// <param name="methodToken">Method metadata token</param>
        /// <param name="methodVersion">Method version.</param>
        /// <param name="ilOffset">IL offset of instruction pointer in method</param>
        /// <param name="localSignatureToken">Method local signature token</param>
        /// <returns>Evaluation context</returns>
        internal static EvaluationContext CreateMethodContext(
            CSharpMetadataContext previous,
            ImmutableArray<MetadataBlock> metadataBlocks,
            object symReader,
            Guid moduleVersionId,
            int methodToken,
            int methodVersion,
            int ilOffset,
            int localSignatureToken)
        {
            Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition);

            var typedSymReader = (ISymUnmanagedReader)symReader;
            var scopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
            typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, scopes);
            var scope = scopes.GetMethodScope(methodToken, methodVersion);

            // Re-use the previous compilation if possible.
            CSharpCompilation compilation;
            if (metadataBlocks.HaveNotChanged(previous))
            {
                // Re-use entire context if method scope has not changed.
                var previousContext = previous.EvaluationContext;
                if ((scope != null) && (previousContext != null) && scope.Equals(previousContext.MethodScope))
                {
                    return previousContext;
                }
                compilation = previous.Compilation;
            }
            else
            {
                compilation = metadataBlocks.ToCompilation();
            }

            var localNames = scopes.GetLocalNames();

            var dynamicLocalMap = ImmutableDictionary<int, ImmutableArray<bool>>.Empty;
            var dynamicLocalConstantMap = ImmutableDictionary<string, ImmutableArray<bool>>.Empty;
            var inScopeHoistedLocalIndices = ImmutableSortedSet<int>.Empty;
            var groupedImportStrings = default(ImmutableArray<ImmutableArray<string>>);
            var externAliasStrings = default(ImmutableArray<string>);

            if (typedSymReader != null)
            {
                try
                {
                    var cdi = typedSymReader.GetCustomDebugInfo(methodToken, methodVersion);
                    if (cdi != null)
                    {
                        CustomDebugInfoReader.GetCSharpDynamicLocalInfo(
                            cdi,
                            methodToken,
                            methodVersion,
                            localNames.FirstOrDefault(),
                            out dynamicLocalMap,
                            out dynamicLocalConstantMap);

                        inScopeHoistedLocalIndices = CustomDebugInfoReader.GetCSharpInScopeHoistedLocalIndices(
                            cdi,
                            methodToken,
                            methodVersion,
                            ilOffset);
                    }

                    groupedImportStrings = typedSymReader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings);
                }
                catch (InvalidOperationException)
                {
                    // bad CDI, ignore
                }
            }

            var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken);
            var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle);
            Debug.Assert((object)currentFrame != null);
            var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame);
            var localInfo = metadataDecoder.GetLocalInfo(localSignatureToken);
            var localBuilder = ArrayBuilder<LocalSymbol>.GetInstance();
            var sourceAssembly = compilation.SourceAssembly;
            GetLocals(localBuilder, currentFrame, localNames, localInfo, dynamicLocalMap, sourceAssembly);
            GetConstants(localBuilder, currentFrame, scopes.GetConstantSignatures(), metadataDecoder, dynamicLocalConstantMap, sourceAssembly);
            scopes.Free();

            var locals = localBuilder.ToImmutableAndFree();

            return new EvaluationContext(
                metadataBlocks,
                scope,
                compilation,
                metadataDecoder,
                currentFrame,
                locals,
                inScopeHoistedLocalIndices,
                groupedImportStrings,
                externAliasStrings);
        }
Example #10
0
 private static PENamedTypeSymbol GetType(PEModuleSymbol module, TypeDefinitionHandle typeHandle)
 {
     var metadataDecoder = new MetadataDecoder(module);
     return (PENamedTypeSymbol)metadataDecoder.GetTypeOfToken(typeHandle);
 }
Example #11
0
        private static EvaluationContext CreateMethodContext(
            CSharpCompilation compilation,
            object symReader,
            Guid moduleVersionId,
            int methodToken,
            int methodVersion,
            int ilOffset,
            int localSignatureToken)
        {
            var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken);
            var localSignatureHandle = (localSignatureToken != 0) ? (StandaloneSignatureHandle)MetadataTokens.Handle(localSignatureToken) : default(StandaloneSignatureHandle);

            var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle);
            Debug.Assert((object)currentFrame != null);
            var sourceAssembly = compilation.SourceAssembly;
            var symbolProvider = new CSharpEESymbolProvider(sourceAssembly, (PEModuleSymbol)currentFrame.ContainingModule, currentFrame);

            var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame);
            var localInfo = metadataDecoder.GetLocalInfo(localSignatureHandle);

            var typedSymReader = (ISymUnmanagedReader3)symReader;
            var inScopeHoistedLocals = InScopeHoistedLocals.Empty;

            var debugInfo = MethodDebugInfo<TypeSymbol, LocalSymbol>.ReadMethodDebugInfo(typedSymReader, symbolProvider, methodToken, methodVersion, ilOffset, isVisualBasicMethod: false);

            var reuseSpan = debugInfo.ReuseSpan;
            var localsBuilder = ArrayBuilder<LocalSymbol>.GetInstance();
            MethodDebugInfo<TypeSymbol, LocalSymbol>.GetLocals(localsBuilder, symbolProvider, debugInfo.LocalVariableNames, localInfo, debugInfo.DynamicLocalMap);
            if (!debugInfo.HoistedLocalScopeRecords.IsDefaultOrEmpty)
            {
                inScopeHoistedLocals = new CSharpInScopeHoistedLocals(debugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref reuseSpan));
            }

            localsBuilder.AddRange(debugInfo.LocalConstants);

            return new EvaluationContext(
                new MethodContextReuseConstraints(moduleVersionId, methodToken, methodVersion, reuseSpan),
                compilation,
                currentFrame,
                localsBuilder.ToImmutableAndFree(),
                inScopeHoistedLocals,
                debugInfo);
        }
Example #12
0
        private static Imports BuildImports(CSharpCompilation compilation, PEModuleSymbol module, ImmutableArray<ImportRecord> importRecords, InContainerBinder binder, MetadataDecoder metadataDecoder)
        {
            // We make a first pass to extract all of the extern aliases because other imports may depend on them.
            var externsBuilder = ArrayBuilder<AliasAndExternAliasDirective>.GetInstance();
            foreach (var importRecord in importRecords)
            {
                if (importRecord.TargetKind != ImportTargetKind.Assembly)
                {
                    continue;
                }

                var alias = importRecord.Alias;
                IdentifierNameSyntax aliasNameSyntax;
                if (!TryParseIdentifierNameSyntax(alias, out aliasNameSyntax))
                {
                    Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid extern alias '{alias}'");
                    continue;
                }

                var externAliasSyntax = SyntaxFactory.ExternAliasDirective(aliasNameSyntax.Identifier);
                var aliasSymbol = new AliasSymbol(binder, externAliasSyntax); // Binder is only used to access compilation.
                externsBuilder.Add(new AliasAndExternAliasDirective(aliasSymbol, externAliasDirective: null)); // We have one, but we pass null for consistency.
            }

            var externs = externsBuilder.ToImmutableAndFree();

            if (externs.Any())
            {
                // NB: This binder (and corresponding Imports) is only used to bind the other imports.
                // We'll merge the externs into a final Imports object and return that to be used in
                // the actual binder chain.
                binder = new InContainerBinder(
                    binder.Container,
                    binder,
                    Imports.FromCustomDebugInfo(binder.Compilation, ImmutableDictionary<string, AliasAndUsingDirective>.Empty, ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, externs));
            }

            var usingAliases = ImmutableDictionary.CreateBuilder<string, AliasAndUsingDirective>();
            var usingsBuilder = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance();

            foreach (var importRecord in importRecords)
            {
                switch (importRecord.TargetKind)
                {
                    case ImportTargetKind.Type:
                        {
                            var portableImportRecord = importRecord as PortableImportRecord;

                            TypeSymbol typeSymbol = portableImportRecord != null
                                    ? portableImportRecord.GetTargetType(metadataDecoder)
                                    : metadataDecoder.GetTypeSymbolForSerializedType(importRecord.TargetString);
                            Debug.Assert((object)typeSymbol != null);

                            if (typeSymbol.IsErrorType())
                            {
                                // Type is unrecognized. The import may have been
                                // valid in the original source but unnecessary.
                                continue; // Don't add anything for this import.
                            }
                            else if (importRecord.Alias == null && !typeSymbol.IsStatic)
                            {
                                // Only static types can be directly imported.
                                continue;
                            }

                            if (!TryAddImport(importRecord.Alias, typeSymbol, usingsBuilder, usingAliases, binder, importRecord))
                            {
                                continue;
                            }

                            break;
                        }
                    case ImportTargetKind.Namespace:
                        {
                            var namespaceName = importRecord.TargetString;
                            NameSyntax targetSyntax;
                            if (!SyntaxHelpers.TryParseDottedName(namespaceName, out targetSyntax))
                            {
                                // DevDiv #999086: Some previous version of VS apparently generated type aliases as "UA{alias} T{alias-qualified type name}". 
                                // Neither Roslyn nor Dev12 parses such imports.  However, Roslyn discards them, rather than interpreting them as "UA{alias}"
                                // (which will rarely work and never be correct).
                                Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid target '{importRecord.TargetString}'");
                                continue;
                            }

                            NamespaceSymbol namespaceSymbol;
                            var portableImportRecord = importRecord as PortableImportRecord;
                            if (portableImportRecord != null)
                            {
                                var targetAssembly = portableImportRecord.GetTargetAssembly<ModuleSymbol, AssemblySymbol>(module, module.Module);
                                if ((object)targetAssembly == null)
                                {
                                    namespaceSymbol = BindNamespace(namespaceName, compilation.GlobalNamespace);
                                }
                                else if (targetAssembly.IsMissing)
                                {
                                    Debug.WriteLine($"Import record '{importRecord}' has invalid assembly reference '{targetAssembly.Identity}'");
                                    continue;
                                }
                                else
                                {
                                    namespaceSymbol = BindNamespace(namespaceName, targetAssembly.GlobalNamespace);
                                }
                            }
                            else
                            {
                                var globalNamespace = compilation.GlobalNamespace;

                                var externAlias = ((NativeImportRecord)importRecord).ExternAlias;
                                if (externAlias != null)
                                {
                                    IdentifierNameSyntax externAliasSyntax = null;
                                    if (!TryParseIdentifierNameSyntax(externAlias, out externAliasSyntax))
                                    {
                                        Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid extern alias '{externAlias}'");
                                        continue;
                                    }

                                    var unusedDiagnostics = DiagnosticBag.GetInstance();
                                    var aliasSymbol = (AliasSymbol)binder.BindNamespaceAliasSymbol(externAliasSyntax, unusedDiagnostics);
                                    unusedDiagnostics.Free();

                                    if ((object)aliasSymbol == null)
                                    {
                                        Debug.WriteLine($"Import record '{importRecord}' requires unknown extern alias '{externAlias}'");
                                        continue;
                                    }

                                    globalNamespace = (NamespaceSymbol)aliasSymbol.Target;
                                }

                                namespaceSymbol = BindNamespace(namespaceName, globalNamespace);
                            }

                            if ((object)namespaceSymbol == null)
                            {
                                // Namespace is unrecognized. The import may have been
                                // valid in the original source but unnecessary.
                                continue; // Don't add anything for this import.
                            }

                            if (!TryAddImport(importRecord.Alias, namespaceSymbol, usingsBuilder, usingAliases, binder, importRecord))
                            {
                                continue;
                            }

                            break;
                        }
                    case ImportTargetKind.Assembly:
                        {
                            // Handled in first pass (above).
                            break;
                        }
                    default:
                        {
                            throw ExceptionUtilities.UnexpectedValue(importRecord.TargetKind);
                        }
                }
            }

            return Imports.FromCustomDebugInfo(binder.Compilation, usingAliases.ToImmutableDictionary(), usingsBuilder.ToImmutableAndFree(), externs);
        }
Example #13
0
        private static Binder CreateBinderChain(
            CSharpCompilation compilation,
            PEModuleSymbol module,
            NamespaceSymbol @namespace,
            ImmutableArray<ImmutableArray<ImportRecord>> importRecordGroups,
            MetadataDecoder metadataDecoder)
        {
            var stack = ArrayBuilder<string>.GetInstance();
            while ((object)@namespace != null)
            {
                stack.Push(@namespace.Name);
                @namespace = @namespace.ContainingNamespace;
            }

            Binder binder = new BuckStopsHereBinder(compilation);
            var hasImports = !importRecordGroups.IsDefaultOrEmpty;
            var numImportStringGroups = hasImports ? importRecordGroups.Length : 0;
            var currentStringGroup = numImportStringGroups - 1;

            // PERF: We used to call compilation.GetCompilationNamespace on every iteration,
            // but that involved walking up to the global namespace, which we have to do
            // anyway.  Instead, we'll inline the functionality into our own walk of the
            // namespace chain.
            @namespace = compilation.GlobalNamespace;

            while (stack.Count > 0)
            {
                var namespaceName = stack.Pop();
                if (namespaceName.Length > 0)
                {
                    // We're re-getting the namespace, rather than using the one containing
                    // the current frame method, because we want the merged namespace.
                    @namespace = @namespace.GetNestedNamespace(namespaceName);
                    Debug.Assert((object)@namespace != null,
                        $"We worked backwards from symbols to names, but no symbol exists for name '{namespaceName}'");
                }
                else
                {
                    Debug.Assert((object)@namespace == (object)compilation.GlobalNamespace);
                }

                Imports imports = null;
                if (hasImports)
                {
                    if (currentStringGroup < 0)
                    {
                        Debug.WriteLine($"No import string group for namespace '{@namespace}'");
                        break;
                    }

                    var importsBinder = new InContainerBinder(@namespace, binder);
                    imports = BuildImports(compilation, module, importRecordGroups[currentStringGroup], importsBinder, metadataDecoder);
                    currentStringGroup--;
                }

                binder = new InContainerBinder(@namespace, binder, imports);
            }

            stack.Free();

            if (currentStringGroup >= 0)
            {
                // CONSIDER: We could lump these into the outermost namespace.  It's probably not worthwhile since
                // the usings are already for the wrong method.
                Debug.WriteLine($"Found {currentStringGroup + 1} import string groups without corresponding namespaces");
            }

            return binder;
        }
Example #14
0
        /// <summary>
        /// Create a context to compile expressions within a method scope.
        /// </summary>
        internal CompilationContext(
            CSharpCompilation compilation,
            MetadataDecoder metadataDecoder,
            MethodSymbol currentFrame,
            ImmutableArray<LocalSymbol> locals,
            InScopeHoistedLocals inScopeHoistedLocals,
            MethodDebugInfo methodDebugInfo,
            CSharpSyntaxNode syntax)
        {
            Debug.Assert(string.IsNullOrEmpty(methodDebugInfo.DefaultNamespaceName));
            Debug.Assert((syntax == null) || (syntax is ExpressionSyntax) || (syntax is LocalDeclarationStatementSyntax));

            // TODO: syntax.SyntaxTree should probably be added to the compilation,
            // but it isn't rooted by a CompilationUnitSyntax so it doesn't work (yet).
            _currentFrame = currentFrame;
            _syntax = syntax;
            _methodNotType = !locals.IsDefault;

            // NOTE: Since this is done within CompilationContext, it will not be cached.
            // CONSIDER: The values should be the same everywhere in the module, so they
            // could be cached.  
            // (Catch: what happens in a type context without a method def?)
            this.Compilation = GetCompilationWithExternAliases(compilation, methodDebugInfo.ExternAliasRecords);
            _metadataDecoder = metadataDecoder;

            // Each expression compile should use a unique compilation
            // to ensure expression-specific synthesized members can be
            // added (anonymous types, for instance).
            Debug.Assert(this.Compilation != compilation);

            this.NamespaceBinder = CreateBinderChain(
                this.Compilation,
                (PEModuleSymbol)currentFrame.ContainingModule,
                currentFrame.ContainingNamespace,
                methodDebugInfo.ImportRecordGroups,
                _metadataDecoder);

            if (_methodNotType)
            {
                _locals = locals;
                ImmutableArray<string> displayClassVariableNamesInOrder;
                GetDisplayClassVariables(
                    currentFrame,
                    _locals,
                    inScopeHoistedLocals,
                    out displayClassVariableNamesInOrder,
                    out _displayClassVariables,
                    out _hoistedParameterNames);
                Debug.Assert(displayClassVariableNamesInOrder.Length == _displayClassVariables.Count);
                _localsForBinding = GetLocalsForBinding(_locals, displayClassVariableNamesInOrder, _displayClassVariables);
            }
            else
            {
                _locals = ImmutableArray<LocalSymbol>.Empty;
                _displayClassVariables = ImmutableDictionary<string, DisplayClassVariable>.Empty;
                _localsForBinding = ImmutableArray<LocalSymbol>.Empty;
            }

            // Assert that the cheap check for "this" is equivalent to the expensive check for "this".
            Debug.Assert(
                _displayClassVariables.ContainsKey(GeneratedNames.ThisProxyFieldName()) ==
                _displayClassVariables.Values.Any(v => v.Kind == DisplayClassVariableKind.This));
        }
        private static Binder ExtendBinderChain(
            InspectionContext inspectionContext,
            CSharpCompilation compilation,
            MetadataDecoder metadataDecoder,
            CSharpSyntaxNode syntax,
            EEMethodSymbol method,
            Binder binder,
            bool hasDisplayClassThis,
            bool methodNotType)
        {
            var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis);
            var substitutedSourceType = substitutedSourceMethod.ContainingType;

            var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance();
            for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType)
            {
                stack.Add(type);
            }

            while (stack.Count > 0)
            {
                substitutedSourceType = stack.Pop();

                binder = new InContainerBinder(substitutedSourceType, binder);
                if (substitutedSourceType.Arity > 0)
                {
                    binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder);
                }
            }

            stack.Free();

            if (substitutedSourceMethod.Arity > 0)
            {
                binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder);
            }

            if (methodNotType)
            {
                // Method locals and parameters shadow pseudo-variables.
                binder = new PlaceholderLocalBinder(inspectionContext, new EETypeNameDecoder(compilation, metadataDecoder.ModuleSymbol), syntax, method, binder);
            }

            binder = new EEMethodBinder(method, substitutedSourceMethod, binder);

            if (methodNotType)
            {
                binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder);
            }

            return binder;
        }
Example #16
0
        private static Imports BuildImports(CSharpCompilation compilation, ImmutableArray<string> importStrings, InContainerBinder binder, MetadataDecoder metadataDecoder)
        {
            // We make a first pass to extract all of the extern aliases because other imports may depend on them.
            var externsBuilder = ArrayBuilder<AliasAndExternAliasDirective>.GetInstance();
            foreach (var importString in importStrings)
            {
                string alias;
                string externAlias;
                string target;
                ImportTargetKind kind;
                if (!CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out target, out kind))
                {
                    Debug.WriteLine("Unable to parse import string '{0}'", (object)importString);
                    continue;
                }
                else if (kind != ImportTargetKind.Assembly)
                {
                    continue;
                }

                Debug.Assert(alias == null);
                Debug.Assert(externAlias != null);
                Debug.Assert(target == null);

                NameSyntax aliasNameSyntax;
                if (!SyntaxHelpers.TryParseDottedName(externAlias, out aliasNameSyntax) || aliasNameSyntax.Kind() != SyntaxKind.IdentifierName)
                {
                    Debug.WriteLine("Import string '{0}' has syntactically invalid extern alias '{1}'", importString, externAlias);
                    continue;
                }

                var aliasToken = ((IdentifierNameSyntax)aliasNameSyntax).Identifier;
                var externAliasSyntax = SyntaxFactory.ExternAliasDirective(aliasToken);
                var aliasSymbol = new AliasSymbol(binder, externAliasSyntax); // Binder is only used to access compilation.
                externsBuilder.Add(new AliasAndExternAliasDirective(aliasSymbol, externAliasSyntax));
            }

            var externs = externsBuilder.ToImmutableAndFree();

            if (externs.Any())
            {
                // NB: This binder (and corresponding Imports) is only used to bind the other imports.
                // We'll merge the externs into a final Imports object and return that to be used in
                // the actual binder chain.
                binder = new InContainerBinder(
                    binder.Container,
                    binder,
                    Imports.FromCustomDebugInfo(binder.Compilation, new Dictionary<string, AliasAndUsingDirective>(), ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, externs));
            }

            var usingAliases = new Dictionary<string, AliasAndUsingDirective>();
            var usingsBuilder = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance();

            foreach (var importString in importStrings)
            {
                string alias;
                string externAlias;
                string target;
                ImportTargetKind kind;
                if (!CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out target, out kind))
                {
                    Debug.WriteLine("Unable to parse import string '{0}'", (object)importString);
                    continue;
                }

                switch (kind)
                {
                    case ImportTargetKind.Type:
                        {
                            Debug.Assert(target != null, string.Format("Type import string '{0}' has no target", importString));
                            Debug.Assert(externAlias == null, string.Format("Type import string '{0}' has an extern alias (should be folded into target)", importString));

                            TypeSymbol typeSymbol = metadataDecoder.GetTypeSymbolForSerializedType(target);
                            Debug.Assert((object)typeSymbol != null);
                            if (typeSymbol.IsErrorType())
                            {
                                // Type is unrecognized. The import may have been
                                // valid in the original source but unnecessary.
                                continue; // Don't add anything for this import.
                            }
                            else if (alias == null && !typeSymbol.IsStatic)
                            {
                                // Only static types can be directly imported.
                                continue;
                            }

                            NameSyntax typeSyntax = SyntaxFactory.ParseName(typeSymbol.ToDisplayString(s_fullNameFormat));
                            if (!TryAddImport(alias, typeSyntax, typeSymbol, usingsBuilder, usingAliases, binder, importString))
                            {
                                continue;
                            }

                            break;
                        }
                    case ImportTargetKind.Namespace:
                        {
                            Debug.Assert(target != null, string.Format("Namespace import string '{0}' has no target", importString));

                            NameSyntax targetSyntax;
                            if (!SyntaxHelpers.TryParseDottedName(target, out targetSyntax))
                            {
                                // DevDiv #999086: Some previous version of VS apparently generated type aliases as "UA{alias} T{alias-qualified type name}". 
                                // Neither Roslyn nor Dev12 parses such imports.  However, Roslyn discards them, rather than interpreting them as "UA{alias}"
                                // (which will rarely work and never be correct).
                                Debug.WriteLine("Import string '{0}' has syntactically invalid target '{1}'", importString, target);
                                continue;
                            }

                            if (externAlias != null)
                            {
                                IdentifierNameSyntax externAliasSyntax;
                                if (!TryParseIdentifierNameSyntax(externAlias, out externAliasSyntax))
                                {
                                    Debug.WriteLine("Import string '{0}' has syntactically invalid extern alias '{1}'", importString, externAlias);
                                    continue;
                                }

                                // This is the case that requires the binder to already know about extern aliases.
                                targetSyntax = SyntaxHelpers.PrependExternAlias(externAliasSyntax, targetSyntax);
                            }

                            var unusedDiagnostics = DiagnosticBag.GetInstance();
                            var namespaceSymbol = binder.BindNamespaceOrType(targetSyntax, unusedDiagnostics).ExpressionSymbol as NamespaceSymbol;
                            unusedDiagnostics.Free();
                            if ((object)namespaceSymbol == null)
                            {
                                // Namespace is unrecognized. The import may have been
                                // valid in the original source but unnecessary.
                                continue; // Don't add anything for this import.
                            }

                            if (!TryAddImport(alias, targetSyntax, namespaceSymbol, usingsBuilder, usingAliases, binder, importString))
                            {
                                continue;
                            }

                            break;
                        }
                    case ImportTargetKind.Assembly:
                        {
                            // Handled in first pass (above).
                            break;
                        }
                    default:
                        {
                            throw ExceptionUtilities.UnexpectedValue(kind);
                        }
                }
            }

            return Imports.FromCustomDebugInfo(binder.Compilation, usingAliases, usingsBuilder.ToImmutableAndFree(), externs);
        }