Skip to content

Commit

Permalink
feat(jvm_indexer): allow JVM nodes to be refined by corpus/root/path (#…
Browse files Browse the repository at this point in the history
…4204)

It may be desirable to separate JVM nodes by corpus (and possibly
root/path).  This is important when mixing two similar corpora that
defines many of the same JVM entities that should not be considered
identical.  It is left up to the indexer whether to incorporate a
corpus/root/path into their emitted JVM nodes.
  • Loading branch information
schroederc committed Nov 14, 2019
1 parent 43e9e65 commit 952d156
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@

package com.google.devtools.kythe.analyzers.base;

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.devtools.kythe.proto.Storage.VName;

/** Path within a particular corpus and corpus root. */
public final class CorpusPath {
/** The empty {@link CorpusPath}. */
public static final CorpusPath EMPTY = new CorpusPath("", "", "");

private final String corpus, root, path;

public CorpusPath(String corpus, String root, String path) {
Preconditions.checkNotNull(corpus, "corpus must be non-null");
Preconditions.checkNotNull(root, "root must be non-null");
Preconditions.checkNotNull(path, "path must be non-null");
this.corpus = corpus;
this.root = root;
this.path = path;
Expand All @@ -47,4 +56,19 @@ public String getRoot() {
public String getPath() {
return path;
}

/** Returns a {@link VName.Builder} equivalent to this {@link CorpusPath}. */
public VName.Builder toVNameBuilder() {
return VName.newBuilder().setCorpus(corpus).setRoot(root).setPath(path);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues()
.add("corpus", Strings.emptyToNull(corpus))
.add("root", Strings.emptyToNull(root))
.add("path", Strings.emptyToNull(path))
.toString();
}
}
11 changes: 4 additions & 7 deletions kythe/java/com/google/devtools/kythe/analyzers/jvm/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,17 @@ languages together. Each JVM VName will have its language component set to
"jvm" and have a well-defined signature corresponding to a JVM entity using the
entity's qualified named (and possibly a differentiating JVM type descriptor).
These VName signatures are unrelated to the JVM concept of a signature. All
other VName fields (i.e. corpus/root/path) are empty. See below for
other VName fields (i.e. corpus/root/path) can be left empty. See below for
descriptions of each signature per node kind.

```
signature: <qualified_name> + <type_descriptor>?
language: "jvm"
corpus: <empty>
root: <empty>
path: <empty>
```

It is left to future iterations to use the corpus/root/path components to
possibly differentiate between same-named JVM entities generated across corpora
(or Java modules).
A JVM VName *may* be refined by a corpus/root/path to distinguish between JVM
nodes that share a signature but should not be considered identical. Usually
only a non-empty corpus is necessary to make these distinctions.

#### JVM nodes

Expand Down
126 changes: 111 additions & 15 deletions kythe/java/com/google/devtools/kythe/analyzers/jvm/JvmGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.devtools.kythe.analyzers.base.CorpusPath;
import com.google.devtools.kythe.analyzers.base.EntrySet;
import com.google.devtools.kythe.analyzers.base.FactEmitter;
import com.google.devtools.kythe.analyzers.base.KytheEntrySets;
Expand Down Expand Up @@ -55,42 +56,85 @@ public KytheEntrySets getKytheEntrySets() {
}

/** Returns the {@link VName} corresponding to the given class/enum/interface type. */
@Deprecated
public static VName getReferenceVName(Type.ReferenceType referenceType) {
return VName.newBuilder()
return getReferenceVName(CorpusPath.EMPTY, referenceType);
}

/** Returns the {@link VName} corresponding to the given class/enum/interface type. */
public static VName getReferenceVName(CorpusPath corpusPath, Type.ReferenceType referenceType) {
return corpusPath
.toVNameBuilder()
.setSignature(referenceType.qualifiedName)
.setLanguage(JVM_LANGUAGE)
.build();
}

/** Returns the {@link VName} corresponding to the given method type. */
@Deprecated
public static VName getMethodVName(
Type.ReferenceType parentClass, String name, Type.MethodType methodType) {
return VName.newBuilder()
return getMethodVName(CorpusPath.EMPTY, parentClass, name, methodType);
}

/** Returns the {@link VName} corresponding to the given method type. */
public static VName getMethodVName(
CorpusPath corpusPath,
Type.ReferenceType parentClass,
String name,
Type.MethodType methodType) {
return corpusPath
.toVNameBuilder()
.setSignature(methodSignature(parentClass, name, methodType))
.setLanguage(JVM_LANGUAGE)
.build();
}

/**
* Returns the {@link VName} corresponding to the given parameter of a method type.
*
* <p>Parameter indices are used because names are only optionally retained in class files and not
* required by the spec.
*/
@Deprecated
public static VName getParameterVName(
Type.ReferenceType parentClass,
String methodName,
Type.MethodType methodType,
int parameterIndex) {
return getParameterVName(CorpusPath.EMPTY, parentClass, methodName, methodType, parameterIndex);
}

/**
* Returns the {@link VName} corresponding to the given parameter of a method type.
*
* <p>Parameter indices are used because names are only optionally retained in class files and not
* required by the spec.
*/
public static VName getParameterVName(
CorpusPath corpusPath,
Type.ReferenceType parentClass,
String methodName,
Type.MethodType methodType,
int parameterIndex) {
return VName.newBuilder()
return corpusPath
.toVNameBuilder()
.setSignature(parameterSignature(parentClass, methodName, methodType, parameterIndex))
.setLanguage(JVM_LANGUAGE)
.build();
}

/** Returns the {@link VName} corresponding to the given field type. */
@Deprecated
public static VName getFieldVName(Type.ReferenceType parentClass, String name) {
return VName.newBuilder()
return getFieldVName(CorpusPath.EMPTY, parentClass, name);
}

/** Returns the {@link VName} corresponding to the given field type. */
public static VName getFieldVName(
CorpusPath corpusPath, Type.ReferenceType parentClass, String name) {
return corpusPath
.toVNameBuilder()
.setSignature(parentClass.qualifiedName + "." + name)
.setLanguage(JVM_LANGUAGE)
.build();
Expand All @@ -110,55 +154,107 @@ private static String parameterSignature(
}

/** Emits and returns a Kythe {@code record} node for a JVM class. */
@Deprecated
public VName emitClassNode(Type.ReferenceType refType) {
return emitNode(NodeKind.RECORD_CLASS, refType.qualifiedName, markedSource(refType));
return emitClassNode(CorpusPath.EMPTY, refType);
}

/** Emits and returns a Kythe {@code record} node for a JVM class. */
public VName emitClassNode(CorpusPath corpusPath, Type.ReferenceType refType) {
return emitNode(
NodeKind.RECORD_CLASS, getReferenceVName(corpusPath, refType), markedSource(refType));
}

/** Emits and returns a Kythe {@code interface} node for a JVM interface. */
@Deprecated
public VName emitInterfaceNode(Type.ReferenceType refType) {
return emitNode(NodeKind.INTERFACE, refType.qualifiedName, markedSource(refType));
return emitInterfaceNode(CorpusPath.EMPTY, refType);
}
/** Emits and returns a Kythe {@code interface} node for a JVM interface. */
public VName emitInterfaceNode(CorpusPath corpusPath, Type.ReferenceType refType) {
return emitNode(
NodeKind.INTERFACE, getReferenceVName(corpusPath, refType), markedSource(refType));
}

/** Emits and returns a Kythe {@code sum} node for a JVM enum class. */
@Deprecated
public VName emitEnumNode(Type.ReferenceType refType) {
return emitNode(NodeKind.SUM_ENUM_CLASS, refType.qualifiedName, markedSource(refType));
return emitEnumNode(CorpusPath.EMPTY, refType);
}

/** Emits and returns a Kythe {@code sum} node for a JVM enum class. */
public VName emitEnumNode(CorpusPath corpusPath, Type.ReferenceType refType) {
return emitNode(
NodeKind.SUM_ENUM_CLASS, getReferenceVName(corpusPath, refType), markedSource(refType));
}

/** Emits and returns a Kythe {@code variable} node for a JVM field. */
@Deprecated
public VName emitFieldNode(Type.ReferenceType parentClass, String name) {
return emitNode(NodeKind.VARIABLE_FIELD, parentClass.qualifiedName + "." + name);
return emitFieldNode(CorpusPath.EMPTY, parentClass, name);
}

/** Emits and returns a Kythe {@code variable} node for a JVM field. */
public VName emitFieldNode(CorpusPath corpusPath, Type.ReferenceType parentClass, String name) {
return emitNode(NodeKind.VARIABLE_FIELD, getFieldVName(corpusPath, parentClass, name));
}

/** Emits and returns a Kythe {@code function} node for a JVM method. */
@Deprecated
public VName emitMethodNode(
Type.ReferenceType parentClass, String methodName, Type.MethodType type) {
return emitMethodNode(CorpusPath.EMPTY, parentClass, methodName, type);
}

/** Emits and returns a Kythe {@code function} node for a JVM method. */
public VName emitMethodNode(
CorpusPath corpusPath,
Type.ReferenceType parentClass,
String methodName,
Type.MethodType type) {
return emitNode(
methodName.equals("<init>") ? NodeKind.FUNCTION_CONSTRUCTOR : NodeKind.FUNCTION,
methodSignature(parentClass, methodName, type));
getMethodVName(corpusPath, parentClass, methodName, type));
}

/**
* Emits and returns a Kythe {@code variable/local/parameter} node for a JVM parameter to a
* method.
*
* @see #getParameterVName(Type.ReferenceType, String, Type.MethodType, int)
*/
@Deprecated
public VName emitParameterNode(
Type.ReferenceType parentClass,
String methodName,
Type.MethodType methodType,
int parameterIndex) {
return emitParameterNode(CorpusPath.EMPTY, parentClass, methodName, methodType, parameterIndex);
}

/**
* Emits and returns a Kythe {@code variable/local/parameter} node for a JVM parameter to a
* method.
*
* @see #getParameterVName(ReferenceType, String, MethodType, int)
* @see #getParameterVName(Type.ReferenceType, String, Type.MethodType, int)
*/
public VName emitParameterNode(
CorpusPath corpusPath,
Type.ReferenceType parentClass,
String methodName,
Type.MethodType methodType,
int parameterIndex) {
return emitNode(
NodeKind.VARIABLE_PARAMETER,
parameterSignature(parentClass, methodName, methodType, parameterIndex));
getParameterVName(corpusPath, parentClass, methodName, methodType, parameterIndex));
}

private VName emitNode(NodeKind nodeKind, String signature) {
return emitNode(nodeKind, signature, null);
private VName emitNode(NodeKind nodeKind, VName name) {
return emitNode(nodeKind, name, null);
}

private VName emitNode(NodeKind nodeKind, String signature, MarkedSource markedSource) {
NodeBuilder builder = entrySets.newNode(nodeKind).setSignature(signature);
private VName emitNode(NodeKind nodeKind, VName name, MarkedSource markedSource) {
NodeBuilder builder = entrySets.newNode(nodeKind, name);
if (markedSource != null) {
builder.setProperty("code", markedSource);
}
Expand Down

0 comments on commit 952d156

Please sign in to comment.