Example #1
0
        public ImmutableArray <Diagnostic> Diagnostics => _diagnostics != null?_diagnostics.ToImmutableArray() : ImmutableArray <Diagnostic> .Empty; // Save an allocation if no errors were found

        public void Error(Span span, ErrorInfo info, params string[] argsOpt)
        {
            if (_diagnostics == null)
            {
                _diagnostics = new List <Diagnostic>();
            }

            _diagnostics.Add(DiagnosticBagExtensions.ParserDiagnostic(_syntaxTree, span, info, argsOpt));
        }
        /// <summary>
        /// Collects declaration diagnostics.
        /// </summary>
        internal void GetDiagnostics(DiagnosticBag diagnostic)
        {
            // check functions duplicity
            var funcs = this.Functions;

            if (funcs.Length > 1)
            {
                var set = new HashSet <QualifiedName>();

                // handle unconditionally declared functions:
                foreach (var f in funcs)
                {
                    if (f.IsConditional)
                    {
                        continue;
                    }

                    if (!set.Add(f.QualifiedName))
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(_syntaxTree, ((FunctionDecl)f.Syntax).HeadingSpan, Devsense.PHP.Errors.FatalErrors.FunctionRedeclared, f.QualifiedName.ToString()));
                    }
                }

                //// handle conditionally declared functions: // NOTE: commented since we should allow to compile it
                //foreach (var f in funcs.Where(f => f.IsConditional))
                //{
                //    if (set.Contains(f.QualifiedName))  // does not make sense to declare function if it is declared already unconditionally
                //    {
                //        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(_syntaxTree, ((FunctionDecl)f.Syntax).HeadingSpan, Devsense.PHP.Errors.FatalErrors.FunctionRedeclared, f.PhpName));
                //    }
                //}
            }

            // check class/interface duplicity:
            var types = this.ContainedTypes;

            if (types.Count > 1)
            {
                var set = new HashSet <QualifiedName>();
                foreach (var t in types)
                {
                    if (t.Syntax.IsConditional)
                    {
                        continue;
                    }

                    if (!set.Add(t.FullName))
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(_syntaxTree, t.Syntax.HeadingSpan, Devsense.PHP.Errors.FatalErrors.TypeRedeclared, t.FullName.ToString()));
                    }
                }
            }
        }
 internal void ValidateReferences(CommonCompilation compilation, DiagnosticBag diagnostics)
 {
     foreach (AssemblyIdentity identity in compilation.ReferencedAssemblyNames)
     {
         if (CommonScriptEngine.IsReservedAssemblyName(identity))
         {
             DiagnosticBagExtensions.Add(diagnostics, ErrorCode.ERR_ReservedAssemblyName, (Location)null, new object[1]
             {
                 (object)identity.GetDisplayName(false)
             });
         }
     }
 }
Example #4
0
        public ImmutableArray <Diagnostic> Diagnostics => _diagnostics != null?_diagnostics.ToImmutableArray() : ImmutableArray <Diagnostic> .Empty; // Save an allocation if no errors were found

        public void Error(Span span, ErrorInfo info, params string[] argsOpt)
        {
            if (info == FatalErrors.ParentAccessedInParentlessClass)
            {
                // ignore PHP2070: we'll handle it more precisely, also we might recover from it
                // otherwise we'll report it again in our diagnostics
                return;
            }

            if (_diagnostics == null)
            {
                _diagnostics = new List <Diagnostic>();
            }

            _diagnostics.Add(DiagnosticBagExtensions.ParserDiagnostic(_syntaxTree, span, info, argsOpt));
        }
Example #5
0
        /// <summary>
        /// Collects declaration diagnostics.
        /// </summary>
        public virtual void GetDiagnostics(DiagnosticBag diagnostic)
        {
            // check mandatory behind and optional parameter
            bool foundopt = false;

            foreach (var p in SyntaxSignature.FormalParams)
            {
                if (p.InitValue == null)
                {
                    if (foundopt && !p.IsVariadic)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, p.Span, Devsense.PHP.Errors.Warnings.MandatoryBehindOptionalParam, "$" + p.Name.Name.Value));
                    }
                }
                else
                {
                    foundopt = true;
                }
            }
        }
