private void checkNullArguments(Tree syntaxTree, JavaSymbol.MethodJavaSymbol symbol, List<SymbolicValue> argumentValues) { List<JavaSymbol> scopeSymbols = symbol.getParameters().scopeSymbols(); int parametersToTest = argumentValues.size(); if (scopeSymbols.size() < parametersToTest) { // The last parameter is a variable length argument: the non-null condition does not apply to its values parametersToTest = scopeSymbols.size() - 1; } for (int i = 0; i < parametersToTest; i++) { checkNullArgument(syntaxTree, symbol, scopeSymbols.get(i), argumentValues.get(i), i); } }
private void checkNullArguments(Tree syntaxTree, JavaSymbol.MethodJavaSymbol symbol, List<SymbolicValue> argumentValues) { List<JavaSymbol> scopeSymbols = symbol.getParameters().scopeSymbols(); int parametersToTest = argumentValues.size(); if (scopeSymbols.size() < parametersToTest) { // The last parameter is a variable length argument: the non-null condition does not apply to its values parametersToTest = scopeSymbols.size() - 1; } for (int i = 0; i < parametersToTest; i++) { checkNullArgument(syntaxTree, symbol, scopeSymbols.get(i), argumentValues.get(i), i); } }
@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); }
protected boolean isIdentifierDynamicString(Tree methodTree, IdentifierTree arg, @Nullable Symbol currentlyChecking, boolean firstLevel) { Symbol symbol = arg.symbol(); if (isExcluded(currentlyChecking, symbol)) { return false; } boolean isLocalVar = symbol.owner().isMethodSymbol() && !((JavaSymbol.MethodJavaSymbol) symbol.owner()).getParameters().scopeSymbols().contains(symbol); if (isLocalVar) { //symbol is a local variable, check it is not a dynamic string. //Check declaration VariableTree declaration = ((Symbol.VariableSymbol) symbol).declaration(); ExpressionTree initializer = declaration.initializer(); if (initializer != null && isDynamicString(methodTree, initializer, currentlyChecking)) { return true; } //check usages by revisiting the enclosing tree. Collection<IdentifierTree> usages = symbol.usages(); LocalVariableDynamicStringVisitor visitor = new LocalVariableDynamicStringVisitor(symbol, usages, methodTree); Tree argEnclosingDeclarationTree = semanticModel.getTree(semanticModel.getEnv(symbol)); argEnclosingDeclarationTree.accept(visitor); return visitor.dynamicString; } //arg is not a local variable nor a constant, so it is a parameter or a field. parameterName = "\""+arg.name()+"\""; return symbol.owner().isMethodSymbol() && !firstLevel; }
protected boolean isIdentifierDynamicString(Tree methodTree, IdentifierTree arg, @Nullable Symbol currentlyChecking, boolean firstLevel) { Symbol symbol = arg.symbol(); if (isExcluded(currentlyChecking, symbol)) { return false; } boolean isLocalVar = symbol.owner().isMethodSymbol() && !((JavaSymbol.MethodJavaSymbol) symbol.owner()).getParameters().scopeSymbols().contains(symbol); if (isLocalVar) { //symbol is a local variable, check it is not a dynamic string. //Check declaration VariableTree declaration = ((Symbol.VariableSymbol) symbol).declaration(); ExpressionTree initializer = declaration.initializer(); if (initializer != null && isDynamicString(methodTree, initializer, currentlyChecking)) { return true; } //check usages by revisiting the enclosing tree. Collection<IdentifierTree> usages = symbol.usages(); LocalVariableDynamicStringVisitor visitor = new LocalVariableDynamicStringVisitor(symbol, usages, methodTree); Tree argEnclosingDeclarationTree = semanticModel.getTree(semanticModel.getEnv(symbol)); argEnclosingDeclarationTree.accept(visitor); return visitor.dynamicString; } //arg is not a local variable nor a constant, so it is a parameter or a field. parameterName = "\""+arg.name()+"\""; return symbol.owner().isMethodSymbol() && !firstLevel; }
private void checkParameters(Tree syntaxNode, Symbol symbol, Arguments arguments, ProgramState state) { if (!symbol.isMethodSymbol() || arguments.isEmpty()) { return; } JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) symbol; if (nonNullAnnotationOnParameters(methodSymbol) == null) { // method is not annotated (locally or globally) return; } int nbArguments = arguments.size(); List<SymbolicValue> argumentSVs = getArgumentSVs(state, syntaxNode, nbArguments); List<JavaSymbol> argumentSymbols = methodSymbol.getParameters().scopeSymbols(); int nbArgumentToCheck = Math.min(nbArguments, argumentSymbols.size() - (methodSymbol.isVarArgs() ? 1 : 0)); for (int i = 0; i < nbArgumentToCheck; i++) { ObjectConstraint constraint = state.getConstraint(argumentSVs.get(i), ObjectConstraint.class); if (constraint != null && constraint.isNull() && !parameterIsNullable(methodSymbol, argumentSymbols.get(i))) { reportIssue(syntaxNode, arguments.get(i), methodSymbol); } } }
private void checkContractChange(MethodTreeImpl methodTree, Symbol.MethodSymbol overridee) { if (methodTree.isEqualsMethod() && methodTree.parameters().get(0).symbol().metadata().isAnnotatedWith(JAVAX_ANNOTATION_NONNULL)) { reportIssue(methodTree.parameters().get(0), "Equals method should accept null parameters and return false."); return; } for (int i = 0; i < methodTree.parameters().size(); i++) { VariableTree parameter = methodTree.parameters().get(i); Symbol overrideeParamSymbol = ((JavaSymbol.MethodJavaSymbol) overridee).getParameters().scopeSymbols().get(i); checkParameter(parameter, overrideeParamSymbol); } if (nonNullVsNull(overridee, methodTree.symbol())) { for (AnnotationTree annotationTree : methodTree.modifiers().annotations()) { if(annotationTree.symbolType().is(JAVAX_ANNOTATION_NULLABLE) || annotationTree.symbolType().is(JAVAX_ANNOTATION_CHECK_FOR_NULL)) { reportIssue(annotationTree, "Remove this \""+ annotationTree.symbolType().name() +"\" annotation to honor the overridden method's contract."); } } } }
private void checkParameters(Tree syntaxNode, Symbol symbol, Arguments arguments, ProgramState state) { if (!symbol.isMethodSymbol() || arguments.isEmpty()) { return; } JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) symbol; if (nonNullAnnotationOnParameters(methodSymbol) == null) { // method is not annotated (locally or globally) return; } int nbArguments = arguments.size(); List<SymbolicValue> argumentSVs = getArgumentSVs(state, syntaxNode, nbArguments); List<JavaSymbol> argumentSymbols = methodSymbol.getParameters().scopeSymbols(); int nbArgumentToCheck = Math.min(nbArguments, argumentSymbols.size() - (methodSymbol.isVarArgs() ? 1 : 0)); for (int i = 0; i < nbArgumentToCheck; i++) { ObjectConstraint constraint = state.getConstraint(argumentSVs.get(i), ObjectConstraint.class); if (constraint != null && constraint.isNull() && !parameterIsNullable(methodSymbol, argumentSymbols.get(i))) { reportIssue(syntaxNode, arguments.get(i), methodSymbol); } } }
private void checkContractChange(MethodTreeImpl methodTree, Symbol.MethodSymbol overridee) { if (methodTree.isEqualsMethod() && methodTree.parameters().get(0).symbol().metadata().isAnnotatedWith(JAVAX_ANNOTATION_NONNULL)) { reportIssue(methodTree.parameters().get(0), "Equals method should accept null parameters and return false."); return; } for (int i = 0; i < methodTree.parameters().size(); i++) { VariableTree parameter = methodTree.parameters().get(i); Symbol overrideeParamSymbol = ((JavaSymbol.MethodJavaSymbol) overridee).getParameters().scopeSymbols().get(i); checkParameter(parameter, overrideeParamSymbol); } if (nonNullVsNull(overridee, methodTree.symbol())) { for (AnnotationTree annotationTree : methodTree.modifiers().annotations()) { if(annotationTree.symbolType().is(JAVAX_ANNOTATION_NULLABLE) || annotationTree.symbolType().is(JAVAX_ANNOTATION_CHECK_FOR_NULL)) { reportIssue(annotationTree, "Remove this \""+ annotationTree.symbolType().name() +"\" annotation to honor the overridden method's contract."); } } } }
@Override public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { JavaType annotationType = bytecodeVisitor.convertAsmType(org.objectweb.asm.Type.getType(desc)); if (annotationType.is("java.lang.Synthetic")) { syntheticArgs++; } else { AnnotationInstanceResolve annotationInstance = new AnnotationInstanceResolve(annotationType.getSymbol()); methodSymbol.getParameters().scopeSymbols().get(parameter - syntheticArgs).metadata().addAnnotation(annotationInstance); return new BytecodeAnnotationVisitor(annotationInstance, bytecodeVisitor); } return null; } }
@Override public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { JavaType annotationType = bytecodeVisitor.convertAsmType(org.objectweb.asm.Type.getType(desc)); if (annotationType.is("java.lang.Synthetic")) { syntheticArgs++; } else { AnnotationInstanceResolve annotationInstance = new AnnotationInstanceResolve(annotationType.getSymbol()); methodSymbol.getParameters().scopeSymbols().get(parameter - syntheticArgs).metadata().addAnnotation(annotationInstance); return new BytecodeAnnotationVisitor(annotationInstance, bytecodeVisitor); } return null; } }
@CheckForNull private static Symbol getParam(ExpressionTree tree) { if (tree.is(Kind.IDENTIFIER)) { Symbol reference = ((IdentifierTree) tree).symbol(); if (reference.owner().isMethodSymbol() && ((JavaSymbol.MethodJavaSymbol) reference.owner()).getParameters().scopeSymbols().contains(reference)) { return reference; } } return null; }
@Override public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { JavaType annotationType = bytecodeVisitor.convertAsmType(org.objectweb.asm.Type.getType(desc), Flags.ANNOTATION); if (annotationType.is("java.lang.Synthetic")) { syntheticArgs++; } else { AnnotationInstanceResolve annotationInstance = new AnnotationInstanceResolve(annotationType.getSymbol()); methodSymbol.getParameters().scopeSymbols().get(parameter - syntheticArgs).metadata().addAnnotation(annotationInstance); return new BytecodeAnnotationVisitor(annotationInstance, bytecodeVisitor); } return null; }
private static boolean differentParameters(JavaSymbol.MethodJavaSymbol method, JavaSymbol.MethodJavaSymbol overridee) { return useRawTypeOfParametrizedType(method.parameterTypes(), overridee.parameterTypes()) || differentAnnotations(method.getParameters().scopeSymbols(), overridee.getParameters().scopeSymbols()); }
private static boolean differentParameters(JavaSymbol.MethodJavaSymbol method, JavaSymbol.MethodJavaSymbol overridee) { return useRawTypeOfParametrizedType(method.parameterTypes(), overridee.parameterTypes()) || differentAnnotations(method.getParameters().scopeSymbols(), overridee.getParameters().scopeSymbols()); }
@Override public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { JavaType annotationType = bytecodeVisitor.convertAsmType(org.objectweb.asm.Type.getType(desc), Flags.ANNOTATION); if (annotationType.is("java.lang.Synthetic")) { syntheticArgs++; } else { AnnotationInstanceResolve annotationInstance = new AnnotationInstanceResolve(annotationType.getSymbol()); methodSymbol.getParameters().scopeSymbols().get(parameter - syntheticArgs).metadata().addAnnotation(annotationInstance); return new BytecodeAnnotationVisitor(annotationInstance, bytecodeVisitor); } return null; }
@CheckForNull private static Symbol getParam(ExpressionTree tree) { if (tree.is(Kind.IDENTIFIER)) { Symbol reference = ((IdentifierTree) tree).symbol(); if (reference.owner().isMethodSymbol() && ((JavaSymbol.MethodJavaSymbol) reference.owner()).getParameters().scopeSymbols().contains(reference)) { return reference; } } return null; }