Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method signature validator #860

Merged
merged 8 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1997-2020 Raja Vallée-Rai, Linghui Luo and others
* Copyright (C) 1997-2020 Raja Vallée-Rai, Linghui Luo, Akshita Dubey and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
Expand All @@ -24,24 +24,74 @@

import java.util.List;
import sootup.core.model.SootClass;
import sootup.core.model.SootMethod;
import sootup.core.types.NullType;
import sootup.core.types.Type;
import sootup.core.types.VoidType;

/**
* Validates classes to make sure that all method signatures are valid
* Validates classes to make sure that all method signatures are valid and does not contain
* impossible method modifier combinations
*
* @author Steven Arzt
* @author Akshita Dubey
*/
public class MethodDeclarationValidator implements ClassValidator {

@Override
public void validate(SootClass sc, List<ValidationException> exceptions) {
// TODO: check code from old soot in the comment

/*
* if (sc.isConcrete()) { for (SootMethod sm : sc.getMethods()) { for (Type tp : sm.getParameterTypes()) { if (tp ==
* null) { exceptions.add(new ValidationException(sm, "Null parameter types are invalid")); } if (tp instanceof VoidType)
* { exceptions.add(new ValidationException(sm, "Void parameter types are invalid")); } if (!tp.isAllowedInFinalCode()) {
* exceptions.add(new ValidationException(sm, "Parameter type not allowed in final code")); } } } }
*/

for (SootMethod sm : sc.getMethods()) {
if (sc.isConcrete()) {
List<Type> parameterTypes = sm.getParameterTypes();
for (Type tp : parameterTypes) {
if (tp instanceof NullType) {
exceptions.add(new ValidationException(sm, "Null parameter types are invalid"));
}
if (tp instanceof VoidType) {
exceptions.add(new ValidationException(sm, "Void parameter types are invalid"));
}
}
}
if (sm.isAbstract()) {
if (sm.isFinal()) {
exceptions.add(new ValidationException(sm, "Method cannot be Abstract and Final"));
}
if (sm.isNative()) {
exceptions.add(new ValidationException(sm, "Method cannot be Abstract and Native"));
}
if (sm.isPrivate()) {
exceptions.add(new ValidationException(sm, "Method cannot be Abstract and Private"));
}
if (sm.isStatic()) {
exceptions.add(new ValidationException(sm, "Method cannot be Abstract and Static"));
}
if (sm.isSynchronized()) {
exceptions.add(new ValidationException(sm, "Method cannot be Abstract and Synchronized"));
}
}

if (sc.isInterface()) {
if (sm.isProtected()) {
exceptions.add(
new ValidationException(sm, "Method cannot be an interface and protected"));
}
if (sm.isSynchronized()) {
exceptions.add(
new ValidationException(sm, "Method cannot be an interface and synchronized"));
}
if (sm.isFinal()) {
exceptions.add(new ValidationException(sm, "Method cannot be an interface and final"));
}
if (sm.isNative()) {
exceptions.add(new ValidationException(sm, "Method cannot be an interface and native"));
}
}

if ((sm.isPrivate() || sm.isProtected()) && (sm.isPublic()) || sm.isProtected()) {
exceptions.add(
new ValidationException(sm, "Method can only be either Public, Protected or Private"));
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package sootup.tests.validator;

import static org.junit.Assert.assertEquals;

import categories.Java8Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import sootup.core.frontend.OverridingBodySource;
import sootup.core.inputlocation.EagerInputLocation;
import sootup.core.jimple.Jimple;
import sootup.core.jimple.basic.LocalGenerator;
import sootup.core.jimple.basic.NoPositionInformation;
import sootup.core.jimple.basic.StmtPositionInfo;
import sootup.core.jimple.common.stmt.JIdentityStmt;
import sootup.core.jimple.common.stmt.JReturnVoidStmt;
import sootup.core.model.Body;
import sootup.core.model.ClassModifier;
import sootup.core.model.MethodModifier;
import sootup.core.model.SourceType;
import sootup.core.signatures.MethodSignature;
import sootup.core.types.ClassType;
import sootup.core.validation.MethodDeclarationValidator;
import sootup.core.validation.ValidationException;
import sootup.java.core.*;
import sootup.java.core.views.JavaView;

@Category(Java8Test.class)
public class MethodDeclarationValidatorTest {
JavaView view;
MethodDeclarationValidator methodDeclarationValidator;

@Before
public void setUp() {
view = new JavaView(Collections.singletonList(new EagerInputLocation()));
methodDeclarationValidator = new MethodDeclarationValidator();
}

public JavaSootClass testClassCreatorWithModifiers(
EnumSet<ClassModifier> classModifierEnumSet,
EnumSet<MethodModifier> methodModifierEnumSet,
List<String> methodParameters) {

JavaView view = new JavaView(Collections.singletonList(new EagerInputLocation()));
ClassType type = view.getIdentifierFactory().getClassType("java.lang.String");

LocalGenerator generator = new LocalGenerator(new HashSet<>());
MethodSignature methodSignature =
view.getIdentifierFactory()
.getMethodSignature("dummyMain", "main", "void", methodParameters);
Body.BodyBuilder bodyBuilder = Body.builder();

final JIdentityStmt firstStmt =
Jimple.newIdentityStmt(
generator.generateLocal(type),
Jimple.newParameterRef(type, 0),
StmtPositionInfo.getNoStmtPositionInfo());
final JReturnVoidStmt returnVoidStmt =
new JReturnVoidStmt(StmtPositionInfo.getNoStmtPositionInfo());

Body body =
bodyBuilder.setMethodSignature(methodSignature).setLocals(generator.getLocals()).build();
assertEquals(1, body.getLocalCount());

JavaSootMethod dummyMainMethod =
new JavaSootMethod(
new OverridingBodySource(methodSignature, body),
methodSignature,
methodModifierEnumSet,
Collections.emptyList(),
Collections.emptyList(),
NoPositionInformation.getInstance());

JavaSootClass mainClass =
new JavaSootClass(
new OverridingJavaClassSource(
new EagerInputLocation(),
null,
view.getIdentifierFactory().getClassType("dummyMain"),
null,
Collections.emptySet(),
null,
Collections.emptySet(),
Collections.singleton(dummyMainMethod),
NoPositionInformation.getInstance(),
classModifierEnumSet,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList()),
SourceType.Application);
assertEquals(mainClass.getMethods().size(), 1);

return mainClass;
}

@Test
public void testClassModifiersValidator_success() {
List<ValidationException> validationExceptions_success = new ArrayList<>();

JavaSootClass javaSootClass =
testClassCreatorWithModifiers(
EnumSet.of(ClassModifier.PUBLIC, ClassModifier.INTERFACE),
EnumSet.of(MethodModifier.ABSTRACT, MethodModifier.PUBLIC),
Collections.emptyList());

methodDeclarationValidator.validate(javaSootClass, validationExceptions_success);

assertEquals(0, validationExceptions_success.size());
}

@Test
public void testClassModifiersValidator_fail1() {
List<ValidationException> validationExceptions_fail1 = new ArrayList<>();

JavaSootClass javaSootClass =
testClassCreatorWithModifiers(
EnumSet.of(ClassModifier.PUBLIC, ClassModifier.INTERFACE),
EnumSet.of(
MethodModifier.ABSTRACT,
MethodModifier.PRIVATE,
MethodModifier.FINAL,
MethodModifier.SYNCHRONIZED,
MethodModifier.NATIVE,
MethodModifier.STATIC,
MethodModifier.PROTECTED),
Collections.emptyList());

methodDeclarationValidator.validate(javaSootClass, validationExceptions_fail1);

assertEquals(10, validationExceptions_fail1.size());
}

@Test
public void testClassModifiersValidator_fail2() {
List<ValidationException> validationExceptions_fail2 = new ArrayList<>();

JavaSootClass javaSootClass =
testClassCreatorWithModifiers(
EnumSet.of(ClassModifier.PUBLIC),
EnumSet.of(MethodModifier.PUBLIC),
Stream.of("void", "null").collect(Collectors.toList()));

methodDeclarationValidator.validate(javaSootClass, validationExceptions_fail2);

assertEquals(2, validationExceptions_fail2.size());
}
}
Loading