Example #6
0
 void Add(Devsense.PHP.Text.Span span, Devsense.PHP.Errors.ErrorInfo err, params string[] args)
 {
     _diagnostics.Add(DiagnosticBagExtensions.ParserDiagnostic(_routine, span, err, args));
 }
Example #7
0
        public override void GetDiagnostics(DiagnosticBag diagnostic)
        {
            var name = _syntax.Name.Name;

            // diagnostics:
            if (name.Value.StartsWith("__", StringComparison.Ordinal))
            {
                // magic methods:
                if (name.IsConstructName) // __construct()
                {
                    if (IsStatic)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Errors.ConstructCannotBeStatic, _type.FullName.ToString()));
                    }
                    if (_syntax.ReturnType != null)
                    {
                        // {0} cannot declare a return type
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_CannotDeclareReturnType, "Constructor " + _type.FullName.ToString(name, false));
                    }
                }
                else if (name.IsDestructName)    // __destruct()
                {
                    if (_syntax.Signature.FormalParams.Length != 0)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Errors.DestructCannotTakeArguments, _type.FullName.ToString()));
                    }
                    if (IsStatic)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Errors.DestructCannotBeStatic, _type.FullName.ToString()));
                    }
                    if (_syntax.ReturnType != null)
                    {
                        // {0} cannot declare a return type
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_CannotDeclareReturnType, "Destructor " + _type.FullName.ToString(name, false));
                    }
                }
                else if (name.IsToStringName)   // __tostring()
                {
                    if ((IsStatic || (_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) != PhpMemberAttributes.Public))
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Warnings.MagicMethodMustBePublicNonStatic, name.Value));
                    }

                    if (_syntax.Signature.FormalParams.Length != 0)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Errors.MethodCannotTakeArguments, _type.FullName.ToString(), name.Value));
                    }
                }
                else if (name.IsCloneName)  // __clone()
                {
                    if (IsStatic)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Errors.CloneCannotBeStatic, _type.FullName.ToString()));
                    }
                    if (_syntax.Signature.FormalParams.Length != 0)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Errors.CloneCannotTakeArguments, _type.FullName.ToString()));
                    }
                    if (_syntax.ReturnType != null)
                    {
                        // {0} cannot declare a return type
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_CannotDeclareReturnType, _type.FullName.ToString(name, false));
                    }
                }
                else if (name.IsCallName) // __call($name, $args)
                {
                    if (IsStatic || (_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) != PhpMemberAttributes.Public)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Warnings.MagicMethodMustBePublicNonStatic, name.Value));
                    }
                    if (_syntax.Signature.FormalParams.Length != 2)
                    {
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_MustTakeArgs, "Method", _type.FullName.ToString(name, false), 2);
                    }
                }
                else if (name.IsCallStaticName) // __callstatic($name, $args)
                {
                    if (!IsStatic || (_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) != PhpMemberAttributes.Public)
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Warnings.CallStatMustBePublicStatic));
                    }
                    if (_syntax.Signature.FormalParams.Length != 2)
                    {
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_MustTakeArgs, "Method", _type.FullName.ToString(name, false), 2);
                    }
                }
                else if (name == Devsense.PHP.Syntax.Name.SpecialMethodNames.Set)   // __set($name, $value)
                {
                    if ((IsStatic || (_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) != PhpMemberAttributes.Public))
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Warnings.MagicMethodMustBePublicNonStatic, name.Value));
                    }
                    if (_syntax.Signature.FormalParams.Length != 2)
                    {
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_MustTakeArgs, "Method", _type.FullName.ToString(name, false), 2);
                    }
                }
                else if (name == Devsense.PHP.Syntax.Name.SpecialMethodNames.Get)   // __get($name)
                {
                    if ((IsStatic || (_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) != PhpMemberAttributes.Public))
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Warnings.MagicMethodMustBePublicNonStatic, name.Value));
                    }
                    if (_syntax.Signature.FormalParams.Length != 1)
                    {
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_MustTakeArgs, "Method", _type.FullName.ToString(name, false), 1);
                    }
                }
                else if (name == Devsense.PHP.Syntax.Name.SpecialMethodNames.Isset)   // __isset($name)
                {
                    if ((IsStatic || (_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) != PhpMemberAttributes.Public))
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Warnings.MagicMethodMustBePublicNonStatic, name.Value));
                    }
                    if (_syntax.Signature.FormalParams.Length != 1)
                    {
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_MustTakeArgs, "Method", _type.FullName.ToString(name, false), 1);
                    }
                }
                else if (name == Devsense.PHP.Syntax.Name.SpecialMethodNames.Unset)   // __unset($name)
                {
                    if ((IsStatic || (_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) != PhpMemberAttributes.Public))
                    {
                        diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.ParametersSpan, Devsense.PHP.Errors.Warnings.MagicMethodMustBePublicNonStatic, name.Value));
                    }
                    if (_syntax.Signature.FormalParams.Length != 1)
                    {
                        diagnostic.Add(this, _syntax.ReturnType.Span.ToTextSpan(), Errors.ErrorCode.ERR_MustTakeArgs, "Method", _type.FullName.ToString(name, false), 1);
                    }
                }
                // ...
            }

            if (_syntax.Modifiers.IsAbstract())
            {
                // abstract member in non-abstract class
                if ((_type.Syntax.MemberAttributes & (PhpMemberAttributes.Abstract | PhpMemberAttributes.Trait)) == 0)  // not abstract nor trait
                {
                    // TODO: ERR_AbstractMethodInNonAbstractClass
                }

                // abstract private
                if ((_syntax.Modifiers & PhpMemberAttributes.VisibilityMask) == PhpMemberAttributes.Private)
                {
                    diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.HeadingSpan, Devsense.PHP.Errors.Errors.AbstractPrivateMethodDeclared));
                }

                // abstract final
                if ((_syntax.Modifiers & PhpMemberAttributes.Final) != 0)
                {
                    diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.HeadingSpan, Devsense.PHP.Errors.Errors.AbstractFinalMethodDeclared));
                }

                // abstract method with body
                if (_syntax.Body != null)
                {
                    diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this,
                                                                            _syntax.HeadingSpan,
                                                                            _type.IsInterface
                            ? Devsense.PHP.Errors.Errors.InterfaceMethodWithBody
                            : Devsense.PHP.Errors.Errors.AbstractMethodWithBody,
                                                                            _type.FullName.ToString(), name.Value));
                }
            }
            else
            {
                if (_syntax.Body == null && !_type.IsInterface)
                {
                    diagnostic.Add(DiagnosticBagExtensions.ParserDiagnostic(this, _syntax.HeadingSpan, Devsense.PHP.Errors.Errors.NonAbstractMethodWithoutBody,
                                                                            _type.FullName.ToString(), name.Value));
                }
            }

            //
            base.GetDiagnostics(diagnostic);
        }
