blob: d407e805bf8a6b6c7ecb8f9f995b534a69054800 [file] [log] [blame]
// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.codeinspector;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AccessFlags;
import com.google.common.collect.ImmutableList;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
public class Matchers {
private enum Visibility {
PUBLIC,
PROTECTED,
PRIVATE,
PACKAGE_PRIVATE;
@Override
public String toString() {
switch (this) {
case PUBLIC:
return "public";
case PROTECTED:
return "protected";
case PRIVATE:
return "private";
case PACKAGE_PRIVATE:
return "package-private";
default:
throw new Unreachable("Unexpected visibility");
}
}
}
private static String type(Subject subject) {
String type = "<unknown subject type>";
if (subject instanceof ClassSubject) {
type = "class";
} else if (subject instanceof MethodSubject) {
type = "method";
} else if (subject instanceof FieldSubject) {
type = "field";
}
return type;
}
private static String name(Subject subject) {
String name = "<unknown>";
if (subject instanceof ClassSubject) {
name = ((ClassSubject) subject).getOriginalName();
} else if (subject instanceof MethodSubject) {
name = ((MethodSubject) subject).getOriginalName();
} else if (subject instanceof FieldSubject) {
name = ((FieldSubject) subject).getOriginalName();
}
return name;
}
public static Matcher<Subject> isPresent() {
return new TypeSafeMatcher<Subject>() {
@Override
public boolean matchesSafely(final Subject subject) {
return subject.isPresent();
}
@Override
public void describeTo(final Description description) {
description.appendText(" present");
}
@Override
public void describeMismatchSafely(final Subject subject, Description description) {
description
.appendText(type(subject) + " ").appendValue(name(subject)).appendText(" was not");
}
};
}
public static Matcher<Subject> isRenamed() {
return new TypeSafeMatcher<Subject>() {
@Override
protected boolean matchesSafely(Subject subject) {
return subject.isPresent() && subject.isRenamed();
}
@Override
public void describeTo(Description description) {
description.appendText(" renamed");
}
@Override
public void describeMismatchSafely(final Subject subject, Description description) {
description
.appendText(type(subject) + " ").appendValue(name(subject)).appendText(" was not");
}
};
}
public static Matcher<Subject> isNotRenamed() {
return new TypeSafeMatcher<Subject>() {
@Override
protected boolean matchesSafely(Subject subject) {
return subject.isPresent() && !subject.isRenamed();
}
@Override
public void describeTo(Description description) {
description.appendText(" not renamed");
}
@Override
public void describeMismatchSafely(final Subject subject, Description description) {
description
.appendText(type(subject) + " ").appendValue(name(subject)).appendText(" was");
}
};
}
public static Matcher<MemberSubject> isStatic() {
return new TypeSafeMatcher<MemberSubject>() {
@Override
public boolean matchesSafely(final MemberSubject subject) {
return subject.isPresent() && subject.isStatic();
}
@Override
public void describeTo(final Description description) {
description.appendText(" present");
}
@Override
public void describeMismatchSafely(final MemberSubject subject, Description description) {
description
.appendText(type(subject) + " ")
.appendValue(name(subject))
.appendText(" was not");
}
};
}
public static Matcher<ClassSubject> hasDefaultConstructor() {
return new TypeSafeMatcher<ClassSubject>() {
@Override
public boolean matchesSafely(final ClassSubject clazz) {
return clazz.init(ImmutableList.of()).isPresent();
}
@Override
public void describeTo(final Description description) {
description.appendText("class having default constructor");
}
@Override
public void describeMismatchSafely(final ClassSubject clazz, Description description) {
description
.appendText("class ").appendValue(clazz.getOriginalName()).appendText(" did not");
}
};
}
public static Matcher<ClassSubject> isMemberClass() {
return new TypeSafeMatcher<ClassSubject>() {
@Override
public boolean matchesSafely(final ClassSubject clazz) {
return clazz.isMemberClass();
}
@Override
public void describeTo(final Description description) {
description.appendText("is member class");
}
@Override
public void describeMismatchSafely(final ClassSubject clazz, Description description) {
description.appendText("class ").appendValue(clazz.getOriginalName()).appendText(" is not");
}
};
}
public static Matcher<MethodSubject> isAbstract() {
return new TypeSafeMatcher<MethodSubject>() {
@Override
public boolean matchesSafely(final MethodSubject method) {
return method.isPresent() && method.isAbstract();
}
@Override
public void describeTo(final Description description) {
description.appendText("method abstract");
}
@Override
public void describeMismatchSafely(final MethodSubject method, Description description) {
description
.appendText("method ").appendValue(method.getOriginalName()).appendText(" was not");
}
};
}
public static <T extends MemberSubject> Matcher<T> isPrivate() {
return hasVisibility(Visibility.PRIVATE);
}
public static <T extends MemberSubject> Matcher<T> isPublic() {
return hasVisibility(Visibility.PUBLIC);
}
private static <T extends MemberSubject> Matcher<T> hasVisibility(Visibility visibility) {
return new TypeSafeMatcher<T>() {
@Override
public boolean matchesSafely(final T subject) {
if (subject.isPresent()) {
switch (visibility) {
case PUBLIC:
return subject.isPublic();
case PROTECTED:
return subject.isProtected();
case PRIVATE:
return subject.isPrivate();
case PACKAGE_PRIVATE:
return subject.isPackagePrivate();
default:
throw new Unreachable("Unexpected visibility: " + visibility);
}
}
return false;
}
@Override
public void describeTo(final Description description) {
description.appendText("method " + visibility);
}
@Override
public void describeMismatchSafely(final T subject, Description description) {
description
.appendText("method ")
.appendValue(subject.getOriginalName())
.appendText(" was ");
if (subject.isPresent()) {
AccessFlags accessFlags =
subject.isMethodSubject()
? subject.asMethodSubject().getMethod().accessFlags
: subject.asFieldSubject().getField().accessFlags;
if (accessFlags.isPublic()) {
description.appendText("public");
} else if (accessFlags.isProtected()) {
description.appendText("protected");
} else if (accessFlags.isPrivate()) {
description.appendText("private");
} else {
description.appendText("package-private");
}
} else {
description.appendText(" was absent");
}
}
};
}
}