use of com.google.errorprone.matchers.Description in project error-prone by google.
the class FunctionalInterfaceClash method matchClass.
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
ClassSymbol origin = getSymbol(tree);
Types types = state.getTypes();
// collect declared and inherited methods whose signature contains a functional interface
Multimap<String, MethodSymbol> methods = HashMultimap.create();
for (Symbol sym : types.membersClosure(getType(tree), /*skipInterface=*/
false).getSymbols()) {
if (!(sym instanceof MethodSymbol)) {
continue;
}
if (isBugCheckerSuppressed((MethodSymbol) sym)) {
continue;
}
MethodSymbol msym = (MethodSymbol) sym;
if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
continue;
}
if (msym.isConstructor() && !msym.owner.equals(origin)) {
continue;
}
methods.put(functionalInterfaceSignature(state, msym), msym);
}
// (don't report clashes between inherited members)
for (Tree member : tree.getMembers()) {
if (!(member instanceof MethodTree)) {
continue;
}
MethodSymbol msym = getSymbol((MethodTree) member);
if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
continue;
}
Collection<MethodSymbol> clash = new ArrayList<>(methods.removeAll(functionalInterfaceSignature(state, msym)));
// Ignore inherited methods that are overridden in the original class. Note that we have to
// handle transitive inheritance explicitly to handle cases where the visibility of an
// overridded method is expanded somewhere in the type hierarchy.
Deque<MethodSymbol> worklist = new ArrayDeque<>();
worklist.push(msym);
clash.remove(msym);
while (!worklist.isEmpty()) {
MethodSymbol msym2 = worklist.removeFirst();
ImmutableList<MethodSymbol> overrides = clash.stream().filter(m -> msym2.overrides(m, origin, types, /*checkResult=*/
false)).collect(toImmutableList());
worklist.addAll(overrides);
clash.removeAll(overrides);
}
if (!clash.isEmpty()) {
// ignore if there are overridden clashing methods in class
if (ASTHelpers.findSuperMethod(msym, types).isPresent() && clash.stream().anyMatch(methodSymbol -> ASTHelpers.findSuperMethod(methodSymbol, types).isPresent())) {
return NO_MATCH;
}
String message = "When passing lambda arguments to this function, callers will need a cast to" + " disambiguate with: " + clash.stream().map(m -> Signatures.prettyMethodSignature(origin, m)).collect(joining("\n "));
state.reportMatch(buildDescription(member).setMessage(message).build());
}
}
return NO_MATCH;
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class HidingField method matchClass.
@Override
public Description matchClass(ClassTree classTree, VisitorState visitorState) {
List<VariableTree> originalClassMembers = classTree.getMembers().stream().filter(mem -> mem instanceof VariableTree).map(mem -> (VariableTree) mem).filter(mem -> !isSuppressed(ASTHelpers.getSymbol(mem)) && !isIgnoredType(mem) && !isStatic(mem)).collect(toCollection(ArrayList::new));
ClassSymbol classSymbol = ASTHelpers.getSymbol(classTree);
while (!Objects.equals(classSymbol.getSuperclass(), Type.noType)) {
TypeSymbol parentSymbol = classSymbol.getSuperclass().asElement();
List<Symbol> parentElements = parentSymbol.getEnclosedElements();
Map<Name, VarSymbol> parentMembers = parentElements.stream().filter(mem -> (mem instanceof VarSymbol)).map(mem -> (VarSymbol) mem).filter(mem -> (!mem.isPrivate() && !mem.getModifiers().contains(Modifier.STATIC))).collect(Collectors.toMap(Symbol::getSimpleName, mem -> mem));
checkForHiddenFields(originalClassMembers, parentMembers, parentSymbol.getSimpleName(), classTree, visitorState);
classSymbol = (ClassSymbol) parentSymbol;
}
return Description.NO_MATCH;
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class DefaultCharset method handlePrintWriterOutputStream.
private Description handlePrintWriterOutputStream(NewClassTree tree, VisitorState state) {
Tree outputStream = tree.getArguments().get(0);
Description.Builder description = buildDescription(tree);
for (CharsetFix charsetFix : CharsetFix.values()) {
SuggestedFix.Builder fix = SuggestedFix.builder().prefixWith(outputStream, "new BufferedWriter(new OutputStreamWriter(").postfixWith(outputStream, String.format(", %s))", charsetFix.replacement()));
charsetFix.addImport(fix, state);
fix.addImport("java.io.BufferedWriter");
fix.addImport("java.io.OutputStreamWriter");
description.addFix(fix.build());
}
return description.build();
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class DefaultCharset method handleFileWriter.
private Description handleFileWriter(NewClassTree tree, VisitorState state) {
Iterator<? extends ExpressionTree> it = tree.getArguments().iterator();
Tree fileArg = it.next();
Tree appendMode = it.hasNext() ? it.next() : null;
Tree parent = state.getPath().getParentPath().getLeaf();
Tree toReplace = BUFFERED_WRITER.matches(parent, state) ? parent : tree;
Description.Builder description = buildDescription(tree);
boolean useGuava = shouldUseGuava(state);
for (CharsetFix charset : CharsetFix.values()) {
if (appendMode == null && useGuava) {
description.addFix(guavaFileWriterFix(state, fileArg, toReplace, charset));
} else {
description.addFix(nioFileWriterFix(state, appendMode, fileArg, toReplace, charset, useGuava));
}
}
return description.build();
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class DefaultCharset method handleFileReader.
private Description handleFileReader(NewClassTree tree, VisitorState state) {
Tree arg = getOnlyElement(tree.getArguments());
Tree parent = state.getPath().getParentPath().getLeaf();
Tree toReplace = BUFFERED_READER.matches(parent, state) ? parent : tree;
Description.Builder description = buildDescription(tree);
fileReaderFix(description, state, arg, toReplace);
return description.build();
}
Aggregations