Exemple #1
0
        /// <summary>
        ///   This function tells whether one of our base classes implements
        ///   the given method (which turns out, it is valid to have an interface
        ///   implementation in a base
        /// </summary>
        bool BaseImplements(TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
        {
            base_method = null;
            var base_type = container.BaseType;

            //
            // Setup filter with no return type to give better error message
            // about mismatch at return type when the check bellow rejects them
            //
            var        parameters  = mi.Parameters;
            MethodSpec close_match = null;

            while (true)
            {
                var candidates = MemberCache.FindMembers(base_type, mi.Name, false);
                if (candidates == null)
                {
                    base_method = close_match;
                    return(false);
                }

                MethodSpec similar_candidate = null;
                foreach (var candidate in candidates)
                {
                    if (candidate.Kind != MemberKind.Method)
                    {
                        continue;
                    }

                    if (candidate.Arity != mi.Arity)
                    {
                        continue;
                    }

                    var candidate_param = ((MethodSpec)candidate).Parameters;
                    if (!TypeSpecComparer.Override.IsEqual(parameters.Types, candidate_param.Types))
                    {
                        continue;
                    }

                    bool modifiers_match = true;
                    for (int i = 0; i < parameters.Count; ++i)
                    {
                        //
                        // First check exact ref/out match
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            continue;
                        }

                        modifiers_match = false;

                        //
                        // Different in ref/out only
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            if (similar_candidate == null)
                            {
                                if (!candidate.IsPublic)
                                {
                                    break;
                                }

                                if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, ((MethodSpec)candidate).ReturnType))
                                {
                                    break;
                                }

                                // It's used for ref/out ambiguity overload check
                                similar_candidate = (MethodSpec)candidate;
                            }

                            continue;
                        }

                        similar_candidate = null;
                        break;
                    }

                    if (!modifiers_match)
                    {
                        continue;
                    }

                    //
                    // From this point the candidate is used for detailed error reporting
                    // because it's very close match to what we are looking for
                    //
                    var m = (MethodSpec)candidate;

                    if (!m.IsPublic)
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, m.ReturnType))
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    base_method = m;

                    if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints(container, m, mi))
                    {
                        return(true);
                    }
                }

                if (base_method != null)
                {
                    if (similar_candidate != null)
                    {
                        Report.SymbolRelatedToPreviousError(similar_candidate);
                        Report.SymbolRelatedToPreviousError(mi);
                        Report.SymbolRelatedToPreviousError(container);
                        Report.Warning(1956, 1, ((MemberCore)base_method.MemberDefinition).Location,
                                       "The interface method `{0}' implementation is ambiguous between following methods: `{1}' and `{2}' in type `{3}'",
                                       mi.GetSignatureForError(), base_method.GetSignatureForError(), similar_candidate.GetSignatureForError(), container.GetSignatureForError());
                    }

                    break;
                }

                base_type = candidates[0].DeclaringType.BaseType;
                if (base_type == null)
                {
                    base_method = close_match;
                    return(false);
                }
            }

            if (!base_method.IsVirtual)
            {
#if STATIC
                var base_builder = base_method.GetMetaInfo() as MethodBuilder;
                if (base_builder != null)
                {
                    //
                    // We can avoid creating a proxy if base_method can be marked 'final virtual'. This can
                    // be done for all methods from compiled assembly
                    //
                    base_builder.__SetAttributes(base_builder.Attributes | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot);
                    return(true);
                }
#endif
                DefineProxy(iface_type, base_method, mi);
            }

            return(true);
        }
