use of com.sun.tools.javac.code.Symbol.ClassSymbol in project error-prone by google.
the class ImmutableEnumChecker method matchClass.
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
ClassSymbol symbol = getSymbol(tree);
if (symbol == null || !symbol.isEnum()) {
return NO_MATCH;
}
if (ASTHelpers.hasAnnotation(symbol, Immutable.class, state) && !implementsImmutableInterface(symbol)) {
AnnotationTree annotation = ASTHelpers.getAnnotationWithSimpleName(tree.getModifiers().getAnnotations(), "Immutable");
if (annotation != null) {
state.reportMatch(buildDescription(annotation).setMessage(ANNOTATED_ENUM_MESSAGE).addFix(SuggestedFix.delete(annotation)).build());
} else {
state.reportMatch(buildDescription(tree).setMessage(ANNOTATED_ENUM_MESSAGE).build());
}
}
Violation info = new ImmutableAnalysis(this, state, "enums should be immutable, and cannot have non-final fields", "enums should only have immutable fields").checkForImmutability(Optional.of(tree), ImmutableSet.of(), getType(tree));
if (!info.isPresent()) {
return NO_MATCH;
}
String message = "enums should be immutable: " + info.message();
return buildDescription(tree).setMessage(message).build();
}
use of com.sun.tools.javac.code.Symbol.ClassSymbol in project error-prone by google.
the class WrongParameterPackage method matchMethod.
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
MethodSymbol method = ASTHelpers.getSymbol(tree);
if (method == null) {
return Description.NO_MATCH;
}
ClassSymbol classSym = method.enclClass();
if (classSym == null) {
return Description.NO_MATCH;
}
TypeSymbol superClass = classSym.getSuperclass().tsym;
if (superClass == null) {
return Description.NO_MATCH;
}
for (Symbol s : superClass.members().getSymbols()) {
if (s.name.contentEquals(method.name) && s.getKind() == ElementKind.METHOD) {
MethodSymbol supermethod = (MethodSymbol) s;
// if this method actually overrides the supermethod, then it's correct and not a match.
if (method.overrides(supermethod, superClass, state.getTypes(), true)) {
return Description.NO_MATCH;
}
// if this doesn't have the right number of parameters, look at other ones.
if (supermethod.params().size() != method.params().size()) {
continue;
}
for (int x = 0; x < method.params().size(); x++) {
Type methodParamType = method.params().get(x).type;
Type supermethodParamType = supermethod.params().get(x).type;
if (methodParamType.tsym.name.contentEquals(supermethodParamType.tsym.name) && !state.getTypes().isSameType(methodParamType, supermethodParamType)) {
this.supermethod = supermethod;
return describe(tree, state);
}
}
}
}
return Description.NO_MATCH;
}
use of com.sun.tools.javac.code.Symbol.ClassSymbol in project error-prone by google.
the class EqualsIncompatibleType method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree invocationTree, final VisitorState state) {
if (!STATIC_EQUALS_INVOCATION_MATCHER.matches(invocationTree, state) && !INSTANCE_EQUALS_INVOCATION_MATCHER.matches(invocationTree, state)) {
return Description.NO_MATCH;
}
// This is the type of the object on which the java.lang.Object.equals() method
// is called, either directly or indirectly via a static utility method. In the latter,
// it is the type of the first argument to the static method.
Type receiverType;
// This is the type of the argument to the java.lang.Object.equals() method.
// In case a static utility method is used, it is the type of the second argument
// to this method.
Type argumentType;
if (STATIC_EQUALS_INVOCATION_MATCHER.matches(invocationTree, state)) {
receiverType = ASTHelpers.getType(invocationTree.getArguments().get(0));
argumentType = ASTHelpers.getType(invocationTree.getArguments().get(1));
} else {
receiverType = ASTHelpers.getReceiverType(invocationTree);
argumentType = ASTHelpers.getType(invocationTree.getArguments().get(0));
}
if (receiverType == null || argumentType == null) {
return Description.NO_MATCH;
}
// 1.7: java.lang.Object can be cast to primitives (implicitly through the boxed primitive type)
if (ASTHelpers.isCastable(argumentType, receiverType, state)) {
return Description.NO_MATCH;
}
// Otherwise, we explore the superclasses of the receiver type as well as the interfaces it
// implements and we collect all overrides of java.lang.Object.equals(). If one of those
// overrides is inherited by the argument, then we don't flag the equality test.
final Types types = state.getTypes();
Predicate<MethodSymbol> equalsPredicate = new Predicate<MethodSymbol>() {
@Override
public boolean apply(MethodSymbol methodSymbol) {
return !methodSymbol.isStatic() && ((methodSymbol.flags() & Flags.SYNTHETIC) == 0) && types.isSameType(methodSymbol.getReturnType(), state.getSymtab().booleanType) && methodSymbol.getParameters().size() == 1 && types.isSameType(methodSymbol.getParameters().get(0).type, state.getSymtab().objectType);
}
};
Name equalsName = state.getName("equals");
Set<MethodSymbol> overridesOfEquals = ASTHelpers.findMatchingMethods(equalsName, equalsPredicate, receiverType, types);
ClassSymbol argumentClass = (ClassSymbol) argumentType.tsym;
for (MethodSymbol method : overridesOfEquals) {
ClassSymbol methodClass = method.enclClass();
if (argumentClass.isSubClass(methodClass, types) && !methodClass.equals(state.getSymtab().objectType.tsym) && !methodClass.equals(state.getSymtab().enumSym)) {
// with the receiver that implements an override of java.lang.Object.equals().
return Description.NO_MATCH;
}
}
// assertFalse(objOfReceiverType.equals(objOfArgumentType))
if (ASSERT_FALSE_MATCHER.matches(state.getPath().getParentPath().getLeaf(), state)) {
return Description.NO_MATCH;
}
// When we reach this point, we know that the two following facts hold:
// (1) The types of the receiver and the argument to the eventual invocation of
// java.lang.Object.equals() are incompatible.
// (2) No common superclass (other than java.lang.Object) or interface of the receiver and the
// argument defines an override of java.lang.Object.equals().
// This equality test almost certainly evaluates to false, which is very unlikely to be the
// programmer's intent. Hence, this is reported as an error. There is no sensible fix to suggest
// in this situation.
Description.Builder description = buildDescription(invocationTree);
description.setMessage("Calling " + ASTHelpers.getSymbol(invocationTree).getSimpleName() + " on incompatible types " + receiverType + " and " + argumentType);
return description.build();
}
use of com.sun.tools.javac.code.Symbol.ClassSymbol in project error-prone by google.
the class AmbiguousMethodReference method matchClass.
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
ClassSymbol origin = getSymbol(tree);
Types types = state.getTypes();
Iterable<Symbol> members = types.membersClosure(getType(tree), /*skipInterface=*/
false).getSymbols();
// collect declared and inherited methods, grouped by reference descriptor
Map<String, List<MethodSymbol>> methods = stream(members.spliterator(), false).filter(MethodSymbol.class::isInstance).map(MethodSymbol.class::cast).filter(m -> m.isConstructor() || m.owner.equals(origin)).collect(groupingBy(m -> methodReferenceDescriptor(types, m), toCollection(ArrayList::new)));
// look for groups of ambiguous method references
for (Tree member : tree.getMembers()) {
if (!(member instanceof MethodTree)) {
continue;
}
MethodSymbol msym = getSymbol((MethodTree) member);
if (isSuppressed(msym)) {
continue;
}
List<MethodSymbol> clash = methods.remove(methodReferenceDescriptor(types, msym));
if (clash == null) {
continue;
}
clash.remove(msym);
// ignore overridden inherited methods and hidden interface methods
clash.removeIf(m -> types.isSubSignature(msym.type, m.type));
if (clash.isEmpty()) {
continue;
}
String message = String.format("This method's reference is ambiguous, its name and functional interface type" + " are the same as: %s", clash.stream().map(m -> Signatures.prettyMethodSignature(origin, m)).collect(joining(", ")));
state.reportMatch(buildDescription(member).setMessage(message).build());
}
return NO_MATCH;
}
use of com.sun.tools.javac.code.Symbol.ClassSymbol in project error-prone by google.
the class FindIdentifiers method isVisible.
private static boolean isVisible(VarSymbol var, final TreePath path) {
switch(var.getKind()) {
case ENUM_CONSTANT:
case FIELD:
// TODO(eaftan): Switch collector to ImmutableList.toImmutableList() when released
List<ClassSymbol> enclosingClasses = StreamSupport.stream(path.spliterator(), false).filter(tree -> tree instanceof ClassTree).map(ClassTree.class::cast).map(ASTHelpers::getSymbol).collect(Collectors.toCollection(ArrayList::new));
if (!var.isStatic()) {
// Instance fields are not visible if we are in a static context...
if (inStaticContext(path)) {
return false;
}
// the enclosing static nested class (JLS 8.5.1).
if (lowerThan(path, (curr, unused) -> curr instanceof ClassTree && ASTHelpers.getSymbol((ClassTree) curr).isStatic(), (curr, unused) -> curr instanceof ClassTree && ASTHelpers.getSymbol((ClassTree) curr).equals(var.owner))) {
return false;
}
}
// fields (JLS 6.6.1).
if (enclosingClasses.contains(ASTHelpers.enclosingClass(var))) {
return true;
}
PackageSymbol enclosingPackage = ((JCCompilationUnit) path.getCompilationUnit()).packge;
Set<Modifier> modifiers = var.getModifiers();
// (JLS 6.6.1).
if (Objects.equals(enclosingPackage, ASTHelpers.enclosingPackage(var))) {
return !modifiers.contains(Modifier.PRIVATE);
}
// in the enclosing class or a superclass).
return modifiers.contains(Modifier.PUBLIC) || modifiers.contains(Modifier.PROTECTED);
case PARAMETER:
case LOCAL_VARIABLE:
// final or effectively final (JLS 8.1.3).
if (lowerThan(path, (curr, parent) -> curr.getKind() == Kind.LAMBDA_EXPRESSION || (curr.getKind() == Kind.NEW_CLASS && ((NewClassTree) curr).getClassBody() != null) || (curr.getKind() == Kind.CLASS && parent.getKind() == Kind.BLOCK), (curr, unused) -> Objects.equals(var.owner, ASTHelpers.getSymbol(curr)))) {
if ((var.flags() & (Flags.FINAL | Flags.EFFECTIVELY_FINAL)) == 0) {
return false;
}
}
return true;
case EXCEPTION_PARAMETER:
case RESOURCE_VARIABLE:
return true;
default:
throw new IllegalArgumentException("Unexpected variable type: " + var.getKind());
}
}
Aggregations