SourceConstructorSymbol.cs 12.1 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

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

namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
11
    internal sealed class SourceConstructorSymbol : SourceMemberMethodSymbol
P
Pilchie 已提交
12
    {
13 14 15
        private ImmutableArray<ParameterSymbol> _lazyParameters;
        private TypeSymbol _lazyReturnType;
        private bool _lazyIsVararg;
16
        private readonly bool _isExpressionBodied;
17

P
Pilchie 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
        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) :
33
            base(containingType, syntax.GetReference(), syntax.Body?.GetReference() ?? syntax.ExpressionBody?.GetReference(), ImmutableArray.Create(location))
P
Pilchie 已提交
34 35 36
        {
            bool modifierErrors;
            var declarationModifiers = this.MakeModifiers(syntax.Modifiers, methodKind, location, diagnostics, out modifierErrors);
37
            this.MakeFlags(methodKind, declarationModifiers, returnsVoid: true, isExtensionMethod: false);
P
Pilchie 已提交
38

39 40 41 42 43 44
            if (syntax.Identifier.ValueText != containingType.Name)
            {
                // This is probably a method declaration with the type missing.
                diagnostics.Add(ErrorCode.ERR_MemberNeedsType, location);
            }

45 46 47
            bool hasBlockBody = syntax.Body != null;
            _isExpressionBodied = !hasBlockBody && syntax.ExpressionBody != null;

48
            if (IsExtern)
P
Pilchie 已提交
49
            {
50 51 52 53 54
                if (methodKind == MethodKind.Constructor && syntax.Initializer != null)
                {
                    diagnostics.Add(ErrorCode.ERR_ExternHasConstructorInitializer, location, this);
                }

55
                if (hasBlockBody || _isExpressionBodied)
P
Pilchie 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
                {
                    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);
            }
71 72 73

            CheckForBlockAndExpressionBody(
                syntax.Body, syntax.ExpressionBody, syntax, diagnostics);
P
Pilchie 已提交
74 75 76 77
        }

        protected override void MethodChecks(DiagnosticBag diagnostics)
        {
78 79
            var syntax = GetSyntax();
            var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntax.SyntaxTree);
80
            ParameterListSyntax parameterList = syntax.ParameterList;
P
Pilchie 已提交
81 82 83 84

            // 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.
85
            var bodyBinder = binderFactory.GetBinder(parameterList, syntax, this).WithContainingMemberOrLambda(this);
P
Pilchie 已提交
86 87

            SyntaxToken arglistToken;
88
            _lazyParameters = ParameterHelpers.MakeParameters(
89 90 91
                bodyBinder, this, parameterList, out arglistToken,
                allowRefOrOut: true,
                allowThis: false,
92
                addRefReadOnlyModifier: false,
93 94
                diagnostics: diagnostics);

95 96
            _lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword);
            _lazyReturnType = bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax);
P
Pilchie 已提交
97

98
            var location = this.Locations[0];
99
            if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0))
P
Pilchie 已提交
100
            {
101
                diagnostics.Add(ErrorCode.ERR_StaticConstParam, location, this);
P
Pilchie 已提交
102 103
            }

104
            this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics);
P
Pilchie 已提交
105

106
            if (_lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || _lazyParameters.Length > 0 && _lazyParameters[_lazyParameters.Length - 1].IsParams))
P
Pilchie 已提交
107
            {
108
                diagnostics.Add(ErrorCode.ERR_BadVarargs, location);
P
Pilchie 已提交
109 110 111
            }
        }

112 113 114 115 116 117 118
        internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics)
        {
            base.AfterAddingTypeMembersChecks(conversions, diagnostics);

            ParameterHelpers.EnsureIsReadOnlyAttributeExists(Parameters, diagnostics, modifyCompilationForRefReadOnly: true);
        }

119 120 121 122 123 124
        internal ConstructorDeclarationSyntax GetSyntax()
        {
            Debug.Assert(syntaxReferenceOpt != null);
            return (ConstructorDeclarationSyntax)syntaxReferenceOpt.GetSyntax();
        }

P
Pilchie 已提交
125 126 127 128 129
        public override bool IsVararg
        {
            get
            {
                LazyMethodChecks();
130
                return _lazyIsVararg;
P
Pilchie 已提交
131 132 133
            }
        }

134 135 136 137
        public override bool IsImplicitlyDeclared
        {
            get
            {
138
                return base.IsImplicitlyDeclared;
139 140 141
            }
        }

P
Pilchie 已提交
142 143 144 145
        internal override int ParameterCount
        {
            get
            {
146
                if (!_lazyParameters.IsDefault)
147
                {
148
                    return _lazyParameters.Length;
149 150
                }

151
                return GetSyntax().ParameterList.ParameterCount;
P
Pilchie 已提交
152 153 154 155 156 157 158 159
            }
        }

        public override ImmutableArray<ParameterSymbol> Parameters
        {
            get
            {
                LazyMethodChecks();
160
                return _lazyParameters;
P
Pilchie 已提交
161 162 163 164 165 166 167 168
            }
        }

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

169 170 171
        public override ImmutableArray<TypeParameterConstraintClause> TypeParameterConstraintClauses
            => ImmutableArray<TypeParameterConstraintClause>.Empty;

172
        public override RefKind RefKind
173 174 175 176
        {
            get { return RefKind.None; }
        }

P
Pilchie 已提交
177 178 179 180 181
        public override TypeSymbol ReturnType
        {
            get
            {
                LazyMethodChecks();
182
                return _lazyReturnType;
P
Pilchie 已提交
183 184 185 186 187 188 189 190
            }
        }

        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
191
            const DeclarationModifiers allowedModifiers =
P
Pilchie 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
                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)
        {
218
            if (bodySyntaxReferenceOpt == null && !IsExtern)
P
Pilchie 已提交
219 220 221
            {
                diagnostics.Add(ErrorCode.ERR_ConcreteMissingBody, location, this);
            }
222 223 224 225
            else if (ContainingType.IsSealed && this.DeclaredAccessibility.HasProtected() && !this.IsOverride)
            {
                diagnostics.Add(AccessCheck.GetProtectedMemberInSealedTypeError(ContainingType), location, this);
            }
P
Pilchie 已提交
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
            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>));
        }
247 248 249 250 251 252 253 254

        protected override IAttributeTargetSymbol AttributeOwner
        {
            get
            {
                return base.AttributeOwner;
            }
        }
255 256 257

        internal override bool IsExpressionBodied
        {
258 259 260 261
            get
            {
                return _isExpressionBodied;
            }
262
        }
263 264 265 266 267

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

269
        internal override int CalculateLocalSyntaxOffset(int position, SyntaxTree tree)
270
        {
271 272
            Debug.Assert(position >= 0 && tree != null);

273 274
            TextSpan span;

275 276
            // local/lambda/closure defined within the body of the constructor:
            if (tree == bodySyntaxReferenceOpt?.SyntaxTree)
277 278
            {
                span = bodySyntaxReferenceOpt.Span;
279 280 281 282 283 284 285 286 287 288 289 290
                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 已提交
291
                // -1 works since a field initializer and a constructor declaration header can't squeeze into a single character.
292 293 294 295 296 297 298 299 300 301 302 303
                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))
304
                {
305
                    return -ctorInitializerLength + (position - span.Start);
306 307
                }
            }
308 309 310 311 312 313 314 315 316 317 318 319
            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;
            }
320

C
Charles Stoner 已提交
321
            // we haven't found the constructor part that declares the variable:
322 323
            throw ExceptionUtilities.Unreachable;
        }
P
Pilchie 已提交
324 325
    }
}