Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix CFGTranslationPhaseOne#findOwner() for lambdas #5045

Merged
merged 6 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions checker/tests/nullness/Issue5042.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;

public class Issue5042 {
interface PromptViewModel {
boolean isPending();

@Nullable PromptButtonViewModel getConfirmationButton();
}

interface PromptButtonViewModel {
@Nullable ConfirmationPopupViewModel getConfirmationPopup();
}

interface ConfirmationPopupViewModel {
boolean isShowingConfirmation();
}

boolean f(PromptViewModel viewModel) {
PromptButtonViewModel prompt = viewModel.getConfirmationButton();
ConfirmationPopupViewModel popup = prompt != null ? prompt.getConfirmationPopup() : null;
return viewModel.isPending() || (popup != null && popup.isShowingConfirmation());
}

static final Function<PromptViewModel, Boolean> IS_PENDING_OR_SHOWING_CONFIRMATION =
(viewModel) -> {
@Nullable PromptButtonViewModel promptLambda = viewModel.getConfirmationButton();
@Nullable ConfirmationPopupViewModel popup =
promptLambda != null ? promptLambda.getConfirmationPopup() : null;
return viewModel.isPending() || (popup != null && popup.isShowingConfirmation());
};

final Function<PromptViewModel, Boolean> IS_PENDING_OR_SHOWING_CONFIRMATION2 =
(viewModel) -> {
@Nullable PromptButtonViewModel prompt = viewModel.getConfirmationButton();
@Nullable ConfirmationPopupViewModel popup =
prompt == null ? null : prompt.getConfirmationPopup();
return viewModel.isPending() || (popup != null && popup.isShowingConfirmation());
};

@Nullable PromptButtonViewModel promptfield;
Producer o =
() -> {
@Nullable ConfirmationPopupViewModel popup =
promptfield == null ? null : promptfield.getConfirmationPopup();
return (popup != null && popup.isShowingConfirmation());
};

static @Nullable PromptButtonViewModel promptfield2;

static Producer o2 =
() -> {
@Nullable ConfirmationPopupViewModel popup =
promptfield2 == null ? null : promptfield2.getConfirmationPopup();
return (popup != null && popup.isShowingConfirmation());
};

interface Producer {
Object apply();
}

Issue5042(int i, int i2) {}

Issue5042(int i) {}

Issue5042() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.sun.source.tree.SynchronizedTree;
import com.sun.source.tree.ThrowTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.TryTree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.TypeParameterTree;
Expand Down Expand Up @@ -1507,14 +1508,45 @@ protected VariableTree getAssertionsEnabledVariable() {
}

/**
* Find nearest owner element(Method or Class) which holds current tree.
* Find nearest owner element (Method or Class) which holds current tree.
*
* @return nearest owner element of current tree
*/
private Element findOwner() {
MethodTree enclosingMethod = TreePathUtil.enclosingMethod(getCurrentPath());
if (enclosingMethod != null) {
return TreeUtils.elementFromDeclaration(enclosingMethod);
Tree enclosingMethodOrLambda = TreePathUtil.enclosingMethodOrLambda(getCurrentPath());
if (enclosingMethodOrLambda != null) {
if (enclosingMethodOrLambda.getKind() == Kind.METHOD) {
return TreeUtils.elementFromDeclaration((MethodTree) enclosingMethodOrLambda);
} else {
// The current path is in a lambda tree. In this case the owner is either a method or
// an initializer block.
LambdaExpressionTree lambdaTree = (LambdaExpressionTree) enclosingMethodOrLambda;
if (!lambdaTree.getParameters().isEmpty()) {
// If there is a lambda parameter, use the same owner.
return TreeUtils.elementFromDeclaration(lambdaTree.getParameters().get(0))
.getEnclosingElement();
}
// If there are no lambda parameters then if the lambda is enclosed in a method, that's the
// owner.
MethodTree enclosingMethod = TreePathUtil.enclosingMethod(getCurrentPath());
if (enclosingMethod != null) {
return TreeUtils.elementFromDeclaration(enclosingMethod);
}

// If the lambda is not enclosed in a method, then the owner should be a constructor. javac
// seems to use the last constructor in the list. (If the lambda is in an initializer of a
// static field then the owner should be a static initializer block, but there doesn't seem
// to be a way to get a reference to the static initializer element.)
ClassTree enclosingClass = TreePathUtil.enclosingClass(getCurrentPath());
TypeElement typeElement = TreeUtils.elementFromDeclaration(enclosingClass);
ExecutableElement constructor = null;
for (Element enclosing : typeElement.getEnclosedElements()) {
if (enclosing.getKind() == ElementKind.CONSTRUCTOR) {
constructor = (ExecutableElement) enclosing;
}
}
return constructor;
}
} else {
ClassTree enclosingClass = TreePathUtil.enclosingClass(getCurrentPath());
return TreeUtils.elementFromDeclaration(enclosingClass);
Expand Down
68 changes: 68 additions & 0 deletions framework/tests/all-systems/Issue5042.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;

@SuppressWarnings("initializedfields") // The fields are intialized.
public class Issue5042 {
interface PromptViewModel {
boolean isPending();

@Nullable PromptButtonViewModel getConfirmationButton();
}

interface PromptButtonViewModel {
@Nullable ConfirmationPopupViewModel getConfirmationPopup();
}

interface ConfirmationPopupViewModel {
boolean isShowingConfirmation();
}

boolean f(PromptViewModel viewModel) {
PromptButtonViewModel prompt = viewModel.getConfirmationButton();
ConfirmationPopupViewModel popup = prompt != null ? prompt.getConfirmationPopup() : null;
return viewModel.isPending() || (popup != null && popup.isShowingConfirmation());
}

static final Function<PromptViewModel, Boolean> IS_PENDING_OR_SHOWING_CONFIRMATION =
(viewModel) -> {
@Nullable PromptButtonViewModel promptLambda = viewModel.getConfirmationButton();
@Nullable ConfirmationPopupViewModel popup =
promptLambda != null ? promptLambda.getConfirmationPopup() : null;
return viewModel.isPending() || (popup != null && popup.isShowingConfirmation());
};

final Function<PromptViewModel, Boolean> IS_PENDING_OR_SHOWING_CONFIRMATION2 =
(viewModel) -> {
@Nullable PromptButtonViewModel prompt = viewModel.getConfirmationButton();
@Nullable ConfirmationPopupViewModel popup =
prompt == null ? null : prompt.getConfirmationPopup();
return viewModel.isPending() || (popup != null && popup.isShowingConfirmation());
};

@Nullable PromptButtonViewModel promptfield;
Producer o =
() -> {
@Nullable ConfirmationPopupViewModel popup =
promptfield == null ? null : promptfield.getConfirmationPopup();
return (popup != null && popup.isShowingConfirmation());
};

static @Nullable PromptButtonViewModel promptfield2;

static Producer o2 =
() -> {
@Nullable ConfirmationPopupViewModel popup =
promptfield2 == null ? null : promptfield2.getConfirmationPopup();
return (popup != null && popup.isShowingConfirmation());
};

interface Producer {
Object apply();
}

Issue5042(int i, int i2) {}

Issue5042(int i) {}

Issue5042() {}
}