SourceConstructorSymbol.cs 10.8 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2 3 4 5 6 7 8 9 10 11 12

using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    internal sealed class SourceConstructorSymbol : SourceMethodSymbol
    {
13 14 15
        private ImmutableArray<ParameterSymbol> _lazyParameters;
        private TypeSymbol _lazyReturnType;
        private bool _lazyIsVararg;
16

P
Pilchie 已提交
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
        public static SourceConstructorSymbol CreateConstructorSymbol(
            SourceMemberContainerTypeSymbol containingType,
            ConstructorDeclarationSyntax syntax,
            DiagnosticBag diagnostics)
        {
            var methodKind = syntax.Modifiers.Any(SyntaxKind.StaticKeyword) ? MethodKind.StaticConstructor : MethodKind.Constructor;
            return new SourceConstructorSymbol(containingType, syntax.Identifier.GetLocation(), syntax, methodKind, diagnostics);
        }

        private SourceConstructorSymbol(
            SourceMemberContainerTypeSymbol containingType,
            Location location,
            ConstructorDeclarationSyntax syntax,
            MethodKind methodKind,
            DiagnosticBag diagnostics) :
32
            base(containingType, syntax.GetReference(), syntax.Body?.GetReference(), ImmutableArray.Create(location))
P
Pilchie 已提交
33 34 35
        {
            bool modifierErrors;
            var declarationModifiers = this.MakeModifiers(syntax.Modifiers, methodKind, location, diagnostics, out modifierErrors);
36
            this.MakeFlags(methodKind, declarationModifiers, returnsVoid: true, isExtensionMethod: false);
P
Pilchie 已提交
37

38
            if (IsExtern)
P
Pilchie 已提交
39
            {
40 41 42 43 44 45
                if (methodKind == MethodKind.Constructor && syntax.Initializer != null)
                {
                    diagnostics.Add(ErrorCode.ERR_ExternHasConstructorInitializer, location, this);
                }

                if (syntax.Body != null)
P
Pilchie 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
                {
                    diagnostics.Add(ErrorCode.ERR_ExternHasBody, location, this);
                }
            }

            var info = ModifierUtils.CheckAccessibility(this.DeclarationModifiers);
            if (info != null)
            {
                diagnostics.Add(info, location);
            }

            if (!modifierErrors)
            {
                this.CheckModifiers(methodKind, location, diagnostics);
            }
        }

        protected override void MethodChecks(DiagnosticBag diagnostics)
        {
65 66
            var syntax = GetSyntax();
            var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntax.SyntaxTree);
67
            ParameterListSyntax parameterList = syntax.ParameterList;
P
Pilchie 已提交
68 69 70 71

            // NOTE: if we asked for the binder for the body of the constructor, we'd risk a stack overflow because
            // we might still be constructing the member list of the containing type.  However, getting the binder
            // for the parameters should be safe.
72
            var bodyBinder = binderFactory.GetBinder(parameterList, syntax, this).WithContainingMemberOrLambda(this);
P
Pilchie 已提交
73 74

            SyntaxToken arglistToken;
E
Evan Hauck 已提交
75
            _lazyParameters = ParameterHelpers.MakeParameters(bodyBinder, this, parameterList, true, out arglistToken, diagnostics, false);
76 77
            _lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword);
            _lazyReturnType = bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax);
P
Pilchie 已提交
78

79
            var location = this.Locations[0];
80
            if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0))
P
Pilchie 已提交
81
            {
82
                diagnostics.Add(ErrorCode.ERR_StaticConstParam, location, this);
P
Pilchie 已提交
83 84
            }

85
            this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics);
P
Pilchie 已提交
86

87
            if (_lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || _lazyParameters.Length > 0 && _lazyParameters[_lazyParameters.Length - 1].IsParams))
P
Pilchie 已提交
88
            {
89
                diagnostics.Add(ErrorCode.ERR_BadVarargs, location);
P
Pilchie 已提交
90 91 92
            }
        }

93 94 95 96 97 98
        internal ConstructorDeclarationSyntax GetSyntax()
        {
            Debug.Assert(syntaxReferenceOpt != null);
            return (ConstructorDeclarationSyntax)syntaxReferenceOpt.GetSyntax();
        }

P
Pilchie 已提交
99 100 101 102 103
        public override bool IsVararg
        {
            get
            {
                LazyMethodChecks();
104
                return _lazyIsVararg;
P
Pilchie 已提交
105 106 107
            }
        }

108 109 110 111
        public override bool IsImplicitlyDeclared
        {
            get
            {
112
                return base.IsImplicitlyDeclared;
113 114 115
            }
        }

P
Pilchie 已提交
116 117 118 119
        internal override int ParameterCount
        {
            get
            {
120
                if (!_lazyParameters.IsDefault)
121
                {
122
                    return _lazyParameters.Length;
123 124
                }

125
                return GetSyntax().ParameterList.ParameterCount;
P
Pilchie 已提交
126 127 128 129 130 131 132 133
            }
        }

        public override ImmutableArray<ParameterSymbol> Parameters
        {
            get
            {
                LazyMethodChecks();
134
                return _lazyParameters;
P
Pilchie 已提交
135 136 137 138 139 140 141 142
            }
        }

        public override ImmutableArray<TypeParameterSymbol> TypeParameters
        {
            get { return ImmutableArray<TypeParameterSymbol>.Empty; }
        }

