Skip to content

Commit

Permalink
feat(java): emit visibility and other modifier facts (#4886)
Browse files Browse the repository at this point in the history
Adds support for
 * visibility = {public, private, package, protected}

Also adds support for
 * tag/volatile
 * tag/abstract
 * tag/default
  • Loading branch information
jaysachs committed Apr 14, 2021
1 parent 2b175da commit 04347f6
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 14 deletions.
Expand Up @@ -337,9 +337,8 @@ public JavaNode visitClassDef(JCClassDecl classDef, TreeContext owner) {
// initializers. But there's no harm in emitting the same fact twice!
getScope(ctx).forEach(scope -> entrySets.emitEdge(classNode, EdgeKind.CHILDOF, scope));

if (classDef.getModifiers().getFlags().contains(Modifier.STATIC)) {
emitStatic(classNode);
}
emitModifiers(classNode, classDef.getModifiers());
emitVisibility(classNode, classDef.getModifiers(), ctx);

NestingKind nestingKind = classDef.sym.getNestingKind();
if (nestingKind != NestingKind.LOCAL
Expand Down Expand Up @@ -388,10 +387,6 @@ public JavaNode visitClassDef(JCClassDecl classDef, TreeContext owner) {
emitComment(classDef, classNode);
}

if (classDef.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
entrySets.getEmitter().emitFact(classNode, "/kythe/tag/abstract", "");
}

visitAnnotations(classNode, classDef.getModifiers().getAnnotations(), ctx);

JavaNode superClassNode = scan(classDef.getExtendsClause(), ctx);
Expand Down Expand Up @@ -538,9 +533,8 @@ public JavaNode visitMethodDef(JCMethodDecl methodDef, TreeContext owner) {
VName methodNode =
entrySets.getNode(signatureGenerator, methodDef.sym, signature.get(), markedSource, null);
visitAnnotations(methodNode, methodDef.getModifiers().getAnnotations(), ctx);
if (methodDef.getModifiers().getFlags().contains(Modifier.STATIC)) {
emitStatic(methodNode);
}
emitModifiers(methodNode, methodDef.getModifiers());
emitVisibility(methodNode, methodDef.getModifiers(), ctx);

EntrySet absNode =
defineTypeParameters(
Expand Down Expand Up @@ -736,9 +730,11 @@ public JavaNode visitVarDef(JCVariableDecl varDef, TreeContext owner) {
getScope(ctx).forEach(scope -> entrySets.emitEdge(varNode, EdgeKind.CHILDOF, scope));
visitAnnotations(varNode, varDef.getModifiers().getAnnotations(), ctx);

emitModifiers(varNode, varDef.getModifiers());
if (varDef.sym.getKind().isField()) {
emitVisibility(varNode, varDef.getModifiers(), ctx);
}
if (varDef.getModifiers().getFlags().contains(Modifier.STATIC)) {
emitStatic(varNode);

if (varDef.sym.getKind().isField() && owner.getNode().getClassInit().isPresent()) {
ctx.setNode(new JavaNode(owner.getNode().getClassInit().get()));
}
Expand Down Expand Up @@ -1269,6 +1265,39 @@ private static ImmutableList<VName> getCallScope(TreeContext ctx) {
return getScope(ctx);
}

static enum Visibility {
PUBLIC("public"),
PACKAGE("package"),
PRIVATE("private"),
PROTECTED("protected");

private Visibility(String factValue) {
this.factValue = factValue;
}

final String factValue;

static Visibility get(JCModifiers modifiers, TreeContext ctx) {
if (modifiers.getFlags().contains(Modifier.PUBLIC)) {
return PUBLIC;
}
if (modifiers.getFlags().contains(Modifier.PRIVATE)) {
return PRIVATE;
}
if (modifiers.getFlags().contains(Modifier.PROTECTED)) {
return PROTECTED;
}
JCClassDecl parent = ctx.getClassParentDecl();
if (parent == null) {
return PACKAGE;
}
if (parent.getKind().equals(Kind.INTERFACE)) {
return PUBLIC;
}
return PACKAGE;
}
}

private static ImmutableList<VName> getScope(TreeContext ctx) {
return Optional.ofNullable(ctx.getScope())
.map(TreeContext::getNode)
Expand Down Expand Up @@ -1439,8 +1468,28 @@ private void emitDeprecated(Optional<String> deprecation, VName node) {
deprecation.ifPresent(d -> entrySets.getEmitter().emitFact(node, "/kythe/tag/deprecated", d));
}

private void emitStatic(VName node) {
entrySets.getEmitter().emitFact(node, "/kythe/tag/static", "");
private void emitModifiers(VName node, JCModifiers modifiers) {
if (modifiers.getFlags().contains(Modifier.ABSTRACT)) {
entrySets.getEmitter().emitFact(node, "/kythe/tag/abstract", "");
}

if (modifiers.getFlags().contains(Modifier.STATIC)) {
entrySets.getEmitter().emitFact(node, "/kythe/tag/static", "");
}

if (modifiers.getFlags().contains(Modifier.VOLATILE)) {
entrySets.getEmitter().emitFact(node, "/kythe/tag/volatile", "");
}

if (modifiers.getFlags().contains(Modifier.DEFAULT)) {
entrySets.getEmitter().emitFact(node, "/kythe/tag/default", "");
}
}

private void emitVisibility(VName node, JCModifiers modifiers, TreeContext ctx) {
entrySets
.getEmitter()
.emitFact(node, "/kythe/visibility", Visibility.get(modifiers, ctx).factValue);
}

// Unwraps the target EntrySet and emits an edge to it from the sourceNode
Expand Down
Expand Up @@ -94,6 +94,17 @@ public TreeContext getMethodParent() {
return parent;
}

public JCClassDecl getClassParentDecl() {
TreeContext parent = up();
while (parent != null && !(parent.getTree() instanceof JCClassDecl)) {
parent = parent.up();
}
if (parent == null) {
return null;
}
return (JCClassDecl) parent.getTree();
}

public TreeContext getScope() {
TreeContext parent = up();
while (parent != null
Expand Down
Expand Up @@ -355,6 +355,18 @@ java_verifier_test(
srcs = ["StaticVariables.java"],
)

java_verifier_test(
name = "visibility_tests",
size = "small",
srcs = ["Visibility.java"],
)

java_verifier_test(
name = "modifier_tests",
size = "small",
srcs = ["Modifiers.java"],
)

java_verifier_test(
name = "package_tests",
size = "small",
Expand Down
@@ -0,0 +1,49 @@
package pkg;

@SuppressWarnings("unused")
//- @Modifiers defines/binding AbstractClass
public abstract class Modifiers {

//- @privMember defines/binding PrivateMember
private int privMember;
//- @volMember defines/binding VolatileMember
private volatile int volMember;
//- @volStatic defines/binding VolatileStatic
private static volatile int volStatic;

//- @method defines/binding Method
int method() {
return 0;
}

//- @absmethod defines/binding AbstractMethod
abstract int absmethod();

//- @Clazz defines/binding Class
class Clazz { }

//- @Intf defines/binding Interface
interface Intf {
//- @func defines/binding IMethod
int func();

//- @defFunc defines/binding DefaultMethod
default int defFunc() {
return 0;
}
}
}

//- !{ PrivateMember.tag/volatile _ }
//- VolatileMember.tag/volatile _
//- VolatileStatic.tag/volatile _

//- !{ IMethod.tag/default _ }
//- DefaultMethod.tag/default _

//- !{ Method.tag/abstract _ }
//- AbstractMethod.tag/abstract _

//- !{ Class.tag/abstract _ }
//- AbstractClass.tag/abstract _
//- !{ Interface.tag/abstract _ }
@@ -0,0 +1,89 @@
package pkg;

@SuppressWarnings("unused")
public class Visibility {

//- @privMember defines/binding PrivateMember
private int privMember;

//- @defMember defines/binding DefaultMember
int defMember;

//- @protMember defines/binding ProtectedMember
protected int protMember;

//- @pubMember defines/binding PublicMember
public int pubMember;

//- @privMethod defines/binding PrivateMethod
private int privMethod() {
return 0;
}

//- @defMethod defines/binding DefaultMethod
int defMethod() {
return 0;
}

//- @protMethod defines/binding ProtectedMethod
protected int protMethod() {
return 0;
}

//- @pubMethod defines/binding PublicMethod
public int pubMethod() {

//- @local defines/binding LocalVar
int local = 0;
return local;
}

//- @PrivClass defines/binding PrivateClass
private class PrivClass {}

//- @DefClass defines/binding DefaultClass
class DefClass {}

//- @ProtClass defines/binding ProtectedClass
protected class ProtClass {}

//- @PubClass defines/binding PublicClass
public class PubClass {}

//- @DefIntf defines/binding DefaultInterface
interface DefIntf {
//- @f defines/binding DefaultInterfaceMethod
int f();
}

//- @DefEnum defines/binding DefaultEnum
enum DefEnum {
//- @X defines/binding EnumValueX
X,
Y;
}
}

//- PrivateMember.visibility private
//- DefaultMember.visibility package
//- ProtectedMember.visibility protected
//- PublicMember.visibility public

//- PrivateMethod.visibility private
//- DefaultMethod.visibility package
//- ProtectedMethod.visibility protected
//- PublicMethod.visibility public

//- PrivateClass.visibility private
//- DefaultClass.visibility package
//- ProtectedClass.visibility protected
//- PublicClass.visibility public

//- !{ LocalVar.visibility _ }

//- DefaultInterface.visibility package
//- DefaultInterfaceMethod.visibility public

//- DefaultEnum.visibility package
// N.B. enum values are tagged as public, final and static by the Java compiler.
//- EnumValueX.visibility public

0 comments on commit 04347f6

Please sign in to comment.