Example #8
0
        /// <summary>
        /// Matches all methods that can be overriden (non-static, public or protected, abstract or virtual)
        /// within this type sub-tree (this type, its base and interfaces)
        /// with its override.
        /// Methods without an override are either abstract or a ghost stup has to be synthesized.
        /// </summary>
        /// <param name="diagnostics"></param>
        internal OverrideInfo[] ResolveOverrides(DiagnosticBag diagnostics)
        {
            if (_lazyOverrides != null)
            {
                // already resolved
                return(_lazyOverrides);
            }

            // inherit abstracts from base type
            // ignoring System.Object (we don't override its methods from PHP)
            var overrides = new List <OverrideInfo>();

            if (BaseType != null && BaseType.SpecialType != SpecialType.System_Object)
            {
                overrides.AddRange(BaseType.ResolveOverrides(diagnostics));
            }

            // collect this type declared methods including synthesized methods
            var members = this.GetMembers();

            // resolve overrides of inherited members
            for (int i = 0; i < overrides.Count; i++)
            {
                var m = overrides[i];
                if (m.HasOverride == false)
                {
                    // update override info of the inherited member
                    overrides[i] = new OverrideInfo(m.Method, OverrideHelper.ResolveMethodImplementation(m.Method, members));
                }
                else
                {
                    // clear the interface flag of inherited override info
                    m.ImplementsInterface = false;
                    overrides[i]          = m;
                }
            }

            // resolve overrides of interface methods
            foreach (var iface in Interfaces)
            {
                // skip interfaces implemented by base type or other interfaces,
                // we don't want to add redundant override entries:
                if ((BaseType != null && BaseType.ImplementsInterface(iface)) ||
                    Interfaces.Any(x => x != iface && x.ImplementsInterface(iface)))
                {
                    // iface is already handled within overrides => skip
                    // note: iface can be ignored in metadata at all actually
                    continue;
                }

                var iface_abstracts = iface.ResolveOverrides(diagnostics);
                foreach (var m in iface_abstracts)
                {
                    if (BaseType != null && m.Method.ContainingType != iface && BaseType.ImplementsInterface(m.Method.ContainingType))
                    {
                        // iface {m.Method.ContainingType} already handled within overrides => skip
                        continue;
                    }

                    // ignore interface method that is already implemented:
                    if (overrides.Any(o => OverrideHelper.SignaturesMatch(o.Method, m.Method)))
                    {
                        continue;
                    }

                    // add interface member,
                    // resolve its override
                    overrides.Add(new OverrideInfo(m.Method, this.IsInterface ? null : OverrideHelper.ResolveMethodImplementation(m.Method, this))
                    {
                        ImplementsInterface = true
                    });
                }
            }

            // add overrideable routines from this type
            foreach (var s in members)
            {
                if (s is MethodSymbol m && m.IsOverrideable())
                {
                    overrides.Add(new OverrideInfo(m));
                }
            }

            // handle unresolved abstracts
            for (int i = 0; i < overrides.Count; i++)
            {
                var m = overrides[i];

                if (m.IsUnresolvedAbstract && this is SourceTypeSymbol srct && !this.IsInterface)
                {
                    if (!this.IsAbstract)
                    {
                        // Class '{0}' doesn't implement abstract method {1}::{2}()
                        diagnostics.Add(DiagnosticBagExtensions.ParserDiagnostic(srct.ContainingFile.SyntaxTree, srct.Syntax.HeadingSpan,
                                                                                 Devsense.PHP.Errors.Errors.AbstractMethodNotImplemented,
                                                                                 srct.FullName.ToString(), ((IPhpTypeSymbol)m.Method.ContainingType).FullName.ToString(), m.RoutineName));
                    }
                    else if (m.ImplementsInterface /*&& this.IsAbstract*/)
                    {
                        m.ImplementsInterface = false;

                        var method = m.Method;

                        Debug.Assert(!method.IsStatic);
                        Debug.Assert(method.DeclaredAccessibility != Accessibility.Private);
                        Debug.Assert(method.ContainingType.IsInterface);

                        // Template: abstract function {name}({parameters})
                        var ghost = new SynthesizedMethodSymbol(this, method.RoutineName,
                                                                isstatic: false, isvirtual: true, isabstract: true, isfinal: false,
                                                                returnType: method.ReturnType,
                                                                accessibility: method.DeclaredAccessibility);

                        ghost.SetParameters(SynthesizedParameterSymbol.Create(ghost, method.Parameters));
                        //module.SynthesizedManager.AddMethod(this, ghost); // will be added to synthesized manager by FinalizeMethodTable

                        m.Method = ghost;   // replace the interface method with synthesized abstract method

                        // update overrides
                        overrides[i] = m;
                    }
                }
            }

            // cache & return
            return(_lazyOverrides = overrides.ToArray());
        }
