/*
* 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.Iterables;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.semantic.Type;
import org.sonar.plugins.java.api.tree.AssignmentExpressionTree;
import org.sonar.plugins.java.api.tree.BlockTree;
import org.sonar.plugins.java.api.tree.ConditionalExpressionTree;
import org.sonar.plugins.java.api.tree.ExpressionStatementTree;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.LambdaExpressionTree;
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.MethodReferenceTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.NewClassTree;
import org.sonar.plugins.java.api.tree.ParenthesizedTree;
import org.sonar.plugins.java.api.tree.ReturnStatementTree;
import org.sonar.plugins.java.api.tree.SyntaxToken;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.VariableTree;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class SymbolTableTest {
@Rule
public ExpectedException expectedEx = ExpectedException.none();
@Test
public void Generics() {
Result result = Result.createFor("Generics");
JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("A");
JavaSymbol symbolA1 = result.symbol("a1");
assertThat(symbolA1.type.symbol).isSameAs(typeSymbol);
JavaSymbol symbolA2 = result.symbol("a1");
assertThat(symbolA2.type.symbol).isSameAs(typeSymbol);
assertThat(symbolA2.type).isSameAs(symbolA1.type);
JavaSymbol symbolA3 = result.symbol("a1");
assertThat(symbolA3.type.symbol).isSameAs(typeSymbol);
assertThat(result.reference(12, 5)).isSameAs(result.symbol("foo", 8));
assertThat(result.reference(13, 5)).isSameAs(result.symbol("foo", 9));
// Check erasure
TypeVariableJavaType STypeVariableType = (TypeVariableJavaType) typeSymbol.typeParameters.lookup("S").get(0).type;
assertThat(STypeVariableType.erasure().getSymbol().getName()).isEqualTo("CharSequence");
JavaType arrayErasure = typeSymbol.members().lookup("arrayErasure").get(0).type;
assertThat(arrayErasure.isTagged(JavaType.ARRAY)).isTrue();
assertThat(arrayErasure.erasure().isTagged(JavaType.ARRAY)).isTrue();
assertThat(((ArrayJavaType) arrayErasure.erasure()).elementType().symbol.getName()).isEqualTo("CharSequence");
IdentifierTree tree = result.referenceTree(20, 7);
JavaType symbolType = (JavaType) tree.symbolType();
assertThat(symbolType).isInstanceOf(ParametrizedTypeJavaType.class);
ParametrizedTypeJavaType ptt = (ParametrizedTypeJavaType) symbolType;
assertThat(ptt.symbol.getName()).isEqualTo("C");
assertThat(ptt.typeSubstitution.size()).isEqualTo(1);
assertThat(ptt.typeSubstitution.substitutedType(ptt.typeSubstitution.typeVariables().iterator().next()).symbol.getName()).isEqualTo("String");
JavaSymbol.MethodJavaSymbol method1 = (JavaSymbol.MethodJavaSymbol) typeSymbol.members().lookup("method1").get(0);
assertThat(((MethodJavaType) method1.type).resultType).isSameAs(STypeVariableType);
JavaSymbol.MethodJavaSymbol method2 = (JavaSymbol.MethodJavaSymbol) typeSymbol.members().lookup("method2").get(0);
TypeVariableJavaType PTypeVariableType = (TypeVariableJavaType) method2.typeParameters().lookup("P").get(0).type;
assertThat(method2.getReturnType().type).isSameAs(PTypeVariableType);
assertThat(method2.parameterTypes().get(0)).isSameAs(PTypeVariableType);
// Type parameter defined in outer class
JavaSymbol.TypeJavaSymbol classCSymbol = (JavaSymbol.TypeJavaSymbol) typeSymbol.members().lookup("C").get(0);
JavaSymbol innerClassField = classCSymbol.members().lookup("innerClassField").get(0);
assertThat(innerClassField.type).isSameAs(STypeVariableType);
// Unknown parametrized type should be tagged as unknown
MethodTree methodTree = (MethodTree) result.symbol("unknownSymbol").declaration();
VariableTree variableTree = (VariableTree) methodTree.block().body().get(0);
assertThat(variableTree.type().symbolType().isUnknown()).isTrue();
//Inner class referenced as type parameter in super class/interface
assertThat(result.reference(68,53)).isSameAs(result.symbol("B", 69));
JavaSymbol applyMethod = result.symbol("apply");
assertThat(result.reference(83, 12)).isSameAs(applyMethod);
assertThat(result.reference(89, 61)).isSameAs(applyMethod);
// this method does not compile but is resolved whereas it should not.
assertThat(result.reference(85, 12)).isSameAs(applyMethod);
assertThat(applyMethod.usages()).hasSize(3);
}
@Test
public void parameterized_method_type() throws Exception {
Result result = Result.createFor("Generics");
MethodTree method3 = (MethodTree) result.symbol("method3").declaration();
VariableTree variable = (VariableTree) method3.block().body().get(0);
assertThat(variable.initializer().symbolType().symbol().name()).isEqualTo("String");
MethodTree method4 = (MethodTree) result.symbol("method4").declaration();
variable = (VariableTree) method4.block().body().get(0);
Type symbolType = variable.initializer().symbolType();
assertThat(symbolType).isInstanceOf(ParametrizedTypeJavaType.class);
ParametrizedTypeJavaType ptt = (ParametrizedTypeJavaType) symbolType;
assertThat(ptt.typeSubstitution.substitutedTypes().iterator().next().getSymbol().getName()).isEqualTo("String");
assertThat(result.reference(58, 25)).isSameAs(result.symbol("method_of_e"));
}
@Test
public void extended_type_variables() throws Exception {
String javaLangObject = "java.lang.Object";
Result result = Result.createFor("Generics");
Type MyClass = result.symbol("MyClass", 100).type();
Type i = result.symbol("I").type();
Type j = result.symbol("J").type();
JavaSymbol.TypeJavaSymbol w = (JavaSymbol.TypeJavaSymbol) result.symbol("W", 103);
assertThat(w.superClass().is(javaLangObject)).isTrue();
assertThat(w.interfaces()).isEmpty();
JavaSymbol.TypeJavaSymbol x = (JavaSymbol.TypeJavaSymbol) result.symbol("X", 103);
assertThat(x.superClass()).isSameAs(MyClass);
assertThat(x.interfaces()).isEmpty();
JavaSymbol.TypeJavaSymbol y = (JavaSymbol.TypeJavaSymbol) result.symbol("Y", 103);
assertThat(y.superClass().is(javaLangObject)).isTrue();
assertThat(y.interfaces()).containsExactly(i);
JavaSymbol.TypeJavaSymbol z = (JavaSymbol.TypeJavaSymbol) result.symbol("Z", 103);
assertThat(z.superClass()).isSameAs(MyClass);
assertThat(z.interfaces()).containsExactly(i, j);
}
@Test
public void recursive_type_substitution() {
Result result = Result.createFor("Generics");
MethodTree ddt_method = (MethodTree) result.symbol("ddt_method").declaration();
VariableTree variable = (VariableTree) ddt_method.block().body().get(0);
assertThat(variable.initializer().symbolType().name()).isEqualTo("String");
}
@Test
public void ClassDeclaration() {
Result result = Result.createFor("declarations/ClassDeclaration");
JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Declaration");
JavaSymbol classDeclaration = result.symbol("ClassDeclaration");
List<JavaSymbol> parameters = classDeclaration.type.symbol.typeParameters.lookup("T");
assertThat(parameters).hasSize(1);
assertThat(parameters.get(0).getName()).isEqualTo("T");
parameters = classDeclaration.type.symbol.typeParameters.lookup("S");
assertThat(parameters).hasSize(1);
assertThat(parameters.get(0).getName()).isEqualTo("S");
assertThat(typeSymbol.owner()).isSameAs(classDeclaration);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PRIVATE);
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("Superclass").type);
assertThat(typeSymbol.getInterfaces()).containsExactly(
result.symbol("FirstInterface").type,
result.symbol("SecondInterface").type);
assertThat(typeSymbol.members.lookup("this")).isNotEmpty();
assertThat(typeSymbol.members.lookup("super")).hasSize(1);
JavaSymbol superSymbol = typeSymbol.members.lookup("super").get(0);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Superclass");
assertThat(superSymbol.type.symbol).isSameAs(typeSymbol);
assertThat(typeSymbol.symbolMetadata.isAnnotatedWith("java.lang.Override")).isFalse();
assertThat(typeSymbol.members.lookup("super")).hasSize(1);
superSymbol = typeSymbol.members.lookup("super").get(0);
assertThat(superSymbol.owner).isSameAs(typeSymbol);
assertThat(((JavaSymbol.VariableJavaSymbol) superSymbol).type.symbol).isSameAs(typeSymbol.getSuperclass().symbol);
JavaSymbol superclass = typeSymbol.getSuperclass().symbol;
assertThat(superclass.getName()).isEqualTo("Object");
assertThat(superclass.owner).isInstanceOf(JavaSymbol.PackageJavaSymbol.class);
assertThat(superclass.owner.getName()).isEqualTo("java.lang");
assertThat(typeSymbol.getInterfaces()).isEmpty();
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Foo");
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("Baz").type);
assertThat(result.reference(25, 21)).isSameAs(result.symbol("method"));
SymbolMetadataResolve metadata = classDeclaration.metadata();
assertThat(metadata.annotations()).hasSize(1);
assertThat(metadata.valuesForAnnotation("java.lang.Override")).isNull();
assertThat(metadata.isAnnotatedWith("java.lang.Override")).isFalse();
assertThat(metadata.valuesForAnnotation("java.lang.SuppressWarnings")).hasSize(1);
assertThat(metadata.isAnnotatedWith("java.lang.SuppressWarnings")).isTrue();
}
@Test
public void DirectCyclingClassDeclaration() {
expectedEx.expectMessage("Cycling class hierarchy detected with symbol : Foo");
expectedEx.expect(IllegalStateException.class);
Result.createForJavaFile("src/test/filesInError/DirectCyclingClassDeclaration");
}
@Test
public void CyclingClassDeclaration() {
expectedEx.expect(IllegalStateException.class);
expectedEx.expectMessage("Cycling class hierarchy detected with symbol : Qix");
Result.createForJavaFile("src/test/filesInError/CyclingClassDeclaration");
}
@Test
public void AnonymousClassDeclaration() {
Result result = Result.createFor("declarations/AnonymousClassDeclaration");
JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("methodInAnonymousClass").owner();
assertThat(typeSymbol.owner()).isSameAs(result.symbol("method"));
assertThat(typeSymbol.flags()).isEqualTo(0);
assertThat(typeSymbol.name).isEqualTo("");
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("Superclass").type);
assertThat(typeSymbol.getInterfaces()).isEmpty();
assertThat(typeSymbol.members.lookup("this")).isNotEmpty();
Collection<JavaSymbol> superSymbols = typeSymbol.members.lookup("super");
assertThat(superSymbols).isNotEmpty();
assertThat(superSymbols.iterator().next().type()).isSameAs(result.symbol("Superclass").type);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("methodInAnonymousClassInterface").owner();
assertThat(typeSymbol.owner()).isSameAs(result.symbol("method"));
assertThat(typeSymbol.flags()).isEqualTo(0);
assertThat(typeSymbol.name).isEqualTo("");
assertThat(typeSymbol.getSuperclass().getSymbol().getName()).isEqualTo("Object");
assertThat(typeSymbol.getInterfaces()).hasSize(1);
assertThat(typeSymbol.getInterfaces().get(0)).isSameAs(result.symbol("SuperInterface").type);
assertThat(typeSymbol.members.lookup("this")).isNotEmpty();
}
@Test
public void LocalClassDeclaration() {
Result result = Result.createFor("declarations/LocalClassDeclaration");
JavaSymbol.TypeJavaSymbol typeSymbol;
// TODO no forward references here, for the moment considered as a really rare situation
// typeSymbol = (Symbol.TypeSymbol) result.symbol("Declaration", 14);
// assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("Superclass", 9));
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Declaration", 22);
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("Superclass", 22 - 2).type);
assertThat(typeSymbol.members.lookup("this")).isNotEmpty();
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Declaration", 25);
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("Superclass", 9).type);
}
@Test
public void InterfaceDeclaration() {
Result result = Result.createFor("declarations/InterfaceDeclaration");
JavaSymbol.TypeJavaSymbol interfaceSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Declaration");
assertThat(interfaceSymbol.owner()).isSameAs(result.symbol("InterfaceDeclaration"));
assertThat(interfaceSymbol.flags()).isEqualTo(Flags.PRIVATE | Flags.INTERFACE | Flags.STATIC);
assertThat(interfaceSymbol.getSuperclass().getSymbol().getName()).isEqualTo("Object");
assertThat(interfaceSymbol.getInterfaces()).containsExactly(
result.symbol("FirstInterface").type,
result.symbol("SecondInterface").type);
assertThat(interfaceSymbol.members.lookup("this")).hasSize(1);
assertThat(interfaceSymbol.members.lookup("super")).isEmpty();
JavaSymbol.VariableJavaSymbol variableSymbol = (JavaSymbol.VariableJavaSymbol) result.symbol("FIRST_CONSTANT");
assertThat(variableSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(variableSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.FINAL);
variableSymbol = (JavaSymbol.VariableJavaSymbol) result.symbol("SECOND_CONSTANT");
assertThat(variableSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(variableSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.FINAL);
JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) result.symbol("method");
assertThat(methodSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(methodSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.ABSTRACT);
JavaSymbol.MethodJavaSymbol staticMethodSymbol = (JavaSymbol.MethodJavaSymbol) result.symbol("staticMethod");
assertThat(staticMethodSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(staticMethodSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC);
JavaSymbol.MethodJavaSymbol defaultMethodSymbol = (JavaSymbol.MethodJavaSymbol) result.symbol("defaultMethod");
assertThat(defaultMethodSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(defaultMethodSymbol.flags()).isEqualTo(Flags.DEFAULT | Flags.PUBLIC);
JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("NestedClass");
assertThat(typeSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("NestedInterface");
assertThat(typeSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.INTERFACE);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("NestedEnum");
assertThat(typeSymbol.owner()).isSameAs(interfaceSymbol);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.ENUM | Flags.STATIC);
}
@Test
public void EnumDeclaration() {
Result result = Result.createFor("declarations/EnumDeclaration");
JavaSymbol.TypeJavaSymbol enumSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Declaration");
assertThat(enumSymbol.owner()).isSameAs(result.symbol("EnumDeclaration"));
assertThat(enumSymbol.flags()).isEqualTo(Flags.PRIVATE | Flags.ENUM | Flags.STATIC);
ParametrizedTypeJavaType superType = (ParametrizedTypeJavaType) enumSymbol.getSuperclass();
JavaSymbol.TypeJavaSymbol superclass = superType.symbol;
assertThat(superclass.getName()).isEqualTo("Enum");
assertThat(superclass.owner).isInstanceOf(JavaSymbol.PackageJavaSymbol.class);
assertThat(superclass.owner.getName()).isEqualTo("java.lang");
assertThat(superType.typeSubstitution.size()).isEqualTo(1);
Map.Entry<TypeVariableJavaType, JavaType> entry = superType.typeSubstitution.substitutionEntries().iterator().next();
assertThat(entry.getKey()).isSameAs(superclass.typeParameters.lookup("E").get(0).type);
assertThat(entry.getValue()).isSameAs(enumSymbol.type);
assertThat(enumSymbol.superClass()).isSameAs(result.symbol("parameterizedDeclaration").type);
assertThat(enumSymbol.members.lookup("super")).hasSize(1);
JavaSymbol.VariableJavaSymbol superSymbol = (JavaSymbol.VariableJavaSymbol) enumSymbol.members.lookup("super").get(0);
assertThat(superSymbol.type).isSameAs(superType);
assertThat(enumSymbol.getInterfaces()).containsExactly(
result.symbol("FirstInterface").type,
result.symbol("SecondInterface").type);
assertThat(enumSymbol.members.lookup("this")).isNotEmpty();
JavaSymbol.VariableJavaSymbol variableSymbol = (JavaSymbol.VariableJavaSymbol) result.symbol("FIRST_CONSTANT");
assertThat(variableSymbol.owner()).isSameAs(enumSymbol);
assertThat(variableSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.FINAL | Flags.ENUM);
JavaSymbol.TypeJavaSymbol anonymousSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("method", 11).owner();
assertThat(anonymousSymbol.name).isEqualTo("");
assertThat(anonymousSymbol.owner()).isSameAs(enumSymbol);
assertThat(anonymousSymbol.flags()).isEqualTo(0); // FIXME should be ENUM
assertThat(anonymousSymbol.getSuperclass()).isSameAs(result.symbol("Declaration").type);
assertThat(anonymousSymbol.getInterfaces()).isEmpty();
variableSymbol = (JavaSymbol.VariableJavaSymbol) result.symbol("SECOND_CONSTANT");
assertThat(variableSymbol.owner()).isSameAs(enumSymbol);
assertThat(variableSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.FINAL | Flags.ENUM);
anonymousSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("method", 16).owner();
assertThat(anonymousSymbol.name).isEqualTo("");
assertThat(anonymousSymbol.owner()).isSameAs(enumSymbol);
assertThat(anonymousSymbol.flags()).isEqualTo(0); // FIXME should be ENUM
assertThat(anonymousSymbol.getSuperclass()).isSameAs(result.symbol("Declaration").type);
assertThat(anonymousSymbol.getInterfaces()).isEmpty();
JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) result.symbol("method", 21);
assertThat(methodSymbol.owner()).isSameAs(enumSymbol);
assertThat(methodSymbol.flags()).isEqualTo(Flags.ABSTRACT);
JavaSymbol.TypeJavaSymbol enumConstructorSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("ConstructorEnum");
assertThat(enumConstructorSymbol).isNotNull();
methodSymbol = (JavaSymbol.MethodJavaSymbol) enumConstructorSymbol.members().lookup("<init>").get(0);
assertThat(methodSymbol.isPrivate()).isTrue();
assertThat(result.reference(36, 5)).isSameAs(result.symbol("<init>", 38));
assertThat(result.reference(37, 5)).isSameAs(result.symbol("<init>", 39));
}
@Test
public void Enum() {
Result result = Result.createFor("Enum");
JavaSymbol.TypeJavaSymbol enumSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Foo");
assertThat(enumSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.ENUM);
ParametrizedTypeJavaType superType = (ParametrizedTypeJavaType) enumSymbol.getSuperclass();
JavaSymbol.TypeJavaSymbol superclass = superType.symbol;
assertThat(superclass.getName()).isEqualTo("Enum");
// usages of methods values() and valueOf(String s) from an enum when enum definition is in file
JavaSymbol.MethodJavaSymbol valuesMethod = (JavaSymbol.MethodJavaSymbol) enumSymbol.lookupSymbols("values").iterator().next();
assertThat(valuesMethod.declaration).isNull();
assertThat(valuesMethod.isStatic()).isTrue();
assertThat(valuesMethod.parameterTypes()).isEmpty();
assertThat(((MethodJavaType) valuesMethod.type).resultType).isInstanceOf(ArrayJavaType.class);
assertThat(((ArrayJavaType) (((MethodJavaType) valuesMethod.type).resultType)).elementType).isSameAs(enumSymbol.type);
assertThat(result.reference(9, 19)).isSameAs(valuesMethod);
assertThat(result.reference(9, 5)).isSameAs(result.symbol("useValues", 13));
JavaSymbol.MethodJavaSymbol valueOfMethod = (JavaSymbol.MethodJavaSymbol) enumSymbol.lookupSymbols("valueOf").iterator().next();
assertThat(valueOfMethod.declaration).isNull();
assertThat(valueOfMethod.isStatic()).isTrue();
assertThat(valueOfMethod.parameterTypes()).hasSize(1);
assertThat(valueOfMethod.parameterTypes().get(0).is("java.lang.String")).isTrue();
assertThat(((MethodJavaType) valueOfMethod.type).resultType).isSameAs(enumSymbol.type);
assertThat(result.reference(10, 20)).isSameAs(valueOfMethod);
assertThat(result.reference(10, 5)).isSameAs(result.symbol("useValueOf", 14));
// usages of methods values() and valueOf(String s) from an enum when read from byte code
assertThat(result.reference(17, 5)).isSameAs(result.symbol("useValues", 21));
assertThat(result.reference(18, 5)).isSameAs(result.symbol("useValueOf", 22));
// deprecated enum constants
List<Symbol> deprecatedEnumConstant = new ArrayList<>(enumSymbol.lookupSymbols("C"));
assertThat(deprecatedEnumConstant).hasSize(1);
assertThat(deprecatedEnumConstant.get(0).isDeprecated()).isTrue();
}
@Test
public void AnnotationTypeDeclaration() {
Result result = Result.createFor("declarations/AnnotationTypeDeclaration");
JavaSymbol.TypeJavaSymbol annotationSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Declaration");
assertThat(annotationSymbol.owner()).isSameAs(result.symbol("AnnotationTypeDeclaration"));
assertThat(annotationSymbol.flags()).isEqualTo(Flags.PRIVATE | Flags.INTERFACE | Flags.ANNOTATION);
assertThat(annotationSymbol.getSuperclass()).isNull(); // TODO should it be java.lang.Object?
JavaSymbol superinterface = Iterables.getOnlyElement(annotationSymbol.getInterfaces()).symbol;
assertThat(superinterface.getName()).isEqualTo("Annotation");
assertThat(superinterface.owner).isInstanceOf(JavaSymbol.PackageJavaSymbol.class);
assertThat(superinterface.owner.getName()).isEqualTo("java.lang.annotation");
assertThat(annotationSymbol.members.lookup("this")).isEmpty();
JavaSymbol.VariableJavaSymbol variableSymbol = (JavaSymbol.VariableJavaSymbol) result.symbol("FIRST_CONSTANT");
assertThat(variableSymbol.owner()).isSameAs(annotationSymbol);
assertThat(variableSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.FINAL);
variableSymbol = (JavaSymbol.VariableJavaSymbol) result.symbol("SECOND_CONSTANT");
assertThat(variableSymbol.owner()).isSameAs(annotationSymbol);
assertThat(variableSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.FINAL);
JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) result.symbol("value", 15);
assertThat(methodSymbol.owner()).isSameAs(annotationSymbol);
assertThat(methodSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.ABSTRACT);
JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("NestedClass");
assertThat(typeSymbol.owner()).isSameAs(annotationSymbol);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("NestedInterface");
assertThat(typeSymbol.owner()).isSameAs(annotationSymbol);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.INTERFACE);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("NestedEnum");
assertThat(typeSymbol.owner()).isSameAs(annotationSymbol);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.ENUM | Flags.STATIC);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("NestedAnnotationType");
assertThat(typeSymbol.owner()).isSameAs(annotationSymbol);
assertThat(typeSymbol.flags()).isEqualTo(Flags.PUBLIC | Flags.STATIC | Flags.INTERFACE | Flags.ANNOTATION);
}
@Test
public void MethodDeclaration() {
Result result = Result.createFor("declarations/MethodDeclaration");
JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) result.symbol("declaration");
assertThat(methodSymbol.owner()).isSameAs(result.symbol("MethodDeclaration"));
assertThat(methodSymbol.flags()).isEqualTo(Flags.PROTECTED);
assertThat(methodSymbol.getReturnType()).isSameAs(result.symbol("ReturnType"));
assertThat(methodSymbol.thrownTypes()).containsExactly(
result.symbol("FirstExceptionType").type(),
result.symbol("SecondExceptionType").type());
}
@Test
public void ConstructorDeclaration() {
Result result = Result.createFor("declarations/ConstructorDeclaration");
JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) result.symbol("<init>", 18);
assertThat(methodSymbol.owner()).isSameAs(result.symbol("ConstructorDeclaration"));
assertThat(methodSymbol.flags()).isEqualTo(0);
assertThat(methodSymbol.getReturnType()).isNull();
assertThat(methodSymbol.parameterTypes()).hasSize(1);
assertThat(methodSymbol.thrownTypes()).containsExactly(
result.symbol("FirstExceptionType").type(),
result.symbol("SecondExceptionType").type());
assertThat(result.reference(21, 35)).isEqualTo(methodSymbol);
assertThat(((JavaSymbol.TypeJavaSymbol) methodSymbol.owner()).lookupSymbols("<init>")).as("Constructor with a declared constructor should not have a default one").hasSize(1);
//Default constructor
JavaSymbol defaultConstructor = result.reference(23, 26);
assertThat(defaultConstructor.owner).isSameAs(result.symbol("ParameterType"));
defaultConstructor = result.reference(28, 7);
assertThat(defaultConstructor.isAbstract()).isFalse();
}
@Test
public void ConstructorResolution() throws Exception {
Result result = Result.createFor("PrivateConstructors");
JavaSymbol.TypeJavaSymbol classSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("PrivateConstructorClass");
List<JavaSymbol> constructors = classSymbol.members.lookup("<init>");
JavaSymbol ObjectConstructor = constructors.get(0);
JavaSymbol stringConstructor = constructors.get(1);
JavaSymbol.MethodJavaSymbol constructorReference;
// this(s) - > PrivateConstructorClass(s)
constructorReference = (JavaSymbol.MethodJavaSymbol) result.reference(11, 7);
assertThat(constructorReference.owner()).isSameAs(classSymbol);
assertThat(constructorReference).isEqualTo(stringConstructor);
// super(s) -> PrivateConstructorClass(s)
constructorReference = (JavaSymbol.MethodJavaSymbol) result.reference(17, 7);
assertThat(constructorReference.owner()).isSameAs(classSymbol);
assertThat(constructorReference).isEqualTo(stringConstructor);
// super(s) -> PrivateConstructorClass(o)
constructorReference = (JavaSymbol.MethodJavaSymbol) result.reference(24, 5);
assertThat(constructorReference.owner()).isSameAs(classSymbol);
assertThat(constructorReference).isEqualTo(ObjectConstructor);
assertThat(stringConstructor.usages()).hasSize(2);
assertThat(ObjectConstructor.usages()).hasSize(1);
}
@Test
public void ConstructorWithEnclosingClass() {
Result result = Result.createFor("ConstructorWithEnclosingClass");
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("Inner")).members().scopeSymbols.get(0)).isSameAs(result.reference(9, 29));
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("Inner2")).members().scopeSymbols.get(0)).isSameAs(result.reference(21, 30));
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("Inner3")).members().scopeSymbols.get(0)).isSameAs(result.reference(34, 19));
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("Inner3")).members().scopeSymbols.get(1)).isSameAs(result.reference(34, 36));
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("Foo3")).members().scopeSymbols.get(1)).isSameAs(result.reference(34, 5));
JavaSymbol.MethodJavaSymbol defaultConstructor = (JavaSymbol.MethodJavaSymbol) Iterables
.getOnlyElement(((JavaSymbol.TypeJavaSymbol) result.symbol("Inner3")).lookupSymbols("<init>"));
assertThat(defaultConstructor).isSameAs(result.reference(34, 19));
assertThat(defaultConstructor.parameterTypes()).containsExactly(result.symbol("Outer3").type);
}
@Test
public void SuperConstructorOfInnerClass() {
Result result = Result.createFor("SuperConstructorOfInnerClass");
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("StaticInner")).members().lookup("<init>").get(0)).isSameAs(result.reference(7, 7));
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("ChildInner")).members().lookup("<init>").get(1)).isSameAs(result.reference(16, 7));
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("Inner")).members().lookup("<init>").get(0)).isSameAs(result.reference(20, 7));
}
@Test
public void SuperConstructorOfExternalInnerClass() {
Result result = Result.createFor("SuperConstructorOfExternalInnerClass");
// FIXME SONARJAVA-1678 the constructor of the inner class is used
assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("InnerA")).members().lookup("<init>").get(0).usages()).isEmpty();
// assertThat(((JavaSymbol.TypeJavaSymbol) result.symbol("InnerA")).members().lookup("<init>").get(0))
// .isEqualTo(result.reference(10, 9));
}
@Test
public void ConstructorWithInference() throws Exception {
Result result = Result.createFor("ConstructorWithInference");
JavaSymbol.TypeJavaSymbol classSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("A");
List<JavaSymbol> constructors = classSymbol.members.lookup("<init>");
JavaSymbol noParamConstructor = constructors.get(0);
JavaSymbol parametrizedConstructor = constructors.get(1);
JavaSymbol wildcardConstructor = constructors.get(2);
Type aObjectType = result.symbol("aObject").type();
Type aStringType = result.symbol("aString").type();
IdentifierTree constStringNoArg = result.referenceTree(14, 9);
assertThat(constStringNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constStringNoArg)).isSameAs(aStringType);
IdentifierTree constDiamondNoArg = result.referenceTree(16, 9);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constDiamondNoArg)).isSameAs(aObjectType);
constDiamondNoArg = result.referenceTree(17, 9);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constDiamondNoArg)).isSameAs(aObjectType);
assertThat(result.reference(17, 15)).isSameAs(result.symbol("foo", 10));
constDiamondNoArg = result.referenceTree(18, 13);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constDiamondNoArg)).isSameAs(aObjectType);
constDiamondNoArg = result.referenceTree(20, 25);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constDiamondNoArg)).isSameAs(aStringType);
constDiamondNoArg = result.referenceTree(21, 18);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constDiamondNoArg)).isSameAs(aObjectType);
constDiamondNoArg = result.referenceTree(23, 13);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constDiamondNoArg)).isSameAs(aStringType);
assertThat(result.reference(23, 5)).isSameAs(result.symbol("bar", 11));
IdentifierTree constDiamondObject = result.referenceTree(25, 9);
assertThat(constDiamondObject.symbol()).isSameAs(parametrizedConstructor);
assertThat(getNewClassTreeType(constDiamondObject)).isSameAs(aObjectType);
IdentifierTree constDiamondString = result.referenceTree(26, 9);
assertThat(constDiamondString.symbol()).isSameAs(parametrizedConstructor);
assertThat(getNewClassTreeType(constDiamondString)).isSameAs(aStringType);
IdentifierTree constWildcardDiamond = result.referenceTree(28, 9);
assertThat(constWildcardDiamond.symbol()).isSameAs(wildcardConstructor);
assertThat(getNewClassTreeType(constWildcardDiamond)).isSameAs(aStringType);
IdentifierTree returnConstDiamondNoArg = result.referenceTree(30, 16);
assertThat(returnConstDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(returnConstDiamondNoArg)).isSameAs(aStringType);
// inference allowing to deduce only partially the type parameters
classSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("B");
noParamConstructor = classSymbol.members.lookup("<init>").get(0);
ParametrizedTypeJavaType type;
constDiamondNoArg = result.referenceTree(42, 13);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
type = (ParametrizedTypeJavaType) getNewClassTreeType(constDiamondNoArg);
assertThat(type.erasure()).isSameAs(classSymbol.type().erasure());
assertThat(type.substitution(type.typeParameters().get(0)).is("java.lang.String")).isTrue();
assertThat(type.substitution(type.typeParameters().get(1)).is("java.lang.Object")).isTrue();
assertThat(type.substitution(type.typeParameters().get(2)).is("java.lang.Object")).isTrue();
assertThat(result.reference(42, 5)).isSameAs(result.symbol("qix", 46));
constDiamondNoArg = result.referenceTree(43, 13);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
type = (ParametrizedTypeJavaType) getNewClassTreeType(constDiamondNoArg);
assertThat(type.erasure()).isSameAs(classSymbol.type().erasure());
assertThat(type.substitution(type.typeParameters().get(0)).is("java.lang.Object")).isTrue();
assertThat(type.substitution(type.typeParameters().get(1)).is("java.lang.String")).isTrue();
assertThat(type.substitution(type.typeParameters().get(2)).is("java.lang.Integer")).isTrue();
assertThat(result.reference(43, 5)).isSameAs(result.symbol("bar", 47));
// erasure of bounded type parameters
classSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("D");
noParamConstructor = classSymbol.members.lookup("<init>").get(0);
constDiamondNoArg = result.referenceTree(60, 9);
assertThat(constDiamondNoArg.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constDiamondNoArg)).isSameAs(result.symbol("dC").type());
assertThat(result.reference(60, 15)).isSameAs(result.symbol("foo", 55));
// enclosing expression
classSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("F");
constructors = classSymbol.members.lookup("<init>");
noParamConstructor = constructors.get(0);
parametrizedConstructor = constructors.get(1);
IdentifierTree constructorCall = result.referenceTree(75, 15);
assertThat(constructorCall.symbol()).isSameAs(noParamConstructor);
assertThat(getNewClassTreeType(constructorCall)).isSameAs(result.symbol("fString").type());
assertThat(result.reference(75, 5)).isSameAs(result.symbol("foo", 72));
constructorCall = result.referenceTree(76, 15);
assertThat(constructorCall.symbol()).isSameAs(parametrizedConstructor);
assertThat(getNewClassTreeType(constructorCall)).isSameAs(result.symbol("fString").type());
assertThat(result.reference(76, 5)).isSameAs(result.symbol("foo", 72));
}
@Test
public void constructorWithTypeArguments() {
Result result = Result.createFor("ConstructorWithTypeArguments");
JavaSymbol.TypeJavaSymbol classSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("MyClass");
List<JavaSymbol> constructors = classSymbol.members.lookup("<init>");
assertThat(constructors.get(0).usages()).hasSize(1);
assertThat(constructors.get(1).usages()).hasSize(1);
}
private static Type getNewClassTreeType(IdentifierTree constructorId) {
Tree tree = constructorId;
while (!tree.is(Tree.Kind.NEW_CLASS)) {
tree = tree.parent();
}
return ((NewClassTree) tree).symbolType();
}
@Test
public void CompleteHierarchyOfTypes() {
Result result = Result.createFor("CompleteHierarchyOfTypes");
JavaSymbol.TypeJavaSymbol typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("Foo");
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("Baz").type);
}
@Test
public void type_accessibility() throws Exception {
Result result = Result.createForJavaFile("src/test/java/org/sonar/java/test/AccessibilityTestCase");
JavaSymbol reference = result.reference(26, 7);
MethodJavaType type = (MethodJavaType) reference.type;
assertThat(type.resultType.symbol.name).isEqualTo("int");
}
@Test
public void Accessibility() {
Result result = Result.createFor("Accessibility");
JavaSymbol.TypeJavaSymbol typeSymbol;
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("D1", 11);
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("A1", 6).type);
typeSymbol = (JavaSymbol.TypeJavaSymbol) result.symbol("D2", 31);
assertThat(typeSymbol.getSuperclass()).isSameAs(result.symbol("A2", 19).type);
JavaSymbol.VariableJavaSymbol variableSymbol;
variableSymbol = (JavaSymbol.VariableJavaSymbol) result.reference(32, 15, "j");
assertThat(variableSymbol).isSameAs(result.symbol("j", 17));
JavaSymbol.MethodJavaSymbol methodSymbol;
methodSymbol = (JavaSymbol.MethodJavaSymbol) result.reference(34, 9, "foo");
assertThat(methodSymbol).isSameAs(result.symbol("foo", 22));
}
@Test
public void Example() {
Result.createFor("Example");
}
@Test
public void ScopesAndSymbols() {
Result.createFor("ScopesAndSymbols");
}
@Test
public void TypesOfDeclarations() {
Result result = Result.createFor("TypesOfDeclarations");
assertThat(result.symbol("Class2").kind == JavaSymbol.TYP).isTrue();
JavaSymbol.TypeJavaSymbol class1 = (JavaSymbol.TypeJavaSymbol) result.symbol("Class1");
JavaSymbol.TypeJavaSymbol class2 = (JavaSymbol.TypeJavaSymbol) result.symbol("Class2");
assertThat(class2.getSuperclass().symbol).isEqualTo(class1);
assertThat(class1.getSuperclass()).isNotNull();
assertThat(class1.getSuperclass().symbol.name).isEqualTo("Collection");
JavaSymbol.TypeJavaSymbol interface1 = (JavaSymbol.TypeJavaSymbol) result.symbol("Interface1");
assertThat(interface1.getInterfaces()).isNotEmpty();
assertThat(interface1.getInterfaces().get(0).symbol.name).isEqualTo("List");
}
@Test
public void Labels() {
Result result = Result.createFor("references/Labels");
assertThat(result.reference(8, 13)).isSameAs(result.symbol("label", 6));
assertThat(result.reference(13, 13)).isSameAs(result.symbol("label", 11));
assertThat(result.reference(20, 18)).isSameAs(result.symbol("label", 16));
}
@Test
public void FieldAccess() {
Result result = Result.createFor("references/FieldAccess");
assertThat(result.reference(9, 5)).isSameAs(result.symbol("field"));
assertThat(result.reference(10, 10)).isSameAs(result.symbol("field"));
assertThat(result.reference(11, 5)).isSameAs(result.symbol("FieldAccess"));
assertThat(result.reference(11, 17)).isSameAs(result.symbol("field"));
// FIXME
// assertThat(result.reference(12, 5)).isSameAs(/*package "references"*/);
assertThat(result.reference(14, 5)).isSameAs(result.symbol("FirstStaticNestedClass"));
assertThat(result.reference(14, 28)).isSameAs(result.symbol("field_in_FirstStaticNestedClass"));
assertThat(result.reference(15, 5)).isSameAs(result.symbol("FirstStaticNestedClass"));
assertThat(result.reference(15, 28)).isSameAs(result.symbol("SecondStaticNestedClass"));
assertThat(result.reference(15, 52)).isSameAs(result.symbol("field_in_SecondStaticNestedClass"));
assertThat(result.reference(16, 5)).isSameAs(result.symbol("field"));
assertThat(result.reference(16, 11)).isSameAs(result.symbol("field_in_FirstStaticNestedClass"));
assertThat(result.reference(17, 5)).isSameAs(result.symbol("field"));
assertThat(result.reference(17, 11)).isSameAs(result.symbol("field_in_Superclass"));
}
@Test
public void MethodParameterAccess() {
Result result = Result.createFor("references/MethodParameterAccess");
result.symbol("param");
assertThat(result.reference(7, 5)).isSameAs(result.symbol("param"));
assertThat(result.reference(8, 5)).isSameAs(result.symbol("param"));
assertThat(result.reference(8, 11)).isSameAs(result.symbol("field"));
}
@Test
public void ExpressionInAnnotation() {
Result result = Result.createFor("references/ExpressionInAnnotation");
assertThat(result.reference(3, 19)).isSameAs(result.symbol("ExpressionInAnnotation"));
assertThat(result.reference(3, 42)).isSameAs(result.symbol("VALUE"));
assertThat(result.reference(18, 6)).isSameAs(result.symbol("foo", 11));
assertThat(result.reference(19, 6)).isSameAs(result.symbol("foo", 14));
assertThat(result.reference(19, 14)).isSameAs(result.symbol("bar", 15));
}
@Test
public void generic_method_call() throws Exception {
Result result = Result.createFor("references/GenericMethodCall");
JavaSymbol funMethod = result.symbol("fun");
int startLine = 25;
assertThat(result.reference(startLine, 5)).isSameAs(funMethod);
assertThat(result.reference(startLine + 1, 5)).isSameAs(funMethod);
assertThat(result.reference(startLine + 2, 5)).isSameAs(funMethod);
assertThat(result.reference(startLine + 3, 5)).isSameAs(funMethod);
JavaSymbol gulInt = result.symbol("gul", 34);
JavaSymbol gulString = result.symbol("gul", 36);
assertThat(((JavaSymbol.MethodJavaSymbol) gulInt).parameterTypes().get(0).is("java.lang.Integer")).isTrue();
assertThat(gulString.usages()).hasSize(1);
assertThat(gulInt.usages()).isEmpty();
assertThat(result.symbol("myMethod").usages()).hasSize(1);
assertThat(result.symbol("myMethod2").usages()).hasSize(1);
assertThat(result.symbol("myMethod3").usages()).hasSize(1);
assertThat(result.reference(62, 5)).isSameAs(result.symbol("meth"));
}
@Test
public void MethodCall() {
Result result = Result.createFor("references/MethodCall");
assertThat(result.reference(10, 5)).isSameAs(result.symbol("target"));
assertThat(result.reference(11, 5)).isSameAs(result.symbol("foo", 17));
assertThat(result.reference(30, 5)).isSameAs(result.symbol("fun", 22));
assertThat(result.reference(42, 5)).isSameAs(result.symbol("bar", 35));
assertThat(result.reference(52, 5)).isSameAs(result.symbol("bar", 35));
assertThat(result.reference(61, 5)).isSameAs(result.symbol("bar", 57));
assertThat(result.reference(67, 5)).isSameAs(result.symbol("bar", 35));
assertThat(result.reference(79, 5)).isSameAs(result.symbol("defaultMethod", 72));
assertThat(result.reference(88, 7)).isSameAs(result.symbol("func", 84));
assertThat(result.reference(95, 5)).isSameAs(result.symbol("num", 94));
assertThat(result.reference(102, 5)).isSameAs(result.symbol("varargs", 100));
assertThat(result.reference(103, 5)).isSameAs(result.symbol("varargs", 100));
assertThat(result.reference(104, 5)).isSameAs(result.symbol("varargs", 100));
assertThat(result.reference(105, 5)).isSameAs(result.symbol("varargs", 100));
assertThat(result.reference(106, 5)).isSameAs(result.symbol("varargs", 111));
assertThat(result.reference(121, 5)).isSameAs(result.symbol("fun1", 115));
assertThat(result.reference(122, 5)).isSameAs(result.symbol("fun2", 116));
assertThat(result.reference(123, 5)).isSameAs(result.symbol("fun3", 117));
assertThat(result.reference(124, 5)).isSameAs(result.symbol("fun4", 118));
assertThat(result.reference(125, 5)).isSameAs(result.symbol("fun5", 119));
assertThat(result.reference(132, 5)).isSameAs(result.symbol("fun", 131));
assertThat(result.reference(134, 5)).isSameAs(result.symbol("fun", 131));
assertThat(result.reference(143, 5)).isSameAs(result.symbol("process", 140));
assertThat(result.reference(144, 5)).isSameAs(result.symbol("process", 141));
assertThat(result.reference(149, 5)).isSameAs(result.symbol("process2", 147));
assertThat(result.reference(150, 5)).isSameAs(result.symbol("process2", 146));
assertThat(result.reference(156, 5)).isSameAs(result.symbol("process3", 153));
assertThat(result.reference(157, 5)).isSameAs(result.symbol("process3", 154));
assertThat(result.reference(169, 5)).isSameAs(result.symbol("varargs", 162));
assertThat(result.reference(170, 5)).isSameAs(result.symbol("varargs", 165));
assertThat(result.reference(180, 5)).isSameAs(result.symbol("varargs2", 173));
assertThat(result.reference(181, 5)).isSameAs(result.symbol("varargs2", 176));
assertThat(result.reference(204, 63, "<init>")).isSameAs(result.symbol("<init>", 188));
assertThat(result.reference(205, 24)).isSameAs(result.symbol("genericMethod", 191));
assertThat(result.reference(206, 77, "<init>")).isSameAs(result.symbol("<init>", 196));
assertThat(result.reference(207, 31)).isSameAs(result.symbol("complexGenericMethod", 199));
assertThat(result.reference(208, 40, "<init>")).isSameAs(result.symbol("<init>", 196));
assertThat(result.reference(209, 43, "<init>")).isSameAs(result.symbol("<init>", 196));
assertThat(result.reference(210, 64, "<init>")).isSameAs(result.symbol("<init>", 196));
assertThat(result.reference(221, 5)).isSameAs(result.symbol("varargs3", 216));
assertThat(result.reference(222, 5)).isSameAs(result.symbol("varargs4", 218));
assertThat(result.reference(236, 5)).isSameAs(result.symbol("varargs5", 227));
assertThat(result.reference(237, 5)).isSameAs(result.symbol("varargs5", 227));
assertThat(result.reference(238, 5)).isSameAs(result.symbol("varargs6", 233));
assertThat(result.reference(239, 5)).isSameAs(result.symbol("varargs6", 233));
assertThat(result.reference(254, 9)).isSameAs(result.symbol("by", 251));
assertThat(result.reference(264, 7)).isSameAs(result.symbol("by", 246));
assertThat(result.reference(265, 7)).isSameAs(result.symbol("by", 251));
assertThat(result.reference(256, 9)).isSameAs(result.symbol("of", 250));
assertThat(result.reference(257, 9)).isSameAs(result.symbol("of", 245));
assertThat(result.reference(267, 7)).isSameAs(result.symbol("of", 245));
assertThat(result.reference(268, 7)).isSameAs(result.symbol("of", 250));
assertThat(result.reference(269, 7)).isSameAs(result.symbol("of", 245));
assertThat(result.reference(277, 5)).isSameAs(result.symbol("foo", 274));
assertThat(result.reference(278, 13)).isSameAs(result.symbol("foo", 274));
assertThat(result.reference(295, 5)).isSameAs(result.symbol("to", 290));
assertThat(result.reference(296, 5)).isSameAs(result.symbol("to", 289));
assertThat(result.reference(298, 5)).isSameAs(result.symbol("from", 302));
assertThat(result.reference(297, 5)).isSameAs(result.symbol("from", 301));
assertThat(result.reference(310, 5)).isSameAs(result.symbol("cast", 314));
assertThat(result.reference(330, 31)).isSameAs(result.symbol("in", 320));
assertThat(result.reference(330, 12)).isSameAs(result.symbol("removeIf", 325));
assertThat(result.reference(342, 5)).isSameAs(result.symbol("myMethod", 339));
assertThat(result.symbol("myMethod", 338).usages()).isEmpty();
JavaSymbol add = result.symbol("add");
assertThat(add.usages()).hasSize(1);
}
@Test
public void FieldTypes() {
Result result = Result.createFor("FieldTypes");
assertThat(result.symbol("fieldBoolean").type.symbol.name).isEqualTo("Boolean");
assertThat(result.symbol("fieldBoolean").type.symbol.owner().name).isEqualTo("java.lang");
assertThat(result.symbol("fieldList").type.toString()).isEqualTo("List");
assertThat(result.symbol("fieldList").type.symbol.owner.name).isEqualTo("java.util");
assertThat(result.symbol("fieldInt").type).isNotNull();
assertThat(result.symbol("fieldInt").type.symbol.name).isEqualTo("int");
}
@Test
public void ArrayTypes() {
Result result = Result.createFor("ArrayTypes");
assertThat(result.symbol("strings1").type.symbol.name).isEqualTo("Array");
assertThat(result.symbol("strings2").type.symbol.name).isEqualTo("Array");
assertThat(result.symbol("strings3").type.symbol.name).isEqualTo("Array");
assertThat(result.symbol("strings3").type.toString()).isEqualTo("String[][][]");
assertThat(result.symbol("objects").type.toString()).isEqualTo("Object[][][]");
}
@Test
public void ThisReference() {
Result result = Result.createFor("references/ThisReference");
JavaSymbol classA = result.symbol("A");
assertThat(result.reference(7, 5).type.symbol).isEqualTo(classA);
assertThat(result.reference(17, 17).type.symbol).isEqualTo(result.symbol("theHashtable").type.symbol);
}
@Test
public void DeprecatedSymbols() {
Result result = Result.createFor("DeprecatedSymbols");
JavaSymbol sym = result.symbol("A");
assertThat(sym.isDeprecated()).isTrue();
sym = result.symbol("field");
assertThat(sym.isDeprecated()).isTrue();
sym = result.symbol("fun");
assertThat(sym.isDeprecated()).isTrue();
}
/**
* This test covers cases used as examples of ambiguous method invocations in JEP 302: Lambda Leftovers.
* These cases are not resolved and causes compilations errors in java 8.
*
* We are correctly resolving them.
*
* @see <a href="http://openjdk.java.net/jeps/302">JEP-302</a>
*/
@Test
public void java8_ambiguous_method_invocations_as_for_JEP302() {
Result result = Result.createFor("Java8AmbiguousMethodInvocationsJEP302");
assertThat(usageLines(result.symbol("m", 9))).containsExactly(4, 5);
assertThat(usageLines(result.symbol("m", 10))).isEmpty();
assertThat(usageLines(result.symbol("m2", 12))).containsExactly(6);
assertThat(usageLines(result.symbol("m2", 13))).isEmpty();
assertThat(usageLines(result.symbol("g", 33))).containsExactly(5);
assertThat(usageLines(result.symbol("g", 34))).isEmpty();
assertThat(usageLines(result.symbol("f", 38))).containsExactly(6);
assertThat(usageLines(result.symbol("f", 39))).isEmpty();
}
private static List<Integer> usageLines(JavaSymbol symbol) {
return symbol.usages().stream().map(IdentifierTree::firstToken).map(SyntaxToken::line).collect(Collectors.toList());
}
@Test
public void Lambdas() throws Exception {
Result result = Result.createFor("Lambdas");
JavaSymbol barMethod = result.symbol("bar");
assertThat(barMethod.usages()).hasSize(1);
MethodTree methodTree = (MethodTree) barMethod.declaration();
Type Ftype = result.symbol("F").type();
assertThat(((ReturnStatementTree) methodTree.block().body().get(0)).expression().symbolType()).isSameAs(Ftype);
JavaSymbol qixMethod = result.symbol("qix");
LambdaExpressionTree lamdba = ((LambdaExpressionTree) ((ReturnStatementTree) ((MethodTree) qixMethod.declaration()).block().body().get(0)).expression());
assertThat(((ReturnStatementTree) ((BlockTree) lamdba.body()).body().get(0)).expression().symbolType()).isSameAs(result.symbol("F2").type());
JavaSymbol fieldSymbol = result.symbol("field");
assertThat(((VariableTree) fieldSymbol.declaration()).initializer().symbolType()).isSameAs(fieldSymbol.type());
assertThat(((AssignmentExpressionTree) fieldSymbol.usages().get(0).parent()).expression().symbolType()).isSameAs(fieldSymbol.type());
JavaSymbol bSymbol = result.symbol("b");
assertThat(((NewClassTree) ((VariableTree) bSymbol.declaration()).initializer()).arguments().get(0).symbolType()).isSameAs(Ftype);
JavaSymbol condMethod = result.symbol("cond");
ConditionalExpressionTree conditionalExpression = (ConditionalExpressionTree) ((ReturnStatementTree) ((MethodTree) condMethod.declaration()).block().body().get(0)).expression();
assertThat(conditionalExpression.symbolType()).isSameAs(Ftype);
JavaSymbol parenthMethod = result.symbol("parenth");
ParenthesizedTree parenthesizedTree = (ParenthesizedTree) ((ReturnStatementTree) ((MethodTree) parenthMethod.declaration()).block().body().get(0)).expression();
assertThat(parenthesizedTree.symbolType()).isSameAs(Ftype);
assertThat(result.symbol("s", 33).type().is("java.lang.String")).isTrue();
JavaSymbol sym = result.symbol("o");
assertThat(sym.type.is("java.lang.Object")).isTrue();
assertThat(result.reference(8, 16)).isEqualTo(result.symbol("v", 8));
assertThat(result.reference(9, 16)).isEqualTo(result.symbol("v", 9));
JavaSymbol operations = result.symbol("operations");
MethodInvocationTree mit = (MethodInvocationTree) operations.usages().get(0).parent().parent();
assertThat(((ParametrizedTypeJavaType) operations.type).typeSubstitution.substitutedTypes().get(0)).isSameAs(mit.arguments().get(0).symbolType());
JavaSymbol myStringParam = result.symbol("myStringParam");
Symbol.MethodSymbol stringParamMethod = (Symbol.MethodSymbol) result.symbol("stringParamMethod");
assertThat(stringParamMethod.usages()).hasSize(1);
assertThat(myStringParam.type.is("java.lang.String")).isTrue();
assertThat(result.symbol("s1").type.is("java.lang.String")).as(result.symbol("s1").type.name()).isTrue();
assertThat(result.symbol("s2").type.is("java.lang.String")).isTrue();
assertThat(result.symbol("foo", 95).usages()).hasSize(1);
assertThat(result.symbol("x", 103).type.is("java.lang.Integer")).as(result.symbol("x",103).type.name()).isTrue();
}
@Test
public void MethodReference() throws Exception {
Result result = Result.createFor("MethodReferences");
JavaSymbol methodReference = result.symbol("methodReference");
assertThat(methodReference.usages()).hasSize(3);
JavaSymbol bar = result.symbol("bar");
assertThat(bar.usages()).hasSize(3);
JavaSymbol qix = result.symbol("qix");
assertThat(result.reference(11, 27)).isSameAs(bar);
assertThat(result.reference(12, 30)).isSameAs(bar);
assertThat(result.reference(13, 24)).isSameAs(qix);
assertThat(result.reference(14, 17)).isSameAs(bar);
assertThat(result.reference(11, 21).owner).isSameAs(result.symbol("A"));
assertThat(result.reference(11, 21).getName()).isEqualTo("this");
assertThat(result.reference(12, 25).owner).isSameAs(result.symbol("A"));
assertThat(result.reference(13, 21)).isSameAs(result.symbol("A"));
JavaSymbol methodRefConstructor = result.symbol("methodRefConstructor");
assertThat(methodRefConstructor.usages()).hasSize(1);
assertThat(methodRefConstructor.isMethodSymbol()).isTrue();
assertThat(((Symbol.MethodSymbol) methodRefConstructor).parameterTypes().get(0)).isSameAs(result.symbol("AProducer").type);
}
@Test
public void MethodReferenceUsingThis() throws Exception {
Result result = Result.createFor("MethodReferencesThis");
JavaSymbol bar1 = result.symbol("bar1");
assertThat(bar1.usages()).hasSize(2);
JavaSymbol bar = result.symbol("bar");
assertThat(bar.usages()).hasSize(1);
MethodReferenceTree methodRef = (MethodReferenceTree) bar.usages().get(0).parent();
assertThat(methodRef.symbolType().is("java.util.function.Consumer")).isTrue();
MethodInvocationTree foreach = (MethodInvocationTree) methodRef.parent().parent();
assertThat(foreach.symbol().owner().type().is("java.lang.Iterable")).isTrue();
}
@Test
public void MethodReferenceWithArrayNew() throws Exception {
Result result = Result.createFor("MethodReferencesArrayNew");
JavaSymbol bar = result.symbol("bar");
assertThat(bar.usages()).hasSize(1);
MethodInvocationTree callingBar = (MethodInvocationTree) bar.usages().get(0).parent();
MethodInvocationTree toArray = (MethodInvocationTree) callingBar.arguments().get(0);
assertThat(toArray.symbolType().is("B[][]")).isTrue();
JavaSymbol bool = result.symbol("bool");
assertThat(bool.usages()).hasSize(1);
}
@Test
public void MethodReferenceWithStream() throws Exception {
Result result = Result.createFor("MethodReferencesStream");
JavaSymbol flatipus1 = result.symbol("flatipus1");
assertThat(flatipus1.usages()).hasSize(1);
MethodInvocationTree flatMap = (MethodInvocationTree) flatipus1.usages().get(0).parent().parent().parent();
Type symbolType = flatMap.symbolType();
assertThat(symbolType.is("java.util.Optional")).isTrue();
JavaSymbol flatipus2 = result.symbol("flatipus2");
assertThat(flatipus2.usages()).hasSize(1);
JavaSymbol bool = result.symbol("bool");
assertThat(bool.usages()).hasSize(1);
}
@Test
public void MethodReferencesNoArguments() throws Exception {
Result result = Result.createFor("MethodReferencesNoArguments");
JavaSymbol isTrue = result.symbol("isTrue");
assertThat(isTrue.usages()).hasSize(1);
JavaSymbol isFalse = result.symbol("isFalse");
assertThat(isFalse.usages()).hasSize(1);
JavaSymbol up = result.symbol("up");
assertThat(up.usages()).hasSize(1);
Tree upMethodRef = up.usages().get(0).parent();
MethodInvocationTree map = (MethodInvocationTree) upMethodRef.parent().parent();
JavaType mapType = (JavaType) map.symbolType();
assertThat(mapType.is("java.util.stream.Stream")).isTrue();
assertThat(mapType.isParameterized()).isTrue();
List<JavaType> substitutedTypes = ((ParametrizedTypeJavaType) mapType).typeSubstitution.substitutedTypes();
assertThat(substitutedTypes).hasSize(1);
assertThat(substitutedTypes.get(0).is("A$B")).isTrue();
JavaSymbol bool = result.symbol("bool", 28);
assertThat(bool.usages().stream().map(id -> id.identifierToken().line()).collect(Collectors.toList())).containsExactly(11, 12, 13);
bool = result.symbol("bool", 29);
assertThat(bool.usages().stream().map(id -> id.identifierToken().line()).collect(Collectors.toList())).containsExactly(14, 15);
}
@Test
public void MethodReferencesTypeArguments() throws Exception {
Result result = Result.createFor("MethodReferencesTypeArguments");
JavaSymbol getValue = result.symbol("getValue");
// FIXME SONARJAVA-1663 type arguments are currently ignored
assertThat(getValue.usages()).hasSize(0);
}
@Test
public void UnionType() throws Exception {
Result result = Result.createFor("UnionTypes");
JavaSymbol exceptionVariableSymbol = result.symbol("e0");
assertThat(exceptionVariableSymbol.type()).isNotSameAs(Symbols.unknownType);
assertThat(exceptionVariableSymbol.type().is("java.lang.Exception")).isTrue();
JavaSymbol methodSymbol = result.reference(6, 13);
assertThat(methodSymbol.owner).isSameAs(result.symbol("UnionTypes"));
JavaSymbol methodDeclarationSymbol = result.symbol("unwrapException", 18);
assertThat(methodSymbol).isEqualTo(methodDeclarationSymbol);
assertThat(methodDeclarationSymbol.usages()).hasSize(1);
exceptionVariableSymbol = result.symbol("e1");
assertThat(exceptionVariableSymbol.type()).isNotSameAs(Symbols.unknownType);
assertThat(exceptionVariableSymbol.type().is("UnionTypes$B")).isTrue();
methodSymbol = result.reference(8, 13);
assertThat(methodSymbol.owner).isSameAs(result.symbol("UnionTypes"));
methodDeclarationSymbol = result.symbol("unwrapException", 22);
assertThat(methodSymbol).isEqualTo(methodDeclarationSymbol);
assertThat(methodDeclarationSymbol.usages()).hasSize(1);
assertThat(exceptionVariableSymbol.usages()).hasSize(1);
try {
exceptionVariableSymbol.usages().clear();
fail("list of usages of a symbol is not immutable");
} catch (UnsupportedOperationException uoe) {
assertThat(exceptionVariableSymbol.usages()).hasSize(1);
}
exceptionVariableSymbol = result.symbol("e2");
assertThat(exceptionVariableSymbol.type()).isEqualTo(Symbols.unknownType);
methodDeclarationSymbol = result.symbol("unwrapException", 26);
assertThat(methodDeclarationSymbol.usages()).isEmpty();
}
@Test
public void symbolNotFound() throws Exception {
Result result = Result.createFor("SymbolsNotFound");
MethodTree methodDeclaration = (MethodTree) result.symbol("method").declaration();
ExpressionStatementTree expression = (ExpressionStatementTree) methodDeclaration.block().body().get(0);
MethodInvocationTree methodInvocation = (MethodInvocationTree) expression.expression();
Symbol symbolNotFound = methodInvocation.symbol();
assertThat(symbolNotFound).isNotNull();
assertThat(symbolNotFound.name()).isNull();
assertThat(symbolNotFound.owner()).isSameAs(Symbols.unknownSymbol);
}
@Test
public void annotations_on_fields() throws Exception {
Result result = Result.createFor("AnnotationOnFields");
JavaSymbol.TypeSymbol app = (JavaSymbol.TypeSymbol) result.symbol("App");
for (Symbol sym : app.memberSymbols()) {
if (!sym.isMethodSymbol() && !(sym.name().equals("super") || sym.name().equals("this"))) {
assertThat(sym.metadata().isAnnotatedWith("java.lang.Deprecated")).isTrue();
}
}
}
@Test
public void try_with_resources() {
Result result = Result.createFor("references/TryWithResources");
assertThat(result.symbol("foo3", 4)).isSameAs(result.reference(5, 7));
assertThat(result.symbol("foo3", 7)).isSameAs(result.reference(8, 7));
}
@Test
public void switch_statement() {
Result result = Result.createFor("SwitchStatement");
assertThat(result.symbol("a", 16)).isSameAs(result.reference(18, 28));
assertThat(result.symbol("a", 20)).isSameAs(result.reference(21, 24));
}
@Test
public void wildcard_invocation_inference() {
Result result = Result.createFor("WildcardsInvocation");
assertThat(result.symbol("fun")).isSameAs(result.reference(11, 5));
assertThat(result.symbol("foo")).isSameAs(result.reference(20, 5));
}
@Test
public void inference_on_parameterized_method_with_no_arg() {
Result result = Result.createFor("ParameterizedMethodInvocation");
assertThat(result.symbol("method")).isSameAs(result.reference(3, 9));
assertThat(result.symbol("fun")).isSameAs(result.reference(3, 5));
}
@Test
public void lookup_method_on_defered_type() throws Exception {
Result result = Result.createFor("InferedCascadedReturnType");
JavaSymbol sortKeysByValue = result.symbol("sortKeysByValue");
JavaSymbol reverse = result.symbol("reverse");
//lookup on defered type allow method resolution
assertThat(sortKeysByValue.usages()).hasSize(1);
//Lack of resolution when target type is deduced, we should be able to redo the lookup
assertThat(reverse.usages()).isEmpty();
}
@Test
public void infer_fully_lambda_types() {
Result result = Result.createFor("InferLambdaType");
// Check lambda with a block return type.
assertThat(getRSubstitution(result, "line0").is("java.lang.String[]")).isTrue();
// Check lambda with a block with multiple return (using lub).
assertThat(getRSubstitution(result, "line1").is("java.lang.Number")).isTrue();
// Check lambda with a block only throwing.
assertThat(getRSubstitution(result, "line2").isTagged(JavaType.WILDCARD)).isTrue();
// Check lambda with nested returns
assertThat(getRSubstitution(result, "line3").is("java.lang.Integer")).isTrue();
// Check one liner lambdas
assertThat(getRSubstitution(result, "line").is("java.lang.String[]")).isTrue();
MethodInvocationTree mapMethod = (MethodInvocationTree) result.symbol("line").declaration().parent().parent().parent();
Type mapType = mapMethod.symbolType();
assertThat(mapType.is("java.util.stream.Stream")).as("Found "+ mapType +" instead of Stream").isTrue();
assertThat(((JavaType) mapType).isParameterized()).isTrue();
assertThat(((ParametrizedTypeJavaType) mapType).typeSubstitution.substitutedTypes()).hasSize(1);
assertThat(((ParametrizedTypeJavaType) mapType).typeSubstitution.substitutedTypes().get(0).is("java.lang.String[]")).isTrue();
JavaSymbol sx = result.symbol("sx");
assertThat(sx.type.is("java.lang.String")).isTrue();
}
@Test
public void infer_steam_types_on_chained_map() {
Result result = Result.createFor("InferLambdaType");
JavaSymbol stringToBoolean = result.symbol("stringToBoolean");
assertThat(stringToBoolean.usages()).hasSize(2);
assertThat(result.reference(63, 17)).isEqualTo(stringToBoolean);
assertThat(result.reference(67, 17)).isEqualTo(stringToBoolean);
IdentifierTree map = result.referenceTree(63, 8);
MethodJavaType methodJavaType = (MethodJavaType) map.symbolType();
// expression type is correctly infered but method type is not recomputed and thus is still defered
assertThat(methodJavaType.resultType.isTagged(JavaType.DEFERRED)).isTrue();
JavaSymbol booleanToInt = result.symbol("booleanToInt");
assertThat(booleanToInt.usages()).hasSize(1);
assertThat(result.reference(68, 17)).isEqualTo(booleanToInt);
JavaSymbol intToInt = result.symbol("intToInt");
assertThat(intToInt.usages()).hasSize(1);
assertThat(result.reference(72, 20)).isEqualTo(intToInt);
}
private JavaType getRSubstitution(Result result, String symbolName) {
LambdaExpressionTree lambda = ((LambdaExpressionTree) result.symbol(symbolName).declaration().parent());
JavaType lambdaType = (JavaType) lambda.symbolType();
assertThat(lambdaType.isParameterized()).isTrue();
assertThat(lambdaType.is("java.util.function.Function")).isTrue();
TypeSubstitution typeSubstitution = ((ParametrizedTypeJavaType) lambdaType).typeSubstitution;
assertThat(typeSubstitution.size()).isEqualTo(2);
JavaType Tsubstitution = typeSubstitution.substitutedTypes().get(0);
// check that T -> ? super String
assertThat(Tsubstitution.isTagged(JavaType.WILDCARD)).isTrue();
assertThat(((WildCardType) Tsubstitution).boundType).isEqualTo(WildCardType.BoundType.SUPER);
assertThat(((WildCardType) Tsubstitution).bound.is("java.lang.String")).isTrue();
return typeSubstitution.substitutedTypes().get(1);
}
@Test
public void infer_from_type_variable_bounds() throws Exception {
Result result = Result.createFor("TypeVarBoundsInference");
assertThat(result.symbol("write1").usages()).hasSize(1);
assertThat(result.symbol("write2").usages()).hasSize(1);
assertThat(result.symbol("noneOf").usages()).hasSize(1);
JavaType type = ((MethodJavaType) result.symbol("noneOf").usages().get(0).symbolType()).resultType;
assertThat(type.is("java.util.EnumSet")).isTrue();
assertThat(type.isTagged(JavaType.PARAMETERIZED)).isTrue();
List<JavaType> substitutedTypes = ((ParametrizedTypeJavaType) type).typeSubstitution.substitutedTypes();
assertThat(substitutedTypes).hasSize(1);
assertThat(substitutedTypes.get(0).is("A$MyENUM")).isTrue();
}
@Test
public void return_type_of_map_method() throws Exception {
Result result = Result.createFor("MapMethod");
assertThat(result.symbol("test1").usages()).hasSize(1);
assertThat(result.symbol("test2").usages()).hasSize(1);
assertThat(result.symbol("test3").usages()).hasSize(1);
}
@Test
public void infer_method_invocation_return_type() throws Exception {
Result result = Result.createFor("CollectorsToList");
List<IdentifierTree> usages = result.symbol("foo").usages();
assertThat(usages).hasSize(1);
ExpressionTree arg = ((MethodInvocationTree) usages.get(0).parent()).arguments().get(0);
assertThat(arg.symbolType().is("java.util.List")).isTrue();
assertThat(((JavaType) arg.symbolType()).isParameterized()).isTrue();
assertThat(((ParametrizedTypeJavaType) arg.symbolType()).typeSubstitution.substitutedTypes()).hasSize(1);
assertThat(((ParametrizedTypeJavaType) arg.symbolType()).typeSubstitution.substitutedTypes().get(0).is("java.lang.String")).isTrue();
usages = result.symbol("foo2").usages();
assertThat(usages).hasSize(1);
arg = ((MethodInvocationTree) usages.get(0).parent()).arguments().get(0);
assertThat(arg.symbolType().is("java.util.LinkedHashSet")).overridingErrorMessage("Expected java.util.Collection but got "+arg.symbolType().name()).isTrue();
assertThat(((JavaType) arg.symbolType()).isParameterized()).isTrue();
assertThat(((ParametrizedTypeJavaType) arg.symbolType()).typeSubstitution.substitutedTypes()).hasSize(1);
assertThat(((ParametrizedTypeJavaType) arg.symbolType()).typeSubstitution.substitutedTypes().get(0).is("java.lang.String")).isTrue();
}
@Test
public void infer_method_invocation_return_type_on_chained_parameterized_methods() throws Exception {
Result result = Result.createFor("ChainedParameterizedMethods");
List<IdentifierTree> usages = result.symbol("newBounds").usages();
assertThat(usages).hasSize(1);
}
@Test
public void method_reference_as_variable_initializer() {
Result result = Result.createFor("MethodReferencesVariableInitializers");
JavaSymbol invalidate = result.symbol("invalidate");
assertThat(invalidate.usages()).hasSize(1);
assertThat(result.reference(4, 46)).isEqualTo(invalidate);
JavaSymbol foo = result.symbol("foo");
assertThat(foo.usages()).hasSize(1);
assertThat(result.reference(5, 54)).isEqualTo(foo);
}
@Test
public void double_lambda_type_propagation() {
Result result = Result.createFor("DoubleLambda");
JavaSymbol my = result.symbol("my");
assertThat(my.usages()).hasSize(2);
}
@Test
public void method_reference_constructor_inference() throws Exception {
Result result = Result.createFor("ConstructorInMethodRef");
MethodTree methodTree = (MethodTree) result.symbol("erased").declaration();
Type returnStatementType = ((ReturnStatementTree) methodTree.block().body().get(0)).expression().symbolType();
assertThat(returnStatementType.is("java.util.List")).isTrue();
assertThat(((JavaType) returnStatementType).isParameterized()).isTrue();
assertThat(((ParametrizedTypeJavaType) returnStatementType).typeSubstitution.substitutedTypes()).hasSize(1);
assertThat(((ParametrizedTypeJavaType) returnStatementType).typeSubstitution.substitutedTypes().get(0).is("java.util.LinkedHashSet")).isTrue();
methodTree = (MethodTree) result.symbol("erased2").declaration();
returnStatementType = ((ReturnStatementTree) methodTree.block().body().get(0)).expression().symbolType();
assertThat(returnStatementType.is("java.util.List")).isTrue();
assertThat(((JavaType) returnStatementType).isParameterized()).isTrue();
assertThat(((ParametrizedTypeJavaType) returnStatementType).typeSubstitution.substitutedTypes()).hasSize(1);
assertThat(((ParametrizedTypeJavaType) returnStatementType).typeSubstitution.substitutedTypes().get(0).is("java.util.LinkedHashSet")).isTrue();
}
@Test
public void conditional_expression_in_lambda() {
Result result = Result.createFor("ConditionalExpressionInLambda");
JavaSymbol foo = result.symbol("foo");
assertThat(foo.usages()).hasSize(1);
IdentifierTree map = result.referenceTree(8, 8);
MethodJavaType mapJavaType = (MethodJavaType) map.symbolType();
// expression type is correctly inferred but method type is not recomputed and thus is still deferred
assertThat(mapJavaType.resultType.isTagged(JavaType.DEFERRED)).isTrue();
JavaType lambdaType = (JavaType) ((MethodInvocationTree) map.parent().parent()).arguments().get(0).symbolType();
assertThat(lambdaType.isParameterized()).isTrue();
assertThat(lambdaType.is("java.util.function.Function")).isTrue();
// only interested in return type: LUB of Integer and String
JavaType returnType = ((ParametrizedTypeJavaType) lambdaType).typeSubstitution.substitutedTypes().get(1);
assertThat(returnType.isSubtypeOf("java.lang.Comparable")).isTrue();
JavaSymbol bar = result.symbol("bar");
assertThat(bar.usages()).hasSize(1);
IdentifierTree flatMap = result.referenceTree(13, 8);
MethodJavaType flatMapJavaType = (MethodJavaType) flatMap.symbolType();
// expression type is correctly inferred but method type is not recomputed and thus is still deferred
assertThat(flatMapJavaType.resultType.isTagged(JavaType.DEFERRED)).isTrue();
lambdaType = (JavaType) ((MethodInvocationTree) flatMap.parent().parent()).arguments().get(0).symbolType();
assertThat(lambdaType.isParameterized()).isTrue();
assertThat(lambdaType.is("java.util.function.Function")).isTrue();
// only interested in return type: LUB of deferred type Stream.empty() and Stream<Integer>
returnType = ((ParametrizedTypeJavaType) lambdaType).typeSubstitution.substitutedTypes().get(1);
assertThat(returnType.isParameterized()).isTrue();
assertThat(returnType.is("java.util.stream.Stream")).isTrue();
JavaType substitution = ((ParametrizedTypeJavaType) returnType).typeSubstitution.substitutedTypes().get(0);
assertThat(substitution.is("java.lang.Integer")).isTrue();
}
@Test
public void getClass_return_type() {
Result result = Result.createFor("GetClassReturnType");
JavaSymbol maybeAddListener = result.symbol("maybeAddListener");
assertThat(maybeAddListener.isMethodSymbol()).isTrue();
List<IdentifierTree> usages = maybeAddListener.usages();
assertThat(usages).hasSize(1);
Type getClassType = ((MethodInvocationTree) usages.get(0).parent()).arguments().get(1).symbolType();
assertThat(getClassType).isInstanceOf(ParametrizedTypeJavaType.class);
Type param = ((ParametrizedTypeJavaType) getClassType).typeSubstitution.substitutedTypes().get(0);
assertThat(param).isInstanceOf(WildCardType.class);
assertThat(((WildCardType) param).boundType).isEqualTo(WildCardType.BoundType.EXTENDS);
assertThat(((WildCardType) param).bound.is("ISuiteListener")).isTrue();
}
@Test
public void lambda_on_sam_interface_defining_object_methods() throws Exception {
Result result = Result.createFor("SAMResolution");
assertThat(((VariableTree) result.symbol("var").declaration()).initializer().symbolType().is("A$MySAM")).isTrue();
assertThat(((VariableTree) result.symbol("var2").declaration()).initializer().symbolType().is("A$MySAM2")).isTrue();
}
}