Skip to content

Commit

Permalink
feat(java_indexer): emit implicit anchors for default constructors (#…
Browse files Browse the repository at this point in the history
…3317)

Emit implicit `defines` anchors for default constructors and emit
implicit `ref/call` edges for implicit `super` constructor calls (even
if the callsites are in an implicit constructor).
  • Loading branch information
schroederc committed Dec 17, 2018
1 parent e1e6fa6 commit 90d1abf
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public EntrySet newAnchorAndEmit(VName fileVName, Span loc, Span snippet) {
return null;
}
EntrySet.Builder builder =
newNode(NodeKind.ANCHOR)
newNode(loc.getStart() == loc.getEnd() ? NodeKind.ANCHOR_IMPLICIT : NodeKind.ANCHOR)
.setCorpusPath(CorpusPath.fromVName(fileVName))
.addSignatureSalt(fileVName)
.setProperty("loc/start", "" + loc.getStart())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,15 +453,17 @@ public JavaNode visitMethodDef(JCMethodDecl methodDef, TreeContext owner) {
EntrySet bindingAnchor = null;
if (methodDef.sym.isConstructor()) {
// Implicit constructors (those without syntactic definition locations) share the same
// preferred position as their owned class. Since implicit constructors don't exist in the
// file's text, don't generate anchors them by ensuring the constructor's position is ahead
// of the owner's position.
// preferred position as their owned class. We can differentiate them from other constructors
// by checking if its position is ahead of the owner's position.
if (methodDef.getPreferredPosition() > owner.getTree().getPreferredPosition()) {
// Use the owner's name (the class name) to find the definition anchor's
// location because constructors are internally named "<init>".
// Explicit constructor: use the owner's name (the class name) to find the definition
// anchor's location because constructors are internally named "<init>".
bindingAnchor =
emitDefinesBindingAnchorEdge(
ctx, methodDef.sym.owner.name, methodDef.getPreferredPosition(), methodNode);
} else {
// Implicit constructor: generate a zero-length implicit anchor
emitAnchor(ctx, EdgeKind.DEFINES, methodNode);
}
// Likewise, constructors don't have return types in the Java AST, but
// Kythe models all functions with return types. As a solution, we use
Expand Down Expand Up @@ -1000,7 +1002,7 @@ private JavaNode emitNameUsage(TreeContext ctx, Symbol sym, Name name, EdgeKind
// Ensure the context has a valid source span before searching for the Name. Otherwise, anchors
// may accidentily be emitted for Names that happen to appear after the tree context (e.g.
// lambdas with type-inferred parameters that use the parameter type in the lambda body).
if (filePositions.getSpan(ctx.getTree()).isValid()) {
if (filePositions.getSpan(ctx.getTree()).isValidAndNonZero()) {
emitAnchor(
name,
ctx.getTree().getPreferredPosition(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ public Span findBracketGroup(int startCharOffset) {

/** Returns the byte span for the given tree in the source text. */
public Span getSpan(JCTree tree) {
return new Span(getStart(tree), getEnd(tree));
int start = getStart(tree);
int end = getEnd(tree);
return start >= 0 && end == -1 ? new Span(start, start) : new Span(start, end);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions kythe/java/com/google/devtools/kythe/util/Span.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public boolean isValid() {
return start <= end && start >= 0;
}

public boolean isValidAndNonZero() {
return isValid() && start != end;
}

/** Determines if the given integer is contained within {@code this} {@link Span}. */
public boolean contains(int n) {
return getStart() <= n && n < getEnd();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,44 @@
//- @Classes defines/binding N
//- N.node/kind record
//- N.subkind class
//- DefaultCtrAnchor.loc/start @^class
//- DefaultCtrAnchor.loc/end @^class
public class Classes {

//- DefaultCtor childof N
//- DefaultCtor.node/kind function
//- DefaultCtor typed DefaultCtorType
//- DefaultCtorType param.0 FnBuiltin
//- DefaultCtorType param.1 N
//- !{ _DefaultCtorAnchor defines/binding DefaultCtor }
//- DefaultCtrAnchor defines DefaultCtor
//- !{ _DefaultCtorBindingAnchor defines/binding DefaultCtor }

private static class Subclass extends Classes {
//- ImplicitSuperCall ref/call DefaultCtor
//- ImplicitSuperCall.loc/start @^"{}"
//- ImplicitSuperCall.loc/end @^"{}"
//- ImplicitSuperCall childof SubclassCtor
//- @Subclass defines/binding SubclassCtor
Subclass() {}
}

//- @Subclass2 defines/binding SubclassTwo
//- ImplicitSubclassTwoCtorDef.node/kind anchor
//- ImplicitSubclassTwoCtorDef.subkind implicit
//- ImplicitSubclassTwoCtorDef defines ImplicitSubclassTwoCtor
//- ImplicitSubclassTwoCtorDef.loc/start @^#0class
//- ImplicitSubclassTwoCtorDef.loc/end @^#0class
//- ExtraImplicitSuperCall.node/kind anchor
//- ExtraImplicitSuperCall.subkind implicit
//- ExtraImplicitSuperCall.loc/start @^#0class
//- ExtraImplicitSuperCall.loc/end @^#0class
private static class Subclass2 extends Classes {
//- ImplicitSubclassTwoCtor.node/kind function
//- ImplicitSubclassTwoCtor.subkind constructor
//- ImplicitSubclassTwoCtor childof SubclassTwo
//- ExtraImplicitSuperCall ref/call DefaultCtor
//- ExtraImplicitSuperCall childof ImplicitSubclassTwoCtor
}

//- @StaticInner defines/binding SI
//- SI.node/kind record
Expand Down

0 comments on commit 90d1abf

Please sign in to comment.