Definitions.java revision 1238
349N/A/*
349N/A * CDDL HEADER START
349N/A *
349N/A * The contents of this file are subject to the terms of the
349N/A * Common Development and Distribution License (the "License").
349N/A * You may not use this file except in compliance with the License.
349N/A *
349N/A * See LICENSE.txt included in this distribution for the specific
349N/A * language governing permissions and limitations under the License.
349N/A *
349N/A * When distributing Covered Code, include this CDDL HEADER in each
349N/A * file and include the License file at LICENSE.txt.
349N/A * If applicable, add the following below this CDDL HEADER, with the
349N/A * fields enclosed by brackets "[]" replaced with your own identifying
349N/A * information: Portions Copyright [yyyy] [name of copyright owner]
349N/A *
349N/A * CDDL HEADER END
349N/A */
349N/A
349N/A/*
1071N/A * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
349N/A */
349N/A
349N/Apackage org.opensolaris.opengrok.analysis;
349N/A
350N/Aimport java.io.ByteArrayInputStream;
350N/Aimport java.io.ByteArrayOutputStream;
350N/Aimport java.io.IOException;
350N/Aimport java.io.ObjectInputStream;
350N/Aimport java.io.ObjectOutputStream;
350N/Aimport java.io.Serializable;
349N/Aimport java.util.ArrayList;
349N/Aimport java.util.HashMap;
349N/Aimport java.util.HashSet;
349N/Aimport java.util.List;
349N/Aimport java.util.Map;
349N/Aimport java.util.Set;
349N/A
350N/Apublic class Definitions implements Serializable {
1238N/A private static final long serialVersionUID = 1191703801007779489L;
1089N/A
1108N/A // Per line sym -> tags mapping
1108N/A public static class LineTagMap implements Serializable {
1238N/A private static final long serialVersionUID = 1191703801007779481L;
1112N/A private final Map<String, Set<Tag>> sym_tags; //NOPMD
1108N/A
1108N/A protected LineTagMap() {
1108N/A this.sym_tags = new HashMap<String, Set<Tag>>();
1108N/A }
1181N/A }
1108N/A // line -> tag_map
1108N/A private final Map<Integer, LineTagMap> line_maps;
1108N/A
349N/A /** Map from symbol to the line numbers on which the symbol is defined. */
349N/A private final Map<String, Set<Integer>> symbols;
349N/A /** List of all the tags. */
349N/A private final List<Tag> tags;
349N/A
1071N/A public Definitions() {
349N/A symbols = new HashMap<String, Set<Integer>>();
1108N/A line_maps = new HashMap<Integer, LineTagMap>();
349N/A tags = new ArrayList<Tag>();
349N/A }
349N/A
349N/A /**
349N/A * Get all symbols used in definitions.
349N/A * @return a set containing all the symbols
349N/A */
349N/A public Set<String> getSymbols() {
349N/A return symbols.keySet();
349N/A }
349N/A
349N/A /**
349N/A * Check if there is a tag for a symbol.
349N/A * @param symbol the symbol to check
349N/A * @return {@code true} iff there is a tag for {@code symbol}
349N/A */
349N/A public boolean hasSymbol(String symbol) {
349N/A return symbols.containsKey(symbol);
349N/A }
349N/A
349N/A /**
349N/A * Check whether the specified symbol is defined on the given line.
349N/A * @param symbol the symbol to look for
349N/A * @param lineNumber the line to check
1108N/A * @param strs type of definition(to be passed back to caller)
349N/A * @return {@code true} iff {@code symbol} is defined on the specified line
349N/A */
1108N/A public boolean hasDefinitionAt(String symbol, int lineNumber, String[] strs) {
349N/A Set<Integer> lines = symbols.get(symbol);
1108N/A if (strs.length > 0) {
1108N/A strs[0] = "none";
1108N/A }
1108N/A
1108N/A // Get tag info
1108N/A if (lines != null && lines.contains(lineNumber)) {
1108N/A LineTagMap line_map = line_maps.get(lineNumber);
1108N/A if (line_map != null) {
1185N/A for (Tag tag : line_map.sym_tags.get(symbol)) {
1112N/A if (strs.length > 0) { //NOPMD
1108N/A strs[0] = tag.type;
1108N/A }
1108N/A // Assume the first one
1108N/A break;
1108N/A }
1108N/A }
1108N/A return true;
1108N/A }
1108N/A return false;
349N/A }
349N/A
349N/A /**
349N/A * Return the number of occurrences of definitions with the specified
349N/A * symbol.
349N/A * @param symbol the symbol to count the occurrences of
349N/A * @return the number of times the specified symbol is defined
349N/A */
349N/A public int occurrences(String symbol) {
349N/A Set<Integer> lines = symbols.get(symbol);
349N/A return lines == null ? 0 : lines.size();
349N/A }
349N/A
349N/A /**
349N/A * Return the number of distinct symbols.
349N/A * @return number of distinct symbols
349N/A */
349N/A public int numberOfSymbols() {
349N/A return symbols.size();
349N/A }
349N/A
349N/A /**
349N/A * Get a list of all tags.
349N/A * @return all tags
349N/A */
349N/A public List<Tag> getTags() {
349N/A return tags;
349N/A }
349N/A
349N/A /**
349N/A * Class that represents a single tag.
349N/A */
438N/A public static class Tag implements Serializable {
1238N/A private static final long serialVersionUID = 1217869075425651464L;
1089N/A
349N/A /** Line number of the tag. */
349N/A public final int line;
349N/A /** The symbol used in the definition. */
349N/A public final String symbol;
349N/A /** The type of the tag. */
349N/A public final String type;
349N/A /** The full line on which the definition occurs. */
349N/A public final String text;
349N/A
589N/A protected Tag(int line, String symbol, String type, String text) {
349N/A this.line = line;
349N/A this.symbol = symbol;
349N/A this.type = type;
349N/A this.text = text;
349N/A }
349N/A }
349N/A
1071N/A public void addTag(int line, String symbol, String type, String text) {
351N/A // The strings are frequently repeated (a symbol can be used in
351N/A // multiple definitions, multiple definitions can have the same type,
351N/A // one line can contain multiple definitions). Intern them to minimize
351N/A // the space consumed by them (see bug #809).
415N/A final String internedSymbol = symbol.intern();
415N/A final String internedType = type.intern();
415N/A final String internedText = text.intern();
1108N/A Tag new_tag = new Tag(line, internedSymbol, internedType, internedText);
1108N/A tags.add(new_tag);
415N/A Set<Integer> lines = symbols.get(internedSymbol);
349N/A if (lines == null) {
349N/A lines = new HashSet<Integer>();
415N/A symbols.put(internedSymbol, lines);
349N/A }
1202N/A Integer aLine = Integer.valueOf(line);
1185N/A lines.add(aLine);
1108N/A
1108N/A // Get per line map
1185N/A LineTagMap line_map = line_maps.get(aLine);
1108N/A if (line_map == null) {
1108N/A line_map = new LineTagMap();
1185N/A line_maps.put(aLine, line_map);
1108N/A }
1108N/A
1108N/A // Insert sym->tag map for this line
1108N/A Set<Tag> tags = line_map.sym_tags.get(internedSymbol);
1108N/A if (tags == null) {
1108N/A tags = new HashSet<Tag>();
1108N/A line_map.sym_tags.put(internedSymbol, tags);
1108N/A }
1108N/A tags.add(new_tag);
349N/A }
350N/A
350N/A /**
350N/A * Create a binary representation of this object.
350N/A * @return a byte array representing this object
350N/A * @throws IOException if an error happens when writing to the array
350N/A */
350N/A public byte[] serialize() throws IOException {
350N/A ByteArrayOutputStream bytes = new ByteArrayOutputStream();
350N/A new ObjectOutputStream(bytes).writeObject(this);
350N/A return bytes.toByteArray();
350N/A }
350N/A
350N/A /**
350N/A * Deserialize a binary representation of a {@code Definitions} object.
350N/A * @param bytes a byte array containing the {@code Definitions} object
350N/A * @return a {@code Definitions} object
350N/A * @throws IOException if an I/O error happens when reading the array
350N/A * @throws ClassNotFoundException if the class definition for an object
350N/A * stored in the byte array cannot be found
350N/A * @throws ClassCastException if the array contains an object of another
350N/A * type than {@code Definitions}
350N/A */
350N/A public static Definitions deserialize(byte[] bytes)
350N/A throws IOException, ClassNotFoundException {
350N/A ObjectInputStream in =
350N/A new ObjectInputStream(new ByteArrayInputStream(bytes));
350N/A return (Definitions) in.readObject();
350N/A }
349N/A}