Skip to content

Commit

Permalink
Output Kythe mapping metadata in the J2ObjC header generator.
Browse files Browse the repository at this point in the history
	Change on 2018/06/15 by duffin <duffin@google.com>

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=200768666
  • Loading branch information
duffin authored and Tom Ball committed Jul 31, 2018
1 parent b3ce6b7 commit 4f6025d
Show file tree
Hide file tree
Showing 12 changed files with 435 additions and 7 deletions.
12 changes: 12 additions & 0 deletions translator/src/main/java/com/google/devtools/j2objc/Options.java
Expand Up @@ -84,6 +84,7 @@ public class Options {
private String annotationsJar = null;
private String globalCombinedOutput = null;
private String bootclasspath = null;
private boolean emitKytheMappings = false;

private Mappings mappings = new Mappings();
private FileUtil fileUtil = new FileUtil();
Expand Down Expand Up @@ -425,6 +426,8 @@ private void processArg(Iterator<String> args) throws IOException {
translateClassfiles = true;
} else if (arg.equals("-Xannotations-jar")) {
annotationsJar = getArgValue(args, arg);
} else if (arg.equals("-Xkythe-mapping")) {
emitKytheMappings = true;
} else if (arg.equals("-version")) {
version();
} else if (arg.startsWith("-h") || arg.equals("--help")) {
Expand Down Expand Up @@ -860,6 +863,15 @@ public boolean translateBootclasspathFiles() {
return translateBootclasspath;
}

public boolean emitKytheMappings() {
return emitKytheMappings;
}

@VisibleForTesting
public void setEmitKytheMappings(boolean b) {
emitKytheMappings = b;
}

// Unreleased experimental project.
public boolean translateClassfiles() {
return translateClassfiles;
Expand Down
Expand Up @@ -26,6 +26,7 @@
public class MethodDeclaration extends BodyDeclaration {

private ExecutableElement executableElement = null;
private Name name = null;
private boolean isConstructor = false;
private boolean hasDeclaration = true;
private boolean isUnavailable = false;
Expand All @@ -38,6 +39,7 @@ public MethodDeclaration() {}
public MethodDeclaration(MethodDeclaration other) {
super(other);
executableElement = other.getExecutableElement();
name = other.getName();
isConstructor = other.isConstructor();
hasDeclaration = other.hasDeclaration();
isUnavailable = other.isUnavailable();
Expand Down Expand Up @@ -65,6 +67,17 @@ public MethodDeclaration setExecutableElement(ExecutableElement newElement) {
return this;
}

public Name getName() {
return name != null
? name
: (executableElement != null ? Name.newName(null, executableElement) : null);
}

public MethodDeclaration setName(Name newName) {
name = newName;
return this;
}

public boolean isConstructor() {
return isConstructor;
}
Expand Down
@@ -0,0 +1,99 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.devtools.j2objc.gen;

import com.google.devtools.j2objc.ast.MethodDeclaration;
import com.google.devtools.j2objc.ast.Name;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
* Contains byte-offset mappings between identifiers in a source .java file and their equivalents in
* a generated Objective-C header file.
*
* <p>These mappings may be converted to {@link
* com.google.devtools.j2objc.gen.KytheIndexingMetadata} objects to support cross-language links in
* <a href="http://kythe.io">Kythe.</a>
*/
public class GeneratedSourceMappings {

/** Maps an identifier from a byte range in a source file and target file. */
public static class Mapping {
private final String identifier;
private final int sourceBegin;
private final int sourceEnd;
private final int targetBegin;
private final int targetEnd;

private Mapping(
String identifier, int sourceBegin, int sourceEnd, int targetBegin, int targetEnd) {
this.identifier = identifier;
this.sourceBegin = sourceBegin;
this.sourceEnd = sourceEnd;
this.targetBegin = targetBegin;
this.targetEnd = targetEnd;
}

static Mapping fromMethodDeclaration(
MethodDeclaration methodDeclaration, int targetBegin, int targetEnd) {
assert methodDeclaration.getName() != null;
Name name = methodDeclaration.getName();
int sourceBegin = name.getStartPosition();
int sourceEnd = sourceBegin + name.getLength();
return new Mapping(name.toString(), sourceBegin, sourceEnd, targetBegin, targetEnd);
}

public String getIdentifier() {
return identifier;
}

public int getSourceBegin() {
return sourceBegin;
}

public int getSourceEnd() {
return sourceEnd;
}

public int getTargetBegin() {
return targetBegin;
}

public int getTargetEnd() {
return targetEnd;
}
}

private final Set<Mapping> mappings = new HashSet<>();
private int targetOffset = 0;

public void addMethodMapping(MethodDeclaration methodDeclaration, int targetBegin, int length) {
mappings.add(
Mapping.fromMethodDeclaration(methodDeclaration, targetBegin, targetBegin + length));
}

public Set<Mapping> getMappings() {
return Collections.unmodifiableSet(mappings);
}

public void setTargetOffset(int targetOffset) {
this.targetOffset = targetOffset;
}

public int getTargetOffset() {
return targetOffset;
}
}
Expand Up @@ -47,6 +47,7 @@ public class GeneratedType {
private final String publicDeclarationCode;
private final String privateDeclarationCode;
private final String implementationCode;
private final GeneratedSourceMappings generatedSourceMappings;

private GeneratedType(
String typeName,
Expand All @@ -58,7 +59,8 @@ private GeneratedType(
Set<Import> implementationIncludes,
String publicDeclarationCode,
String privateDeclarationCode,
String implementationCode) {
String implementationCode,
GeneratedSourceMappings generatedSourceMappings) {
this.typeName = Preconditions.checkNotNull(typeName);
this.isPrivate = isPrivate;
this.superTypes = Preconditions.checkNotNull(superTypes);
Expand All @@ -70,6 +72,7 @@ private GeneratedType(
this.publicDeclarationCode = Preconditions.checkNotNull(publicDeclarationCode);
this.privateDeclarationCode = Preconditions.checkNotNull(privateDeclarationCode);
this.implementationCode = Preconditions.checkNotNull(implementationCode);
this.generatedSourceMappings = Preconditions.checkNotNull(generatedSourceMappings);
}

public static GeneratedType fromTypeDeclaration(AbstractTypeDeclaration typeNode) {
Expand Down Expand Up @@ -99,7 +102,8 @@ public static GeneratedType fromTypeDeclaration(AbstractTypeDeclaration typeNode
typeNode.accept(importCollector);

SourceBuilder builder = new SourceBuilder(emitLineDirectives);
TypeDeclarationGenerator.generate(builder, typeNode);
GeneratedSourceMappings generatedSourceMappings = new GeneratedSourceMappings();
TypeDeclarationGenerator.generate(builder, typeNode, generatedSourceMappings);
String publicDeclarationCode = builder.toString();

builder = new SourceBuilder(emitLineDirectives);
Expand Down Expand Up @@ -137,7 +141,8 @@ public static GeneratedType fromTypeDeclaration(AbstractTypeDeclaration typeNode
implementationIncludes.build(),
publicDeclarationCode,
privateDeclarationCode,
implementationCode);
implementationCode,
generatedSourceMappings);
}

/**
Expand Down Expand Up @@ -187,6 +192,10 @@ public String getImplementationCode() {
return implementationCode;
}

public GeneratedSourceMappings getGeneratedSourceMappings() {
return generatedSourceMappings;
}

@Override
public String toString() {
return typeName != null ? typeName : "<no-type>";
Expand Down
@@ -0,0 +1,108 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.devtools.j2objc.gen;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* Metadata required to create links for indexing in <a href="http://kythe.io">Kythe.</a>
*
* <p>The JSON objects produced by this class conform to the format expected by Kythe's
* postprocessing pipeline; this allows Kythe to create links from source .java files to generated
* .h files.
*/
public class KytheIndexingMetadata {

/**
* A Vname is a unique identifier for a node in a Kythe semantic graph.
*
* <p>For more information, see <a href="https://kythe.io/docs/kythe-uri-spec.html">the Kythe
* documentation.</a>
*/
static class VName {
private final String corpus;
private final String path;

private VName(String corpus, String path) {
this.corpus = corpus;
this.path = path;
}

private String toJson() {
return String.format("{\"corpus\":\"%s\",\"path\":\"%s\"}", corpus, path);
}
}

static class AnchorAnchorMetadata {
private final String type = "anchor_anchor";
private final int sourceBegin;
private final int sourceEnd;
private final int targetBegin;
private final int targetEnd;
private final String edge = "/kythe/edge/imputes";
private final VName sourceVName;

AnchorAnchorMetadata(
int sourceBegin,
int sourceEnd,
int targetBegin,
int targetEnd,
String corpus,
String path) {
this.sourceBegin = sourceBegin;
this.sourceEnd = sourceEnd;
this.targetBegin = targetBegin;
this.targetEnd = targetEnd;
this.sourceVName = new VName(corpus, path);
}

private String toJson() {
return String.format(
"{\"type\":\"%s\",\"source_begin\":%d,\"source_end\":%d,\"target_begin\":%d,"
+ "\"target_end\":%d,\"edge\":\"%s\",\"source_vname\":%s}",
type, sourceBegin, sourceEnd, targetBegin, targetEnd, edge, sourceVName.toJson());
}
}

private final String type = "kythe0";
private final List<AnchorAnchorMetadata> meta = new ArrayList<>();

public void addAnchorAnchor(
int sourceBegin,
int sourceEnd,
int targetBegin,
int targetEnd,
String sourceCorpus,
String sourcePath) {
meta.add(
new AnchorAnchorMetadata(
sourceBegin, sourceEnd, targetBegin, targetEnd, sourceCorpus, sourcePath));
}

public boolean isEmpty() {
return meta.isEmpty();
}

public String toJson() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(String.format("{\"type\":\"%s\",\"meta\":[", type));
stringBuilder.append(
meta.stream().map(AnchorAnchorMetadata::toJson).collect(Collectors.joining(",")));
stringBuilder.append("]}");
return stringBuilder.toString();
}
}

0 comments on commit 4f6025d

Please sign in to comment.