📄 check.java
字号:
cannotOverride(m, other), protectionString(other.flags())); return; } Type mt = types.memberType(origin.type, m); Type ot = types.memberType(origin.type, other); // Error if overriding result type is different // (or, in the case of generics mode, not a subtype) of // overridden result type. We have to rename any type parameters // before comparing types. List<Type> mtvars = mt.getTypeArguments(); List<Type> otvars = ot.getTypeArguments(); Type mtres = mt.getReturnType(); Type otres = types.subst(ot.getReturnType(), otvars, mtvars); overrideWarner.warned = false; boolean resultTypesOK = types.returnTypeSubstitutable(mt, ot, otres, overrideWarner); if (!resultTypesOK) { if (!source.allowCovariantReturns() && m.owner != origin && m.owner.isSubClass(other.owner, types)) { // allow limited interoperability with covariant returns } else { typeError(TreeInfo.diagnosticPositionFor(m, tree), JCDiagnostic.fragment("override.incompatible.ret", cannotOverride(m, other)), mtres, otres); return; } } else if (overrideWarner.warned) { warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), "prob.found.req", JCDiagnostic.fragment("override.unchecked.ret", uncheckedOverrides(m, other)), mtres, otres); } // Error if overriding method throws an exception not reported // by overridden method. List<Type> otthrown = types.subst(ot.getThrownTypes(), otvars, mtvars); List<Type> unhandled = unHandled(mt.getThrownTypes(), otthrown); if (unhandled.nonEmpty()) { log.error(TreeInfo.diagnosticPositionFor(m, tree), "override.meth.doesnt.throw", cannotOverride(m, other), unhandled.head); return; } // Optional warning if varargs don't agree if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0) && lint.isEnabled(Lint.LintCategory.OVERRIDES)) { log.warning(TreeInfo.diagnosticPositionFor(m, tree), ((m.flags() & Flags.VARARGS) != 0) ? "override.varargs.missing" : "override.varargs.extra", varargsOverrides(m, other)); } // Warn if instance method overrides bridge method (compiler spec ??) if ((other.flags() & BRIDGE) != 0) { log.warning(TreeInfo.diagnosticPositionFor(m, tree), "override.bridge", uncheckedOverrides(m, other)); } // Warn if a deprecated method overridden by a non-deprecated one. if ((other.flags() & DEPRECATED) != 0 && (m.flags() & DEPRECATED) == 0 && m.outermostClass() != other.outermostClass() && !isDeprecatedOverrideIgnorable(other, origin)) { warnDeprecated(TreeInfo.diagnosticPositionFor(m, tree), other); } } // where private boolean isDeprecatedOverrideIgnorable(MethodSymbol m, ClassSymbol origin) { // If the method, m, is defined in an interface, then ignore the issue if the method // is only inherited via a supertype and also implemented in the supertype, // because in that case, we will rediscover the issue when examining the method // in the supertype. // If the method, m, is not defined in an interface, then the only time we need to // address the issue is when the method is the supertype implemementation: any other // case, we will have dealt with when examining the supertype classes ClassSymbol mc = m.enclClass(); Type st = types.supertype(origin.type); if (st.tag != CLASS) return true; MethodSymbol stimpl = m.implementation((ClassSymbol)st.tsym, types, false); if (mc != null && ((mc.flags() & INTERFACE) != 0)) { List<Type> intfs = types.interfaces(origin.type); return (intfs.contains(mc.type) ? false : (stimpl != null)); } else return (stimpl != m); } // used to check if there were any unchecked conversions Warner overrideWarner = new Warner(); /** Check that a class does not inherit two concrete methods * with the same signature. * @param pos Position to be used for error reporting. * @param site The class type to be checked. */ public void checkCompatibleConcretes(DiagnosticPosition pos, Type site) { Type sup = types.supertype(site); if (sup.tag != CLASS) return; for (Type t1 = sup; t1.tsym.type.isParameterized(); t1 = types.supertype(t1)) { for (Scope.Entry e1 = t1.tsym.members().elems; e1 != null; e1 = e1.sibling) { Symbol s1 = e1.sym; if (s1.kind != MTH || (s1.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 || !s1.isInheritedIn(site.tsym, types) || ((MethodSymbol)s1).implementation(site.tsym, types, true) != s1) continue; Type st1 = types.memberType(t1, s1); int s1ArgsLength = st1.getParameterTypes().length(); if (st1 == s1.type) continue; for (Type t2 = sup; t2.tag == CLASS; t2 = types.supertype(t2)) { for (Scope.Entry e2 = t1.tsym.members().lookup(s1.name); e2.scope != null; e2 = e2.next()) { Symbol s2 = e2.sym; if (s2 == s1 || s2.kind != MTH || (s2.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 || s2.type.getParameterTypes().length() != s1ArgsLength || !s2.isInheritedIn(site.tsym, types) || ((MethodSymbol)s2).implementation(site.tsym, types, true) != s2) continue; Type st2 = types.memberType(t2, s2); if (types.overrideEquivalent(st1, st2)) log.error(pos, "concrete.inheritance.conflict", s1, t1, s2, t2, sup); } } } } } /** Check that classes (or interfaces) do not each define an abstract * method with same name and arguments but incompatible return types. * @param pos Position to be used for error reporting. * @param t1 The first argument type. * @param t2 The second argument type. */ public boolean checkCompatibleAbstracts(DiagnosticPosition pos, Type t1, Type t2) { return checkCompatibleAbstracts(pos, t1, t2, types.makeCompoundType(t1, t2)); } public boolean checkCompatibleAbstracts(DiagnosticPosition pos, Type t1, Type t2, Type site) { Symbol sym = firstIncompatibility(t1, t2, site); if (sym != null) { log.error(pos, "types.incompatible.diff.ret", t1, t2, sym.name + "(" + types.memberType(t2, sym).getParameterTypes() + ")"); return false; } return true; } /** Return the first method which is defined with same args * but different return types in two given interfaces, or null if none * exists. * @param t1 The first type. * @param t2 The second type. * @param site The most derived type. * @returns symbol from t2 that conflicts with one in t1. */ private Symbol firstIncompatibility(Type t1, Type t2, Type site) { Map<TypeSymbol,Type> interfaces1 = new HashMap<TypeSymbol,Type>(); closure(t1, interfaces1); Map<TypeSymbol,Type> interfaces2; if (t1 == t2) interfaces2 = interfaces1; else closure(t2, interfaces1, interfaces2 = new HashMap<TypeSymbol,Type>()); for (Type t3 : interfaces1.values()) { for (Type t4 : interfaces2.values()) { Symbol s = firstDirectIncompatibility(t3, t4, site); if (s != null) return s; } } return null; } /** Compute all the supertypes of t, indexed by type symbol. */ private void closure(Type t, Map<TypeSymbol,Type> typeMap) { if (t.tag != CLASS) return; if (typeMap.put(t.tsym, t) == null) { closure(types.supertype(t), typeMap); for (Type i : types.interfaces(t)) closure(i, typeMap); } } /** Compute all the supertypes of t, indexed by type symbol (except thise in typesSkip). */ private void closure(Type t, Map<TypeSymbol,Type> typesSkip, Map<TypeSymbol,Type> typeMap) { if (t.tag != CLASS) return; if (typesSkip.get(t.tsym) != null) return; if (typeMap.put(t.tsym, t) == null) { closure(types.supertype(t), typesSkip, typeMap); for (Type i : types.interfaces(t)) closure(i, typesSkip, typeMap); } } /** Return the first method in t2 that conflicts with a method from t1. */ private Symbol firstDirectIncompatibility(Type t1, Type t2, Type site) { for (Scope.Entry e1 = t1.tsym.members().elems; e1 != null; e1 = e1.sibling) { Symbol s1 = e1.sym; Type st1 = null; if (s1.kind != MTH || !s1.isInheritedIn(site.tsym, types)) continue; Symbol impl = ((MethodSymbol)s1).implementation(site.tsym, types, false); if (impl != null && (impl.flags() & ABSTRACT) == 0) continue; for (Scope.Entry e2 = t2.tsym.members().lookup(s1.name); e2.scope != null; e2 = e2.next()) { Symbol s2 = e2.sym; if (s1 == s2) continue; if (s2.kind != MTH || !s2.isInheritedIn(site.tsym, types)) continue; if (st1 == null) st1 = types.memberType(t1, s1); Type st2 = types.memberType(t2, s2); if (types.overrideEquivalent(st1, st2)) { List<Type> tvars1 = st1.getTypeArguments(); List<Type> tvars2 = st2.getTypeArguments(); Type rt1 = st1.getReturnType(); Type rt2 = types.subst(st2.getReturnType(), tvars2, tvars1); boolean compat = types.isSameType(rt1, rt2) || rt1.tag >= CLASS && rt2.tag >= CLASS && (types.covariantReturnType(rt1, rt2, Warner.noWarnings) || types.covariantReturnType(rt2, rt1, Warner.noWarnings)); if (!compat) return s2; } } } return null; } /** Check that a given method conforms with any method it overrides. * @param tree The tree from which positions are extracted * for errors. * @param m The overriding method. */ void checkOverride(JCTree tree, MethodSymbol m) { ClassSymbol origin = (ClassSymbol)m.owner; if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) if (m.overrides(syms.enumFinalFinalize, origin, types, false)) { log.error(tree.pos(), "enum.no.finalize"); return; } for (Type t = types.supertype(origin.type); t.tag == CLASS; t = types.supertype(t)) { TypeSymbol c = t.tsym; Scope.Entry e = c.members().lookup(m.name); while (e.scope != null) { if (m.overrides(e.sym, origin, types, false)) checkOverride(tree, m, (MethodSymbol)e.sym, origin); e = e.next(); } } } /** Check that all abstract members of given class have definitions. * @param pos Position to be used for error reporting. * @param c The class. */ void checkAllDefined(DiagnosticPosition pos, ClassSymbol c) { try { MethodSymbol undef = firstUndef(c, c); if (undef != null) { if ((c.flags() & ENUM) != 0 && types.supertype(c.type).tsym == syms.enumSym && (c.flags() & FINAL) == 0) { // add the ABSTRACT flag to an enum c.flags_field |= ABSTRACT; } else { MethodSymbol undef1 = new MethodSymbol(undef.flags(), undef.name, types.memberType(c.type, undef), undef.owner); log.error(pos, "does.not.override.abstract", c, undef1, undef1.location()); } } } catch (CompletionFailure ex) { completionError(pos, ex); } }//where /** Return first abstract member of class `c' that is not defined * in `impl', null if there is none. */ private MethodSymbol firstUndef(ClassSymbol impl, ClassSymbol c) { MethodSymbol undef = null; // Do not bother to search in classes that are not abstract, // since they cannot have abstract members. if (c == impl || (c.flags() & (ABSTRACT | INTERFACE)) != 0) { Scope s = c.members(); for (Scope.Entry e = s.elems; undef == null && e != null; e = e.sibling) { if (e.sym.kind == MTH && (e.sym.flags() & (ABSTRACT|IPROXY)) == ABSTRACT) { MethodSymbol absmeth = (MethodSymbol)e.sym; MethodSymbol implmeth = absmeth.implementation(impl, types, true); if (implmeth == null || implmeth == absmeth) undef = absmeth; } } if (undef == null) { Type st = types.supertype(c.type); if (st.tag == CLASS) undef = firstUndef(impl, (ClassSymbol)st.tsym); } for (List<Type> l = types.interfaces(c.type); undef == null && l.nonEmpty(); l = l.tail) { undef = firstUndef(impl, (ClassSymbol)l.head.tsym); } } return undef; } /** Check for cyclic references. Issue an error if the * symbol of the type referred to has a LOCKED flag set. * * @param pos Position to be used for error reporting. * @param t The type referred to. */ void checkNonCyclic(DiagnosticPosition pos, Type t) { checkNonCyclicInternal(pos, t); } void checkNonCyclic(DiagnosticPosition pos, TypeVar t) { checkNonCyclic1(pos, t, new HashSet<TypeVar>()); } private void checkNonCyclic1(DiagnosticPosition pos, Type t, Set<TypeVar> seen) { final TypeVar tv; if (seen.contains(t)) { tv = (TypeVar)t; tv.bound = new ErrorType(); log.error(pos, "cyclic.inheritance", t); } else if (t.tag == TYPEVAR) { tv = (TypeVar)t; seen.add(tv); for (Type b : types.getBounds(tv)) checkNonCyclic1(pos, b, seen); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -