/*** @name Unreachable method overloads* @description Having multiple overloads with the same parameter types in TypeScript* makes all overloads except the first one unreachable, as the compiler* always resolves calls to the textually first matching overload.* @kind problem* @problem.severity warning* @id js/unreachable-method-overloads* @precision high* @tags correctness* typescript*/import javascript/*** Gets the `i`th parameter from the method signature.*/SimpleParameter getParameter(MethodSignature sig, int i) { result = sig.getBody().getParameter(i) }/*** Gets a string-representation of the type-annotation from the `i`th parameter in the method signature.*/string getParameterTypeAnnotation(MethodSignature sig, int i) {result = getParameter(sig, i).getTypeAnnotation().toString()}/*** Gets the other overloads for an overloaded method signature.*/MethodSignature getOtherMatchingSignatures(MethodSignature sig) {signaturesMatch(result, sig) andresult != sig}/*** Gets the kind of the member-declaration. Either "static" or "instance".*/string getKind(MemberDeclaration m) {if m.isStatic() then result = "static" else result = "instance"}/*** A call-signature that originates from a MethodSignature in the AST.*/private class MethodCallSig extends CallSignatureType {string name;MethodCallSig() {exists(MethodSignature sig |this = sig.getBody().getCallSignature() andname = sig.getName())}/*** Gets the name of any member that has this signature.*/string getName() { result = name }}pragma[noinline]private MethodCallSig getMethodCallSigWithFingerprint(string name, int optionalParams, int numParams, int requiredParms, SignatureKind kind) {name = result.getName() andoptionalParams = result.getNumOptionalParameter() andnumParams = result.getNumParameter() andrequiredParms = result.getNumRequiredParameter() andkind = result.getKind()}/*** Holds if the two call signatures could be overloads of each other and have the same parameter types.*/predicate matchingCallSignature(MethodCallSig method, MethodCallSig other) {other =getMethodCallSigWithFingerprint(method.getName(), method.getNumOptionalParameter(),method.getNumParameter(), method.getNumRequiredParameter(), method.getKind()) and// purposely not looking at number of type arguments.forall(int i | i in [0 .. -1 + method.getNumParameter()] |method.getParameter(i) = other.getParameter(i) // This is sometimes imprecise, so it is still a good idea to compare type annotations.) and// shared type parameters are equal.forall(int i |i in [0 .. -1 +min(int num | num = method.getNumTypeParameter() or num = other.getNumTypeParameter())]|method.getTypeParameterBound(i) = other.getTypeParameterBound(i))}/*** Gets which overload index the MethodSignature has among the overloads of the same name.*/int getOverloadIndex(MethodSignature sig) {sig.getDeclaringType().getMethodOverload(sig.getName(), result) = sig}pragma[noinline]private MethodSignature getMethodSignatureWithFingerprint(ClassOrInterface declaringType, string name, int numParameters, string kind) {result.getDeclaringType() = declaringType andresult.getName() = name andgetKind(result) = kind andresult.getBody().getNumParameter() = numParameters}/*** Holds if the two method signatures are overloads of each other and have the same parameter types.*/predicate signaturesMatch(MethodSignature method, MethodSignature other) {// the initial search for another overload in a single call for better join-order.other =getMethodSignatureWithFingerprint(method.getDeclaringType(), method.getName(),method.getBody().getNumParameter(), getKind(method)) and// same this parameter (if exists)(not exists(method.getBody().getThisTypeAnnotation()) andnot exists(other.getBody().getThisTypeAnnotation())ormethod.getBody().getThisTypeAnnotation().getType() =other.getBody().getThisTypeAnnotation().getType()) and// The types are compared in matchingCallSignature. This is a consistency check that the textual representation of the type-annotations are somewhat similar.forall(int i | i in [0 .. -1 + method.getBody().getNumParameter()] |getParameterTypeAnnotation(method, i) = getParameterTypeAnnotation(other, i)) andmatchingCallSignature(method.getBody().getCallSignature(), other.getBody().getCallSignature())}from ClassOrInterface decl, string name, MethodSignature previous, MethodSignature unreachablewhereprevious = decl.getMethod(name) andunreachable = getOtherMatchingSignatures(previous) and// If the method is part of inheritance between classes/interfaces, then there can sometimes be reasons for having this pattern.not exists(decl.getASuperTypeDeclaration().getMethod(name)) andnot exists(ClassOrInterface sub |decl = sub.getASuperTypeDeclaration() andexists(sub.getMethod(name))) and// If a later method overload has more type parameters, then that overload can be selected by explicitly declaring the type arguments at the callsite.// This comparison removes those cases.unreachable.getBody().getNumTypeParameter() <= previous.getBody().getNumTypeParameter() and// We always select the first of the overloaded methods.not exists(MethodSignature later | later = getOtherMatchingSignatures(previous) |getOverloadIndex(later) < getOverloadIndex(previous))select unreachable,"This overload of " + name + "() is unreachable, the $@ overload will always be selected.",previous, "previous"
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。