-
-
Notifications
You must be signed in to change notification settings - Fork 358
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
Add CtElement.getCompilationUnit
method to the public API
#3942
Comments
There have been several issues opened about Note that in general, it is not the case that each |
I'd say it's the opposite. In general, it's the case that each
I wouldn't involve EDIT: See #3942 (comment) for why we can't avoid involving the source position with the current design. As Spoon allows us to create and mutate compilation units, I think not accounting for that would make for some very unexpected situations. What I think would be nice is a public CtCompilationUnit getOrCreateCompilationUnit() {
if (this instanceof CtType) {
element.getFactory().CompilationUnit().getOrCreate((CtType<?>) element);
} else if (this instanceof ....) {
// handle all of the special cases, e.g. `CtPackage`, `CtModule` etc)
} else {
CtType<?> enclosingType = getParent(CtType.class);
if (enclosingType != null) {
return enclosingType;
} else {
throw new SpoonException("does not belong to a compilation unit");
}
}
} It's then the client's responsibility to check before-hand that the element in question actually belongs to a compilation unit, and in general, that can just be assumed unless they have created elements themselves. I dislike the idea of returning a null type, because if a compilation unit can't be found for an element then the method has been called on an unrooted element, and that seems like a programmatic error to me. In this case, even returning |
Apart from Simon's explanation, I want to point out a minor detail. This returns the Actually, even the factory methods return an instance of
This error method made me question the name of the method
The above two points are just written to suggest a possibility and question why it is not possible that |
Yes, see my code snippet.
The source position must be immutable. Otherwise it does not make sense. It's fine if the CU of the source position differs from the current CU of the element, as the source position just represents the initial state.
The problem I have with this is that you're creating an unreasonable compilation unit. If you have say a standalone What is the point of getting a compilation unit that cannot exist in the Java language model?
Do you mean that I stand by my original suggestion that
|
Is it because it tells where the CtElement originated from? And that should not change even if the compilation unit is changed.
Your code snippet internally uses the factory methods which use source position to get the compilation unit. Especially
I am saying that We can modify the source code here as below. if (type == null) {
// createType("UnnamedType");
}
// The line 137 will add the type to the compilation unit created.
No, I am against that too. I am just proposing to make an exception for
I agree with this approach too. But we should not use factory methods internally because they use source position to get the compilation unit. |
Looking over the implementation of compilation units, it's pretty clear that the current design intends the compilation unit to be intrinsically linked to the source position. I don't agree with that design as we have methods to manipulate compilation units completely independently of source positions, but that problem is really orthogonal to the discussion of this convenience method. So, for now, we'll leave it at the CU and source position being linked is, changing that is beyond the scope of this discussion.
I'm not sure what you mean by "if Even if it did take an argument, there is no "unnamed type" in Java's language model. Spoon is designed to reflect the semantics of Java, and an unnamed type simply does not make sense semantically. I'm guessing you're thinking that it would be they type equivalent of e.g. the unnamed module or unnamed package, but those two are things that actually exist in the language model, and so it isn't the same.
We can, but why? What is the purpose of this? What would you use an unnamed type for? Also, what if there's already a type called |
Oh, okay. I will open a ticket for this. But don't propose a solution yet. I am assuming it is not urgent so it can wait. I will submit a PR for that soon. 😅
I meant this snippet only. if (type == null) {
// createType("UnnamedType");
}
// The line 137 will add the type to the compilation unit created. I will explain its purpose under the next blockquote. It is not very significant thought.
I was just trying to make EDIT:
Okay, we can open an issue for this and maybe fix it later. |
See my edit to that comment.
I disagree with that design philosophy. If input is unreasonable for the requested action, it's better to let the caller know that by throwing (or as is often the case returning |
Yes, I saw. I agree with it. But should we open an issue so that we may come back later?
Sounds good. My philosophy came from how Django implements |
This can be see as a derived property, a helper API method, so it's a good idea. The key design is what to return when there no CU: return Null, a NoCompilationUnit fake object or throw an exception |
@monperrus There is another problem as well. The only reasonable return value for However, all current ways of getting the compilation unit of an element return the compilation unit from which the element was originally parsed. I think it's fine if when the CU has changed, then Note that As it's entirely possible to move elements across compilation units at runtime, I think it's important that this is reflected in a |
Fully agree. The question I'm asking is about the behavior when no ancestor has a compilation unit. |
Yes, I got that, and that is indeed a key question. I would say either throw an exception, or the null object. But not I could be wrong, but I feel like if you're in a situation where you want to get the compilation unit of an element, but there's a chance that the element doesn't have one, then you should have try/catch error handling. For the other key problem that I highlighted, I think that the best solution may be to introduce |
That is a good point. All will have to update the compilation unit in each child of the node. That could be really cumbersome. Are there any more cases apart from
Sound good. Let me just rephrase this to confirm if I understood what you meant. Spoon is concerned with code transformations only and the client should also be concerned with that only. An option for modifying the compilation unit ( |
Not quite sure what you mean with Let's focus this issue on |
We would need to change the compilation unit of a specific element only when that element is inserted or put as replacement in a different model, right? This is why I thought we would need to take care of updating compilation units in
Prior to that, we need to figure out a way to update the compilation units too. Otherwise, the current solution will compel us to be dependent on |
Currently, we have to retrieve the
CtCompilationUnit
of an element,CtType
in my particular case, using the factory methods defined.I propose we add a public API to directly get the
CtCompilationUnit
. It can be a part of theCtElement
as each element belongs to some compilation unit.Reference: ASSERT-KTH/diffmin#65 (comment)
The text was updated successfully, but these errors were encountered: