Skip to content

C#: Fixes for AST printing #4438

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

Merged
merged 22 commits into from
Oct 28, 2020
Merged

C#: Fixes for AST printing #4438

merged 22 commits into from
Oct 28, 2020

Conversation

tamasvajk
Copy link
Contributor

No description provided.

@tamasvajk
Copy link
Contributor Author

https://jenkins.internal.semmle.com/job/Changes/job/CSharp-Differences/519/
https://jenkins.internal.semmle.com/job/Changes/job/CSharp-Differences/524/

I'm surprised to see the changes in the diffs. None of them seem to be attribute and namespace declaration related though.

@tamasvajk tamasvajk force-pushed the feature/ast-fixes branch 3 times, most recently from 756707f to abff3af Compare October 14, 2020 22:12
Comment on lines 7 to 9
# 4| 0: [LocalVariableDeclAndInitExpr] Int32[] one_dim = ...
# 4| -1: [TypeMention] Int32[]
# 4| -1: [TypeMention] int[]
# 4| 1: [TypeMention] int
Copy link
Contributor Author

@tamasvajk tamasvajk Oct 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hvitved The main motivation for this commit was to unify the type name printing of TypeMentions. I think this looks a bit better, but we're still showing Int32[] in the above LocalVariableDeclAndInitExpr (and in some other nodes too). Should/Can I change those classes to use the Type.toStringWithTypes? It feels a bit strange to change all these base class toString()s just for the sake of AST printing.

What was the initial idea behind toString vs toStringWithTypes?

# 30| -1: [TypeMention] Nullable[]
# 30| 1: [TypeMention] Nullable<Byte>
# 30| 1: [TypeMention] Byte
# 30| -1: [TypeMention] Nullable<Byte>[][]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullable[] vs Nullable<Byte>[][] is the reason why toStringWithTypes() was used.

@tamasvajk tamasvajk changed the title Feature/ast fixes C#: Fixes for AST printing Oct 15, 2020
@tamasvajk tamasvajk marked this pull request as ready for review October 15, 2020 12:02
@tamasvajk tamasvajk requested a review from a team as a code owner October 15, 2020 12:02
@tamasvajk
Copy link
Contributor Author

@tamasvajk
Copy link
Contributor Author

The differences job revealed a couple of type mention extraction failures...

@tamasvajk tamasvajk marked this pull request as draft October 16, 2020 08:02
Comment on lines 461 to 496
# 131| 16: [Field] l
# 131| -1: [TypeMention] MyClass[,,][,,,][][,]
# 131| 1: [TypeMention] MyClass
# 131| 1: [TypeMention] MyClass
# 131| 1: [TypeMention] MyClass
# 131| 1: [TypeMention] MyClass
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This corresponds to MyClass?[,,,][][,]?[,,] l;.

The type mention hierarchy is now similar to MyClass[,,,][][,][,,] k; a couple of lines above, that is, there's only one type mention for the multi dimensional array and one for the element type.

@tamasvajk
Copy link
Contributor Author

@tamasvajk tamasvajk marked this pull request as ready for review October 20, 2020 06:21
@tamasvajk
Copy link
Contributor Author

Note to self: add change notes.

Copy link
Contributor

@hvitved hvitved left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments, otherwise LGTM.

@@ -23,27 +23,36 @@ private TypeMention(Context cx, TypeSyntax syntax, IEntity parent, Type type, Mi
this.loc = loc;
}

private static TypeSyntax GetElementType(TypeSyntax type)
private TypeSyntax GetArrayElementType(TypeSyntax type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps GetUnderlyingType is a better name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this too. This method should not be called from case SyntaxKind.NullableType in Populate. It should only be used to get the element type of array-like TypeSyntax elements (array, pointer), hence the name. However, it's recursive and during the recursion, we need to also handle NullableTypeSyntax, and this introduces a bit of confusion.

| definitions.cs:121:18:121:18 | A | definitions.cs:97:11:97:11 | A | T |
| definitions.cs:121:21:121:22 | I1 | definitions.cs:112:15:112:16 | I1 | T |
| definitions.cs:121:25:121:26 | I2<A> | definitions.cs:117:15:117:19 | I2<> | T |
| definitions.cs:121:25:121:29 | I2<A> | definitions.cs:117:15:117:19 | I2<> | T |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is problematic, as we will now have overlapping location spans for the character A: one for I2<A> (which jumps to I2<>) and one for A (which jumps to A), so not sure if the IDE/LGTM will work correctly when trying to jump to the definition for A. I agree that the right location for I2<A> is the whole span, so perhaps the fix instead is to adjust hasLocationInfo for constructed types to exclude type arguments, just like we remove qualifiers from method calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for noticing. I pushed a fix for this.

Comment on lines 123 to 132
TTopLevelTypeMentionNode(TypeMention typeMention) {
shouldPrint(typeMention.getTarget(), _) and
not isNotNeeded(typeMention.getTarget().getParent*()) and
not typeMention.getTarget().getParent*() instanceof TypeParameter
} or
TNestedTypeMentionNode(TypeMention typeMention) {
shouldPrint(typeMention.getParent+().getTarget(), _) and
not isNotNeeded(typeMention.getParent+().getTarget().getParent*()) and
not typeMention.getParent+().getTarget().getParent*() instanceof TypeParameter
} or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a good reason to distinguish nested and top-level type mentions? It seems that something like this would encompass both cases:

TTypeMentionNode(TypeMention typeMention) {
  exists(Element target |
    target = typeMention.getParent*().getTarget() and
    shouldPrint(target, _) and
    not isNotNeeded(target.getParent*()) and
    not target.getParent*() instanceof TypeParameter
  )
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to differentiate between the two, because we only want to have top level type mentions directly under ElementNodes and BaseTypesNodes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that could be handled by restricting to those TypeMentionNodes for which getTarget() exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Let me adjust it.

@tamasvajk tamasvajk dismissed a stale review via 64b584b October 28, 2020 10:30
@tamasvajk tamasvajk merged commit 59d9be4 into github:main Oct 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants