//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2004-2009 Novell, Inc.
+// Copyright 2011 Xamarin Inc.
//
using System;
using System.Collections.Generic;
-using System.Reflection.Emit;
+using System.IO;
+using System.Security.Cryptography;
namespace Mono.CSharp
{
+ public enum LookupMode
+ {
+ Normal = 0,
+ Probing = 1,
+ IgnoreAccessibility = 2
+ }
+
//
// Implemented by elements which can act as independent contexts
// during resolve phase. Used mostly for lookups.
//
- public interface IMemberContext
+ public interface IMemberContext : IModuleContext
{
//
// A scope type context, it can be inflated for generic types
//
// A scope type parameters either VAR or MVAR
//
- TypeParameter[] CurrentTypeParameters { get; }
+ TypeParameters CurrentTypeParameters { get; }
//
// A member definition of the context. For partial types definition use
bool IsObsolete { get; }
bool IsUnsafe { get; }
bool IsStatic { get; }
- bool HasUnresolvedConstraints { get; }
string GetSignatureForError ();
- IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope);
- FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104);
+ ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity);
+ FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
FullNamedExpression LookupNamespaceAlias (string name);
+ }
- CompilerContext Compiler { get; }
+ public interface IModuleContext
+ {
+ ModuleContainer Module { get; }
}
//
{
FlowBranching current_flow_branching;
- TypeSpec return_type;
-
- /// <summary>
- /// The location where return has to jump to return the
- /// value
- /// </summary>
- public Label ReturnLabel; // TODO: It's emit dependant
-
- /// <summary>
- /// If we already defined the ReturnLabel
- /// </summary>
- public bool HasReturnLabel;
+ readonly TypeSpec return_type;
public int FlowOffset;
if (rc.HasSet (ResolveContext.Options.CheckedScope))
flags |= ResolveContext.Options.CheckedScope;
+
+ if (rc.IsInProbingMode)
+ flags |= ResolveContext.Options.ProbingMode;
+
+ if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
+ flags |= ResolveContext.Options.FieldInitializerScope;
+
+ if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
+ flags |= ResolveContext.Options.ExpressionTreeConversion;
+
+ if (rc.HasSet (ResolveContext.Options.BaseInitializer))
+ flags |= ResolveContext.Options.BaseInitializer;
}
public override FlowBranching CurrentBranching {
get { return current_flow_branching; }
}
+ public TypeSpec ReturnType {
+ get { return return_type; }
+ }
+
+ public bool IsUnreachable {
+ get {
+ return HasSet (Options.UnreachableScope);
+ }
+ set {
+ flags = value ? flags | Options.UnreachableScope : flags & ~Options.UnreachableScope;
+ }
+ }
+
+ public bool UnreachableReported {
+ get {
+ return HasSet (Options.UnreachableReported);
+ }
+ set {
+ flags = value ? flags | Options.UnreachableReported : flags & ~Options.UnreachableScope;
+ }
+ }
+
// <summary>
// Starts a new code branching. This inherits the state of all local
// variables and parameters from the current branching.
return branching;
}
- public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
+ public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
{
- FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
+ FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
current_flow_branching = branching;
return branching;
}
return branching;
}
+ public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
+ {
+ var branching = new FlowBranchingAsync (parent, asyncBody);
+ current_flow_branching = branching;
+ return branching;
+ }
+
public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
{
FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
current_flow_branching = current_flow_branching.Parent;
}
- //
- // This method is used during the Resolution phase to flag the
- // need to define the ReturnLabel
- //
+#if !STATIC
public void NeedReturnLabel ()
{
- if (!HasReturnLabel)
- HasReturnLabel = true;
- }
-
- public TypeSpec ReturnType {
- get { return return_type; }
}
+#endif
}
//
UsingInitializerScope = 1 << 12,
+ LockScope = 1 << 13,
+
+ UnreachableScope = 1 << 14,
+
+ UnreachableReported = 1 << 15,
+
/// <summary>
/// Whether control flow analysis is enabled
/// </summary>
//
// The default setting comes from the command line option
//
- if (RootContext.Checked)
+ if (mc.Module.Compiler.Settings.Checked)
flags |= Options.CheckedScope;
//
flags |= options;
}
- public CompilerContext Compiler {
- get { return MemberContext.Compiler; }
+ #region Properties
+
+ public BuiltinTypes BuiltinTypes {
+ get {
+ return MemberContext.Module.Compiler.BuiltinTypes;
+ }
}
public virtual ExplicitBlock ConstructorBlock {
get { return MemberContext.CurrentType; }
}
- public TypeParameter[] CurrentTypeParameters {
+ public TypeParameters CurrentTypeParameters {
get { return MemberContext.CurrentTypeParameters; }
}
get { return (flags & Options.DoFlowAnalysis) != 0; }
}
- public bool HasUnresolvedConstraints {
- get { return false; }
+ public bool IsInProbingMode {
+ get {
+ return (flags & Options.ProbingMode) != 0;
+ }
}
- public bool IsInProbingMode {
- get { return (flags & Options.ProbingMode) != 0; }
+ public bool IsObsolete {
+ get {
+ // Disables obsolete checks when probing is on
+ return MemberContext.IsObsolete;
+ }
+ }
+
+ public bool IsStatic {
+ get {
+ return MemberContext.IsStatic;
+ }
+ }
+
+ public bool IsUnsafe {
+ get {
+ return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
+ }
+ }
+
+ public bool IsRuntimeBinder {
+ get {
+ return Module.Compiler.IsRuntimeBinder;
+ }
}
public bool IsVariableCapturingRequired {
public ModuleContainer Module {
get {
- return MemberContext.CurrentMemberDefinition.Module;
+ return MemberContext.Module;
}
}
get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
}
+ public Report Report {
+ get {
+ return Module.Compiler.Report;
+ }
+ }
+
+ #endregion
+
public bool MustCaptureVariable (INamedBlockVariable local)
{
if (CurrentAnonymousMethod == null)
return false;
- // FIXME: IsIterator is too aggressive, we should capture only if child
- // block contains yield
+ //
+ // Capture only if this or any of child blocks contain yield
+ // or it's a parameter
+ //
if (CurrentAnonymousMethod.IsIterator)
- return true;
+ return local.IsParameter || local.Block.Explicit.HasYield;
+
+ //
+ // Capture only if this or any of child blocks contain await
+ // or it's a parameter
+ //
+ if (CurrentAnonymousMethod is AsyncInitializer)
+ return local.IsParameter || local.Block.Explicit.HasAwait || CurrentBlock.Explicit.HasAwait;
return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
}
return (this.flags & options) != 0;
}
- public Report Report {
- get {
- return Compiler.Report;
- }
- }
// Temporarily set all the given flags to the given value. Should be used in an 'using' statement
public FlagsHandle Set (Options options)
return MemberContext.GetSignatureForError ();
}
- public bool IsObsolete {
- get {
- // Disables obsolete checks when probing is on
- return MemberContext.IsObsolete;
- }
- }
-
- public bool IsStatic {
- get { return MemberContext.IsStatic; }
- }
-
- public bool IsUnsafe {
- get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
- }
-
- public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
+ public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
- return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
+ return MemberContext.LookupExtensionMethod (extensionType, name, arity);
}
- public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
+ public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
{
- return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
+ return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
}
public FullNamedExpression LookupNamespaceAlias (string name)
//
public class CompilerContext
{
+ static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
+
readonly Report report;
- readonly BuildinTypes buildin_types;
+ readonly BuiltinTypes builtin_types;
+ readonly CompilerSettings settings;
+
+ Dictionary<string, SourceFile> all_source_files;
- public CompilerContext (Report report)
+ public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
{
- this.report = report;
- this.buildin_types = new BuildinTypes ();
+ this.settings = settings;
+ this.report = new Report (this, reportPrinter);
+ this.builtin_types = new BuiltinTypes ();
+ this.TimeReporter = DisabledTimeReporter;
}
#region Properties
- internal BuildinTypes BuildinTypes {
+ public BuiltinTypes BuiltinTypes {
get {
- return buildin_types;
+ return builtin_types;
}
}
- // TODO: Obsolete, it has to go
- public RootNamespace GlobalRootNamespace { get; set; }
-
- public bool IsRuntimeBinder { get; set; }
+ // Used for special handling of runtime dynamic context mostly
+ // by error reporting but also by member accessibility checks
+ public bool IsRuntimeBinder {
+ get; set;
+ }
public Report Report {
get {
}
}
+ public CompilerSettings Settings {
+ get {
+ return settings;
+ }
+ }
+
+ public List<SourceFile> SourceFiles {
+ get {
+ return settings.SourceFiles;
+ }
+ }
+
+ internal TimeReporter TimeReporter {
+ get; set;
+ }
+
#endregion
+
+ //
+ // This is used when we encounter a #line preprocessing directive during parsing
+ // to register additional source file names
+ //
+ public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
+ {
+ if (all_source_files == null) {
+ all_source_files = new Dictionary<string, SourceFile> ();
+ foreach (var source in SourceFiles)
+ all_source_files[source.FullPathName] = source;
+ }
+
+ string path;
+ if (!Path.IsPathRooted (name)) {
+ string root = Path.GetDirectoryName (comp_unit.SourceFile.FullPathName);
+ path = Path.Combine (root, name);
+ } else
+ path = name;
+
+ SourceFile retval;
+ if (all_source_files.TryGetValue (path, out retval))
+ return retval;
+
+ retval = new SourceFile (name, path, all_source_files.Count + 1);
+ Location.AddFile (retval);
+ all_source_files.Add (path, retval);
+ return retval;
+ }
}
//
/// </summary>
CheckedScope = 1 << 0,
- /// <summary>
- /// The constant check state is always set to `true' and cant be changed
- /// from the command line. The source code can change this setting with
- /// the `checked' and `unchecked' statements and expressions.
- /// </summary>
- ConstantCheckState = 1 << 1,
-
- AllCheckStateFlags = CheckedScope | ConstantCheckState,
+ AccurateDebugInfo = 1 << 1,
OmitDebugInfo = 1 << 2,
- ConstructorScope = 1 << 3
+ ConstructorScope = 1 << 3,
+
+ AsyncBody = 1 << 4
}
// utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
}
}
- Options flags;
+ protected Options flags;
public bool HasSet (Options options)
{
return new FlagsHandle (this, options, enable ? options : 0);
}
}
+
+ //
+ // Parser session objects. We could recreate all these objects for each parser
+ // instance but the best parser performance the session object can be reused
+ //
+ public class ParserSession
+ {
+ MD5 md5;
+
+ public readonly char[] StreamReaderBuffer = new char[SeekableStreamReader.DefaultReadAheadSize * 2];
+ public readonly Dictionary<char[], string>[] Identifiers = new Dictionary<char[], string>[Tokenizer.MaxIdentifierLength + 1];
+ public readonly List<Parameter> ParametersStack = new List<Parameter> (4);
+ public readonly char[] IDBuilder = new char[Tokenizer.MaxIdentifierLength];
+ public readonly char[] NumberBuilder = new char[Tokenizer.MaxNumberLength];
+
+ public LocationsBag LocationsBag { get; set; }
+ public bool UseJayGlobalArrays { get; set; }
+ public Tokenizer.LocatedToken[] LocatedTokens { get; set; }
+
+ public MD5 GetChecksumAlgorithm ()
+ {
+ return md5 ?? (md5 = MD5.Create ());
+ }
+ }
}