Exemple #2
0
        private static MemberSpec FindDocumentedMemberNoNest(
            MemberCore mc, TypeSpec type, string member_name,
            AParametersCollection param_list, DeclSpace ds, out int warning_type,
            string cref, bool warn419, string name_for_error, Report Report)
        {
            warning_type = 0;
//			var filter = new MemberFilter (member_name, 0, MemberKind.All, param_list, null);
            IList <MemberSpec> found = null;

            while (type != null && found == null)
            {
                found = MemberCache.FindMembers(type, member_name, false);
                type  = type.DeclaringType;
            }

            if (found == null)
            {
                return(null);
            }

            if (warn419 && found.Count > 1)
            {
                Report419(mc, name_for_error, found.ToArray(), Report);
            }

            return(found [0]);

/*
 *                      if (param_list == null) {
 *                              // search for fields/events etc.
 *                              mis = TypeManager.MemberLookup (type, null,
 *                                      type, MemberKind.All,
 *                                      BindingRestriction.None,
 *                                      member_name, null);
 *                              mis = FilterOverridenMembersOut (mis);
 *                              if (mis == null || mis.Length == 0)
 *                                      return null;
 *                              if (warn419 && IsAmbiguous (mis))
 *                                      Report419 (mc, name_for_error, mis, Report);
 *                              return mis [0];
 *                      }
 *
 *                      MethodSignature msig = new MethodSignature (member_name, null, param_list);
 *                      mis = FindMethodBase (type,
 *                              BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance,
 *                              msig);
 *
 *                      if (warn419 && mis.Length > 0) {
 *                              if (IsAmbiguous (mis))
 *                                      Report419 (mc, name_for_error, mis, Report);
 *                              return mis [0];
 *                      }
 *
 *                      // search for operators (whose parameters exactly
 *                      // matches with the list) and possibly report CS1581.
 *                      string oper = null;
 *                      string return_type_name = null;
 *                      if (member_name.StartsWith ("implicit operator ")) {
 *                              Operator.GetMetadataName (Operator.OpType.Implicit);
 *                              return_type_name = member_name.Substring (18).Trim (wsChars);
 *                      }
 *                      else if (member_name.StartsWith ("explicit operator ")) {
 *                              oper = Operator.GetMetadataName (Operator.OpType.Explicit);
 *                              return_type_name = member_name.Substring (18).Trim (wsChars);
 *                      }
 *                      else if (member_name.StartsWith ("operator ")) {
 *                              oper = member_name.Substring (9).Trim (wsChars);
 *                              switch (oper) {
 *                              // either unary or binary
 *                              case "+":
 *                                      oper = param_list.Length == 2 ?
 *                                              Operator.GetMetadataName (Operator.OpType.Addition) :
 *                                              Operator.GetMetadataName (Operator.OpType.UnaryPlus);
 *                                      break;
 *                              case "-":
 *                                      oper = param_list.Length == 2 ?
 *                                              Operator.GetMetadataName (Operator.OpType.Subtraction) :
 *                                              Operator.GetMetadataName (Operator.OpType.UnaryNegation);
 *                                      break;
 *                              default:
 *                                      oper = Operator.GetMetadataName (oper);
 *                                      if (oper != null)
 *                                              break;
 *
 *                                      warning_type = 1584;
 *                                      Report.Warning (1020, 1, mc.Location, "Overloadable {0} operator is expected", param_list.Length == 2 ? "binary" : "unary");
 *                                      Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
 *                                              mc.GetSignatureForError (), cref);
 *                                      return null;
 *                              }
 *                      }
 *                      // here we still don't consider return type (to
 *                      // detect CS1581 or CS1002+CS1584).
 *                      msig = new MethodSignature (oper, null, param_list);
 *
 *                      mis = FindMethodBase (type,
 *                              BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance,
 *                              msig);
 *                      if (mis.Length == 0)
 *                              return null; // CS1574
 *                      var mi = mis [0];
 *                      TypeSpec expected = mi is MethodSpec ?
 *                              ((MethodSpec) mi).ReturnType :
 *                              mi is PropertySpec ?
 *                              ((PropertySpec) mi).PropertyType :
 *                              null;
 *                      if (return_type_name != null) {
 *                              TypeSpec returnType = FindDocumentedType (mc, return_type_name, ds, cref, Report);
 *                              if (returnType == null || returnType != expected) {
 *                                      warning_type = 1581;
 *                                      Report.Warning (1581, 1, mc.Location, "Invalid return type in XML comment cref attribute `{0}'", cref);
 *                                      return null;
 *                              }
 *                      }
 *                      return mis [0];
 */
        }
