/* * Copyright 2008 Google Inc. * * 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.gwt.dev.js; import com.google.gwt.core.ext.soyc.Range; import com.google.gwt.dev.jjs.HasSourceInfo; import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.SourceOrigin; import com.google.gwt.dev.jjs.ast.JDeclaredType; import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap; import com.google.gwt.dev.js.ast.JsName; import com.google.gwt.dev.js.ast.JsVisitable; import com.google.gwt.dev.util.TextOutput; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A variation on the standard source generation visitor that records the * locations of SourceInfo objects in the output. */ public class JsReportGenerationVisitor extends JsSourceGenerationVisitorWithSizeBreakdown { private final Map<Range, SourceInfo> sourceInfoMap = new HashMap<Range, SourceInfo>(); private final TextOutput out; public JsReportGenerationVisitor(TextOutput out, JavaToJavaScriptMap map) { super(out, map); this.out = out; } @Override protected <T extends JsVisitable> T generateAndBill(T node, JsName nameToBillTo) { if (!(node instanceof HasSourceInfo)) { return super.generateAndBill(node, nameToBillTo); } // Remember the position before generating the JavaScript. int beforePosition = out.getPosition(); int beforeLine = out.getLine(); int beforeColumn = out.getColumn(); // Write some JavaScript (changing the position). T toReturn = super.generateAndBill(node, nameToBillTo); Range javaScriptRange = new Range(beforePosition, out.getPosition(), beforeLine, beforeColumn, out.getLine(), out.getColumn()); SourceInfo defaultTarget = ((HasSourceInfo) node).getSourceInfo(); SourceInfo newTarget = findTarget(nameToBillTo, defaultTarget); sourceInfoMap.put(javaScriptRange, newTarget); return toReturn; } @Override public Map<Range, SourceInfo> getSourceInfoMap() { return Collections.unmodifiableMap(sourceInfoMap); } @Override protected <T extends JsVisitable> void doAcceptList(List<T> collection) { for (T t : collection) { doAccept(t); } } @Override protected <T extends JsVisitable> void doAcceptWithInsertRemove( List<T> collection) { for (T t : collection) { doAccept(t); } } /** * Finds the Java filename and line number that we want in the source map. * (This needs to be a relative path that makes sense as a URL.) */ private SourceInfo findTarget(JsName nameToBillTo, SourceInfo defaultTarget) { String newFilename = findTargetFile(nameToBillTo, defaultTarget.getFileName()); if (newFilename == defaultTarget.getFileName()) { return defaultTarget; } else { return SourceOrigin.create(defaultTarget.getStartLine(), newFilename); } } /** * Finds the name of the Java file that we want to put in the source map. */ private String findTargetFile(JsName nameToBillTo, String defaultFilename) { // For the filename, we really want the path passed to ResourceLoader.getResource(). // But for now, fake it based on the type name. // TODO(skybrian): fix JDeclaredType type = getDirectlyEnclosingType(nameToBillTo); if (type == null) { return defaultFilename; } // remove inner classes while (type.getEnclosingType() != null) { type = type.getEnclosingType(); } return type.getName().replace('.', '/') + ".java"; } }