/*
* SonarQube Java
* Copyright (C) 2012-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.java.ast.visitors;
import org.sonar.api.batch.sensor.symbol.NewSymbol;
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
import org.sonar.java.resolve.SemanticModel;
import org.sonar.java.resolve.Symbols;
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
import org.sonar.plugins.java.api.tree.ClassTree;
import org.sonar.plugins.java.api.tree.CompilationUnitTree;
import org.sonar.plugins.java.api.tree.EnumConstantTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.ImportTree;
import org.sonar.plugins.java.api.tree.LabeledStatementTree;
import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.SyntaxToken;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.TypeParameterTree;
import org.sonar.plugins.java.api.tree.VariableTree;
import java.util.List;
public class SonarSymbolTableVisitor extends BaseTreeVisitor {
private final NewSymbolTable newSymbolTable;
private final SemanticModel semanticModel;
private CompilationUnitTree outerClass;
public SonarSymbolTableVisitor(NewSymbolTable newSymbolTable, SemanticModel semanticModel) {
this.newSymbolTable = newSymbolTable;
this.semanticModel = semanticModel;
}
@Override
public void visitCompilationUnit(CompilationUnitTree tree) {
if (outerClass == null) {
outerClass = tree;
}
super.visitCompilationUnit(tree);
if (tree.equals(outerClass)) {
newSymbolTable.save();
}
}
@Override
public void visitClass(ClassTree tree) {
IdentifierTree simpleName = tree.simpleName();
if (simpleName != null) {
createSymbol(simpleName, tree.symbol().usages());
}
for (TypeParameterTree typeParameterTree : tree.typeParameters()) {
createSymbol(typeParameterTree.identifier(), typeParameterTree);
}
super.visitClass(tree);
}
@Override
public void visitVariable(VariableTree tree) {
createSymbol(tree.simpleName(), tree.symbol().usages());
super.visitVariable(tree);
}
@Override
public void visitEnumConstant(EnumConstantTree tree) {
createSymbol(tree.simpleName(), tree);
super.visitEnumConstant(tree);
}
@Override
public void visitMethod(MethodTree tree) {
List<IdentifierTree> usages = tree.symbol().usages();
createSymbol(tree.simpleName(), usages);
for (TypeParameterTree typeParameterTree : tree.typeParameters()) {
createSymbol(typeParameterTree.identifier(), typeParameterTree);
}
super.visitMethod(tree);
}
@Override
public void visitLabeledStatement(LabeledStatementTree tree) {
createSymbol(tree.label(), tree.symbol().usages());
super.visitLabeledStatement(tree);
}
@Override
public void visitImport(ImportTree tree) {
IdentifierTree identifierTree;
if (tree.qualifiedIdentifier().is(Tree.Kind.IDENTIFIER)) {
identifierTree = (IdentifierTree) tree.qualifiedIdentifier();
} else {
identifierTree = ((MemberSelectExpressionTree) tree.qualifiedIdentifier()).identifier();
}
// Exclude on demands imports
if (!"*".equals(identifierTree.name())) {
createSymbol(identifierTree, tree);
}
super.visitImport(tree);
}
private void createSymbol(IdentifierTree declaration, Tree tree) {
org.sonar.plugins.java.api.semantic.Symbol semanticSymbol = semanticModel.getSymbol(tree);
if (semanticSymbol == null) {
semanticSymbol = Symbols.unknownSymbol;
}
createSymbol(declaration, semanticSymbol.usages());
}
private void createSymbol(IdentifierTree declaration, List<IdentifierTree> usages) {
SyntaxToken syntaxToken = declaration.identifierToken();
NewSymbol newSymbol = newSymbolTable.newSymbol(syntaxToken.line(), syntaxToken.column(), syntaxToken.line(), syntaxToken.text().length() + syntaxToken.column());
for (IdentifierTree usage : usages) {
syntaxToken = usage.identifierToken();
newSymbol.newReference(syntaxToken.line(), syntaxToken.column(), syntaxToken.line(), syntaxToken.text().length() + syntaxToken.column());
}
}
}