@Override public void visitMethodInvocation(MethodInvocationTree tree) { Symbol symbol = tree.symbol(); if (symbol.isMethodSymbol()) { MethodJavaSymbol methodSymbol = (MethodJavaSymbol) symbol; List<JavaSymbol> parameters = methodSymbol.getParameters().scopeSymbols(); if (!parameters.isEmpty()) { for (int i = 0; i < tree.arguments().size(); i += 1) { // in case of varargs, there could be more arguments than parameters. in that case, pick the last parameter. if (checkNullity(parameters.get(i < parameters.size() ? i : parameters.size() - 1)) == AbstractValue.NOTNULL) { this.checkForIssue(tree.arguments().get(i), String.format("'%%s' is nullable here and method '%s' does not accept nullable argument", methodSymbol.name()), String.format("method '%s' does not accept nullable argument", methodSymbol.name())); } } } } super.visitMethodInvocation(tree); }
/** * @return true, if signature of m1 is more specific than signature of m2 */ private boolean isSignatureMoreSpecific(JavaSymbol m1, JavaSymbol m2, List<JavaType> argTypes, TypeSubstitution m1Substitution, TypeSubstitution m2Substitution) { List<JavaType> m1ArgTypes = ((MethodJavaType) m1.type).argTypes; List<JavaType> m2ArgTypes = ((MethodJavaType) m2.type).argTypes; JavaSymbol.MethodJavaSymbol methodJavaSymbol = (JavaSymbol.MethodJavaSymbol) m1; boolean m1VarArity = methodJavaSymbol.isVarArgs(); boolean m2VarArity = ((JavaSymbol.MethodJavaSymbol) m2).isVarArgs(); if (m1VarArity != m2VarArity) { // last arg is an array boolean lastArgIsArray = !argTypes.isEmpty() && argTypes.get(argTypes.size() -1).isArray() && (argTypes.size() == m2ArgTypes.size() || argTypes.size() == m1ArgTypes.size()); // general case : prefer strict arity invocation over varArity, so if m2 is variadic, m1 is most specific, but not if last arg of invocation is an array return lastArgIsArray ^ m2VarArity; } if (m1VarArity) { m1ArgTypes = expandVarArgsToFitSize(m1ArgTypes, m2ArgTypes.size()); } if(!hasCompatibleArity(m1ArgTypes.size(), m2ArgTypes.size(), m2VarArity)) { return false; } m1ArgTypes = typeSubstitutionSolver.applySubstitutionToFormalParameters(m1ArgTypes, m1Substitution); m2ArgTypes = typeSubstitutionSolver.applySubstitutionToFormalParameters(m2ArgTypes, m2Substitution); return isArgumentsAcceptable(m1ArgTypes, m2ArgTypes, m2VarArity, true); }
@Override public MethodVisitor visitMethod(int flags, String name, String desc, @Nullable String signature, @Nullable String[] exceptions) { Preconditions.checkNotNull(name); Preconditions.checkNotNull(desc); if (!BytecodeCompleter.isSynthetic(flags)) { Preconditions.checkState((flags & Opcodes.ACC_BRIDGE) == 0, "bridge method not marked as synthetic in class " + className); // TODO(Godin): according to JVMS 4.7.24 - parameter can be marked as synthetic JavaType.MethodJavaType type = new JavaType.MethodJavaType( convertAsmTypes(org.objectweb.asm.Type.getArgumentTypes(desc)), convertAsmType(org.objectweb.asm.Type.getReturnType(desc)), getCompletedClassSymbolsType(exceptions), classSymbol ); final JavaSymbol.MethodJavaSymbol methodSymbol = new JavaSymbol.MethodJavaSymbol(bytecodeCompleter.filterBytecodeFlags(flags), name, type, classSymbol); classSymbol.members.enter(methodSymbol); if (signature != null) { new SignatureReader(signature).accept(new ReadMethodSignature(methodSymbol)); } methodSymbol.parameters = new OrderedScope(methodSymbol); for (int i = 0; i < type.argTypes.size(); i += 1) { methodSymbol.parameters.enter(new JavaSymbol.VariableJavaSymbol(0, "arg" + i, methodSymbol)); } // checks for annotations on the method and its parameters return new BytecodeMethodVisitor(methodSymbol, this); } return null; }
JavaSymbol.MethodJavaSymbol valuesMethod = new JavaSymbol.MethodJavaSymbol((symbol.flags & Flags.ACCESS_FLAGS) | Flags.STATIC, "values", symbol); ArrayJavaType enumArrayType = new ArrayJavaType(symbol.type, symbols.arrayClass); MethodJavaType valuesMethodType = new MethodJavaType(ImmutableList.<JavaType>of(), enumArrayType, ImmutableList.<JavaType>of(), symbol); valuesMethod.setMethodType(valuesMethodType); valuesMethod.parameters = new Scope(valuesMethod); classEnv.scope.enter(valuesMethod); JavaSymbol.MethodJavaSymbol valueOfMethod = new JavaSymbol.MethodJavaSymbol((symbol.flags & Flags.ACCESS_FLAGS) | Flags.STATIC, "valueOf", symbol); MethodJavaType valueOfMethodType = new MethodJavaType(ImmutableList.<JavaType>of(symbols.stringType), symbol.type, ImmutableList.<JavaType>of(), symbol); valueOfMethod.setMethodType(valueOfMethodType); valueOfMethod.parameters = new Scope(valueOfMethod); valueOfMethod.parameters.enter(new JavaSymbol.VariableJavaSymbol(0, "name", symbols.stringType, valueOfMethod));
if(!hasCompatibleArity(methodJavaSymbol.parameterTypes().size(), argTypes.size(), methodJavaSymbol.isVarArgs())) { return bestSoFar; if (!isArgumentsAcceptable(argTypes, formals, methodJavaSymbol.isVarArgs(), looseInvocation)) { return bestSoFar; List<JavaType> thrownTypes = ((MethodJavaType) mostSpecific.type).thrown; JavaType returnType = ((MethodJavaType) mostSpecificMethod.type).resultType; if((substitution.isUnchecked() || applicableWithUncheckedConversion(mostSpecificMethod, defSite, typeParams)) && !mostSpecificMethod.isConstructor()) { returnType = returnType.erasure(); thrownTypes = erasure(thrownTypes);
JavaSymbol.MethodJavaSymbol valuesMethod = new JavaSymbol.MethodJavaSymbol((symbol.flags & Flags.ACCESS_FLAGS) | Flags.STATIC, "values", symbol); ArrayJavaType enumArrayType = new ArrayJavaType(symbol.type, symbols.arrayClass); MethodJavaType valuesMethodType = new MethodJavaType(ImmutableList.<JavaType>of(), enumArrayType, ImmutableList.<JavaType>of(), symbol); valuesMethod.setMethodType(valuesMethodType); valuesMethod.parameters = new Scope(valuesMethod); classEnv.scope.enter(valuesMethod); JavaSymbol.MethodJavaSymbol valueOfMethod = new JavaSymbol.MethodJavaSymbol((symbol.flags & Flags.ACCESS_FLAGS) | Flags.STATIC, "valueOf", symbol); MethodJavaType valueOfMethodType = new MethodJavaType(ImmutableList.<JavaType>of(symbols.stringType), symbol.type, ImmutableList.<JavaType>of(), symbol); valueOfMethod.setMethodType(valueOfMethodType); valueOfMethod.parameters = new Scope(valueOfMethod); valueOfMethod.parameters.enter(new JavaSymbol.VariableJavaSymbol(0, "name", symbols.stringType, valueOfMethod));
JavaSymbol.MethodJavaSymbol defaultConstructor = new JavaSymbol.MethodJavaSymbol(symbol.flags & Flags.ACCESS_FLAGS, CONSTRUCTOR_NAME, symbol); MethodJavaType defaultConstructorType = new MethodJavaType(argTypes, null, ImmutableList.of(), symbol); defaultConstructor.setMethodType(defaultConstructorType); defaultConstructor.parameters = new Scope(defaultConstructor); symbol.members.enter(defaultConstructor);
JavaSymbol.MethodJavaSymbol defaultConstructor = new JavaSymbol.MethodJavaSymbol(symbol.flags & Flags.ACCESS_FLAGS, CONSTRUCTOR_NAME, symbol); JavaType.MethodJavaType defaultConstructorType = new JavaType.MethodJavaType(ImmutableList.<JavaType>of(), null, ImmutableList.<JavaType>of(), symbol); defaultConstructor.setMethodType(defaultConstructorType); classEnv.scope.enter(defaultConstructor);
JavaSymbol.MethodJavaSymbol defaultConstructor = new JavaSymbol.MethodJavaSymbol(symbol.flags & Flags.ACCESS_FLAGS, CONSTRUCTOR_NAME, symbol); MethodJavaType defaultConstructorType = new MethodJavaType(argTypes, null, ImmutableList.of(), symbol); defaultConstructor.setMethodType(defaultConstructorType); defaultConstructor.parameters = new Scope(defaultConstructor); symbol.members.enter(defaultConstructor);
if(!hasCompatibleArity(methodJavaSymbol.parameterTypes().size(), argTypes.size(), methodJavaSymbol.isVarArgs())) { return bestSoFar; if (!isArgumentsAcceptable(argTypes, formals, methodJavaSymbol.isVarArgs(), looseInvocation)) { return bestSoFar; List<JavaType> thrownTypes = ((MethodJavaType) mostSpecific.type).thrown; JavaType returnType = ((MethodJavaType) mostSpecificMethod.type).resultType; if((substitution.isUnchecked() || applicableWithUncheckedConversion(mostSpecificMethod, defSite, typeParams)) && !mostSpecificMethod.isConstructor()) { returnType = returnType.erasure(); thrownTypes = erasure(thrownTypes);
symbol.returnType = returnType.symbol; } else if (!symbol.enclosingClass().isStatic()) { JavaSymbol owner = symbol.enclosingClass().owner(); if (!owner.isPackageSymbol()) { symbol.setMethodType(methodType);
final JavaSymbol.MethodJavaSymbol methodSymbol = new JavaSymbol.MethodJavaSymbol(methodFlags, name, type, classSymbol); methodSymbol.desc = desc; classSymbol.members.enter(methodSymbol);
symbol.returnType = returnType.symbol; } else if (!symbol.enclosingClass().isStatic()) { JavaSymbol owner = symbol.enclosingClass().owner(); if (!owner.isPackageSymbol()) { symbol.setMethodType(methodType);
@Override public void visitMethod(MethodTree tree) { String name = tree.returnType() == null ? CONSTRUCTOR_NAME : tree.simpleName().name(); JavaSymbol.MethodJavaSymbol symbol = new JavaSymbol.MethodJavaSymbol(computeFlags(tree.modifiers(), tree), name, env.scope.owner); symbol.declaration = tree; if (Flags.isFlagged(env.scope.owner.flags, Flags.ENUM) && tree.returnType() == null) { for (TypeParameterTree typeParameterTree : tree.typeParameters()) { JavaSymbol.TypeVariableJavaSymbol typeVariableSymbol = new JavaSymbol.TypeVariableJavaSymbol(typeParameterTree.identifier().name(), symbol); symbol.addTypeParameter((TypeVariableJavaType) typeVariableSymbol.type); enterSymbol(typeParameterTree, typeVariableSymbol);
@Override public void visitMethod(MethodTree tree) { String name = tree.returnType() == null ? CONSTRUCTOR_NAME : tree.simpleName().name(); JavaSymbol.MethodJavaSymbol symbol = new JavaSymbol.MethodJavaSymbol(computeFlags(tree.modifiers(), tree), name, env.scope.owner); symbol.declaration = tree; if((env.scope.owner.flags & Flags.ENUM) !=0 && tree.returnType()==null ) { for (TypeParameterTree typeParameterTree : tree.typeParameters()) { JavaSymbol.TypeVariableJavaSymbol typeVariableSymbol = new JavaSymbol.TypeVariableJavaSymbol(typeParameterTree.identifier().name(), symbol); symbol.addTypeParameter((JavaType.TypeVariableJavaType) typeVariableSymbol.type); enterSymbol(typeParameterTree, typeVariableSymbol);
@Override public void visitMethod(MethodTree tree) { String name = tree.returnType() == null ? "<init>" : tree.simpleName().name(); JavaSymbol.MethodJavaSymbol symbol = new JavaSymbol.MethodJavaSymbol(computeFlags(tree.modifiers()), name, env.scope.owner); symbol.declaration = tree; if((env.scope.owner.flags & Flags.ENUM) !=0 && tree.returnType()==null ) { for (TypeParameterTree typeParameterTree : tree.typeParameters()) { JavaSymbol.TypeVariableJavaSymbol typeVariableSymbol = new JavaSymbol.TypeVariableJavaSymbol(typeParameterTree.identifier().name(), symbol); symbol.addTypeParameter((JavaType.TypeVariableJavaType) typeVariableSymbol.type); enterSymbol(typeParameterTree, typeVariableSymbol);
@Override public void visitMethod(MethodTree tree) { String name = tree.returnType() == null ? CONSTRUCTOR_NAME : tree.simpleName().name(); JavaSymbol.MethodJavaSymbol symbol = new JavaSymbol.MethodJavaSymbol(computeFlags(tree.modifiers(), tree), name, env.scope.owner); symbol.declaration = tree; if (Flags.isFlagged(env.scope.owner.flags, Flags.ENUM) && tree.returnType() == null) { for (TypeParameterTree typeParameterTree : tree.typeParameters()) { JavaSymbol.TypeVariableJavaSymbol typeVariableSymbol = new JavaSymbol.TypeVariableJavaSymbol(typeParameterTree.identifier().name(), symbol); symbol.addTypeParameter((TypeVariableJavaType) typeVariableSymbol.type); enterSymbol(typeParameterTree, typeVariableSymbol);
final JavaSymbol.MethodJavaSymbol methodSymbol = new JavaSymbol.MethodJavaSymbol(methodFlags, name, type, classSymbol); methodSymbol.desc = desc; classSymbol.members.enter(methodSymbol);
@Override public MethodVisitor visitMethod(int flags, String name, String desc, @Nullable String signature, @Nullable String[] exceptions) { Preconditions.checkNotNull(name); Preconditions.checkNotNull(desc); if (!BytecodeCompleter.isSynthetic(flags)) { Preconditions.checkState((flags & Opcodes.ACC_BRIDGE) == 0, "bridge method not marked as synthetic in class " + className); // TODO(Godin): according to JVMS 4.7.24 - parameter can be marked as synthetic JavaType.MethodJavaType type = new JavaType.MethodJavaType( convertAsmTypes(org.objectweb.asm.Type.getArgumentTypes(desc)), convertAsmType(org.objectweb.asm.Type.getReturnType(desc)), getCompletedClassSymbolsType(exceptions), classSymbol ); final JavaSymbol.MethodJavaSymbol methodSymbol = new JavaSymbol.MethodJavaSymbol(bytecodeCompleter.filterBytecodeFlags(flags), name, type, classSymbol); classSymbol.members.enter(methodSymbol); if (signature != null) { SignatureReader signatureReader = new SignatureReader(signature); signatureReader.accept(new TypeParameterDeclaration(methodSymbol)); signatureReader.accept(new ReadMethodSignature(methodSymbol)); } methodSymbol.parameters = new Scope(methodSymbol); for (int i = 0; i < type.argTypes.size(); i += 1) { methodSymbol.parameters.enter(new JavaSymbol.VariableJavaSymbol(0, "arg" + i, methodSymbol)); } // checks for annotations on the method and its parameters return new BytecodeMethodVisitor(methodSymbol, this); } return null; }
@Nullable private Boolean isOverriding(MethodJavaSymbol overridee, JavaType.ClassJavaType classType) { // same number and type of formal parameters if (getParametersTypes().size() != overridee.getParametersTypes().size()) { return false; } for (int i = 0; i < getParametersTypes().size(); i++) { JavaType paramOverrider = getParametersTypes().get(i); if (paramOverrider.isTagged(JavaType.UNKNOWN)) { // FIXME : complete symbol table should not have unknown types and generics should be handled properly for this. return null; } // Generics type should have same erasure see JLS8 8.4.2 JavaType overrideeType = overridee.getParametersTypes().get(i); if (classType instanceof JavaType.ParametrizedTypeJavaType) { overrideeType = ((JavaType.ParametrizedTypeJavaType) classType).typeSubstitution.substitutedType(overrideeType); if (overrideeType == null) { overrideeType = overridee.getParametersTypes().get(i); } } if (!paramOverrider.erasure().equals(overrideeType.erasure())) { return false; } } // we assume code is compiling so no need to check return type at this point. return true; }