001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020
021 package org.sonar.batch.symbol;
022
023 import com.google.common.collect.SortedSetMultimap;
024 import com.google.common.collect.TreeMultimap;
025 import org.sonar.api.batch.sensor.symbol.Symbol;
026 import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder;
027 import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbol;
028 import org.sonar.batch.index.ComponentDataCache;
029 import org.sonar.core.source.SnapshotDataTypes;
030
031 import java.io.Serializable;
032 import java.util.Comparator;
033
034 public class DefaultSymbolTableBuilder implements SymbolTableBuilder {
035
036 private final String componentKey;
037 private final ComponentDataCache cache;
038 private final SortedSetMultimap<Symbol, Integer> referencesBySymbol;
039
040 public DefaultSymbolTableBuilder(String componentKey, ComponentDataCache cache) {
041 this.componentKey = componentKey;
042 this.cache = cache;
043 this.referencesBySymbol = TreeMultimap.create(new SymbolComparator(), new ReferenceComparator());
044 }
045
046 @Override
047 public Symbol newSymbol(int fromOffset, int toOffset) {
048 Symbol symbol = new DefaultSymbol(componentKey, fromOffset, toOffset);
049 referencesBySymbol.put(symbol, symbol.getDeclarationStartOffset());
050 return symbol;
051 }
052
053 @Override
054 public void newReference(Symbol symbol, int fromOffset) {
055 String otherComponentKey = ((DefaultSymbol) symbol).componentKey();
056 if (!otherComponentKey.equals(componentKey)) {
057 throw new UnsupportedOperationException("Cannot add reference from (" + componentKey + ") to another file (" + otherComponentKey + ")");
058 }
059 if (fromOffset >= symbol.getDeclarationStartOffset() && fromOffset < symbol.getDeclarationEndOffset()) {
060 throw new UnsupportedOperationException("Cannot add reference (" + fromOffset + ") overlapping " + symbol);
061 }
062 referencesBySymbol.put(symbol, fromOffset);
063 }
064
065 @Override
066 public void done() {
067 SymbolData symbolData = new SymbolData(referencesBySymbol);
068 cache.setData(componentKey, SnapshotDataTypes.SYMBOL_HIGHLIGHTING, symbolData);
069 }
070
071 public static class SymbolComparator implements Comparator<Symbol>, Serializable {
072 @Override
073 public int compare(Symbol left, Symbol right) {
074 return left.getDeclarationStartOffset() - right.getDeclarationStartOffset();
075 }
076 }
077
078 public static class ReferenceComparator implements Comparator<Integer>, Serializable {
079 @Override
080 public int compare(Integer left, Integer right) {
081 int result;
082 if (left != null & right != null) {
083 result = left - right;
084 } else {
085 result = left == null ? -1 : 1;
086 }
087 return result;
088 }
089 }
090 }