/* * 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.resolve; import com.google.common.collect.Lists; import com.sonar.sslr.api.typed.ActionParser; import org.sonar.java.ast.parser.JavaParser; import org.sonar.java.model.JavaTree; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.BaseTreeVisitor; import org.sonar.plugins.java.api.tree.CompilationUnitTree; import org.sonar.plugins.java.api.tree.IdentifierTree; import org.sonar.plugins.java.api.tree.SyntaxToken; import org.sonar.plugins.java.api.tree.Tree; import javax.annotation.Nullable; import java.io.File; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.HashSet; import java.util.Map; class Result { private static final ActionParser parser = JavaParser.createParser(StandardCharsets.UTF_8); private final SemanticModel semanticModel; private final Collection<Symbol> symbolsUsed; private Result(SemanticModel semanticModel, Collection<Symbol> symbolsUsed) { this.semanticModel = semanticModel; this.symbolsUsed = symbolsUsed; } public static Result createFor(String name) { return createForJavaFile("src/test/files/sym/" + name); } public static Result createForJavaFile(String filePath) { File file = new File(filePath + ".java"); CompilationUnitTree compilationUnitTree = (CompilationUnitTree) parser.parse(file); SemanticModel semanticModel = SemanticModel.createFor(compilationUnitTree, Lists.newArrayList(new File("target/test-classes"), new File("target/classes"))); UsageVisitor usageVisitor = new UsageVisitor(); compilationUnitTree.accept(usageVisitor); return new Result(semanticModel, usageVisitor.symbolsUsed); } private static class UsageVisitor extends BaseTreeVisitor { public Collection<Symbol> symbolsUsed = new HashSet<>(); @Override public void visitIdentifier(IdentifierTree tree) { symbolsUsed.add(tree.symbol()); super.visitIdentifier(tree); } } public JavaSymbol symbol(String name) { Symbol result = null; for (Symbol symbol : semanticModel.getSymbolsTree().values()) { if (name.equals(symbol.name())) { if (result != null) { throw new IllegalArgumentException("Ambiguous coordinates of symbol"); } result = symbol; } } if (result == null) { throw new IllegalArgumentException("Symbol not found"); } return (JavaSymbol) result; } public JavaSymbol symbol(String name, int line) { Symbol result = null; for (Map.Entry<Tree, Symbol> entry : semanticModel.getSymbolsTree().entrySet()) { if (name.equals(entry.getValue().name()) && ((JavaTree) entry.getKey()).getLine() == line) { if (result != null) { throw new IllegalArgumentException("Ambiguous coordinates of symbol"); } result = entry.getValue(); } } if (result == null) { throw new IllegalArgumentException("Symbol not found"); } return (JavaSymbol) result; } public JavaSymbol reference(int line, int column) { return (JavaSymbol) referenceTree(line, column, true, null); } public JavaSymbol reference(int line, int column, String name) { return (JavaSymbol) referenceTree(line, column, true, name); } public IdentifierTree referenceTree(int line, int column) { return (IdentifierTree) referenceTree(line, column, false, null); } private Object referenceTree(int line, int column, boolean searchSymbol, @Nullable String name) { // In SSLR column starts at 0, but here we want consistency with IDE, so we start from 1: column -= 1; for (Symbol symbol : symbolsUsed) { if (name != null && !name.equals(symbol.name())) { continue; } for (IdentifierTree usage : symbol.usages()) { SyntaxToken token = usage.identifierToken(); if (token.line() == line && token.column() == column) { if(searchSymbol) { return symbol; } else { return usage; } } } } throw new IllegalArgumentException("Reference Tree not found "+line); } }