All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.NameReferenceGraphReport Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs.

There is a newer version: v20250528
Show newest version
/*
 * Copyright 2009 The Closure Compiler Authors.
 *
 * 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.javascript.jscomp;

import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.javascript.jscomp.NameReferenceGraph.Name;
import com.google.javascript.jscomp.NameReferenceGraph.Reference;
import com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge;
import com.google.javascript.jscomp.graph.DiGraph.DiGraphNode;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.JSType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Generate a nice HTML file describing the name reference graph.
 * For each declaration, list the sites where the declaration's name
 * is referenced, and list all the names that the declaration references.
 * For each, name exactly where use occurs in the source code.
 *
 * 

This report should be useful both for internal compiler * developers and for engineers trying to understand running behavior * of their code or who want to understand why the compiler won't * move their code into a new module. * * @author [email protected] (Robert Bowdidge) */ final class NameReferenceGraphReport { private NameReferenceGraph graph = null; /** * Create a NameReferenceGraphReport object. * * @param g name reference graph to describe in report. */ NameReferenceGraphReport(NameReferenceGraph g) { this.graph = g; } /** * Generate a nice HTML file describing the name reference graph. * For each declaration, list the sites where the declaration's name * is referenced, and list all the names that the declaration references. * For each, name exactly where use occurs in the source code. * *

This report should be useful both for internal compiler * developers and for engineers trying to understand running * behavior of their code or who want to understand why * AbstractCompiler won't move their code into a new module. * * @return String containing the entire HTML for the report. */ public String getHtmlReport() { StringBuilder builder = new StringBuilder(); List> nodes = new ArrayList<>(); Iterables.addAll(nodes, graph.getDirectedGraphNodes()); generateHtmlReportHeader(builder); builder.append("

Name Reference Graph Dump

\n"); builder.append("OVERALL STATS\n"); builder.append("
    \n"); builder.append("
  • Total names: ").append(nodes.size()); builder.append("
\n"); builder.append("ALL NAMES\n"); builder.append("
    \n"); // Sort declarations in alphabetical order. Collections.sort(nodes, new DiGraphNodeComparator()); for (DiGraphNode n : nodes) { // Generate the HTML describing the declaration itself. generateDeclarationReport(builder, n); // Next, list the places where this name is used (REFERS TO), and the // names that this declaration refers to (REFERENCED BY). List> outEdges = graph.getOutEdges(n.getValue()); List> inEdges = graph.getInEdges(n.getValue()); // Don't bother to create the dotted list if we don't have anything to // put in it. if (!outEdges.isEmpty() || !inEdges.isEmpty()) { builder.append("
      "); if (!outEdges.isEmpty()) { builder.append("
    • REFERS TO:
      \n"); builder.append("
        "); for (DiGraphEdge edge : outEdges) { generateEdgeReport(builder, edge.getDestination().getValue(), edge); } builder.append("
      \n"); } if (!inEdges.isEmpty()) { builder.append("
    • REFERENCED BY:
      \n"); builder.append("
        "); for (DiGraphEdge edge : inEdges) { generateEdgeReport(builder, edge.getSource().getValue(), edge); } builder.append("
      "); } builder.append("
    \n"); } } builder.append("
\n"); generateHtmlReportFooter(builder); return builder.toString(); } /** * Given a node, find the name of the containing source file. * * @param node Parse tree node whose filename is requested * @return String containing name of source file, or empty string if name * cannot be identified. */ private static String getSourceFile(Node node) { String filename = node.getSourceFileName(); if (filename == null) { return ""; } return filename; } /** * Generate the HTML for describing a specific declaration. * @param builder contents of report to be generated * @param declarationNode declaration to describe */ private void generateDeclarationReport(StringBuilder builder, DiGraphNode declarationNode) { // Provide the name and location of declaration, // with an anchor to allow navigation to this declaration. String declName = declarationNode.getValue().getQualifiedName(); JSType declType = declarationNode.getValue().getType(); builder.append("
  • "); builder.append(""); builder.append(declName); builder.append("\n"); // Provide the type of the declaration. // This is helpful for debugging. generateType(builder, declType); // List all the definitions of this name that were found in the code. // For each, list List defs = declarationNode.getValue().getDeclarations(); if (defs.isEmpty()) { builder.append("
    No definitions found
    "); } else { // Otherwise, provide a list of definitions in a dotted list. // For each definition, print the location where that definition is // found. builder.append("
      "); for (DefinitionsRemover.Definition def : defs) { Node fnDef = def.getRValue(); String sourceFileName = getSourceFile(fnDef); builder.append("
    • Defined: "); generateSourceReferenceLink(builder, sourceFileName, fnDef.getLineno(), fnDef.getCharno()); } builder.append("
    "); } } /** * Generate the HTML header for the report style. * Borrowed straight from NameAnalyzer's report style. * * @param builder contents of the report to be generated */ private static void generateHtmlReportHeader(StringBuilder builder) { builder.append("\n" + "" + "" + "" + "Name Reference Graph Dump" + "\n"); } /** * Generate the HTML footer for the report style. */ private static void generateHtmlReportFooter(StringBuilder builder) { builder.append(""); } /** * Generate a description of a specific edge between two nodes. * For each edge, name the element being linked, the location of the * reference in the source file, and the type of the reference. * * @param builder contents of the report to be generated * @param referencedDecl name of the declaration being referenced * @param edge the graph edge being described */ private void generateEdgeReport(StringBuilder builder, Name referencedDecl, DiGraphEdge edge) { String srcDeclName = referencedDecl.getQualifiedName(); builder.append("
  • "); builder.append(srcDeclName); builder.append(" "); Node def = edge.getValue().getSite(); int lineNumber = def.getLineno(); int columnNumber = def.getCharno(); String sourceFile = getSourceFile(def); generateSourceReferenceLink(builder, sourceFile, lineNumber, columnNumber); JSType defType = edge.getValue().getSite().getJSType(); generateType(builder, defType); } /** * Generate a link and text for a reference to a particular location * in a source file. Selecting the link should take the programmer * to a browsable version of the file. * * @param builder contents of the report to be generated * @param sourceFile Path to the file * @param lineNumber line where the object to view is located * @param columnNumber column where the object to highlight is located. */ private static void generateSourceReferenceLink(StringBuilder builder, String sourceFile, int lineNumber, int columnNumber) { assert(sourceFile != null); builder.append("("); // Print out the text path so the user knows where things come from. builder.append(sourceFile).append(":").append(lineNumber).append(",").append(columnNumber); builder.append(")"); } /** * Dump a type in a nice, readable way. * * @param builder contents of the report to be generated. * @param defType type to describe */ private static void generateType(StringBuilder builder, JSType defType) { if (defType == null) { builder.append(" (type: null) "); } else if (defType.isUnknownType()) { builder.append(" (type: unknown) "); } else { builder.append(" (type: ").append(defType).append(") "); } } /** * DiGraphNodeComparator gives us a way to generate sorted lists * of DiGraphNodes. It provides a compare function used by the * String class's sort method. */ class DiGraphNodeComparator implements Comparator> { @Override public int compare(DiGraphNode node1, DiGraphNode node2) { Preconditions.checkNotNull(node1.getValue()); Preconditions.checkNotNull(node2.getValue()); if ((node1.getValue().getQualifiedName() == null) && (node2.getValue().getQualifiedName() == null)) { return 0; } // Node 1, if null, comes before node 2. if (node1.getValue().getQualifiedName() == null) { return -1; } // Node 2, if null, comes before node 1. if (node2.getValue().getQualifiedName() == null) { return 1; } return node1.getValue().getQualifiedName().compareTo( node2.getValue().getQualifiedName()); } } }




  • © 2015 - 2025 Weber Informatics LLC | Privacy Policy