Exemple #3
0
        //
        // Processes "see" or "seealso" elements from cref attribute.
        //
        void HandleXrefCommon(MemberCore mc, XmlElement xref)
        {
            string cref = xref.GetAttribute("cref");

            // when, XmlReader, "if (cref == null)"
            if (!xref.HasAttribute("cref"))
            {
                return;
            }

            // Nothing to be resolved the reference is marked explicitly
            if (cref.Length > 2 && cref [1] == ':')
            {
                return;
            }

            // Additional symbols for < and > are allowed for easier XML typing
            cref = cref.Replace('{', '<').Replace('}', '>');

            var encoding = module.Compiler.Settings.Encoding;
            var s        = new MemoryStream(encoding.GetBytes(cref));

            var source_file = new CompilationSourceFile(doc_module, mc.Location.SourceFile);
            var report      = new Report(doc_module.Compiler, new NullReportPrinter());

            if (session == null)
            {
                session = new ParserSession {
                    UseJayGlobalArrays = true
                }
            }
            ;

            SeekableStreamReader seekable = new SeekableStreamReader(s, encoding, session.StreamReaderBuffer);

            var parser = new CSharpParser(seekable, source_file, report, session);

            ParsedParameters          = null;
            ParsedName                = null;
            ParsedBuiltinType         = null;
            ParsedOperator            = null;
            parser.Lexer.putback_char = Tokenizer.DocumentationXref;
            parser.Lexer.parsing_generic_declaration_doc = true;
            parser.parse();
            if (report.Errors > 0)
            {
                Report.Warning(1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'",
                               mc.GetSignatureForError(), cref);

                xref.SetAttribute("cref", "!:" + cref);
                return;
            }

            MemberSpec          member;
            string              prefix = null;
            FullNamedExpression fne    = null;

            //
            // Try built-in type first because we are using ParsedName as identifier of
            // member names on built-in types
            //
            if (ParsedBuiltinType != null && (ParsedParameters == null || ParsedName != null))
            {
                member = ParsedBuiltinType.Type;
            }
            else
            {
                member = null;
            }

            if (ParsedName != null || ParsedOperator.HasValue)
            {
                TypeSpec type        = null;
                string   member_name = null;

                if (member == null)
                {
                    if (ParsedOperator.HasValue)
                    {
                        type = mc.CurrentType;
                    }
                    else if (ParsedName.Left != null)
                    {
                        fne = ResolveMemberName(mc, ParsedName.Left);
                        if (fne != null)
                        {
                            var ns = fne as NamespaceExpression;
                            if (ns != null)
                            {
                                fne = ns.LookupTypeOrNamespace(mc, ParsedName.Name, ParsedName.Arity, LookupMode.Probing, Location.Null);
                                if (fne != null)
                                {
                                    member = fne.Type;
                                }
                            }
                            else
                            {
                                type = fne.Type;
                            }
                        }
                    }
                    else
                    {
                        fne = ResolveMemberName(mc, ParsedName);
                        if (fne == null)
                        {
                            type = mc.CurrentType;
                        }
                        else if (ParsedParameters == null)
                        {
                            member = fne.Type;
                        }
                        else if (fne.Type.MemberDefinition == mc.CurrentType.MemberDefinition)
                        {
                            member_name = Constructor.ConstructorName;
                            type        = fne.Type;
                        }
                    }
                }
                else
                {
                    type   = (TypeSpec)member;
                    member = null;
                }

                if (ParsedParameters != null)
                {
                    var old_printer = mc.Module.Compiler.Report.SetPrinter(new NullReportPrinter());
                    try {
                        var context = new DocumentationMemberContext(mc, ParsedName ?? MemberName.Null);

                        foreach (var pp in ParsedParameters)
                        {
                            pp.Resolve(context);
                        }
                    } finally {
                        mc.Module.Compiler.Report.SetPrinter(old_printer);
                    }
                }

                if (type != null)
                {
                    if (member_name == null)
                    {
                        member_name = ParsedOperator.HasValue ?
                                      Operator.GetMetadataName(ParsedOperator.Value) : ParsedName.Name;
                    }

                    int parsed_param_count;
                    if (ParsedOperator == Operator.OpType.Explicit || ParsedOperator == Operator.OpType.Implicit)
                    {
                        parsed_param_count = ParsedParameters.Count - 1;
                    }
                    else if (ParsedParameters != null)
                    {
                        parsed_param_count = ParsedParameters.Count;
                    }
                    else
                    {
                        parsed_param_count = 0;
                    }

                    int parameters_match = -1;
                    do
                    {
                        var members = MemberCache.FindMembers(type, member_name, true);
                        if (members != null)
                        {
                            foreach (var m in members)
                            {
                                if (ParsedName != null && m.Arity != ParsedName.Arity)
                                {
                                    continue;
                                }

                                if (ParsedParameters != null)
                                {
                                    IParametersMember pm = m as IParametersMember;
                                    if (pm == null)
                                    {
                                        continue;
                                    }

                                    if (m.Kind == MemberKind.Operator && !ParsedOperator.HasValue)
                                    {
                                        continue;
                                    }

                                    var pm_params = pm.Parameters;

                                    int i;
                                    for (i = 0; i < parsed_param_count; ++i)
                                    {
                                        var pparam = ParsedParameters[i];

                                        if (i >= pm_params.Count || pparam == null || pparam.TypeSpec == null ||
                                            !TypeSpecComparer.Override.IsEqual(pparam.TypeSpec, pm_params.Types[i]) ||
                                            (pparam.Modifier & Parameter.Modifier.RefOutMask) != (pm_params.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                                        {
                                            if (i > parameters_match)
                                            {
                                                parameters_match = i;
                                            }

                                            i = -1;
                                            break;
                                        }
                                    }

                                    if (i < 0)
                                    {
                                        continue;
                                    }

                                    if (ParsedOperator == Operator.OpType.Explicit || ParsedOperator == Operator.OpType.Implicit)
                                    {
                                        if (pm.MemberType != ParsedParameters[parsed_param_count].TypeSpec)
                                        {
                                            parameters_match = parsed_param_count + 1;
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        if (parsed_param_count != pm_params.Count)
                                        {
                                            continue;
                                        }
                                    }
                                }

                                if (member != null)
                                {
                                    Report.Warning(419, 3, mc.Location,
                                                   "Ambiguous reference in cref attribute `{0}'. Assuming `{1}' but other overloads including `{2}' have also matched",
                                                   cref, member.GetSignatureForError(), m.GetSignatureForError());

                                    break;
                                }

                                member = m;
                            }
                        }

                        // Continue with parent type for nested types
                        if (member == null)
                        {
                            type = type.DeclaringType;
                        }
                        else
                        {
                            type = null;
                        }
                    } while (type != null);

                    if (member == null && parameters_match >= 0)
                    {
                        for (int i = parameters_match; i < parsed_param_count; ++i)
                        {
                            Report.Warning(1580, 1, mc.Location, "Invalid type for parameter `{0}' in XML comment cref attribute `{1}'",
                                           (i + 1).ToString(), cref);
                        }

                        if (parameters_match == parsed_param_count + 1)
                        {
                            Report.Warning(1581, 1, mc.Location, "Invalid return type in XML comment cref attribute `{0}'", cref);
                        }
                    }
                }
            }

            if (member == null)
            {
                Report.Warning(1574, 1, mc.Location, "XML comment on `{0}' has cref attribute `{1}' that could not be resolved",
                               mc.GetSignatureForError(), cref);
                cref = "!:" + cref;
            }
            else if (member == InternalType.Namespace)
            {
                cref = "N:" + fne.GetSignatureForError();
            }
            else
            {
                prefix = GetMemberDocHead(member);
                cref   = prefix + member.GetSignatureForDocumentation();
            }

            xref.SetAttribute("cref", cref);
        }
Exemple #4
0
        /// <summary>
        ///   This function tells whether one of our base classes implements
        ///   the given method (which turns out, it is valid to have an interface
        ///   implementation in a base
        /// </summary>
        bool BaseImplements(TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
        {
            base_method = null;
            bool     base_can_implement = true;
            TypeSpec lookup_type;

            //
            // Special handling for properties/indexers which cannot have accessors
            // implementing an interface found in different types (e.g. current and base)
            //
            if (mi.IsAccessor && container.Interfaces != null)
            {
                bool new_implementation = false;
                foreach (var iface in container.Interfaces)
                {
                    if (TypeSpecComparer.IsEqual(iface, iface_type))
                    {
                        new_implementation = true;
                        break;
                    }
                }

                if (new_implementation)
                {
                    MemberFilter filter;
                    if (mi.Parameters.Count > 1)
                    {
                        var indexer_params = mi.Name [0] == 'g' ? mi.Parameters : IndexerSpec.CreateParametersFromSetter(mi, mi.Parameters.Count - 1);
                        filter = new MemberFilter(MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, indexer_params, null);
                    }
                    else
                    {
                        var pname = mi.Name.Substring(4);
                        filter = MemberFilter.Property(pname, null);
                    }

                    var prop = MemberCache.FindMember(container.CurrentType, filter, BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly);
                    if (prop != null && (prop.Modifiers & Modifiers.NEW) != 0)
                    {
                        base_can_implement = false;
                    }
                }
            }

            if (base_can_implement)
            {
                lookup_type = container.BaseType;

                if (lookup_type.ImplementsInterface(iface_type, false))
                {
                    return(true);
                }
            }
            else
            {
                lookup_type = container.CurrentType;
            }

            //
            // Setup filter with no return type to give better error message
            // about mismatch at return type when the check bellow rejects them
            //
            var        parameters  = mi.Parameters;
            MethodSpec close_match = null;

            while (true)
            {
                var candidates = MemberCache.FindMembers(lookup_type, mi.Name, !base_can_implement);
                if (candidates == null)
                {
                    base_method = close_match;
                    return(false);
                }

                MethodSpec similar_candidate = null;
                foreach (var candidate in candidates)
                {
                    if (candidate.Kind != MemberKind.Method)
                    {
                        continue;
                    }

                    if (candidate.Arity != mi.Arity)
                    {
                        continue;
                    }

                    var candidate_param = ((MethodSpec)candidate).Parameters;
                    if (!TypeSpecComparer.Override.IsEqual(parameters.Types, candidate_param.Types))
                    {
                        continue;
                    }

                    bool modifiers_match = true;
                    for (int i = 0; i < parameters.Count; ++i)
                    {
                        //
                        // First check exact ref/out match
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            continue;
                        }

                        modifiers_match = false;

                        //
                        // Different in ref/out only
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            if (similar_candidate == null)
                            {
                                if (!candidate.IsPublic)
                                {
                                    break;
                                }

                                if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, ((MethodSpec)candidate).ReturnType))
                                {
                                    break;
                                }

                                // It's used for ref/out ambiguity overload check
                                similar_candidate = (MethodSpec)candidate;
                            }

                            continue;
                        }

                        similar_candidate = null;
                        break;
                    }

                    if (!modifiers_match)
                    {
                        continue;
                    }

                    //
                    // From this point the candidate is used for detailed error reporting
                    // because it's very close match to what we are looking for
                    //
                    var m = (MethodSpec)candidate;

                    if (!m.IsPublic)
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, m.ReturnType))
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    base_method = m;

                    if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints(container, m, mi))
                    {
                        return(true);
                    }
                }

                if (base_method != null)
                {
                    if (similar_candidate != null)
                    {
                        Report.SymbolRelatedToPreviousError(similar_candidate);
                        Report.SymbolRelatedToPreviousError(mi);
                        Report.SymbolRelatedToPreviousError(container);
                        Report.Warning(1956, 1, ((MemberCore)base_method.MemberDefinition).Location,
                                       "The interface method `{0}' implementation is ambiguous between following methods: `{1}' and `{2}' in type `{3}'",
                                       mi.GetSignatureForError(), base_method.GetSignatureForError(), similar_candidate.GetSignatureForError(), container.GetSignatureForError());
                    }

                    break;
                }

                if (!base_can_implement)
                {
                    return(false);
                }

                lookup_type = candidates[0].DeclaringType.BaseType;
                if (lookup_type == null)
                {
                    base_method = close_match;
                    return(false);
                }
            }

            if (!base_method.IsVirtual)
            {
#if STATIC
                var base_builder = base_method.GetMetaInfo() as MethodBuilder;
                if (base_builder != null)
                {
                    //
                    // We can avoid creating a proxy if base_method can be marked 'final virtual'. This can
                    // be done for all methods from compiled assembly
                    //
                    base_builder.__SetAttributes(base_builder.Attributes | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot);
                    return(true);
                }
#endif
                DefineProxy(iface_type, base_method, mi);
            }

            return(true);
        }