Example #9
0
        /// <summary>
        /// Matches all methods that can be overriden (non-static, public or protected, abstract or virtual)
        /// within this type sub-tree (this type, its base and interfaces)
        /// with its override.
        /// Methods without an override are either abstract or a ghost stup has to be synthesized.
        /// </summary>
        /// <param name="diagnostics"></param>
        internal OverrideInfo[] ResolveOverrides(DiagnosticBag diagnostics)
        {
            if (_lazyOverrides != null)
            {
                // already resolved
                return(_lazyOverrides);
            }

            // TODO: ignore System.Object ?

            // inherit abstracts from base type
            var overrides = new List <OverrideInfo>();

            if (BaseType != null)
            {
                overrides.AddRange(BaseType.ResolveOverrides(diagnostics));
            }

            // collect this type declared methods including synthesized methods
            var methods       = this.GetMembers().OfType <MethodSymbol>();
            var methodslookup = methods.Where(OverrideHelper.CanOverride).ToLookup(m => m.RoutineName, StringComparer.OrdinalIgnoreCase);

            // resolve overrides of inherited members
            for (int i = 0; i < overrides.Count; i++)
            {
                var m = overrides[i];
                if (m.HasOverride == false)
                {
                    // update override info of the inherited member
                    overrides[i] = new OverrideInfo(m.Method, OverrideHelper.ResolveMethodImplementation(m.Method, methodslookup[m.RoutineName]));
                }
                else
                {
                    // clear the interface flag of inherited override info
                    m.ImplementsInterface = false;
                    overrides[i]          = m;
                }
            }

            // resolve overrides of interface methods
            foreach (var iface in Interfaces)
            {
                // skip interfaces implemented by base type or other interfaces,
                // we don't want to add redundant override entries:
                if ((BaseType != null && BaseType.ImplementsInterface(iface)) ||
                    Interfaces.Any(x => x != iface && x.ImplementsInterface(iface)))
                {
                    // iface is already handled within overrides => skip
                    // note: iface can be ignored in metadata at all actually
                    continue;
                }

                var iface_abstracts = iface.ResolveOverrides(diagnostics);
                foreach (var m in iface_abstracts)
                {
                    if (BaseType != null && m.Method.ContainingType != iface && BaseType.ImplementsInterface(m.Method.ContainingType))
                    {
                        // iface {m.Method.ContainingType} already handled within overrides => skip
                        continue;
                    }

                    // ignore interface method that is already implemented:
                    if (overrides.Any(o => OverrideHelper.SignaturesMatch(o.Method, m.Method)))
                    {
                        continue;
                    }

                    // add interface member,
                    // resolve its override
                    overrides.Add(new OverrideInfo(m.Method, this.IsInterface ? null : OverrideHelper.ResolveMethodImplementation(m.Method, this))
                    {
                        ImplementsInterface = true
                    });
                }
            }

            // add overrideable routines from this type
            foreach (var m in methods)
            {
                if (m.IsOverrideable())
                {
                    overrides.Add(new OverrideInfo(m));
                }
            }

            // report unresolved abstracts
            if (!this.IsAbstract && !this.IsInterface && this is SourceTypeSymbol srct)
            {
                foreach (var m in overrides)
                {
                    if (m.IsUnresolvedAbstract)
                    {
                        // Class '{0}' doesn't implement abstract method {1}::{2}()
                        diagnostics.Add(DiagnosticBagExtensions.ParserDiagnostic(srct.ContainingFile.SyntaxTree, srct.Syntax.HeadingSpan,
                                                                                 Devsense.PHP.Errors.Errors.AbstractMethodNotImplemented,
                                                                                 srct.FullName.ToString(), ((IPhpTypeSymbol)m.Method.ContainingType).FullName.ToString(), m.RoutineName));
                    }
                }
            }

            // cache & return
            return(_lazyOverrides = overrides.ToArray());
        }