143 144 145 146 147
        internal override RefKind RefKind
        {
            get { return RefKind.None; }
        }

P
Pilchie 已提交
148 149 150 151 152
        public override TypeSymbol ReturnType
        {
            get
            {
                LazyMethodChecks();
153
                return _lazyReturnType;
P
Pilchie 已提交
154 155 156 157 158 159 160 161
            }
        }

        private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, MethodKind methodKind, Location location, DiagnosticBag diagnostics, out bool modifierErrors)
        {
            var defaultAccess = (methodKind == MethodKind.StaticConstructor) ? DeclarationModifiers.None : DeclarationModifiers.Private;

            // Check that the set of modifiers is allowed
162
            const DeclarationModifiers allowedModifiers =
P
Pilchie 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
                DeclarationModifiers.AccessibilityMask |
                DeclarationModifiers.Static |
                DeclarationModifiers.Extern |
                DeclarationModifiers.Unsafe;

            var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors);

            this.CheckUnsafeModifier(mods, diagnostics);

            if (methodKind == MethodKind.StaticConstructor)
            {
                if ((mods & DeclarationModifiers.AccessibilityMask) != 0)
                {
                    diagnostics.Add(ErrorCode.ERR_StaticConstructorWithAccessModifiers, location, this);
                    mods = mods & ~DeclarationModifiers.AccessibilityMask;
                    modifierErrors = true;
                }

                mods |= DeclarationModifiers.Private; // we mark static constructors private in the symbol table
            }

            return mods;
        }

        private void CheckModifiers(MethodKind methodKind, Location location, DiagnosticBag diagnostics)
        {
189
            if (bodySyntaxReferenceOpt == null && !IsExtern)
P
Pilchie 已提交
190 191 192
            {
                diagnostics.Add(ErrorCode.ERR_ConcreteMissingBody, location, this);
            }
193 194 195 196
            else if (ContainingType.IsSealed && this.DeclaredAccessibility.HasProtected() && !this.IsOverride)
            {
                diagnostics.Add(AccessCheck.GetProtectedMemberInSealedTypeError(ContainingType), location, this);
            }
P
Pilchie 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
            else if (ContainingType.IsStatic && methodKind == MethodKind.Constructor)
            {
                diagnostics.Add(ErrorCode.ERR_ConstructorInStaticClass, location);
            }
        }

        public override string Name
        {
            get { return this.IsStatic ? WellKnownMemberNames.StaticConstructorName : WellKnownMemberNames.InstanceConstructorName; }
        }

        internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations()
        {
            return OneOrMany.Create(((ConstructorDeclarationSyntax)this.SyntaxNode).AttributeLists);
        }

        internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetReturnTypeAttributeDeclarations()
        {
            // constructors can't have return type attributes
            return OneOrMany.Create(default(SyntaxList<AttributeListSyntax>));
        }
218 219 220 221 222 223 224 225

        protected override IAttributeTargetSymbol AttributeOwner
        {
            get
            {
                return base.AttributeOwner;
            }
        }
226 227 228 229 230

        internal override bool IsExpressionBodied
        {
            get { return false; }
        }
231 232 233 234 235

        internal override bool GenerateDebugInfo
        {
            get { return true; }
        }
236

237
        internal override int CalculateLocalSyntaxOffset(int position, SyntaxTree tree)
238
        {
239 240
            Debug.Assert(position >= 0 && tree != null);

241 242
            TextSpan span;

243 244
            // local/lambda/closure defined within the body of the constructor:
            if (tree == bodySyntaxReferenceOpt?.SyntaxTree)
245 246
            {
                span = bodySyntaxReferenceOpt.Span;
247 248 249 250 251 252 253 254 255 256 257 258
                if (span.Contains(position))
                {
                    return position - span.Start;
                }
            }

            var ctorSyntax = GetSyntax();

            // closure in ctor initializer lifting its parameter(s) spans the constructor declaration:
            if (position == ctorSyntax.SpanStart)
            {
                // Use a constant that is distinct from any other syntax offset.
C
Charles Stoner 已提交
259
                // -1 works since a field initializer and a constructor declaration header can't squeeze into a single character.
260 261 262 263 264 265 266 267 268 269 270 271
                return -1;
            }

            // lambdas in ctor initializer:
            int ctorInitializerLength;
            var ctorInitializer = ctorSyntax.Initializer;
            if (tree == ctorInitializer?.SyntaxTree)
            {
                span = ctorInitializer.Span;
                ctorInitializerLength = span.Length;

                if (span.Contains(position))
272
                {
273
                    return -ctorInitializerLength + (position - span.Start);
274 275
                }
            }
276 277 278 279 280 281 282 283 284 285 286 287
            else
            {
                ctorInitializerLength = 0;
            }

            // lambdas in field/property initializers:
            int syntaxOffset;
            var containingType = (SourceNamedTypeSymbol)this.ContainingType;
            if (containingType.TryCalculateSyntaxOffsetOfPositionInInitializer(position, tree, this.IsStatic, ctorInitializerLength, out syntaxOffset))
            {
                return syntaxOffset;
            }
288

C
Charles Stoner 已提交
289
            // we haven't found the constructor part that declares the variable:
290 291
            throw ExceptionUtilities.Unreachable;
        }
P
Pilchie 已提交
292 293
    }
}